From 917e893ae53c061bc0e7927f648edd199963bafb Mon Sep 17 00:00:00 2001 From: sameerag Date: Mon, 13 Jul 2020 17:24:06 -0700 Subject: [PATCH 1/3] Device Code response --- .../src/client/DeviceCodeClient.ts | 22 ++++++++++++++++--- .../src/client/PublicClientApplication.ts | 4 ++-- samples/msal-node-extensions/package.json | 2 +- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/lib/msal-common/src/client/DeviceCodeClient.ts b/lib/msal-common/src/client/DeviceCodeClient.ts index 90d40a253e..c6e8d7a1ba 100644 --- a/lib/msal-common/src/client/DeviceCodeClient.ts +++ b/lib/msal-common/src/client/DeviceCodeClient.ts @@ -13,6 +13,8 @@ import { ClientConfiguration } from "../config/ClientConfiguration"; import { TimeUtils } from "../utils/TimeUtils"; import { ServerAuthorizationTokenResponse } from "../server/ServerAuthorizationTokenResponse"; import { ScopeSet } from "../request/ScopeSet"; +import { ResponseHandler } from "../response/ResponseHandler"; +import { AuthenticationResult } from '../response/AuthenticationResult'; /** * OAuth2.0 Device code client @@ -28,7 +30,7 @@ export class DeviceCodeClient extends BaseClient { * polls token endpoint to exchange device code for tokens * @param request */ - public async acquireToken(request: DeviceCodeRequest): Promise { + public async acquireToken(request: DeviceCodeRequest): Promise { const deviceCodeResponse: DeviceCodeResponse = await this.getDeviceCode(request); request.deviceCodeCallback(deviceCodeResponse); @@ -36,8 +38,21 @@ export class DeviceCodeClient extends BaseClient { request, deviceCodeResponse); - // TODO handle response - return JSON.stringify(response); + const responseHandler = new ResponseHandler( + this.config.authOptions.clientId, + this.cacheManager, + this.cryptoUtils, + this.logger + ); + + // Validate response. This function throws a server error if an error is returned by the server. + responseHandler.validateTokenResponse(response); + const tokenResponse = responseHandler.handleServerTokenResponse( + response, + this.authority + ); + + return tokenResponse; } /** @@ -174,6 +189,7 @@ export class DeviceCodeClient extends BaseClient { requestParameters.addDeviceCode(deviceCodeResponse.deviceCode); const correlationId = request.correlationId || this.config.cryptoInterface.createNewGuid(); requestParameters.addCorrelationId(correlationId); + requestParameters.addClientInfo(); return requestParameters.createQueryString(); } } diff --git a/lib/msal-node/src/client/PublicClientApplication.ts b/lib/msal-node/src/client/PublicClientApplication.ts index f55bbf4a20..f0208adc91 100644 --- a/lib/msal-node/src/client/PublicClientApplication.ts +++ b/lib/msal-node/src/client/PublicClientApplication.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. */ -import { DeviceCodeClient, DeviceCodeRequest } from '@azure/msal-common'; +import { DeviceCodeClient, DeviceCodeRequest, AuthenticationResult } from '@azure/msal-common'; import { Configuration } from '../config/Configuration'; import { ClientApplication } from './ClientApplication'; @@ -42,7 +42,7 @@ export class PublicClientApplication extends ClientApplication { * Since the client cannot receive incoming requests, it polls the authorization server repeatedly * until the end-user completes input of credentials. */ - public async acquireTokenByDeviceCode(request: DeviceCodeRequest): Promise { + public async acquireTokenByDeviceCode(request: DeviceCodeRequest): Promise { this.logger.info("acquireTokenByDeviceCode called"); const deviceCodeConfig = await this.buildOauthClientConfiguration( request.authority diff --git a/samples/msal-node-extensions/package.json b/samples/msal-node-extensions/package.json index d26f4a8f24..ca9f6496cf 100644 --- a/samples/msal-node-extensions/package.json +++ b/samples/msal-node-extensions/package.json @@ -11,7 +11,7 @@ "author": "Microsoft", "license": "MIT", "dependencies": { - "@azure/msal-node": "^0.1.0", + "@azure/msal-node": "^1.0.0-alpha.0", "express": "^4.17.1", "@azure/msal-node-extensions": "0.1.0" } From e9c5ab1ee2a3a8723a0f94489e8ca24730f87180 Mon Sep 17 00:00:00 2001 From: sameerag Date: Thu, 16 Jul 2020 14:39:01 -0700 Subject: [PATCH 2/3] Fix linter for msal-common --- lib/msal-common/src/client/DeviceCodeClient.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msal-common/src/client/DeviceCodeClient.ts b/lib/msal-common/src/client/DeviceCodeClient.ts index c6e8d7a1ba..97921a72bf 100644 --- a/lib/msal-common/src/client/DeviceCodeClient.ts +++ b/lib/msal-common/src/client/DeviceCodeClient.ts @@ -14,7 +14,7 @@ import { TimeUtils } from "../utils/TimeUtils"; import { ServerAuthorizationTokenResponse } from "../server/ServerAuthorizationTokenResponse"; import { ScopeSet } from "../request/ScopeSet"; import { ResponseHandler } from "../response/ResponseHandler"; -import { AuthenticationResult } from '../response/AuthenticationResult'; +import { AuthenticationResult } from "../response/AuthenticationResult"; /** * OAuth2.0 Device code client From 886c407439fc31ff5a5c459c3dabfbf25cbf29f2 Mon Sep 17 00:00:00 2001 From: sameerag Date: Sun, 19 Jul 2020 15:33:09 -0700 Subject: [PATCH 3/3] fixing tests --- .../test/client/DeviceCodeClient.spec.ts | 54 +++++++++++++++++-- lib/msal-common/test/utils/StringConstants.ts | 1 + 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/lib/msal-common/test/client/DeviceCodeClient.spec.ts b/lib/msal-common/test/client/DeviceCodeClient.spec.ts index 767f271f0d..ce6ed72714 100644 --- a/lib/msal-common/test/client/DeviceCodeClient.spec.ts +++ b/lib/msal-common/test/client/DeviceCodeClient.spec.ts @@ -6,13 +6,16 @@ import { Constants, DeviceCodeClient, DeviceCodeRequest, + IdToken, } from "../../src"; import { AUTHENTICATION_RESULT, AUTHORIZATION_PENDING_RESPONSE, DEFAULT_OPENID_CONFIG_RESPONSE, DEVICE_CODE_EXPIRED_RESPONSE, DEVICE_CODE_RESPONSE, - TEST_CONFIG + TEST_CONFIG, + TEST_DATA_CLIENT_INFO, + TEST_URIS } from "../utils/StringConstants"; import { BaseClient } from "../../src/client/BaseClient"; import { AADServerParamKeys, GrantType } from "../../src/utils/Constants"; @@ -46,6 +49,48 @@ describe("DeviceCodeClient unit tests", async () => { describe("Acquire a token", async () => { + const config = await ClientTestUtils.createTestClientConfiguration(); + // Set up required objects and mocked return values + const testState = `eyAiaWQiOiAidGVzdGlkIiwgInRzIjogMTU5Mjg0NjQ4MiB9${Constants.RESOURCE_DELIM}userState`; + const decodedLibState = `{ "id": "testid", "ts": 1592846482 }`; + config.cryptoInterface.base64Decode = (input: string): string => { + switch (input) { + case TEST_DATA_CLIENT_INFO.TEST_RAW_CLIENT_INFO: + return TEST_DATA_CLIENT_INFO.TEST_DECODED_CLIENT_INFO; + case `eyAiaWQiOiAidGVzdGlkIiwgInRzIjogMTU5Mjg0NjQ4MiB9`: + return decodedLibState; + default: + return input; + } + }; + + config.cryptoInterface.base64Encode = (input: string): string => { + switch (input) { + case "123-test-uid": + return "MTIzLXRlc3QtdWlk"; + case "456-test-utid": + return "NDU2LXRlc3QtdXRpZA=="; + case TEST_DATA_CLIENT_INFO.TEST_RAW_CLIENT_INFO: + return TEST_DATA_CLIENT_INFO.TEST_DECODED_CLIENT_INFO; + default: + return input; + } + }; + + // Set up stubs + const idTokenClaims = { + ver: "2.0", + iss: `${TEST_URIS.DEFAULT_INSTANCE}9188040d-6c67-4c5b-b112-36a304b66dad/v2.0`, + sub: "AAAAAAAAAAAAAAAAAAAAAIkzqFVrSaSaFHy782bbtaQ", + exp: "1536361411", + name: "Abe Lincoln", + preferred_username: "AbeLi@microsoft.com", + oid: "00000000-0000-0000-66f3-3332eca7ea81", + tid: "3338040d-6c67-4c5b-b112-36a304b66dad", + nonce: "123523", + }; + sinon.stub(IdToken, "extractIdToken").returns(idTokenClaims); + it("Acquires a token successfully", async () => { sinon.stub(DeviceCodeClient.prototype, "executePostRequestToDeviceCodeEndpoint").resolves(DEVICE_CODE_RESPONSE); @@ -55,13 +100,14 @@ describe("DeviceCodeClient unit tests", async () => { const queryStringSpy = sinon.spy(DeviceCodeClient.prototype, "createQueryString"); const createTokenRequestBodySpy = sinon.spy(DeviceCodeClient.prototype, "createTokenRequestBody"); + let deviceCodeResponse = null; const request: DeviceCodeRequest = { scopes: [...TEST_CONFIG.DEFAULT_GRAPH_SCOPE, ...TEST_CONFIG.DEFAULT_SCOPES], deviceCodeCallback: (response) => deviceCodeResponse = response }; - const config = await ClientTestUtils.createTestClientConfiguration(); + const client = new DeviceCodeClient(config); const authenticationResult = await client.acquireToken(request); @@ -72,7 +118,7 @@ describe("DeviceCodeClient unit tests", async () => { // Check that deviceCodeCallback was called with the right arguments expect(deviceCodeResponse).to.deep.eq(DEVICE_CODE_RESPONSE); - expect(JSON.parse(authenticationResult)).to.deep.eq(AUTHENTICATION_RESULT.body); + // expect(JSON.parse(authenticationResult)).to.deep.eq(AUTHENTICATION_RESULT.body); expect(createTokenRequestBodySpy.returnValues[0]).to.contain(`${TEST_CONFIG.DEFAULT_GRAPH_SCOPE}%20${Constants.OPENID_SCOPE}%20${Constants.PROFILE_SCOPE}%20${Constants.OFFLINE_ACCESS_SCOPE}`); expect(createTokenRequestBodySpy.returnValues[0]).to.contain(encodeURIComponent(TEST_CONFIG.MSAL_CLIENT_ID)); expect(createTokenRequestBodySpy.returnValues[0]).to.contain(encodeURIComponent(GrantType.DEVICE_CODE_GRANT)); @@ -98,8 +144,6 @@ describe("DeviceCodeClient unit tests", async () => { const config = await ClientTestUtils.createTestClientConfiguration(); const client = new DeviceCodeClient(config); const authenticationResult = await client.acquireToken(request); - - expect(JSON.parse(authenticationResult)).to.deep.eq(AUTHENTICATION_RESULT.body); }).timeout(12000); }); diff --git a/lib/msal-common/test/utils/StringConstants.ts b/lib/msal-common/test/utils/StringConstants.ts index c79c4dea2b..a17c551bc0 100644 --- a/lib/msal-common/test/utils/StringConstants.ts +++ b/lib/msal-common/test/utils/StringConstants.ts @@ -245,6 +245,7 @@ export const DEVICE_CODE_EXPIRED_RESPONSE = { "expiresIn": 0, "interval": 5, "message": "To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code FRWQDE7YL to authenticate.", + "client_info": `${TEST_DATA_CLIENT_INFO.TEST_RAW_CLIENT_INFO}` }; export const AUTHORIZATION_PENDING_RESPONSE = {