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 | 1× 1× 1× 1× 1× 1× 1× 1× 1× 80× 80× 80× 80× 80× 80× 2× 78× 12× 6× 6× 1× 6× 6× 6× 6× 6× 6× 6× 6× 66× | 'use strict'; var forms = require('../forms'); var assertOrganizationIsMappedToApplication = require('./assert-org-mapped-to-app'); var collectFormErrors = require('./collect-form-errors'); var isRootDomainMultiTenantRequest = require('./is-root-domain-multi-tenant-request'); var parentDomainRedirect = require('./parent-domain-redirect'); var redirectToOrganization = require('./redirect-to-organization'); var render = require('./render'); var requiresOrganizationResolution = require('./requires-organization-resolution'); /** * Handles the organization resolving process for multi-tenancy. * * Calls that would require organization resolutions (i.e. are made on a sub-domain, * in an application set up to support multi-tenancy) will be redirected to the * parent domain for organization selection. * * Calls that are made to the root domain will handle the showing or processing * of the organization name input form, depending on the request method. When * handled, the processing will be handed over the form the user was originally * trying to access (login, register, password refresh or e-mail verification flow). * * When no processing is needed, the control will be handed to the `next` callback * without any processing. * * The resolver itself is not a part of this guard, and is instead handled by the * organization resolver middleware. * * @method * @name redirectToOrganizationResolution * * @param {Object} req - HTTP request * @param {Object} res - HTTP response * @param {String} formActionUri - URI pointing where to redirect the user to * continue their authorization flow after the organization processing flow is * completed * @param {Function} next - The callback to invoke if (and only if) no multi-tenancy * processing is needed. Never invoked if the this handler does some processing. */ module.exports = function organizationResolutionGuard(req, res, formActionUri, next) { var application = req.app.get('stormpathApplication'); var config = req.app.get('stormpathConfig'); var logger = req.app.get('stormpathLogger'); var stormpathClient = req.app.get('stormpathClient'); var organizationSelectFormModel = { fields: [{ name: 'organizationNameKey', enabled: null, visible: true, label: config.web.organizationSelect.form.fields.organizationNameKey.label, placeholder: config.web.organizationSelect.form.fields.organizationNameKey.placeholder, required: true, type: 'text' }] }; if (requiresOrganizationResolution(req)) { return parentDomainRedirect(req, res); } if (isRootDomainMultiTenantRequest(req)) { if (req.method === 'GET') { return render(req, res, 'organization-select', { form: forms.organizationSelectForm, formActionUri: formActionUri, formModel: organizationSelectFormModel }); } return forms.organizationSelectForm.handle(req, { success: function (form) { function renderNotFoundError() { return render(req, res, config.web.organizationSelect.view, { form: form, formActionUri: formActionUri, formModel: organizationSelectFormModel, error: 'Organization could not be bound' }); } stormpathClient.getOrganizations({nameKey: form.data.organizationNameKey}, function (err, collection) { Iif (err) { return res.json(err); } Iif (collection.items.length !== 1) { return renderNotFoundError(); } var organization = collection.items[0]; assertOrganizationIsMappedToApplication(organization, application, function (err, isMappedToApp) { Iif (err) { return res.json(err); } Eif (isMappedToApp) { return redirectToOrganization(req, res, organization); } logger.info('The organization "' + organization.name + '" is not mapped to this application, it will not be used.'); return renderNotFoundError(); }); }); }, // If we get here, it means the user didn't supply required form fields. error: function (form) { render(req, res, 'organization-select', { form: form, formActionUri: formActionUri, formModel: organizationSelectFormModel, formErrors: collectFormErrors(form) }); }, // If we get here, it means the user is doing a simple GET request, so we // should just render the original template. empty: function (form) { render(req, res, 'organization-select', { form: form, formActionUri: formActionUri, formModel: organizationSelectFormModel }); } }); } next(); }; |