OIDC: Redirect to delegated auth provider when signing out (#11432)

* util for account url

* test cases

* disable multi session selection on device list

* remove sign out all from context menus when oidc-aware

* comment

* remove unused param

* redirect to auth provider when signing out

* open auth provider in new tab, refresh sessions on return

* correct comment

* fix bad copy paste

* try to make sonar happy

* Update for latest revision of MSCs

* Update SessionManagerTab-test.tsx

* Make InteractiveAuthCallback async and await it

---------

Co-authored-by: Hugh Nimmo-Smith <hughns@matrix.org>
Co-authored-by: Hugh Nimmo-Smith <hughns@users.noreply.github.com>
Co-authored-by: Andy Balaam <andy.balaam@matrix.org>
This commit is contained in:
Kerry 2023-08-22 23:15:35 +12:00 committed by GitHub
parent 5c1b62cf99
commit 23196d49e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 199 additions and 44 deletions

View file

@ -55,6 +55,9 @@ import { getClientInformationEventType } from "../../../../../../src/utils/devic
mockPlatformPeg();
// to restore later
const realWindowLocation = window.location;
describe("<SessionManagerTab />", () => {
const aliceId = "@alice:server.org";
const deviceId = "alices_device";
@ -166,7 +169,7 @@ describe("<SessionManagerTab />", () => {
confirm = true,
): Promise<void> => {
// modal has sleeps in rendering process :(
await sleep(100);
await screen.findByRole("dialog");
const buttonId = confirm ? "dialog-primary-button" : "dialog-cancel-button";
fireEvent.click(getByTestId(buttonId));
@ -227,11 +230,23 @@ describe("<SessionManagerTab />", () => {
}
});
// @ts-ignore allow delete of non-optional prop
delete window.location;
// @ts-ignore ugly mocking
window.location = {
href: "https://localhost/",
origin: "https://localhost/",
};
// sometimes a verification modal is in modal state when these tests run
// make sure the coast is clear
await clearAllModals();
});
afterAll(() => {
window.location = realWindowLocation;
});
it("renders spinner while devices load", () => {
const { container } = render(getComponent());
expect(container.getElementsByClassName("mx_Spinner").length).toBeTruthy();
@ -858,7 +873,7 @@ describe("<SessionManagerTab />", () => {
await flushPromises();
// modal rendering has some weird sleeps
await sleep(100);
await screen.findByRole("dialog");
expect(mockClient.deleteMultipleDevices).toHaveBeenCalledWith(
[alicesMobileDevice.device_id],
@ -1082,19 +1097,10 @@ describe("<SessionManagerTab />", () => {
});
describe("other devices", () => {
// signing out a single device still works
// this test will be updated once redirect to MAS is added
// https://github.com/vector-im/element-web/issues/26000
it("deletes a device when interactive auth is not required", async () => {
mockClient.deleteMultipleDevices.mockResolvedValue({});
mockClient.getDevices
.mockResolvedValueOnce({
devices: [alicesDevice, alicesMobileDevice, alicesOlderMobileDevice],
})
// pretend it was really deleted on refresh
.mockResolvedValueOnce({
devices: [alicesDevice, alicesOlderMobileDevice],
});
it("opens delegated auth provider to sign out a single device", async () => {
mockClient.getDevices.mockResolvedValue({
devices: [alicesDevice, alicesMobileDevice, alicesOlderMobileDevice],
});
const { getByTestId } = render(getComponent());
@ -1102,6 +1108,9 @@ describe("<SessionManagerTab />", () => {
await flushPromises();
});
// reset call count
mockClient.getDevices.mockClear();
toggleDeviceDetails(getByTestId, alicesMobileDevice.device_id);
const deviceDetails = getByTestId(`device-detail-${alicesMobileDevice.device_id}`);
@ -1110,23 +1119,28 @@ describe("<SessionManagerTab />", () => {
) as Element;
fireEvent.click(signOutButton);
await confirmSignout(getByTestId);
// sign out button is disabled with spinner
await screen.findByRole("dialog");
expect(
(
deviceDetails.querySelector('[data-testid="device-detail-sign-out-cta"]') as Element
).getAttribute("aria-disabled"),
).toEqual("true");
// delete called
expect(mockClient.deleteMultipleDevices).toHaveBeenCalledWith(
[alicesMobileDevice.device_id],
undefined,
screen.getByText(
"You will be redirected to your server's authentication provider to complete sign out.",
),
).toBeInTheDocument();
// correct link to auth provider
expect(screen.getByText("Continue")).toHaveAttribute(
"href",
`https://issuer.org/account?action=session_end&device_id=${alicesMobileDevice.device_id}`,
);
// go to the link
fireEvent.click(screen.getByText("Continue"));
await flushPromises();
// come back from the link and close the modal
fireEvent.click(screen.getByText("Close"));
await flushPromises();
// devices refreshed
// devices were refreshed
expect(mockClient.getDevices).toHaveBeenCalled();
});