learning_ai_common_plat/dashboards/admin-web/e2e/smartauth-enterprise.spec.ts
saravanakumardb1 0c4e53a0ed feat(auth): Phase 6 — enterprise SAML/OIDC, magic link, HIBP, E2E specs
6A: Enterprise IdP CRUD, SAML callback, OIDC callback, email domain lookup
6B: Magic link send/verify (15min TTL, anti-enumeration), HIBP breach check
6D: 3 new E2E specs (account-linking, step-up, enterprise) — total 8 SmartAuth specs
- All 53 auth tests passing
2026-03-12 15:25:28 -07:00

131 lines
4.0 KiB
TypeScript

/**
* SmartAuth E2E — Enterprise SAML/OIDC
* Tests IdP configuration, email domain lookup, and SSO login flows.
*/
import { test, expect } from '@playwright/test';
test.describe('SmartAuth: Enterprise SSO', () => {
test.beforeEach(async ({ page }) => {
await page.route('**/api/auth/me', route =>
route.fulfill({
status: 200,
body: JSON.stringify({
id: 'usr_admin',
email: 'admin@bytelyst.com',
role: 'super_admin',
displayName: 'Super Admin',
}),
})
);
});
test('should lookup IdP by email domain', async ({ page }) => {
await page.route('**/api/auth/enterprise/lookup?email=*', route =>
route.fulfill({
status: 200,
body: JSON.stringify({
found: true,
idp: {
id: 'idp_acme_saml_abc123',
orgId: 'org_acme',
protocol: 'saml',
name: 'Acme Corp SAML',
emailDomains: ['acme.com'],
},
}),
})
);
await page.goto('/settings/security');
const response = await page.evaluate(async () => {
const res = await fetch('/api/auth/enterprise/lookup?email=user@acme.com');
return res.json();
});
expect(response.found).toBe(true);
expect(response.idp.protocol).toBe('saml');
});
test('should return not found for unknown domain', async ({ page }) => {
await page.route('**/api/auth/enterprise/lookup?email=*', route =>
route.fulfill({
status: 200,
body: JSON.stringify({ found: false, idp: null }),
})
);
await page.goto('/settings/security');
const response = await page.evaluate(async () => {
const res = await fetch('/api/auth/enterprise/lookup?email=user@unknown.com');
return res.json();
});
expect(response.found).toBe(false);
});
test('should create IdP config (admin)', async ({ page }) => {
await page.route('**/api/auth/enterprise/idps', route => {
if (route.request().method() === 'POST') {
route.fulfill({
status: 200,
body: JSON.stringify({
id: 'idp_acme_oidc_def456',
orgId: 'org_acme',
protocol: 'oidc',
name: 'Acme OIDC',
emailDomains: ['acme.com'],
enabled: true,
}),
});
} else {
route.fulfill({ status: 200, body: '[]' });
}
});
await page.goto('/settings/security');
const response = await page.evaluate(async () => {
const res = await fetch('/api/auth/enterprise/idps', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
orgId: 'org_acme',
protocol: 'oidc',
name: 'Acme OIDC',
emailDomains: ['acme.com'],
oidc: {
issuer: 'https://login.acme.com',
clientId: 'client123',
clientSecret: 'secret456',
authorizationUrl: 'https://login.acme.com/authorize',
tokenUrl: 'https://login.acme.com/token',
},
}),
});
return res.json();
});
expect(response.id).toMatch(/^idp_/);
expect(response.protocol).toBe('oidc');
});
test('should handle SAML callback', async ({ page }) => {
await page.route('**/api/auth/saml/callback', route =>
route.fulfill({
status: 200,
body: JSON.stringify({
accessToken: 'at_test',
refreshToken: 'rt_test',
user: { id: 'usr_saml', email: 'user@acme.com', displayName: 'SAML User' },
}),
})
);
await page.goto('/');
const response = await page.evaluate(async () => {
const samlResponse = btoa('<saml:NameID>user@acme.com</saml:NameID>');
const res = await fetch('/api/auth/saml/callback', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ SAMLResponse: samlResponse }),
});
return res.json();
});
expect(response).toHaveProperty('accessToken');
expect(response.user.email).toBe('user@acme.com');
});
});