mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-03-01 05:29:41 +00:00
- Remove Passport.js wrapper from OIDC auth, use openid-client directly - Add schema-driven OIDC settings UI (OidcSettingsSchema.js drives form rendering) - Add group mapping with KeyValueEditor (explicit mapping or legacy direct name match) - Add scopes configuration (authOpenIDScopes) - Add verified email enforcement option (authOpenIDRequireVerifiedEmail) - Fix group claim validation rejecting URN-style claims (#4744) - Add auto-discover endpoint for OIDC provider configuration - Store oidcIdToken in sessions table instead of cookie - Add AuthError class for structured error handling in auth flows - Migration v2.33.0 adds oidcIdToken column and new settings fields
155 lines
4.9 KiB
JavaScript
155 lines
4.9 KiB
JavaScript
const { expect } = require('chai')
|
|
const { validateSettings } = require('../../../server/auth/OidcSettingsSchema')
|
|
|
|
describe('OidcSettingsSchema - validateSettings', function () {
|
|
const validSettings = {
|
|
authOpenIDIssuerURL: 'https://auth.example.com',
|
|
authOpenIDAuthorizationURL: 'https://auth.example.com/authorize',
|
|
authOpenIDTokenURL: 'https://auth.example.com/token',
|
|
authOpenIDUserInfoURL: 'https://auth.example.com/userinfo',
|
|
authOpenIDJwksURL: 'https://auth.example.com/jwks',
|
|
authOpenIDClientID: 'my-client-id',
|
|
authOpenIDClientSecret: 'my-client-secret',
|
|
authOpenIDTokenSigningAlgorithm: 'RS256'
|
|
}
|
|
|
|
it('should pass with valid required settings', function () {
|
|
const result = validateSettings(validSettings)
|
|
expect(result.valid).to.be.true
|
|
})
|
|
|
|
it('should fail when required fields are missing', function () {
|
|
const result = validateSettings({})
|
|
expect(result.valid).to.be.false
|
|
expect(result.errors).to.include('Issuer URL is required')
|
|
expect(result.errors).to.include('Client ID is required')
|
|
expect(result.errors).to.include('Client Secret is required')
|
|
})
|
|
|
|
it('should fail with invalid URL', function () {
|
|
const result = validateSettings({
|
|
...validSettings,
|
|
authOpenIDIssuerURL: 'not-a-url'
|
|
})
|
|
expect(result.valid).to.be.false
|
|
expect(result.errors).to.include('Issuer URL: Invalid URL')
|
|
})
|
|
|
|
it('should pass with valid optional fields', function () {
|
|
const result = validateSettings({
|
|
...validSettings,
|
|
authOpenIDLogoutURL: 'https://auth.example.com/logout',
|
|
authOpenIDButtonText: 'Login with SSO',
|
|
authOpenIDAutoLaunch: false,
|
|
authOpenIDAutoRegister: true,
|
|
authOpenIDScopes: 'openid profile email groups',
|
|
authOpenIDGroupClaim: 'groups'
|
|
})
|
|
expect(result.valid).to.be.true
|
|
})
|
|
|
|
it('should fail with invalid boolean type', function () {
|
|
const result = validateSettings({
|
|
...validSettings,
|
|
authOpenIDAutoLaunch: 'yes'
|
|
})
|
|
expect(result.valid).to.be.false
|
|
expect(result.errors).to.include('Auto Launch: Expected boolean')
|
|
})
|
|
|
|
it('should fail with invalid claim name', function () {
|
|
const result = validateSettings({
|
|
...validSettings,
|
|
authOpenIDGroupClaim: '123invalid'
|
|
})
|
|
expect(result.valid).to.be.false
|
|
expect(result.errors).to.include('Group Claim: Invalid claim name')
|
|
})
|
|
|
|
it('should pass with valid claim name', function () {
|
|
const result = validateSettings({
|
|
...validSettings,
|
|
authOpenIDGroupClaim: 'my-groups_claim'
|
|
})
|
|
expect(result.valid).to.be.true
|
|
})
|
|
|
|
it('should pass with URN-style claim name (e.g. ZITADEL)', function () {
|
|
const result = validateSettings({
|
|
...validSettings,
|
|
authOpenIDGroupClaim: 'urn:zitadel:iam:org:project:roles'
|
|
})
|
|
expect(result.valid).to.be.true
|
|
})
|
|
|
|
it('should fail with invalid group map values', function () {
|
|
const result = validateSettings({
|
|
...validSettings,
|
|
authOpenIDGroupMap: { 'my-group': 'superadmin' }
|
|
})
|
|
expect(result.valid).to.be.false
|
|
expect(result.errors[0]).to.include('Invalid value "superadmin"')
|
|
})
|
|
|
|
it('should pass with valid group map', function () {
|
|
const result = validateSettings({
|
|
...validSettings,
|
|
authOpenIDGroupMap: { 'oidc-admins': 'admin', 'oidc-users': 'user', 'oidc-guests': 'guest' }
|
|
})
|
|
expect(result.valid).to.be.true
|
|
})
|
|
|
|
it('should fail with non-object group map', function () {
|
|
const result = validateSettings({
|
|
...validSettings,
|
|
authOpenIDGroupMap: 'not-an-object'
|
|
})
|
|
expect(result.valid).to.be.false
|
|
expect(result.errors).to.include('Group Mapping: Expected object')
|
|
})
|
|
|
|
it('should fail with invalid mobile redirect URIs', function () {
|
|
const result = validateSettings({
|
|
...validSettings,
|
|
authOpenIDMobileRedirectURIs: 'not-an-array'
|
|
})
|
|
expect(result.valid).to.be.false
|
|
expect(result.errors).to.include('Mobile Redirect URIs: Expected array')
|
|
})
|
|
|
|
it('should pass with valid redirect URI', function () {
|
|
const result = validateSettings({
|
|
...validSettings,
|
|
authOpenIDMobileRedirectURIs: ['audiobookshelf://oauth']
|
|
})
|
|
expect(result.valid).to.be.true
|
|
})
|
|
|
|
it('should fail with wildcard URI', function () {
|
|
const result = validateSettings({
|
|
...validSettings,
|
|
authOpenIDMobileRedirectURIs: ['*']
|
|
})
|
|
expect(result.valid).to.be.false
|
|
expect(result.errors[0]).to.include('Invalid URI')
|
|
})
|
|
|
|
it('should reject unknown keys', function () {
|
|
const result = validateSettings({
|
|
...validSettings,
|
|
unknownSetting: 'value'
|
|
})
|
|
expect(result.valid).to.be.false
|
|
expect(result.errors).to.include('Unknown setting: "unknownSetting"')
|
|
})
|
|
|
|
it('should skip validation for empty optional fields', function () {
|
|
const result = validateSettings({
|
|
...validSettings,
|
|
authOpenIDLogoutURL: '',
|
|
authOpenIDGroupClaim: '',
|
|
authOpenIDGroupMap: {}
|
|
})
|
|
expect(result.valid).to.be.true
|
|
})
|
|
})
|