stormpath / express-stormpath

Build simple, secure web applications with Stormpath and Express!
http://docs.stormpath.com/nodejs/express/
Apache License 2.0
325 stars 111 forks source link

Multi-Tenancy Regular Login and Social Login #590

Open oshalygin opened 7 years ago

oshalygin commented 7 years ago

Greetings gents, if anyone has any insight into what I may be doing wrong I'd be really love it. I've configured my application to match the documentation for MultiTenancy, but for some reason the subdomain isn't getting picked up and passed down to Stormpath, it just seems to default to the first organization. The JWT doesn't seem to store the organization either:

Documentation that I'm following: https://github.com/stormpath/express-stormpath/blob/2610219368dbe4bc32bdbcd69a0ce6d575626202/docs/multi_tenancy.rst

Also reading a lot into this PR: https://github.com/stormpath/express-stormpath/pull/538

My stormpath config which contains the multiTenancy config section

web: {
    produces: ['application/json'],
    domainName: process.env.DOMAIN_NAME || 'localhost',
    multiTenancy: {
      enabled: true,
      strategy: 'subdomain'
    },
    me: {
      expand: {
        customData: true
      }
    }
  },
application.get('/api/user', stormpath.authenticationRequired, (req, res) => { //eslint-disable-line

  const client = req.app.get('stormpathClient');
  const orgHref = req.authenticationResult.expandedJwt.claims.org;
  console.log(req.authenticationResult); //this returns the object shown in the next code snippet
  if (!orgHref) {
    return res.json(403, 'You are not logged in to an organization.');
  }

  client.getOrganization(orgHref, (err, organization) => { //eslint-disable-line
    if (err) {
      return res.json(err.status, err.message);
    }

    res.json({
      message: `You are logged into the "' + ${organization.name} + '" ${organization}.`
    });
  });
});

This is the expandedJwt object. I modified the actual values but this is the object thats returned back. As you can see, there's no org property under claims:


expandedJwt: 
   { header: { kid: '5V38Y84HVAWFP6LPAHQ', stt: 'access', alg: 'HS256' },
     claims: 
      { jti: '6Y8b3vZBLl66rDYbo4Q3',
        iat: 1485509,
        iss: 'https://api.stormpath.com/v1/applications/5ioZxR3PpuA9nQm5oP',
        sub: 'https://api.stormpath.com/v1/accounts/6YFsKcBjjE3iYBoR5',
        exp: 1485570409,
        rti: '6Y8b3sF6Rz' },
     signature: 'yMOUwV-adh97E' },

}

Looking at the /me response that happens during the login step, the organization is also null

{
  "organization": null,
  "account": {
    "href": "https://api.stormpath.com/v1/accounts/m0FfVfmU43rBlSJz",
    "username": "oleg.shalygin@gmail.com",
    "email": "oleg.shalygin@gmail.com",
    "givenName": "Oleg",
    "middleName": null,
    "surname": "Shalygin",
    "fullName": "Oleg Shalygin",
    "status": "ENABLED",
    "createdAt": "2017-01-28T02:11:37.600Z",
    "modifiedAt": "2017-01-28T02:11:37.600Z",
    "passwordModifiedAt": "2017-01-28T02:11:37.000Z",
    "emailVerificationStatus": "VERIFIED",
    "emailVerificationToken": null,
    "customData": {
      "href": "https://api.stormpath.com/v1/accounts/m0FfVfmAt3rBlSJz/customData",
      "createdAt": "2017-01-28T02:11:37.600Z",
      "modifiedAt": "2017-01-28T02:11:37.600Z"
    }
  }
}
oshalygin commented 7 years ago

Debugging: Looks like it's properly set at the organization resolver.

image

Going line by line through all of the calls I narrowed down my problem, I wasnt mapping the organization to the application in the Admin portal! Ugh stupid mistake on my part!

image

After I attached all of the organizations to the application, things work!

oshalygin commented 7 years ago

Okay after quite a bit of research, the disconnect for Social Login with MultiTenancy appears to be that the organization is never passed down to getFormViewModel.

Inside getFormViewModel(https://github.com/stormpath/express-stormpath/blob/master/lib/helpers/get-form-view-model.js#L80-L101) we're looking for the accountStoreMapping at the application level instead of at the organization level.

Despite having the organization nameKey on hand in the request object(req.organization, which gets set in default-organization-resolver.js => https://github.com/stormpath/express-stormpath/blob/master/lib/middleware/default-organization-resolver.js#L48-L50).

Looking at the structure of the application and separation through multi-tenancy via organizations:

image

image

Looking specifically at getProviders and the call to getAccountStores, in here we accept the application object instead of the organization object, which contains the accountStores for that organization and not the accountStores for the application: https://github.com/stormpath/express-stormpath/blob/master/lib/helpers/get-form-view-model.js#L136-L139

oshalygin commented 7 years ago

This has been resolved with, https://github.com/stormpath/express-stormpath/commit/a558f8ca55e3515fe5e20cbd0fe4e7666be53ba5

Big thanks to @robertjd and the team at Stormpath.

Feel free to close this one out as I'm currently on the mt-social branch but if you guys wanted to track this to make sure it makes it over to master then I understand leaving it open.

Thanks!!