From d723561d661af563f930ed0e69b14dd6ef923f3b Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 3 Mar 2022 15:16:43 +0100 Subject: [PATCH] Generate the OIDC redirect URI from the URLRouter This also saves the redirectUri during the flow --- src/domain/login/CompleteOIDCLoginViewModel.js | 5 +++-- src/domain/login/StartOIDCLoginViewModel.js | 6 +++++- src/domain/navigation/URLRouter.js | 4 ++++ src/matrix/login/OIDCLoginMethod.ts | 5 +++++ src/matrix/net/OidcApi.ts | 12 ++++++++---- 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/domain/login/CompleteOIDCLoginViewModel.js b/src/domain/login/CompleteOIDCLoginViewModel.js index fa0b665e..f3a9c441 100644 --- a/src/domain/login/CompleteOIDCLoginViewModel.js +++ b/src/domain/login/CompleteOIDCLoginViewModel.js @@ -49,10 +49,11 @@ export class CompleteOIDCLoginViewModel extends ViewModel { } const code = this._code; // TODO: cleanup settings storage - const [startedAt, nonce, codeVerifier, homeserver, issuer] = await Promise.all([ + const [startedAt, nonce, codeVerifier, redirectUri, homeserver, issuer] = await Promise.all([ this.platform.settingsStorage.getInt(`oidc_${this._state}_started_at`), this.platform.settingsStorage.getString(`oidc_${this._state}_nonce`), this.platform.settingsStorage.getString(`oidc_${this._state}_code_verifier`), + this.platform.settingsStorage.getString(`oidc_${this._state}_redirect_uri`), this.platform.settingsStorage.getString(`oidc_${this._state}_homeserver`), this.platform.settingsStorage.getString(`oidc_${this._state}_issuer`), ]); @@ -63,7 +64,7 @@ export class CompleteOIDCLoginViewModel extends ViewModel { request: this._request, encoding: this._encoding, }); - const method = new OIDCLoginMethod({oidcApi, nonce, codeVerifier, code, homeserver, startedAt}); + const method = new OIDCLoginMethod({oidcApi, nonce, codeVerifier, code, homeserver, startedAt, redirectUri}); const status = await this._attemptLogin(method); let error = ""; switch (status) { diff --git a/src/domain/login/StartOIDCLoginViewModel.js b/src/domain/login/StartOIDCLoginViewModel.js index 146d81b1..89600d58 100644 --- a/src/domain/login/StartOIDCLoginViewModel.js +++ b/src/domain/login/StartOIDCLoginViewModel.js @@ -44,11 +44,15 @@ export class StartOIDCLoginViewModel extends ViewModel { } async startOIDCLogin() { - const p = this._api.generateParams("openid"); + const p = this._api.generateParams({ + scope: "openid", + redirectUri: this.urlCreator.createOIDCRedirectURL(), + }); await Promise.all([ this.platform.settingsStorage.setInt(`oidc_${p.state}_started_at`, Date.now()), this.platform.settingsStorage.setString(`oidc_${p.state}_nonce`, p.nonce), this.platform.settingsStorage.setString(`oidc_${p.state}_code_verifier`, p.codeVerifier), + this.platform.settingsStorage.setString(`oidc_${p.state}_redirect_uri`, p.redirectUri), this.platform.settingsStorage.setString(`oidc_${p.state}_homeserver`, this._homeserver), this.platform.settingsStorage.setString(`oidc_${p.state}_issuer`, this._issuer), ]); diff --git a/src/domain/navigation/URLRouter.js b/src/domain/navigation/URLRouter.js index 586eec8a..00614951 100644 --- a/src/domain/navigation/URLRouter.js +++ b/src/domain/navigation/URLRouter.js @@ -125,6 +125,10 @@ export class URLRouter { return window.location.origin; } + createOIDCRedirectURL() { + return window.location.origin; + } + normalizeUrl() { // Remove any queryParameters from the URL // Gets rid of the loginToken after SSO diff --git a/src/matrix/login/OIDCLoginMethod.ts b/src/matrix/login/OIDCLoginMethod.ts index 0226877a..1e834b64 100644 --- a/src/matrix/login/OIDCLoginMethod.ts +++ b/src/matrix/login/OIDCLoginMethod.ts @@ -23,6 +23,7 @@ export class OIDCLoginMethod implements ILoginMethod { private readonly _code: string; private readonly _codeVerifier: string; private readonly _nonce: string; + private readonly _redirectUri: string; private readonly _oidcApi: OidcApi; public readonly homeserver: string; @@ -31,18 +32,21 @@ export class OIDCLoginMethod implements ILoginMethod { codeVerifier, code, homeserver, + redirectUri, oidcApi, }: { nonce: string, code: string, codeVerifier: string, homeserver: string, + redirectUri: string, oidcApi: OidcApi, }) { this._oidcApi = oidcApi; this._code = code; this._codeVerifier = codeVerifier; this._nonce = nonce; + this._redirectUri = redirectUri; this.homeserver = homeserver; } @@ -50,6 +54,7 @@ export class OIDCLoginMethod implements ILoginMethod { const { access_token, refresh_token, expires_in } = await this._oidcApi.completeAuthorizationCodeGrant({ code: this._code, codeVerifier: this._codeVerifier, + redirectUri: this._redirectUri, }); // TODO: validate the id_token and the nonce claim diff --git a/src/matrix/net/OidcApi.ts b/src/matrix/net/OidcApi.ts index 3111d65f..3dfe4cdd 100644 --- a/src/matrix/net/OidcApi.ts +++ b/src/matrix/net/OidcApi.ts @@ -39,6 +39,7 @@ const isValidBearerToken = (t: any): t is BearerToken => type AuthorizationParams = { state: string, scope: string, + redirectUri: string, nonce?: string, codeVerifier?: string, }; @@ -118,6 +119,7 @@ export class OidcApi { async authorizationEndpoint({ state, + redirectUri, scope, nonce, codeVerifier, @@ -126,7 +128,7 @@ export class OidcApi { const url = new URL(metadata["authorization_endpoint"]); url.searchParams.append("response_mode", "fragment"); url.searchParams.append("response_type", "code"); - url.searchParams.append("redirect_uri", this.redirectUri); + url.searchParams.append("redirect_uri", redirectUri); url.searchParams.append("client_id", this._clientId); url.searchParams.append("state", state); url.searchParams.append("scope", scope); @@ -147,9 +149,10 @@ export class OidcApi { return metadata["token_endpoint"]; } - generateParams(scope: string): AuthorizationParams { + generateParams({ scope, redirectUri }: { scope: string, redirectUri: string }): AuthorizationParams { return { scope, + redirectUri, state: randomString(8), nonce: randomString(8), codeVerifier: randomString(32), @@ -159,12 +162,13 @@ export class OidcApi { async completeAuthorizationCodeGrant({ codeVerifier, code, - }: { codeVerifier: string, code: string }): Promise { + redirectUri, + }: { codeVerifier: string, code: string, redirectUri: string }): Promise { const params = new URLSearchParams(); params.append("grant_type", "authorization_code"); params.append("client_id", this._clientId); params.append("code_verifier", codeVerifier); - params.append("redirect_uri", this.redirectUri); + params.append("redirect_uri", redirectUri); params.append("code", code); const body = params.toString();