OIDC: use delegated auth account URL from OidcClientStore (#11723)

* test persistCredentials without a pickle key

* test setLoggedIn with pickle key

* lint

* type error

* extract token persisting code into function, persist refresh token

* store has_refresh_token too

* pass refreshToken from oidcAuthGrant into credentials

* rest restore session with pickle key

* retreive stored refresh token and add to credentials

* extract token decryption into function

* remove TODO

* very messy poc

* utils to persist clientId and issuer after oidc authentication

* add dep oidc-client-ts

* persist issuer and clientId after successful oidc auth

* add OidcClientStore

* comments and tidy

* expose getters for stored refresh and access tokens in Lifecycle

* revoke tokens with oidc provider

* test logout action in MatrixChat

* comments

* prettier

* test OidcClientStore.revokeTokens

* put pickle key destruction back

* comment pedantry

* working refresh without persistence

* extract token persistence functions to utils

* add sugar

* implement TokenRefresher class with persistence

* tidying

* persist idTokenClaims

* persist idTokenClaims

* tests

* remove unused cde

* create token refresher during doSetLoggedIn

* tidying

* also tidying

* OidcClientStore.initClient use stored issuer when client well known unavailable

* test Lifecycle.logout

* update Lifecycle test replaceUsingCreds calls

* fix test

* add sdkContext to UserSettingsDialog

* use sdkContext and oidcClientStore in session manager

* use sdkContext and OidcClientStore in generalusersettingstab

* tidy

* test tokenrefresher creation in login flow

* test token refresher

* Update src/utils/oidc/TokenRefresher.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* use literal value for m.authentication

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* improve comments

* fix test mock, comment

* typo

* add sdkContext to SoftLogout, pass oidcClientStore to logout

* fullstops

* comments

* fussy comment formatting

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
This commit is contained in:
Kerry 2023-10-16 12:03:25 +13:00 committed by GitHub
parent 84ca519b3f
commit d9d52fba8c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 96 additions and 179 deletions

View file

@ -13,11 +13,11 @@ limitations under the License.
import { fireEvent, render, screen, within } from "@testing-library/react";
import React from "react";
import { M_AUTHENTICATION, ThreepidMedium } from "matrix-js-sdk/src/matrix";
import { ThreepidMedium } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import GeneralUserSettingsTab from "../../../../../../src/components/views/settings/tabs/user/GeneralUserSettingsTab";
import MatrixClientContext from "../../../../../../src/contexts/MatrixClientContext";
import { SdkContextClass, SDKContext } from "../../../../../../src/contexts/SDKContext";
import SettingsStore from "../../../../../../src/settings/SettingsStore";
import {
getMockClientWithEventEmitter,
@ -28,6 +28,7 @@ import {
} from "../../../../../test-utils";
import { UIFeature } from "../../../../../../src/settings/UIFeature";
import { SettingLevel } from "../../../../../../src/settings/SettingLevel";
import { OidcClientStore } from "../../../../../../src/stores/oidc/OidcClientStore";
describe("<GeneralUserSettingsTab />", () => {
const defaultProps = {
@ -44,19 +45,18 @@ describe("<GeneralUserSettingsTab />", () => {
deleteThreePid: jest.fn(),
});
const getComponent = () => (
<MatrixClientContext.Provider value={mockClient}>
<GeneralUserSettingsTab {...defaultProps} />
</MatrixClientContext.Provider>
);
let stores: SdkContextClass;
const clientWellKnownSpy = jest.spyOn(mockClient, "getClientWellKnown");
const getComponent = () => (
<SDKContext.Provider value={stores}>
<GeneralUserSettingsTab {...defaultProps} />
</SDKContext.Provider>
);
beforeEach(() => {
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
mockPlatformPeg();
jest.clearAllMocks();
clientWellKnownSpy.mockReturnValue({});
jest.spyOn(SettingsStore, "getValue").mockRestore();
jest.spyOn(logger, "error").mockRestore();
@ -67,6 +67,12 @@ describe("<GeneralUserSettingsTab />", () => {
mockClient.deleteThreePid.mockResolvedValue({
id_server_unbind_result: "success",
});
stores = new SdkContextClass();
stores.client = mockClient;
// stub out this store completely to avoid mocking initialisation
const mockOidcClientStore = {} as unknown as OidcClientStore;
jest.spyOn(stores, "oidcClientStore", "get").mockReturnValue(mockOidcClientStore);
});
it("does not show account management link when not available", () => {
@ -78,12 +84,11 @@ describe("<GeneralUserSettingsTab />", () => {
it("show account management link in expected format", async () => {
const accountManagementLink = "https://id.server.org/my-account";
clientWellKnownSpy.mockReturnValue({
[M_AUTHENTICATION.name]: {
issuer: "https://id.server.org",
account: accountManagementLink,
},
});
const mockOidcClientStore = {
accountManagementEndpoint: accountManagementLink,
} as unknown as OidcClientStore;
jest.spyOn(stores, "oidcClientStore", "get").mockReturnValue(mockOidcClientStore);
const { getByTestId } = render(getComponent());
// wait for well-known call to settle
@ -167,12 +172,11 @@ describe("<GeneralUserSettingsTab />", () => {
(settingName) => settingName === UIFeature.Deactivate,
);
// account is managed externally when we have delegated auth configured
mockClient.getClientWellKnown.mockReturnValue({
[M_AUTHENTICATION.name]: {
issuer: "https://issuer.org",
account: "https://issuer.org/account",
},
});
const accountManagementLink = "https://id.server.org/my-account";
const mockOidcClientStore = {
accountManagementEndpoint: accountManagementLink,
} as unknown as OidcClientStore;
jest.spyOn(stores, "oidcClientStore", "get").mockReturnValue(mockOidcClientStore);
render(getComponent());
await flushPromises();