You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-06 12:02:40 +03:00
OIDC: add dynamic client registration util function (#3481)
* rename OidcDiscoveryError to OidcError * oidc client registration functions * test registerOidcClient * tidy test file * reexport OidcDiscoveryError for backwards compatibility
This commit is contained in:
@@ -18,7 +18,7 @@ limitations under the License.
|
|||||||
import MockHttpBackend from "matrix-mock-request";
|
import MockHttpBackend from "matrix-mock-request";
|
||||||
|
|
||||||
import { AutoDiscovery } from "../../src/autodiscovery";
|
import { AutoDiscovery } from "../../src/autodiscovery";
|
||||||
import { OidcDiscoveryError } from "../../src/oidc/validate";
|
import { OidcError } from "../../src/oidc/error";
|
||||||
|
|
||||||
describe("AutoDiscovery", function () {
|
describe("AutoDiscovery", function () {
|
||||||
const getHttpBackend = (): MockHttpBackend => {
|
const getHttpBackend = (): MockHttpBackend => {
|
||||||
@@ -400,7 +400,7 @@ describe("AutoDiscovery", function () {
|
|||||||
},
|
},
|
||||||
"m.authentication": {
|
"m.authentication": {
|
||||||
state: "IGNORE",
|
state: "IGNORE",
|
||||||
error: OidcDiscoveryError.NotSupported,
|
error: OidcError.NotSupported,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -441,7 +441,7 @@ describe("AutoDiscovery", function () {
|
|||||||
},
|
},
|
||||||
"m.authentication": {
|
"m.authentication": {
|
||||||
state: "IGNORE",
|
state: "IGNORE",
|
||||||
error: OidcDiscoveryError.NotSupported,
|
error: OidcError.NotSupported,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -485,7 +485,7 @@ describe("AutoDiscovery", function () {
|
|||||||
},
|
},
|
||||||
"m.authentication": {
|
"m.authentication": {
|
||||||
state: "FAIL_ERROR",
|
state: "FAIL_ERROR",
|
||||||
error: OidcDiscoveryError.Misconfigured,
|
error: OidcError.Misconfigured,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -719,7 +719,7 @@ describe("AutoDiscovery", function () {
|
|||||||
},
|
},
|
||||||
"m.authentication": {
|
"m.authentication": {
|
||||||
state: "IGNORE",
|
state: "IGNORE",
|
||||||
error: OidcDiscoveryError.NotSupported,
|
error: OidcError.NotSupported,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -775,7 +775,7 @@ describe("AutoDiscovery", function () {
|
|||||||
},
|
},
|
||||||
"m.authentication": {
|
"m.authentication": {
|
||||||
state: "IGNORE",
|
state: "IGNORE",
|
||||||
error: OidcDiscoveryError.NotSupported,
|
error: OidcError.NotSupported,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
84
spec/unit/oidc/register.spec.ts
Normal file
84
spec/unit/oidc/register.spec.ts
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import fetchMockJest from "fetch-mock-jest";
|
||||||
|
|
||||||
|
import { OidcError } from "../../../src/oidc/error";
|
||||||
|
import { registerOidcClient } from "../../../src/oidc/register";
|
||||||
|
|
||||||
|
describe("registerOidcClient()", () => {
|
||||||
|
const issuer = "https://auth.com/";
|
||||||
|
const registrationEndpoint = "https://auth.com/register";
|
||||||
|
const clientName = "Element";
|
||||||
|
const baseUrl = "https://just.testing";
|
||||||
|
const dynamicClientId = "xyz789";
|
||||||
|
|
||||||
|
const delegatedAuthConfig = {
|
||||||
|
issuer,
|
||||||
|
registrationEndpoint,
|
||||||
|
authorizationEndpoint: issuer + "auth",
|
||||||
|
tokenEndpoint: issuer + "token",
|
||||||
|
};
|
||||||
|
beforeEach(() => {
|
||||||
|
fetchMockJest.mockClear();
|
||||||
|
fetchMockJest.resetBehavior();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should make correct request to register client", async () => {
|
||||||
|
fetchMockJest.post(registrationEndpoint, {
|
||||||
|
status: 200,
|
||||||
|
body: JSON.stringify({ client_id: dynamicClientId }),
|
||||||
|
});
|
||||||
|
expect(await registerOidcClient(delegatedAuthConfig, clientName, baseUrl)).toEqual(dynamicClientId);
|
||||||
|
expect(fetchMockJest).toHaveBeenCalledWith(registrationEndpoint, {
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({
|
||||||
|
client_name: clientName,
|
||||||
|
client_uri: baseUrl,
|
||||||
|
response_types: ["code"],
|
||||||
|
grant_types: ["authorization_code", "refresh_token"],
|
||||||
|
redirect_uris: [baseUrl],
|
||||||
|
id_token_signed_response_alg: "RS256",
|
||||||
|
token_endpoint_auth_method: "none",
|
||||||
|
application_type: "web",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should throw when registration request fails", async () => {
|
||||||
|
fetchMockJest.post(registrationEndpoint, {
|
||||||
|
status: 500,
|
||||||
|
});
|
||||||
|
expect(() => registerOidcClient(delegatedAuthConfig, clientName, baseUrl)).rejects.toThrow(
|
||||||
|
OidcError.DynamicRegistrationFailed,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should throw when registration response is invalid", async () => {
|
||||||
|
fetchMockJest.post(registrationEndpoint, {
|
||||||
|
status: 200,
|
||||||
|
// no clientId in response
|
||||||
|
body: "{}",
|
||||||
|
});
|
||||||
|
expect(() => registerOidcClient(delegatedAuthConfig, clientName, baseUrl)).rejects.toThrow(
|
||||||
|
OidcError.DynamicRegistrationInvalid,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
@@ -16,11 +16,8 @@ limitations under the License.
|
|||||||
|
|
||||||
import { M_AUTHENTICATION } from "../../../src";
|
import { M_AUTHENTICATION } from "../../../src";
|
||||||
import { logger } from "../../../src/logger";
|
import { logger } from "../../../src/logger";
|
||||||
import {
|
import { validateOIDCIssuerWellKnown, validateWellKnownAuthentication } from "../../../src/oidc/validate";
|
||||||
OidcDiscoveryError,
|
import { OidcError } from "../../../src/oidc/error";
|
||||||
validateOIDCIssuerWellKnown,
|
|
||||||
validateWellKnownAuthentication,
|
|
||||||
} from "../../../src/oidc/validate";
|
|
||||||
|
|
||||||
describe("validateWellKnownAuthentication()", () => {
|
describe("validateWellKnownAuthentication()", () => {
|
||||||
const baseWk = {
|
const baseWk = {
|
||||||
@@ -29,7 +26,7 @@ describe("validateWellKnownAuthentication()", () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
it("should throw not supported error when wellKnown has no m.authentication section", () => {
|
it("should throw not supported error when wellKnown has no m.authentication section", () => {
|
||||||
expect(() => validateWellKnownAuthentication(baseWk)).toThrow(OidcDiscoveryError.NotSupported);
|
expect(() => validateWellKnownAuthentication(baseWk)).toThrow(OidcError.NotSupported);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should throw misconfigured error when authentication issuer is not a string", () => {
|
it("should throw misconfigured error when authentication issuer is not a string", () => {
|
||||||
@@ -39,7 +36,7 @@ describe("validateWellKnownAuthentication()", () => {
|
|||||||
issuer: { url: "test.com" },
|
issuer: { url: "test.com" },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
expect(() => validateWellKnownAuthentication(wk)).toThrow(OidcDiscoveryError.Misconfigured);
|
expect(() => validateWellKnownAuthentication(wk)).toThrow(OidcError.Misconfigured);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should throw misconfigured error when authentication account is not a string", () => {
|
it("should throw misconfigured error when authentication account is not a string", () => {
|
||||||
@@ -50,7 +47,7 @@ describe("validateWellKnownAuthentication()", () => {
|
|||||||
account: { url: "test" },
|
account: { url: "test" },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
expect(() => validateWellKnownAuthentication(wk)).toThrow(OidcDiscoveryError.Misconfigured);
|
expect(() => validateWellKnownAuthentication(wk)).toThrow(OidcError.Misconfigured);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should throw misconfigured error when authentication account is false", () => {
|
it("should throw misconfigured error when authentication account is false", () => {
|
||||||
@@ -61,7 +58,7 @@ describe("validateWellKnownAuthentication()", () => {
|
|||||||
account: false,
|
account: false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
expect(() => validateWellKnownAuthentication(wk)).toThrow(OidcDiscoveryError.Misconfigured);
|
expect(() => validateWellKnownAuthentication(wk)).toThrow(OidcError.Misconfigured);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return valid config when wk uses stable m.authentication", () => {
|
it("should return valid config when wk uses stable m.authentication", () => {
|
||||||
@@ -137,7 +134,7 @@ describe("validateOIDCIssuerWellKnown", () => {
|
|||||||
it("should throw OP support error when wellKnown is not an object", () => {
|
it("should throw OP support error when wellKnown is not an object", () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
validateOIDCIssuerWellKnown([]);
|
validateOIDCIssuerWellKnown([]);
|
||||||
}).toThrow(OidcDiscoveryError.OpSupport);
|
}).toThrow(OidcError.OpSupport);
|
||||||
expect(logger.error).toHaveBeenCalledWith("Issuer configuration not found or malformed");
|
expect(logger.error).toHaveBeenCalledWith("Issuer configuration not found or malformed");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -148,7 +145,7 @@ describe("validateOIDCIssuerWellKnown", () => {
|
|||||||
authorization_endpoint: undefined,
|
authorization_endpoint: undefined,
|
||||||
response_types_supported: [],
|
response_types_supported: [],
|
||||||
});
|
});
|
||||||
}).toThrow(OidcDiscoveryError.OpSupport);
|
}).toThrow(OidcError.OpSupport);
|
||||||
expect(logger.error).toHaveBeenCalledWith("OIDC issuer configuration: authorization_endpoint is invalid");
|
expect(logger.error).toHaveBeenCalledWith("OIDC issuer configuration: authorization_endpoint is invalid");
|
||||||
expect(logger.error).toHaveBeenCalledWith(
|
expect(logger.error).toHaveBeenCalledWith(
|
||||||
"OIDC issuer configuration: response_types_supported is invalid. code is required.",
|
"OIDC issuer configuration: response_types_supported is invalid. code is required.",
|
||||||
@@ -194,6 +191,6 @@ describe("validateOIDCIssuerWellKnown", () => {
|
|||||||
...validWk,
|
...validWk,
|
||||||
[key]: value,
|
[key]: value,
|
||||||
};
|
};
|
||||||
expect(() => validateOIDCIssuerWellKnown(wk)).toThrow(OidcDiscoveryError.OpSupport);
|
expect(() => validateOIDCIssuerWellKnown(wk)).toThrow(OidcError.OpSupport);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -18,12 +18,8 @@ limitations under the License.
|
|||||||
import { IClientWellKnown, IWellKnownConfig, IDelegatedAuthConfig, IServerVersions, M_AUTHENTICATION } from "./client";
|
import { IClientWellKnown, IWellKnownConfig, IDelegatedAuthConfig, IServerVersions, M_AUTHENTICATION } from "./client";
|
||||||
import { logger } from "./logger";
|
import { logger } from "./logger";
|
||||||
import { MatrixError, Method, timeoutSignal } from "./http-api";
|
import { MatrixError, Method, timeoutSignal } from "./http-api";
|
||||||
import {
|
import { ValidatedIssuerConfig, validateOIDCIssuerWellKnown, validateWellKnownAuthentication } from "./oidc/validate";
|
||||||
OidcDiscoveryError,
|
import { OidcError } from "./oidc/error";
|
||||||
ValidatedIssuerConfig,
|
|
||||||
validateOIDCIssuerWellKnown,
|
|
||||||
validateWellKnownAuthentication,
|
|
||||||
} from "./oidc/validate";
|
|
||||||
|
|
||||||
// Dev note: Auto discovery is part of the spec.
|
// Dev note: Auto discovery is part of the spec.
|
||||||
// See: https://matrix.org/docs/spec/client_server/r0.4.0.html#server-discovery
|
// See: https://matrix.org/docs/spec/client_server/r0.4.0.html#server-discovery
|
||||||
@@ -297,7 +293,7 @@ export class AutoDiscovery {
|
|||||||
|
|
||||||
if (issuerWellKnown.action !== AutoDiscoveryAction.SUCCESS) {
|
if (issuerWellKnown.action !== AutoDiscoveryAction.SUCCESS) {
|
||||||
logger.error("Failed to fetch issuer openid configuration");
|
logger.error("Failed to fetch issuer openid configuration");
|
||||||
throw new Error(OidcDiscoveryError.General);
|
throw new Error(OidcError.General);
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedIssuerConfig = validateOIDCIssuerWellKnown(issuerWellKnown.raw);
|
const validatedIssuerConfig = validateOIDCIssuerWellKnown(issuerWellKnown.raw);
|
||||||
@@ -310,15 +306,11 @@ export class AutoDiscovery {
|
|||||||
};
|
};
|
||||||
return delegatedAuthConfig;
|
return delegatedAuthConfig;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage = (error as Error).message as unknown as OidcDiscoveryError;
|
const errorMessage = (error as Error).message as unknown as OidcError;
|
||||||
const errorType = Object.values(OidcDiscoveryError).includes(errorMessage)
|
const errorType = Object.values(OidcError).includes(errorMessage) ? errorMessage : OidcError.General;
|
||||||
? errorMessage
|
|
||||||
: OidcDiscoveryError.General;
|
|
||||||
|
|
||||||
const state =
|
const state =
|
||||||
errorType === OidcDiscoveryError.NotSupported
|
errorType === OidcError.NotSupported ? AutoDiscoveryAction.IGNORE : AutoDiscoveryAction.FAIL_ERROR;
|
||||||
? AutoDiscoveryAction.IGNORE
|
|
||||||
: AutoDiscoveryAction.FAIL_ERROR;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
state,
|
state,
|
||||||
|
25
src/oidc/error.ts
Normal file
25
src/oidc/error.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export enum OidcError {
|
||||||
|
NotSupported = "OIDC authentication not supported",
|
||||||
|
Misconfigured = "OIDC is misconfigured",
|
||||||
|
General = "Something went wrong with OIDC discovery",
|
||||||
|
OpSupport = "Configured OIDC OP does not support required functions",
|
||||||
|
DynamicRegistrationNotSupported = "Dynamic registration not supported",
|
||||||
|
DynamicRegistrationFailed = "Dynamic registration failed",
|
||||||
|
DynamicRegistrationInvalid = "Dynamic registration invalid response",
|
||||||
|
}
|
111
src/oidc/register.ts
Normal file
111
src/oidc/register.ts
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { IDelegatedAuthConfig } from "../client";
|
||||||
|
import { OidcError } from "./error";
|
||||||
|
import { Method } from "../http-api";
|
||||||
|
import { logger } from "../logger";
|
||||||
|
import { ValidatedIssuerConfig } from "./validate";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client metadata passed to registration endpoint
|
||||||
|
*/
|
||||||
|
export type OidcRegistrationClientMetadata = {
|
||||||
|
clientName: string;
|
||||||
|
clientUri: string;
|
||||||
|
redirectUris: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the client registration request
|
||||||
|
* @param registrationEndpoint - URL as returned from issuer ./well-known/openid-configuration
|
||||||
|
* @param clientMetadata - registration metadata
|
||||||
|
* @returns resolves to the registered client id when registration is successful
|
||||||
|
* @throws when registration request fails, or response is invalid
|
||||||
|
*/
|
||||||
|
const doRegistration = async (
|
||||||
|
registrationEndpoint: string,
|
||||||
|
clientMetadata: OidcRegistrationClientMetadata,
|
||||||
|
): Promise<string> => {
|
||||||
|
// https://openid.net/specs/openid-connect-registration-1_0.html
|
||||||
|
const metadata = {
|
||||||
|
client_name: clientMetadata.clientName,
|
||||||
|
client_uri: clientMetadata.clientUri,
|
||||||
|
response_types: ["code"],
|
||||||
|
grant_types: ["authorization_code", "refresh_token"],
|
||||||
|
redirect_uris: clientMetadata.redirectUris,
|
||||||
|
id_token_signed_response_alg: "RS256",
|
||||||
|
token_endpoint_auth_method: "none",
|
||||||
|
application_type: "web",
|
||||||
|
};
|
||||||
|
const headers = {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(registrationEndpoint, {
|
||||||
|
method: Method.Post,
|
||||||
|
headers,
|
||||||
|
body: JSON.stringify(metadata),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.status >= 400) {
|
||||||
|
throw new Error(OidcError.DynamicRegistrationFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = await response.json();
|
||||||
|
const clientId = body["client_id"];
|
||||||
|
if (!clientId || typeof clientId !== "string") {
|
||||||
|
throw new Error(OidcError.DynamicRegistrationInvalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientId;
|
||||||
|
} catch (error) {
|
||||||
|
if (Object.values(OidcError).includes((error as Error).message as OidcError)) {
|
||||||
|
throw error;
|
||||||
|
} else {
|
||||||
|
logger.error("Dynamic registration request failed", error);
|
||||||
|
throw new Error(OidcError.DynamicRegistrationFailed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts dynamic registration against the configured registration endpoint
|
||||||
|
* @param delegatedAuthConfig - Auth config from ValidatedServerConfig
|
||||||
|
* @param clientName - Client name to register with the OP, eg 'Element'
|
||||||
|
* @param baseUrl - URL of the home page of the Client, eg 'https://app.element.io/'
|
||||||
|
* @returns Promise<string> resolved with registered clientId
|
||||||
|
* @throws when registration is not supported, on failed request or invalid response
|
||||||
|
*/
|
||||||
|
export const registerOidcClient = async (
|
||||||
|
delegatedAuthConfig: IDelegatedAuthConfig & ValidatedIssuerConfig,
|
||||||
|
clientName: string,
|
||||||
|
baseUrl: string,
|
||||||
|
): Promise<string> => {
|
||||||
|
const clientMetadata = {
|
||||||
|
clientName,
|
||||||
|
clientUri: baseUrl,
|
||||||
|
redirectUris: [baseUrl],
|
||||||
|
};
|
||||||
|
if (!delegatedAuthConfig.registrationEndpoint) {
|
||||||
|
throw new Error(OidcError.DynamicRegistrationNotSupported);
|
||||||
|
}
|
||||||
|
const clientId = await doRegistration(delegatedAuthConfig.registrationEndpoint, clientMetadata);
|
||||||
|
|
||||||
|
return clientId;
|
||||||
|
};
|
@@ -16,13 +16,13 @@ limitations under the License.
|
|||||||
|
|
||||||
import { IClientWellKnown, IDelegatedAuthConfig, M_AUTHENTICATION } from "../client";
|
import { IClientWellKnown, IDelegatedAuthConfig, M_AUTHENTICATION } from "../client";
|
||||||
import { logger } from "../logger";
|
import { logger } from "../logger";
|
||||||
|
import { OidcError } from "./error";
|
||||||
|
|
||||||
export enum OidcDiscoveryError {
|
/**
|
||||||
NotSupported = "OIDC authentication not supported",
|
* re-export for backwards compatibility
|
||||||
Misconfigured = "OIDC is misconfigured",
|
* @deprecated use OidcError
|
||||||
General = "Something went wrong with OIDC discovery",
|
*/
|
||||||
OpSupport = "Configured OIDC OP does not support required functions",
|
export { OidcError as OidcDiscoveryError };
|
||||||
}
|
|
||||||
|
|
||||||
export type ValidatedIssuerConfig = {
|
export type ValidatedIssuerConfig = {
|
||||||
authorizationEndpoint: string;
|
authorizationEndpoint: string;
|
||||||
@@ -41,7 +41,7 @@ export const validateWellKnownAuthentication = (wellKnown: IClientWellKnown): ID
|
|||||||
const authentication = M_AUTHENTICATION.findIn<IDelegatedAuthConfig>(wellKnown);
|
const authentication = M_AUTHENTICATION.findIn<IDelegatedAuthConfig>(wellKnown);
|
||||||
|
|
||||||
if (!authentication) {
|
if (!authentication) {
|
||||||
throw new Error(OidcDiscoveryError.NotSupported);
|
throw new Error(OidcError.NotSupported);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -54,7 +54,7 @@ export const validateWellKnownAuthentication = (wellKnown: IClientWellKnown): ID
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(OidcDiscoveryError.Misconfigured);
|
throw new Error(OidcError.Misconfigured);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
||||||
@@ -93,7 +93,7 @@ const requiredArrayValue = (wellKnown: Record<string, unknown>, key: string, val
|
|||||||
export const validateOIDCIssuerWellKnown = (wellKnown: unknown): ValidatedIssuerConfig => {
|
export const validateOIDCIssuerWellKnown = (wellKnown: unknown): ValidatedIssuerConfig => {
|
||||||
if (!isRecord(wellKnown)) {
|
if (!isRecord(wellKnown)) {
|
||||||
logger.error("Issuer configuration not found or malformed");
|
logger.error("Issuer configuration not found or malformed");
|
||||||
throw new Error(OidcDiscoveryError.OpSupport);
|
throw new Error(OidcError.OpSupport);
|
||||||
}
|
}
|
||||||
|
|
||||||
const isInvalid = [
|
const isInvalid = [
|
||||||
@@ -114,5 +114,5 @@ export const validateOIDCIssuerWellKnown = (wellKnown: unknown): ValidatedIssuer
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.error("Issuer configuration not valid");
|
logger.error("Issuer configuration not valid");
|
||||||
throw new Error(OidcDiscoveryError.OpSupport);
|
throw new Error(OidcError.OpSupport);
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user