Some checks failed
		
		
	
	Build Test Deploy / authority-container (push) Has been cancelled
				
			Build Test Deploy / docs (push) Has been cancelled
				
			Build Test Deploy / deploy (push) Has been cancelled
				
			Build Test Deploy / build-test (push) Has been cancelled
				
			Docs CI / lint-and-preview (push) Has been cancelled
				
			
		
			
				
	
	
	
		
			8.7 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	
			8.7 KiB
		
	
	
	
	
	
	
	
RFC: StellaOps.Authority.Plugin.Ldap
Status: Draft – for review by Auth Guild, Security Guild, DevEx (2025-10-10)
Authors: Plugin Team 4 (Auth Libraries & Identity Providers)
Related initiatives: PLG7 backlog, CORE5 event handlers, DOC4 developer guide
1. Problem Statement
Many on-prem StellaOps deployments rely on existing LDAP/Active Directory domains for workforce identity. The current Standard Mongo-backed plugin requires duplicating users and secrets, which increases operational overhead and violates corporate policy in some regulated environments. We need a sovereign, offline-friendly LDAP plugin that:
- Supports password grant and bootstrap provisioning flows without storing credentials in Mongo.
 - Enforces StellaOps security policies (lockout, password policy hints, audit logging) while delegating credential validation to LDAP.
 - Operates deterministically in offline or partially connected environments by caching directory metadata when necessary.
 
2. Goals
- Provide a first-party 
StellaOps.Authority.Plugin.Ldapplugin advertisingpasswordand optionalclientProvisioningcapabilities at launch. - Support username/password authentication against LDAP bind operations with configurable DN templates.
 - Allow optional bootstrap seeding of service accounts by writing into LDAP (guarded behind explicit configuration) or by mapping to pre-existing entries.
 - Surface directory-derived claims (groups, attributes) for downstream authorization via 
IClaimsEnricher. - Integrate with Authority lockout telemetry and structured logging without persisting secrets locally.
 
3. Non-Goals
- Implement multi-factor authentication out of the box (future enhancement once TOTP/WebAuthn strategy is finalised).
 - Provide write-heavy directory management (e.g., user creation workflows) beyond optional bootstrap service account seeding.
 - Replace the Standard plugin; both must remain supported and selectable per environment.
 
4. Key Constraints & Assumptions
- Offline-first posture: deployments may operate without outbound internet and with intermittent directory connectivity (e.g., read-only replicas). The plugin must tolerate transient LDAP connectivity failures and degrade gracefully.
 - Deterministic behaviour: identical configuration and directory state must yield identical token issuance results. Cached metadata (e.g., group lookups) must have defined expiration.
 - Security: No plaintext credential storage; TLS must be enforced for LDAP connections unless explicitly overridden for air-gapped lab environments.
 
5. High-Level Architecture
- Configuration binding (
ldap.yaml): defines server endpoints, bind strategy, claim mapping, and optional bootstrap overrides. - Connection factory: pooled LDAP connections using a resilient client (preferred dependency: 
Novell.Directory.Ldap.NETStandard). - Credential validator (
IUserCredentialStore): performs bind-as-user flow with optional fallback bind using service account when directories disallow anonymous search. - Claims enricher (
IClaimsEnricher): queries group membership/attributes and projects them into canonical roles/claims. - Optional client provisioning (
IClientProvisioningStore): maintains machine/service principals either in Mongo (metadata) or via LDAPserviceConnectionPointentries based on configuration. - Health checks: periodic LDAP 
whoamiorsearchprobes surfaced throughAuthorityPluginHealthResult. 
Authority Host
 ├── Plugin Manifest (ldap)
 ├── Registrar → registers ConnectionFactory, LdapCredentialStore, LdapClaimsEnricher
 ├── Password Grant Handler → CredentialStore.VerifyPasswordAsync → LDAP Bind
 └── Claims Pipeline → ClaimsEnricher.EnrichAsync → LDAP group lookup
6. Configuration Schema (Draft)
connection:
  host: "ldaps://ldap.example.internal"
  port: 636
  useStartTls: false
  validateCertificates: true
  bindDn: "cn=stellaops-bind,ou=service,dc=example,dc=internal"
  bindPasswordSecret: "file:/etc/stellaops/secrets/ldap-bind.txt"
  searchBase: "dc=example,dc=internal"
  usernameAttribute: "uid"
  userDnFormat: "uid={username},ou=people,dc=example,dc=internal"  # optional template
security:
  requireTls: true
  allowedCipherSuites: []          # optional allow-list
  referralChasing: false
lockout:
  useAuthorityPolicies: true       # reuse Authority lockout counters
  directoryLockoutAttribute: "pwdAccountLockedTime"
claims:
  groupAttribute: "memberOf"
  groupToRoleMap:
    "cn=stellaops-admins,ou=groups,dc=example,dc=internal": "operators"
    "cn=stellaops-read,ou=groups,dc=example,dc=internal": "auditors"
  extraAttributes:
    displayName: "displayName"
    email: "mail"
clientProvisioning:
  enabled: false
  containerDn: "ou=service,dc=example,dc=internal"
  secretAttribute: "userPassword"
health:
  probeIntervalSeconds: 60
  timeoutSeconds: 5
7. Capability Mapping
| Capability | Implementation Notes | 
|---|---|
password | 
Bind-as-user validation with Authority lockout integration. Mandatory. | 
clientProvisioning | 
Optional; when enabled, creates/updates LDAP entries for machine clients or stores metadata in Mongo if directory writes are disabled. | 
bootstrap | 
Exposed only when bootstrap manifest provides service account credentials AND directory write permissions are confirmed during startup. | 
mfa | 
Not supported in MVP. Future iteration may integrate TOTP attributes or external MFA providers. | 
8. Operational Considerations
- Offline cache: provide optional Mongo cache for group membership to keep 
/readyresponsive if LDAP is temporarily unreachable. Cache entries must include TTL and invalidation hooks. - Secrets management: accept 
file:and environment variable references; integrate with existingStellaOps.Configurationsecret providers. - Observability: emit structured logs with event IDs (
LDAP_BIND_START,LDAP_BIND_FAILURE,LDAP_GROUP_LOOKUP), counters for success/failure, and latency histograms. - Throttling: reuse Authority rate-limiting middleware; add per-connection throttles to avoid saturating directory servers during brute-force attacks.
 
9. Security & Compliance
- Enforce TLS (
ldaps://or STARTTLS) by default. Provide explicitallowInsecureflag gated behind environment variable for lab/testing only. - Support password hash migration by detecting directory lockout attributes and surfacing 
RequiresPasswordResetwhen policies demand changes. - Log distinguished names only at 
Debuglevel to avoid leaking sensitive structure in default logs. - Coordinate with Security Guild for penetration testing before GA; incorporate audit log entries for bind attempts and provisioning changes.
 
10. Testing Strategy
- Unit tests: mock LDAP connections to validate DN formatting, error mapping, and capability negotiation.
 - Integration tests: run against an ephemeral OpenLDAP container (seeded via LDIF fixtures) within CI. Include offline cache regression (disconnect LDAP mid-test).
 - Determinism tests: feed identical LDIF snapshots and configuration to ensure output tokens/claims remain stable across runs.
 - Smoke tests: 
dotnet testharness plus manualdotnet runscenario verifying/tokenpassword grants and/internal/usersbootstrap with LDAP-backed store. 
11. Implementation Plan
- Scaffold 
StellaOps.Authority.Plugin.Ldapproject + tests (net10.0,<IsAuthorityPlugin>true). - Implement configuration options + validation (mirroring Standard plugin guardrails).
 - Build connection factory + credential store with bind logic.
 - Implement claims enricher and optional cache layer.
 - Add client provisioning store (optional) with toggles for read-only deployments.
 - Wire bootstrapper to validate connectivity/permissions and record findings in startup logs.
 - Extend developer guide with LDAP specifics (post-RFC acceptance).
 - Update Docs and TODO trackers; produce release notes entry once merged.
 
12. Open Questions
- Should client provisioning default to storing metadata in Mongo even when LDAP writes succeed (to preserve audit history)?
 - Do we require LDAPS mutual TLS support (client certificates) for regulated environments? If yes, need to extend configuration schema.
 - How will we map LDAP groups to Authority scopes/roles when names differ significantly? Consider supporting regex or mapping scripts.
 
13. Timeline (Tentative)
- Week 1: RFC review & sign-off.
 - Week 2-3: Implementation & unit tests.
 - Week 4: Integration tests + documentation updates.
 - Week 5: Security review, release candidate packaging.
 
14. Approval
- Auth Guild Lead: TBD
 - Security Guild Representative: TBD
 - DevEx Docs: TBD
 
Please add comments inline or via PR review. Once approved, track execution under PLG7.