all files / express-stormpath/lib/middleware/ default-organization-resolver.js

81.03% Statements 47/58
62.07% Branches 18/29
100% Functions 10/10
81.03% Lines 47/58
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                                                                                                                                           
'use strict';
 
var stormpath = require('stormpath');
var parseDomain = require('psl').parse;
var helpers = require('../helpers/');
 
var organizationNameKeyToHrefMap = {};
 
function defaultOrganizationResolver(req, res, next) {
  var client = req.app.get('stormpathClient');
  var config = req.app.get('stormpathConfig');
  var application = req.app.get('stormpathApplication');
  var web = config.web;
 
  function resolveOrganizationByHref(href, callback) {
    client.getOrganization(href, callback);
  }
 
  function resolveOrganizationByNameKey(nameKey, callback) {
    var organizationHref = organizationNameKeyToHrefMap[nameKey];
 
    Iif (organizationHref) {
      return resolveOrganizationByHref(organizationHref, callback);
    }
 
    client.getOrganizations({ nameKey: nameKey }, function (err, collection) {
      Iif (err) {
        return callback(err);
      }
 
      var organization = collection.items[0];
 
      Eif (organization) {
        organizationNameKeyToHrefMap[nameKey] = organization.href;
      }
 
      callback(null, organization);
    });
  }
 
  // Once we have an organization, attach it to the request and
  // continue processing the middleware pipeline.
  function continueWithOrganization(organization) {
    req.organization = organization;
    next();
  }
 
  // Strategy which tries to resolve an organization from an access token cookie 'org' claim.
  // If this strategy fails then it falls back to resolving the organization from the request body.
  function continueWithAccessTokenStrategy() {
    Eif (req.cookies && req.cookies[web.accessTokenCookie.name]) {
      var accessTokenCookie = req.cookies[web.accessTokenCookie.name];
 
      var authenticator = new stormpath.JwtAuthenticator(application);
 
      authenticator.withLocalValidation();
 
      return authenticator.authenticate(accessTokenCookie, function (err, authResult) {
        Iif (err) {
          return next(err);
        }
 
        var verifiedJwt = authResult.expandedJwt;
 
        Eif (verifiedJwt.body.org) {
          return resolveOrganizationByHref(verifiedJwt.body.org, function (err, organization) {
            Iif (err) {
              return next(err);
            }
 
            var currentHost = parseDomain(helpers.getHost(req, true));
 
            Iif (web.multiTenancy.useSubdomain && organization.nameKey !== currentHost.subdomain) {
              res.status(401);
              res.json({
                status: 401,
                message: 'Multi-tenancy useDomainName mode is enabled but organization name key does not match current subdomain.'
              });
              res.end();
              return;
            }
 
            continueWithOrganization(organization);
          });
        }
 
        next();
      });
    }
 
    next();
  }
 
  // Strategy which tries to resolve an organization from a sub domain.
  // If this step fails then it falls back to resolving an organization from an access token cookie.
  function continueWithSubDomainStrategy() {
    if (web.multiTenancy.useSubdomain) {
      var currentHost = parseDomain(helpers.getHost(req, true));
 
      Eif ((!web.domainName || web.domainName === currentHost.domain) && currentHost.subdomain) {
        return resolveOrganizationByNameKey(currentHost.subdomain, function (err, organization) {
          Iif (err) {
            return next(err);
          }
 
          continueWithOrganization(organization);
        });
      }
    }
 
    continueWithAccessTokenStrategy();
  }
 
  continueWithSubDomainStrategy();
}
 
module.exports = defaultOrganizationResolver;