From 911cf794f476aba5b35b8dca2a1cc7b877bac209 Mon Sep 17 00:00:00 2001 From: "Carlos J. Muentes" <42616259+cmuentes@users.noreply.github.com> Date: Wed, 1 Jun 2022 10:57:24 -0400 Subject: [PATCH] CSA-2 SSO user interaction token (#780) * Adding token processing for SSO redirect * Update preValidate return type * Remove unreachable code Co-authored-by: Carlos J. Muentes Co-authored-by: Matt Gibson --- angular/src/components/sso.component.ts | 31 +++++++++++-------- common/src/abstractions/api.service.ts | 3 +- .../models/response/ssoPreValidateResponse.ts | 10 ++++++ common/src/services/api.service.ts | 6 ++-- 4 files changed, 34 insertions(+), 16 deletions(-) create mode 100644 common/src/models/response/ssoPreValidateResponse.ts diff --git a/angular/src/components/sso.component.ts b/angular/src/components/sso.component.ts index 51f2cb3b92..9732ce967e 100644 --- a/angular/src/components/sso.component.ts +++ b/angular/src/components/sso.component.ts @@ -14,6 +14,7 @@ import { StateService } from "jslib-common/abstractions/state.service"; import { Utils } from "jslib-common/misc/utils"; import { AuthResult } from "jslib-common/models/domain/authResult"; import { SsoLogInCredentials } from "jslib-common/models/domain/logInCredentials"; +import { SsoPreValidateResponse } from "jslib-common/models/response/ssoPreValidateResponse"; @Directive() export class SsoComponent { @@ -21,7 +22,7 @@ export class SsoComponent { loggingIn = false; formPromise: Promise; - initiateSsoFormPromise: Promise; + initiateSsoFormPromise: Promise; onSuccessfulLogin: () => Promise; onSuccessfulLoginNavigate: () => Promise; onSuccessfulLoginTwoFactorNavigate: () => Promise; @@ -85,28 +86,30 @@ export class SsoComponent { } async submit(returnUri?: string, includeUserIdentifier?: boolean) { - this.initiateSsoFormPromise = this.preValidate(); - if (await this.initiateSsoFormPromise) { - const authorizeUrl = await this.buildAuthorizeUrl(returnUri, includeUserIdentifier); - this.platformUtilsService.launchUri(authorizeUrl, { sameWindow: true }); - } - } - - async preValidate(): Promise { if (this.identifier == null || this.identifier === "") { this.platformUtilsService.showToast( "error", this.i18nService.t("ssoValidationFailed"), this.i18nService.t("ssoIdentifierRequired") ); - return false; + return; } - return await this.apiService.preValidateSso(this.identifier); + + this.initiateSsoFormPromise = this.apiService.preValidateSso(this.identifier); + const response = await this.initiateSsoFormPromise; + + const authorizeUrl = await this.buildAuthorizeUrl( + returnUri, + includeUserIdentifier, + response.token + ); + this.platformUtilsService.launchUri(authorizeUrl, { sameWindow: true }); } protected async buildAuthorizeUrl( returnUri?: string, - includeUserIdentifier?: boolean + includeUserIdentifier?: boolean, + token?: string ): Promise { let codeChallenge = this.codeChallenge; let state = this.state; @@ -156,7 +159,9 @@ export class SsoComponent { "&" + "code_challenge_method=S256&response_mode=query&" + "domain_hint=" + - encodeURIComponent(this.identifier); + encodeURIComponent(this.identifier) + + "&ssoToken=" + + encodeURIComponent(token); if (includeUserIdentifier) { const userIdentifier = await this.apiService.getSsoUserIdentifier(); diff --git a/common/src/abstractions/api.service.ts b/common/src/abstractions/api.service.ts index 5a99589210..21a5373aa7 100644 --- a/common/src/abstractions/api.service.ts +++ b/common/src/abstractions/api.service.ts @@ -6,6 +6,7 @@ import { OrganizationConnectionConfigApis, OrganizationConnectionResponse, } from "jslib-common/models/response/organizationConnectionResponse"; +import { SsoPreValidateResponse } from "jslib-common/models/response/ssoPreValidateResponse"; import { PolicyType } from "../enums/policyType"; import { SetKeyConnectorKeyRequest } from "../models/request/account/setKeyConnectorKeyRequest"; @@ -688,7 +689,7 @@ export abstract class ApiService { fetch: (request: Request) => Promise; nativeFetch: (request: Request) => Promise; - preValidateSso: (identifier: string) => Promise; + preValidateSso: (identifier: string) => Promise; postCreateSponsorship: ( sponsorshipOrgId: string, diff --git a/common/src/models/response/ssoPreValidateResponse.ts b/common/src/models/response/ssoPreValidateResponse.ts new file mode 100644 index 0000000000..1b403e522c --- /dev/null +++ b/common/src/models/response/ssoPreValidateResponse.ts @@ -0,0 +1,10 @@ +import { BaseResponse } from "./baseResponse"; + +export class SsoPreValidateResponse extends BaseResponse { + token: string; + + constructor(response: any) { + super(response); + this.token = this.getResponseProperty("Token"); + } +} diff --git a/common/src/services/api.service.ts b/common/src/services/api.service.ts index 17e98d733e..2e0e3b92cf 100644 --- a/common/src/services/api.service.ts +++ b/common/src/services/api.service.ts @@ -9,6 +9,7 @@ import { OrganizationConnectionConfigApis, OrganizationConnectionResponse, } from "jslib-common/models/response/organizationConnectionResponse"; +import { SsoPreValidateResponse } from "jslib-common/models/response/ssoPreValidateResponse"; import { ApiService as ApiServiceAbstraction } from "../abstractions/api.service"; import { EnvironmentService } from "../abstractions/environment.service"; @@ -2295,7 +2296,7 @@ export class ApiService implements ApiServiceAbstraction { return fetch(request); } - async preValidateSso(identifier: string): Promise { + async preValidateSso(identifier: string): Promise { if (identifier == null || identifier === "") { throw new Error("Organization Identifier was not provided."); } @@ -2318,7 +2319,8 @@ export class ApiService implements ApiServiceAbstraction { ); if (response.status === 200) { - return true; + const body = await response.json(); + return new SsoPreValidateResponse(body); } else { const error = await this.handleError(response, false, true); return Promise.reject(error);