* fix(oidc): Add logging to help debug missing OIDC button (Issue #1036) When OIDC is configured but the login button doesn't appear, users had no way to debug what was wrong. This adds comprehensive logging: - Log when OIDC is disabled with helpful message - Log when providers are successfully loaded - Warn when numbered providers are skipped due to missing fields - Error when single provider config is incomplete with specific missing fields - Warn when OIDC is enabled but no valid providers found This helps users quickly identify configuration issues like: - Typos in environment variable names - Missing required fields (issuer, clientId, clientSecret) - Incorrect OIDC_ENABLED value Fixes #1036 * fix(ui): Auto-focus project search field when opened (Issue #992) When clicking on the project field in a task to add or change the project, the search input field now automatically receives focus, eliminating the need to manually click on it. This improves the user experience by reducing friction in the project assignment workflow. Fixes #992
344 lines
13 KiB
JavaScript
344 lines
13 KiB
JavaScript
const providerConfig = require('../../../../modules/oidc/providerConfig');
|
|
|
|
describe('OIDC Provider Configuration', () => {
|
|
let originalEnv;
|
|
|
|
beforeEach(() => {
|
|
originalEnv = { ...process.env };
|
|
providerConfig.reloadProviders();
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.env = originalEnv;
|
|
providerConfig.reloadProviders();
|
|
});
|
|
|
|
describe('when OIDC is disabled', () => {
|
|
it('should return empty array when OIDC_ENABLED is not true', () => {
|
|
process.env.OIDC_ENABLED = 'false';
|
|
providerConfig.reloadProviders();
|
|
|
|
const providers = providerConfig.getAllProviders();
|
|
expect(providers).toEqual([]);
|
|
expect(providerConfig.isOidcEnabled()).toBe(false);
|
|
});
|
|
|
|
it('should return empty array when OIDC_ENABLED is not set', () => {
|
|
delete process.env.OIDC_ENABLED;
|
|
providerConfig.reloadProviders();
|
|
|
|
const providers = providerConfig.getAllProviders();
|
|
expect(providers).toEqual([]);
|
|
expect(providerConfig.isOidcEnabled()).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('single provider configuration', () => {
|
|
it('should load single provider from .env', () => {
|
|
process.env.OIDC_ENABLED = 'true';
|
|
process.env.OIDC_PROVIDER_NAME = 'Google';
|
|
process.env.OIDC_PROVIDER_SLUG = 'google';
|
|
process.env.OIDC_ISSUER_URL = 'https://accounts.google.com';
|
|
process.env.OIDC_CLIENT_ID = 'test-client-id';
|
|
process.env.OIDC_CLIENT_SECRET = 'test-client-secret';
|
|
|
|
providerConfig.reloadProviders();
|
|
const providers = providerConfig.getAllProviders();
|
|
|
|
expect(providers).toHaveLength(1);
|
|
expect(providers[0]).toMatchObject({
|
|
slug: 'google',
|
|
name: 'Google',
|
|
issuer: 'https://accounts.google.com',
|
|
clientId: 'test-client-id',
|
|
clientSecret: 'test-client-secret',
|
|
scope: 'openid profile email',
|
|
autoProvision: true,
|
|
});
|
|
});
|
|
|
|
it('should use default slug if not provided', () => {
|
|
process.env.OIDC_ENABLED = 'true';
|
|
process.env.OIDC_PROVIDER_NAME = 'Custom Provider';
|
|
process.env.OIDC_ISSUER_URL = 'https://auth.example.com';
|
|
process.env.OIDC_CLIENT_ID = 'test-id';
|
|
process.env.OIDC_CLIENT_SECRET = 'test-secret';
|
|
|
|
providerConfig.reloadProviders();
|
|
const provider = providerConfig.getProvider('default');
|
|
|
|
expect(provider).toBeDefined();
|
|
expect(provider.slug).toBe('default');
|
|
});
|
|
|
|
it('should parse custom scope', () => {
|
|
process.env.OIDC_ENABLED = 'true';
|
|
process.env.OIDC_PROVIDER_NAME = 'Okta';
|
|
process.env.OIDC_PROVIDER_SLUG = 'okta';
|
|
process.env.OIDC_ISSUER_URL = 'https://company.okta.com';
|
|
process.env.OIDC_CLIENT_ID = 'test-id';
|
|
process.env.OIDC_CLIENT_SECRET = 'test-secret';
|
|
process.env.OIDC_SCOPE = 'openid profile email groups';
|
|
|
|
providerConfig.reloadProviders();
|
|
const provider = providerConfig.getProvider('okta');
|
|
|
|
expect(provider.scope).toBe('openid profile email groups');
|
|
});
|
|
|
|
it('should parse admin email domains', () => {
|
|
process.env.OIDC_ENABLED = 'true';
|
|
process.env.OIDC_PROVIDER_NAME = 'Google';
|
|
process.env.OIDC_PROVIDER_SLUG = 'google';
|
|
process.env.OIDC_ISSUER_URL = 'https://accounts.google.com';
|
|
process.env.OIDC_CLIENT_ID = 'test-id';
|
|
process.env.OIDC_CLIENT_SECRET = 'test-secret';
|
|
process.env.OIDC_ADMIN_EMAIL_DOMAINS = 'example.com,company.com';
|
|
|
|
providerConfig.reloadProviders();
|
|
const provider = providerConfig.getProvider('google');
|
|
|
|
expect(provider.adminEmailDomains).toEqual([
|
|
'example.com',
|
|
'company.com',
|
|
]);
|
|
});
|
|
|
|
it('should respect AUTO_PROVISION=false', () => {
|
|
process.env.OIDC_ENABLED = 'true';
|
|
process.env.OIDC_PROVIDER_NAME = 'Okta';
|
|
process.env.OIDC_PROVIDER_SLUG = 'okta';
|
|
process.env.OIDC_ISSUER_URL = 'https://company.okta.com';
|
|
process.env.OIDC_CLIENT_ID = 'test-id';
|
|
process.env.OIDC_CLIENT_SECRET = 'test-secret';
|
|
process.env.OIDC_AUTO_PROVISION = 'false';
|
|
|
|
providerConfig.reloadProviders();
|
|
const provider = providerConfig.getProvider('okta');
|
|
|
|
expect(provider.autoProvision).toBe(false);
|
|
});
|
|
|
|
it('should return empty array if configuration is incomplete', () => {
|
|
const consoleErrorSpy = jest
|
|
.spyOn(console, 'error')
|
|
.mockImplementation();
|
|
|
|
process.env.OIDC_ENABLED = 'true';
|
|
process.env.OIDC_PROVIDER_NAME = 'Google';
|
|
|
|
providerConfig.reloadProviders();
|
|
const providers = providerConfig.getAllProviders();
|
|
|
|
expect(providers).toEqual([]);
|
|
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
expect.stringContaining('Cannot load OIDC provider')
|
|
);
|
|
|
|
consoleErrorSpy.mockRestore();
|
|
});
|
|
});
|
|
|
|
describe('multiple provider configuration', () => {
|
|
it('should load multiple numbered providers', () => {
|
|
process.env.OIDC_ENABLED = 'true';
|
|
|
|
process.env.OIDC_PROVIDER_1_NAME = 'Google';
|
|
process.env.OIDC_PROVIDER_1_SLUG = 'google';
|
|
process.env.OIDC_PROVIDER_1_ISSUER = 'https://accounts.google.com';
|
|
process.env.OIDC_PROVIDER_1_CLIENT_ID = 'google-id';
|
|
process.env.OIDC_PROVIDER_1_CLIENT_SECRET = 'google-secret';
|
|
|
|
process.env.OIDC_PROVIDER_2_NAME = 'Okta';
|
|
process.env.OIDC_PROVIDER_2_SLUG = 'okta';
|
|
process.env.OIDC_PROVIDER_2_ISSUER = 'https://company.okta.com';
|
|
process.env.OIDC_PROVIDER_2_CLIENT_ID = 'okta-id';
|
|
process.env.OIDC_PROVIDER_2_CLIENT_SECRET = 'okta-secret';
|
|
|
|
providerConfig.reloadProviders();
|
|
const providers = providerConfig.getAllProviders();
|
|
|
|
expect(providers).toHaveLength(2);
|
|
expect(providers[0].slug).toBe('google');
|
|
expect(providers[1].slug).toBe('okta');
|
|
});
|
|
|
|
it('should skip numbered providers with incomplete config', () => {
|
|
const consoleWarnSpy = jest
|
|
.spyOn(console, 'warn')
|
|
.mockImplementation();
|
|
const consoleLogSpy = jest
|
|
.spyOn(console, 'log')
|
|
.mockImplementation();
|
|
|
|
process.env.OIDC_ENABLED = 'true';
|
|
|
|
process.env.OIDC_PROVIDER_1_NAME = 'Google';
|
|
process.env.OIDC_PROVIDER_1_SLUG = 'google';
|
|
|
|
process.env.OIDC_PROVIDER_2_NAME = 'Okta';
|
|
process.env.OIDC_PROVIDER_2_SLUG = 'okta';
|
|
process.env.OIDC_PROVIDER_2_ISSUER = 'https://company.okta.com';
|
|
process.env.OIDC_PROVIDER_2_CLIENT_ID = 'okta-id';
|
|
process.env.OIDC_PROVIDER_2_CLIENT_SECRET = 'okta-secret';
|
|
|
|
providerConfig.reloadProviders();
|
|
const providers = providerConfig.getAllProviders();
|
|
|
|
expect(providers).toHaveLength(1);
|
|
expect(providers[0].slug).toBe('okta');
|
|
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
expect.stringContaining('Skipping OIDC provider 1')
|
|
);
|
|
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
expect.stringContaining('Loaded OIDC provider 2: Okta')
|
|
);
|
|
|
|
consoleWarnSpy.mockRestore();
|
|
consoleLogSpy.mockRestore();
|
|
});
|
|
|
|
it('should handle different settings per provider', () => {
|
|
process.env.OIDC_ENABLED = 'true';
|
|
|
|
process.env.OIDC_PROVIDER_1_NAME = 'Google';
|
|
process.env.OIDC_PROVIDER_1_SLUG = 'google';
|
|
process.env.OIDC_PROVIDER_1_ISSUER = 'https://accounts.google.com';
|
|
process.env.OIDC_PROVIDER_1_CLIENT_ID = 'google-id';
|
|
process.env.OIDC_PROVIDER_1_CLIENT_SECRET = 'google-secret';
|
|
process.env.OIDC_PROVIDER_1_AUTO_PROVISION = 'true';
|
|
|
|
process.env.OIDC_PROVIDER_2_NAME = 'Corporate';
|
|
process.env.OIDC_PROVIDER_2_SLUG = 'corp';
|
|
process.env.OIDC_PROVIDER_2_ISSUER = 'https://auth.corp.com';
|
|
process.env.OIDC_PROVIDER_2_CLIENT_ID = 'corp-id';
|
|
process.env.OIDC_PROVIDER_2_CLIENT_SECRET = 'corp-secret';
|
|
process.env.OIDC_PROVIDER_2_AUTO_PROVISION = 'false';
|
|
process.env.OIDC_PROVIDER_2_ADMIN_EMAIL_DOMAINS = 'corp.com';
|
|
|
|
providerConfig.reloadProviders();
|
|
|
|
const google = providerConfig.getProvider('google');
|
|
const corp = providerConfig.getProvider('corp');
|
|
|
|
expect(google.autoProvision).toBe(true);
|
|
expect(google.adminEmailDomains).toEqual([]);
|
|
|
|
expect(corp.autoProvision).toBe(false);
|
|
expect(corp.adminEmailDomains).toEqual(['corp.com']);
|
|
});
|
|
});
|
|
|
|
describe('getProvider', () => {
|
|
beforeEach(() => {
|
|
process.env.OIDC_ENABLED = 'true';
|
|
process.env.OIDC_PROVIDER_NAME = 'Google';
|
|
process.env.OIDC_PROVIDER_SLUG = 'google';
|
|
process.env.OIDC_ISSUER_URL = 'https://accounts.google.com';
|
|
process.env.OIDC_CLIENT_ID = 'test-id';
|
|
process.env.OIDC_CLIENT_SECRET = 'test-secret';
|
|
providerConfig.reloadProviders();
|
|
});
|
|
|
|
it('should return provider by slug', () => {
|
|
const provider = providerConfig.getProvider('google');
|
|
expect(provider).toBeDefined();
|
|
expect(provider.slug).toBe('google');
|
|
});
|
|
|
|
it('should return null for non-existent slug', () => {
|
|
const provider = providerConfig.getProvider('nonexistent');
|
|
expect(provider).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('isOidcEnabled', () => {
|
|
it('should return true when OIDC is enabled with valid provider', () => {
|
|
const consoleLogSpy = jest
|
|
.spyOn(console, 'log')
|
|
.mockImplementation();
|
|
|
|
process.env.OIDC_ENABLED = 'true';
|
|
process.env.OIDC_PROVIDER_NAME = 'Google';
|
|
process.env.OIDC_PROVIDER_SLUG = 'google';
|
|
process.env.OIDC_ISSUER_URL = 'https://accounts.google.com';
|
|
process.env.OIDC_CLIENT_ID = 'test-id';
|
|
process.env.OIDC_CLIENT_SECRET = 'test-secret';
|
|
|
|
providerConfig.reloadProviders();
|
|
expect(providerConfig.isOidcEnabled()).toBe(true);
|
|
|
|
consoleLogSpy.mockRestore();
|
|
});
|
|
|
|
it('should return false when OIDC_ENABLED is false', () => {
|
|
const consoleLogSpy = jest
|
|
.spyOn(console, 'log')
|
|
.mockImplementation();
|
|
|
|
process.env.OIDC_ENABLED = 'false';
|
|
providerConfig.reloadProviders();
|
|
expect(providerConfig.isOidcEnabled()).toBe(false);
|
|
|
|
consoleLogSpy.mockRestore();
|
|
});
|
|
|
|
it('should return false when no providers configured', () => {
|
|
const consoleWarnSpy = jest
|
|
.spyOn(console, 'warn')
|
|
.mockImplementation();
|
|
|
|
process.env.OIDC_ENABLED = 'true';
|
|
providerConfig.reloadProviders();
|
|
expect(providerConfig.isOidcEnabled()).toBe(false);
|
|
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
expect.stringContaining(
|
|
'OIDC is enabled but no valid providers are configured'
|
|
)
|
|
);
|
|
|
|
consoleWarnSpy.mockRestore();
|
|
});
|
|
});
|
|
|
|
describe('provider caching', () => {
|
|
it('should cache providers after first load', () => {
|
|
process.env.OIDC_ENABLED = 'true';
|
|
process.env.OIDC_PROVIDER_NAME = 'Google';
|
|
process.env.OIDC_PROVIDER_SLUG = 'google';
|
|
process.env.OIDC_ISSUER_URL = 'https://accounts.google.com';
|
|
process.env.OIDC_CLIENT_ID = 'test-id';
|
|
process.env.OIDC_CLIENT_SECRET = 'test-secret';
|
|
|
|
providerConfig.reloadProviders();
|
|
const providers1 = providerConfig.getAllProviders();
|
|
|
|
process.env.OIDC_PROVIDER_NAME = 'Changed';
|
|
|
|
const providers2 = providerConfig.getAllProviders();
|
|
|
|
expect(providers1).toBe(providers2);
|
|
expect(providers2[0].name).toBe('Google');
|
|
});
|
|
|
|
it('should reload providers when reloadProviders is called', () => {
|
|
process.env.OIDC_ENABLED = 'true';
|
|
process.env.OIDC_PROVIDER_NAME = 'Google';
|
|
process.env.OIDC_PROVIDER_SLUG = 'google';
|
|
process.env.OIDC_ISSUER_URL = 'https://accounts.google.com';
|
|
process.env.OIDC_CLIENT_ID = 'test-id';
|
|
process.env.OIDC_CLIENT_SECRET = 'test-secret';
|
|
|
|
providerConfig.reloadProviders();
|
|
const providers1 = providerConfig.getAllProviders();
|
|
|
|
process.env.OIDC_PROVIDER_NAME = 'Changed';
|
|
providerConfig.reloadProviders();
|
|
|
|
const providers2 = providerConfig.getAllProviders();
|
|
|
|
expect(providers1).not.toBe(providers2);
|
|
expect(providers2[0].name).toBe('Changed');
|
|
});
|
|
});
|
|
});
|