Skip to content

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 onlinehttps://<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 attributeOutgoing claim type
E-Mail-AddressesE-Mail Address
Display-NameName

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 attributeOutgoing claim type
Token-Groups - Unqualified NamesGroup

"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 Artifact or Redirect the 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.xml

This 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:

yaml
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)
bash
helm upgrade orbitalreg charts/orbitalreg -n <ns> -f values-adfs.yaml

7. 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.

SymptomCauseFix
Pod crashes, saml init failedFederationMetadata.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 clickMetadata 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 loginSAML ACS endpoint on the trust uses Artifact/Redirect binding → response arrives as GETSet the endpoint binding to POST
404 on /saml/acsTrusted URL with trailing slash or wrong pathExactly https://<domain>/saml/acs
405 opening /saml/acs in a browserNormal — GET on a POST-only endpointNot an error
AD FS event 364, "Invalid SAML request signature"Trust created manually without the SP signature certificateImport sp.crt on the trust's Signature tab, or re-create the trust from the SP metadata URL
AD FS event 364, audience/identifier mismatchRelying party identifier ≠ saml.entityIDBoth must be exactly https://<domain>/saml/metadata
Login works but roles: readerToken-Groups rule missing, or qualified names (DOMAIN\…) don't match auth.adminGroupsUse Token-Groups — Unqualified NamesGroup; match the plain name
groups empty in whoamiClaim rule issues a different outgoing claim type, or stale sessionOutgoing claim type must be Group; full re-login

Reference: what OrbitalReg reads (preset adfs)

OrbitalReg expectsSAML attribute name
Email (identity)http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
Groups (→ role)http://schemas.xmlsoap.org/claims/Group
Display namehttp://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.

Released under the Apache-2.0 License.