Generate the OIDC redirect URI from the URLRouter

This also saves the redirectUri during the flow
This commit is contained in:
Quentin Gliech 2022-03-03 15:16:43 +01:00
parent 4b07f04843
commit bbfa6de6dc
No known key found for this signature in database
GPG Key ID: 22D62B84552719FC
5 changed files with 25 additions and 7 deletions

View File

@ -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) {

View File

@ -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),
]);

View File

@ -152,6 +152,10 @@ export class URLRouter<T extends {session: string | boolean}> implements IURLRou
return window.location.origin;
}
createOIDCRedirectURL(): string {
return window.location.origin;
}
normalizeUrl(): void {
// Remove any queryParameters from the URL
// Gets rid of the loginToken after SSO

View File

@ -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

View File

@ -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<BearerToken> {
redirectUri,
}: { codeVerifier: string, code: string, redirectUri: string }): Promise<BearerToken> {
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();