diff --git a/tf/actions/samlMappings.js b/tf/actions/samlMappings.js index 1966572..6d09770 100644 --- a/tf/actions/samlMappings.js +++ b/tf/actions/samlMappings.js @@ -99,6 +99,9 @@ exports.onExecutePostLogin = async (event, api) => { roles: [{ role: "view_only", account: "acct_1EJOaaJNcmPzuWtR" }], }, ]; + // Each user may have multiple roles assigned to them per account. + // We gather each of their assigned roles, and then assert it afterwards. + const accountRoles = {}; for (const rule of groupToRoles) { const usersAllowed = rule.users ?? []; const isAllowedByEmail = usersAllowed.includes(event.user.email); @@ -106,13 +109,19 @@ exports.onExecutePostLogin = async (event, api) => { if (!(isAllowedByEmail || isAllowedByGroup)) { continue; } + // Gather the user's roles in each account. for (const role of rule.roles) { - api.samlResponse.setAttribute( - `Stripe-Role-${role.account}`, - role.role - ); + const account = `Stripe-Role-${role.account}`; + if (account in accountRoles) { + accountRoles[account].push(role.role); + } else { + accountRoles[account] = [role.role]; + } } } + for (const account in accountRoles) { + api.samlResponse.setAttribute(account, accountRoles[account]); + } break; } // acoustic-stage, acoustic-prod diff --git a/tf/tests/samlMappings.test.js b/tf/tests/samlMappings.test.js index 32e107e..8991194 100644 --- a/tf/tests/samlMappings.test.js +++ b/tf/tests/samlMappings.test.js @@ -332,7 +332,7 @@ describe("Stripe-Subplat SAML tests", () => { _event.user.app_metadata.groups = _event.user.app_metadata.groups || []; _event.user.app_metadata.groups.push(group); expectedSamlAttributes = { - "Stripe-Role-acct_1EJOaaJNcmPzuWtR": role, + "Stripe-Role-acct_1EJOaaJNcmPzuWtR": [role], }; } else { delete _event.user.groups; @@ -355,7 +355,21 @@ describe("Stripe-Subplat SAML tests", () => { _event.client.client_id = "cEfnJekrSStxxxBascTjNEDAZVUPAIU2"; _event.user.email = "araccounting@mozilla.com"; const expectedSamlAttributes = { - "Stripe-Role-acct_1EJOaaJNcmPzuWtR": "admin", + "Stripe-Role-acct_1EJOaaJNcmPzuWtR": ["admin"], + }; + await onExecutePostLogin(_event, api); + expect(api.samlResponse.setAttribute).toHaveBeenCalled(); + expect(_samlAttributes).toEqual(expectedSamlAttributes); + }); + + test("User with multiple roles", async () => { + _event.client.client_id = "cEfnJekrSStxxxBascTjNEDAZVUPAIU2"; + _event.user.app_metadata.groups = [ + "mozilliansorg_stripe_subplat_analyst", + "mozilliansorg_stripe_subplat_viewonly", + ]; + const expectedSamlAttributes = { + "Stripe-Role-acct_1EJOaaJNcmPzuWtR": ["analyst", "view_only"], }; await onExecutePostLogin(_event, api); expect(api.samlResponse.setAttribute).toHaveBeenCalled(); @@ -374,7 +388,7 @@ describe("Acoustic SAML tests", () => { async (clientID) => { _event.client.client_id = clientID; - expectedSamlAttributes = { + const expectedSamlAttributes = { Nameid: _event.user.email, email: _event.user.email, firstName: _event.user.given_name,