Skip to content

Commit 01bd80f

Browse files
author
Kerry
authored
OIDC: update to oidc-client-ts functions from js-sdk (matrix-org#11193)
* test util for oidcclientconfigs * rename type and lint * correct oidc test util * store issuer and clientId pre auth navigation * update for js-sdk userstate, tidy
1 parent 1a75d5d commit 01bd80f

File tree

5 files changed

+91
-78
lines changed

5 files changed

+91
-78
lines changed

src/utils/AutoDiscoveryUtils.tsx

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ limitations under the License.
1515
*/
1616

1717
import React, { ReactNode } from "react";
18-
import { AutoDiscovery, ClientConfig } from "matrix-js-sdk/src/autodiscovery";
18+
import { AutoDiscovery, ClientConfig, OidcClientConfig } from "matrix-js-sdk/src/autodiscovery";
1919
import { M_AUTHENTICATION } from "matrix-js-sdk/src/client";
2020
import { logger } from "matrix-js-sdk/src/logger";
2121
import { IClientWellKnown } from "matrix-js-sdk/src/matrix";
2222

2323
import { _t, UserFriendlyError } from "../languageHandler";
2424
import SdkConfig from "../SdkConfig";
25-
import { ValidatedDelegatedAuthConfig, ValidatedServerConfig } from "./ValidatedServerConfig";
25+
import { ValidatedServerConfig } from "./ValidatedServerConfig";
2626

2727
const LIVELINESS_DISCOVERY_ERRORS: string[] = [
2828
AutoDiscovery.ERROR_INVALID_HOMESERVER,
@@ -259,25 +259,25 @@ export default class AutoDiscoveryUtils {
259259
throw new UserFriendlyError("Unexpected error resolving homeserver configuration");
260260
}
261261

262-
let delegatedAuthentication:
263-
| {
264-
authorizationEndpoint: string;
265-
registrationEndpoint?: string;
266-
tokenEndpoint: string;
267-
account?: string;
268-
issuer: string;
269-
}
270-
| undefined;
262+
let delegatedAuthentication: OidcClientConfig | undefined;
271263
if (discoveryResult[M_AUTHENTICATION.stable!]?.state === AutoDiscovery.SUCCESS) {
272-
const { authorizationEndpoint, registrationEndpoint, tokenEndpoint, account, issuer } = discoveryResult[
273-
M_AUTHENTICATION.stable!
274-
] as ValidatedDelegatedAuthConfig;
264+
const {
265+
authorizationEndpoint,
266+
registrationEndpoint,
267+
tokenEndpoint,
268+
account,
269+
issuer,
270+
metadata,
271+
signingKeys,
272+
} = discoveryResult[M_AUTHENTICATION.stable!] as OidcClientConfig;
275273
delegatedAuthentication = Object.freeze({
276274
authorizationEndpoint,
277275
registrationEndpoint,
278276
tokenEndpoint,
279277
account,
280278
issuer,
279+
metadata,
280+
signingKeys,
281281
});
282282
}
283283

src/utils/ValidatedServerConfig.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17+
import { OidcClientConfig } from "matrix-js-sdk/src/autodiscovery";
1718
import { IDelegatedAuthConfig } from "matrix-js-sdk/src/client";
1819
import { ValidatedIssuerConfig } from "matrix-js-sdk/src/oidc/validate";
1920

@@ -38,5 +39,5 @@ export interface ValidatedServerConfig {
3839
* From homeserver .well-known m.authentication, and issuer's .well-known/openid-configuration
3940
* Used for OIDC native flow authentication
4041
*/
41-
delegatedAuthentication?: ValidatedDelegatedAuthConfig;
42+
delegatedAuthentication?: OidcClientConfig;
4243
}

src/utils/oidc/authorize.ts

Lines changed: 16 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,60 +14,38 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
import {
18-
AuthorizationParams,
19-
generateAuthorizationParams,
20-
generateAuthorizationUrl,
21-
} from "matrix-js-sdk/src/oidc/authorize";
22-
23-
import { ValidatedDelegatedAuthConfig } from "../ValidatedServerConfig";
24-
25-
/**
26-
* Store authorization params for retrieval when returning from OIDC OP
27-
* @param authorizationParams from `generateAuthorizationParams`
28-
* @param delegatedAuthConfig used for future interactions with OP
29-
* @param clientId this client's id as registered with configured issuer
30-
* @param homeserver target homeserver
31-
*/
32-
const storeAuthorizationParams = (
33-
{ redirectUri, state, nonce, codeVerifier }: AuthorizationParams,
34-
{ issuer }: ValidatedDelegatedAuthConfig,
35-
clientId: string,
36-
homeserver: string,
37-
): void => {
38-
window.sessionStorage.setItem(`oidc_${state}_nonce`, nonce);
39-
window.sessionStorage.setItem(`oidc_${state}_redirectUri`, redirectUri);
40-
window.sessionStorage.setItem(`oidc_${state}_codeVerifier`, codeVerifier);
41-
window.sessionStorage.setItem(`oidc_${state}_clientId`, clientId);
42-
window.sessionStorage.setItem(`oidc_${state}_issuer`, issuer);
43-
window.sessionStorage.setItem(`oidc_${state}_homeserver`, homeserver);
44-
};
17+
import { OidcClientConfig } from "matrix-js-sdk/src/autodiscovery";
18+
import { generateOidcAuthorizationUrl } from "matrix-js-sdk/src/oidc/authorize";
19+
import { randomString } from "matrix-js-sdk/src/randomstring";
4520

4621
/**
4722
* Start OIDC authorization code flow
4823
* Generates auth params, stores them in session storage and
4924
* Navigates to configured authorization endpoint
5025
* @param delegatedAuthConfig from discovery
5126
* @param clientId this client's id as registered with configured issuer
52-
* @param homeserver target homeserver
27+
* @param homeserverUrl target homeserver
28+
* @param identityServerUrl OPTIONAL target identity server
5329
* @returns Promise that resolves after we have navigated to auth endpoint
5430
*/
5531
export const startOidcLogin = async (
56-
delegatedAuthConfig: ValidatedDelegatedAuthConfig,
32+
delegatedAuthConfig: OidcClientConfig,
5733
clientId: string,
58-
homeserver: string,
34+
homeserverUrl: string,
35+
identityServerUrl?: string,
5936
): Promise<void> => {
60-
// TODO(kerrya) afterloginfragment https://github.com/vector-im/element-web/issues/25656
6137
const redirectUri = window.location.origin;
62-
const authParams = generateAuthorizationParams({ redirectUri });
6338

64-
storeAuthorizationParams(authParams, delegatedAuthConfig, clientId, homeserver);
39+
const nonce = randomString(10);
6540

66-
const authorizationUrl = await generateAuthorizationUrl(
67-
delegatedAuthConfig.authorizationEndpoint,
41+
const authorizationUrl = await generateOidcAuthorizationUrl({
42+
metadata: delegatedAuthConfig.metadata,
43+
redirectUri,
6844
clientId,
69-
authParams,
70-
);
45+
homeserverUrl,
46+
identityServerUrl,
47+
nonce,
48+
});
7149

7250
window.location.href = authorizationUrl;
7351
};

test/test-utils/oidc.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
Copyright 2023 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { OidcClientConfig } from "matrix-js-sdk/src/autodiscovery";
18+
import { ValidatedIssuerMetadata } from "matrix-js-sdk/src/oidc/validate";
19+
20+
/**
21+
* Makes a valid OidcClientConfig with minimum valid values
22+
* @param issuer used as the base for all other urls
23+
* @returns OidcClientConfig
24+
*/
25+
export const makeDelegatedAuthConfig = (issuer = "https://auth.org/"): OidcClientConfig => {
26+
const metadata = mockOpenIdConfiguration(issuer);
27+
28+
return {
29+
issuer,
30+
account: issuer + "account",
31+
registrationEndpoint: metadata.registration_endpoint,
32+
authorizationEndpoint: metadata.authorization_endpoint,
33+
tokenEndpoint: metadata.token_endpoint,
34+
metadata,
35+
};
36+
};
37+
38+
/**
39+
* Useful for mocking <issuer>/.well-known/openid-configuration
40+
* @param issuer used as the base for all other urls
41+
* @returns ValidatedIssuerMetadata
42+
*/
43+
export const mockOpenIdConfiguration = (issuer = "https://auth.org/"): ValidatedIssuerMetadata => ({
44+
issuer,
45+
revocation_endpoint: issuer + "revoke",
46+
token_endpoint: issuer + "token",
47+
authorization_endpoint: issuer + "auth",
48+
registration_endpoint: issuer + "registration",
49+
jwks_uri: issuer + "jwks",
50+
response_types_supported: ["code"],
51+
grant_types_supported: ["authorization_code", "refresh_token"],
52+
code_challenge_methods_supported: ["S256"],
53+
});

test/utils/oidc/authorize-test.ts

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,17 @@ import fetchMockJest from "fetch-mock-jest";
1818
import * as randomStringUtils from "matrix-js-sdk/src/randomstring";
1919

2020
import { startOidcLogin } from "../../../src/utils/oidc/authorize";
21+
import { makeDelegatedAuthConfig, mockOpenIdConfiguration } from "../../test-utils/oidc";
2122

2223
describe("startOidcLogin()", () => {
2324
const issuer = "https://auth.com/";
24-
const authorizationEndpoint = "https://auth.com/authorization";
2525
const homeserver = "https://matrix.org";
2626
const clientId = "xyz789";
2727
const baseUrl = "https://test.com";
2828

29-
const delegatedAuthConfig = {
30-
issuer,
31-
registrationEndpoint: issuer + "registration",
32-
authorizationEndpoint,
33-
tokenEndpoint: issuer + "token",
34-
};
29+
const delegatedAuthConfig = makeDelegatedAuthConfig(issuer);
3530

3631
const sessionStorageGetSpy = jest.spyOn(sessionStorage.__proto__, "setItem").mockReturnValue(undefined);
37-
const randomStringMockImpl = (length: number) => new Array(length).fill("x").join("");
3832

3933
// to restore later
4034
const realWindowLocation = window.location;
@@ -53,30 +47,17 @@ describe("startOidcLogin()", () => {
5347
origin: baseUrl,
5448
};
5549

50+
fetchMockJest.get(
51+
delegatedAuthConfig.metadata.issuer + ".well-known/openid-configuration",
52+
mockOpenIdConfiguration(),
53+
);
5654
jest.spyOn(randomStringUtils, "randomString").mockRestore();
5755
});
5856

5957
afterAll(() => {
6058
window.location = realWindowLocation;
6159
});
6260

63-
it("should store authorization params in session storage", async () => {
64-
jest.spyOn(randomStringUtils, "randomString").mockReset().mockImplementation(randomStringMockImpl);
65-
await startOidcLogin(delegatedAuthConfig, clientId, homeserver);
66-
67-
const state = randomStringUtils.randomString(8);
68-
69-
expect(sessionStorageGetSpy).toHaveBeenCalledWith(`oidc_${state}_nonce`, randomStringUtils.randomString(8));
70-
expect(sessionStorageGetSpy).toHaveBeenCalledWith(`oidc_${state}_redirectUri`, baseUrl);
71-
expect(sessionStorageGetSpy).toHaveBeenCalledWith(
72-
`oidc_${state}_codeVerifier`,
73-
randomStringUtils.randomString(64),
74-
);
75-
expect(sessionStorageGetSpy).toHaveBeenCalledWith(`oidc_${state}_clientId`, clientId);
76-
expect(sessionStorageGetSpy).toHaveBeenCalledWith(`oidc_${state}_issuer`, issuer);
77-
expect(sessionStorageGetSpy).toHaveBeenCalledWith(`oidc_${state}_homeserver`, homeserver);
78-
});
79-
8061
it("navigates to authorization endpoint with correct parameters", async () => {
8162
await startOidcLogin(delegatedAuthConfig, clientId, homeserver);
8263

0 commit comments

Comments
 (0)