-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
separate idplogin helper into separate file
- Loading branch information
1 parent
9189eb0
commit 31dd0a6
Showing
4 changed files
with
168 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/** | ||
* @jest-environment node | ||
*/ | ||
/* eslint header/header: "off", max-lines:"off" */ | ||
/* | ||
* Copyright (c) 2022, salesforce.com, inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
*/ | ||
|
||
import nock from 'nock'; | ||
import {ShopperLogin, TokenResponse} from '../../lib/shopperLogin'; | ||
import loginIDPUser from './IDPLoginHelper'; | ||
import ResponseError from '../responseError'; | ||
|
||
const credentialsPublic = {}; | ||
|
||
const expectedTokenResponse: TokenResponse = { | ||
access_token: 'access_token', | ||
id_token: 'id_token', | ||
refresh_token: 'refresh_token', | ||
expires_in: 0, | ||
refresh_token_expires_in: 0, | ||
token_type: 'token_type', | ||
usid: 'usid', | ||
customer_id: 'customer_id', | ||
enc_user_id: 'enc_user_id', | ||
idp_access_token: 'idp', | ||
}; | ||
|
||
const parameters = { | ||
accessToken: 'access_token', | ||
redirectURI: 'redirect_uri', | ||
refreshToken: 'refresh_token', | ||
usid: 'usid', | ||
hint: 'hint', | ||
dnt: false, | ||
}; | ||
|
||
const url = | ||
'https://localhost:3000/callback?usid=048adcfb-aa93-4978-be9e-09cb569fdcb9&code=J2lHm0cgXmnXpwDhjhLoyLJBoUAlBfxDY-AhjqGMC-o'; | ||
|
||
const authenticateCustomerMock = jest.fn(() => ({url})); | ||
|
||
const getAccessTokenMock = jest.fn(() => expectedTokenResponse); | ||
const logoutCustomerMock = jest.fn(() => expectedTokenResponse); | ||
const generateCodeChallengeMock = jest.fn(() => 'code_challenge'); | ||
|
||
const createMockSlasClient = () => | ||
({ | ||
clientConfig: { | ||
parameters: { | ||
shortCode: 'short_code', | ||
organizationId: 'organization_id', | ||
clientId: 'client_id', | ||
siteId: 'site_id', | ||
}, | ||
}, | ||
authenticateCustomer: authenticateCustomerMock, | ||
getAccessToken: getAccessTokenMock, | ||
logoutCustomer: logoutCustomerMock, | ||
generateCodeChallenge: generateCodeChallengeMock, | ||
} as unknown as ShopperLogin<{ | ||
shortCode: string; | ||
organizationId: string; | ||
clientId: string; | ||
siteId: string; | ||
}>); | ||
|
||
describe('Social login user flow', () => { | ||
test('loginIDPUser does not stop when authorizeCustomer returns 303', async () => { | ||
// slasClient is copied and tries to make an actual API call | ||
const mockSlasClient = createMockSlasClient(); | ||
const {shortCode, organizationId} = mockSlasClient.clientConfig.parameters; | ||
|
||
// Mock authorizeCustomer | ||
nock(`https://${shortCode}.api.commercecloud.salesforce.com`) | ||
.get(`/shopper/auth/v1/organizations/${organizationId}/oauth2/authorize`) | ||
.query(true) | ||
.reply(303, {message: 'Oh yes!'}); | ||
|
||
await expect( | ||
loginIDPUser(mockSlasClient, credentialsPublic, parameters) | ||
).resolves.not.toThrow(ResponseError); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* | ||
* Copyright (c) 2022, Salesforce, Inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
*/ | ||
import {stringToBase64, createCodeVerifier, authorize} from './slasHelper'; | ||
import { | ||
ShopperLogin, | ||
TokenRequest, | ||
TokenResponse, | ||
} from '../../lib/shopperLogin'; | ||
|
||
/** | ||
* A single function to execute the ShopperLogin External IDP Login with proof key for code exchange flow as described in the [API documentation](https://developer.salesforce.com/docs/commerce/commerce-api/references?meta=shopper-login:Summary). | ||
* **Note**: this func can run on client side. Only use private slas when the slas client secret is secured. | ||
* @param slasClient a configured instance of the ShopperLogin SDK client. | ||
* @param credentials - the clientSecret (if applicable) to login with. | ||
* @param credentials.clientSecret? - secret associated with client ID | ||
* @param parameters - parameters to pass in the API calls. | ||
* @param parameters.redirectURI - Per OAuth standard, a valid app route. Must be listed in your SLAS configuration. On server, this will not be actually called. On browser, this will be called, but ignored. | ||
* @param parameters.hint - Name of an identity provider (IDP) to redirect to | ||
* @param parameters.usid? - Unique Shopper Identifier to enable personalization. | ||
* @param parameters.dnt? - Optional parameter to enable Do Not Track (DNT) for the user. | ||
* @returns TokenResponse | ||
*/ | ||
async function loginIDPUser( | ||
slasClient: ShopperLogin<{ | ||
shortCode: string; | ||
organizationId: string; | ||
clientId: string; | ||
siteId: string; | ||
}>, | ||
credentials: { | ||
clientSecret?: string; | ||
}, | ||
parameters: { | ||
redirectURI: string; | ||
hint: string; | ||
usid?: string; | ||
dnt?: boolean; | ||
} | ||
): Promise<TokenResponse> { | ||
const codeVerifier = createCodeVerifier(); | ||
|
||
const authResponse = await authorize(slasClient, codeVerifier, { | ||
redirectURI: parameters.redirectURI, | ||
hint: parameters.hint, | ||
...(parameters.usid && {usid: parameters.usid}), | ||
}); | ||
|
||
const tokenBody: TokenRequest = { | ||
client_id: slasClient.clientConfig.parameters.clientId, | ||
channel_id: slasClient.clientConfig.parameters.siteId, | ||
code: authResponse.code, | ||
code_verifier: codeVerifier, | ||
grant_type: 'authorization_code_pkce', | ||
redirect_uri: parameters.redirectURI, | ||
usid: authResponse.usid, | ||
...(parameters.dnt !== undefined && {dnt: parameters.dnt.toString()}), | ||
}; | ||
|
||
// Using private client | ||
if (credentials.clientSecret) { | ||
const authHeaderIdSecret = `Basic ${stringToBase64( | ||
`${slasClient.clientConfig.parameters.clientId}:${credentials.clientSecret}` | ||
)}`; | ||
|
||
const optionsToken = { | ||
headers: { | ||
Authorization: authHeaderIdSecret, | ||
}, | ||
body: tokenBody, | ||
}; | ||
return slasClient.getAccessToken(optionsToken); | ||
} | ||
|
||
return slasClient.getAccessToken({body: tokenBody}); | ||
} | ||
|
||
export default loginIDPUser; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters