feat(server)!: oauth encryption algorithm setting (#6818)

* feat: add oauth signing algorithm setting

* chore: open api

* chore: change default to RS256

* feat: test and clean up

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
This commit is contained in:
Daniel Dietzler
2024-02-02 06:27:54 +01:00
committed by GitHub
parent 8a643e5e48
commit d3404f927c
15 changed files with 189 additions and 127 deletions

View File

@@ -73,7 +73,7 @@ describe('AuthService', () => {
jest.spyOn(generators, 'state').mockReturnValue('state');
jest.spyOn(Issuer, 'discover').mockResolvedValue({
id_token_signing_alg_values_supported: ['HS256'],
id_token_signing_alg_values_supported: ['RS256'],
Client: jest.fn().mockResolvedValue({
issuer: {
metadata: {

View File

@@ -318,12 +318,25 @@ export class AuthService {
const redirectUri = this.normalize(config, url.split('?')[0]);
const client = await this.getOAuthClient(config);
const params = client.callbackParams(url);
const tokens = await client.callback(redirectUri, params, { state: params.state });
return client.userinfo<OAuthProfile>(tokens.access_token || '');
try {
const tokens = await client.callback(redirectUri, params, { state: params.state });
return client.userinfo<OAuthProfile>(tokens.access_token || '');
} catch (error: Error | any) {
if (error.message.includes('unexpected JWT alg received')) {
this.logger.warn(
[
'Algorithm mismatch. Make sure the signing algorithm is set correctly in the OAuth settings.',
'Or, that you have specified a signing key in your OAuth provider.',
].join(' '),
);
}
throw error;
}
}
private async getOAuthClient(config: SystemConfig) {
const { enabled, clientId, clientSecret, issuerUrl } = config.oauth;
const { enabled, clientId, clientSecret, issuerUrl, signingAlgorithm } = config.oauth;
if (!enabled) {
throw new BadRequestException('OAuth2 is not enabled');
@@ -337,10 +350,7 @@ export class AuthService {
try {
const issuer = await Issuer.discover(issuerUrl);
const algorithms = (issuer.id_token_signing_alg_values_supported || []) as string[];
if (algorithms[0] === 'HS256') {
metadata.id_token_signed_response_alg = algorithms[0];
}
metadata.id_token_signed_response_alg = signingAlgorithm;
return new issuer.Client(metadata);
} catch (error: any | AggregateError) {

View File

@@ -5,12 +5,13 @@ const isOverrideEnabled = (config: SystemConfigOAuthDto) => config.mobileOverrid
export class SystemConfigOAuthDto {
@IsBoolean()
enabled!: boolean;
autoLaunch!: boolean;
@IsBoolean()
autoRegister!: boolean;
@ValidateIf(isEnabled)
@IsNotEmpty()
@IsString()
issuerUrl!: string;
buttonText!: string;
@ValidateIf(isEnabled)
@IsNotEmpty()
@@ -22,20 +23,13 @@ export class SystemConfigOAuthDto {
@IsString()
clientSecret!: string;
@IsString()
scope!: string;
@IsString()
storageLabelClaim!: string;
@IsString()
buttonText!: string;
@IsBoolean()
autoRegister!: boolean;
enabled!: boolean;
@IsBoolean()
autoLaunch!: boolean;
@ValidateIf(isEnabled)
@IsNotEmpty()
@IsString()
issuerUrl!: string;
@IsBoolean()
mobileOverrideEnabled!: boolean;
@@ -43,4 +37,14 @@ export class SystemConfigOAuthDto {
@ValidateIf(isOverrideEnabled)
@IsUrl()
mobileRedirectUri!: string;
@IsString()
scope!: string;
@IsString()
@IsNotEmpty()
signingAlgorithm!: string;
@IsString()
storageLabelClaim!: string;
}

View File

@@ -88,17 +88,18 @@ export const defaults = Object.freeze<SystemConfig>({
enabled: true,
},
oauth: {
enabled: false,
issuerUrl: '',
autoLaunch: false,
autoRegister: true,
buttonText: 'Login with OAuth',
clientId: '',
clientSecret: '',
enabled: false,
issuerUrl: '',
mobileOverrideEnabled: false,
mobileRedirectUri: '',
scope: 'openid email profile',
signingAlgorithm: 'RS256',
storageLabelClaim: 'preferred_username',
buttonText: 'Login with OAuth',
autoRegister: true,
autoLaunch: false,
},
passwordLogin: {
enabled: true,

View File

@@ -98,6 +98,7 @@ const updatedConfig = Object.freeze<SystemConfig>({
mobileOverrideEnabled: false,
mobileRedirectUri: '',
scope: 'openid email profile',
signingAlgorithm: 'RS256',
storageLabelClaim: 'preferred_username',
},
passwordLogin: {