Discrepancy in documentation of SAML config
Describe the Bug
I have configured Directus with SAML SSO with Okta The auth flow is initiated from Directus but throws unexpected error upon receiving SAML Response Error:
[06:44:05.272] WARN: [SAML] Unexpected error during SAML login
directus | err: {
directus | "type": "TypeError",
directus | "message": "Cannot read properties of undefined (reading 'toLowerCase')",
directus | "stack":
directus | TypeError: Cannot read properties of undefined (reading 'toLowerCase')
directus | at SAMLAuthDriver.fetchUserID (file:///directus/node_modules/.pnpm/file+api/node_modules/@directus/api/dist/auth/drivers/saml.js:36:75)
directus | at SAMLAuthDriver.getUserID (file:///directus/node_modules/.pnpm/file+api/node_modules/@directus/api/dist/auth/drivers/saml.js:44:35)
directus | at AuthenticationService.login (file:///directus/node_modules/.pnpm/file+api/node_modules/@directus/api/dist/services/authentication.js:43:37)
directus | at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
directus | at async file:///directus/node_modules/.pnpm/file+api/node_modules/@directus/api/dist/auth/drivers/saml.js:114:60
directus | }
Following is the Content of SAML Response:
<?xml version="1.0" encoding="UTF-8"?>
<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="http://directus.192.168.29.216.nip.io/auth/login/sso/acs" ID="id10163046429617805585028950" InResponseTo="_a5e37f1a-171f-4b89-b097-e4aa1a5c46af" IssueInstant="2023-08-09T06:44:02.093Z" Version="2.0">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91vwiyk0PeANC25d7</saml2:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#id10163046429617805585028950">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>HEI77t+IuSL/yWFDtYZMhcVO2njjHNQ4anv6wUBsEyA=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>k1rt1oCpMqBm8j8OCC5k46Fd8hNa2OCT5TvvVt/pryvvyh370MEUjtmXnbskMBMfbfGz1MDvEK1lqs30UljHSJn9DFMnqUMxJs+xDDPDjpbtTATxPgZfyjK2IuCAoDgBsWAUf0VEiNAgsy/g5HPkKF0qedfhX9RMO0Eyei6lMSJen5beHwi3Bgn1aUvTO/ZfuYgGn7U8zWHYVffeyvulQu37qbSyFMEmwgCY9F8rnzrqvwVrYdcQBbPcHAmFtqJFFuoogHHXxLKoMlhd689nqA7a0HeoTGhlnIgATNJ38k9YEG214rdAP4NYL1OK4z1smd5uzVlPu5lTmS2j49VF5g==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDqDCCApCgAwIBAgIGAYdpe5zzMA0GCSqGSIb3DQEBCwUAMIGUMQswCQYDVQQGEwJVUzETMBEG
A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
MBIGA1UECwwLU1NPUHJvdmlkZXIxFTATBgNVBAMMDGRldi0yMjIzMTgxMzEcMBoGCSqGSIb3DQEJ
ARYNaW5mb0Bva3RhLmNvbTAeFw0yMzA0MTAwNDQ0MjFaFw0zMzA0MTAwNDQ1MjFaMIGUMQswCQYD
VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsG
A1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxFTATBgNVBAMMDGRldi0yMjIzMTgxMzEc
MBoGCSqGSIb3DQEJARYNaW5mb0Bva3RhLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAKA4byPf3iEgVEL3NHfhZYCd6izBNa8lkmbT5ImHyjEJfqw0fTocmQRb5Nn3G3pg6MoX8yYG
v2wfcyXDt67Fio5vDsJ7BjxhmL13TuD/S2jUAX0qRgXrO40xlzkteoanWZSxbjQATKcp30VhkZS+
RYWuXTYSrEZYL35nk8+NMaNfqSeEeoXqt3DsH4uXOcZgxCzZqbSJ2iSIuOBFUPYvIzBZ0qDMcGsE
fA/fAa1KMclHYWCubOkYQB9+VOywoyikiyOE4ZTLRCZ505TbP/o/ADa0GDgJSQwYuntHuHDO4Frt
lHs4qKWnLVXEblNHmMa69Hvhlm1WISNBzeZjM3RkZNcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA
A7QcvaJaoCSHM9EJMg52CsZwo5zAPLUrKn6ZHj+AJXcwpd7Pfd+0vyFttjCRCD2rmUlTGU44OW34
AoPuQnH+ETWxj8AdPC9kGcZqpjEpXh+nfp27cp/67ZJIBdju5E+FkjFX7nQsjwFWVKTJ13G+4KXi
+8cDHrmLqjKKSf7aUHXoOmjsXQo7YTaykvM4Sp13g7wsZJFZsUKNGNi/fDG/+LNl7erctXGPKvat
guN1UEB86Sh/9BVY1SH4EWQshxcZpo/jRZzKFOup2DD6NQLYxFiMTvQy7tWJwaA+jUAa8ZzDgqow
W13+irxzqbkwqUoLzwhXYqhoPLlYL6jGH8i+uA==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2p:Status xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
<saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</saml2p:Status>
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="id101630464297580882046872582" IssueInstant="2023-08-09T06:44:02.093Z" Version="2.0">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91vwiyk0PeANC25d7</saml2:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#id101630464297580882046872582">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>QyNEk7ZgU3v5j57efbX1tUvT9vU2/VmNFYFLYnSVCRk=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>jevD05xiyy2U2ypjrxgQlaa6Rceut39giUHC5RIObxs0fxFa+IYEv+EW36rW5u+j/X5pJwbcuYMQVWEOzG5zLo4b5Q2scIyDu0nwymZLLZB8HwslZoAWv4hCas67tqdpKs+oE7aMWXSbRvcg2U22ryrKlJiRHTXJnTfxjIFffdZ6uYUC28MJCl0xE8iI9G1jNMDQU5MCi4gV0WsbXMzFlA4OZ1KhVwcKnwhopUm+RRDHpIIEB29S9ZQ9d/kwknp08KB2qIQqDSkcSBldoq3t28JHKP1cWHOP7b2OekhyZYDFRPRFMc1IIg+MIWrU8FKdnGNNdjYKc5xAqj9qsWQ9VQ==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDqDCCApCgAwIBAgIGAYdpe5zzMA0GCSqGSIb3DQEBCwUAMIGUMQswCQYDVQQGEwJVUzETMBEG
A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
MBIGA1UECwwLU1NPUHJvdmlkZXIxFTATBgNVBAMMDGRldi0yMjIzMTgxMzEcMBoGCSqGSIb3DQEJ
ARYNaW5mb0Bva3RhLmNvbTAeFw0yMzA0MTAwNDQ0MjFaFw0zMzA0MTAwNDQ1MjFaMIGUMQswCQYD
VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsG
A1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxFTATBgNVBAMMDGRldi0yMjIzMTgxMzEc
MBoGCSqGSIb3DQEJARYNaW5mb0Bva3RhLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAKA4byPf3iEgVEL3NHfhZYCd6izBNa8lkmbT5ImHyjEJfqw0fTocmQRb5Nn3G3pg6MoX8yYG
v2wfcyXDt67Fio5vDsJ7BjxhmL13TuD/S2jUAX0qRgXrO40xlzkteoanWZSxbjQATKcp30VhkZS+
RYWuXTYSrEZYL35nk8+NMaNfqSeEeoXqt3DsH4uXOcZgxCzZqbSJ2iSIuOBFUPYvIzBZ0qDMcGsE
fA/fAa1KMclHYWCubOkYQB9+VOywoyikiyOE4ZTLRCZ505TbP/o/ADa0GDgJSQwYuntHuHDO4Frt
lHs4qKWnLVXEblNHmMa69Hvhlm1WISNBzeZjM3RkZNcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA
A7QcvaJaoCSHM9EJMg52CsZwo5zAPLUrKn6ZHj+AJXcwpd7Pfd+0vyFttjCRCD2rmUlTGU44OW34
AoPuQnH+ETWxj8AdPC9kGcZqpjEpXh+nfp27cp/67ZJIBdju5E+FkjFX7nQsjwFWVKTJ13G+4KXi
+8cDHrmLqjKKSf7aUHXoOmjsXQo7YTaykvM4Sp13g7wsZJFZsUKNGNi/fDG/+LNl7erctXGPKvat
guN1UEB86Sh/9BVY1SH4EWQshxcZpo/jRZzKFOup2DD6NQLYxFiMTvQy7tWJwaA+jUAa8ZzDgqow
W13+irxzqbkwqUoLzwhXYqhoPLlYL6jGH8i+uA==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">[email protected]</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData InResponseTo="_a5e37f1a-171f-4b89-b097-e4aa1a5c46af" NotOnOrAfter="2023-08-09T06:49:02.094Z" Recipient="http://directus.192.168.29.216.nip.io/auth/login/sso/acs"/>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" NotBefore="2023-08-09T06:39:02.094Z" NotOnOrAfter="2023-08-09T06:49:02.094Z">
<saml2:AudienceRestriction>
<saml2:Audience>directus.192.168.29.216.nip.io</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" AuthnInstant="2023-08-09T06:44:02.093Z" SessionIndex="_a5e37f1a-171f-4b89-b097-e4aa1a5c46af">
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
</saml2:Assertion>
</saml2p:Response>
To Reproduce
Setup
Following are the required docker-compose to setup the stack in local
Change the IP 192.168.29.216 to you system's LAN IP which can be found using hostname -I on Linux or ipconfig getifaddr en0 on a Mac
Traefik
#docker-compose.yaml
version: "3.3"
services:
traefik:
image: "traefik:v2.9"
container_name: "traefik"
command:
#- "--log.level=DEBUG"
- "--api.insecure=true"
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--experimental.plugins.traefik-themepark.modulename=github.com/packruler/traefik-themepark"
- "--experimental.plugins.traefik-themepark.version=v1.3.0"
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.entryPoints=web"
- "traefik.http.routers.api.rule=PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
ports:
- "80:80"
# - "8080:8080"
- "443:443"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
networks:
- frontend
- backend
whoami:
image: "traefik/whoami"
container_name: "simple-service"
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.127.0.0.1.nip.io`)"
- "traefik.http.routers.whoami.entrypoints=web"
networks:
- backend
networks:
frontend:
driver: bridge
backend:
driver: bridge
Directus
Replace SAML IDP Metadata with the one from your IDP setup:
version: '3'
services:
mailhog:
image: mailhog/mailhog
container_name: 'mailhog'
ports:
- "1025:1025"
- "8025:8025"
database:
container_name: database
image: postgis/postgis:13-master
# Required when running on platform other than amd64, like Apple M1/M2:
# platform: linux/amd64
volumes:
- ./data/database:/var/lib/postgresql/data
environment:
POSTGRES_USER: 'directus'
POSTGRES_PASSWORD: 'directus'
POSTGRES_DB: 'directus'
directus:
container_name: directus
image: directus/directus:latest
ports:
- 8055:8055
volumes:
# By default, uploads are stored in /directus/uploads
# Always make sure your volumes matches the storage root when using
# local driver
- ./uploads:/directus/uploads
# Make sure to also mount the volume when using SQLite
# - ./database:/directus/database
# If you want to load extensions from the host
# - ./extensions:/directus/extensions
- database
expose:
- 8055
environment:
KEY: '255d861b-5ea1-5996-9aa3-922530ec40b1'
SECRET: '6116487b-cda1-52c2-b5b5-c8022c45e263'
DB_CLIENT: 'pg'
DB_HOST: 'database'
DB_PORT: '5432'
DB_DATABASE: 'directus'
DB_USER: 'directus'
DB_PASSWORD: 'directus'
CACHE_ENABLED: 'false'
ADMIN_EMAIL: '[email protected]'
ADMIN_PASSWORD: 'd1r3ctu5'
EMAIL_SMTP_NAME: local
EMAIL_SMTP_HOST: mailhog
EMAIL_SMTP_PORT: 1025
EMAIL_FROM: [email protected]
EMAIL_TRANSPORT: smtp
AUTH_PROVIDERS: 'sso'
AUTH_SSO_DRIVER: 'saml'
AUTH_SSO_SP_metadata: ''
AUTH_SSO_IDP_metadata: |
<?xml version="1.0" encoding="UTF-8"?><md:EntityDescriptor entityID="http://www.okta.com/exk91vwiyk0PeANC25d7" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"><md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><md:KeyDescriptor use="signing"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>MIIDqDCCApCgAwIBAgIGAYdpe5zzMA0GCSqGSIb3DQEBCwUAMIGUMQswCQYDVQQGEwJVUzETMBEG
A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
MBIGA1UECwwLU1NPUHJvdmlkZXIxFTATBgNVBAMMDGRldi0yMjIzMTgxMzEcMBoGCSqGSIb3DQEJ
ARYNaW5mb0Bva3RhLmNvbTAeFw0yMzA0MTAwNDQ0MjFaFw0zMzA0MTAwNDQ1MjFaMIGUMQswCQYD
VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsG
A1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxFTATBgNVBAMMDGRldi0yMjIzMTgxMzEc
MBoGCSqGSIb3DQEJARYNaW5mb0Bva3RhLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAKA4byPf3iEgVEL3NHfhZYCd6izBNa8lkmbT5ImHyjEJfqw0fTocmQRb5Nn3G3pg6MoX8yYG
v2wfcyXDt67Fio5vDsJ7BjxhmL13TuD/S2jUAX0qRgXrO40xlzkteoanWZSxbjQATKcp30VhkZS+
RYWuXTYSrEZYL35nk8+NMaNfqSeEeoXqt3DsH4uXOcZgxCzZqbSJ2iSIuOBFUPYvIzBZ0qDMcGsE
fA/fAa1KMclHYWCubOkYQB9+VOywoyikiyOE4ZTLRCZ505TbP/o/ADa0GDgJSQwYuntHuHDO4Frt
lHs4qKWnLVXEblNHmMa69Hvhlm1WISNBzeZjM3RkZNcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA
A7QcvaJaoCSHM9EJMg52CsZwo5zAPLUrKn6ZHj+AJXcwpd7Pfd+0vyFttjCRCD2rmUlTGU44OW34
AoPuQnH+ETWxj8AdPC9kGcZqpjEpXh+nfp27cp/67ZJIBdju5E+FkjFX7nQsjwFWVKTJ13G+4KXi
+8cDHrmLqjKKSf7aUHXoOmjsXQo7YTaykvM4Sp13g7wsZJFZsUKNGNi/fDG/+LNl7erctXGPKvat
guN1UEB86Sh/9BVY1SH4EWQshxcZpo/jRZzKFOup2DD6NQLYxFiMTvQy7tWJwaA+jUAa8ZzDgqow
W13+irxzqbkwqUoLzwhXYqhoPLlYL6jGH8i+uA==</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://dev-22231813.okta.com/app/dev-22231813_directus_1/exk91vwiyk0PeANC25d7/sso/saml"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://dev-22231813.okta.com/app/dev-22231813_directus_1/exk91vwiyk0PeANC25d7/sso/saml"/></md:IDPSSODescriptor></md:EntityDescriptor>
PUBLIC_URL: "http://directus.192.168.29.216.nip.io"
labels:
- "traefik.enable=true"
- "traefik.http.routers.directus.rule=Host(`directus.192.168.29.216.nip.io`)"
- "traefik.http.routers.directus.entrypoints=web"
- "traefik.http.routers.directus"
networks:
default:
external: true
name: traefik_backend
Directus Version
v10.5.x
Hosting Strategy
Self-Hosted (Docker Image)
The identifier is missing in the payload. Please meke sure that AUTH_<PROVIDER>_IDENTIFIER_KEY is set correctly, see https://docs.directus.io/self-hosted/config-options.html#saml and https://docs.directus.io/self-hosted/sso-examples.html.
@paescuj please update the doc regarding the same.
As per this doc, it is assumed that if I am not providing AUTH_<PROVIDER>IDENTIFIER_KEY, it should default to the value of AUTH<PROVIDER>_EMAIL_KEY, for which default value is email.
This implies that if both variables are not set by user the value shoud be email and that's what I am getting from my IDP.
But I have to explicitly set both values.
Although on Okta I also have to explicity add email key to attributes as it doesn't do it by default. I hope we can contribute to the doc to provide more working examples.
I think you're right! The docs should be updated in this regard: https://github.com/directus/directus/blob/a885c7b86811d6877a2abb75bd1b668ff490c0cc/api/src/auth/drivers/saml.ts#L52-L53
Seems like a copypasta issue from the OAuth docs. Might be nice to actually default to email to keep the functionality consistent with other SSO providers, rather than updating the docs.