@stackwright-pro/auth 0.2.0-alpha.14 → 0.2.0-alpha.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.mts +197 -0
- package/dist/client.d.ts +197 -0
- package/dist/client.js +345 -0
- package/dist/client.js.map +1 -0
- package/dist/client.mjs +334 -0
- package/dist/client.mjs.map +1 -0
- package/dist/index.d.mts +6 -200
- package/dist/index.d.ts +6 -200
- package/dist/index.js +0 -194
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -185
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/cert-parser.ts","../src/pki/header-signing.ts","../src/audit/audit-logger.ts","../src/pki/revocation-checker.ts","../src/providers/pki-provider.ts","../src/oidc/discovery.ts","../src/oidc/token-exchange.ts","../src/oidc/providers/keycloak-adapter.ts","../src/oidc/state.ts","../src/oidc/pkce.ts","../src/providers/oidc-provider.ts","../src/session/token-encryption.ts","../src/session/revocation.ts","../src/session/session-manager.ts","../src/session/cookie-helpers.ts","../src/rbac/rbac-engine.ts","../src/context/AuthContext.tsx","../src/context/AuthProvider.tsx","../src/profiles/dod-cac.ts","../src/decorators/withAuth.tsx","../src/registration.ts"],"names":["crypto","AuditEventType","jose","crypto2","crypto4","crypto5","jose2","crypto6","jsx"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * X.509 Certificate Parser\n *\n * Utilities for parsing and validating X.509 certificates.\n * Supports both PEM/DER formats and gateway header extraction.\n */\n\nimport { X509Certificate } from '@peculiar/x509';\n\nexport interface ParsedCertificate {\n subject: {\n commonName?: string;\n email?: string;\n organizationalUnit?: string[];\n organization?: string;\n country?: string;\n };\n issuer: {\n commonName?: string;\n organization?: string;\n };\n serialNumber: string;\n notBefore: Date;\n notAfter: Date;\n isValid: boolean;\n}\n\n/**\n * Parse X.509 certificate from PEM string or DER buffer\n */\nexport function parseCertificate(pemOrDer: string | ArrayBuffer): ParsedCertificate {\n // Handle both PEM and DER formats\n const cert = new X509Certificate(pemOrDer);\n\n // Extract fields from subject name\n const subjectAttrs = cert.subject.split(',').map((s) => s.trim());\n const issuerAttrs = cert.issuer.split(',').map((s) => s.trim());\n\n return {\n subject: parseNameAttributes(subjectAttrs),\n issuer: {\n commonName: extractAttribute(issuerAttrs, 'CN'),\n organization: extractAttribute(issuerAttrs, 'O'),\n },\n serialNumber: cert.serialNumber,\n notBefore: cert.notBefore,\n notAfter: cert.notAfter,\n isValid: Date.now() >= cert.notBefore.getTime() && Date.now() <= cert.notAfter.getTime(),\n };\n}\n\n/**\n * Extract attribute value from name attributes array\n */\nfunction extractAttribute(attrs: string[], key: string): string | undefined {\n for (const attr of attrs) {\n const [attrKey, ...valueParts] = attr.split('=');\n if (attrKey.trim().toUpperCase() === key.toUpperCase()) {\n return valueParts.join('=').trim();\n }\n }\n return undefined;\n}\n\n/**\n * Extract all attributes with a given key (for multi-valued attributes like OU)\n */\nfunction extractAttributes(attrs: string[], key: string): string[] {\n const results: string[] = [];\n for (const attr of attrs) {\n const [attrKey, ...valueParts] = attr.split('=');\n if (attrKey.trim().toUpperCase() === key.toUpperCase()) {\n results.push(valueParts.join('=').trim());\n }\n }\n return results;\n}\n\n/**\n * Parse name attributes into structured subject object\n */\nfunction parseNameAttributes(attrs: string[]): ParsedCertificate['subject'] {\n return {\n commonName: extractAttribute(attrs, 'CN'),\n email: extractAttribute(attrs, 'E') || extractAttribute(attrs, 'emailAddress'),\n organizationalUnit: extractAttributes(attrs, 'OU'),\n organization: extractAttribute(attrs, 'O'),\n country: extractAttribute(attrs, 'C'),\n };\n}\n\n/**\n * Extract EDIPI from DoD CAC certificate\n * EDIPI is stored in OID 2.16.840.1.101.2.1.11.42\n */\nexport function extractEDIPI(cert: X509Certificate): string | undefined {\n const EDIPI_OID = '2.16.840.1.101.2.1.11.42';\n\n // Try to find EDIPI in certificate extensions\n for (const ext of cert.extensions) {\n if (ext.type === EDIPI_OID) {\n // Parse the extension value (it's ASN.1 encoded)\n const value = ext.value;\n // For now, return as hex string - can parse ASN.1 later if needed\n return Buffer.from(value).toString('hex');\n }\n }\n\n return undefined;\n}\n\n/**\n * Validate certificate against DoD CAC requirements\n */\nexport function validateDoDCAC(parsed: ParsedCertificate): boolean {\n // Check OU contains DOD or DoD\n const hasDoDOU = parsed.subject.organizationalUnit?.some(\n (ou) => ou.toUpperCase().includes('DOD') || ou === 'DoD'\n );\n\n // Check certificate is still valid\n if (!parsed.isValid) {\n return false;\n }\n\n // Must have DoD in OU\n if (!hasDoDOU) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Parse certificate from gateway headers (x-client-cert-* pattern)\n */\nexport function parseCertFromHeaders(\n headers: Record<string, string>,\n prefix = 'x-client-cert-'\n): ParsedCertificate | null {\n const dnHeader = headers[`${prefix}dn`] || headers[`${prefix}subject-dn`];\n const serialHeader = headers[`${prefix}serial`];\n const verifiedHeader = headers[`${prefix}verified`];\n\n if (!dnHeader) {\n return null;\n }\n\n // Parse DN string (format: CN=John Doe,OU=DOD,O=U.S. Government,C=US)\n const subject = parseDN(dnHeader);\n\n // Note: Gateway headers don't give us full cert, so we construct minimal info\n return {\n subject,\n issuer: {}, // Not available from headers\n serialNumber: serialHeader || 'unknown',\n notBefore: new Date(0), // Not available from headers\n notAfter: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000), // Assume valid for a year\n isValid: verifiedHeader?.toUpperCase() === 'SUCCESS',\n };\n}\n\n/**\n * Parse Distinguished Name (DN) string into structured object\n */\nfunction parseDN(dn: string): ParsedCertificate['subject'] {\n const parts = dn.split(',').map((p) => p.trim());\n const result: ParsedCertificate['subject'] = {\n organizationalUnit: [],\n };\n\n for (const part of parts) {\n const [key, ...valueParts] = part.split('=');\n const value = valueParts.join('='); // Handle values with = in them\n\n switch (key.toUpperCase()) {\n case 'CN':\n result.commonName = value;\n break;\n case 'E':\n case 'EMAILADDRESS':\n result.email = value;\n break;\n case 'OU':\n result.organizationalUnit?.push(value);\n break;\n case 'O':\n result.organization = value;\n break;\n case 'C':\n result.country = value;\n break;\n }\n }\n\n return result;\n}\n","/**\n * HMAC Header Signing for PKI Gateway Authentication\n *\n * Prevents header forgery attacks by HMAC-signing certificate headers\n * at the gateway (nginx/HAProxy) and verifying them in the application.\n *\n * Without this, any request that bypasses the reverse proxy can forge\n * x-client-cert-* headers and impersonate any certificate identity.\n *\n * Canonical string format:\n * {prefix}dn:{value}\\n{prefix}issuer:{value}\\n...{prefix}fingerprint:{value}\\n_ts:{timestamp}\n *\n * @see packages/auth/test/integration/docker/nginx/nginx.conf for gateway setup\n */\n\nimport * as crypto from 'node:crypto';\n\n/**\n * Header suffixes included in the HMAC signature.\n * Order matters — both signer and verifier MUST use the same order.\n */\nconst SIGNED_HEADER_SUFFIXES = ['dn', 'issuer', 'serial', 'verify', 'fingerprint'] as const;\n\nexport interface HeaderSigningConfig {\n /** Shared HMAC secret between gateway and application */\n secret: string;\n /** Header name for the signature (default: 'x-client-cert-sig') */\n signatureHeader?: string;\n /** Header name for the timestamp (default: 'x-client-cert-sig-ts') */\n timestampHeader?: string;\n /** Maximum age of signature in seconds (default: 30) */\n maxAge?: number;\n /** Custom header prefix if not using default 'x-client-cert-' */\n headerPrefix?: string;\n}\n\n/**\n * Build the canonical string used for HMAC computation.\n * Extracted to keep signing and verification DRY.\n */\nfunction buildCanonical(\n headers: Record<string, string | undefined>,\n prefix: string,\n timestamp: string\n): string {\n return (\n SIGNED_HEADER_SUFFIXES.map(\n (suffix) => `${prefix}${suffix}:${headers[`${prefix}${suffix}`] || ''}`\n ).join('\\n') + `\\n_ts:${timestamp}`\n );\n}\n\n/**\n * Compute HMAC-SHA256 over a canonical string.\n */\nfunction hmacSign(secret: string, data: string): string {\n return crypto.createHmac('sha256', secret).update(data).digest('base64url');\n}\n\n/**\n * Signs certificate headers with HMAC-SHA256.\n *\n * Used by the gateway (nginx via lua-resty-hmac, or a sidecar) to sign\n * headers before forwarding to the application.\n *\n * @returns Object with `signature` and `timestamp` to set as additional headers\n */\nexport function signCertHeaders(\n headers: Record<string, string>,\n config: HeaderSigningConfig\n): { signature: string; timestamp: string } {\n const prefix = config.headerPrefix || 'x-client-cert-';\n const timestamp = Math.floor(Date.now() / 1000).toString();\n\n const canonical = buildCanonical(headers, prefix, timestamp);\n const signature = hmacSign(config.secret, canonical);\n\n return { signature, timestamp };\n}\n\n/**\n * Verifies the HMAC signature on certificate headers.\n *\n * Call this in the auth provider BEFORE trusting any cert header values.\n * Returns `{ valid: true }` only when the signature is both correct and fresh.\n */\nexport function verifyCertHeaders(\n headers: Record<string, string | undefined>,\n config: HeaderSigningConfig\n): { valid: boolean; reason?: string } {\n const sigHeader = config.signatureHeader || 'x-client-cert-sig';\n const tsHeader = config.timestampHeader || 'x-client-cert-sig-ts';\n const prefix = config.headerPrefix || 'x-client-cert-';\n const maxAge = config.maxAge ?? 30;\n\n const signature = headers[sigHeader];\n const timestamp = headers[tsHeader];\n\n if (!signature) {\n return { valid: false, reason: 'Missing signature header' };\n }\n\n if (!timestamp) {\n return { valid: false, reason: 'Missing timestamp header' };\n }\n\n // Check timestamp freshness\n const ts = parseInt(timestamp, 10);\n if (isNaN(ts)) {\n return { valid: false, reason: 'Invalid timestamp' };\n }\n\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - ts) > maxAge) {\n return {\n valid: false,\n reason: `Signature expired (age: ${Math.abs(now - ts)}s, max: ${maxAge}s)`,\n };\n }\n\n // Reconstruct canonical string and compute expected HMAC\n const canonical = buildCanonical(headers, prefix, timestamp);\n const expected = hmacSign(config.secret, canonical);\n\n // Constant-time comparison to prevent timing attacks\n if (signature.length !== expected.length) {\n return { valid: false, reason: 'Signature mismatch' };\n }\n\n const valid = crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));\n\n return valid ? { valid: true } : { valid: false, reason: 'Signature mismatch' };\n}\n","/**\n * Authentication Audit Logging\n *\n * Pluggable audit logging for all authentication events.\n * Required for government deployments (ATO/SIEM integration).\n *\n * The interface is intentionally simple — implement AuditLogger to\n * send events to CloudWatch, Splunk, ELK, a database, or anywhere else.\n */\n\n/**\n * Authentication audit event types.\n * Maps to security event categories for SIEM integration.\n */\nexport enum AuditEventType {\n // Authentication events\n AUTH_SUCCESS = 'auth.success',\n AUTH_FAILURE = 'auth.failure',\n AUTH_LOGOUT = 'auth.logout',\n\n // Session events\n SESSION_CREATED = 'session.created',\n SESSION_VERIFIED = 'session.verified',\n SESSION_REFRESHED = 'session.refreshed',\n SESSION_EXPIRED = 'session.expired',\n SESSION_INVALID = 'session.invalid',\n SESSION_REVOKED = 'session.revoked',\n\n // Authorization events\n AUTHZ_GRANTED = 'authz.granted',\n AUTHZ_DENIED = 'authz.denied',\n\n // PKI events\n PKI_CERT_VALIDATED = 'pki.cert.validated',\n PKI_CERT_REJECTED = 'pki.cert.rejected',\n PKI_HEADER_SIG_FAILED = 'pki.header_sig.failed',\n\n // Certificate revocation events\n PKI_CERT_REVOKED = 'pki.cert.revoked',\n PKI_REVOCATION_CHECK_FAILED = 'pki.revocation_check.failed',\n\n // OIDC events\n OIDC_STATE_MISMATCH = 'oidc.state_mismatch',\n OIDC_TOKEN_EXCHANGE = 'oidc.token_exchange',\n OIDC_NONCE_MISMATCH = 'oidc.nonce_mismatch',\n}\n\nexport interface AuditEvent {\n /** Event type */\n type: AuditEventType;\n /** ISO 8601 timestamp */\n timestamp: string;\n /** Success or failure */\n outcome: 'success' | 'failure';\n /** User identifier (if known) */\n userId?: string;\n /** IP address (if available) */\n ipAddress?: string;\n /** User agent (if available) */\n userAgent?: string;\n /** Auth method used */\n authMethod?: 'oidc' | 'pki' | 'session';\n /** Additional context */\n details?: Record<string, unknown>;\n /** Request path (if applicable) */\n path?: string;\n /** Session ID / jti (if applicable) */\n sessionId?: string;\n /** Reason for failure */\n reason?: string;\n}\n\n/**\n * Audit logger interface. Implement this to send audit events to your SIEM,\n * CloudWatch, database, or any other sink.\n */\nexport interface AuditLogger {\n log(event: AuditEvent): void | Promise<void>;\n}\n\n/**\n * Console-based audit logger for development and debugging.\n * Outputs structured JSON to stdout.\n */\nexport class ConsoleAuditLogger implements AuditLogger {\n log(event: AuditEvent): void {\n const prefix = event.outcome === 'failure' ? '🔴' : '🟢';\n console.log(`${prefix} [AUDIT] ${JSON.stringify(event)}`);\n }\n}\n\n/**\n * No-op audit logger. Used when auditing is not configured.\n */\nexport class NoopAuditLogger implements AuditLogger {\n log(_event: AuditEvent): void {\n // Intentionally empty\n }\n}\n\n/**\n * Composite logger that fans out to multiple audit sinks.\n */\nexport class CompositeAuditLogger implements AuditLogger {\n constructor(private loggers: AuditLogger[]) {}\n\n async log(event: AuditEvent): Promise<void> {\n await Promise.all(this.loggers.map((l) => l.log(event)));\n }\n}\n\n/**\n * Helper to create audit events with consistent timestamp and defaults.\n */\nexport function createAuditEvent(\n type: AuditEventType,\n outcome: 'success' | 'failure',\n details?: Partial<Omit<AuditEvent, 'type' | 'timestamp' | 'outcome'>>\n): AuditEvent {\n return {\n type,\n timestamp: new Date().toISOString(),\n outcome,\n ...details,\n };\n}\n","/**\n * Certificate Revocation Checking\n *\n * Pluggable OCSP and CRL revocation checking for X.509 certificates.\n * Designed for government/DoD deployments requiring IL-4 compliance.\n *\n * Architecture:\n * - CertRevocationChecker interface — all strategies implement this\n * - OCSPRevocationChecker — queries an OCSP responder via HTTP GET\n * - CRLRevocationChecker — fetches and parses a CRL distribution point\n * - CompositeRevocationChecker — OCSP with CRL fallback\n * - SkipRevocationChecker — passthrough (document that gateway handles it)\n * - RevocationCache — simple TTL cache keyed by serial number\n *\n * Note on gateway_headers source:\n * When PKI source is 'gateway_headers', the application only receives parsed\n * certificate fields — not the raw PEM. OCSP CertID construction requires\n * the issuer's public key hash (issuerKeyHash), which is not available from\n * headers alone. For OCSP with gateway_headers, you MUST configure\n * ocspResponderUrl AND the checker will construct a simplified GET request\n * using the serial number. For full RFC-6960 compliance with direct_tls,\n * the certPem is used to extract AIA and construct the proper CertID.\n */\n\nimport type { CertRevocationConfig } from '@stackwright-pro/types';\n\n// ============================================================================\n// Interfaces\n// ============================================================================\n\nexport interface RevocationInput {\n /** Certificate serial number (hex string, e.g. '1234ABCDEF') */\n serialNumber: string;\n /** Issuer common name if known (from parsed cert) */\n issuerName?: string;\n /** Full certificate PEM — available for direct_tls source only */\n certPem?: string;\n}\n\nexport type RevocationStatus =\n | { revoked: false }\n | { revoked: true; reason?: string; revokedAt?: Date }\n | { revoked: false; skipped: true; reason: string };\n\nexport interface CertRevocationChecker {\n /**\n * Check whether a certificate has been revoked.\n * @returns RevocationStatus — { revoked: true } means reject the cert.\n * @throws May throw if hardFail is true and the check cannot be completed.\n */\n check(input: RevocationInput): Promise<RevocationStatus>;\n}\n\n// ============================================================================\n// TTL Cache\n// ============================================================================\n\ninterface CacheEntry {\n status: RevocationStatus;\n expiresAt: number;\n}\n\nexport class RevocationCache {\n private readonly store = new Map<string, CacheEntry>();\n private readonly maxAgeMs: number;\n\n constructor(cacheMaxAgeSecs: number = 300) {\n this.maxAgeMs = cacheMaxAgeSecs * 1000;\n }\n\n get(serialNumber: string): RevocationStatus | null {\n const entry = this.store.get(serialNumber);\n if (!entry) return null;\n if (Date.now() > entry.expiresAt) {\n this.store.delete(serialNumber);\n return null;\n }\n return entry.status;\n }\n\n set(serialNumber: string, status: RevocationStatus): void {\n this.store.set(serialNumber, {\n status,\n expiresAt: Date.now() + this.maxAgeMs,\n });\n }\n\n /** Invalidate a single entry (e.g. after a forced re-check) */\n invalidate(serialNumber: string): void {\n this.store.delete(serialNumber);\n }\n\n /** Number of cached entries (for testing/monitoring) */\n get size(): number {\n return this.store.size;\n }\n}\n\n// ============================================================================\n// Skip (passthrough) — use when gateway handles revocation\n// ============================================================================\n\nexport class SkipRevocationChecker implements CertRevocationChecker {\n private readonly reason: string;\n\n constructor(reason = 'Revocation checking delegated to upstream gateway') {\n this.reason = reason;\n }\n\n async check(_input: RevocationInput): Promise<RevocationStatus> {\n return { revoked: false, skipped: true, reason: this.reason };\n }\n}\n\n// ============================================================================\n// CRL Checker\n// ============================================================================\n\n/**\n * CRL revocation checker.\n *\n * Fetches a Certificate Revocation List from a distribution point URL\n * and checks whether the certificate serial number appears in it.\n *\n * CRL format: DER-encoded X.509 CRL (RFC 5280). The revoked certificate\n * list is an ASN.1 SEQUENCE of TBSCertList entries, each containing a\n * serial number as an ASN.1 INTEGER.\n *\n * This implementation parses just the serial numbers from the DER blob\n * using manual ASN.1 traversal — no additional dependencies needed.\n */\nexport class CRLRevocationChecker implements CertRevocationChecker {\n private readonly cache: RevocationCache;\n private readonly config: CertRevocationConfig;\n\n constructor(config: CertRevocationConfig) {\n this.config = config;\n this.cache = new RevocationCache(config.cacheMaxAge ?? 300);\n }\n\n async check(input: RevocationInput): Promise<RevocationStatus> {\n const { serialNumber } = input;\n const crlUrl = this.config.crlDistributionPoint;\n\n if (!crlUrl) {\n if (this.config.hardFail) {\n throw new Error('[revocation] CRL strategy requires crlDistributionPoint to be configured');\n }\n return {\n revoked: false,\n skipped: true,\n reason: 'CRL distribution point not configured',\n };\n }\n\n // Check cache first\n const cached = this.cache.get(serialNumber);\n if (cached !== null) return cached;\n\n let derBuffer: ArrayBuffer;\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.config.timeoutMs ?? 5000);\n const response = await fetch(crlUrl, {\n signal: controller.signal,\n headers: { Accept: 'application/pkix-crl' },\n });\n clearTimeout(timer);\n\n if (!response.ok) {\n throw new Error(`CRL fetch returned HTTP ${response.status}`);\n }\n derBuffer = await response.arrayBuffer();\n } catch (err) {\n if (this.config.hardFail) {\n throw new Error(`[revocation] CRL fetch failed (hardFail=true): ${String(err)}`, {\n cause: err,\n });\n }\n return { revoked: false, skipped: true, reason: `CRL fetch failed: ${String(err)}` };\n }\n\n let revokedSerials: Set<string>;\n try {\n revokedSerials = parseCRLRevokedSerials(Buffer.from(derBuffer));\n } catch (err) {\n if (this.config.hardFail) {\n throw new Error(`[revocation] CRL parse failed (hardFail=true): ${String(err)}`, {\n cause: err,\n });\n }\n return { revoked: false, skipped: true, reason: `CRL parse failed: ${String(err)}` };\n }\n\n const normalizedSerial = normalizeSerial(serialNumber);\n const isRevoked = revokedSerials.has(normalizedSerial);\n\n const status: RevocationStatus = isRevoked\n ? { revoked: true, reason: 'Certificate found in CRL' }\n : { revoked: false };\n\n this.cache.set(serialNumber, status);\n return status;\n }\n\n /** Exposed for testing */\n get _cache(): RevocationCache {\n return this.cache;\n }\n}\n\n// ============================================================================\n// OCSP Checker\n// ============================================================================\n\n/**\n * OCSP revocation checker (RFC 6960).\n *\n * Constructs and sends an OCSP GET request to the configured responder.\n * Uses SHA-1 for CertID hashing (per RFC 6960 — SHA-1 is mandated for\n * CertID even though it's deprecated for other uses).\n *\n * For gateway_headers source: requires ocspResponderUrl in config.\n * The serial number is included in the request; issuerNameHash and\n * issuerKeyHash are derived from the CA chain if provided, or zeroed\n * (some OCSP responders accept this for simple serial lookups).\n *\n * For direct_tls source: certPem in RevocationInput enables full\n * CertID construction per RFC 6960.\n */\nexport class OCSPRevocationChecker implements CertRevocationChecker {\n private readonly cache: RevocationCache;\n private readonly config: CertRevocationConfig;\n\n constructor(config: CertRevocationConfig) {\n this.config = config;\n this.cache = new RevocationCache(config.cacheMaxAge ?? 300);\n }\n\n async check(input: RevocationInput): Promise<RevocationStatus> {\n const { serialNumber } = input;\n const ocspUrl = this.config.ocspResponderUrl;\n\n if (!ocspUrl) {\n // For direct_tls with full cert PEM, we could extract AIA — not yet implemented\n if (this.config.hardFail) {\n throw new Error('[revocation] OCSP strategy requires ocspResponderUrl to be configured');\n }\n return {\n revoked: false,\n skipped: true,\n reason: 'OCSP responder URL not configured',\n };\n }\n\n // Check cache first\n const cached = this.cache.get(serialNumber);\n if (cached !== null) return cached;\n\n let response: Response;\n try {\n const ocspRequest = buildOCSPGetRequest(ocspUrl, serialNumber);\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.config.timeoutMs ?? 5000);\n response = await fetch(ocspRequest, {\n signal: controller.signal,\n headers: { Accept: 'application/ocsp-response' },\n });\n clearTimeout(timer);\n } catch (err) {\n if (this.config.hardFail) {\n throw new Error(`[revocation] OCSP request failed (hardFail=true): ${String(err)}`, {\n cause: err,\n });\n }\n return { revoked: false, skipped: true, reason: `OCSP request failed: ${String(err)}` };\n }\n\n if (!response.ok) {\n if (this.config.hardFail) {\n throw new Error(\n `[revocation] OCSP responder returned HTTP ${response.status} (hardFail=true)`\n );\n }\n // Cache non-ok responses to avoid hammering an unavailable responder\n const skippedStatus: RevocationStatus = {\n revoked: false,\n skipped: true,\n reason: `OCSP responder returned HTTP ${response.status}`,\n };\n this.cache.set(serialNumber, skippedStatus);\n return skippedStatus;\n }\n\n let status: RevocationStatus;\n try {\n const derBuffer = await response.arrayBuffer();\n status = parseOCSPResponse(Buffer.from(derBuffer), serialNumber);\n } catch (err) {\n if (this.config.hardFail) {\n throw new Error(`[revocation] OCSP response parse failed (hardFail=true): ${String(err)}`, {\n cause: err,\n });\n }\n return { revoked: false, skipped: true, reason: `OCSP parse failed: ${String(err)}` };\n }\n\n this.cache.set(serialNumber, status);\n return status;\n }\n\n /** Exposed for testing */\n get _cache(): RevocationCache {\n return this.cache;\n }\n}\n\n// ============================================================================\n// Composite (OCSP with CRL fallback)\n// ============================================================================\n\nexport class CompositeRevocationChecker implements CertRevocationChecker {\n private readonly ocsp: OCSPRevocationChecker;\n private readonly crl: CRLRevocationChecker;\n\n constructor(config: CertRevocationConfig) {\n // Use fail-open on OCSP (so CRL gets a chance), hardFail only on CRL\n this.ocsp = new OCSPRevocationChecker({ ...config, hardFail: false });\n this.crl = new CRLRevocationChecker(config);\n }\n\n async check(input: RevocationInput): Promise<RevocationStatus> {\n const ocspResult = await this.ocsp.check(input);\n\n // If OCSP returned a definitive answer (revoked or not-revoked without skip), use it\n if (!('skipped' in ocspResult && ocspResult.skipped)) {\n return ocspResult;\n }\n\n // OCSP was unavailable — fall back to CRL\n return this.crl.check(input);\n }\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\nexport function createRevocationChecker(config: CertRevocationConfig): CertRevocationChecker {\n switch (config.strategy) {\n case 'ocsp':\n return new OCSPRevocationChecker(config);\n case 'crl':\n return new CRLRevocationChecker(config);\n case 'ocsp_with_crl_fallback':\n return new CompositeRevocationChecker(config);\n case 'skip':\n default:\n return new SkipRevocationChecker();\n }\n}\n\n// ============================================================================\n// ASN.1 / DER Parsing Utilities\n// ============================================================================\n\n/**\n * Normalize a certificate serial number to uppercase hex without leading zeros\n * for consistent comparison.\n * Handles formats: '1234abcd', '12:34:ab:cd', '0x1234abcd'\n */\nexport function normalizeSerial(serial: string): string {\n // Remove common separators and prefix\n const clean = serial.replace(/[:\\s]/g, '').replace(/^0x/i, '').toUpperCase();\n // Remove leading zeros (but keep at least one digit)\n return clean.replace(/^0+(?=.)/, '') || '0';\n}\n\n/**\n * Parse revoked certificate serial numbers from a DER-encoded CRL (RFC 5280).\n *\n * CRL DER structure (simplified):\n * CertificateList SEQUENCE {\n * TBSCertList SEQUENCE {\n * ... (version, signature, issuer, thisUpdate, nextUpdate)\n * revokedCertificates SEQUENCE OF {\n * SEQUENCE {\n * userCertificate INTEGER ← serial number we want\n * revocationDate Time\n * ...\n * }\n * }\n * }\n * }\n *\n * We scan for the revokedCertificates SEQUENCE and extract all INTEGER values\n * at the appropriate nesting depth.\n */\nexport function parseCRLRevokedSerials(der: Buffer): Set<string> {\n const serials = new Set<string>();\n\n // Walk the outer SEQUENCE (CertificateList) → inner SEQUENCE (TBSCertList)\n // then find the revokedCertificates SEQUENCE OF\n const tbsCertList = unwrapSequence(unwrapSequence(der));\n\n // Skip past: version (optional), signature AlgorithmIdentifier, issuer Name,\n // thisUpdate Time, nextUpdate Time (optional) to reach revokedCertificates.\n // We do this by scanning for a SEQUENCE OF SEQUENCE pattern.\n let offset = 0;\n let revokedSeqOffset = -1;\n\n while (offset < tbsCertList.length - 2) {\n const tag = tbsCertList[offset];\n if (tag === undefined) break;\n const { length: len, headerLen } = readTLVLength(tbsCertList, offset + 1);\n\n // SEQUENCE (0x30) that contains sub-SEQUENCEs — this is revokedCertificates\n if (tag === 0x30 && len > 0) {\n const inner = tbsCertList.slice(offset + headerLen, offset + headerLen + len);\n // Peek: does it start with another SEQUENCE?\n if (inner.length > 0 && inner[0] === 0x30) {\n // Likely the revokedCertificates block\n revokedSeqOffset = offset + headerLen;\n break;\n }\n }\n\n offset += headerLen + len;\n }\n\n if (revokedSeqOffset === -1) {\n // No revoked certificates in this CRL (valid — empty revocation list)\n return serials;\n }\n\n // Parse each SEQUENCE { INTEGER serial, Time date, ... }\n const revokedBlock = tbsCertList.slice(revokedSeqOffset);\n let pos = 0;\n\n while (pos < revokedBlock.length - 2) {\n const tag = revokedBlock[pos];\n if (tag !== 0x30) break;\n\n const { length: entryLen, headerLen: entryHdrLen } = readTLVLength(revokedBlock, pos + 1);\n const entry = revokedBlock.slice(pos + entryHdrLen, pos + entryHdrLen + entryLen);\n\n // First element of entry SEQUENCE should be INTEGER (serial number)\n if (entry.length > 0 && entry[0] === 0x02) {\n const { length: intLen, headerLen: intHdrLen } = readTLVLength(entry, 1);\n const serialBytes = entry.slice(intHdrLen, intHdrLen + intLen);\n // ASN.1 INTEGER may have a leading 0x00 byte to indicate positive — strip it\n const trimmed =\n serialBytes[0] === 0x00 && serialBytes.length > 1 ? serialBytes.slice(1) : serialBytes;\n const hexSerial = trimmed\n .toString('hex')\n .toUpperCase()\n .replace(/^0+(?=.)/, '');\n serials.add(hexSerial || '0');\n }\n\n pos += entryHdrLen + entryLen;\n }\n\n return serials;\n}\n\n/**\n * Unwrap the first SEQUENCE TLV from a DER buffer, returning its contents.\n */\nfunction unwrapSequence(der: Buffer): Buffer {\n if (der[0] !== 0x30) {\n throw new Error(`Expected SEQUENCE (0x30), got 0x${der[0]?.toString(16)}`);\n }\n const { length, headerLen } = readTLVLength(der, 1);\n return der.slice(headerLen, headerLen + length);\n}\n\n/**\n * Read BER/DER length encoding starting at `offset` in `buf`.\n * Returns the content length and total header bytes consumed (tag + length).\n *\n * @param buf - Buffer to read from\n * @param offset - Position of the length byte (one after the tag byte)\n * @returns length (content byte count) and headerLen (tag + all length bytes)\n */\nfunction readTLVLength(buf: Buffer, offset: number): { length: number; headerLen: number } {\n const firstByte = buf[offset];\n if (firstByte === undefined) throw new Error('Unexpected end of DER data');\n\n if ((firstByte & 0x80) === 0) {\n // Short form: length is in the lower 7 bits; header = 1 tag + 1 length byte\n return { length: firstByte, headerLen: 2 };\n }\n\n // Long form: lower 7 bits = number of subsequent length bytes\n const numLenBytes = firstByte & 0x7f;\n let length = 0;\n for (let i = 1; i <= numLenBytes; i++) {\n const b = buf[offset + i];\n if (b === undefined) throw new Error('Unexpected end of DER length encoding');\n length = (length << 8) | b;\n }\n // headerLen = 1 (tag) + 1 (length indicator byte) + numLenBytes\n return { length, headerLen: 2 + numLenBytes };\n}\n\n/**\n * Build an OCSP GET request URL (RFC 6960 Appendix C).\n *\n * The OCSP GET request URL is: {baseUrl}/{base64url(DER-encoded OCSPRequest)}\n *\n * For the simplified case (serial number only, no full cert chain),\n * we construct a minimal OCSPRequest with zeroed issuerNameHash and\n * issuerKeyHash. Some OCSP responders support this for serial lookup;\n * others require a valid CertID. Document this limitation in comments.\n *\n * For full RFC compliance with direct_tls source, pass certPem and\n * the implementation will construct a proper CertID (future enhancement).\n */\nexport function buildOCSPGetRequest(baseUrl: string, serialNumber: string): string {\n // Encode serial as minimal DER INTEGER\n const serialHex = normalizeSerial(serialNumber);\n const serialBuf = Buffer.from(serialHex.length % 2 === 0 ? serialHex : '0' + serialHex, 'hex');\n\n // Prepend 0x00 if high bit set (to indicate positive integer in ASN.1)\n const serialDer =\n (serialBuf[0] & 0x80) !== 0 ? Buffer.concat([Buffer.from([0x00]), serialBuf]) : serialBuf;\n\n // SHA-1 AlgorithmIdentifier SEQUENCE { OID 1.3.14.3.2.26, NULL }\n // SHA-1 is mandated for CertID per RFC 6960, even though deprecated elsewhere\n const sha1Oid = Buffer.from([\n 0x30,\n 0x09, // SEQUENCE, 9 bytes\n 0x06,\n 0x05,\n 0x2b,\n 0x0e,\n 0x03,\n 0x02,\n 0x1a, // OID 1.3.14.3.2.26 (SHA-1)\n 0x05,\n 0x00, // NULL\n ]);\n\n // 20-byte zeroed hashes (simplified — responder must accept serial-only lookup)\n const zeroHash = Buffer.alloc(20, 0);\n const issuerNameHashDer = derOctetString(zeroHash);\n const issuerKeyHashDer = derOctetString(zeroHash);\n const serialDerTagged = derInteger(serialDer);\n\n // CertID SEQUENCE\n const certId = derSequence(\n Buffer.concat([sha1Oid, issuerNameHashDer, issuerKeyHashDer, serialDerTagged])\n );\n\n // Request SEQUENCE { CertID }\n const requestItem = derSequence(certId);\n\n // requestList SEQUENCE OF Request\n const requestList = derSequence(requestItem);\n\n // TBSRequest SEQUENCE { requestList }\n const tbsRequest = derSequence(requestList);\n\n // OCSPRequest SEQUENCE { TBSRequest }\n const ocspRequest = derSequence(tbsRequest);\n\n const b64 = ocspRequest.toString('base64url');\n const separator = baseUrl.endsWith('/') ? '' : '/';\n return `${baseUrl}${separator}${b64}`;\n}\n\n/**\n * Parse an OCSP response (DER) and determine revocation status.\n *\n * OCSP response status values (RFC 6960):\n * 0 = successful\n * 1 = malformedRequest\n * 2 = internalError\n * 3 = tryLater\n * 5 = sigRequired\n * 6 = unauthorized\n *\n * CertStatus choices:\n * good [0] IMPLICIT NULL\n * revoked [1] IMPLICIT RevokedInfo\n * unknown [2] IMPLICIT UnknownInfo\n */\nexport function parseOCSPResponse(der: Buffer, _serialNumber: string): RevocationStatus {\n // Outer SEQUENCE (OCSPResponse)\n const ocspResponse = unwrapSequence(der);\n\n // First element: responseStatus ENUMERATED\n if (ocspResponse[0] !== 0x0a) {\n throw new Error('Expected ENUMERATED responseStatus in OCSPResponse');\n }\n const statusLen = ocspResponse[1] ?? 0;\n const responseStatus = ocspResponse[2 + statusLen - 1] ?? 0;\n\n if (responseStatus !== 0) {\n // Non-successful OCSP response — treat as inconclusive\n const statusNames: Record<number, string> = {\n 1: 'malformedRequest',\n 2: 'internalError',\n 3: 'tryLater',\n 5: 'sigRequired',\n 6: 'unauthorized',\n };\n throw new Error(\n `OCSP responder returned non-success status: ${statusNames[responseStatus] ?? responseStatus}`\n );\n }\n\n // Scan for CertStatus tag within BasicOCSPResponse\n // [0] IMPLICIT NULL (good) = 0x80 0x00\n // [1] IMPLICIT RevokedInfo (revoked) = 0xa1 ...\n // [2] IMPLICIT UnknownInfo (unknown) = 0x82 ...\n const derStr = ocspResponse.toString('hex');\n\n if (derStr.includes('8000')) {\n return { revoked: false };\n }\n\n if (derStr.includes('a1')) {\n const revokedIdx = ocspResponse.indexOf(0xa1);\n if (revokedIdx !== -1) {\n return {\n revoked: true,\n reason: 'Certificate revoked per OCSP responder',\n };\n }\n }\n\n // Unknown or unparseable — treat as not revoked (fail open unless hardFail)\n return { revoked: false };\n}\n\n// ============================================================================\n// DER Encoding Helpers\n// ============================================================================\n\nfunction derTLV(tag: number, value: Buffer): Buffer {\n const lenBytes = encodeDERLength(value.length);\n return Buffer.concat([Buffer.from([tag]), lenBytes, value]);\n}\n\nfunction derSequence(content: Buffer): Buffer {\n return derTLV(0x30, content);\n}\n\nfunction derOctetString(value: Buffer): Buffer {\n return derTLV(0x04, value);\n}\n\nfunction derInteger(value: Buffer): Buffer {\n return derTLV(0x02, value);\n}\n\nfunction encodeDERLength(len: number): Buffer {\n if (len < 0x80) {\n return Buffer.from([len]);\n } else if (len < 0x100) {\n return Buffer.from([0x81, len]);\n } else if (len < 0x10000) {\n return Buffer.from([0x82, (len >> 8) & 0xff, len & 0xff]);\n }\n throw new Error(`DER length ${len} too large for this implementation`);\n}\n","/**\n * PKI Authentication Provider\n *\n * Implements certificate-based authentication supporting:\n * - Gateway header extraction (e.g., from NGINX, HAProxy)\n * - Direct TLS termination\n * - DoD CAC profile validation\n * - Custom PKI deployments\n * - HMAC header signature verification (prevents header forgery)\n * - Pluggable audit logging for SIEM integration\n */\n\nimport type {\n AuthProvider,\n AuthUser,\n AuthSession,\n AuthContext,\n PKIConfig,\n} from '../types/index.js';\nimport {\n parseCertificate,\n parseCertFromHeaders,\n validateDoDCAC,\n type ParsedCertificate,\n} from '../utils/cert-parser.js';\nimport { verifyCertHeaders } from '../pki/header-signing.js';\nimport { type AuditLogger, AuditEventType, createAuditEvent } from '../audit/audit-logger.js';\nimport {\n createRevocationChecker,\n type CertRevocationChecker,\n type RevocationInput,\n} from '../pki/revocation-checker.js';\n\nexport class PKIProvider implements AuthProvider {\n private auditLogger?: AuditLogger;\n private revocationChecker: CertRevocationChecker;\n\n constructor(\n private config: PKIConfig,\n auditLogger?: AuditLogger\n ) {\n this.auditLogger = auditLogger;\n this.revocationChecker = createRevocationChecker(\n config.revocationCheck ?? { strategy: 'skip' }\n );\n }\n\n async authenticate(context: AuthContext): Promise<AuthUser | null> {\n let parsed: ParsedCertificate | null = null;\n\n // Determine source of certificate data\n if (this.config.source === 'gateway_headers') {\n if (!context.headers) {\n return null;\n }\n\n // When headerSigning is configured, verify HMAC before trusting headers.\n // This prevents header forgery if the gateway is bypassed.\n if (this.config.headerSigning) {\n const result = verifyCertHeaders(context.headers, this.config.headerSigning);\n if (!result.valid) {\n console.error(\n '[stackwright-auth] PKI header signature verification failed: ' + result.reason\n );\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.PKI_HEADER_SIG_FAILED, 'failure', {\n authMethod: 'pki',\n reason: result.reason,\n })\n );\n } catch {\n /* audit must never break auth */\n }\n return null;\n }\n }\n\n parsed = parseCertFromHeaders(context.headers, this.config.headerPrefix);\n } else {\n // direct_tls - expect certificate in context\n // This would be set by server that terminates TLS\n const certData = context.headers?.['x-client-cert'];\n if (!certData) {\n return null;\n }\n parsed = parseCertificate(certData);\n }\n\n if (!parsed) {\n return null;\n }\n\n // Validate certificate is still valid\n if (!parsed.isValid) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.PKI_CERT_REJECTED, 'failure', {\n authMethod: 'pki',\n reason: 'Certificate is not valid (expired or not yet valid)',\n })\n );\n } catch {\n /* audit must never break auth */\n }\n return null;\n }\n\n // Check certificate revocation status (OCSP/CRL/skip based on config)\n const revocationInput: RevocationInput = {\n serialNumber: parsed.serialNumber,\n issuerName: parsed.issuer.commonName,\n // certPem not available for gateway_headers source\n };\n try {\n const revocationStatus = await this.revocationChecker.check(revocationInput);\n if (revocationStatus.revoked) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.PKI_CERT_REVOKED, 'failure', {\n authMethod: 'pki',\n reason:\n 'reason' in revocationStatus ? revocationStatus.reason : 'Certificate revoked',\n details: { serialNumber: parsed.serialNumber },\n })\n );\n } catch {\n /* audit must never break auth */\n }\n return null;\n }\n } catch (err) {\n // Thrown only when hardFail: true\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.PKI_REVOCATION_CHECK_FAILED, 'failure', {\n authMethod: 'pki',\n reason: String(err),\n details: { serialNumber: parsed.serialNumber },\n })\n );\n } catch {\n /* audit must never break auth */\n }\n return null;\n }\n\n // Apply profile-specific validation\n if (this.config.profile === 'dod_cac') {\n if (!validateDoDCAC(parsed)) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.PKI_CERT_REJECTED, 'failure', {\n authMethod: 'pki',\n reason: 'DoD CAC validation failed',\n details: { subject: parsed.subject.commonName },\n })\n );\n } catch {\n /* audit must never break auth */\n }\n return null;\n }\n }\n\n // Check required OU if specified\n if (this.config.requiredOU) {\n const hasRequiredOU = this.config.requiredOU.some((required) =>\n parsed!.subject.organizationalUnit?.some((ou) => ou.includes(required))\n );\n if (!hasRequiredOU) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.PKI_CERT_REJECTED, 'failure', {\n authMethod: 'pki',\n reason: 'Missing required OU',\n details: { subject: parsed.subject.commonName },\n })\n );\n } catch {\n /* audit must never break auth */\n }\n return null;\n }\n }\n\n // Check allowed issuers if specified\n if (this.config.allowedIssuers) {\n const issuerCN = parsed.issuer.commonName;\n if (!issuerCN || !this.config.allowedIssuers.includes(issuerCN)) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.PKI_CERT_REJECTED, 'failure', {\n authMethod: 'pki',\n reason: 'Issuer not in allowedIssuers',\n details: { issuer: issuerCN },\n })\n );\n } catch {\n /* audit must never break auth */\n }\n return null;\n }\n }\n\n // Extract user claims from certificate\n const user: AuthUser = {\n id: parsed.serialNumber, // Use serial as unique ID\n name: parsed.subject.commonName,\n email: parsed.subject.email,\n roles: this.extractRolesFromCertificate(parsed),\n metadata: {\n organizationalUnit: parsed.subject.organizationalUnit,\n organization: parsed.subject.organization,\n country: parsed.subject.country,\n issuer: parsed.issuer.commonName,\n notBefore: parsed.notBefore.toISOString(),\n notAfter: parsed.notAfter.toISOString(),\n },\n };\n\n // Audit success\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.PKI_CERT_VALIDATED, 'success', {\n userId: user.id,\n authMethod: 'pki',\n })\n );\n } catch {\n /* audit must never break auth */\n }\n\n return user;\n }\n\n async validate(session: AuthSession): Promise<boolean> {\n // Check session hasn't expired\n if (Date.now() > session.expiresAt) {\n return false;\n }\n\n // For PKI, we could re-validate the certificate here\n // But that requires storing cert data in session metadata\n // For now, trust the session if it hasn't expired\n\n return true;\n }\n\n /**\n * Extract roles from certificate based on organizational units\n * Can be customized per deployment via subclassing\n */\n private extractRolesFromCertificate(parsed: ParsedCertificate): string[] {\n const roles: string[] = [];\n\n // For DoD CAC, we might derive roles from OU\n const ous = parsed.subject.organizationalUnit || [];\n\n // Example role mapping (customize per deployment)\n if (ous.some((ou) => ou.includes('ADMIN') || ou.includes('ADMINISTRATOR'))) {\n roles.push('ADMIN');\n } else if (ous.some((ou) => ou.includes('ANALYST'))) {\n roles.push('ANALYST');\n } else {\n roles.push('VIEWER'); // Default role\n }\n\n return roles;\n }\n}\n","/**\n * OIDC Discovery Client\n *\n * Handles OIDC provider discovery and authorization URL generation.\n * Follows the OpenID Connect Discovery 1.0 specification.\n */\n\n/**\n * OIDC Provider Metadata (from .well-known/openid-configuration)\n */\nexport interface OIDCMetadata {\n issuer: string;\n authorization_endpoint: string;\n token_endpoint: string;\n jwks_uri: string;\n userinfo_endpoint?: string;\n end_session_endpoint?: string;\n scopes_supported?: string[];\n response_types_supported?: string[];\n code_challenge_methods_supported?: string[];\n}\n\n/**\n * Discover OIDC provider configuration\n *\n * Fetches the OIDC discovery document from the well-known endpoint.\n * This is the first step in any OIDC flow.\n *\n * @param discoveryUrl - Full URL to .well-known/openid-configuration\n * @returns OIDC metadata with endpoints and capabilities\n * @throws Error if discovery fails or metadata is invalid\n */\nexport async function discoverOIDC(discoveryUrl: string): Promise<OIDCMetadata> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 10_000);\n\n try {\n const response = await fetch(discoveryUrl, { signal: controller.signal });\n\n if (!response.ok) {\n throw new Error(`OIDC discovery failed: ${response.statusText}`);\n }\n\n const metadata = (await response.json()) as any;\n\n // Validate required fields per OIDC spec\n if (\n !metadata.issuer ||\n !metadata.authorization_endpoint ||\n !metadata.token_endpoint ||\n !metadata.jwks_uri\n ) {\n throw new Error('Invalid OIDC metadata: missing required fields');\n }\n\n return metadata as OIDCMetadata;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`OIDC request timed out after 10s: ${discoveryUrl}`, { cause: error });\n }\n throw error;\n } finally {\n clearTimeout(timeout);\n }\n}\n\n/**\n * Generate authorization URL for OIDC login\n *\n * Builds the URL to redirect users to for authentication.\n * Follows OAuth 2.0 authorization code flow.\n *\n * @param metadata - OIDC provider metadata from discovery\n * @param clientId - OAuth client ID\n * @param redirectUri - Where to redirect after authentication\n * @param options - Optional state, nonce, PKCE, and scope overrides\n * @returns Authorization URL to redirect user to\n */\nexport function buildAuthorizationUrl(\n metadata: OIDCMetadata,\n clientId: string,\n redirectUri: string,\n options: BuildAuthorizationUrlOptions = {}\n): string {\n const {\n state,\n nonce,\n codeChallenge,\n codeChallengeMethod,\n scopes = ['openid', 'profile', 'email'],\n } = options;\n\n const url = new URL(metadata.authorization_endpoint);\n url.searchParams.set('client_id', clientId);\n url.searchParams.set('redirect_uri', redirectUri);\n url.searchParams.set('response_type', 'code');\n url.searchParams.set('scope', scopes.join(' '));\n\n if (state) {\n url.searchParams.set('state', state);\n }\n if (nonce) {\n url.searchParams.set('nonce', nonce);\n }\n if (codeChallenge && codeChallengeMethod) {\n url.searchParams.set('code_challenge', codeChallenge);\n url.searchParams.set('code_challenge_method', codeChallengeMethod);\n }\n\n return url.toString();\n}\n\nexport interface BuildAuthorizationUrlOptions {\n state?: string;\n nonce?: string;\n codeChallenge?: string;\n codeChallengeMethod?: string;\n scopes?: string[];\n}\n","/**\n * OIDC Token Exchange & Validation\n *\n * Handles OAuth2 token exchange, refresh, and JWT validation.\n * Uses jose for secure JWT operations.\n */\n\nimport * as crypto from 'node:crypto';\nimport * as jose from 'jose';\nimport type { OIDCMetadata } from './discovery.js';\n\nexport interface TokenSet {\n access_token: string;\n id_token: string;\n refresh_token?: string;\n expires_in: number;\n token_type: string;\n}\n\n/**\n * Exchange authorization code for tokens\n *\n * This is step 2 of the OAuth2 authorization code flow.\n * The authorization code is exchanged for access/ID/refresh tokens.\n *\n * @param metadata - OIDC provider metadata\n * @param code - Authorization code from callback\n * @param clientId - OAuth client ID\n * @param clientSecret - OAuth client secret\n * @param redirectUri - Must match the redirect_uri used in authorization\n * @param codeVerifier - PKCE code verifier (if PKCE was used in authorization request)\n * @returns Token set with access_token, id_token, and optionally refresh_token\n * @throws Error if token exchange fails\n */\nexport async function exchangeCodeForTokens(\n metadata: OIDCMetadata,\n code: string,\n clientId: string,\n clientSecret: string,\n redirectUri: string,\n codeVerifier?: string\n): Promise<TokenSet> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 10_000);\n\n try {\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri,\n });\n if (codeVerifier) {\n body.append('code_verifier', codeVerifier);\n }\n\n const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');\n const response = await fetch(metadata.token_endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Authorization: `Basic ${credentials}`,\n },\n body,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n // Log full error server-side, expose only status to caller\n const errorBody = await response.text().catch(() => '');\n console.error(`[stackwright-auth] Token exchange failed (${response.status}):`, errorBody);\n throw new Error(`Token exchange failed: HTTP ${response.status} ${response.statusText}`);\n }\n\n return (await response.json()) as TokenSet;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`OIDC request timed out after 10s: ${metadata.token_endpoint}`, {\n cause: error,\n });\n }\n throw error;\n } finally {\n clearTimeout(timeout);\n }\n}\n\n/**\n * Refresh access token using refresh token\n *\n * When access tokens expire, use the refresh token to get new ones\n * without requiring user to re-authenticate.\n *\n * @param metadata - OIDC provider metadata\n * @param refreshToken - Refresh token from initial token exchange\n * @param clientId - OAuth client ID\n * @param clientSecret - OAuth client secret\n * @returns New token set\n * @throws Error if refresh fails\n */\nexport async function refreshAccessToken(\n metadata: OIDCMetadata,\n refreshToken: string,\n clientId: string,\n clientSecret: string\n): Promise<TokenSet> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 10_000);\n\n try {\n const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');\n const response = await fetch(metadata.token_endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Authorization: `Basic ${credentials}`,\n },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n // Log full error server-side, expose only status to caller\n const errorBody = await response.text().catch(() => '');\n console.error(`[stackwright-auth] Token refresh failed (${response.status}):`, errorBody);\n throw new Error(`Token refresh failed: HTTP ${response.status} ${response.statusText}`);\n }\n\n return (await response.json()) as TokenSet;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`OIDC request timed out after 10s: ${metadata.token_endpoint}`, {\n cause: error,\n });\n }\n throw error;\n } finally {\n clearTimeout(timeout);\n }\n}\n\n/**\n * Validate ID token JWT and extract claims\n *\n * Verifies the JWT signature using the provider's JWKS and validates\n * standard claims (issuer, audience, expiration).\n *\n * This is critical for security - never trust an ID token without validation!\n *\n * @param idToken - JWT ID token from token exchange\n * @param jwksUri - JWKS URI from OIDC metadata\n * @param issuer - Expected issuer (should match token's iss claim)\n * @param clientId - Expected audience (should match token's aud claim)\n * @param skipIssuerCheck - Skip issuer validation (use for Keycloak quirks)\n * @param expectedNonce - Nonce from the authorization request to verify against the ID token (OIDC Core §3.1.3.7)\n * @returns Validated JWT payload with user claims\n * @throws Error if JWT validation fails or nonce mismatch\n */\nexport async function validateIdToken(\n idToken: string,\n jwksUri: string,\n issuer: string,\n clientId: string,\n skipIssuerCheck = false,\n expectedNonce?: string\n): Promise<Record<string, any>> {\n // Fetch JWKS for signature validation\n const JWKS = jose.createRemoteJWKSet(new URL(jwksUri));\n\n // Verify JWT signature and claims\n const { payload } = await jose.jwtVerify(idToken, JWKS, {\n issuer: skipIssuerCheck ? undefined : issuer,\n audience: clientId,\n });\n\n // Verify nonce if expected (OIDC Core §3.1.3.7)\n if (expectedNonce) {\n const tokenNonce = payload.nonce as string | undefined;\n if (!tokenNonce) {\n throw new Error('ID token missing nonce claim');\n }\n // Constant-time comparison to prevent timing attacks\n if (\n tokenNonce.length !== expectedNonce.length ||\n !crypto.timingSafeEqual(Buffer.from(tokenNonce), Buffer.from(expectedNonce))\n ) {\n throw new Error('ID token nonce mismatch — possible replay attack');\n }\n }\n\n return payload as Record<string, any>;\n}\n","/**\n * Keycloak-specific OIDC Adapter\n *\n * Keycloak has several quirks in its OIDC implementation that require\n * special handling. This adapter normalizes Keycloak behavior.\n *\n * Known Issues:\n * 1. Issuer in token doesn't always match discovery URL\n * 2. Refresh token rotation is inconsistent\n * 3. Claims structure differs from standard OIDC\n * 4. Role mapping is non-standard (realm_access.roles)\n */\n\n/**\n * Keycloak-specific OIDC adapter\n *\n * Use this when working with Keycloak to handle its many quirks.\n * Tested with Keycloak 19.x - 23.x\n */\nexport class KeycloakAdapter {\n /**\n * Normalize Keycloak issuer (remove /auth prefix if present)\n *\n * Keycloak's issuer URLs changed between versions:\n * - Pre-17: https://keycloak.example.com/auth/realms/myrealm\n * - Post-17: https://keycloak.example.com/realms/myrealm\n *\n * This normalizes to the post-17 format.\n *\n * @param issuer - Issuer from token or metadata\n * @returns Normalized issuer\n */\n static normalizeIssuer(issuer: string): string {\n return issuer.replace('/auth/realms/', '/realms/');\n }\n\n /**\n * Map Keycloak-specific claims to standard format\n *\n * Keycloak stores roles and groups in non-standard locations:\n * - Roles: realm_access.roles (not standard)\n * - Groups: groups array (sometimes, if configured)\n * - Username: preferred_username (not always 'name')\n *\n * @param tokenPayload - Raw JWT payload from Keycloak\n * @returns Normalized claims matching AuthUser interface\n */\n static mapClaims(tokenPayload: Record<string, any>): Record<string, any> {\n return {\n user_id: tokenPayload.sub,\n email: tokenPayload.email,\n name: tokenPayload.name || tokenPayload.preferred_username,\n roles: tokenPayload.realm_access?.roles || [],\n groups: tokenPayload.groups || [],\n // Keep original payload for advanced use cases\n ...tokenPayload,\n };\n }\n\n /**\n * Keycloak refresh tokens should be refreshed earlier than spec suggests\n *\n * Keycloak's refresh token rotation is buggy and sometimes fails if you\n * wait too long. Refresh aggressively when less than 10 minutes remain.\n *\n * @param expiresIn - Seconds until token expires\n * @returns true if token should be refreshed now\n */\n static shouldRefreshToken(expiresIn: number): boolean {\n // Refresh when less than 10 minutes remaining (Keycloak's rotation is buggy)\n return expiresIn < 600;\n }\n}\n","/**\n * OAuth 2.0 State & Nonce Utilities\n *\n * Provides cryptographically secure state and nonce generation for\n * CSRF protection (state) and ID token replay prevention (nonce).\n *\n * State comparison uses constant-time equality to prevent timing attacks.\n */\n\nimport * as crypto from 'node:crypto';\n\n/**\n * Generates a cryptographically random state parameter for OAuth 2.0 CSRF protection.\n * Returns a URL-safe base64-encoded 32-byte random value (43 characters).\n */\nexport function generateState(): string {\n return crypto.randomBytes(32).toString('base64url');\n}\n\n/**\n * Generates a nonce for OpenID Connect ID Token replay protection.\n * Returns a URL-safe base64-encoded 32-byte random value (43 characters).\n */\nexport function generateNonce(): string {\n return crypto.randomBytes(32).toString('base64url');\n}\n\n/**\n * Constant-time comparison for state/nonce validation.\n * Prevents timing attacks on state parameter verification.\n *\n * @param received - State value received from the callback query params\n * @param expected - State value stored server-side before redirect\n * @returns true if the values match\n */\nexport function verifyState(received: string, expected: string): boolean {\n if (received.length !== expected.length) return false;\n const a = Buffer.from(received);\n const b = Buffer.from(expected);\n return crypto.timingSafeEqual(a, b);\n}\n","/**\n * PKCE (Proof Key for Code Exchange) Utilities — RFC 7636\n *\n * Implements S256 code challenge method for protecting the\n * authorization code grant against interception attacks.\n *\n * Only S256 is supported — the 'plain' method is intentionally excluded\n * as it provides no security benefit and exists only for legacy compatibility.\n */\n\nimport * as crypto from 'node:crypto';\n\n/**\n * Generates a PKCE code verifier (RFC 7636 §4.1).\n *\n * 32 random bytes → 43 base64url characters (within the spec's 43–128 range).\n * Uses the unreserved character set: [A-Z] / [a-z] / [0-9] / \"-\" / \".\" / \"_\" / \"~\"\n */\nexport function generateCodeVerifier(): string {\n return crypto.randomBytes(32).toString('base64url');\n}\n\n/**\n * Generates a PKCE code challenge from a verifier using S256 (RFC 7636 §4.2).\n *\n * challenge = BASE64URL(SHA256(ASCII(code_verifier)))\n *\n * @param verifier - The code verifier string\n * @returns Base64url-encoded SHA-256 hash of the verifier\n */\nexport function generateCodeChallenge(verifier: string): string {\n return crypto.createHash('sha256').update(verifier).digest('base64url');\n}\n","/**\n * OIDC Authentication Provider\n *\n * Implements the AuthProvider interface for OAuth2/OIDC authentication.\n * Supports major providers (Cognito, Azure AD, Keycloak, etc.) with\n * configurable claims mapping and provider-specific quirks handling.\n *\n * Security features:\n * - State parameter for CSRF protection\n * - Nonce for ID token replay prevention\n * - PKCE (S256) for authorization code interception protection\n * - Pluggable audit logging for SIEM integration\n */\n\nimport type {\n AuthProvider,\n AuthUser,\n AuthSession,\n AuthContext,\n OIDCConfig,\n} from '../types/index.js';\nimport { discoverOIDC, buildAuthorizationUrl, type OIDCMetadata } from '../oidc/discovery.js';\nimport {\n exchangeCodeForTokens,\n validateIdToken,\n refreshAccessToken,\n} from '../oidc/token-exchange.js';\nimport { KeycloakAdapter } from '../oidc/providers/keycloak-adapter.js';\nimport { generateState, generateNonce, verifyState } from '../oidc/state.js';\nimport { generateCodeVerifier, generateCodeChallenge } from '../oidc/pkce.js';\nimport { type AuditLogger, AuditEventType, createAuditEvent } from '../audit/audit-logger.js';\n\n/**\n * Returned by getAuthorizationUrl() — contains everything the caller needs\n * to store server-side before redirecting the user.\n */\nexport interface AuthorizationRequest {\n /** The full authorization URL to redirect the user to */\n url: string;\n /** CSRF protection token — store and verify on callback */\n state: string;\n /** ID token replay protection — store and verify on callback */\n nonce: string;\n /** PKCE code verifier — store and send during token exchange (undefined if IdP doesn't support PKCE) */\n codeVerifier?: string;\n}\n\n/**\n * OIDC Provider\n *\n * Handles OAuth2/OIDC authentication flows including:\n * - Discovery of OIDC configuration\n * - Authorization code exchange (with PKCE)\n * - State/CSRF validation\n * - JWT validation\n * - Session refresh\n * - Provider-specific quirks (Keycloak, Cognito, etc.)\n */\nexport class OIDCProvider implements AuthProvider {\n private metadata: OIDCMetadata | null = null;\n private auditLogger?: AuditLogger;\n\n constructor(\n private config: OIDCConfig,\n auditLogger?: AuditLogger\n ) {\n this.auditLogger = auditLogger;\n }\n\n /**\n * Initialize provider by discovering OIDC configuration\n *\n * Call this during app startup to pre-fetch OIDC metadata.\n * If not called, metadata will be lazily loaded on first use.\n */\n async initialize(): Promise<void> {\n this.metadata = await discoverOIDC(this.config.discoveryUrl);\n }\n\n /**\n * Get metadata (lazy load if not initialized)\n */\n private async getMetadata(): Promise<OIDCMetadata> {\n if (!this.metadata) {\n await this.initialize();\n }\n return this.metadata!;\n }\n\n /**\n * Authenticate user by exchanging authorization code for tokens.\n *\n * This is called after the user is redirected back from the OIDC provider\n * with an authorization code in the query parameters.\n *\n * When expectedState is provided, the state parameter from the callback\n * query is verified using constant-time comparison. A mismatch throws\n * to prevent login CSRF attacks.\n *\n * @param context - Auth context with query params and optional security tokens\n * @returns Authenticated user or null if no code present\n * @throws Error if state mismatch (CSRF) or token exchange/validation fails\n */\n async authenticate(context: AuthContext): Promise<AuthUser | null> {\n const code = context.query?.code;\n const redirectUri = this.config.redirectUri || '/api/auth/callback';\n\n if (!code) {\n return null;\n }\n\n // Verify state parameter (CSRF protection)\n const requireState = this.config.requireState !== false; // default true\n\n if (requireState) {\n if (!context.expectedState) {\n throw new Error(\n 'OIDC state validation required but no expectedState provided. ' +\n 'Pass the state from getAuthorizationUrl() stored in the user session.'\n );\n }\n const callbackState = context.query?.state;\n if (!callbackState || !verifyState(callbackState, context.expectedState)) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.OIDC_STATE_MISMATCH, 'failure', {\n authMethod: 'oidc',\n reason: 'State mismatch - possible CSRF',\n })\n );\n } catch {\n /* audit must never break auth */\n }\n throw new Error('OAuth state mismatch \\u2014 possible CSRF attack');\n }\n } else if (context.expectedState) {\n // Even when not required, validate if provided\n const callbackState = context.query?.state;\n if (!callbackState || !verifyState(callbackState, context.expectedState)) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.OIDC_STATE_MISMATCH, 'failure', {\n authMethod: 'oidc',\n reason: 'State mismatch - possible CSRF',\n })\n );\n } catch {\n /* audit must never break auth */\n }\n throw new Error('OAuth state mismatch \\u2014 possible CSRF attack');\n }\n }\n\n const metadata = await this.getMetadata();\n\n // Log token exchange attempt\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.OIDC_TOKEN_EXCHANGE, 'success', { authMethod: 'oidc' })\n );\n } catch {\n /* audit must never break auth */\n }\n\n // Exchange code for tokens (include PKCE verifier if provided)\n const tokens = await exchangeCodeForTokens(\n metadata,\n code,\n this.config.clientId,\n this.config.clientSecret,\n redirectUri,\n context.codeVerifier\n );\n\n // Validate ID token and extract claims\n const issuer = this.config.quirks?.skipIssuerCheck\n ? undefined\n : this.config.provider === 'keycloak'\n ? KeycloakAdapter.normalizeIssuer(metadata.issuer)\n : metadata.issuer;\n\n const claims = await validateIdToken(\n tokens.id_token,\n metadata.jwks_uri,\n issuer || metadata.issuer,\n this.config.clientId,\n this.config.quirks?.skipIssuerCheck,\n context.expectedNonce\n );\n\n // Map claims to AuthUser based on provider-specific logic\n const mappedClaims =\n this.config.provider === 'keycloak' ? KeycloakAdapter.mapClaims(claims) : claims;\n\n // Apply custom claims mapping if provided\n const user: AuthUser = {\n id: this.getClaimValue(mappedClaims, this.config.claimsMapping?.user_id, 'sub'),\n email: this.getClaimValue(mappedClaims, this.config.claimsMapping?.email, 'email'),\n name: this.getClaimValue(mappedClaims, this.config.claimsMapping?.name, 'name'),\n roles: this.extractRoles(mappedClaims),\n metadata: {\n provider: this.config.provider,\n originalClaims: mappedClaims,\n },\n };\n\n // Audit success\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.AUTH_SUCCESS, 'success', {\n userId: user.id,\n authMethod: 'oidc',\n })\n );\n } catch {\n /* audit must never break auth */\n }\n\n return user;\n }\n\n /**\n * Validate session (check if token is still valid)\n *\n * @param session - Session to validate\n * @returns true if session is still valid\n */\n async validate(session: AuthSession): Promise<boolean> {\n if (Date.now() > session.expiresAt) {\n return false;\n }\n return true;\n }\n\n /**\n * Refresh session using refresh token\n *\n * @param session - Session with refresh token\n * @returns Updated session with new tokens, or null if refresh failed\n */\n async refresh(session: AuthSession): Promise<AuthSession | null> {\n if (!session.refreshToken) {\n return null;\n }\n\n const metadata = await this.getMetadata();\n\n try {\n const tokens = await refreshAccessToken(\n metadata,\n session.refreshToken,\n this.config.clientId,\n this.config.clientSecret\n );\n\n return {\n ...session,\n expiresAt: Date.now() + tokens.expires_in * 1000,\n refreshToken: tokens.refresh_token || session.refreshToken,\n };\n } catch {\n return null;\n }\n }\n\n /**\n * Generates the authorization URL for the OIDC provider.\n *\n * The returned state, nonce, and codeVerifier MUST be stored server-side\n * (e.g., in an encrypted cookie or session) before redirecting the user.\n * They are required for validating the callback in authenticate().\n *\n * PKCE (S256) is automatically enabled when the IdP advertises support\n * or when code_challenge_methods_supported is absent from metadata\n * (safe default \\u2014 most modern IdPs support S256).\n *\n * @param redirectUri - Where to redirect after authentication\n * @returns AuthorizationRequest with url, state, nonce, and optional codeVerifier\n */\n async getAuthorizationUrl(redirectUri: string): Promise<AuthorizationRequest> {\n const metadata = await this.getMetadata();\n\n const state = generateState();\n const nonce = generateNonce();\n\n // Enable PKCE when IdP supports S256 or doesn't advertise supported methods\n // (most modern IdPs support S256 even if not declared in metadata)\n let codeVerifier: string | undefined;\n let codeChallenge: string | undefined;\n const supportedMethods = metadata.code_challenge_methods_supported;\n if (!supportedMethods || supportedMethods.includes('S256')) {\n codeVerifier = generateCodeVerifier();\n codeChallenge = generateCodeChallenge(codeVerifier);\n }\n\n const url = buildAuthorizationUrl(metadata, this.config.clientId, redirectUri, {\n state,\n nonce,\n codeChallenge,\n codeChallengeMethod: codeChallenge ? 'S256' : undefined,\n });\n\n return { url, state, nonce, codeVerifier };\n }\n\n /**\n * Extract claim value with fallback\n */\n private getClaimValue(claims: Record<string, any>, mappedKey?: string, defaultKey?: string): any {\n if (mappedKey && claims[mappedKey]) {\n return claims[mappedKey];\n }\n if (defaultKey && claims[defaultKey]) {\n return claims[defaultKey];\n }\n return undefined;\n }\n\n /**\n * Extract roles from claims (provider-specific logic)\n *\n * Different OIDC providers store roles in different places:\n * - Standard: 'roles' claim\n * - Keycloak: realm_access.roles\n * - Cognito: cognito:groups\n * - Azure AD: roles claim\n */\n private extractRoles(claims: Record<string, any>): string[] {\n // Try custom mapping first\n if (this.config.claimsMapping?.roles) {\n const rolesValue = claims[this.config.claimsMapping.roles];\n if (Array.isArray(rolesValue)) {\n return rolesValue;\n }\n if (typeof rolesValue === 'string') {\n return [rolesValue];\n }\n }\n\n // Standard OIDC claims\n if (Array.isArray(claims.roles)) {\n return claims.roles;\n }\n\n // Keycloak realm_access.roles\n if (claims.realm_access?.roles) {\n return claims.realm_access.roles;\n }\n\n // Cognito cognito:groups\n if (claims['cognito:groups']) {\n return claims['cognito:groups'];\n }\n\n // Default: no roles\n return [];\n }\n}\n","import * as jose from 'jose';\nimport * as crypto from 'node:crypto';\n\n/**\n * Derives a 32-byte encryption key from the session secret using HKDF.\n *\n * Uses a distinct info string ('stackwright-token-enc') so this key is\n * cryptographically independent from the HMAC signing key — even though\n * both derive from the same root secret.\n *\n * @param secret - The session secret (any length ≥ 32 chars)\n * @returns A 256-bit (32-byte) key suitable for A256GCM\n */\nexport function deriveEncryptionKey(secret: string): Uint8Array {\n return new Uint8Array(crypto.hkdfSync('sha256', secret, '', 'stackwright-token-enc', 32));\n}\n\n/**\n * Encrypts a token value using JWE (direct key agreement + A256GCM).\n *\n * The output is a JWE compact serialization (5 dot-separated parts) that\n * reveals nothing about the plaintext to anyone without the key.\n *\n * @param token - Plaintext token to encrypt (e.g. a refresh token)\n * @param key - 32-byte encryption key from {@link deriveEncryptionKey}\n * @returns JWE compact serialization string\n */\nexport async function encryptToken(token: string, key: Uint8Array): Promise<string> {\n return new jose.CompactEncrypt(new TextEncoder().encode(token))\n .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' })\n .encrypt(key);\n}\n\n/**\n * Decrypts a JWE-encrypted token value.\n *\n * @param jwe - JWE compact serialization string\n * @param key - 32-byte decryption key from {@link deriveEncryptionKey}\n * @returns The original plaintext token\n * @throws If the JWE is malformed or the key is wrong\n */\nexport async function decryptToken(jwe: string, key: Uint8Array): Promise<string> {\n const { plaintext } = await jose.compactDecrypt(jwe, key);\n return new TextDecoder().decode(plaintext);\n}\n","/**\n * Session Revocation with JTI Claims\n *\n * Provides unique JWT IDs (jti) for session tracking and a pluggable\n * revocation store for invalidating sessions before expiry.\n *\n * The InMemoryRevocationStore is fine for single-instance dev deployments.\n * For production multi-instance deployments, implement RevocationStore\n * backed by Redis, DynamoDB, or similar.\n */\n\nimport * as crypto from 'node:crypto';\n\n/**\n * Generates a unique JWT ID (jti) for session tracking and revocation.\n */\nexport function generateJti(): string {\n return crypto.randomUUID();\n}\n\n/**\n * Session revocation store interface.\n * Implement this to use Redis, database, or any other backend.\n */\nexport interface RevocationStore {\n /** Mark a session as revoked. TTL should match session duration. */\n revoke(jti: string, expiresAt: number): Promise<void>;\n /** Check if a session has been revoked. */\n isRevoked(jti: string): Promise<boolean>;\n}\n\n/**\n * In-memory revocation store for development and single-instance deployments.\n * NOT suitable for multi-instance deployments — use Redis or similar.\n */\nexport class InMemoryRevocationStore implements RevocationStore {\n private revoked = new Map<string, number>(); // jti -> expiry timestamp\n private cleanupInterval: ReturnType<typeof setInterval> | null = null;\n\n constructor(cleanupIntervalMs: number = 60_000) {\n // Periodically clean up expired entries to prevent memory leaks\n this.cleanupInterval = setInterval(() => this.cleanup(), cleanupIntervalMs);\n // Don't prevent process exit\n if (this.cleanupInterval.unref) {\n this.cleanupInterval.unref();\n }\n }\n\n async revoke(jti: string, expiresAt: number): Promise<void> {\n this.revoked.set(jti, expiresAt);\n }\n\n async isRevoked(jti: string): Promise<boolean> {\n return this.revoked.has(jti);\n }\n\n private cleanup(): void {\n const now = Math.floor(Date.now() / 1000);\n for (const [jti, exp] of this.revoked) {\n if (exp < now) {\n this.revoked.delete(jti);\n }\n }\n }\n\n /** Stop the cleanup timer. Call this when shutting down. */\n destroy(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = null;\n }\n }\n\n /** Number of currently tracked revoked sessions (for testing/monitoring). */\n get size(): number {\n return this.revoked.size;\n }\n}\n","import * as jose from 'jose';\nimport type { AuthUser, AuthSession } from '../types/index.js';\nimport { deriveEncryptionKey, encryptToken, decryptToken } from './token-encryption.js';\nimport { type AuditLogger, AuditEventType, createAuditEvent } from '../audit/audit-logger.js';\nimport { generateJti, type RevocationStore } from './revocation.js';\n\nexport interface SessionManagerConfig {\n /**\n * Secret key for JWT signing (must be at least 32 bytes)\n */\n secret: string;\n\n /**\n * Session duration in seconds (default: 15 minutes)\n */\n sessionDuration?: number;\n\n /**\n * Algorithm for JWT signing (default: HS256)\n */\n algorithm?: string;\n\n /**\n * Issuer claim for JWT\n */\n issuer?: string;\n\n /**\n * Audience claim for JWT\n */\n audience?: string;\n\n /**\n * Optional audit logger for security event logging\n */\n auditLogger?: AuditLogger;\n\n /**\n * Optional revocation store for session invalidation via jti claims\n */\n revocationStore?: RevocationStore;\n}\n\nexport class SessionManager {\n private secret: Uint8Array;\n private encryptionKey: Uint8Array;\n private sessionDuration: number;\n private algorithm: string;\n private issuer?: string;\n private audience?: string;\n private auditLogger?: AuditLogger;\n private revocationStore?: RevocationStore;\n\n constructor(config: SessionManagerConfig) {\n // Validate secret length\n if (config.secret.length < 32) {\n throw new Error('Session secret must be at least 32 characters');\n }\n\n // Convert string secret to Uint8Array for jose\n this.secret = new TextEncoder().encode(config.secret);\n // Derive a dedicated 256-bit key for refresh-token encryption (A256GCM)\n this.encryptionKey = deriveEncryptionKey(config.secret);\n this.sessionDuration = config.sessionDuration || 900; // 15 minutes default\n this.algorithm = config.algorithm || 'HS256';\n this.issuer = config.issuer;\n this.audience = config.audience;\n this.auditLogger = config.auditLogger;\n this.revocationStore = config.revocationStore;\n }\n\n /**\n * Create a new session for authenticated user.\n * Automatically assigns a unique jti for revocation support.\n */\n async createSession(user: AuthUser, refreshToken?: string): Promise<AuthSession> {\n const now = Date.now();\n const expiresAt = now + this.sessionDuration * 1000;\n const jti = generateJti();\n\n const session: AuthSession = {\n user,\n issuedAt: now,\n expiresAt,\n refreshToken,\n jti,\n };\n\n // Fire-and-forget audit log\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.SESSION_CREATED, 'success', {\n userId: user.id,\n authMethod: 'session',\n sessionId: jti,\n })\n );\n } catch {\n /* audit must never break auth */\n }\n\n return session;\n }\n\n /**\n * Sign session into a JWT.\n *\n * If the session carries a refresh token it is encrypted with JWE\n * (A256GCM) before being embedded in the payload as `encRefreshToken`.\n * The plaintext `refreshToken` field is **never** written to the JWT.\n *\n * The jti claim is included for session revocation support.\n */\n async signSession(session: AuthSession): Promise<string> {\n // Build payload - encrypt the refresh token so it isn't readable in the JWT\n const payload: Record<string, unknown> = { user: session.user };\n\n if (session.refreshToken) {\n payload.encRefreshToken = await encryptToken(session.refreshToken, this.encryptionKey);\n }\n\n const builder = new jose.SignJWT(payload)\n .setProtectedHeader({ alg: this.algorithm })\n .setIssuedAt(Math.floor(session.issuedAt / 1000)) // jose expects integer seconds\n .setExpirationTime(Math.floor(session.expiresAt / 1000))\n .setIssuer(this.issuer || 'stackwright-auth')\n .setAudience(this.audience || 'stackwright-app');\n\n // Include jti if present (always should be for new sessions)\n if (session.jti) {\n builder.setJti(session.jti);\n }\n\n const jwt = await builder.sign(this.secret);\n\n return jwt;\n }\n\n /**\n * Verify and decode session JWT.\n *\n * Handles two payload shapes:\n * - **Current**: `encRefreshToken` (JWE) - decrypted transparently.\n * - **Legacy**: plain `refreshToken` - accepted for backward compat\n * with a deprecation warning so operators know to rotate sessions.\n *\n * When a revocation store is configured, checks the jti against\n * the store and returns null for revoked sessions.\n */\n async verifySession(jwt: string): Promise<AuthSession | null> {\n try {\n const { payload } = await jose.jwtVerify(jwt, this.secret, {\n issuer: this.issuer || 'stackwright-auth',\n audience: this.audience || 'stackwright-app',\n algorithms: [this.algorithm],\n });\n\n // Check revocation if store is configured and jti is present\n if (this.revocationStore && payload.jti) {\n const revoked = await this.revocationStore.isRevoked(payload.jti as string);\n if (revoked) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.SESSION_REVOKED, 'failure', {\n sessionId: payload.jti as string,\n authMethod: 'session',\n })\n );\n } catch {\n /* audit must never break auth */\n }\n return null;\n }\n }\n\n // Decrypt or fall back to legacy plaintext refresh token\n let refreshToken: string | undefined;\n\n if (payload.encRefreshToken) {\n refreshToken = await decryptToken(payload.encRefreshToken as string, this.encryptionKey);\n } else if (payload.refreshToken) {\n // Backward compatibility: plain refresh token from pre-encryption sessions\n console.warn(\n '[stackwright-auth] WARNING: Session contains unencrypted refresh token. ' +\n 'Rotate sessions to upgrade.'\n );\n refreshToken = payload.refreshToken as string;\n }\n\n // Reconstruct session from payload\n const session: AuthSession = {\n user: payload.user as AuthUser,\n issuedAt: (payload.iat || 0) * 1000, // Convert back to milliseconds\n expiresAt: (payload.exp || 0) * 1000,\n refreshToken,\n jti: payload.jti as string | undefined,\n };\n\n // Fire-and-forget audit log\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.SESSION_VERIFIED, 'success', {\n userId: session.user?.id,\n authMethod: 'session',\n sessionId: session.jti,\n })\n );\n } catch {\n /* audit must never break auth */\n }\n\n return session;\n } catch (error) {\n // Distinguish expired from other failures for audit logging\n const isExpired = error instanceof jose.errors.JWTExpired;\n if (isExpired) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.SESSION_EXPIRED, 'failure', {\n authMethod: 'session',\n reason: 'JWT expired',\n })\n );\n } catch {\n /* audit must never break auth */\n }\n } else {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.SESSION_INVALID, 'failure', {\n authMethod: 'session',\n reason: String(error),\n })\n );\n } catch {\n /* audit must never break auth */\n }\n }\n\n // JWT verification failed (expired, invalid signature, etc.)\n return null;\n }\n }\n\n /**\n * Revoke a session by adding its jti to the revocation store.\n *\n * @throws Error if no revocation store is configured\n * @throws Error if session has no jti claim\n */\n async revokeSession(session: AuthSession): Promise<void> {\n if (!this.revocationStore) {\n throw new Error('Cannot revoke session: no revocation store configured');\n }\n if (!session.jti) {\n throw new Error('Cannot revoke session: session has no jti claim');\n }\n\n await this.revocationStore.revoke(session.jti, session.expiresAt);\n\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.SESSION_REVOKED, 'success', {\n sessionId: session.jti,\n userId: session.user?.id,\n authMethod: 'session',\n })\n );\n } catch {\n /* audit must never break auth */\n }\n }\n\n /**\n * Check if session is expired\n */\n isExpired(session: AuthSession): boolean {\n return Date.now() > session.expiresAt;\n }\n\n /**\n * Check if session should be refreshed (within 5 minutes of expiry)\n */\n shouldRefresh(session: AuthSession): boolean {\n const timeUntilExpiry = session.expiresAt - Date.now();\n const REFRESH_THRESHOLD = 5 * 60 * 1000; // 5 minutes\n\n return timeUntilExpiry < REFRESH_THRESHOLD && timeUntilExpiry > 0;\n }\n\n /**\n * Refresh session (extend expiration)\n */\n async refreshSession(session: AuthSession): Promise<AuthSession> {\n return {\n ...session,\n issuedAt: Date.now(),\n expiresAt: Date.now() + this.sessionDuration * 1000,\n };\n }\n\n /**\n * Serialize session to string (for cookies/localStorage)\n */\n async serialize(session: AuthSession): Promise<string> {\n return this.signSession(session);\n }\n\n /**\n * Deserialize session from string\n */\n async deserialize(serialized: string): Promise<AuthSession | null> {\n return this.verifySession(serialized);\n }\n}\n","/**\n * Cookie options for session cookies\n */\nexport interface CookieOptions {\n /**\n * Cookie name (default: 'stackwright_session')\n */\n name?: string;\n\n /**\n * Domain for cookie\n */\n domain?: string;\n\n /**\n * Path for cookie (default: '/')\n */\n path?: string;\n\n /**\n * Max age in seconds\n */\n maxAge?: number;\n\n /**\n * HttpOnly flag (default: true)\n */\n httpOnly?: boolean;\n\n /**\n * Secure flag (default: true)\n */\n secure?: boolean;\n\n /**\n * SameSite policy (default: 'lax')\n */\n sameSite?: 'strict' | 'lax' | 'none';\n}\n\n/**\n * Serialize cookie with options\n */\nexport function serializeCookie(name: string, value: string, options: CookieOptions = {}): string {\n const {\n domain,\n path = '/',\n maxAge,\n httpOnly = true,\n secure = true, // Always secure by default; opt-out explicitly if needed\n sameSite = 'lax',\n } = options;\n\n const parts: string[] = [`${name}=${encodeURIComponent(value)}`];\n\n if (domain) {\n parts.push(`Domain=${domain}`);\n }\n\n parts.push(`Path=${path}`);\n\n if (maxAge !== undefined) {\n parts.push(`Max-Age=${maxAge}`);\n }\n\n if (httpOnly) {\n parts.push('HttpOnly');\n }\n\n if (secure) {\n parts.push('Secure');\n }\n\n if (sameSite) {\n parts.push(`SameSite=${sameSite.charAt(0).toUpperCase() + sameSite.slice(1)}`);\n }\n\n return parts.join('; ');\n}\n\n/**\n * Parse cookie string into key-value pairs\n */\nexport function parseCookies(cookieHeader?: string): Record<string, string> {\n if (!cookieHeader) {\n return {};\n }\n\n const cookies: Record<string, string> = {};\n\n for (const cookie of cookieHeader.split(';')) {\n const [key, ...valueParts] = cookie.trim().split('=');\n if (key) {\n cookies[key] = decodeURIComponent(valueParts.join('='));\n }\n }\n\n return cookies;\n}\n\n/**\n * Create a cookie header for clearing/deleting a cookie\n */\nexport function clearCookie(\n name: string,\n options: Pick<CookieOptions, 'domain' | 'path'> = {}\n): string {\n return serializeCookie(name, '', {\n ...options,\n maxAge: 0,\n });\n}\n","import type { AuthUser, RBACConfig, ComponentAuthConfig } from '../types/index.js';\n\n/**\n * RBAC Engine for checking roles and permissions\n */\nexport class RBACEngine {\n private config: RBACConfig;\n private rolePermissions: Map<string, Set<string>>;\n\n constructor(config: RBACConfig) {\n this.config = config;\n this.rolePermissions = this.buildRolePermissionMap();\n }\n\n /**\n * Build internal map of role → permissions for fast lookups\n */\n private buildRolePermissionMap(): Map<string, Set<string>> {\n const map = new Map<string, Set<string>>();\n\n for (const role of this.config.roles) {\n map.set(role.name, new Set(role.permissions || []));\n }\n\n return map;\n }\n\n /**\n * Check if user has a specific role\n */\n hasRole(user: AuthUser, role: string): boolean {\n return user.roles.includes(role);\n }\n\n /**\n * Check if user has any of the specified roles\n */\n hasAnyRole(user: AuthUser, roles: string[]): boolean {\n return roles.some((role) => this.hasRole(user, role));\n }\n\n /**\n * Check if user has all of the specified roles\n */\n hasAllRoles(user: AuthUser, roles: string[]): boolean {\n return roles.every((role) => this.hasRole(user, role));\n }\n\n /**\n * Check if user has a specific permission\n * Permissions are checked both:\n * 1. Directly in user.permissions array\n * 2. Through role-based permissions from config\n */\n hasPermission(user: AuthUser, permission: string): boolean {\n // Check direct permissions\n if (user.permissions?.includes(permission)) {\n return true;\n }\n\n // Check role-based permissions\n for (const role of user.roles) {\n const permissions = this.rolePermissions.get(role);\n if (permissions?.has(permission)) {\n return true;\n }\n\n // Check wildcard permissions (e.g., admin:* grants admin:read, admin:write)\n if (permissions) {\n for (const p of permissions) {\n if (p.endsWith(':*')) {\n const prefix = p.slice(0, -1); // Remove the *\n if (permission.startsWith(prefix)) {\n return true;\n }\n }\n }\n }\n }\n\n return false;\n }\n\n /**\n * Check if user has any of the specified permissions\n */\n hasAnyPermission(user: AuthUser, permissions: string[]): boolean {\n return permissions.some((permission) => this.hasPermission(user, permission));\n }\n\n /**\n * Check if user has all of the specified permissions\n */\n hasAllPermissions(user: AuthUser, permissions: string[]): boolean {\n return permissions.every((permission) => this.hasPermission(user, permission));\n }\n\n /**\n * Check if route is public (no auth required)\n */\n isPublicRoute(path: string): boolean {\n if (!this.config.public_routes) {\n return false;\n }\n\n return this.config.public_routes.some((publicPath) => {\n return this.matchPath(path, publicPath);\n });\n }\n\n /**\n * Check if user can access a route based on protected_routes config\n */\n canAccessRoute(user: AuthUser | null, path: string): boolean {\n // Check if route is public\n if (this.isPublicRoute(path)) {\n return true;\n }\n\n // No user = can't access protected routes\n if (!user) {\n return false;\n }\n\n // If no protected routes configured, allow by default\n if (!this.config.protected_routes || this.config.protected_routes.length === 0) {\n return true;\n }\n\n // Find matching protected route\n const matchingRoute = this.config.protected_routes.find((route) => {\n return this.matchPath(path, route.path);\n });\n\n // If no matching protected route, allow (route not explicitly protected)\n if (!matchingRoute) {\n return true;\n }\n\n // Check if user has required role for this route\n return this.hasAnyRole(user, matchingRoute.roles);\n }\n\n /**\n * Check if user can access a component based on component auth config\n */\n canAccessComponent(user: AuthUser | null, authConfig: ComponentAuthConfig | undefined): boolean {\n // No auth config = public component\n if (!authConfig) {\n return true;\n }\n\n // No user = can't access protected component\n if (!user) {\n return false;\n }\n\n // Check required roles\n if (authConfig.required_roles && authConfig.required_roles.length > 0) {\n if (!this.hasAnyRole(user, authConfig.required_roles)) {\n return false;\n }\n }\n\n // Check required permissions\n if (authConfig.required_permissions && authConfig.required_permissions.length > 0) {\n if (!this.hasAllPermissions(user, authConfig.required_permissions)) {\n return false;\n }\n }\n\n return true;\n }\n\n // Match a path against a pattern with wildcard support\n private matchPath(path: string, pattern: string): boolean {\n // Exact match\n if (path === pattern) {\n return true;\n }\n\n // No wildcards in pattern — only exact match applies\n if (!pattern.includes('*')) {\n return false;\n }\n\n // Escape ALL regex metacharacters, then convert glob * to .*\n // This prevents ReDoS from crafted route patterns in YAML config\n const escaped = pattern\n .replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&') // Escape regex specials\n .replace(/\\*/g, '.*'); // Convert glob * to .*\n\n const regex = new RegExp(`^${escaped}$`);\n return regex.test(path);\n }\n}\n","import { createContext, useContext } from 'react';\nimport type { AuthUser, AuthSession } from '../types/index.js';\n\n/**\n * Auth context value provided to component tree\n */\nexport interface AuthContextValue {\n /**\n * Currently authenticated user (null if not authenticated)\n */\n user: AuthUser | null;\n\n /**\n * Current session (null if not authenticated)\n */\n session: AuthSession | null;\n\n /**\n * Whether user is authenticated\n */\n isAuthenticated: boolean;\n\n /**\n * Whether auth is still loading\n */\n isLoading: boolean;\n\n /**\n * Check if user has a specific role\n */\n hasRole: (role: string) => boolean;\n\n /**\n * Check if user has a specific permission\n */\n hasPermission: (permission: string) => boolean;\n\n /**\n * Check if user has any of the specified roles\n */\n hasAnyRole: (roles: string[]) => boolean;\n\n /**\n * Check if user has all of the specified permissions\n */\n hasAllPermissions: (permissions: string[]) => boolean;\n}\n\n/**\n * Auth context - provides authentication state to components\n */\nexport const AuthContext = createContext<AuthContextValue | null>(null);\n\n/**\n * Hook to access auth context\n * Throws error if used outside AuthProvider\n */\nexport function useAuth(): AuthContextValue {\n const context = useContext(AuthContext);\n\n if (!context) {\n throw new Error('useAuth must be used within AuthProvider');\n }\n\n return context;\n}\n\n/**\n * Hook to require authentication\n * Returns null and logs warning if not authenticated\n */\nexport function useRequireAuth(): AuthContextValue | null {\n const auth = useAuth();\n\n if (!auth.isAuthenticated) {\n console.warn('useRequireAuth: User is not authenticated');\n return null;\n }\n\n return auth;\n}\n","import React, { useMemo, type ReactNode, type ReactElement } from 'react';\nimport { AuthContext, type AuthContextValue } from './AuthContext.js';\nimport { RBACEngine } from '../rbac/rbac-engine.js';\nimport type { AuthUser, AuthSession, RBACConfig } from '../types/index.js';\n\nexport interface AuthProviderProps {\n /**\n * Current authenticated user (null if not authenticated)\n */\n user: AuthUser | null;\n\n /**\n * Current session (null if not authenticated)\n */\n session: AuthSession | null;\n\n /**\n * RBAC configuration for role/permission checking\n */\n rbacConfig: RBACConfig;\n\n /**\n * Whether auth is still loading\n */\n isLoading?: boolean;\n\n /**\n * Child components\n */\n children: ReactNode;\n}\n\n/**\n * AuthProvider - Provides authentication state to component tree\n *\n * @example\n * ```tsx\n * <AuthProvider user={user} session={session} rbacConfig={config}>\n * <App />\n * </AuthProvider>\n * ```\n */\nexport function AuthProvider({\n user,\n session,\n rbacConfig,\n isLoading = false,\n children,\n}: AuthProviderProps): ReactElement {\n // Create RBAC engine for role/permission checking\n const rbac = useMemo(() => new RBACEngine(rbacConfig), [rbacConfig]);\n\n // Build context value with helper functions\n const value: AuthContextValue = useMemo(\n () => ({\n user,\n session,\n isAuthenticated: user !== null,\n isLoading,\n\n hasRole: (role: string) => {\n if (!user) return false;\n return rbac.hasRole(user, role);\n },\n\n hasPermission: (permission: string) => {\n if (!user) return false;\n return rbac.hasPermission(user, permission);\n },\n\n hasAnyRole: (roles: string[]) => {\n if (!user) return false;\n return rbac.hasAnyRole(user, roles);\n },\n\n hasAllPermissions: (permissions: string[]) => {\n if (!user) return false;\n return rbac.hasAllPermissions(user, permissions);\n },\n }),\n [user, session, isLoading, rbac]\n );\n\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\n}\n","/**\n * DoD CAC Profile Configuration\n *\n * Pre-built profile for DoD Common Access Card (CAC) certificates.\n *\n * This profile includes:\n * - List of trusted DoD CA issuers\n * - Required OU validation (DOD)\n * - EDIPI extraction for user ID\n *\n * Last updated: 2025-01 (DoD PKI CA list)\n *\n * Note: DoD PKI infrastructure is regularly updated. Verify current CA list at:\n * https://public.cyber.mil/pki-pke/\n */\n\nimport type { PKIConfig } from '../types/index.js';\n\n/**\n * DoD CAC profile configuration\n *\n * This provides sensible defaults for DoD CAC authentication in most deployments.\n * Assumes gateway (e.g., NGINX, HAProxy) handles mTLS and forwards headers.\n */\nexport const DOD_CAC_PROFILE: Omit<PKIConfig, 'type'> = {\n profile: 'dod_cac',\n source: 'gateway_headers',\n headerPrefix: 'x-client-cert-',\n verifiedHeader: 'x-client-cert-verified',\n requiredValue: 'SUCCESS',\n requiredOU: ['DOD', 'DoD', 'U.S. Government'],\n\n // DoD Root CAs (add current list)\n // These are sample CA names - verify against current DoD PKI infrastructure\n allowedIssuers: [\n // DoD Interoperability Root CA 2\n 'CN=DoD Interoperability Root CA 2',\n\n // DoD Root CA 3-6 (current generation)\n 'CN=DoD Root CA 3',\n 'CN=DoD Root CA 4',\n 'CN=DoD Root CA 5',\n 'CN=DoD Root CA 6',\n\n // DoD ID CAs (email/PIV auth)\n 'CN=DOD ID CA-59',\n 'CN=DOD ID CA-60',\n 'CN=DOD ID CA-61',\n 'CN=DOD ID CA-62',\n 'CN=DOD ID CA-63',\n 'CN=DOD ID CA-64',\n 'CN=DOD ID CA-65',\n 'CN=DOD ID CA-66',\n 'CN=DOD ID CA-67',\n 'CN=DOD ID CA-68',\n 'CN=DOD ID CA-69',\n 'CN=DOD ID CA-70',\n\n // DoD SW CAs (software/device auth)\n 'CN=DOD SW CA-59',\n 'CN=DOD SW CA-60',\n 'CN=DOD SW CA-61',\n 'CN=DOD SW CA-62',\n 'CN=DOD SW CA-63',\n 'CN=DOD SW CA-64',\n 'CN=DOD SW CA-65',\n 'CN=DOD SW CA-66',\n\n // Legacy DoD Email CAs (being phased out but may still be in use)\n 'CN=DOD EMAIL CA-59',\n 'CN=DOD EMAIL CA-60',\n 'CN=DOD EMAIL CA-61',\n 'CN=DOD EMAIL CA-62',\n 'CN=DOD EMAIL CA-63',\n 'CN=DOD EMAIL CA-64',\n 'CN=DOD EMAIL CA-65',\n 'CN=DOD EMAIL CA-66',\n ],\n};\n\n/**\n * Create DoD CAC configuration with custom overrides\n *\n * @example\n * ```typescript\n * const config = createDoDCACConfig({\n * source: 'direct_tls', // If terminating TLS in Node.js\n * headerPrefix: 'ssl-client-', // Custom gateway header prefix\n * });\n * ```\n */\nexport function createDoDCACConfig(overrides?: Partial<PKIConfig>): PKIConfig {\n return {\n type: 'pki',\n ...DOD_CAC_PROFILE,\n ...overrides,\n };\n}\n\n/**\n * Minimal DoD CAC config for development/testing\n * Relaxes some requirements for local testing without real CAC cards\n */\nexport function createDoDCACDevConfig(): PKIConfig {\n return {\n type: 'pki',\n profile: 'dod_cac',\n source: 'gateway_headers',\n headerPrefix: 'x-client-cert-',\n verifiedHeader: 'x-client-cert-verified',\n requiredValue: 'SUCCESS',\n // Only require 'DOD' in OU for dev\n requiredOU: ['DOD'],\n // Don't restrict issuers in dev mode\n allowedIssuers: undefined,\n };\n}\n","import React from 'react';\nimport { useAuth } from '../context/AuthContext.js';\nimport type { ComponentAuthConfig } from '../types/index.js';\n\n/**\n * Props that any component wrapped with withAuth will receive\n */\nexport interface ComponentProps {\n id?: string;\n [key: string]: any;\n}\n\n/**\n * Fallback component props\n */\ninterface FallbackProps {\n message?: string;\n className?: string;\n}\n\n/**\n * Default fallback components for unauthorized access\n */\nconst FallbackComponents = {\n /**\n * Hide component (render nothing)\n */\n hide: () => null,\n\n /**\n * Show placeholder message\n */\n placeholder: ({ className }: FallbackProps) => (\n <div\n className={className || 'auth-placeholder'}\n style={{\n padding: '1rem',\n border: '1px dashed #ccc',\n borderRadius: '4px',\n color: '#666',\n fontStyle: 'italic',\n textAlign: 'center',\n }}\n >\n Content requires authorization\n </div>\n ),\n\n /**\n * Show custom message\n */\n message: ({ message, className }: FallbackProps) => (\n <div\n className={className || 'auth-message'}\n style={{\n padding: '1rem',\n border: '1px solid #f0ad4e',\n borderRadius: '4px',\n backgroundColor: '#fcf8e3',\n color: '#8a6d3b',\n }}\n >\n {message || 'Unauthorized'}\n </div>\n ),\n};\n\n/**\n * Higher-order component that wraps a component with authentication checks\n *\n * @example\n * ```tsx\n * const ProtectedButton = withAuth(Button, {\n * required_roles: ['ADMIN'],\n * fallback: 'message',\n * fallback_message: 'Only admins can see this button'\n * });\n * ```\n *\n * @param Component - The component to wrap\n * @param authConfig - Authentication requirements from YAML\n * @returns Wrapped component with auth enforcement\n */\nexport function withAuth<P extends ComponentProps>(\n Component: React.ComponentType<P>,\n authConfig?: ComponentAuthConfig\n): React.ComponentType<P> {\n // If no auth config, return component unchanged\n if (!authConfig) {\n return Component;\n }\n\n // Create wrapped component with display name for debugging\n const WrappedComponent = (props: P) => {\n const auth = useAuth();\n\n // Check role requirements\n if (authConfig.required_roles && authConfig.required_roles.length > 0) {\n if (!auth.hasAnyRole(authConfig.required_roles)) {\n return renderFallback(authConfig);\n }\n }\n\n // Check permission requirements (must have ALL permissions)\n if (authConfig.required_permissions && authConfig.required_permissions.length > 0) {\n if (!auth.hasAllPermissions(authConfig.required_permissions)) {\n return renderFallback(authConfig);\n }\n }\n\n // User authorized - render component\n return <Component {...props} />;\n };\n\n // Set display name for React DevTools\n const componentName = Component.displayName || Component.name || 'Component';\n WrappedComponent.displayName = `withAuth(${componentName})`;\n\n return WrappedComponent;\n}\n\n/**\n * Render fallback component based on configuration\n */\nfunction renderFallback(authConfig: ComponentAuthConfig): React.ReactElement | null {\n const fallbackType = authConfig.fallback || 'hide';\n\n switch (fallbackType) {\n case 'hide':\n return FallbackComponents.hide();\n\n case 'placeholder':\n return FallbackComponents.placeholder({});\n\n case 'message':\n return FallbackComponents.message({\n message: authConfig.fallback_message,\n });\n\n default:\n return null;\n }\n}\n\n/**\n * Custom fallback component (for advanced use cases)\n */\nexport function withAuthFallback<P extends ComponentProps>(\n Component: React.ComponentType<P>,\n authConfig: ComponentAuthConfig,\n FallbackComponent: React.ComponentType<any>\n): React.ComponentType<P> {\n const WrappedComponent = (props: P) => {\n const auth = useAuth();\n\n // Check authorization\n const isAuthorized = checkAuthorization(auth, authConfig);\n\n if (!isAuthorized) {\n return <FallbackComponent />;\n }\n\n return <Component {...props} />;\n };\n\n const componentName = Component.displayName || Component.name || 'Component';\n WrappedComponent.displayName = `withAuthFallback(${componentName})`;\n\n return WrappedComponent;\n}\n\n/**\n * Check if user is authorized based on auth config\n */\nfunction checkAuthorization(\n auth: ReturnType<typeof useAuth>,\n authConfig: ComponentAuthConfig\n): boolean {\n // Check roles\n if (authConfig.required_roles && authConfig.required_roles.length > 0) {\n if (!auth.hasAnyRole(authConfig.required_roles)) {\n return false;\n }\n }\n\n // Check permissions\n if (authConfig.required_permissions && authConfig.required_permissions.length > 0) {\n if (!auth.hasAllPermissions(authConfig.required_permissions)) {\n return false;\n }\n }\n\n return true;\n}\n","import { withAuth } from './decorators/withAuth.js';\nimport type { ComponentAuthConfig } from './types/index.js';\nimport type React from 'react';\n\n/**\n * Global registry for auth decorator function\n * This allows OSS packages to optionally use auth without depending on it\n *\n * Design principle: No hard dependencies!\n * - OSS core never imports from pro packages\n * - Pro package registers itself at runtime\n * - User app is the glue that connects them\n */\nconst authDecoratorRegistry: {\n decorator: typeof withAuth | null;\n} = {\n decorator: null,\n};\n\n/**\n * Register the auth decorator for use by content renderers\n *\n * This should be called once in your app's initialization (e.g., _app.tsx)\n * to enable auth-aware component rendering.\n *\n * @example\n * ```tsx\n * // In pages/_app.tsx\n * import { registerAuthDecorator } from '@stackwright-pro/auth';\n *\n * registerAuthDecorator();\n *\n * function MyApp({ Component, pageProps }: AppProps) {\n * return (\n * <AuthProvider {...authProps}>\n * <Component {...pageProps} />\n * </AuthProvider>\n * );\n * }\n * ```\n */\nexport function registerAuthDecorator(): void {\n authDecoratorRegistry.decorator = withAuth;\n\n // Debug logging (only in browser with debug flag)\n if (typeof window !== 'undefined' && (window as any).__STACKWRIGHT_DEBUG__) {\n console.log('🔐 Auth decorator registered');\n }\n}\n\n/**\n * Get the registered auth decorator (for use by content renderers)\n *\n * Returns null if auth is not registered, allowing graceful degradation.\n * This is the function that OSS core would call to check if auth is available.\n *\n * @returns The withAuth decorator function, or null if not registered\n */\nexport function getAuthDecorator(): typeof withAuth | null {\n return authDecoratorRegistry.decorator;\n}\n\n/**\n * Wrap a component with auth if decorator is registered and config exists\n *\n * This is a safe wrapper that OSS packages can use without depending on auth.\n * If auth is not registered, returns the original component unchanged.\n * If auth config is missing/undefined, returns the original component unchanged.\n *\n * @example\n * ```tsx\n * // In content renderer (can live in OSS core!)\\n * function renderContentItem(item: ContentItem) {\n * const Component = getComponentFromRegistry(item.type);\n *\n * // Apply auth if available\n * const WrappedComponent = maybeWrapWithAuth(Component, item.auth);\n *\n * return <WrappedComponent {...item} />;\n * }\n * ```\n *\n * @param Component - Component to wrap\n * @param authConfig - Auth configuration from YAML (optional)\n * @returns Wrapped component if auth is registered, original component otherwise\n */\nexport function maybeWrapWithAuth<P extends { id?: string; [key: string]: any }>(\n Component: React.ComponentType<P>,\n authConfig?: ComponentAuthConfig\n): React.ComponentType<P> {\n const decorator = getAuthDecorator();\n\n // No decorator registered or no auth config = return unwrapped\n // This ensures graceful degradation when auth isn't installed\n if (!decorator || !authConfig) {\n return Component;\n }\n\n // Wrap with auth\n return decorator(Component, authConfig);\n}\n\n/**\n * Type guard to check if content item has auth config\n *\n * Useful for conditionally applying auth in renderers without\n * needing to import auth types.\n *\n * @example\n * ```tsx\n * if (hasAuthConfig(item)) {\n * // TypeScript knows item.auth exists\n * WrappedComponent = maybeWrapWithAuth(Component, item.auth);\n * }\n * ```\n */\nexport function hasAuthConfig(item: any): item is { auth: ComponentAuthConfig } {\n // Explicitly return boolean to handle null/undefined properly\n if (!item || typeof item !== 'object') {\n return false;\n }\n return 'auth' in item;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/cert-parser.ts","../src/pki/header-signing.ts","../src/audit/audit-logger.ts","../src/pki/revocation-checker.ts","../src/providers/pki-provider.ts","../src/oidc/discovery.ts","../src/oidc/token-exchange.ts","../src/oidc/providers/keycloak-adapter.ts","../src/oidc/state.ts","../src/oidc/pkce.ts","../src/providers/oidc-provider.ts","../src/session/token-encryption.ts","../src/session/revocation.ts","../src/session/session-manager.ts","../src/session/cookie-helpers.ts","../src/rbac/rbac-engine.ts","../src/profiles/dod-cac.ts"],"names":["crypto","AuditEventType","jose","crypto2","crypto4","crypto5","jose2","crypto6"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * X.509 Certificate Parser\n *\n * Utilities for parsing and validating X.509 certificates.\n * Supports both PEM/DER formats and gateway header extraction.\n */\n\nimport { X509Certificate } from '@peculiar/x509';\n\nexport interface ParsedCertificate {\n subject: {\n commonName?: string;\n email?: string;\n organizationalUnit?: string[];\n organization?: string;\n country?: string;\n };\n issuer: {\n commonName?: string;\n organization?: string;\n };\n serialNumber: string;\n notBefore: Date;\n notAfter: Date;\n isValid: boolean;\n}\n\n/**\n * Parse X.509 certificate from PEM string or DER buffer\n */\nexport function parseCertificate(pemOrDer: string | ArrayBuffer): ParsedCertificate {\n // Handle both PEM and DER formats\n const cert = new X509Certificate(pemOrDer);\n\n // Extract fields from subject name\n const subjectAttrs = cert.subject.split(',').map((s) => s.trim());\n const issuerAttrs = cert.issuer.split(',').map((s) => s.trim());\n\n return {\n subject: parseNameAttributes(subjectAttrs),\n issuer: {\n commonName: extractAttribute(issuerAttrs, 'CN'),\n organization: extractAttribute(issuerAttrs, 'O'),\n },\n serialNumber: cert.serialNumber,\n notBefore: cert.notBefore,\n notAfter: cert.notAfter,\n isValid: Date.now() >= cert.notBefore.getTime() && Date.now() <= cert.notAfter.getTime(),\n };\n}\n\n/**\n * Extract attribute value from name attributes array\n */\nfunction extractAttribute(attrs: string[], key: string): string | undefined {\n for (const attr of attrs) {\n const [attrKey, ...valueParts] = attr.split('=');\n if (attrKey.trim().toUpperCase() === key.toUpperCase()) {\n return valueParts.join('=').trim();\n }\n }\n return undefined;\n}\n\n/**\n * Extract all attributes with a given key (for multi-valued attributes like OU)\n */\nfunction extractAttributes(attrs: string[], key: string): string[] {\n const results: string[] = [];\n for (const attr of attrs) {\n const [attrKey, ...valueParts] = attr.split('=');\n if (attrKey.trim().toUpperCase() === key.toUpperCase()) {\n results.push(valueParts.join('=').trim());\n }\n }\n return results;\n}\n\n/**\n * Parse name attributes into structured subject object\n */\nfunction parseNameAttributes(attrs: string[]): ParsedCertificate['subject'] {\n return {\n commonName: extractAttribute(attrs, 'CN'),\n email: extractAttribute(attrs, 'E') || extractAttribute(attrs, 'emailAddress'),\n organizationalUnit: extractAttributes(attrs, 'OU'),\n organization: extractAttribute(attrs, 'O'),\n country: extractAttribute(attrs, 'C'),\n };\n}\n\n/**\n * Extract EDIPI from DoD CAC certificate\n * EDIPI is stored in OID 2.16.840.1.101.2.1.11.42\n */\nexport function extractEDIPI(cert: X509Certificate): string | undefined {\n const EDIPI_OID = '2.16.840.1.101.2.1.11.42';\n\n // Try to find EDIPI in certificate extensions\n for (const ext of cert.extensions) {\n if (ext.type === EDIPI_OID) {\n // Parse the extension value (it's ASN.1 encoded)\n const value = ext.value;\n // For now, return as hex string - can parse ASN.1 later if needed\n return Buffer.from(value).toString('hex');\n }\n }\n\n return undefined;\n}\n\n/**\n * Validate certificate against DoD CAC requirements\n */\nexport function validateDoDCAC(parsed: ParsedCertificate): boolean {\n // Check OU contains DOD or DoD\n const hasDoDOU = parsed.subject.organizationalUnit?.some(\n (ou) => ou.toUpperCase().includes('DOD') || ou === 'DoD'\n );\n\n // Check certificate is still valid\n if (!parsed.isValid) {\n return false;\n }\n\n // Must have DoD in OU\n if (!hasDoDOU) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Parse certificate from gateway headers (x-client-cert-* pattern)\n */\nexport function parseCertFromHeaders(\n headers: Record<string, string>,\n prefix = 'x-client-cert-'\n): ParsedCertificate | null {\n const dnHeader = headers[`${prefix}dn`] || headers[`${prefix}subject-dn`];\n const serialHeader = headers[`${prefix}serial`];\n const verifiedHeader = headers[`${prefix}verified`];\n\n if (!dnHeader) {\n return null;\n }\n\n // Parse DN string (format: CN=John Doe,OU=DOD,O=U.S. Government,C=US)\n const subject = parseDN(dnHeader);\n\n // Note: Gateway headers don't give us full cert, so we construct minimal info\n return {\n subject,\n issuer: {}, // Not available from headers\n serialNumber: serialHeader || 'unknown',\n notBefore: new Date(0), // Not available from headers\n notAfter: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000), // Assume valid for a year\n isValid: verifiedHeader?.toUpperCase() === 'SUCCESS',\n };\n}\n\n/**\n * Parse Distinguished Name (DN) string into structured object\n */\nfunction parseDN(dn: string): ParsedCertificate['subject'] {\n const parts = dn.split(',').map((p) => p.trim());\n const result: ParsedCertificate['subject'] = {\n organizationalUnit: [],\n };\n\n for (const part of parts) {\n const [key, ...valueParts] = part.split('=');\n const value = valueParts.join('='); // Handle values with = in them\n\n switch (key.toUpperCase()) {\n case 'CN':\n result.commonName = value;\n break;\n case 'E':\n case 'EMAILADDRESS':\n result.email = value;\n break;\n case 'OU':\n result.organizationalUnit?.push(value);\n break;\n case 'O':\n result.organization = value;\n break;\n case 'C':\n result.country = value;\n break;\n }\n }\n\n return result;\n}\n","/**\n * HMAC Header Signing for PKI Gateway Authentication\n *\n * Prevents header forgery attacks by HMAC-signing certificate headers\n * at the gateway (nginx/HAProxy) and verifying them in the application.\n *\n * Without this, any request that bypasses the reverse proxy can forge\n * x-client-cert-* headers and impersonate any certificate identity.\n *\n * Canonical string format:\n * {prefix}dn:{value}\\n{prefix}issuer:{value}\\n...{prefix}fingerprint:{value}\\n_ts:{timestamp}\n *\n * @see packages/auth/test/integration/docker/nginx/nginx.conf for gateway setup\n */\n\nimport * as crypto from 'node:crypto';\n\n/**\n * Header suffixes included in the HMAC signature.\n * Order matters — both signer and verifier MUST use the same order.\n */\nconst SIGNED_HEADER_SUFFIXES = ['dn', 'issuer', 'serial', 'verify', 'fingerprint'] as const;\n\nexport interface HeaderSigningConfig {\n /** Shared HMAC secret between gateway and application */\n secret: string;\n /** Header name for the signature (default: 'x-client-cert-sig') */\n signatureHeader?: string;\n /** Header name for the timestamp (default: 'x-client-cert-sig-ts') */\n timestampHeader?: string;\n /** Maximum age of signature in seconds (default: 30) */\n maxAge?: number;\n /** Custom header prefix if not using default 'x-client-cert-' */\n headerPrefix?: string;\n}\n\n/**\n * Build the canonical string used for HMAC computation.\n * Extracted to keep signing and verification DRY.\n */\nfunction buildCanonical(\n headers: Record<string, string | undefined>,\n prefix: string,\n timestamp: string\n): string {\n return (\n SIGNED_HEADER_SUFFIXES.map(\n (suffix) => `${prefix}${suffix}:${headers[`${prefix}${suffix}`] || ''}`\n ).join('\\n') + `\\n_ts:${timestamp}`\n );\n}\n\n/**\n * Compute HMAC-SHA256 over a canonical string.\n */\nfunction hmacSign(secret: string, data: string): string {\n return crypto.createHmac('sha256', secret).update(data).digest('base64url');\n}\n\n/**\n * Signs certificate headers with HMAC-SHA256.\n *\n * Used by the gateway (nginx via lua-resty-hmac, or a sidecar) to sign\n * headers before forwarding to the application.\n *\n * @returns Object with `signature` and `timestamp` to set as additional headers\n */\nexport function signCertHeaders(\n headers: Record<string, string>,\n config: HeaderSigningConfig\n): { signature: string; timestamp: string } {\n const prefix = config.headerPrefix || 'x-client-cert-';\n const timestamp = Math.floor(Date.now() / 1000).toString();\n\n const canonical = buildCanonical(headers, prefix, timestamp);\n const signature = hmacSign(config.secret, canonical);\n\n return { signature, timestamp };\n}\n\n/**\n * Verifies the HMAC signature on certificate headers.\n *\n * Call this in the auth provider BEFORE trusting any cert header values.\n * Returns `{ valid: true }` only when the signature is both correct and fresh.\n */\nexport function verifyCertHeaders(\n headers: Record<string, string | undefined>,\n config: HeaderSigningConfig\n): { valid: boolean; reason?: string } {\n const sigHeader = config.signatureHeader || 'x-client-cert-sig';\n const tsHeader = config.timestampHeader || 'x-client-cert-sig-ts';\n const prefix = config.headerPrefix || 'x-client-cert-';\n const maxAge = config.maxAge ?? 30;\n\n const signature = headers[sigHeader];\n const timestamp = headers[tsHeader];\n\n if (!signature) {\n return { valid: false, reason: 'Missing signature header' };\n }\n\n if (!timestamp) {\n return { valid: false, reason: 'Missing timestamp header' };\n }\n\n // Check timestamp freshness\n const ts = parseInt(timestamp, 10);\n if (isNaN(ts)) {\n return { valid: false, reason: 'Invalid timestamp' };\n }\n\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - ts) > maxAge) {\n return {\n valid: false,\n reason: `Signature expired (age: ${Math.abs(now - ts)}s, max: ${maxAge}s)`,\n };\n }\n\n // Reconstruct canonical string and compute expected HMAC\n const canonical = buildCanonical(headers, prefix, timestamp);\n const expected = hmacSign(config.secret, canonical);\n\n // Constant-time comparison to prevent timing attacks\n if (signature.length !== expected.length) {\n return { valid: false, reason: 'Signature mismatch' };\n }\n\n const valid = crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));\n\n return valid ? { valid: true } : { valid: false, reason: 'Signature mismatch' };\n}\n","/**\n * Authentication Audit Logging\n *\n * Pluggable audit logging for all authentication events.\n * Required for government deployments (ATO/SIEM integration).\n *\n * The interface is intentionally simple — implement AuditLogger to\n * send events to CloudWatch, Splunk, ELK, a database, or anywhere else.\n */\n\n/**\n * Authentication audit event types.\n * Maps to security event categories for SIEM integration.\n */\nexport enum AuditEventType {\n // Authentication events\n AUTH_SUCCESS = 'auth.success',\n AUTH_FAILURE = 'auth.failure',\n AUTH_LOGOUT = 'auth.logout',\n\n // Session events\n SESSION_CREATED = 'session.created',\n SESSION_VERIFIED = 'session.verified',\n SESSION_REFRESHED = 'session.refreshed',\n SESSION_EXPIRED = 'session.expired',\n SESSION_INVALID = 'session.invalid',\n SESSION_REVOKED = 'session.revoked',\n\n // Authorization events\n AUTHZ_GRANTED = 'authz.granted',\n AUTHZ_DENIED = 'authz.denied',\n\n // PKI events\n PKI_CERT_VALIDATED = 'pki.cert.validated',\n PKI_CERT_REJECTED = 'pki.cert.rejected',\n PKI_HEADER_SIG_FAILED = 'pki.header_sig.failed',\n\n // Certificate revocation events\n PKI_CERT_REVOKED = 'pki.cert.revoked',\n PKI_REVOCATION_CHECK_FAILED = 'pki.revocation_check.failed',\n\n // OIDC events\n OIDC_STATE_MISMATCH = 'oidc.state_mismatch',\n OIDC_TOKEN_EXCHANGE = 'oidc.token_exchange',\n OIDC_NONCE_MISMATCH = 'oidc.nonce_mismatch',\n}\n\nexport interface AuditEvent {\n /** Event type */\n type: AuditEventType;\n /** ISO 8601 timestamp */\n timestamp: string;\n /** Success or failure */\n outcome: 'success' | 'failure';\n /** User identifier (if known) */\n userId?: string;\n /** IP address (if available) */\n ipAddress?: string;\n /** User agent (if available) */\n userAgent?: string;\n /** Auth method used */\n authMethod?: 'oidc' | 'pki' | 'session';\n /** Additional context */\n details?: Record<string, unknown>;\n /** Request path (if applicable) */\n path?: string;\n /** Session ID / jti (if applicable) */\n sessionId?: string;\n /** Reason for failure */\n reason?: string;\n}\n\n/**\n * Audit logger interface. Implement this to send audit events to your SIEM,\n * CloudWatch, database, or any other sink.\n */\nexport interface AuditLogger {\n log(event: AuditEvent): void | Promise<void>;\n}\n\n/**\n * Console-based audit logger for development and debugging.\n * Outputs structured JSON to stdout.\n */\nexport class ConsoleAuditLogger implements AuditLogger {\n log(event: AuditEvent): void {\n const prefix = event.outcome === 'failure' ? '🔴' : '🟢';\n console.log(`${prefix} [AUDIT] ${JSON.stringify(event)}`);\n }\n}\n\n/**\n * No-op audit logger. Used when auditing is not configured.\n */\nexport class NoopAuditLogger implements AuditLogger {\n log(_event: AuditEvent): void {\n // Intentionally empty\n }\n}\n\n/**\n * Composite logger that fans out to multiple audit sinks.\n */\nexport class CompositeAuditLogger implements AuditLogger {\n constructor(private loggers: AuditLogger[]) {}\n\n async log(event: AuditEvent): Promise<void> {\n await Promise.all(this.loggers.map((l) => l.log(event)));\n }\n}\n\n/**\n * Helper to create audit events with consistent timestamp and defaults.\n */\nexport function createAuditEvent(\n type: AuditEventType,\n outcome: 'success' | 'failure',\n details?: Partial<Omit<AuditEvent, 'type' | 'timestamp' | 'outcome'>>\n): AuditEvent {\n return {\n type,\n timestamp: new Date().toISOString(),\n outcome,\n ...details,\n };\n}\n","/**\n * Certificate Revocation Checking\n *\n * Pluggable OCSP and CRL revocation checking for X.509 certificates.\n * Designed for government/DoD deployments requiring IL-4 compliance.\n *\n * Architecture:\n * - CertRevocationChecker interface — all strategies implement this\n * - OCSPRevocationChecker — queries an OCSP responder via HTTP GET\n * - CRLRevocationChecker — fetches and parses a CRL distribution point\n * - CompositeRevocationChecker — OCSP with CRL fallback\n * - SkipRevocationChecker — passthrough (document that gateway handles it)\n * - RevocationCache — simple TTL cache keyed by serial number\n *\n * Note on gateway_headers source:\n * When PKI source is 'gateway_headers', the application only receives parsed\n * certificate fields — not the raw PEM. OCSP CertID construction requires\n * the issuer's public key hash (issuerKeyHash), which is not available from\n * headers alone. For OCSP with gateway_headers, you MUST configure\n * ocspResponderUrl AND the checker will construct a simplified GET request\n * using the serial number. For full RFC-6960 compliance with direct_tls,\n * the certPem is used to extract AIA and construct the proper CertID.\n */\n\nimport type { CertRevocationConfig } from '@stackwright-pro/types';\n\n// ============================================================================\n// Interfaces\n// ============================================================================\n\nexport interface RevocationInput {\n /** Certificate serial number (hex string, e.g. '1234ABCDEF') */\n serialNumber: string;\n /** Issuer common name if known (from parsed cert) */\n issuerName?: string;\n /** Full certificate PEM — available for direct_tls source only */\n certPem?: string;\n}\n\nexport type RevocationStatus =\n | { revoked: false }\n | { revoked: true; reason?: string; revokedAt?: Date }\n | { revoked: false; skipped: true; reason: string };\n\nexport interface CertRevocationChecker {\n /**\n * Check whether a certificate has been revoked.\n * @returns RevocationStatus — { revoked: true } means reject the cert.\n * @throws May throw if hardFail is true and the check cannot be completed.\n */\n check(input: RevocationInput): Promise<RevocationStatus>;\n}\n\n// ============================================================================\n// TTL Cache\n// ============================================================================\n\ninterface CacheEntry {\n status: RevocationStatus;\n expiresAt: number;\n}\n\nexport class RevocationCache {\n private readonly store = new Map<string, CacheEntry>();\n private readonly maxAgeMs: number;\n\n constructor(cacheMaxAgeSecs: number = 300) {\n this.maxAgeMs = cacheMaxAgeSecs * 1000;\n }\n\n get(serialNumber: string): RevocationStatus | null {\n const entry = this.store.get(serialNumber);\n if (!entry) return null;\n if (Date.now() > entry.expiresAt) {\n this.store.delete(serialNumber);\n return null;\n }\n return entry.status;\n }\n\n set(serialNumber: string, status: RevocationStatus): void {\n this.store.set(serialNumber, {\n status,\n expiresAt: Date.now() + this.maxAgeMs,\n });\n }\n\n /** Invalidate a single entry (e.g. after a forced re-check) */\n invalidate(serialNumber: string): void {\n this.store.delete(serialNumber);\n }\n\n /** Number of cached entries (for testing/monitoring) */\n get size(): number {\n return this.store.size;\n }\n}\n\n// ============================================================================\n// Skip (passthrough) — use when gateway handles revocation\n// ============================================================================\n\nexport class SkipRevocationChecker implements CertRevocationChecker {\n private readonly reason: string;\n\n constructor(reason = 'Revocation checking delegated to upstream gateway') {\n this.reason = reason;\n }\n\n async check(_input: RevocationInput): Promise<RevocationStatus> {\n return { revoked: false, skipped: true, reason: this.reason };\n }\n}\n\n// ============================================================================\n// CRL Checker\n// ============================================================================\n\n/**\n * CRL revocation checker.\n *\n * Fetches a Certificate Revocation List from a distribution point URL\n * and checks whether the certificate serial number appears in it.\n *\n * CRL format: DER-encoded X.509 CRL (RFC 5280). The revoked certificate\n * list is an ASN.1 SEQUENCE of TBSCertList entries, each containing a\n * serial number as an ASN.1 INTEGER.\n *\n * This implementation parses just the serial numbers from the DER blob\n * using manual ASN.1 traversal — no additional dependencies needed.\n */\nexport class CRLRevocationChecker implements CertRevocationChecker {\n private readonly cache: RevocationCache;\n private readonly config: CertRevocationConfig;\n\n constructor(config: CertRevocationConfig) {\n this.config = config;\n this.cache = new RevocationCache(config.cacheMaxAge ?? 300);\n }\n\n async check(input: RevocationInput): Promise<RevocationStatus> {\n const { serialNumber } = input;\n const crlUrl = this.config.crlDistributionPoint;\n\n if (!crlUrl) {\n if (this.config.hardFail) {\n throw new Error('[revocation] CRL strategy requires crlDistributionPoint to be configured');\n }\n return {\n revoked: false,\n skipped: true,\n reason: 'CRL distribution point not configured',\n };\n }\n\n // Check cache first\n const cached = this.cache.get(serialNumber);\n if (cached !== null) return cached;\n\n let derBuffer: ArrayBuffer;\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.config.timeoutMs ?? 5000);\n const response = await fetch(crlUrl, {\n signal: controller.signal,\n headers: { Accept: 'application/pkix-crl' },\n });\n clearTimeout(timer);\n\n if (!response.ok) {\n throw new Error(`CRL fetch returned HTTP ${response.status}`);\n }\n derBuffer = await response.arrayBuffer();\n } catch (err) {\n if (this.config.hardFail) {\n throw new Error(`[revocation] CRL fetch failed (hardFail=true): ${String(err)}`, {\n cause: err,\n });\n }\n return { revoked: false, skipped: true, reason: `CRL fetch failed: ${String(err)}` };\n }\n\n let revokedSerials: Set<string>;\n try {\n revokedSerials = parseCRLRevokedSerials(Buffer.from(derBuffer));\n } catch (err) {\n if (this.config.hardFail) {\n throw new Error(`[revocation] CRL parse failed (hardFail=true): ${String(err)}`, {\n cause: err,\n });\n }\n return { revoked: false, skipped: true, reason: `CRL parse failed: ${String(err)}` };\n }\n\n const normalizedSerial = normalizeSerial(serialNumber);\n const isRevoked = revokedSerials.has(normalizedSerial);\n\n const status: RevocationStatus = isRevoked\n ? { revoked: true, reason: 'Certificate found in CRL' }\n : { revoked: false };\n\n this.cache.set(serialNumber, status);\n return status;\n }\n\n /** Exposed for testing */\n get _cache(): RevocationCache {\n return this.cache;\n }\n}\n\n// ============================================================================\n// OCSP Checker\n// ============================================================================\n\n/**\n * OCSP revocation checker (RFC 6960).\n *\n * Constructs and sends an OCSP GET request to the configured responder.\n * Uses SHA-1 for CertID hashing (per RFC 6960 — SHA-1 is mandated for\n * CertID even though it's deprecated for other uses).\n *\n * For gateway_headers source: requires ocspResponderUrl in config.\n * The serial number is included in the request; issuerNameHash and\n * issuerKeyHash are derived from the CA chain if provided, or zeroed\n * (some OCSP responders accept this for simple serial lookups).\n *\n * For direct_tls source: certPem in RevocationInput enables full\n * CertID construction per RFC 6960.\n */\nexport class OCSPRevocationChecker implements CertRevocationChecker {\n private readonly cache: RevocationCache;\n private readonly config: CertRevocationConfig;\n\n constructor(config: CertRevocationConfig) {\n this.config = config;\n this.cache = new RevocationCache(config.cacheMaxAge ?? 300);\n }\n\n async check(input: RevocationInput): Promise<RevocationStatus> {\n const { serialNumber } = input;\n const ocspUrl = this.config.ocspResponderUrl;\n\n if (!ocspUrl) {\n // For direct_tls with full cert PEM, we could extract AIA — not yet implemented\n if (this.config.hardFail) {\n throw new Error('[revocation] OCSP strategy requires ocspResponderUrl to be configured');\n }\n return {\n revoked: false,\n skipped: true,\n reason: 'OCSP responder URL not configured',\n };\n }\n\n // Check cache first\n const cached = this.cache.get(serialNumber);\n if (cached !== null) return cached;\n\n let response: Response;\n try {\n const ocspRequest = buildOCSPGetRequest(ocspUrl, serialNumber);\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.config.timeoutMs ?? 5000);\n response = await fetch(ocspRequest, {\n signal: controller.signal,\n headers: { Accept: 'application/ocsp-response' },\n });\n clearTimeout(timer);\n } catch (err) {\n if (this.config.hardFail) {\n throw new Error(`[revocation] OCSP request failed (hardFail=true): ${String(err)}`, {\n cause: err,\n });\n }\n return { revoked: false, skipped: true, reason: `OCSP request failed: ${String(err)}` };\n }\n\n if (!response.ok) {\n if (this.config.hardFail) {\n throw new Error(\n `[revocation] OCSP responder returned HTTP ${response.status} (hardFail=true)`\n );\n }\n // Cache non-ok responses to avoid hammering an unavailable responder\n const skippedStatus: RevocationStatus = {\n revoked: false,\n skipped: true,\n reason: `OCSP responder returned HTTP ${response.status}`,\n };\n this.cache.set(serialNumber, skippedStatus);\n return skippedStatus;\n }\n\n let status: RevocationStatus;\n try {\n const derBuffer = await response.arrayBuffer();\n status = parseOCSPResponse(Buffer.from(derBuffer), serialNumber);\n } catch (err) {\n if (this.config.hardFail) {\n throw new Error(`[revocation] OCSP response parse failed (hardFail=true): ${String(err)}`, {\n cause: err,\n });\n }\n return { revoked: false, skipped: true, reason: `OCSP parse failed: ${String(err)}` };\n }\n\n this.cache.set(serialNumber, status);\n return status;\n }\n\n /** Exposed for testing */\n get _cache(): RevocationCache {\n return this.cache;\n }\n}\n\n// ============================================================================\n// Composite (OCSP with CRL fallback)\n// ============================================================================\n\nexport class CompositeRevocationChecker implements CertRevocationChecker {\n private readonly ocsp: OCSPRevocationChecker;\n private readonly crl: CRLRevocationChecker;\n\n constructor(config: CertRevocationConfig) {\n // Use fail-open on OCSP (so CRL gets a chance), hardFail only on CRL\n this.ocsp = new OCSPRevocationChecker({ ...config, hardFail: false });\n this.crl = new CRLRevocationChecker(config);\n }\n\n async check(input: RevocationInput): Promise<RevocationStatus> {\n const ocspResult = await this.ocsp.check(input);\n\n // If OCSP returned a definitive answer (revoked or not-revoked without skip), use it\n if (!('skipped' in ocspResult && ocspResult.skipped)) {\n return ocspResult;\n }\n\n // OCSP was unavailable — fall back to CRL\n return this.crl.check(input);\n }\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\nexport function createRevocationChecker(config: CertRevocationConfig): CertRevocationChecker {\n switch (config.strategy) {\n case 'ocsp':\n return new OCSPRevocationChecker(config);\n case 'crl':\n return new CRLRevocationChecker(config);\n case 'ocsp_with_crl_fallback':\n return new CompositeRevocationChecker(config);\n case 'skip':\n default:\n return new SkipRevocationChecker();\n }\n}\n\n// ============================================================================\n// ASN.1 / DER Parsing Utilities\n// ============================================================================\n\n/**\n * Normalize a certificate serial number to uppercase hex without leading zeros\n * for consistent comparison.\n * Handles formats: '1234abcd', '12:34:ab:cd', '0x1234abcd'\n */\nexport function normalizeSerial(serial: string): string {\n // Remove common separators and prefix\n const clean = serial.replace(/[:\\s]/g, '').replace(/^0x/i, '').toUpperCase();\n // Remove leading zeros (but keep at least one digit)\n return clean.replace(/^0+(?=.)/, '') || '0';\n}\n\n/**\n * Parse revoked certificate serial numbers from a DER-encoded CRL (RFC 5280).\n *\n * CRL DER structure (simplified):\n * CertificateList SEQUENCE {\n * TBSCertList SEQUENCE {\n * ... (version, signature, issuer, thisUpdate, nextUpdate)\n * revokedCertificates SEQUENCE OF {\n * SEQUENCE {\n * userCertificate INTEGER ← serial number we want\n * revocationDate Time\n * ...\n * }\n * }\n * }\n * }\n *\n * We scan for the revokedCertificates SEQUENCE and extract all INTEGER values\n * at the appropriate nesting depth.\n */\nexport function parseCRLRevokedSerials(der: Buffer): Set<string> {\n const serials = new Set<string>();\n\n // Walk the outer SEQUENCE (CertificateList) → inner SEQUENCE (TBSCertList)\n // then find the revokedCertificates SEQUENCE OF\n const tbsCertList = unwrapSequence(unwrapSequence(der));\n\n // Skip past: version (optional), signature AlgorithmIdentifier, issuer Name,\n // thisUpdate Time, nextUpdate Time (optional) to reach revokedCertificates.\n // We do this by scanning for a SEQUENCE OF SEQUENCE pattern.\n let offset = 0;\n let revokedSeqOffset = -1;\n\n while (offset < tbsCertList.length - 2) {\n const tag = tbsCertList[offset];\n if (tag === undefined) break;\n const { length: len, headerLen } = readTLVLength(tbsCertList, offset + 1);\n\n // SEQUENCE (0x30) that contains sub-SEQUENCEs — this is revokedCertificates\n if (tag === 0x30 && len > 0) {\n const inner = tbsCertList.slice(offset + headerLen, offset + headerLen + len);\n // Peek: does it start with another SEQUENCE?\n if (inner.length > 0 && inner[0] === 0x30) {\n // Likely the revokedCertificates block\n revokedSeqOffset = offset + headerLen;\n break;\n }\n }\n\n offset += headerLen + len;\n }\n\n if (revokedSeqOffset === -1) {\n // No revoked certificates in this CRL (valid — empty revocation list)\n return serials;\n }\n\n // Parse each SEQUENCE { INTEGER serial, Time date, ... }\n const revokedBlock = tbsCertList.slice(revokedSeqOffset);\n let pos = 0;\n\n while (pos < revokedBlock.length - 2) {\n const tag = revokedBlock[pos];\n if (tag !== 0x30) break;\n\n const { length: entryLen, headerLen: entryHdrLen } = readTLVLength(revokedBlock, pos + 1);\n const entry = revokedBlock.slice(pos + entryHdrLen, pos + entryHdrLen + entryLen);\n\n // First element of entry SEQUENCE should be INTEGER (serial number)\n if (entry.length > 0 && entry[0] === 0x02) {\n const { length: intLen, headerLen: intHdrLen } = readTLVLength(entry, 1);\n const serialBytes = entry.slice(intHdrLen, intHdrLen + intLen);\n // ASN.1 INTEGER may have a leading 0x00 byte to indicate positive — strip it\n const trimmed =\n serialBytes[0] === 0x00 && serialBytes.length > 1 ? serialBytes.slice(1) : serialBytes;\n const hexSerial = trimmed\n .toString('hex')\n .toUpperCase()\n .replace(/^0+(?=.)/, '');\n serials.add(hexSerial || '0');\n }\n\n pos += entryHdrLen + entryLen;\n }\n\n return serials;\n}\n\n/**\n * Unwrap the first SEQUENCE TLV from a DER buffer, returning its contents.\n */\nfunction unwrapSequence(der: Buffer): Buffer {\n if (der[0] !== 0x30) {\n throw new Error(`Expected SEQUENCE (0x30), got 0x${der[0]?.toString(16)}`);\n }\n const { length, headerLen } = readTLVLength(der, 1);\n return der.slice(headerLen, headerLen + length);\n}\n\n/**\n * Read BER/DER length encoding starting at `offset` in `buf`.\n * Returns the content length and total header bytes consumed (tag + length).\n *\n * @param buf - Buffer to read from\n * @param offset - Position of the length byte (one after the tag byte)\n * @returns length (content byte count) and headerLen (tag + all length bytes)\n */\nfunction readTLVLength(buf: Buffer, offset: number): { length: number; headerLen: number } {\n const firstByte = buf[offset];\n if (firstByte === undefined) throw new Error('Unexpected end of DER data');\n\n if ((firstByte & 0x80) === 0) {\n // Short form: length is in the lower 7 bits; header = 1 tag + 1 length byte\n return { length: firstByte, headerLen: 2 };\n }\n\n // Long form: lower 7 bits = number of subsequent length bytes\n const numLenBytes = firstByte & 0x7f;\n let length = 0;\n for (let i = 1; i <= numLenBytes; i++) {\n const b = buf[offset + i];\n if (b === undefined) throw new Error('Unexpected end of DER length encoding');\n length = (length << 8) | b;\n }\n // headerLen = 1 (tag) + 1 (length indicator byte) + numLenBytes\n return { length, headerLen: 2 + numLenBytes };\n}\n\n/**\n * Build an OCSP GET request URL (RFC 6960 Appendix C).\n *\n * The OCSP GET request URL is: {baseUrl}/{base64url(DER-encoded OCSPRequest)}\n *\n * For the simplified case (serial number only, no full cert chain),\n * we construct a minimal OCSPRequest with zeroed issuerNameHash and\n * issuerKeyHash. Some OCSP responders support this for serial lookup;\n * others require a valid CertID. Document this limitation in comments.\n *\n * For full RFC compliance with direct_tls source, pass certPem and\n * the implementation will construct a proper CertID (future enhancement).\n */\nexport function buildOCSPGetRequest(baseUrl: string, serialNumber: string): string {\n // Encode serial as minimal DER INTEGER\n const serialHex = normalizeSerial(serialNumber);\n const serialBuf = Buffer.from(serialHex.length % 2 === 0 ? serialHex : '0' + serialHex, 'hex');\n\n // Prepend 0x00 if high bit set (to indicate positive integer in ASN.1)\n const serialDer =\n (serialBuf[0] & 0x80) !== 0 ? Buffer.concat([Buffer.from([0x00]), serialBuf]) : serialBuf;\n\n // SHA-1 AlgorithmIdentifier SEQUENCE { OID 1.3.14.3.2.26, NULL }\n // SHA-1 is mandated for CertID per RFC 6960, even though deprecated elsewhere\n const sha1Oid = Buffer.from([\n 0x30,\n 0x09, // SEQUENCE, 9 bytes\n 0x06,\n 0x05,\n 0x2b,\n 0x0e,\n 0x03,\n 0x02,\n 0x1a, // OID 1.3.14.3.2.26 (SHA-1)\n 0x05,\n 0x00, // NULL\n ]);\n\n // 20-byte zeroed hashes (simplified — responder must accept serial-only lookup)\n const zeroHash = Buffer.alloc(20, 0);\n const issuerNameHashDer = derOctetString(zeroHash);\n const issuerKeyHashDer = derOctetString(zeroHash);\n const serialDerTagged = derInteger(serialDer);\n\n // CertID SEQUENCE\n const certId = derSequence(\n Buffer.concat([sha1Oid, issuerNameHashDer, issuerKeyHashDer, serialDerTagged])\n );\n\n // Request SEQUENCE { CertID }\n const requestItem = derSequence(certId);\n\n // requestList SEQUENCE OF Request\n const requestList = derSequence(requestItem);\n\n // TBSRequest SEQUENCE { requestList }\n const tbsRequest = derSequence(requestList);\n\n // OCSPRequest SEQUENCE { TBSRequest }\n const ocspRequest = derSequence(tbsRequest);\n\n const b64 = ocspRequest.toString('base64url');\n const separator = baseUrl.endsWith('/') ? '' : '/';\n return `${baseUrl}${separator}${b64}`;\n}\n\n/**\n * Parse an OCSP response (DER) and determine revocation status.\n *\n * OCSP response status values (RFC 6960):\n * 0 = successful\n * 1 = malformedRequest\n * 2 = internalError\n * 3 = tryLater\n * 5 = sigRequired\n * 6 = unauthorized\n *\n * CertStatus choices:\n * good [0] IMPLICIT NULL\n * revoked [1] IMPLICIT RevokedInfo\n * unknown [2] IMPLICIT UnknownInfo\n */\nexport function parseOCSPResponse(der: Buffer, _serialNumber: string): RevocationStatus {\n // Outer SEQUENCE (OCSPResponse)\n const ocspResponse = unwrapSequence(der);\n\n // First element: responseStatus ENUMERATED\n if (ocspResponse[0] !== 0x0a) {\n throw new Error('Expected ENUMERATED responseStatus in OCSPResponse');\n }\n const statusLen = ocspResponse[1] ?? 0;\n const responseStatus = ocspResponse[2 + statusLen - 1] ?? 0;\n\n if (responseStatus !== 0) {\n // Non-successful OCSP response — treat as inconclusive\n const statusNames: Record<number, string> = {\n 1: 'malformedRequest',\n 2: 'internalError',\n 3: 'tryLater',\n 5: 'sigRequired',\n 6: 'unauthorized',\n };\n throw new Error(\n `OCSP responder returned non-success status: ${statusNames[responseStatus] ?? responseStatus}`\n );\n }\n\n // Scan for CertStatus tag within BasicOCSPResponse\n // [0] IMPLICIT NULL (good) = 0x80 0x00\n // [1] IMPLICIT RevokedInfo (revoked) = 0xa1 ...\n // [2] IMPLICIT UnknownInfo (unknown) = 0x82 ...\n const derStr = ocspResponse.toString('hex');\n\n if (derStr.includes('8000')) {\n return { revoked: false };\n }\n\n if (derStr.includes('a1')) {\n const revokedIdx = ocspResponse.indexOf(0xa1);\n if (revokedIdx !== -1) {\n return {\n revoked: true,\n reason: 'Certificate revoked per OCSP responder',\n };\n }\n }\n\n // Unknown or unparseable — treat as not revoked (fail open unless hardFail)\n return { revoked: false };\n}\n\n// ============================================================================\n// DER Encoding Helpers\n// ============================================================================\n\nfunction derTLV(tag: number, value: Buffer): Buffer {\n const lenBytes = encodeDERLength(value.length);\n return Buffer.concat([Buffer.from([tag]), lenBytes, value]);\n}\n\nfunction derSequence(content: Buffer): Buffer {\n return derTLV(0x30, content);\n}\n\nfunction derOctetString(value: Buffer): Buffer {\n return derTLV(0x04, value);\n}\n\nfunction derInteger(value: Buffer): Buffer {\n return derTLV(0x02, value);\n}\n\nfunction encodeDERLength(len: number): Buffer {\n if (len < 0x80) {\n return Buffer.from([len]);\n } else if (len < 0x100) {\n return Buffer.from([0x81, len]);\n } else if (len < 0x10000) {\n return Buffer.from([0x82, (len >> 8) & 0xff, len & 0xff]);\n }\n throw new Error(`DER length ${len} too large for this implementation`);\n}\n","/**\n * PKI Authentication Provider\n *\n * Implements certificate-based authentication supporting:\n * - Gateway header extraction (e.g., from NGINX, HAProxy)\n * - Direct TLS termination\n * - DoD CAC profile validation\n * - Custom PKI deployments\n * - HMAC header signature verification (prevents header forgery)\n * - Pluggable audit logging for SIEM integration\n */\n\nimport type {\n AuthProvider,\n AuthUser,\n AuthSession,\n AuthContext,\n PKIConfig,\n} from '../types/index.js';\nimport {\n parseCertificate,\n parseCertFromHeaders,\n validateDoDCAC,\n type ParsedCertificate,\n} from '../utils/cert-parser.js';\nimport { verifyCertHeaders } from '../pki/header-signing.js';\nimport { type AuditLogger, AuditEventType, createAuditEvent } from '../audit/audit-logger.js';\nimport {\n createRevocationChecker,\n type CertRevocationChecker,\n type RevocationInput,\n} from '../pki/revocation-checker.js';\n\nexport class PKIProvider implements AuthProvider {\n private auditLogger?: AuditLogger;\n private revocationChecker: CertRevocationChecker;\n\n constructor(\n private config: PKIConfig,\n auditLogger?: AuditLogger\n ) {\n this.auditLogger = auditLogger;\n this.revocationChecker = createRevocationChecker(\n config.revocationCheck ?? { strategy: 'skip' }\n );\n }\n\n async authenticate(context: AuthContext): Promise<AuthUser | null> {\n let parsed: ParsedCertificate | null = null;\n\n // Determine source of certificate data\n if (this.config.source === 'gateway_headers') {\n if (!context.headers) {\n return null;\n }\n\n // When headerSigning is configured, verify HMAC before trusting headers.\n // This prevents header forgery if the gateway is bypassed.\n if (this.config.headerSigning) {\n const result = verifyCertHeaders(context.headers, this.config.headerSigning);\n if (!result.valid) {\n console.error(\n '[stackwright-auth] PKI header signature verification failed: ' + result.reason\n );\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.PKI_HEADER_SIG_FAILED, 'failure', {\n authMethod: 'pki',\n reason: result.reason,\n })\n );\n } catch {\n /* audit must never break auth */\n }\n return null;\n }\n }\n\n parsed = parseCertFromHeaders(context.headers, this.config.headerPrefix);\n } else {\n // direct_tls - expect certificate in context\n // This would be set by server that terminates TLS\n const certData = context.headers?.['x-client-cert'];\n if (!certData) {\n return null;\n }\n parsed = parseCertificate(certData);\n }\n\n if (!parsed) {\n return null;\n }\n\n // Validate certificate is still valid\n if (!parsed.isValid) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.PKI_CERT_REJECTED, 'failure', {\n authMethod: 'pki',\n reason: 'Certificate is not valid (expired or not yet valid)',\n })\n );\n } catch {\n /* audit must never break auth */\n }\n return null;\n }\n\n // Check certificate revocation status (OCSP/CRL/skip based on config)\n const revocationInput: RevocationInput = {\n serialNumber: parsed.serialNumber,\n issuerName: parsed.issuer.commonName,\n // certPem not available for gateway_headers source\n };\n try {\n const revocationStatus = await this.revocationChecker.check(revocationInput);\n if (revocationStatus.revoked) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.PKI_CERT_REVOKED, 'failure', {\n authMethod: 'pki',\n reason:\n 'reason' in revocationStatus ? revocationStatus.reason : 'Certificate revoked',\n details: { serialNumber: parsed.serialNumber },\n })\n );\n } catch {\n /* audit must never break auth */\n }\n return null;\n }\n } catch (err) {\n // Thrown only when hardFail: true\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.PKI_REVOCATION_CHECK_FAILED, 'failure', {\n authMethod: 'pki',\n reason: String(err),\n details: { serialNumber: parsed.serialNumber },\n })\n );\n } catch {\n /* audit must never break auth */\n }\n return null;\n }\n\n // Apply profile-specific validation\n if (this.config.profile === 'dod_cac') {\n if (!validateDoDCAC(parsed)) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.PKI_CERT_REJECTED, 'failure', {\n authMethod: 'pki',\n reason: 'DoD CAC validation failed',\n details: { subject: parsed.subject.commonName },\n })\n );\n } catch {\n /* audit must never break auth */\n }\n return null;\n }\n }\n\n // Check required OU if specified\n if (this.config.requiredOU) {\n const hasRequiredOU = this.config.requiredOU.some((required) =>\n parsed!.subject.organizationalUnit?.some((ou) => ou.includes(required))\n );\n if (!hasRequiredOU) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.PKI_CERT_REJECTED, 'failure', {\n authMethod: 'pki',\n reason: 'Missing required OU',\n details: { subject: parsed.subject.commonName },\n })\n );\n } catch {\n /* audit must never break auth */\n }\n return null;\n }\n }\n\n // Check allowed issuers if specified\n if (this.config.allowedIssuers) {\n const issuerCN = parsed.issuer.commonName;\n if (!issuerCN || !this.config.allowedIssuers.includes(issuerCN)) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.PKI_CERT_REJECTED, 'failure', {\n authMethod: 'pki',\n reason: 'Issuer not in allowedIssuers',\n details: { issuer: issuerCN },\n })\n );\n } catch {\n /* audit must never break auth */\n }\n return null;\n }\n }\n\n // Extract user claims from certificate\n const user: AuthUser = {\n id: parsed.serialNumber, // Use serial as unique ID\n name: parsed.subject.commonName,\n email: parsed.subject.email,\n roles: this.extractRolesFromCertificate(parsed),\n metadata: {\n organizationalUnit: parsed.subject.organizationalUnit,\n organization: parsed.subject.organization,\n country: parsed.subject.country,\n issuer: parsed.issuer.commonName,\n notBefore: parsed.notBefore.toISOString(),\n notAfter: parsed.notAfter.toISOString(),\n },\n };\n\n // Audit success\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.PKI_CERT_VALIDATED, 'success', {\n userId: user.id,\n authMethod: 'pki',\n })\n );\n } catch {\n /* audit must never break auth */\n }\n\n return user;\n }\n\n async validate(session: AuthSession): Promise<boolean> {\n // Check session hasn't expired\n if (Date.now() > session.expiresAt) {\n return false;\n }\n\n // For PKI, we could re-validate the certificate here\n // But that requires storing cert data in session metadata\n // For now, trust the session if it hasn't expired\n\n return true;\n }\n\n /**\n * Extract roles from certificate based on organizational units\n * Can be customized per deployment via subclassing\n */\n private extractRolesFromCertificate(parsed: ParsedCertificate): string[] {\n const roles: string[] = [];\n\n // For DoD CAC, we might derive roles from OU\n const ous = parsed.subject.organizationalUnit || [];\n\n // Example role mapping (customize per deployment)\n if (ous.some((ou) => ou.includes('ADMIN') || ou.includes('ADMINISTRATOR'))) {\n roles.push('ADMIN');\n } else if (ous.some((ou) => ou.includes('ANALYST'))) {\n roles.push('ANALYST');\n } else {\n roles.push('VIEWER'); // Default role\n }\n\n return roles;\n }\n}\n","/**\n * OIDC Discovery Client\n *\n * Handles OIDC provider discovery and authorization URL generation.\n * Follows the OpenID Connect Discovery 1.0 specification.\n */\n\n/**\n * OIDC Provider Metadata (from .well-known/openid-configuration)\n */\nexport interface OIDCMetadata {\n issuer: string;\n authorization_endpoint: string;\n token_endpoint: string;\n jwks_uri: string;\n userinfo_endpoint?: string;\n end_session_endpoint?: string;\n scopes_supported?: string[];\n response_types_supported?: string[];\n code_challenge_methods_supported?: string[];\n}\n\n/**\n * Discover OIDC provider configuration\n *\n * Fetches the OIDC discovery document from the well-known endpoint.\n * This is the first step in any OIDC flow.\n *\n * @param discoveryUrl - Full URL to .well-known/openid-configuration\n * @returns OIDC metadata with endpoints and capabilities\n * @throws Error if discovery fails or metadata is invalid\n */\nexport async function discoverOIDC(discoveryUrl: string): Promise<OIDCMetadata> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 10_000);\n\n try {\n const response = await fetch(discoveryUrl, { signal: controller.signal });\n\n if (!response.ok) {\n throw new Error(`OIDC discovery failed: ${response.statusText}`);\n }\n\n const metadata = (await response.json()) as any;\n\n // Validate required fields per OIDC spec\n if (\n !metadata.issuer ||\n !metadata.authorization_endpoint ||\n !metadata.token_endpoint ||\n !metadata.jwks_uri\n ) {\n throw new Error('Invalid OIDC metadata: missing required fields');\n }\n\n return metadata as OIDCMetadata;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`OIDC request timed out after 10s: ${discoveryUrl}`, { cause: error });\n }\n throw error;\n } finally {\n clearTimeout(timeout);\n }\n}\n\n/**\n * Generate authorization URL for OIDC login\n *\n * Builds the URL to redirect users to for authentication.\n * Follows OAuth 2.0 authorization code flow.\n *\n * @param metadata - OIDC provider metadata from discovery\n * @param clientId - OAuth client ID\n * @param redirectUri - Where to redirect after authentication\n * @param options - Optional state, nonce, PKCE, and scope overrides\n * @returns Authorization URL to redirect user to\n */\nexport function buildAuthorizationUrl(\n metadata: OIDCMetadata,\n clientId: string,\n redirectUri: string,\n options: BuildAuthorizationUrlOptions = {}\n): string {\n const {\n state,\n nonce,\n codeChallenge,\n codeChallengeMethod,\n scopes = ['openid', 'profile', 'email'],\n } = options;\n\n const url = new URL(metadata.authorization_endpoint);\n url.searchParams.set('client_id', clientId);\n url.searchParams.set('redirect_uri', redirectUri);\n url.searchParams.set('response_type', 'code');\n url.searchParams.set('scope', scopes.join(' '));\n\n if (state) {\n url.searchParams.set('state', state);\n }\n if (nonce) {\n url.searchParams.set('nonce', nonce);\n }\n if (codeChallenge && codeChallengeMethod) {\n url.searchParams.set('code_challenge', codeChallenge);\n url.searchParams.set('code_challenge_method', codeChallengeMethod);\n }\n\n return url.toString();\n}\n\nexport interface BuildAuthorizationUrlOptions {\n state?: string;\n nonce?: string;\n codeChallenge?: string;\n codeChallengeMethod?: string;\n scopes?: string[];\n}\n","/**\n * OIDC Token Exchange & Validation\n *\n * Handles OAuth2 token exchange, refresh, and JWT validation.\n * Uses jose for secure JWT operations.\n */\n\nimport * as crypto from 'node:crypto';\nimport * as jose from 'jose';\nimport type { OIDCMetadata } from './discovery.js';\n\nexport interface TokenSet {\n access_token: string;\n id_token: string;\n refresh_token?: string;\n expires_in: number;\n token_type: string;\n}\n\n/**\n * Exchange authorization code for tokens\n *\n * This is step 2 of the OAuth2 authorization code flow.\n * The authorization code is exchanged for access/ID/refresh tokens.\n *\n * @param metadata - OIDC provider metadata\n * @param code - Authorization code from callback\n * @param clientId - OAuth client ID\n * @param clientSecret - OAuth client secret\n * @param redirectUri - Must match the redirect_uri used in authorization\n * @param codeVerifier - PKCE code verifier (if PKCE was used in authorization request)\n * @returns Token set with access_token, id_token, and optionally refresh_token\n * @throws Error if token exchange fails\n */\nexport async function exchangeCodeForTokens(\n metadata: OIDCMetadata,\n code: string,\n clientId: string,\n clientSecret: string,\n redirectUri: string,\n codeVerifier?: string\n): Promise<TokenSet> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 10_000);\n\n try {\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri,\n });\n if (codeVerifier) {\n body.append('code_verifier', codeVerifier);\n }\n\n const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');\n const response = await fetch(metadata.token_endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Authorization: `Basic ${credentials}`,\n },\n body,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n // Log full error server-side, expose only status to caller\n const errorBody = await response.text().catch(() => '');\n console.error(`[stackwright-auth] Token exchange failed (${response.status}):`, errorBody);\n throw new Error(`Token exchange failed: HTTP ${response.status} ${response.statusText}`);\n }\n\n return (await response.json()) as TokenSet;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`OIDC request timed out after 10s: ${metadata.token_endpoint}`, {\n cause: error,\n });\n }\n throw error;\n } finally {\n clearTimeout(timeout);\n }\n}\n\n/**\n * Refresh access token using refresh token\n *\n * When access tokens expire, use the refresh token to get new ones\n * without requiring user to re-authenticate.\n *\n * @param metadata - OIDC provider metadata\n * @param refreshToken - Refresh token from initial token exchange\n * @param clientId - OAuth client ID\n * @param clientSecret - OAuth client secret\n * @returns New token set\n * @throws Error if refresh fails\n */\nexport async function refreshAccessToken(\n metadata: OIDCMetadata,\n refreshToken: string,\n clientId: string,\n clientSecret: string\n): Promise<TokenSet> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 10_000);\n\n try {\n const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');\n const response = await fetch(metadata.token_endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Authorization: `Basic ${credentials}`,\n },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n // Log full error server-side, expose only status to caller\n const errorBody = await response.text().catch(() => '');\n console.error(`[stackwright-auth] Token refresh failed (${response.status}):`, errorBody);\n throw new Error(`Token refresh failed: HTTP ${response.status} ${response.statusText}`);\n }\n\n return (await response.json()) as TokenSet;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`OIDC request timed out after 10s: ${metadata.token_endpoint}`, {\n cause: error,\n });\n }\n throw error;\n } finally {\n clearTimeout(timeout);\n }\n}\n\n/**\n * Validate ID token JWT and extract claims\n *\n * Verifies the JWT signature using the provider's JWKS and validates\n * standard claims (issuer, audience, expiration).\n *\n * This is critical for security - never trust an ID token without validation!\n *\n * @param idToken - JWT ID token from token exchange\n * @param jwksUri - JWKS URI from OIDC metadata\n * @param issuer - Expected issuer (should match token's iss claim)\n * @param clientId - Expected audience (should match token's aud claim)\n * @param skipIssuerCheck - Skip issuer validation (use for Keycloak quirks)\n * @param expectedNonce - Nonce from the authorization request to verify against the ID token (OIDC Core §3.1.3.7)\n * @returns Validated JWT payload with user claims\n * @throws Error if JWT validation fails or nonce mismatch\n */\nexport async function validateIdToken(\n idToken: string,\n jwksUri: string,\n issuer: string,\n clientId: string,\n skipIssuerCheck = false,\n expectedNonce?: string\n): Promise<Record<string, any>> {\n // Fetch JWKS for signature validation\n const JWKS = jose.createRemoteJWKSet(new URL(jwksUri));\n\n // Verify JWT signature and claims\n const { payload } = await jose.jwtVerify(idToken, JWKS, {\n issuer: skipIssuerCheck ? undefined : issuer,\n audience: clientId,\n });\n\n // Verify nonce if expected (OIDC Core §3.1.3.7)\n if (expectedNonce) {\n const tokenNonce = payload.nonce as string | undefined;\n if (!tokenNonce) {\n throw new Error('ID token missing nonce claim');\n }\n // Constant-time comparison to prevent timing attacks\n if (\n tokenNonce.length !== expectedNonce.length ||\n !crypto.timingSafeEqual(Buffer.from(tokenNonce), Buffer.from(expectedNonce))\n ) {\n throw new Error('ID token nonce mismatch — possible replay attack');\n }\n }\n\n return payload as Record<string, any>;\n}\n","/**\n * Keycloak-specific OIDC Adapter\n *\n * Keycloak has several quirks in its OIDC implementation that require\n * special handling. This adapter normalizes Keycloak behavior.\n *\n * Known Issues:\n * 1. Issuer in token doesn't always match discovery URL\n * 2. Refresh token rotation is inconsistent\n * 3. Claims structure differs from standard OIDC\n * 4. Role mapping is non-standard (realm_access.roles)\n */\n\n/**\n * Keycloak-specific OIDC adapter\n *\n * Use this when working with Keycloak to handle its many quirks.\n * Tested with Keycloak 19.x - 23.x\n */\nexport class KeycloakAdapter {\n /**\n * Normalize Keycloak issuer (remove /auth prefix if present)\n *\n * Keycloak's issuer URLs changed between versions:\n * - Pre-17: https://keycloak.example.com/auth/realms/myrealm\n * - Post-17: https://keycloak.example.com/realms/myrealm\n *\n * This normalizes to the post-17 format.\n *\n * @param issuer - Issuer from token or metadata\n * @returns Normalized issuer\n */\n static normalizeIssuer(issuer: string): string {\n return issuer.replace('/auth/realms/', '/realms/');\n }\n\n /**\n * Map Keycloak-specific claims to standard format\n *\n * Keycloak stores roles and groups in non-standard locations:\n * - Roles: realm_access.roles (not standard)\n * - Groups: groups array (sometimes, if configured)\n * - Username: preferred_username (not always 'name')\n *\n * @param tokenPayload - Raw JWT payload from Keycloak\n * @returns Normalized claims matching AuthUser interface\n */\n static mapClaims(tokenPayload: Record<string, any>): Record<string, any> {\n return {\n user_id: tokenPayload.sub,\n email: tokenPayload.email,\n name: tokenPayload.name || tokenPayload.preferred_username,\n roles: tokenPayload.realm_access?.roles || [],\n groups: tokenPayload.groups || [],\n // Keep original payload for advanced use cases\n ...tokenPayload,\n };\n }\n\n /**\n * Keycloak refresh tokens should be refreshed earlier than spec suggests\n *\n * Keycloak's refresh token rotation is buggy and sometimes fails if you\n * wait too long. Refresh aggressively when less than 10 minutes remain.\n *\n * @param expiresIn - Seconds until token expires\n * @returns true if token should be refreshed now\n */\n static shouldRefreshToken(expiresIn: number): boolean {\n // Refresh when less than 10 minutes remaining (Keycloak's rotation is buggy)\n return expiresIn < 600;\n }\n}\n","/**\n * OAuth 2.0 State & Nonce Utilities\n *\n * Provides cryptographically secure state and nonce generation for\n * CSRF protection (state) and ID token replay prevention (nonce).\n *\n * State comparison uses constant-time equality to prevent timing attacks.\n */\n\nimport * as crypto from 'node:crypto';\n\n/**\n * Generates a cryptographically random state parameter for OAuth 2.0 CSRF protection.\n * Returns a URL-safe base64-encoded 32-byte random value (43 characters).\n */\nexport function generateState(): string {\n return crypto.randomBytes(32).toString('base64url');\n}\n\n/**\n * Generates a nonce for OpenID Connect ID Token replay protection.\n * Returns a URL-safe base64-encoded 32-byte random value (43 characters).\n */\nexport function generateNonce(): string {\n return crypto.randomBytes(32).toString('base64url');\n}\n\n/**\n * Constant-time comparison for state/nonce validation.\n * Prevents timing attacks on state parameter verification.\n *\n * @param received - State value received from the callback query params\n * @param expected - State value stored server-side before redirect\n * @returns true if the values match\n */\nexport function verifyState(received: string, expected: string): boolean {\n if (received.length !== expected.length) return false;\n const a = Buffer.from(received);\n const b = Buffer.from(expected);\n return crypto.timingSafeEqual(a, b);\n}\n","/**\n * PKCE (Proof Key for Code Exchange) Utilities — RFC 7636\n *\n * Implements S256 code challenge method for protecting the\n * authorization code grant against interception attacks.\n *\n * Only S256 is supported — the 'plain' method is intentionally excluded\n * as it provides no security benefit and exists only for legacy compatibility.\n */\n\nimport * as crypto from 'node:crypto';\n\n/**\n * Generates a PKCE code verifier (RFC 7636 §4.1).\n *\n * 32 random bytes → 43 base64url characters (within the spec's 43–128 range).\n * Uses the unreserved character set: [A-Z] / [a-z] / [0-9] / \"-\" / \".\" / \"_\" / \"~\"\n */\nexport function generateCodeVerifier(): string {\n return crypto.randomBytes(32).toString('base64url');\n}\n\n/**\n * Generates a PKCE code challenge from a verifier using S256 (RFC 7636 §4.2).\n *\n * challenge = BASE64URL(SHA256(ASCII(code_verifier)))\n *\n * @param verifier - The code verifier string\n * @returns Base64url-encoded SHA-256 hash of the verifier\n */\nexport function generateCodeChallenge(verifier: string): string {\n return crypto.createHash('sha256').update(verifier).digest('base64url');\n}\n","/**\n * OIDC Authentication Provider\n *\n * Implements the AuthProvider interface for OAuth2/OIDC authentication.\n * Supports major providers (Cognito, Azure AD, Keycloak, etc.) with\n * configurable claims mapping and provider-specific quirks handling.\n *\n * Security features:\n * - State parameter for CSRF protection\n * - Nonce for ID token replay prevention\n * - PKCE (S256) for authorization code interception protection\n * - Pluggable audit logging for SIEM integration\n */\n\nimport type {\n AuthProvider,\n AuthUser,\n AuthSession,\n AuthContext,\n OIDCConfig,\n} from '../types/index.js';\nimport { discoverOIDC, buildAuthorizationUrl, type OIDCMetadata } from '../oidc/discovery.js';\nimport {\n exchangeCodeForTokens,\n validateIdToken,\n refreshAccessToken,\n} from '../oidc/token-exchange.js';\nimport { KeycloakAdapter } from '../oidc/providers/keycloak-adapter.js';\nimport { generateState, generateNonce, verifyState } from '../oidc/state.js';\nimport { generateCodeVerifier, generateCodeChallenge } from '../oidc/pkce.js';\nimport { type AuditLogger, AuditEventType, createAuditEvent } from '../audit/audit-logger.js';\n\n/**\n * Returned by getAuthorizationUrl() — contains everything the caller needs\n * to store server-side before redirecting the user.\n */\nexport interface AuthorizationRequest {\n /** The full authorization URL to redirect the user to */\n url: string;\n /** CSRF protection token — store and verify on callback */\n state: string;\n /** ID token replay protection — store and verify on callback */\n nonce: string;\n /** PKCE code verifier — store and send during token exchange (undefined if IdP doesn't support PKCE) */\n codeVerifier?: string;\n}\n\n/**\n * OIDC Provider\n *\n * Handles OAuth2/OIDC authentication flows including:\n * - Discovery of OIDC configuration\n * - Authorization code exchange (with PKCE)\n * - State/CSRF validation\n * - JWT validation\n * - Session refresh\n * - Provider-specific quirks (Keycloak, Cognito, etc.)\n */\nexport class OIDCProvider implements AuthProvider {\n private metadata: OIDCMetadata | null = null;\n private auditLogger?: AuditLogger;\n\n constructor(\n private config: OIDCConfig,\n auditLogger?: AuditLogger\n ) {\n this.auditLogger = auditLogger;\n }\n\n /**\n * Initialize provider by discovering OIDC configuration\n *\n * Call this during app startup to pre-fetch OIDC metadata.\n * If not called, metadata will be lazily loaded on first use.\n */\n async initialize(): Promise<void> {\n this.metadata = await discoverOIDC(this.config.discoveryUrl);\n }\n\n /**\n * Get metadata (lazy load if not initialized)\n */\n private async getMetadata(): Promise<OIDCMetadata> {\n if (!this.metadata) {\n await this.initialize();\n }\n return this.metadata!;\n }\n\n /**\n * Authenticate user by exchanging authorization code for tokens.\n *\n * This is called after the user is redirected back from the OIDC provider\n * with an authorization code in the query parameters.\n *\n * When expectedState is provided, the state parameter from the callback\n * query is verified using constant-time comparison. A mismatch throws\n * to prevent login CSRF attacks.\n *\n * @param context - Auth context with query params and optional security tokens\n * @returns Authenticated user or null if no code present\n * @throws Error if state mismatch (CSRF) or token exchange/validation fails\n */\n async authenticate(context: AuthContext): Promise<AuthUser | null> {\n const code = context.query?.code;\n const redirectUri = this.config.redirectUri || '/api/auth/callback';\n\n if (!code) {\n return null;\n }\n\n // Verify state parameter (CSRF protection)\n const requireState = this.config.requireState !== false; // default true\n\n if (requireState) {\n if (!context.expectedState) {\n throw new Error(\n 'OIDC state validation required but no expectedState provided. ' +\n 'Pass the state from getAuthorizationUrl() stored in the user session.'\n );\n }\n const callbackState = context.query?.state;\n if (!callbackState || !verifyState(callbackState, context.expectedState)) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.OIDC_STATE_MISMATCH, 'failure', {\n authMethod: 'oidc',\n reason: 'State mismatch - possible CSRF',\n })\n );\n } catch {\n /* audit must never break auth */\n }\n throw new Error('OAuth state mismatch \\u2014 possible CSRF attack');\n }\n } else if (context.expectedState) {\n // Even when not required, validate if provided\n const callbackState = context.query?.state;\n if (!callbackState || !verifyState(callbackState, context.expectedState)) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.OIDC_STATE_MISMATCH, 'failure', {\n authMethod: 'oidc',\n reason: 'State mismatch - possible CSRF',\n })\n );\n } catch {\n /* audit must never break auth */\n }\n throw new Error('OAuth state mismatch \\u2014 possible CSRF attack');\n }\n }\n\n const metadata = await this.getMetadata();\n\n // Log token exchange attempt\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.OIDC_TOKEN_EXCHANGE, 'success', { authMethod: 'oidc' })\n );\n } catch {\n /* audit must never break auth */\n }\n\n // Exchange code for tokens (include PKCE verifier if provided)\n const tokens = await exchangeCodeForTokens(\n metadata,\n code,\n this.config.clientId,\n this.config.clientSecret,\n redirectUri,\n context.codeVerifier\n );\n\n // Validate ID token and extract claims\n const issuer = this.config.quirks?.skipIssuerCheck\n ? undefined\n : this.config.provider === 'keycloak'\n ? KeycloakAdapter.normalizeIssuer(metadata.issuer)\n : metadata.issuer;\n\n const claims = await validateIdToken(\n tokens.id_token,\n metadata.jwks_uri,\n issuer || metadata.issuer,\n this.config.clientId,\n this.config.quirks?.skipIssuerCheck,\n context.expectedNonce\n );\n\n // Map claims to AuthUser based on provider-specific logic\n const mappedClaims =\n this.config.provider === 'keycloak' ? KeycloakAdapter.mapClaims(claims) : claims;\n\n // Apply custom claims mapping if provided\n const user: AuthUser = {\n id: this.getClaimValue(mappedClaims, this.config.claimsMapping?.user_id, 'sub'),\n email: this.getClaimValue(mappedClaims, this.config.claimsMapping?.email, 'email'),\n name: this.getClaimValue(mappedClaims, this.config.claimsMapping?.name, 'name'),\n roles: this.extractRoles(mappedClaims),\n metadata: {\n provider: this.config.provider,\n originalClaims: mappedClaims,\n },\n };\n\n // Audit success\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.AUTH_SUCCESS, 'success', {\n userId: user.id,\n authMethod: 'oidc',\n })\n );\n } catch {\n /* audit must never break auth */\n }\n\n return user;\n }\n\n /**\n * Validate session (check if token is still valid)\n *\n * @param session - Session to validate\n * @returns true if session is still valid\n */\n async validate(session: AuthSession): Promise<boolean> {\n if (Date.now() > session.expiresAt) {\n return false;\n }\n return true;\n }\n\n /**\n * Refresh session using refresh token\n *\n * @param session - Session with refresh token\n * @returns Updated session with new tokens, or null if refresh failed\n */\n async refresh(session: AuthSession): Promise<AuthSession | null> {\n if (!session.refreshToken) {\n return null;\n }\n\n const metadata = await this.getMetadata();\n\n try {\n const tokens = await refreshAccessToken(\n metadata,\n session.refreshToken,\n this.config.clientId,\n this.config.clientSecret\n );\n\n return {\n ...session,\n expiresAt: Date.now() + tokens.expires_in * 1000,\n refreshToken: tokens.refresh_token || session.refreshToken,\n };\n } catch {\n return null;\n }\n }\n\n /**\n * Generates the authorization URL for the OIDC provider.\n *\n * The returned state, nonce, and codeVerifier MUST be stored server-side\n * (e.g., in an encrypted cookie or session) before redirecting the user.\n * They are required for validating the callback in authenticate().\n *\n * PKCE (S256) is automatically enabled when the IdP advertises support\n * or when code_challenge_methods_supported is absent from metadata\n * (safe default \\u2014 most modern IdPs support S256).\n *\n * @param redirectUri - Where to redirect after authentication\n * @returns AuthorizationRequest with url, state, nonce, and optional codeVerifier\n */\n async getAuthorizationUrl(redirectUri: string): Promise<AuthorizationRequest> {\n const metadata = await this.getMetadata();\n\n const state = generateState();\n const nonce = generateNonce();\n\n // Enable PKCE when IdP supports S256 or doesn't advertise supported methods\n // (most modern IdPs support S256 even if not declared in metadata)\n let codeVerifier: string | undefined;\n let codeChallenge: string | undefined;\n const supportedMethods = metadata.code_challenge_methods_supported;\n if (!supportedMethods || supportedMethods.includes('S256')) {\n codeVerifier = generateCodeVerifier();\n codeChallenge = generateCodeChallenge(codeVerifier);\n }\n\n const url = buildAuthorizationUrl(metadata, this.config.clientId, redirectUri, {\n state,\n nonce,\n codeChallenge,\n codeChallengeMethod: codeChallenge ? 'S256' : undefined,\n });\n\n return { url, state, nonce, codeVerifier };\n }\n\n /**\n * Extract claim value with fallback\n */\n private getClaimValue(claims: Record<string, any>, mappedKey?: string, defaultKey?: string): any {\n if (mappedKey && claims[mappedKey]) {\n return claims[mappedKey];\n }\n if (defaultKey && claims[defaultKey]) {\n return claims[defaultKey];\n }\n return undefined;\n }\n\n /**\n * Extract roles from claims (provider-specific logic)\n *\n * Different OIDC providers store roles in different places:\n * - Standard: 'roles' claim\n * - Keycloak: realm_access.roles\n * - Cognito: cognito:groups\n * - Azure AD: roles claim\n */\n private extractRoles(claims: Record<string, any>): string[] {\n // Try custom mapping first\n if (this.config.claimsMapping?.roles) {\n const rolesValue = claims[this.config.claimsMapping.roles];\n if (Array.isArray(rolesValue)) {\n return rolesValue;\n }\n if (typeof rolesValue === 'string') {\n return [rolesValue];\n }\n }\n\n // Standard OIDC claims\n if (Array.isArray(claims.roles)) {\n return claims.roles;\n }\n\n // Keycloak realm_access.roles\n if (claims.realm_access?.roles) {\n return claims.realm_access.roles;\n }\n\n // Cognito cognito:groups\n if (claims['cognito:groups']) {\n return claims['cognito:groups'];\n }\n\n // Default: no roles\n return [];\n }\n}\n","import * as jose from 'jose';\nimport * as crypto from 'node:crypto';\n\n/**\n * Derives a 32-byte encryption key from the session secret using HKDF.\n *\n * Uses a distinct info string ('stackwright-token-enc') so this key is\n * cryptographically independent from the HMAC signing key — even though\n * both derive from the same root secret.\n *\n * @param secret - The session secret (any length ≥ 32 chars)\n * @returns A 256-bit (32-byte) key suitable for A256GCM\n */\nexport function deriveEncryptionKey(secret: string): Uint8Array {\n return new Uint8Array(crypto.hkdfSync('sha256', secret, '', 'stackwright-token-enc', 32));\n}\n\n/**\n * Encrypts a token value using JWE (direct key agreement + A256GCM).\n *\n * The output is a JWE compact serialization (5 dot-separated parts) that\n * reveals nothing about the plaintext to anyone without the key.\n *\n * @param token - Plaintext token to encrypt (e.g. a refresh token)\n * @param key - 32-byte encryption key from {@link deriveEncryptionKey}\n * @returns JWE compact serialization string\n */\nexport async function encryptToken(token: string, key: Uint8Array): Promise<string> {\n return new jose.CompactEncrypt(new TextEncoder().encode(token))\n .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' })\n .encrypt(key);\n}\n\n/**\n * Decrypts a JWE-encrypted token value.\n *\n * @param jwe - JWE compact serialization string\n * @param key - 32-byte decryption key from {@link deriveEncryptionKey}\n * @returns The original plaintext token\n * @throws If the JWE is malformed or the key is wrong\n */\nexport async function decryptToken(jwe: string, key: Uint8Array): Promise<string> {\n const { plaintext } = await jose.compactDecrypt(jwe, key);\n return new TextDecoder().decode(plaintext);\n}\n","/**\n * Session Revocation with JTI Claims\n *\n * Provides unique JWT IDs (jti) for session tracking and a pluggable\n * revocation store for invalidating sessions before expiry.\n *\n * The InMemoryRevocationStore is fine for single-instance dev deployments.\n * For production multi-instance deployments, implement RevocationStore\n * backed by Redis, DynamoDB, or similar.\n */\n\nimport * as crypto from 'node:crypto';\n\n/**\n * Generates a unique JWT ID (jti) for session tracking and revocation.\n */\nexport function generateJti(): string {\n return crypto.randomUUID();\n}\n\n/**\n * Session revocation store interface.\n * Implement this to use Redis, database, or any other backend.\n */\nexport interface RevocationStore {\n /** Mark a session as revoked. TTL should match session duration. */\n revoke(jti: string, expiresAt: number): Promise<void>;\n /** Check if a session has been revoked. */\n isRevoked(jti: string): Promise<boolean>;\n}\n\n/**\n * In-memory revocation store for development and single-instance deployments.\n * NOT suitable for multi-instance deployments — use Redis or similar.\n */\nexport class InMemoryRevocationStore implements RevocationStore {\n private revoked = new Map<string, number>(); // jti -> expiry timestamp\n private cleanupInterval: ReturnType<typeof setInterval> | null = null;\n\n constructor(cleanupIntervalMs: number = 60_000) {\n // Periodically clean up expired entries to prevent memory leaks\n this.cleanupInterval = setInterval(() => this.cleanup(), cleanupIntervalMs);\n // Don't prevent process exit\n if (this.cleanupInterval.unref) {\n this.cleanupInterval.unref();\n }\n }\n\n async revoke(jti: string, expiresAt: number): Promise<void> {\n this.revoked.set(jti, expiresAt);\n }\n\n async isRevoked(jti: string): Promise<boolean> {\n return this.revoked.has(jti);\n }\n\n private cleanup(): void {\n const now = Math.floor(Date.now() / 1000);\n for (const [jti, exp] of this.revoked) {\n if (exp < now) {\n this.revoked.delete(jti);\n }\n }\n }\n\n /** Stop the cleanup timer. Call this when shutting down. */\n destroy(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = null;\n }\n }\n\n /** Number of currently tracked revoked sessions (for testing/monitoring). */\n get size(): number {\n return this.revoked.size;\n }\n}\n","import * as jose from 'jose';\nimport type { AuthUser, AuthSession } from '../types/index.js';\nimport { deriveEncryptionKey, encryptToken, decryptToken } from './token-encryption.js';\nimport { type AuditLogger, AuditEventType, createAuditEvent } from '../audit/audit-logger.js';\nimport { generateJti, type RevocationStore } from './revocation.js';\n\nexport interface SessionManagerConfig {\n /**\n * Secret key for JWT signing (must be at least 32 bytes)\n */\n secret: string;\n\n /**\n * Session duration in seconds (default: 15 minutes)\n */\n sessionDuration?: number;\n\n /**\n * Algorithm for JWT signing (default: HS256)\n */\n algorithm?: string;\n\n /**\n * Issuer claim for JWT\n */\n issuer?: string;\n\n /**\n * Audience claim for JWT\n */\n audience?: string;\n\n /**\n * Optional audit logger for security event logging\n */\n auditLogger?: AuditLogger;\n\n /**\n * Optional revocation store for session invalidation via jti claims\n */\n revocationStore?: RevocationStore;\n}\n\nexport class SessionManager {\n private secret: Uint8Array;\n private encryptionKey: Uint8Array;\n private sessionDuration: number;\n private algorithm: string;\n private issuer?: string;\n private audience?: string;\n private auditLogger?: AuditLogger;\n private revocationStore?: RevocationStore;\n\n constructor(config: SessionManagerConfig) {\n // Validate secret length\n if (config.secret.length < 32) {\n throw new Error('Session secret must be at least 32 characters');\n }\n\n // Convert string secret to Uint8Array for jose\n this.secret = new TextEncoder().encode(config.secret);\n // Derive a dedicated 256-bit key for refresh-token encryption (A256GCM)\n this.encryptionKey = deriveEncryptionKey(config.secret);\n this.sessionDuration = config.sessionDuration || 900; // 15 minutes default\n this.algorithm = config.algorithm || 'HS256';\n this.issuer = config.issuer;\n this.audience = config.audience;\n this.auditLogger = config.auditLogger;\n this.revocationStore = config.revocationStore;\n }\n\n /**\n * Create a new session for authenticated user.\n * Automatically assigns a unique jti for revocation support.\n */\n async createSession(user: AuthUser, refreshToken?: string): Promise<AuthSession> {\n const now = Date.now();\n const expiresAt = now + this.sessionDuration * 1000;\n const jti = generateJti();\n\n const session: AuthSession = {\n user,\n issuedAt: now,\n expiresAt,\n refreshToken,\n jti,\n };\n\n // Fire-and-forget audit log\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.SESSION_CREATED, 'success', {\n userId: user.id,\n authMethod: 'session',\n sessionId: jti,\n })\n );\n } catch {\n /* audit must never break auth */\n }\n\n return session;\n }\n\n /**\n * Sign session into a JWT.\n *\n * If the session carries a refresh token it is encrypted with JWE\n * (A256GCM) before being embedded in the payload as `encRefreshToken`.\n * The plaintext `refreshToken` field is **never** written to the JWT.\n *\n * The jti claim is included for session revocation support.\n */\n async signSession(session: AuthSession): Promise<string> {\n // Build payload - encrypt the refresh token so it isn't readable in the JWT\n const payload: Record<string, unknown> = { user: session.user };\n\n if (session.refreshToken) {\n payload.encRefreshToken = await encryptToken(session.refreshToken, this.encryptionKey);\n }\n\n const builder = new jose.SignJWT(payload)\n .setProtectedHeader({ alg: this.algorithm })\n .setIssuedAt(Math.floor(session.issuedAt / 1000)) // jose expects integer seconds\n .setExpirationTime(Math.floor(session.expiresAt / 1000))\n .setIssuer(this.issuer || 'stackwright-auth')\n .setAudience(this.audience || 'stackwright-app');\n\n // Include jti if present (always should be for new sessions)\n if (session.jti) {\n builder.setJti(session.jti);\n }\n\n const jwt = await builder.sign(this.secret);\n\n return jwt;\n }\n\n /**\n * Verify and decode session JWT.\n *\n * Handles two payload shapes:\n * - **Current**: `encRefreshToken` (JWE) - decrypted transparently.\n * - **Legacy**: plain `refreshToken` - accepted for backward compat\n * with a deprecation warning so operators know to rotate sessions.\n *\n * When a revocation store is configured, checks the jti against\n * the store and returns null for revoked sessions.\n */\n async verifySession(jwt: string): Promise<AuthSession | null> {\n try {\n const { payload } = await jose.jwtVerify(jwt, this.secret, {\n issuer: this.issuer || 'stackwright-auth',\n audience: this.audience || 'stackwright-app',\n algorithms: [this.algorithm],\n });\n\n // Check revocation if store is configured and jti is present\n if (this.revocationStore && payload.jti) {\n const revoked = await this.revocationStore.isRevoked(payload.jti as string);\n if (revoked) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.SESSION_REVOKED, 'failure', {\n sessionId: payload.jti as string,\n authMethod: 'session',\n })\n );\n } catch {\n /* audit must never break auth */\n }\n return null;\n }\n }\n\n // Decrypt or fall back to legacy plaintext refresh token\n let refreshToken: string | undefined;\n\n if (payload.encRefreshToken) {\n refreshToken = await decryptToken(payload.encRefreshToken as string, this.encryptionKey);\n } else if (payload.refreshToken) {\n // Backward compatibility: plain refresh token from pre-encryption sessions\n console.warn(\n '[stackwright-auth] WARNING: Session contains unencrypted refresh token. ' +\n 'Rotate sessions to upgrade.'\n );\n refreshToken = payload.refreshToken as string;\n }\n\n // Reconstruct session from payload\n const session: AuthSession = {\n user: payload.user as AuthUser,\n issuedAt: (payload.iat || 0) * 1000, // Convert back to milliseconds\n expiresAt: (payload.exp || 0) * 1000,\n refreshToken,\n jti: payload.jti as string | undefined,\n };\n\n // Fire-and-forget audit log\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.SESSION_VERIFIED, 'success', {\n userId: session.user?.id,\n authMethod: 'session',\n sessionId: session.jti,\n })\n );\n } catch {\n /* audit must never break auth */\n }\n\n return session;\n } catch (error) {\n // Distinguish expired from other failures for audit logging\n const isExpired = error instanceof jose.errors.JWTExpired;\n if (isExpired) {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.SESSION_EXPIRED, 'failure', {\n authMethod: 'session',\n reason: 'JWT expired',\n })\n );\n } catch {\n /* audit must never break auth */\n }\n } else {\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.SESSION_INVALID, 'failure', {\n authMethod: 'session',\n reason: String(error),\n })\n );\n } catch {\n /* audit must never break auth */\n }\n }\n\n // JWT verification failed (expired, invalid signature, etc.)\n return null;\n }\n }\n\n /**\n * Revoke a session by adding its jti to the revocation store.\n *\n * @throws Error if no revocation store is configured\n * @throws Error if session has no jti claim\n */\n async revokeSession(session: AuthSession): Promise<void> {\n if (!this.revocationStore) {\n throw new Error('Cannot revoke session: no revocation store configured');\n }\n if (!session.jti) {\n throw new Error('Cannot revoke session: session has no jti claim');\n }\n\n await this.revocationStore.revoke(session.jti, session.expiresAt);\n\n try {\n this.auditLogger?.log(\n createAuditEvent(AuditEventType.SESSION_REVOKED, 'success', {\n sessionId: session.jti,\n userId: session.user?.id,\n authMethod: 'session',\n })\n );\n } catch {\n /* audit must never break auth */\n }\n }\n\n /**\n * Check if session is expired\n */\n isExpired(session: AuthSession): boolean {\n return Date.now() > session.expiresAt;\n }\n\n /**\n * Check if session should be refreshed (within 5 minutes of expiry)\n */\n shouldRefresh(session: AuthSession): boolean {\n const timeUntilExpiry = session.expiresAt - Date.now();\n const REFRESH_THRESHOLD = 5 * 60 * 1000; // 5 minutes\n\n return timeUntilExpiry < REFRESH_THRESHOLD && timeUntilExpiry > 0;\n }\n\n /**\n * Refresh session (extend expiration)\n */\n async refreshSession(session: AuthSession): Promise<AuthSession> {\n return {\n ...session,\n issuedAt: Date.now(),\n expiresAt: Date.now() + this.sessionDuration * 1000,\n };\n }\n\n /**\n * Serialize session to string (for cookies/localStorage)\n */\n async serialize(session: AuthSession): Promise<string> {\n return this.signSession(session);\n }\n\n /**\n * Deserialize session from string\n */\n async deserialize(serialized: string): Promise<AuthSession | null> {\n return this.verifySession(serialized);\n }\n}\n","/**\n * Cookie options for session cookies\n */\nexport interface CookieOptions {\n /**\n * Cookie name (default: 'stackwright_session')\n */\n name?: string;\n\n /**\n * Domain for cookie\n */\n domain?: string;\n\n /**\n * Path for cookie (default: '/')\n */\n path?: string;\n\n /**\n * Max age in seconds\n */\n maxAge?: number;\n\n /**\n * HttpOnly flag (default: true)\n */\n httpOnly?: boolean;\n\n /**\n * Secure flag (default: true)\n */\n secure?: boolean;\n\n /**\n * SameSite policy (default: 'lax')\n */\n sameSite?: 'strict' | 'lax' | 'none';\n}\n\n/**\n * Serialize cookie with options\n */\nexport function serializeCookie(name: string, value: string, options: CookieOptions = {}): string {\n const {\n domain,\n path = '/',\n maxAge,\n httpOnly = true,\n secure = true, // Always secure by default; opt-out explicitly if needed\n sameSite = 'lax',\n } = options;\n\n const parts: string[] = [`${name}=${encodeURIComponent(value)}`];\n\n if (domain) {\n parts.push(`Domain=${domain}`);\n }\n\n parts.push(`Path=${path}`);\n\n if (maxAge !== undefined) {\n parts.push(`Max-Age=${maxAge}`);\n }\n\n if (httpOnly) {\n parts.push('HttpOnly');\n }\n\n if (secure) {\n parts.push('Secure');\n }\n\n if (sameSite) {\n parts.push(`SameSite=${sameSite.charAt(0).toUpperCase() + sameSite.slice(1)}`);\n }\n\n return parts.join('; ');\n}\n\n/**\n * Parse cookie string into key-value pairs\n */\nexport function parseCookies(cookieHeader?: string): Record<string, string> {\n if (!cookieHeader) {\n return {};\n }\n\n const cookies: Record<string, string> = {};\n\n for (const cookie of cookieHeader.split(';')) {\n const [key, ...valueParts] = cookie.trim().split('=');\n if (key) {\n cookies[key] = decodeURIComponent(valueParts.join('='));\n }\n }\n\n return cookies;\n}\n\n/**\n * Create a cookie header for clearing/deleting a cookie\n */\nexport function clearCookie(\n name: string,\n options: Pick<CookieOptions, 'domain' | 'path'> = {}\n): string {\n return serializeCookie(name, '', {\n ...options,\n maxAge: 0,\n });\n}\n","import type { AuthUser, RBACConfig, ComponentAuthConfig } from '../types/index.js';\n\n/**\n * RBAC Engine for checking roles and permissions\n */\nexport class RBACEngine {\n private config: RBACConfig;\n private rolePermissions: Map<string, Set<string>>;\n\n constructor(config: RBACConfig) {\n this.config = config;\n this.rolePermissions = this.buildRolePermissionMap();\n }\n\n /**\n * Build internal map of role → permissions for fast lookups\n */\n private buildRolePermissionMap(): Map<string, Set<string>> {\n const map = new Map<string, Set<string>>();\n\n for (const role of this.config.roles) {\n map.set(role.name, new Set(role.permissions || []));\n }\n\n return map;\n }\n\n /**\n * Check if user has a specific role\n */\n hasRole(user: AuthUser, role: string): boolean {\n return user.roles.includes(role);\n }\n\n /**\n * Check if user has any of the specified roles\n */\n hasAnyRole(user: AuthUser, roles: string[]): boolean {\n return roles.some((role) => this.hasRole(user, role));\n }\n\n /**\n * Check if user has all of the specified roles\n */\n hasAllRoles(user: AuthUser, roles: string[]): boolean {\n return roles.every((role) => this.hasRole(user, role));\n }\n\n /**\n * Check if user has a specific permission\n * Permissions are checked both:\n * 1. Directly in user.permissions array\n * 2. Through role-based permissions from config\n */\n hasPermission(user: AuthUser, permission: string): boolean {\n // Check direct permissions\n if (user.permissions?.includes(permission)) {\n return true;\n }\n\n // Check role-based permissions\n for (const role of user.roles) {\n const permissions = this.rolePermissions.get(role);\n if (permissions?.has(permission)) {\n return true;\n }\n\n // Check wildcard permissions (e.g., admin:* grants admin:read, admin:write)\n if (permissions) {\n for (const p of permissions) {\n if (p.endsWith(':*')) {\n const prefix = p.slice(0, -1); // Remove the *\n if (permission.startsWith(prefix)) {\n return true;\n }\n }\n }\n }\n }\n\n return false;\n }\n\n /**\n * Check if user has any of the specified permissions\n */\n hasAnyPermission(user: AuthUser, permissions: string[]): boolean {\n return permissions.some((permission) => this.hasPermission(user, permission));\n }\n\n /**\n * Check if user has all of the specified permissions\n */\n hasAllPermissions(user: AuthUser, permissions: string[]): boolean {\n return permissions.every((permission) => this.hasPermission(user, permission));\n }\n\n /**\n * Check if route is public (no auth required)\n */\n isPublicRoute(path: string): boolean {\n if (!this.config.public_routes) {\n return false;\n }\n\n return this.config.public_routes.some((publicPath) => {\n return this.matchPath(path, publicPath);\n });\n }\n\n /**\n * Check if user can access a route based on protected_routes config\n */\n canAccessRoute(user: AuthUser | null, path: string): boolean {\n // Check if route is public\n if (this.isPublicRoute(path)) {\n return true;\n }\n\n // No user = can't access protected routes\n if (!user) {\n return false;\n }\n\n // If no protected routes configured, allow by default\n if (!this.config.protected_routes || this.config.protected_routes.length === 0) {\n return true;\n }\n\n // Find matching protected route\n const matchingRoute = this.config.protected_routes.find((route) => {\n return this.matchPath(path, route.path);\n });\n\n // If no matching protected route, allow (route not explicitly protected)\n if (!matchingRoute) {\n return true;\n }\n\n // Check if user has required role for this route\n return this.hasAnyRole(user, matchingRoute.roles);\n }\n\n /**\n * Check if user can access a component based on component auth config\n */\n canAccessComponent(user: AuthUser | null, authConfig: ComponentAuthConfig | undefined): boolean {\n // No auth config = public component\n if (!authConfig) {\n return true;\n }\n\n // No user = can't access protected component\n if (!user) {\n return false;\n }\n\n // Check required roles\n if (authConfig.required_roles && authConfig.required_roles.length > 0) {\n if (!this.hasAnyRole(user, authConfig.required_roles)) {\n return false;\n }\n }\n\n // Check required permissions\n if (authConfig.required_permissions && authConfig.required_permissions.length > 0) {\n if (!this.hasAllPermissions(user, authConfig.required_permissions)) {\n return false;\n }\n }\n\n return true;\n }\n\n // Match a path against a pattern with wildcard support\n private matchPath(path: string, pattern: string): boolean {\n // Exact match\n if (path === pattern) {\n return true;\n }\n\n // No wildcards in pattern — only exact match applies\n if (!pattern.includes('*')) {\n return false;\n }\n\n // Escape ALL regex metacharacters, then convert glob * to .*\n // This prevents ReDoS from crafted route patterns in YAML config\n const escaped = pattern\n .replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&') // Escape regex specials\n .replace(/\\*/g, '.*'); // Convert glob * to .*\n\n const regex = new RegExp(`^${escaped}$`);\n return regex.test(path);\n }\n}\n","/**\n * DoD CAC Profile Configuration\n *\n * Pre-built profile for DoD Common Access Card (CAC) certificates.\n *\n * This profile includes:\n * - List of trusted DoD CA issuers\n * - Required OU validation (DOD)\n * - EDIPI extraction for user ID\n *\n * Last updated: 2025-01 (DoD PKI CA list)\n *\n * Note: DoD PKI infrastructure is regularly updated. Verify current CA list at:\n * https://public.cyber.mil/pki-pke/\n */\n\nimport type { PKIConfig } from '../types/index.js';\n\n/**\n * DoD CAC profile configuration\n *\n * This provides sensible defaults for DoD CAC authentication in most deployments.\n * Assumes gateway (e.g., NGINX, HAProxy) handles mTLS and forwards headers.\n */\nexport const DOD_CAC_PROFILE: Omit<PKIConfig, 'type'> = {\n profile: 'dod_cac',\n source: 'gateway_headers',\n headerPrefix: 'x-client-cert-',\n verifiedHeader: 'x-client-cert-verified',\n requiredValue: 'SUCCESS',\n requiredOU: ['DOD', 'DoD', 'U.S. Government'],\n\n // DoD Root CAs (add current list)\n // These are sample CA names - verify against current DoD PKI infrastructure\n allowedIssuers: [\n // DoD Interoperability Root CA 2\n 'CN=DoD Interoperability Root CA 2',\n\n // DoD Root CA 3-6 (current generation)\n 'CN=DoD Root CA 3',\n 'CN=DoD Root CA 4',\n 'CN=DoD Root CA 5',\n 'CN=DoD Root CA 6',\n\n // DoD ID CAs (email/PIV auth)\n 'CN=DOD ID CA-59',\n 'CN=DOD ID CA-60',\n 'CN=DOD ID CA-61',\n 'CN=DOD ID CA-62',\n 'CN=DOD ID CA-63',\n 'CN=DOD ID CA-64',\n 'CN=DOD ID CA-65',\n 'CN=DOD ID CA-66',\n 'CN=DOD ID CA-67',\n 'CN=DOD ID CA-68',\n 'CN=DOD ID CA-69',\n 'CN=DOD ID CA-70',\n\n // DoD SW CAs (software/device auth)\n 'CN=DOD SW CA-59',\n 'CN=DOD SW CA-60',\n 'CN=DOD SW CA-61',\n 'CN=DOD SW CA-62',\n 'CN=DOD SW CA-63',\n 'CN=DOD SW CA-64',\n 'CN=DOD SW CA-65',\n 'CN=DOD SW CA-66',\n\n // Legacy DoD Email CAs (being phased out but may still be in use)\n 'CN=DOD EMAIL CA-59',\n 'CN=DOD EMAIL CA-60',\n 'CN=DOD EMAIL CA-61',\n 'CN=DOD EMAIL CA-62',\n 'CN=DOD EMAIL CA-63',\n 'CN=DOD EMAIL CA-64',\n 'CN=DOD EMAIL CA-65',\n 'CN=DOD EMAIL CA-66',\n ],\n};\n\n/**\n * Create DoD CAC configuration with custom overrides\n *\n * @example\n * ```typescript\n * const config = createDoDCACConfig({\n * source: 'direct_tls', // If terminating TLS in Node.js\n * headerPrefix: 'ssl-client-', // Custom gateway header prefix\n * });\n * ```\n */\nexport function createDoDCACConfig(overrides?: Partial<PKIConfig>): PKIConfig {\n return {\n type: 'pki',\n ...DOD_CAC_PROFILE,\n ...overrides,\n };\n}\n\n/**\n * Minimal DoD CAC config for development/testing\n * Relaxes some requirements for local testing without real CAC cards\n */\nexport function createDoDCACDevConfig(): PKIConfig {\n return {\n type: 'pki',\n profile: 'dod_cac',\n source: 'gateway_headers',\n headerPrefix: 'x-client-cert-',\n verifiedHeader: 'x-client-cert-verified',\n requiredValue: 'SUCCESS',\n // Only require 'DOD' in OU for dev\n requiredOU: ['DOD'],\n // Don't restrict issuers in dev mode\n allowedIssuers: undefined,\n };\n}\n"]}
|