From 55d982a5383120a46c577cb755da6ee6e8425c55 Mon Sep 17 00:00:00 2001 From: Lester Choi Date: Wed, 18 Oct 2023 19:08:31 -0400 Subject: [PATCH] fix: launch-authenticator relatesTo work-around (#1466) OKTA-659175 fix: launch-authenticator relatesTo work-around --- CHANGELOG.md | 6 + lib/idx/idxState/v1/idxResponseParser.ts | 13 +- package.json | 2 +- .../safari-relatesTo-fixed-response.json | 143 ++++++++++++++++++ .../mocks/safari-relatesTo-response.json | 135 +++++++++++++++++ .../unit/v1/idxResponseParser.test.js | 26 ++++ 6 files changed, 323 insertions(+), 2 deletions(-) create mode 100644 test/spec/idx/idxState/mocks/safari-relatesTo-fixed-response.json create mode 100644 test/spec/idx/idxState/mocks/safari-relatesTo-response.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dc2f6cc9..1688c2f93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 7.4.3 + +### Bug Fix + +- [#1466](https://github.com/okta/okta-auth-js/pull/1466) Fix: Issues with `launch-authenticator` rememdiation on safari + ## 7.4.2 ### Bug Fix diff --git a/lib/idx/idxState/v1/idxResponseParser.ts b/lib/idx/idxState/v1/idxResponseParser.ts index c5db593ab..27a1e841d 100644 --- a/lib/idx/idxState/v1/idxResponseParser.ts +++ b/lib/idx/idxState/v1/idxResponseParser.ts @@ -113,7 +113,18 @@ export const parseIdxResponse = function parseIdxResponse( authClient: OktaAuthI const remediationData = idxResponse.remediation?.value || []; remediationData.forEach( - remediation => expandRelatesTo(idxResponse, remediation) + remediation => { + // TODO: remove once IDX is fixed - OKTA-659181 + if (remediation.name === 'launch-authenticator' && + remediation?.relatesTo?.[0] === 'authenticatorChallenge' && + !idxResponse?.authenticatorChallenge + ) { + delete remediation.relatesTo; + return; + } + + return expandRelatesTo(idxResponse, remediation); + } ); const remediations = remediationData.map(remediation => convertRemediationAction( authClient, remediation, toPersist )); diff --git a/package.json b/package.json index fba0f97a6..ad82d0f26 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "private": true, "name": "@okta/okta-auth-js", "description": "The Okta Auth SDK", - "version": "7.4.2", + "version": "7.4.3", "homepage": "https://github.com/okta/okta-auth-js", "license": "Apache-2.0", "main": "build/cjs/exports/default.js", diff --git a/test/spec/idx/idxState/mocks/safari-relatesTo-fixed-response.json b/test/spec/idx/idxState/mocks/safari-relatesTo-fixed-response.json new file mode 100644 index 000000000..578d7ec7a --- /dev/null +++ b/test/spec/idx/idxState/mocks/safari-relatesTo-fixed-response.json @@ -0,0 +1,143 @@ +{ + "version": "1.0.0", + "stateHandle": "stateHandle", + "expiresAt": "2023-10-18T18:18:41.000Z", + "intent": "LOGIN", + "remediation": { + "type": "array", + "value": [ + { + "rel": [ + "create-form" + ], + "name": "identify", + "href": "http://localhost:3000.com/idp/idx/identify", + "method": "POST", + "produces": "application/ion+json; okta-version=1.0.0", + "value": [ + { + "name": "identifier", + "label": "Username", + "required": true + }, + { + "name": "rememberMe", + "type": "boolean", + "label": "Remember this device" + }, + { + "name": "stateHandle", + "required": true, + "value": "stateHande", + "visible": false, + "mutable": false + } + ], + "accepts": "application/json; okta-version=1.0.0" + }, + { + "rel": [ + "create-form" + ], + "name": "launch-authenticator", + "relatesTo": [ + "authenticatorChallenge" + ], + "href": "http://localhost:3000.com/idp/idx/authenticators/okta-verify/launch", + "method": "POST", + "produces": "application/ion+json; okta-version=1.0.0", + "value": [ + { + "name": "rememberMe", + "type": "boolean", + "label": "Remember this device" + }, + { + "name": "stateHandle", + "required": true, + "value": "stateHande", + "visible": false, + "mutable": false + } + ], + "accepts": "application/json; okta-version=1.0.0" + }, + { + "rel": [ + "create-form" + ], + "name": "select-enroll-profile", + "href": "http://localhost:3000.com/idp/idx/enroll", + "method": "POST", + "produces": "application/ion+json; okta-version=1.0.0", + "value": [ + { + "name": "stateHandle", + "required": true, + "value": "stateHande", + "visible": false, + "mutable": false + } + ], + "accepts": "application/json; okta-version=1.0.0" + } + ] + }, + "cancel": { + "rel": [ + "create-form" + ], + "name": "cancel", + "href": "http://localhost:3000.com/idp/idx/cancel", + "method": "POST", + "produces": "application/ion+json; okta-version=1.0.0", + "value": [ + { + "name": "stateHandle", + "required": true, + "value": "stateHande", + "visible": false, + "mutable": false + } + ], + "accepts": "application/json; okta-version=1.0.0" + }, + "app": { + "type": "object", + "value": { + "name": "okta_enduser", + "label": "Okta Dashboard", + "id": "srhgsefasef" + } + }, + "authentication": { + "type": "object", + "value": { + "protocol": "OAUTH2.0", + "issuer": { + "name": "Mock", + "uri": "http://localhost:3000.com" + }, + "request": { + "max_age": -1, + "scope": "openid profile email", + "display": "page", + "response_type": "code", + "redirect_uri": "http://localhost:3000.com/enduser/callback", + "state": "stateValue", + "code_challenge_method": "S256", + "nonce": "nonceValue", + "code_challenge": "code_challenge", + "response_mode": "query" + } + } + }, + "authenticatorChallenge": { + "type": "object", + "value": { + "challengeMethod": "CUSTOM_URI", + "href": "http://localhost:3000/foobar", + "downloadHref": "http://localhost:3000/foobar" + } + } +} diff --git a/test/spec/idx/idxState/mocks/safari-relatesTo-response.json b/test/spec/idx/idxState/mocks/safari-relatesTo-response.json new file mode 100644 index 000000000..537d10959 --- /dev/null +++ b/test/spec/idx/idxState/mocks/safari-relatesTo-response.json @@ -0,0 +1,135 @@ +{ + "version": "1.0.0", + "stateHandle": "stateHandle", + "expiresAt": "2023-10-18T18:18:41.000Z", + "intent": "LOGIN", + "remediation": { + "type": "array", + "value": [ + { + "rel": [ + "create-form" + ], + "name": "identify", + "href": "http://localhost:3000.com/idp/idx/identify", + "method": "POST", + "produces": "application/ion+json; okta-version=1.0.0", + "value": [ + { + "name": "identifier", + "label": "Username", + "required": true + }, + { + "name": "rememberMe", + "type": "boolean", + "label": "Remember this device" + }, + { + "name": "stateHandle", + "required": true, + "value": "stateHande", + "visible": false, + "mutable": false + } + ], + "accepts": "application/json; okta-version=1.0.0" + }, + { + "rel": [ + "create-form" + ], + "name": "launch-authenticator", + "relatesTo": [ + "authenticatorChallenge" + ], + "href": "http://localhost:3000.com/idp/idx/authenticators/okta-verify/launch", + "method": "POST", + "produces": "application/ion+json; okta-version=1.0.0", + "value": [ + { + "name": "rememberMe", + "type": "boolean", + "label": "Remember this device" + }, + { + "name": "stateHandle", + "required": true, + "value": "stateHande", + "visible": false, + "mutable": false + } + ], + "accepts": "application/json; okta-version=1.0.0" + }, + { + "rel": [ + "create-form" + ], + "name": "select-enroll-profile", + "href": "http://localhost:3000.com/idp/idx/enroll", + "method": "POST", + "produces": "application/ion+json; okta-version=1.0.0", + "value": [ + { + "name": "stateHandle", + "required": true, + "value": "stateHande", + "visible": false, + "mutable": false + } + ], + "accepts": "application/json; okta-version=1.0.0" + } + ] + }, + "cancel": { + "rel": [ + "create-form" + ], + "name": "cancel", + "href": "http://localhost:3000.com/idp/idx/cancel", + "method": "POST", + "produces": "application/ion+json; okta-version=1.0.0", + "value": [ + { + "name": "stateHandle", + "required": true, + "value": "stateHande", + "visible": false, + "mutable": false + } + ], + "accepts": "application/json; okta-version=1.0.0" + }, + "app": { + "type": "object", + "value": { + "name": "okta_enduser", + "label": "Okta Dashboard", + "id": "srhgsefasef" + } + }, + "authentication": { + "type": "object", + "value": { + "protocol": "OAUTH2.0", + "issuer": { + "name": "Mock", + "uri": "http://localhost:3000.com" + }, + "request": { + "max_age": -1, + "scope": "openid profile email", + "display": "page", + "response_type": "code", + "redirect_uri": "http://localhost:3000.com/enduser/callback", + "state": "stateValue", + "code_challenge_method": "S256", + "nonce": "nonceValue", + "code_challenge": "code_challenge", + "response_mode": "query" + } + } + } +} diff --git a/test/spec/idx/idxState/unit/v1/idxResponseParser.test.js b/test/spec/idx/idxState/unit/v1/idxResponseParser.test.js index ebca3de59..9327f205e 100644 --- a/test/spec/idx/idxState/unit/v1/idxResponseParser.test.js +++ b/test/spec/idx/idxState/unit/v1/idxResponseParser.test.js @@ -21,6 +21,10 @@ const mockComplexContextIdxResponse = require('../../mocks/poll-for-password'); const mockTerminalIdxResponse = require('../../mocks/terminal-return-email'); const mockMessageIdxResponse = require('../../mocks/unknown-user'); const mockSuccessIdxResponse = require('../../mocks/success'); +// TODO: OKTA-659181 +const mockSafariRelatesToResponse = require('../../mocks/safari-relatesTo-response'); +const mockResponseWithFix = require('../../mocks/safari-relatesTo-fixed-response'); + const mockIdxResponseWithBadRelationship = () => { const mock = require('../../mocks/authenticator-verification-password'); mock.remediation.value[1].value[0].options[0].relatesTo = '$.authenticatorEnrollments.value[999]'; @@ -173,5 +177,27 @@ describe('idxResponseParser', () => { const fn = () => parseIdxResponse( {}, mockIdxResponseWithBadRelationship() ); expect(fn).toThrowError('Cannot resolve relatesTo: $.authenticatorEnrollments.value[999]'); }); + + // TODO: OKTA-659181 + describe('OKTA-659175', () => { + it('removes `relatesTo` when reference is invalid', () => { + const { remediations } = parseIdxResponse({}, mockSafariRelatesToResponse, {}); + expect(remediations[1].name).toEqual('launch-authenticator'); + expect(remediations[1].relatesTo).toBeUndefined(); + }); + + it('resolves `relatesTo` when reference is valid', () => { + const { remediations } = parseIdxResponse({}, mockResponseWithFix, {}); + expect(remediations[1].name).toEqual('launch-authenticator'); + expect(remediations[1].relatesTo).toEqual({ + 'type': 'object', + 'value': { + 'challengeMethod': 'CUSTOM_URI', + 'href': 'http://localhost:3000/foobar', + 'downloadHref': 'http://localhost:3000/foobar' + } + }); + }); + }); }); });