You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-07-30 04:23:07 +03:00
Switch OIDC primarily to new /auth_metadata
API (#4626)
This commit is contained in:
committed by
GitHub
parent
61375ef38a
commit
c0e30ceca0
@ -40,8 +40,8 @@ jest.mock("jwt-decode");
|
||||
|
||||
describe("oidc authorization", () => {
|
||||
const delegatedAuthConfig = makeDelegatedAuthConfig();
|
||||
const authorizationEndpoint = delegatedAuthConfig.authorizationEndpoint;
|
||||
const tokenEndpoint = delegatedAuthConfig.tokenEndpoint;
|
||||
const authorizationEndpoint = delegatedAuthConfig.authorization_endpoint;
|
||||
const tokenEndpoint = delegatedAuthConfig.token_endpoint;
|
||||
const clientId = "xyz789";
|
||||
const baseUrl = "https://test.com";
|
||||
|
||||
@ -52,10 +52,7 @@ describe("oidc authorization", () => {
|
||||
jest.spyOn(logger, "warn");
|
||||
jest.setSystemTime(now);
|
||||
|
||||
fetchMock.get(
|
||||
delegatedAuthConfig.metadata.issuer + ".well-known/openid-configuration",
|
||||
mockOpenIdConfiguration(),
|
||||
);
|
||||
fetchMock.get(delegatedAuthConfig.issuer + ".well-known/openid-configuration", mockOpenIdConfiguration());
|
||||
globalThis.TextEncoder = TextEncoder;
|
||||
});
|
||||
|
||||
@ -127,11 +124,9 @@ describe("oidc authorization", () => {
|
||||
it("should generate url with correct parameters", async () => {
|
||||
const nonce = "abc123";
|
||||
|
||||
const metadata = delegatedAuthConfig.metadata;
|
||||
|
||||
const authUrl = new URL(
|
||||
await generateOidcAuthorizationUrl({
|
||||
metadata,
|
||||
metadata: delegatedAuthConfig,
|
||||
homeserverUrl: baseUrl,
|
||||
clientId,
|
||||
redirectUri: baseUrl,
|
||||
@ -156,11 +151,9 @@ describe("oidc authorization", () => {
|
||||
it("should generate url with create prompt", async () => {
|
||||
const nonce = "abc123";
|
||||
|
||||
const metadata = delegatedAuthConfig.metadata;
|
||||
|
||||
const authUrl = new URL(
|
||||
await generateOidcAuthorizationUrl({
|
||||
metadata,
|
||||
metadata: delegatedAuthConfig,
|
||||
homeserverUrl: baseUrl,
|
||||
clientId,
|
||||
redirectUri: baseUrl,
|
||||
|
@ -42,13 +42,13 @@ describe("registerOidcClient()", () => {
|
||||
});
|
||||
|
||||
it("should make correct request to register client", async () => {
|
||||
fetchMockJest.post(delegatedAuthConfig.registrationEndpoint!, {
|
||||
fetchMockJest.post(delegatedAuthConfig.registration_endpoint!, {
|
||||
status: 200,
|
||||
body: JSON.stringify({ client_id: dynamicClientId }),
|
||||
});
|
||||
expect(await registerOidcClient(delegatedAuthConfig, metadata)).toEqual(dynamicClientId);
|
||||
expect(fetchMockJest).toHaveBeenCalledWith(
|
||||
delegatedAuthConfig.registrationEndpoint!,
|
||||
delegatedAuthConfig.registration_endpoint,
|
||||
expect.objectContaining({
|
||||
headers: {
|
||||
"Accept": "application/json",
|
||||
@ -72,7 +72,7 @@ describe("registerOidcClient()", () => {
|
||||
});
|
||||
|
||||
it("should throw when registration request fails", async () => {
|
||||
fetchMockJest.post(delegatedAuthConfig.registrationEndpoint!, {
|
||||
fetchMockJest.post(delegatedAuthConfig.registration_endpoint!, {
|
||||
status: 500,
|
||||
});
|
||||
await expect(() => registerOidcClient(delegatedAuthConfig, metadata)).rejects.toThrow(
|
||||
@ -81,7 +81,7 @@ describe("registerOidcClient()", () => {
|
||||
});
|
||||
|
||||
it("should throw when registration response is invalid", async () => {
|
||||
fetchMockJest.post(delegatedAuthConfig.registrationEndpoint!, {
|
||||
fetchMockJest.post(delegatedAuthConfig.registration_endpoint!, {
|
||||
status: 200,
|
||||
// no clientId in response
|
||||
body: "{}",
|
||||
@ -96,7 +96,7 @@ describe("registerOidcClient()", () => {
|
||||
registerOidcClient(
|
||||
{
|
||||
...delegatedAuthConfig,
|
||||
registrationEndpoint: undefined,
|
||||
registration_endpoint: undefined,
|
||||
},
|
||||
metadata,
|
||||
),
|
||||
@ -108,10 +108,7 @@ describe("registerOidcClient()", () => {
|
||||
registerOidcClient(
|
||||
{
|
||||
...delegatedAuthConfig,
|
||||
metadata: {
|
||||
...delegatedAuthConfig.metadata,
|
||||
grant_types_supported: [delegatedAuthConfig.metadata.grant_types_supported[0]],
|
||||
},
|
||||
grant_types_supported: [delegatedAuthConfig.grant_types_supported[0]],
|
||||
},
|
||||
metadata,
|
||||
),
|
||||
|
@ -55,8 +55,8 @@ describe("OidcTokenRefresher", () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fetchMock.get(`${config.metadata.issuer}.well-known/openid-configuration`, config.metadata);
|
||||
fetchMock.get(`${config.metadata.issuer}jwks`, {
|
||||
fetchMock.get(`${config.issuer}.well-known/openid-configuration`, config);
|
||||
fetchMock.get(`${config.issuer}jwks`, {
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@ -64,7 +64,7 @@ describe("OidcTokenRefresher", () => {
|
||||
keys: [],
|
||||
});
|
||||
|
||||
fetchMock.post(config.tokenEndpoint, {
|
||||
fetchMock.post(config.token_endpoint, {
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@ -81,7 +81,7 @@ describe("OidcTokenRefresher", () => {
|
||||
it("throws when oidc client cannot be initialised", async () => {
|
||||
jest.spyOn(logger, "error");
|
||||
fetchMock.get(
|
||||
`${config.metadata.issuer}.well-known/openid-configuration`,
|
||||
`${config.issuer}.well-known/openid-configuration`,
|
||||
{
|
||||
ok: false,
|
||||
status: 404,
|
||||
@ -126,7 +126,7 @@ describe("OidcTokenRefresher", () => {
|
||||
|
||||
const result = await refresher.doRefreshAccessToken("refresh-token");
|
||||
|
||||
expect(fetchMock).toHaveFetched(config.tokenEndpoint, {
|
||||
expect(fetchMock).toHaveFetched(config.token_endpoint, {
|
||||
method: "POST",
|
||||
});
|
||||
|
||||
@ -153,7 +153,7 @@ describe("OidcTokenRefresher", () => {
|
||||
it("should only have one inflight refresh request at once", async () => {
|
||||
fetchMock
|
||||
.postOnce(
|
||||
config.tokenEndpoint,
|
||||
config.token_endpoint,
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
@ -164,7 +164,7 @@ describe("OidcTokenRefresher", () => {
|
||||
{ overwriteRoutes: true },
|
||||
)
|
||||
.postOnce(
|
||||
config.tokenEndpoint,
|
||||
config.token_endpoint,
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
@ -188,7 +188,7 @@ describe("OidcTokenRefresher", () => {
|
||||
const result2 = await first;
|
||||
|
||||
// only one call to token endpoint
|
||||
expect(fetchMock).toHaveFetchedTimes(1, config.tokenEndpoint);
|
||||
expect(fetchMock).toHaveFetchedTimes(1, config.token_endpoint);
|
||||
expect(result1).toEqual({
|
||||
accessToken: "first-new-access-token",
|
||||
refreshToken: "first-new-refresh-token",
|
||||
@ -208,7 +208,7 @@ describe("OidcTokenRefresher", () => {
|
||||
|
||||
it("should log and rethrow when token refresh fails", async () => {
|
||||
fetchMock.post(
|
||||
config.tokenEndpoint,
|
||||
config.token_endpoint,
|
||||
{
|
||||
status: 503,
|
||||
headers: {
|
||||
@ -228,7 +228,7 @@ describe("OidcTokenRefresher", () => {
|
||||
// make sure inflight request is cleared after a failure
|
||||
fetchMock
|
||||
.postOnce(
|
||||
config.tokenEndpoint,
|
||||
config.token_endpoint,
|
||||
{
|
||||
status: 503,
|
||||
headers: {
|
||||
@ -238,7 +238,7 @@ describe("OidcTokenRefresher", () => {
|
||||
{ overwriteRoutes: true },
|
||||
)
|
||||
.postOnce(
|
||||
config.tokenEndpoint,
|
||||
config.token_endpoint,
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
|
@ -18,17 +18,18 @@ import { mocked } from "jest-mock";
|
||||
import { jwtDecode } from "jwt-decode";
|
||||
|
||||
import { logger } from "../../../src/logger";
|
||||
import { validateIdToken, validateOIDCIssuerWellKnown } from "../../../src/oidc/validate";
|
||||
import { ValidatedAuthMetadata, validateIdToken, validateAuthMetadata } from "../../../src/oidc/validate";
|
||||
import { OidcError } from "../../../src/oidc/error";
|
||||
|
||||
jest.mock("jwt-decode");
|
||||
|
||||
describe("validateOIDCIssuerWellKnown", () => {
|
||||
const validWk: any = {
|
||||
const validWk: ValidatedAuthMetadata = {
|
||||
issuer: "https://test.org",
|
||||
authorization_endpoint: "https://test.org/authorize",
|
||||
token_endpoint: "https://authorize.org/token",
|
||||
registration_endpoint: "https://authorize.org/regsiter",
|
||||
revocation_endpoint: "https://authorize.org/regsiter",
|
||||
registration_endpoint: "https://authorize.org/register",
|
||||
revocation_endpoint: "https://authorize.org/revoke",
|
||||
response_types_supported: ["code"],
|
||||
grant_types_supported: ["authorization_code"],
|
||||
code_challenge_methods_supported: ["S256"],
|
||||
@ -44,14 +45,14 @@ describe("validateOIDCIssuerWellKnown", () => {
|
||||
|
||||
it("should throw OP support error when wellKnown is not an object", () => {
|
||||
expect(() => {
|
||||
validateOIDCIssuerWellKnown([]);
|
||||
validateAuthMetadata([]);
|
||||
}).toThrow(OidcError.OpSupport);
|
||||
expect(logger.error).toHaveBeenCalledWith("Issuer configuration not found or malformed");
|
||||
});
|
||||
|
||||
it("should log all errors before throwing", () => {
|
||||
expect(() => {
|
||||
validateOIDCIssuerWellKnown({
|
||||
validateAuthMetadata({
|
||||
...validWk,
|
||||
authorization_endpoint: undefined,
|
||||
response_types_supported: [],
|
||||
@ -62,24 +63,31 @@ describe("validateOIDCIssuerWellKnown", () => {
|
||||
});
|
||||
|
||||
it("should return validated issuer config", () => {
|
||||
expect(validateOIDCIssuerWellKnown(validWk)).toEqual({
|
||||
authorizationEndpoint: validWk.authorization_endpoint,
|
||||
tokenEndpoint: validWk.token_endpoint,
|
||||
registrationEndpoint: validWk.registration_endpoint,
|
||||
accountManagementActionsSupported: ["org.matrix.cross_signing_reset"],
|
||||
accountManagementEndpoint: "https://authorize.org/account",
|
||||
});
|
||||
expect(validateAuthMetadata(validWk)).toEqual(
|
||||
expect.objectContaining({
|
||||
issuer: validWk.issuer,
|
||||
authorization_endpoint: validWk.authorization_endpoint,
|
||||
token_endpoint: validWk.token_endpoint,
|
||||
registration_endpoint: validWk.registration_endpoint,
|
||||
account_management_actions_supported: ["org.matrix.cross_signing_reset"],
|
||||
account_management_uri: "https://authorize.org/account",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("should return validated issuer config without registrationendpoint", () => {
|
||||
const wk = { ...validWk };
|
||||
delete wk.registration_endpoint;
|
||||
expect(validateOIDCIssuerWellKnown(wk)).toEqual({
|
||||
authorizationEndpoint: validWk.authorization_endpoint,
|
||||
tokenEndpoint: validWk.token_endpoint,
|
||||
registrationEndpoint: undefined,
|
||||
accountManagementActionsSupported: ["org.matrix.cross_signing_reset"],
|
||||
accountManagementEndpoint: "https://authorize.org/account",
|
||||
it("should return validated issuer config without registration_endpoint", () => {
|
||||
const { registration_endpoint: _, ...wk } = validWk;
|
||||
expect(validateAuthMetadata(wk)).toEqual({
|
||||
issuer: validWk.issuer,
|
||||
authorization_endpoint: validWk.authorization_endpoint,
|
||||
token_endpoint: validWk.token_endpoint,
|
||||
revocation_endpoint: validWk.revocation_endpoint,
|
||||
registration_endpoint: undefined,
|
||||
account_management_actions_supported: ["org.matrix.cross_signing_reset"],
|
||||
account_management_uri: "https://authorize.org/account",
|
||||
code_challenge_methods_supported: ["S256"],
|
||||
grant_types_supported: ["authorization_code"],
|
||||
response_types_supported: ["code"],
|
||||
});
|
||||
});
|
||||
|
||||
@ -106,7 +114,7 @@ describe("validateOIDCIssuerWellKnown", () => {
|
||||
...validWk,
|
||||
[key]: value,
|
||||
};
|
||||
expect(() => validateOIDCIssuerWellKnown(wk)).toThrow(OidcError.OpSupport);
|
||||
expect(() => validateAuthMetadata(wk)).toThrow(OidcError.OpSupport);
|
||||
});
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user