Saltar al contenido principal

SAML IdP overview

Casdoor can act as a SAML 2.0 IdP. This page covers SP configuration, Casdoor IdP settings, and SAML attributes.

Configuration in the SP (service provider)

The SP typically needs Single Sign-On URL, Issuer, and Public Certificate. Most SPs can fill these from the Casdoor XML Metadata URL or by uploading the metadata file.

Casdoor metadata URL format: <casdoor-endpoint>/api/saml/metadata?application=admin/<application-name>

Example: if Casdoor is at https://door.casdoor.com and the application is app-built-in:

https://door.casdoor.com/api/saml/metadata?application=admin/app-built-in

The metadata URL is also on the application edit page; copy it and open in a browser to download the XML.

metadatos

Configuración en Casdoor IdP

Casdoor soporta tanto GET como POST SAMLResponse. Configure the application in Casdoor to match the SAMLResponse binding (GET or POST) that your SP supports.

When integrating Casdoor as a SAML IdP with external identity providers (like Azure AD), the /api/acs endpoint receives SAML responses. This endpoint is configured to accept cross-origin POST requests, allowing IdPs from different domains to send authentication data.

información

Si completa la URL de respuesta, Casdoor enviará la SAMLResponse mediante la solicitud POST. Si la URL de respuesta está vacía, Casdoor usará la solicitud GET. Puede que se pregunte cómo sabe Casdoor la URL de respuesta del SP si la URL de respuesta está vacía. De hecho, Casdoor puede obtener la URL llamada AssertionConsumerServiceURL analizando la SAMLRequest y enviar la solicitud con SAMLResponse a AssertionConsumerServiceURL. La URL de respuesta sobrescribirá la AssertionConsumerServiceURL en SAMLRequest.

  • URL de respuesta: Escriba la URL del ACS que verifica la respuesta SAML.

    URL de respuesta

  • URL de redirección: Escriba un nombre único. Esto puede llamarse Audience o Entity ID en su SP. Asegúrese de completar la misma URL de redirección aquí como en su SP.

    ID de entidad

SAML attributes

If the SP requires extra attributes in the SAML response, add them in the SAML attributes table and map user fields as needed.

If the service provider only needs NameID and not extra user attributes (Email, Name, DisplayName, Roles), enable Disable SAML attributes in the application settings. When enabled, Casdoor will omit these attributes from the SAML response, which can help avoid XML namespace issues with certain SPs that have strict validation requirements.

Assertion signature control

SAML responses from Casdoor are always signed to ensure authenticity. However, some service providers may not support or require signed assertions within the response itself. Starting from version 2.81.0, Casdoor added assertion signatures following SAML 2.0 best practices, but this caused compatibility issues with certain SPs like Sentry.

If a service provider does not handle signed assertions correctly, disable assertion signing while keeping the response envelope signed. Toggle the Enable SAML assertion signature option in your application settings to control this behavior. When disabled, Casdoor will sign only the SAML response envelope, which maintains security while ensuring compatibility with a wider range of service providers.

For example

NombreName formatValue
https://www.aliyun.com/SAML-Role/Attributes/RoleSessionNameUnspecified$user.name
https://www.aliyun.com/SAML-Role/Attributes/RoleUnspecifiedacs:ram::1879818006829152:role/$user.roles,acs:ram::1879818006829152:saml-provider/testa

will generate response with external saml:Attribute

<saml:Attribute Name="https://www.aliyun.com/SAML-Role/Attributes/RoleSessionName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml:AttributeValue xsi:type="xs:string">admi122n@outlook.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="https://www.aliyun.com/SAML-Role/Attributes/Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml:AttributeValue xsi:type="xs:string"> acs:ram::1879818006829152:role/role1,acs:ram::1879818006829152:saml-provider/testa</saml:AttributeValue>
<saml:AttributeValue xsi:type="xs:string"> acs:ram::1879818006829152:role/role2,acs:ram::1879818006829152:saml-provider/testa</saml:AttributeValue>
</saml:Attribute>
información

We only support insert $user.owner,$user.name,$user.email,$user.id,$user.phone,$user.roles,$user.permissions,$user.groups

Perfil de usuario

Después de iniciar sesión con éxito, el perfil de usuario en la SAMLResponse devuelta de Casdoor tiene tres campos. Los atributos en el XML y los atributos del usuario en Casdoor se mapean de la siguiente manera:

Nombre de atributo XMLCampo de usuario
Correo electrónicoemail
Nombre para mostrardisplayName
Namename

See https://en.wikipedia.org/wiki/SAML_2.0 for more information about SAML and its different versions.

Un ejemplo

gosaml2 es una implementación de SAML 2.0 para Proveedores de Servicios basada en etree y goxmldsig, una implementación pura de Go de firmas digitales XML. Usamos esta biblioteca para probar SAML 2.0 en Casdoor como se muestra a continuación.

Example: Casdoor at http://localhost:7001/, application app-built-in in org built-in. Add http://localhost:6900/acs/example and http://localhost:6900/saml/acs/example to Redirect URLs in app-built-in.

import (
"crypto/x509"
"fmt"
"net/http"

"io/ioutil"

"encoding/base64"
"encoding/xml"

saml2 "github.com/russellhaering/gosaml2"
"github.com/russellhaering/gosaml2/types"
dsig "github.com/russellhaering/goxmldsig"
)

func main() {
res, err := http.Get("http://localhost:7001/api/saml/metadata?application=admin/app-built-in")
if err != nil {
panic(err)
}

rawMetadata, err := ioutil.ReadAll(res.Body)
if err != nil {
panic(err)
}

metadata := &types.EntityDescriptor{}
err = xml.Unmarshal(rawMetadata, metadata)
if err != nil {
panic(err)
}

certStore := dsig.MemoryX509CertificateStore{
Roots: []*x509.Certificate{},
}

for _, kd := range metadata.IDPSSODescriptor.KeyDescriptors {
for idx, xcert := range kd.KeyInfo.X509Data.X509Certificates {
if xcert.Data == "" {
panic(fmt.Errorf("metadata certificate(%d) must not be empty", idx))
}
certData, err := base64.StdEncoding.DecodeString(xcert.Data)
if err != nil {
panic(err)
}

idpCert, err := x509.ParseCertificate(certData)
if err != nil {
panic(err)
}

certStore.Roots = append(certStore.Roots, idpCert)
}
}

randomKeyStore := dsig.RandomKeyStoreForTest()

sp := &saml2.SAMLServiceProvider{
IdentityProviderSSOURL: metadata.IDPSSODescriptor.SingleSignOnServices[0].Location,
IdentityProviderIssuer: metadata.EntityID,
ServiceProviderIssuer: "http://localhost:6900/acs/example",
AssertionConsumerServiceURL: "http://localhost:6900/v1/_saml_callback",
SignAuthnRequests: true,
AudienceURI: "http://localhost:6900/saml/acs/example",
IDPCertificateStore: &certStore,
SPKeyStore: randomKeyStore,
}

http.HandleFunc("/v1/_saml_callback", func(rw http.ResponseWriter, req *http.Request) {
err := req.ParseForm()
if err != nil {
rw.WriteHeader(http.StatusBadRequest)
return
}
samlReponse := req.URL.Query().Get("SAMLResponse")
assertionInfo, err := sp.RetrieveAssertionInfo(samlReponse)
if err != nil {
fmt.Println(err)
rw.WriteHeader(http.StatusForbidden)
return
}
fmt.Println(assertionInfo)
if assertionInfo.WarningInfo.InvalidTime {
fmt.Println("here12:", assertionInfo.WarningInfo.InvalidTime)
rw.WriteHeader(http.StatusForbidden)
return
}

if assertionInfo.WarningInfo.NotInAudience {
fmt.Println(assertionInfo)
fmt.Println("here13:", assertionInfo.WarningInfo.NotInAudience)
rw.WriteHeader(http.StatusForbidden)
return
}

fmt.Fprintf(rw, "NameID: %s\n", assertionInfo.NameID)

fmt.Fprintf(rw, "Assertions:\n")

for key, val := range assertionInfo.Values {
fmt.Fprintf(rw, " %s: %+v\n", key, val)
}
fmt.Println(assertionInfo.Values.Get("FirstName"))
fmt.Fprintf(rw, "\n")

fmt.Fprintf(rw, "Warnings:\n")
fmt.Fprintf(rw, "%+v\n", assertionInfo.WarningInfo)
})

println("Visit this URL To Authenticate:")
authURL, err := sp.BuildAuthURL("")
if err != nil {
panic(err)
}

println(authURL)

println("Supply:")
fmt.Printf(" SP ACS URL : %s\n", sp.AssertionConsumerServiceURL)

err = http.ListenAndServe(":6900", nil)
if err != nil {
panic(err)
}
}

Ejecute el código anterior, y la consola mostrará el siguiente mensaje.

Visit this URL To Authenticate:
http://localhost:7001/login/saml/authorize/admin/app-built-in?SAMLRequest=lFVbk6K8Fv0rFvNo2QR...
Supply:
SP ACS URL : http://localhost:6900/v1/_saml_callback

Haga clic en la URL para autenticarse, y se mostrará la página de inicio de sesión de Casdoor.

iniciar sesión

After authentication, the response looks like the examples below.

respuesta