SAML with AD FS
Tested against AD FS on Windows Server 2019/2022. Goal: login through AD FS works and members of an AD security group get org_admin. The adfs preset reads the conventional issuance-transform output: xmlsoap email/name URIs, Token-Groups issued as the xmlsoap Group claim, and Microsoft's 2008/06 role URI.
1. Create the relying party trust
AD FS Management → Relying Party Trusts → Add Relying Party Trust…
- Claims aware → Start.
- Select Data Source: Import data about the relying party published online →
https://<domain>/saml/metadata(OrbitalReg's SP metadata — includes the ACS URL, entityID, and the SP signing certificate, so AD FS can verify the signed AuthnRequests automatically). If the AD FS host cannot reach the registry, export the metadata XML in a browser and import it as a file. - Display name:
OrbitalReg→ Next → default access-control policy ("Permit everyone", tighten later) → finish.
If you configured the trust manually instead of via metadata import, you must set by hand: the SAML endpoint (see step 3), the relying party identifier https://<domain>/saml/metadata, and the signature certificate (sp.crt) on the trust's Signature tab — otherwise AD FS rejects the signed login requests with event 364 (Invalid SAML request signature).
2. Claim rules
Relying Party Trusts → OrbitalReg → Edit Claim Issuance Policy… → Add Rule…
Rule 1 — LDAP attributes (template Send LDAP Attributes as Claims):
| LDAP attribute | Outgoing claim type |
|---|---|
E-Mail-Addresses | E-Mail Address |
Display-Name | Name |
Rule 2 — NameID (template Transform an Incoming Claim):
- Incoming claim type:
E-Mail Address - Outgoing claim type:
Name ID - Outgoing name ID format:
Email
Rule 3 — groups (template Send LDAP Attributes as Claims):
| LDAP attribute | Outgoing claim type |
|---|---|
Token-Groups - Unqualified Names | Group |
"Unqualified Names" emits plain group names (orbital-admins) rather than DOMAIN\orbital-admins — the values below match on the plain name. The outgoing claim type Group is http://schemas.xmlsoap.org/claims/Group, exactly what the preset reads. (Role-based rules issuing the 2008/06 role URI work too — the preset also reads Role.)
3. Endpoint: POST binding
Metadata import sets this up correctly. If you created the trust manually: Trust → Properties → Endpoints → Add SAML…
- Endpoint type: SAML Assertion Consumer
- Binding: POST — with
ArtifactorRedirectthe response arrives as GET and OrbitalReg's ACS answers HTTP 405 - Trusted URL:
https://<domain>/saml/acs(https, no trailing slash)
4. Create the AD group
In Active Directory Users and Computers: create a security group orbital-admins, add your user. (Group membership is evaluated at login — token-groups are baked into the assertion.)
5. Metadata URL
AD FS publishes federation metadata at:
https://<adfs-host>/FederationMetadata/2007-06/FederationMetadata.xmlThis becomes saml.idpMetadataURL. It must be reachable from the OrbitalReg pods (watch out for split-brain DNS where the AD FS host only resolves internally — the URL in the values must be resolvable and its TLS cert valid from the cluster).
6. Values + deploy
Complete example: charts/orbitalreg/values-adfs.yaml.example. Essentials:
saml:
enabled: true
idpPreset: "adfs"
rootURL: "https://registry.example.com"
entityID: "https://registry.example.com/saml/metadata"
idpMetadataURL: "https://<adfs-host>/FederationMetadata/2007-06/FederationMetadata.xml"
existingSecret: "orbitalreg-saml-sp"
auth:
adminGroups:
- "orbital-admins" # unqualified AD group name (Token-Groups rule)helm upgrade orbitalreg charts/orbitalreg -n <ns> -f values-adfs.yaml7. Verify
Log out fully, log back in, check https://<domain>/auth/whoami: groups contains orbital-admins, roles contains org_admin. Email fallback while debugging: add your login email to auth.adminGroups, redeploy, re-login.
Troubleshooting
AD FS errors surface in Event Viewer → Applications and Services Logs → AD FS → Admin — the event ID is usually more useful than the browser error page.
| Symptom | Cause | Fix |
|---|---|---|
Pod crashes, saml init failed | FederationMetadata.xml unreachable from the pod (DNS, internal-only host, TLS) | curl the URL from the pod network; fix DNS/cert |
| "response code null" on login click | Metadata carries endpoint hostnames that don't resolve publicly (farm behind internal alias) | Ensure the AD FS federation service name is the public host |
| HTTP 405 after AD FS login | SAML ACS endpoint on the trust uses Artifact/Redirect binding → response arrives as GET | Set the endpoint binding to POST |
404 on /saml/acs | Trusted URL with trailing slash or wrong path | Exactly https://<domain>/saml/acs |
405 opening /saml/acs in a browser | Normal — GET on a POST-only endpoint | Not an error |
| AD FS event 364, "Invalid SAML request signature" | Trust created manually without the SP signature certificate | Import sp.crt on the trust's Signature tab, or re-create the trust from the SP metadata URL |
| AD FS event 364, audience/identifier mismatch | Relying party identifier ≠ saml.entityID | Both must be exactly https://<domain>/saml/metadata |
Login works but roles: reader | Token-Groups rule missing, or qualified names (DOMAIN\…) don't match auth.adminGroups | Use Token-Groups — Unqualified Names → Group; match the plain name |
groups empty in whoami | Claim rule issues a different outgoing claim type, or stale session | Outgoing claim type must be Group; full re-login |
Reference: what OrbitalReg reads (preset adfs)
| OrbitalReg expects | SAML attribute name |
|---|---|
| Email (identity) | http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress |
| Groups (→ role) | http://schemas.xmlsoap.org/claims/Group |
| Display name | http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name |
| Role (secondary) | http://schemas.microsoft.com/ws/2008/06/identity/claims/role |
See the SSO overview for role mapping and claim-name overrides.