all files / express-stormpath/lib/controllers/ login.js

76.19% Statements 48/63
54.55% Branches 24/44
91.67% Functions 11/12
76.19% Lines 48/63
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169                                                    10×   10×   10× 10×       10×                                                                                                                                                                                    
'use strict';
 
var extend = require('deep-extend');
var url = require('url');
 
var forms = require('../forms');
var helpers = require('../helpers');
var oauth = require('../oauth');
var oktaErrorTransformer = require('../okta/error-transformer');
 
/**
 * Set the account store in the provided data object.
 *
 * @function
 *
 * @param {Object} data - Data object to set account store in.
 * @param {Object} accountStore - Account store to retrieve href from.
 */
function setAccountStoreByHref(data, accountStore) {
  return data.accountStore = accountStore.href;
}
 
/**
 * This controller logs in an existing user.  If there are any errors, an
 * error page is rendered.  If the process succeeds, the user will be logged in
 * and redirected.
 *
 * @method
 *
 * @param {Object} req - The HTTP request.
 * @param {Object} res - The HTTP response.
 * @param {function} next - The next function.
 */
module.exports = function (req, res, next) {
  var config = req.app.get('stormpathConfig');
 
  res.locals.status = req.query.status;
 
  helpers.getFormViewModel('login', config, function (err, viewModel) {
    Iif (err) {
      return helpers.writeJsonError(res, err);
    }
 
    helpers.handleAcceptRequest(req, res, {
      'application/json': function () {
        switch (req.method) {
          case 'GET':
            res.json(viewModel);
            break;
 
          case 'POST':
            Iif (!req.body) {
              return helpers.writeJsonError(res, new Error('Request requires that there is a body.'));
            }
 
            // Social login
            Iif (req.body.providerData) {
              return helpers.loginWithOAuthProvider(req.body, req, res);
            }
 
            Iif (config.web.multiTenancy.enabled && req.organization) {
              setAccountStoreByHref(req.body, req.organization);
            }
 
            helpers.authenticate(req.body, req, res, function (err) {
              if (err) {
                Iif (err.code === 2014) {
                  err.message = err.userMessage = 'Invalid Username, Password, or Organization';
                }
 
                return helpers.writeJsonError(res, oktaErrorTransformer(err));
              }
 
              helpers.loginResponder(req, res);
            });
            break;
 
          default:
            next();
        }
      },
      'text/html': function () {
        var nextUri = url.parse(req.query.next || '').path;
        var formActionUri = (config.web.login.uri + (nextUri ? ('?next=' + nextUri) : ''));
 
        Iif (req.user && config.web.login.enabled) {
          var nextUrl = nextUri || config.web.login.nextUri;
          return res.redirect(302, nextUrl);
        }
 
        function renderForm(form, options) {
          Eif (options === undefined) {
            options = {};
          }
 
          var view = config.web.login.view;
          var oauthStateToken = oauth.common.resolveStateToken(req, res);
 
          var providers = helpers.buildProviderModel(req, res);
 
          var hasSocialProviders = !!Object.keys(providers).length;
 
          extend(options, {
            form: form,
            formActionUri: formActionUri,
            oauthStateToken: oauthStateToken,
            hasSocialProviders: hasSocialProviders,
            formModel: viewModel.form,
            socialProviders: providers,
            organization: req.organization
          });
 
          helpers.render(req, res, view, options);
        }
 
        return helpers.organizationResolutionGuard(req, res, formActionUri, function () {
          helpers.setTempCookie(res, 'oauthRedirectUri', req.originalUrl);
 
          forms.loginForm.handle(req, {
            // If we get here, it means the user is submitting a login request, so we
            // should attempt to log the user into their account.
            success: function (form) {
              Iif (config.web.multiTenancy.enabled && req.organization) {
                setAccountStoreByHref(form.data, req.organization);
              } else {
                /**
                 * Delete this form field, it's automatically added by the
                 * forms library.  If we don't delete it, we submit a null
                 * name key to the REST API and we get an error.
                 */
                delete form.data.organizationNameKey;
              }
 
              helpers.authenticate(form.data, req, res, function (err) {
                Iif (err) {
                  if (err.code === 2014) {
                    err.message = err.userMessage = 'Invalid Username, Password, or Organization';
                  }
 
                  err = oktaErrorTransformer(err);
 
                  return renderForm(form, { error: err.userMessage || err.message });
                }
 
                helpers.loginResponder(req, res);
              });
            },
            // If we get here, it means the user didn't supply required form fields.
            error: function (form) {
              // Special case: if the user is being redirected to this page for the
              // first time, don't display any error.
              Eif (form.data && !form.data.login && !form.data.password) {
                return renderForm(form);
              }
 
              renderForm(form, { formErrors: helpers.collectFormErrors(form) });
            },
            // If we get here, it means the user is doing a simple GET request, so we
            // should just render the login template.
            empty: function (form) {
              renderForm(form);
            }
          });
        });
      }
    }, next);
  });
};