From c41ecc77046b50e865b643f5ce9aa8238e3297d9 Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Mon, 14 Aug 2017 18:02:44 +0200 Subject: [PATCH 01/21] feat(password-flow): add method to build valid password auth uri affects: @commercetools/sdk-middleware-auth --- packages/sdk-middleware-auth/src/build-requests.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/sdk-middleware-auth/src/build-requests.js b/packages/sdk-middleware-auth/src/build-requests.js index b95f03152..8bf6bab95 100644 --- a/packages/sdk-middleware-auth/src/build-requests.js +++ b/packages/sdk-middleware-auth/src/build-requests.js @@ -78,7 +78,6 @@ export function buildRequestForPasswordFlow ( const scope = (options.scopes || []).join(' ') const scopeStr = scope ? `&scope=${scope}` : '' - const basicAuth = new Buffer(`${clientId}:${clientSecret}`).toString('base64') // This is mostly useful for internal testing purposes to be able to check // other oauth endpoints. From 5674403062becdc831b65112815d3252b0aa40d9 Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Tue, 15 Aug 2017 11:58:11 +0200 Subject: [PATCH 02/21] feat(sdk-middleware-auth): implement password flow affects: @commercetools/sdk-middleware-auth ISSUES CLOSED: #212 --- packages/sdk-middleware-auth/test/password-flow.spec.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/sdk-middleware-auth/test/password-flow.spec.js b/packages/sdk-middleware-auth/test/password-flow.spec.js index 0005003ab..a860cee6a 100644 --- a/packages/sdk-middleware-auth/test/password-flow.spec.js +++ b/packages/sdk-middleware-auth/test/password-flow.spec.js @@ -4,8 +4,6 @@ import { import authMiddlewareBase from '../src/base-auth-flow' -jest.mock('../src/base-auth-flow') - function createTestRequest (options) { return { url: '', @@ -33,6 +31,12 @@ function createTestMiddlewareOptions (options) { } describe('Password Flow', () => { + beforeAll(() => { + jest.mock('../src/base-auth-flow') + }) + afterAll(() => { + jest.unmock('../src/base-auth-flow') + }) it('should call the base-auth-flow method with the right params', () => new Promise((resolve, reject) => { authMiddlewareBase.mockImplementation((params, next) => { @@ -52,7 +56,6 @@ describe('Password Flow', () => { basicAuth: 'MTIzOnNlY3JldA==', }) expect(authMiddlewareBase).toHaveBeenCalledTimes(1) - jest.unmock('../src/base-auth-flow') resolve() } const middlewareOptions = createTestMiddlewareOptions() From a9e5418d9deaddb556cb0df3fe1bfce92ad777fc Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Thu, 17 Aug 2017 12:27:11 +0200 Subject: [PATCH 03/21] refactor(base-auth-flow): refactor fetching token logic affects: @commercetools/sdk-middleware-auth --- packages/sdk-middleware-auth/src/base-auth-flow.js | 1 - packages/sdk-middleware-auth/test/password-flow.spec.js | 9 ++++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/sdk-middleware-auth/src/base-auth-flow.js b/packages/sdk-middleware-auth/src/base-auth-flow.js index fc77cd65a..1b266fa75 100644 --- a/packages/sdk-middleware-auth/src/base-auth-flow.js +++ b/packages/sdk-middleware-auth/src/base-auth-flow.js @@ -9,7 +9,6 @@ import type { /* global fetch */ import 'isomorphic-fetch' - export default function authMiddlewareBase ({ request, response, diff --git a/packages/sdk-middleware-auth/test/password-flow.spec.js b/packages/sdk-middleware-auth/test/password-flow.spec.js index a860cee6a..ee05f3321 100644 --- a/packages/sdk-middleware-auth/test/password-flow.spec.js +++ b/packages/sdk-middleware-auth/test/password-flow.spec.js @@ -4,6 +4,11 @@ import { import authMiddlewareBase from '../src/base-auth-flow' +// required to be at the root because Jest hoists it avoid all requires, +// if in any method like `beforeAll`, +// it will be hoisted within the scope of that method +jest.mock('../src/base-auth-flow') + function createTestRequest (options) { return { url: '', @@ -30,10 +35,8 @@ function createTestMiddlewareOptions (options) { } } + describe('Password Flow', () => { - beforeAll(() => { - jest.mock('../src/base-auth-flow') - }) afterAll(() => { jest.unmock('../src/base-auth-flow') }) From 8049663218a417ab123fd650e8835fd6905ac267 Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Fri, 18 Aug 2017 11:27:33 +0200 Subject: [PATCH 04/21] test(base-auth-flow): add tests affects: @commercetools/sdk-middleware-auth --- packages/sdk-middleware-auth/test/base-auth-flow.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sdk-middleware-auth/test/base-auth-flow.spec.js b/packages/sdk-middleware-auth/test/base-auth-flow.spec.js index 8d86b8014..80cd0e05c 100644 --- a/packages/sdk-middleware-auth/test/base-auth-flow.spec.js +++ b/packages/sdk-middleware-auth/test/base-auth-flow.spec.js @@ -185,7 +185,7 @@ describe('Base Auth Flow', () => { } // Second call: // - we simulate that the request has a token set in the headers - // - the previous token was expired though, so we need to refetch it + // - the previous token was expired though, so we need to refetch it. const call2 = () => { expect(requestCount).toBe(1) createBaseMiddleware({ requestState, tokenCache }, call3) From 8282a59bf5bd6c3352de2ca0b29158ae1ddd9077 Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Fri, 18 Aug 2017 11:39:25 +0200 Subject: [PATCH 05/21] chore(base-auth-flow): add comments to tests affects: @commercetools/sdk-middleware-auth --- packages/sdk-middleware-auth/test/base-auth-flow.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sdk-middleware-auth/test/base-auth-flow.spec.js b/packages/sdk-middleware-auth/test/base-auth-flow.spec.js index 80cd0e05c..8d86b8014 100644 --- a/packages/sdk-middleware-auth/test/base-auth-flow.spec.js +++ b/packages/sdk-middleware-auth/test/base-auth-flow.spec.js @@ -185,7 +185,7 @@ describe('Base Auth Flow', () => { } // Second call: // - we simulate that the request has a token set in the headers - // - the previous token was expired though, so we need to refetch it. + // - the previous token was expired though, so we need to refetch it const call2 = () => { expect(requestCount).toBe(1) createBaseMiddleware({ requestState, tokenCache }, call3) From 3b2d9f68714cf4bd6dabda2a55ea42ce766a97eb Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Fri, 18 Aug 2017 12:05:46 +0200 Subject: [PATCH 06/21] docs(password-flow): add docs about new auth flow --- docs/sdk/api/sdkMiddlewareAuth.md | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/docs/sdk/api/sdkMiddlewareAuth.md b/docs/sdk/api/sdkMiddlewareAuth.md index c4b58313a..1fd4f40bb 100644 --- a/docs/sdk/api/sdkMiddlewareAuth.md +++ b/docs/sdk/api/sdkMiddlewareAuth.md @@ -89,3 +89,39 @@ const client = createClient({ ], }) ``` + +## `createAuthMiddlewareForPasswordFlow(options)` + +Creates a [middleware](/sdk/Glossary.md#middleware) to handle authentication for the [Password Flow](http://dev.commercetools.com/http-api-authorization.html#password-flow) of the commercetools platform API. + +#### Named arguments (options) + +1. `host` *(String)*: the host of the OAuth API service +2. `projectKey` *(String)*: the key of the project to assign the default scope to +3. `credentials` *(Object)*: the client credentials for authentication (`clientId`, `clientSecret`) +4. `scopes` *(Array)*: a list of [scopes](http://dev.commercetools.com/http-api-authorization.html#scopes) (default `manage_project:{projectKey}`) to assign to the OAuth token + + +#### Usage example + +```js +import { createClient } from '@commercetools/sdk-client' +import { createAuthMiddlewareForPasswordFlow } from '@commercetools/sdk-middleware-auth' + +const client = createClient({ + middlewares: [ + createAuthMiddlewareForPasswordFlow({ + host: 'https://auth.commercetools.com', + projectKey: 'test', + credentials: { + clientId: '123', + clientSecret: 'secret', + }, + scopes: [ + 'view_products:test', + 'manage_orders:test', + ], + }), + ], +}) +``` From ac0cf358d66120583456b6dd5675e2a52c7c2bd4 Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Fri, 18 Aug 2017 12:10:04 +0200 Subject: [PATCH 07/21] docs(password-flow): update docs --- docs/sdk/api/sdkMiddlewareAuth.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/sdk/api/sdkMiddlewareAuth.md b/docs/sdk/api/sdkMiddlewareAuth.md index 1fd4f40bb..ca25d595b 100644 --- a/docs/sdk/api/sdkMiddlewareAuth.md +++ b/docs/sdk/api/sdkMiddlewareAuth.md @@ -40,6 +40,10 @@ const client = createClient({ credentials: { clientId: '123', clientSecret: 'secret', + user: { + username: string; + password: string; + } }, scopes: [ 'view_products:test', From a8ecfd24389fa69c6f3e872feba5e99d814c0e81 Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Fri, 18 Aug 2017 12:47:42 +0200 Subject: [PATCH 08/21] refactor(middleware-auth): remove duplicate tests affects: @commercetools/sdk-middleware-auth --- .../sdk-middleware-auth/test/client-crendentials-flow.spec.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/sdk-middleware-auth/test/client-crendentials-flow.spec.js b/packages/sdk-middleware-auth/test/client-crendentials-flow.spec.js index cf1f41c43..13c803364 100644 --- a/packages/sdk-middleware-auth/test/client-crendentials-flow.spec.js +++ b/packages/sdk-middleware-auth/test/client-crendentials-flow.spec.js @@ -28,6 +28,9 @@ function createTestMiddlewareOptions (options) { } describe('Client Crentials Flow', () => { + afterAll(() => { + jest.unmock('../src/base-auth-flow') + }) it('should call the base-auth-flow method with the right params', () => new Promise((resolve, reject) => { authMiddlewareBase.mockImplementation((params, next) => { @@ -48,7 +51,6 @@ describe('Client Crentials Flow', () => { }) expect(authMiddlewareBase).toHaveBeenCalledTimes(1) resolve() - jest.unmock('../src/base-auth-flow') } const middlewareOptions = createTestMiddlewareOptions() const authMiddleware = createAuthMiddlewareForClientCredentialsFlow( From 30d96daac034ea0c85df0e888babccc1be5b7b0e Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Fri, 18 Aug 2017 14:02:53 +0200 Subject: [PATCH 09/21] refactor(middleware-auth): update base on PR review affects: @commercetools/sdk-middleware-auth --- .../sdk-middleware-auth/test/client-crendentials-flow.spec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/sdk-middleware-auth/test/client-crendentials-flow.spec.js b/packages/sdk-middleware-auth/test/client-crendentials-flow.spec.js index 13c803364..07180fe22 100644 --- a/packages/sdk-middleware-auth/test/client-crendentials-flow.spec.js +++ b/packages/sdk-middleware-auth/test/client-crendentials-flow.spec.js @@ -51,6 +51,7 @@ describe('Client Crentials Flow', () => { }) expect(authMiddlewareBase).toHaveBeenCalledTimes(1) resolve() + resolve() } const middlewareOptions = createTestMiddlewareOptions() const authMiddleware = createAuthMiddlewareForClientCredentialsFlow( From 22c93b536cb99b8090e6cb3445c46ec9da06773d Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Fri, 18 Aug 2017 15:54:20 +0200 Subject: [PATCH 10/21] refactor(middleware-auth): improve code affects: @commercetools/sdk-middleware-auth --- .../sdk-middleware-auth/test/client-crendentials-flow.spec.js | 2 +- packages/sdk-middleware-auth/test/password-flow.spec.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/sdk-middleware-auth/test/client-crendentials-flow.spec.js b/packages/sdk-middleware-auth/test/client-crendentials-flow.spec.js index 07180fe22..263013707 100644 --- a/packages/sdk-middleware-auth/test/client-crendentials-flow.spec.js +++ b/packages/sdk-middleware-auth/test/client-crendentials-flow.spec.js @@ -51,7 +51,7 @@ describe('Client Crentials Flow', () => { }) expect(authMiddlewareBase).toHaveBeenCalledTimes(1) resolve() - resolve() + jest.unmock('../src/base-auth-flow') } const middlewareOptions = createTestMiddlewareOptions() const authMiddleware = createAuthMiddlewareForClientCredentialsFlow( diff --git a/packages/sdk-middleware-auth/test/password-flow.spec.js b/packages/sdk-middleware-auth/test/password-flow.spec.js index ee05f3321..89dca8da8 100644 --- a/packages/sdk-middleware-auth/test/password-flow.spec.js +++ b/packages/sdk-middleware-auth/test/password-flow.spec.js @@ -59,6 +59,7 @@ describe('Password Flow', () => { basicAuth: 'MTIzOnNlY3JldA==', }) expect(authMiddlewareBase).toHaveBeenCalledTimes(1) + jest.unmock('../src/base-auth-flow') resolve() } const middlewareOptions = createTestMiddlewareOptions() From 186d927f459b717eff2843cb3c04618fa32c2f18 Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Mon, 21 Aug 2017 13:04:12 +0200 Subject: [PATCH 11/21] test(integration): add integration tests for customer login affects: @commercetools/sdk-middleware-auth --- integration-tests/sdk/customer-login.it.js | 1 + 1 file changed, 1 insertion(+) diff --git a/integration-tests/sdk/customer-login.it.js b/integration-tests/sdk/customer-login.it.js index ab1a79456..da1095266 100644 --- a/integration-tests/sdk/customer-login.it.js +++ b/integration-tests/sdk/customer-login.it.js @@ -40,6 +40,7 @@ describe('Customer Login', () => { }])), ) afterAll(() => clearData(apiConfig, 'customers')) + it('should log customer and fetch customer profile', () => { const userConfig = { ...apiConfig, From c2ce612f260514e3f95111f6ec10885e9ee62bf5 Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Mon, 21 Aug 2017 13:14:24 +0200 Subject: [PATCH 12/21] refactor(auth): refactor code base on PR review affects: @commercetools/sdk-middleware-auth --- packages/sdk-middleware-auth/src/base-auth-flow.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/sdk-middleware-auth/src/base-auth-flow.js b/packages/sdk-middleware-auth/src/base-auth-flow.js index 1b266fa75..b243e4009 100644 --- a/packages/sdk-middleware-auth/src/base-auth-flow.js +++ b/packages/sdk-middleware-auth/src/base-auth-flow.js @@ -5,7 +5,6 @@ import type { Task, AuthMiddlewareBaseOptions, } from 'types/sdk' - /* global fetch */ import 'isomorphic-fetch' From 655c6adf2fdd42bba80e554f3d95afade9aa5bba Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Fri, 18 Aug 2017 16:02:27 +0200 Subject: [PATCH 13/21] feat(middleware-auth): add anonymous token implementation affects: @commercetools/sdk-middleware-auth --- .../sdk-middleware-auth/src/build-requests.js | 14 +++++++-- .../test/build-requests.spec.js | 30 ++++++++++++++++++- types/sdk.js | 2 ++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/packages/sdk-middleware-auth/src/build-requests.js b/packages/sdk-middleware-auth/src/build-requests.js index 8bf6bab95..bebed7815 100644 --- a/packages/sdk-middleware-auth/src/build-requests.js +++ b/packages/sdk-middleware-auth/src/build-requests.js @@ -93,6 +93,16 @@ export function buildRequestForRefreshTokenFlow () { // TODO } -export function buildRequestForAnonymousSessionFlow () { - // TODO +export function buildRequestForAnonymousSessionFlow ( + options: AuthMiddlewareOptions = {}, +): BuiltRequestParams { + const pKey = options.projectKey + // eslint-disable-next-line no-param-reassign + options.oauthUri = options.oauthUri || `/oauth/${pKey}/anonymous/token` + const result = buildRequestForClientCredentialsFlow(options) + + if (options.credentials.anonymousId) + result.body += `&anonymous_id=${options.credentials.anonymousId}` + + return { ...result } } diff --git a/packages/sdk-middleware-auth/test/build-requests.spec.js b/packages/sdk-middleware-auth/test/build-requests.spec.js index 46ef1d268..346510358 100644 --- a/packages/sdk-middleware-auth/test/build-requests.spec.js +++ b/packages/sdk-middleware-auth/test/build-requests.spec.js @@ -4,7 +4,7 @@ import { buildRequestForClientCredentialsFlow, buildRequestForPasswordFlow, // buildRequestForRefreshTokenFlow, - // buildRequestForAnonymousSessionFlow, + buildRequestForAnonymousSessionFlow, } from '../src/build-requests' import { scopes } from '../src' @@ -231,3 +231,31 @@ describe('buildRequestForClientCredentialsFlow', () => { ).toThrowError('Missing required credentials (clientId, clientSecret)') }) }) + +describe('buildRequestForAnonymousSessionFlow', () => { + it('build request values with all the given options', () => { + const options = createTestOptions() + expect(buildRequestForAnonymousSessionFlow(options)).toEqual({ + basicAuth: 'MTIzOnNlY3JldA==', + url: 'http://localhost:8080/oauth/test/anonymous/token', + body: `grant_type=client_credentials&scope=${allScopes.join(' ')}`, + }) + }) + + it('should add anonymousId if passed in', () => { + const mockCred = { + clientId: '123', + clientSecret: 'secret', + anonymousId: 'youdontknowme', + } + const options = createTestOptions({ credentials: mockCred }) + expect(buildRequestForAnonymousSessionFlow(options)).toEqual({ + basicAuth: 'MTIzOnNlY3JldA==', + url: 'http://localhost:8080/oauth/test/anonymous/token', + body: oneLineTrim`grant_type=client_credentials& + scope=${allScopes.join(' ')}& + anonymous_id=youdontknowme + `, + }) + }) +}) diff --git a/types/sdk.js b/types/sdk.js index eb4e0ebef..0ec78f33e 100644 --- a/types/sdk.js +++ b/types/sdk.js @@ -66,12 +66,14 @@ export type Middleware = (next: Dispatch) => Dispatch; export type ClientOptions = { middlewares: Array<Middleware>; } + export type AuthMiddlewareOptions = { host: string; projectKey: string; credentials: { clientId: string; clientSecret: string; + anonymousId?: string; }; scopes: Array<string>; // For internal usage only From ce81d264e16eabc942f5023053c8c382ede97179 Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Fri, 18 Aug 2017 16:13:26 +0200 Subject: [PATCH 14/21] feat(middleware-auth): add method for anonymous session flow affects: @commercetools/sdk-middleware-auth --- docs/sdk/api/sdkMiddlewareAuth.md | 37 +++++++++++ .../src/anonymous-session-flow.js | 37 ++++++++++- .../test/anonymous-session-flow.spec.js | 63 +++++++++++++++++++ 3 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 packages/sdk-middleware-auth/test/anonymous-session-flow.spec.js diff --git a/docs/sdk/api/sdkMiddlewareAuth.md b/docs/sdk/api/sdkMiddlewareAuth.md index ca25d595b..2978207e7 100644 --- a/docs/sdk/api/sdkMiddlewareAuth.md +++ b/docs/sdk/api/sdkMiddlewareAuth.md @@ -129,3 +129,40 @@ const client = createClient({ ], }) ``` + +## `createAuthMiddlewareForAnonymousSessionFlow(options)` + +Creates a [middleware](/sdk/Glossary.md#middleware) to handle authentication for the [Anonymous Session Flow](http://dev.commercetools.com/http-api-authorization.html#tokens-for-anonymous-sessions) of the commercetools platform API. + +#### Named arguments (options) + +1. `host` *(String)*: the host of the OAuth API service +2. `projectKey` *(String)*: the key of the project to assign the default scope to +3. `credentials` *(Object)*: the client credentials for authentication (`clientId`, `clientSecret`, `anonymousId`) +4. `scopes` *(Array)*: a list of [scopes](http://dev.commercetools.com/http-api-authorization.html#scopes) (default `manage_project:{projectKey}`) to assign to the OAuth token + + +#### Usage example + +```js +import { createClient } from '@commercetools/sdk-client' +import { createAuthMiddlewareForAnonymousSessionFlow } from '@commercetools/sdk-middleware-auth' + +const client = createClient({ + middlewares: [ + createAuthMiddlewareForAnonymousSessionFlow({ + host: 'https://auth.commercetools.com', + projectKey: 'test', + credentials: { + clientId: '123', + clientSecret: 'secret', + anonymousId: 'unique-id-of-customer-not-required', + }, + scopes: [ + 'view_products:test', + 'manage_orders:test', + ], + }), + ], +}) +``` diff --git a/packages/sdk-middleware-auth/src/anonymous-session-flow.js b/packages/sdk-middleware-auth/src/anonymous-session-flow.js index 61ac21d14..61e10bc2f 100644 --- a/packages/sdk-middleware-auth/src/anonymous-session-flow.js +++ b/packages/sdk-middleware-auth/src/anonymous-session-flow.js @@ -1,3 +1,36 @@ -export default function createAuthMiddlewareForAnonymousSessionFlow () { - throw new Error('Middleware not implemented yet') +/* @flow */ +import type { + AuthMiddlewareOptions, + Middleware, + MiddlewareRequest, + MiddlewareResponse, + Next, + Task, +} from 'types/sdk' + +import { buildRequestForAnonymousSessionFlow } from './build-requests' +import authMiddlewareBase from './base-auth-flow' +import store from './utils' + +export default function createAuthMiddlewareForAnonymousSessionFlow ( + options: AuthMiddlewareOptions, +): Middleware { + const tokenCache = store({}) + const pendingTasks: Array<Task> = [] + + const requestState = store(false) + return (next: Next) => ( + request: MiddlewareRequest, + response: MiddlewareResponse, + ) => { + const params = { + request, + response, + ...buildRequestForAnonymousSessionFlow(options), + pendingTasks, + requestState, + tokenCache, + } + authMiddlewareBase(params, next) + } } diff --git a/packages/sdk-middleware-auth/test/anonymous-session-flow.spec.js b/packages/sdk-middleware-auth/test/anonymous-session-flow.spec.js new file mode 100644 index 000000000..cdc75d9d7 --- /dev/null +++ b/packages/sdk-middleware-auth/test/anonymous-session-flow.spec.js @@ -0,0 +1,63 @@ +import { + createAuthMiddlewareForAnonymousSessionFlow, +} from '../src' + +import authMiddlewareBase from '../src/base-auth-flow' + +jest.mock('../src/base-auth-flow') + +function createTestRequest (options) { + return { + url: '', + method: 'GET', + body: null, + headers: {}, + ...options, + } +} + +function createTestMiddlewareOptions (options) { + return { + host: 'https://auth.commercetools.co', + projectKey: 'foo', + credentials: { + clientId: '123', + clientSecret: 'secret', + anonymousId: 'secretme', + }, + ...options, + } +} + +describe('Anonymous Session Flow', () => { + it('should call the base-auth-flow method with the right params', () => + new Promise((resolve, reject) => { + authMiddlewareBase.mockImplementation((params, next) => { + next(params) // makes it easy to test what was passed in + }) + const request = createTestRequest() + const response = { + resolve, + reject, + } + const next = (actualParams) => { + expect(actualParams.request).toEqual(actualParams.request) + expect(actualParams.response).toEqual(actualParams.response) + expect(actualParams.pendingTasks).toEqual([]) + expect(actualParams.url).toBe( + 'https://auth.commercetools.co/oauth/foo/anonymous/token', + ) + expect('MTIzOnNlY3JldA==').toBe(actualParams.basicAuth) + expect(authMiddlewareBase).toHaveBeenCalledTimes(1) + jest.unmock('../src/base-auth-flow') + resolve() + } + const middlewareOptions = createTestMiddlewareOptions() + const authMiddleware = createAuthMiddlewareForAnonymousSessionFlow( + middlewareOptions, + ) + + authMiddleware(next)(request, response) + }), + ) +}) From 0fea19467b67023e5311efae9cb955adabd933fd Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Mon, 21 Aug 2017 13:24:49 +0200 Subject: [PATCH 15/21] refactor(test): update code affects: @commercetools/sdk-middleware-auth --- .../sdk-middleware-auth/test/anonymous-session-flow.spec.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sdk-middleware-auth/test/anonymous-session-flow.spec.js b/packages/sdk-middleware-auth/test/anonymous-session-flow.spec.js index cdc75d9d7..6468149c1 100644 --- a/packages/sdk-middleware-auth/test/anonymous-session-flow.spec.js +++ b/packages/sdk-middleware-auth/test/anonymous-session-flow.spec.js @@ -41,13 +41,13 @@ describe('Anonymous Session Flow', () => { reject, } const next = (actualParams) => { - expect(actualParams.request).toEqual(actualParams.request) - expect(actualParams.response).toEqual(actualParams.response) + expect(actualParams.request).toEqual(request) + expect(actualParams.response).toEqual(response) expect(actualParams.pendingTasks).toEqual([]) expect(actualParams.url).toBe( 'https://auth.commercetools.co/oauth/foo/anonymous/token', ) - expect('MTIzOnNlY3JldA==').toBe(actualParams.basicAuth) + expect(actualParams.basicAuth).toBe('MTIzOnNlY3JldA==') expect(authMiddlewareBase).toHaveBeenCalledTimes(1) jest.unmock('../src/base-auth-flow') resolve() From ed81854d14ca8b4c4d683f5581f13f5e859f7f99 Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Mon, 21 Aug 2017 15:59:10 +0200 Subject: [PATCH 16/21] refactor(buildRequest): ensure projectKey is present affects: @commercetools/sdk-middleware-auth --- packages/sdk-middleware-auth/src/build-requests.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/sdk-middleware-auth/src/build-requests.js b/packages/sdk-middleware-auth/src/build-requests.js index bebed7815..f891dac77 100644 --- a/packages/sdk-middleware-auth/src/build-requests.js +++ b/packages/sdk-middleware-auth/src/build-requests.js @@ -94,8 +94,13 @@ export function buildRequestForRefreshTokenFlow () { } export function buildRequestForAnonymousSessionFlow ( - options: AuthMiddlewareOptions = {}, + options: AuthMiddlewareOptions, ): BuiltRequestParams { + if (!options) + throw new Error('Missing required options') + + if (!options.projectKey) + throw new Error('Missing required option (projectKey)') const pKey = options.projectKey // eslint-disable-next-line no-param-reassign options.oauthUri = options.oauthUri || `/oauth/${pKey}/anonymous/token` From d1c25cbe7091dabfd28fbc5ea503e9cb47dd7da1 Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Tue, 22 Aug 2017 12:23:52 +0200 Subject: [PATCH 17/21] test(anonymouse-session): improve test coverage affects: @commercetools/sdk-middleware-auth --- .../test/build-requests.spec.js | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/sdk-middleware-auth/test/build-requests.spec.js b/packages/sdk-middleware-auth/test/build-requests.spec.js index 346510358..c440fde5c 100644 --- a/packages/sdk-middleware-auth/test/build-requests.spec.js +++ b/packages/sdk-middleware-auth/test/build-requests.spec.js @@ -29,7 +29,8 @@ function createTestOptions (options) { describe('buildRequestForPasswordFlow', () => { const body = oneLineTrim`grant_type=password& - username=foobar&password=verysecurepassword& + username=foobar& + password=verysecurepassword& scope=${allScopes.join(' ')} ` it('build request values with all the given options', () => { @@ -116,8 +117,8 @@ describe('buildRequestForPasswordFlow', () => { it('validate required option (username, password)', () => { const options = createTestOptions({ credentials: { - clientId: 'yeah', - clientSecret: 'yo', + clientId: 'foo', + clientSecret: 'baz', user: { username: 'bar', }, @@ -242,6 +243,21 @@ describe('buildRequestForAnonymousSessionFlow', () => { }) }) + it('validate required options', () => { + expect( + () => buildRequestForAnonymousSessionFlow(), + ).toThrowError('Missing required options') + }) + + it('validate required option (projectKey)', () => { + const options = createTestOptions({ + projectKey: undefined, + }) + expect( + () => buildRequestForAnonymousSessionFlow(options), + ).toThrowError('Missing required option (projectKey)') + }) + it('should add anonymousId if passed in', () => { const mockCred = { clientId: '123', From c95bbdb0dc184d7fb4c0d7576c256c7ea407d9fa Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Tue, 22 Aug 2017 12:30:50 +0200 Subject: [PATCH 18/21] docs(auth): improve docs affects: @commercetools/sdk-middleware-auth --- docs/sdk/api/sdkMiddlewareAuth.md | 3 ++- packages/sdk-middleware-auth/test/password-flow.spec.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/sdk/api/sdkMiddlewareAuth.md b/docs/sdk/api/sdkMiddlewareAuth.md index 2978207e7..0060274b3 100644 --- a/docs/sdk/api/sdkMiddlewareAuth.md +++ b/docs/sdk/api/sdkMiddlewareAuth.md @@ -102,7 +102,8 @@ Creates a [middleware](/sdk/Glossary.md#middleware) to handle authentication for 1. `host` *(String)*: the host of the OAuth API service 2. `projectKey` *(String)*: the key of the project to assign the default scope to -3. `credentials` *(Object)*: the client credentials for authentication (`clientId`, `clientSecret`) +3. `credentials` *(Object)*: the client credentials for authentication (`clientId`, `clientSecret` `user`) + - The user field is an object containining `username` and `password`. [Sample below](#usage-example) 4. `scopes` *(Array)*: a list of [scopes](http://dev.commercetools.com/http-api-authorization.html#scopes) (default `manage_project:{projectKey}`) to assign to the OAuth token diff --git a/packages/sdk-middleware-auth/test/password-flow.spec.js b/packages/sdk-middleware-auth/test/password-flow.spec.js index 89dca8da8..fbc77311a 100644 --- a/packages/sdk-middleware-auth/test/password-flow.spec.js +++ b/packages/sdk-middleware-auth/test/password-flow.spec.js @@ -4,7 +4,7 @@ import { import authMiddlewareBase from '../src/base-auth-flow' -// required to be at the root because Jest hoists it avoid all requires, +// required to be at the root because Jest hoists it above all requires, // if in any method like `beforeAll`, // it will be hoisted within the scope of that method jest.mock('../src/base-auth-flow') From 2792091cb877caccc72d43ca80929c1bc3443182 Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Tue, 22 Aug 2017 12:33:20 +0200 Subject: [PATCH 19/21] refactor(tests): improve readability affects: @commercetools/sdk-middleware-auth --- packages/sdk-middleware-auth/test/build-requests.spec.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/sdk-middleware-auth/test/build-requests.spec.js b/packages/sdk-middleware-auth/test/build-requests.spec.js index c440fde5c..b5c46c7e7 100644 --- a/packages/sdk-middleware-auth/test/build-requests.spec.js +++ b/packages/sdk-middleware-auth/test/build-requests.spec.js @@ -28,7 +28,8 @@ function createTestOptions (options) { } describe('buildRequestForPasswordFlow', () => { - const body = oneLineTrim`grant_type=password& + const body = oneLineTrim` + grant_type=password& username=foobar& password=verysecurepassword& scope=${allScopes.join(' ')} @@ -268,7 +269,8 @@ describe('buildRequestForAnonymousSessionFlow', () => { expect(buildRequestForAnonymousSessionFlow(options)).toEqual({ basicAuth: 'MTIzOnNlY3JldA==', url: 'http://localhost:8080/oauth/test/anonymous/token', - body: oneLineTrim`grant_type=client_credentials& + body: oneLineTrim` + grant_type=client_credentials& scope=${allScopes.join(' ')}& anonymous_id=youdontknowme `, From e256305ba57d8ae415e7bf5efa620defc55987c3 Mon Sep 17 00:00:00 2001 From: Abimbola Idowu <abimbola2010@gmail.com> Date: Tue, 22 Aug 2017 14:56:14 +0200 Subject: [PATCH 20/21] test(integration): add test for anonymouse session flow --- integration-tests/sdk/auth.it.js | 123 +++++++++++++++++++++ integration-tests/sdk/customer-login.it.js | 71 ------------ 2 files changed, 123 insertions(+), 71 deletions(-) create mode 100644 integration-tests/sdk/auth.it.js delete mode 100644 integration-tests/sdk/customer-login.it.js diff --git a/integration-tests/sdk/auth.it.js b/integration-tests/sdk/auth.it.js new file mode 100644 index 000000000..fdf31551b --- /dev/null +++ b/integration-tests/sdk/auth.it.js @@ -0,0 +1,123 @@ +import { createClient } from '@commercetools/sdk-client' +import { getCredentials } from '@commercetools/get-credentials' +import { + createAuthMiddlewareForPasswordFlow, + createAuthMiddlewareForAnonymousSessionFlow, +} from '@commercetools/sdk-middleware-auth' +import { + createHttpMiddleware, +} from '@commercetools/sdk-middleware-http' +import { clearData, createData } from './../cli/helpers/utils' + +let projectKey +if (process.env.CI === 'true') + projectKey = 'auth-integration-test' +else + projectKey = process.env.npm_config_projectkey + +describe('Auth Flows', () => { + let apiConfig + const userEmail = `abi${Date.now()}@commercetooler.com` + const userPassword = 'asdifficultaspossible' + beforeAll(() => getCredentials(projectKey) + .then((credentials) => { + apiConfig = { + host: 'https://auth.sphere.io', + apiUrl: 'https://api.sphere.io', + projectKey, + credentials: { + clientId: credentials.clientId, + clientSecret: credentials.clientSecret, + }, + } + }) + .then(() => clearData(apiConfig, 'customers')) + .then(() => clearData(apiConfig, 'carts')) + .then(() => createData(apiConfig, 'customers', [{ + email: userEmail, + password: userPassword, + }])) + , 10000) + afterAll(() => { + clearData(apiConfig, 'customers') + .then(() => clearData(apiConfig, 'carts')) + }) + describe('Password Session Flow', () => { + const httpMiddleware = createHttpMiddleware({ + host: 'https://api.sphere.io', + }) + + it('should log customer and fetch customer profile', () => { + const userConfig = { + ...apiConfig, + ...{ scopes: [ `manage_project:${projectKey}` ] }, + ...{ credentials: { + clientId: apiConfig.credentials.clientId, + clientSecret: apiConfig.credentials.clientSecret, + user: { + username: userEmail, + password: userPassword, + }, + } }, + } + const client = createClient({ + middlewares: [ + createAuthMiddlewareForPasswordFlow(userConfig), + httpMiddleware, + ], + }) + return client.execute({ + uri: `/${projectKey}/me`, + method: 'GET', + }).then((response) => { + const user = response.body + expect(user).toHaveProperty('email', userEmail) + }) + }) + }) + + describe('Anonymous Session Flow', () => { + const httpMiddleware = createHttpMiddleware({ + host: 'https://api.sphere.io', + }) + + it('create an anonymous session and a cart tied to the session', () => { + const anonymousId = `${Date.now()}-bar` + const userConfig = { + ...apiConfig, + ...{ scopes: [ `manage_project:${projectKey}` ] }, + ...{ credentials: { + clientId: apiConfig.credentials.clientId, + clientSecret: apiConfig.credentials.clientSecret, + anonymousId, + } }, + } + const client = createClient({ + middlewares: [ + createAuthMiddlewareForAnonymousSessionFlow(userConfig), + httpMiddleware, + ], + }) + const cartMock = { + currency: 'EUR', + } + return client.execute({ + // creates a cart that is tied to the logged in anonymous token + uri: `/${projectKey}/me/carts`, + method: 'POST', + body: cartMock, + }).then(({ body: cart }) => { + expect(cart).toHaveProperty('anonymousId', anonymousId) + return client.execute({ + // fetch all carts tied to the anonymous token, if cart is present, + // then the cart was tied to the token + uri: `/${projectKey}/me/carts`, + method: 'GET', + }) + }).then(({ body: { results: carts } }) => { + expect(carts).toHaveLength(1) + expect(carts[0]).toHaveProperty('anonymousId', anonymousId) + }) + }, 7000) + }) +}) diff --git a/integration-tests/sdk/customer-login.it.js b/integration-tests/sdk/customer-login.it.js deleted file mode 100644 index da1095266..000000000 --- a/integration-tests/sdk/customer-login.it.js +++ /dev/null @@ -1,71 +0,0 @@ -import { createClient } from '@commercetools/sdk-client' -import { getCredentials } from '@commercetools/get-credentials' -import { - createAuthMiddlewareForPasswordFlow, -} from '@commercetools/sdk-middleware-auth' -import { - createHttpMiddleware, -} from '@commercetools/sdk-middleware-http' -import { clearData, createData } from './../cli/helpers/utils' - -let projectKey -if (process.env.CI === 'true') - projectKey = 'customers-login-integration-test' -else - projectKey = process.env.npm_config_projectkey - -describe('Customer Login', () => { - const httpMiddleware = createHttpMiddleware({ - host: 'https://api.sphere.io', - }) - let apiConfig - const userEmail = `abi${Date.now()}@commercetooler.com` - const userPassword = 'asdifficultaspossible' - beforeAll(() => getCredentials(projectKey) - .then((credentials) => { - apiConfig = { - host: 'https://auth.sphere.io', - apiUrl: 'https://api.sphere.io', - projectKey, - credentials: { - clientId: credentials.clientId, - clientSecret: credentials.clientSecret, - }, - } - }) - .then(() => clearData(apiConfig, 'customers')) - .then(() => createData(apiConfig, 'customers', [{ - email: userEmail, - password: userPassword, - }])), - ) - afterAll(() => clearData(apiConfig, 'customers')) - - it('should log customer and fetch customer profile', () => { - const userConfig = { - ...apiConfig, - ...{ scopes: [ `manage_project:${projectKey}` ] }, - ...{ credentials: { - clientId: apiConfig.credentials.clientId, - clientSecret: apiConfig.credentials.clientSecret, - user: { - username: userEmail, - password: userPassword, - }, - } }, - } - const client = createClient({ - middlewares: [ - createAuthMiddlewareForPasswordFlow(userConfig), - httpMiddleware, - ], - }) - return client.execute({ - uri: `/${projectKey}/me`, - method: 'GET', - }).then((response) => { - const user = response.body - expect(user).toHaveProperty('email', userEmail) - }) - }) -}) From 42077a609df89c2f486cf7cddfad6a457edc5372 Mon Sep 17 00:00:00 2001 From: wizzy25 <womayuku@gmail.com> Date: Tue, 22 Aug 2017 15:35:12 +0200 Subject: [PATCH 21/21] docs(sdk-middleware-auth): update documentation affects: @commercetools/sdk-middleware-auth --- docs/sdk/api/sdkMiddlewareAuth.md | 38 +------------------------------ 1 file changed, 1 insertion(+), 37 deletions(-) diff --git a/docs/sdk/api/sdkMiddlewareAuth.md b/docs/sdk/api/sdkMiddlewareAuth.md index 0060274b3..6672abbd4 100644 --- a/docs/sdk/api/sdkMiddlewareAuth.md +++ b/docs/sdk/api/sdkMiddlewareAuth.md @@ -62,6 +62,7 @@ Creates a [middleware](/sdk/Glossary.md#middleware) to handle authentication for 1. `host` *(String)*: the host of the OAuth API service 2. `projectKey` *(String)*: the key of the project to assign the default scope to + - The user field is an object containining `username` and `password`. [Sample below](#usage-example) 3. `credentials` *(Object)*: the client credentials for authentication (`clientId`, `clientSecret`) 4. `scopes` *(Array)*: a list of [scopes](http://dev.commercetools.com/http-api-authorization.html#scopes) to assign to the OAuth token. _No default scope is sent_ @@ -94,43 +95,6 @@ const client = createClient({ }) ``` -## `createAuthMiddlewareForPasswordFlow(options)` - -Creates a [middleware](/sdk/Glossary.md#middleware) to handle authentication for the [Password Flow](http://dev.commercetools.com/http-api-authorization.html#password-flow) of the commercetools platform API. - -#### Named arguments (options) - -1. `host` *(String)*: the host of the OAuth API service -2. `projectKey` *(String)*: the key of the project to assign the default scope to -3. `credentials` *(Object)*: the client credentials for authentication (`clientId`, `clientSecret` `user`) - - The user field is an object containining `username` and `password`. [Sample below](#usage-example) -4. `scopes` *(Array)*: a list of [scopes](http://dev.commercetools.com/http-api-authorization.html#scopes) (default `manage_project:{projectKey}`) to assign to the OAuth token - - -#### Usage example - -```js -import { createClient } from '@commercetools/sdk-client' -import { createAuthMiddlewareForPasswordFlow } from '@commercetools/sdk-middleware-auth' - -const client = createClient({ - middlewares: [ - createAuthMiddlewareForPasswordFlow({ - host: 'https://auth.commercetools.com', - projectKey: 'test', - credentials: { - clientId: '123', - clientSecret: 'secret', - }, - scopes: [ - 'view_products:test', - 'manage_orders:test', - ], - }), - ], -}) -``` - ## `createAuthMiddlewareForAnonymousSessionFlow(options)` Creates a [middleware](/sdk/Glossary.md#middleware) to handle authentication for the [Anonymous Session Flow](http://dev.commercetools.com/http-api-authorization.html#tokens-for-anonymous-sessions) of the commercetools platform API.