mirror of
https://github.com/actualbudget/actual.git
synced 2026-05-05 22:52:20 -05:00
Compare commits
1 Commits
youngcw/un
...
worktree-m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f34acd2927 |
@@ -64,6 +64,19 @@ export async function bootstrapOpenId(configParameter) {
|
||||
return {};
|
||||
}
|
||||
|
||||
export function pickIdTokenSignedResponseAlg(issuer, configParameter) {
|
||||
if (configParameter.id_token_signed_response_alg) {
|
||||
return configParameter.id_token_signed_response_alg;
|
||||
}
|
||||
|
||||
const supported = issuer?.metadata?.id_token_signing_alg_values_supported;
|
||||
if (Array.isArray(supported) && supported.length > 0) {
|
||||
return supported.includes('RS256') ? 'RS256' : supported[0];
|
||||
}
|
||||
|
||||
return 'RS256';
|
||||
}
|
||||
|
||||
async function setupOpenIdClient(configParameter) {
|
||||
const issuer =
|
||||
typeof configParameter.issuer === 'string'
|
||||
@@ -73,6 +86,12 @@ async function setupOpenIdClient(configParameter) {
|
||||
authorization_endpoint: configParameter.issuer.authorization_endpoint,
|
||||
token_endpoint: configParameter.issuer.token_endpoint,
|
||||
userinfo_endpoint: configParameter.issuer.userinfo_endpoint,
|
||||
...(Array.isArray(
|
||||
configParameter.issuer.id_token_signing_alg_values_supported,
|
||||
) && {
|
||||
id_token_signing_alg_values_supported:
|
||||
configParameter.issuer.id_token_signing_alg_values_supported,
|
||||
}),
|
||||
});
|
||||
|
||||
const client = new issuer.Client({
|
||||
@@ -83,6 +102,10 @@ async function setupOpenIdClient(configParameter) {
|
||||
configParameter.server_hostname,
|
||||
).toString(),
|
||||
validate_id_token: true,
|
||||
id_token_signed_response_alg: pickIdTokenSignedResponseAlg(
|
||||
issuer,
|
||||
configParameter,
|
||||
),
|
||||
});
|
||||
|
||||
return client;
|
||||
|
||||
53
packages/sync-server/src/accounts/openid.test.ts
Normal file
53
packages/sync-server/src/accounts/openid.test.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { pickIdTokenSignedResponseAlg } from './openid';
|
||||
|
||||
describe('pickIdTokenSignedResponseAlg', () => {
|
||||
it('returns the explicit override when provided, even if discovery suggests otherwise', () => {
|
||||
const issuer = {
|
||||
metadata: { id_token_signing_alg_values_supported: ['RS256', 'ES384'] },
|
||||
};
|
||||
expect(
|
||||
pickIdTokenSignedResponseAlg(issuer, {
|
||||
id_token_signed_response_alg: 'ES512',
|
||||
}),
|
||||
).toBe('ES512');
|
||||
});
|
||||
|
||||
it('prefers RS256 when it is among the advertised algorithms (backwards-compat)', () => {
|
||||
const issuer = {
|
||||
metadata: { id_token_signing_alg_values_supported: ['ES384', 'RS256'] },
|
||||
};
|
||||
expect(pickIdTokenSignedResponseAlg(issuer, {})).toBe('RS256');
|
||||
});
|
||||
|
||||
it('falls back to the first advertised algorithm when RS256 is not offered', () => {
|
||||
const issuer = {
|
||||
metadata: { id_token_signing_alg_values_supported: ['ES384', 'ES256'] },
|
||||
};
|
||||
expect(pickIdTokenSignedResponseAlg(issuer, {})).toBe('ES384');
|
||||
});
|
||||
|
||||
it('uses a lone ECDSA algorithm (the bug-report case)', () => {
|
||||
const issuer = {
|
||||
metadata: { id_token_signing_alg_values_supported: ['ES384'] },
|
||||
};
|
||||
expect(pickIdTokenSignedResponseAlg(issuer, {})).toBe('ES384');
|
||||
});
|
||||
|
||||
it('defaults to RS256 when the issuer exposes no signing metadata', () => {
|
||||
expect(pickIdTokenSignedResponseAlg({ metadata: {} }, {})).toBe('RS256');
|
||||
expect(pickIdTokenSignedResponseAlg(undefined, {})).toBe('RS256');
|
||||
});
|
||||
|
||||
it('treats an empty override as "auto-detect"', () => {
|
||||
const issuer = {
|
||||
metadata: { id_token_signing_alg_values_supported: ['ES384'] },
|
||||
};
|
||||
expect(
|
||||
pickIdTokenSignedResponseAlg(issuer, {
|
||||
id_token_signed_response_alg: '',
|
||||
}),
|
||||
).toBe('ES384');
|
||||
});
|
||||
});
|
||||
@@ -255,6 +255,12 @@ const configSchema = convict({
|
||||
default: 'openid',
|
||||
env: 'ACTUAL_OPENID_AUTH_METHOD',
|
||||
},
|
||||
id_token_signed_response_alg: {
|
||||
doc: 'Algorithm used by the OpenID provider to sign ID tokens (e.g. RS256, ES256, ES384). Auto-detected from discovery metadata when empty.',
|
||||
format: String,
|
||||
default: '',
|
||||
env: 'ACTUAL_OPENID_ID_TOKEN_SIGNED_RESPONSE_ALG',
|
||||
},
|
||||
},
|
||||
|
||||
token_expiration: {
|
||||
|
||||
@@ -138,4 +138,21 @@ describe('config schema', () => {
|
||||
authorizationEndpoint,
|
||||
);
|
||||
});
|
||||
|
||||
it('parses the ID token signing algorithm override from the environment', () => {
|
||||
process.env.TEST_OPENID_ID_TOKEN_SIGNED_RESPONSE_ALG = 'ES384';
|
||||
|
||||
const testSchema = convict({
|
||||
openId: {
|
||||
id_token_signed_response_alg: {
|
||||
doc: 'Algorithm used by the OpenID provider to sign ID tokens.',
|
||||
format: String,
|
||||
default: '',
|
||||
env: 'TEST_OPENID_ID_TOKEN_SIGNED_RESPONSE_ALG',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(() => testSchema.validate()).not.toThrow();
|
||||
expect(testSchema.get('openId.id_token_signed_response_alg')).toBe('ES384');
|
||||
});
|
||||
});
|
||||
|
||||
6
upcoming-release-notes/7554.md
Normal file
6
upcoming-release-notes/7554.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: Bugfixes
|
||||
authors: [MatissJanis]
|
||||
---
|
||||
|
||||
Sync server: accept non-RS256 OpenID ID tokens. The ID-token signing algorithm is now auto-detected from the provider's discovery metadata (with an optional `ACTUAL_OPENID_ID_TOKEN_SIGNED_RESPONSE_ALG` override), fixing login against IdPs that sign with ECDSA (ES256/ES384/ES512) or other RSA variants.
|
||||
Reference in New Issue
Block a user