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 <cmuentes@bitwarden.com>
Co-authored-by: Matt Gibson <mgibson@bitwarden.com>
This commit is contained in:
Carlos J. Muentes 2022-06-01 10:57:24 -04:00 committed by GitHub
parent 0d658ba26d
commit 911cf794f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 34 additions and 16 deletions

View File

@ -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<AuthResult>;
initiateSsoFormPromise: Promise<any>;
initiateSsoFormPromise: Promise<SsoPreValidateResponse>;
onSuccessfulLogin: () => Promise<any>;
onSuccessfulLoginNavigate: () => Promise<any>;
onSuccessfulLoginTwoFactorNavigate: () => Promise<any>;
@ -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<boolean> {
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<string> {
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();

View File

@ -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<Response>;
nativeFetch: (request: Request) => Promise<Response>;
preValidateSso: (identifier: string) => Promise<boolean>;
preValidateSso: (identifier: string) => Promise<SsoPreValidateResponse>;
postCreateSponsorship: (
sponsorshipOrgId: string,

View File

@ -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");
}
}

View File

@ -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<boolean> {
async preValidateSso(identifier: string): Promise<SsoPreValidateResponse> {
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);