All checks were successful
CI / Lint, typecheck, test (pull_request) Successful in 6m55s
CI / Build container images (pull_request) Successful in 3m0s
CI / Auth e2e pack (pull_request) Successful in 8m49s
CI / Import/export fidelity gate (pull_request) Successful in 58s
CD / Build and push images (push) Successful in 21s
CD / Deploy to Test (push) Successful in 14s
CD / Smoke tests against Test (push) Successful in 1m19s
CD / Promote to Int (push) Successful in 12s
CI / Lint, typecheck, test (push) Successful in 6m28s
CI / Build container images (push) Has been skipped
CI / Auth e2e pack (push) Successful in 8m15s
CI / Import/export fidelity gate (push) Successful in 59s
Declarative instance setting idpMapping.rules turns ID-token claims into pond roles and the site-admin flag on every OIDC login — configuration, not code. Mapped grants travel through the SAME GrantsService path as manual ones (permission cache invalidated, collab access notify fires so live sessions revalidate — asserted by test), never raw rows. Ownership makes precedence explicit: role_grants.origin marks mapped rows, users.is_site_admin_managed marks a mapping-set admin flag. The mapping only creates and revokes what it owns — manual wins: hand-made grants and hand-promoted admins are never revoked by a missing claim (a manual toggle clears the marker and takes ownership). Removal of a claim revokes the mapped grant and the managed flag on the next login. Every mapping-driven change is audited with origin idp_mapping. Failure containment: unknown pond slugs and the last-Pond-Admin protection log-and-skip — a mapping problem must never become a login lockout. Tests drive real OIDC logins against the fake IdP with group claims: grant + working access, revocation incl. notify, manual-wins, managed site-admin promote/demote/hands-off. Documented in permissions.md (own section), ADR 0021, data-model.md and the hardening guide (care rule: same PR). Refs #217. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AUtYMxwTCMHG9mVHnwbFg8
53 lines
2.0 KiB
TypeScript
53 lines
2.0 KiB
TypeScript
import { Logger, Module, OnModuleInit } from '@nestjs/common';
|
|
import { APP_GUARD } from '@nestjs/core';
|
|
|
|
import { AppConfig } from '../config/app-config.service';
|
|
import { GrantsModule } from '../grants/grants.module';
|
|
|
|
import { MailModule } from '../mail/mail.module';
|
|
import { PondsModule } from '../ponds/ponds.module';
|
|
import { UsersModule } from '../users/users.module';
|
|
import { AuthController } from './auth.controller';
|
|
import { AuthGuard } from './auth.guard';
|
|
import { AuthService } from './auth.service';
|
|
import { AuthTokensService } from './auth-tokens.service';
|
|
import { ClaimMappingService } from './claim-mapping.service';
|
|
import { OidcController } from './oidc.controller';
|
|
import { OidcService } from './oidc.service';
|
|
import { ProxyIdentityService } from './proxy-identity.service';
|
|
import { SessionsModule } from './sessions.module';
|
|
|
|
@Module({
|
|
imports: [UsersModule, MailModule, SessionsModule, PondsModule, GrantsModule],
|
|
controllers: [AuthController, OidcController],
|
|
providers: [
|
|
AuthService,
|
|
AuthTokensService,
|
|
ClaimMappingService,
|
|
OidcService,
|
|
ProxyIdentityService,
|
|
// Global default-protected: every route needs a session unless it
|
|
// opts out with @Public().
|
|
{ provide: APP_GUARD, useClass: AuthGuard },
|
|
],
|
|
exports: [AuthTokensService, AuthService, OidcService],
|
|
})
|
|
export class AuthModule implements OnModuleInit {
|
|
constructor(
|
|
private readonly config: AppConfig,
|
|
private readonly oidc: OidcService,
|
|
private readonly proxyIdentity: ProxyIdentityService,
|
|
) {}
|
|
|
|
onModuleInit(): void {
|
|
// #216: local auth off without ANY external path means nobody can ever
|
|
// sign in — loudly stated at boot, because the operator will otherwise
|
|
// discover it at the login screen.
|
|
if (!this.config.env.AUTH_LOCAL_ENABLED && !this.oidc.enabled && !this.proxyIdentity.enabled) {
|
|
new Logger(AuthModule.name).warn(
|
|
'AUTH_LOCAL_ENABLED=false with neither OIDC nor proxy authentication configured — no sign-in path exists',
|
|
);
|
|
}
|
|
}
|
|
}
|