Update MSC2965 OIDC Discovery implementation (#12245)
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
This commit is contained in:
parent
729eca49e4
commit
7b1e8e3d2f
19 changed files with 350 additions and 300 deletions
|
@ -19,9 +19,11 @@ import {
|
|||
AutoDiscovery,
|
||||
AutoDiscoveryError,
|
||||
ClientConfig,
|
||||
OidcClientConfig,
|
||||
M_AUTHENTICATION,
|
||||
discoverAndValidateOIDCIssuerWellKnown,
|
||||
IClientWellKnown,
|
||||
MatrixClient,
|
||||
MatrixError,
|
||||
OidcClientConfig,
|
||||
} from "matrix-js-sdk/src/matrix";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
|
@ -217,12 +219,12 @@ export default class AutoDiscoveryUtils {
|
|||
* @param {boolean} isSynthetic If true, then the discoveryResult was synthesised locally.
|
||||
* @returns {Promise<ValidatedServerConfig>} Resolves to the validated configuration.
|
||||
*/
|
||||
public static buildValidatedConfigFromDiscovery(
|
||||
public static async buildValidatedConfigFromDiscovery(
|
||||
serverName?: string,
|
||||
discoveryResult?: ClientConfig,
|
||||
syntaxOnly = false,
|
||||
isSynthetic = false,
|
||||
): ValidatedServerConfig {
|
||||
): Promise<ValidatedServerConfig> {
|
||||
if (!discoveryResult?.["m.homeserver"]) {
|
||||
// This shouldn't happen without major misconfiguration, so we'll log a bit of information
|
||||
// in the log so we can find this bit of code but otherwise tell the user "it broke".
|
||||
|
@ -293,26 +295,20 @@ export default class AutoDiscoveryUtils {
|
|||
throw new UserFriendlyError("auth|autodiscovery_unexpected_error_hs");
|
||||
}
|
||||
|
||||
// This isn't inherently auto-discovery but used to be in an earlier incarnation of the MSC,
|
||||
// and shuttling the data together makes a lot of sense
|
||||
let delegatedAuthentication: OidcClientConfig | undefined;
|
||||
if (discoveryResult[M_AUTHENTICATION.stable!]?.state === AutoDiscovery.SUCCESS) {
|
||||
const {
|
||||
authorizationEndpoint,
|
||||
registrationEndpoint,
|
||||
tokenEndpoint,
|
||||
account,
|
||||
issuer,
|
||||
metadata,
|
||||
signingKeys,
|
||||
} = discoveryResult[M_AUTHENTICATION.stable!] as OidcClientConfig;
|
||||
delegatedAuthentication = Object.freeze({
|
||||
authorizationEndpoint,
|
||||
registrationEndpoint,
|
||||
tokenEndpoint,
|
||||
account,
|
||||
issuer,
|
||||
metadata,
|
||||
signingKeys,
|
||||
});
|
||||
let delegatedAuthenticationError: Error | undefined;
|
||||
try {
|
||||
const tempClient = new MatrixClient({ baseUrl: preferredHomeserverUrl });
|
||||
const { issuer } = await tempClient.getAuthIssuer();
|
||||
delegatedAuthentication = await discoverAndValidateOIDCIssuerWellKnown(issuer);
|
||||
} catch (e) {
|
||||
if (e instanceof MatrixError && e.httpStatus === 404 && e.errcode === "M_UNRECOGNIZED") {
|
||||
// 404 M_UNRECOGNIZED means the server does not support OIDC
|
||||
} else {
|
||||
delegatedAuthenticationError = e as Error;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -321,7 +317,7 @@ export default class AutoDiscoveryUtils {
|
|||
hsNameIsDifferent: url.hostname !== preferredHomeserverName,
|
||||
isUrl: preferredIdentityUrl,
|
||||
isDefault: false,
|
||||
warning: hsResult.error,
|
||||
warning: hsResult.error ?? delegatedAuthenticationError ?? null,
|
||||
isNameResolvable: !isSynthetic,
|
||||
delegatedAuthentication,
|
||||
} as ValidatedServerConfig;
|
||||
|
|
|
@ -14,10 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { OidcClientConfig, IDelegatedAuthConfig } from "matrix-js-sdk/src/matrix";
|
||||
import { ValidatedIssuerConfig } from "matrix-js-sdk/src/oidc/validate";
|
||||
|
||||
export type ValidatedDelegatedAuthConfig = IDelegatedAuthConfig & ValidatedIssuerConfig;
|
||||
import { OidcClientConfig } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
export interface ValidatedServerConfig {
|
||||
hsUrl: string;
|
||||
|
@ -34,9 +31,9 @@ export interface ValidatedServerConfig {
|
|||
|
||||
/**
|
||||
* Config related to delegated authentication
|
||||
* Included when delegated auth is configured and valid, otherwise undefined
|
||||
* From homeserver .well-known m.authentication, and issuer's .well-known/openid-configuration
|
||||
* Used for OIDC native flow authentication
|
||||
* Included when delegated auth is configured and valid, otherwise undefined.
|
||||
* From issuer's .well-known/openid-configuration.
|
||||
* Used for OIDC native flow authentication.
|
||||
*/
|
||||
delegatedAuthentication?: OidcClientConfig;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { IDelegatedAuthConfig, OidcTokenRefresher, AccessTokens } from "matrix-js-sdk/src/matrix";
|
||||
import { OidcTokenRefresher, AccessTokens } from "matrix-js-sdk/src/matrix";
|
||||
import { IdTokenClaims } from "oidc-client-ts";
|
||||
|
||||
import PlatformPeg from "../../PlatformPeg";
|
||||
|
@ -28,14 +28,14 @@ export class TokenRefresher extends OidcTokenRefresher {
|
|||
private readonly deviceId!: string;
|
||||
|
||||
public constructor(
|
||||
authConfig: IDelegatedAuthConfig,
|
||||
issuer: string,
|
||||
clientId: string,
|
||||
redirectUri: string,
|
||||
deviceId: string,
|
||||
idTokenClaims: IdTokenClaims,
|
||||
private readonly userId: string,
|
||||
) {
|
||||
super(authConfig, clientId, deviceId, redirectUri, idTokenClaims);
|
||||
super(issuer, clientId, deviceId, redirectUri, idTokenClaims);
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
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 { IClientWellKnown, IDelegatedAuthConfig, M_AUTHENTICATION } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
/**
|
||||
* Get the delegated auth account management url if configured
|
||||
* @param clientWellKnown from MatrixClient.getClientWellKnown
|
||||
* @returns the account management url, or undefined
|
||||
*/
|
||||
export const getDelegatedAuthAccountUrl = (clientWellKnown: IClientWellKnown | undefined): string | undefined => {
|
||||
const delegatedAuthConfig = M_AUTHENTICATION.findIn<IDelegatedAuthConfig | undefined>(clientWellKnown);
|
||||
return delegatedAuthConfig?.account;
|
||||
};
|
|
@ -15,10 +15,9 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { registerOidcClient } from "matrix-js-sdk/src/oidc/register";
|
||||
import { registerOidcClient, OidcClientConfig } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { IConfigOptions } from "../../IConfigOptions";
|
||||
import { ValidatedDelegatedAuthConfig } from "../ValidatedServerConfig";
|
||||
import PlatformPeg from "../../PlatformPeg";
|
||||
|
||||
/**
|
||||
|
@ -46,12 +45,12 @@ const getStaticOidcClientId = (
|
|||
* @throws if no clientId is found
|
||||
*/
|
||||
export const getOidcClientId = async (
|
||||
delegatedAuthConfig: ValidatedDelegatedAuthConfig,
|
||||
delegatedAuthConfig: OidcClientConfig,
|
||||
staticOidcClients?: IConfigOptions["oidc_static_clients"],
|
||||
): Promise<string> => {
|
||||
const staticClientId = getStaticOidcClientId(delegatedAuthConfig.issuer, staticOidcClients);
|
||||
const staticClientId = getStaticOidcClientId(delegatedAuthConfig.metadata.issuer, staticOidcClients);
|
||||
if (staticClientId) {
|
||||
logger.debug(`Using static clientId for issuer ${delegatedAuthConfig.issuer}`);
|
||||
logger.debug(`Using static clientId for issuer ${delegatedAuthConfig.metadata.issuer}`);
|
||||
return staticClientId;
|
||||
}
|
||||
return await registerOidcClient(delegatedAuthConfig, await PlatformPeg.get()!.getOidcClientMetadata());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue