Casdoor como proveedor de identidad (IdP) SAML 2.0 de código abierto
Casdoor es un proveedor de identidad (IdP) SAML 2.0. Esta página explica qué configurar en el proveedor de servicios (SP) y en Casdoor, y qué datos de usuario transporta la respuesta SAML. Para guías paso a paso para proveedores de servicios específicos, consulte las otras páginas de esta sección.
Configurar el proveedor de servicios
Un proveedor de servicios generalmente solicita tres valores: la URL de inicio de sesión único, el emisor y el certificado público del IdP. La mayoría de los proveedores de servicios leen estos tres valores de los metadatos SAML del IdP, mediante una URL o desde un archivo cargado.
La URL de metadatos de una aplicación de Casdoor es:
<casdoor-host>/api/saml/metadata?application=admin/<application-name>
Por ejemplo, para Casdoor en https://door.casdoor.com y la aplicación app-built-in:
https://door.casdoor.com/api/saml/metadata?application=admin/app-built-in
Para obtener la URL en la consola de administración de Casdoor, abra la página de edición de la aplicación, vaya a la pestaña SAML y haga clic en Copy SAML metadata URL. Para descargar los metadatos como un archivo XML, abra la URL en un navegador.

Configurar la aplicación de Casdoor
En la página de edición de la aplicación, establezca dos campos:
| Field | Value |
|---|---|
| Redirect URLs | The identifier of the service provider, which the SP calls the audience or the entity ID. Enter exactly the same value as in the SP |
| SAML reply URL | La URL del Assertion Consumer Service (ACS) del SP, que recibe y verifica la respuesta SAML. Déjela vacía para usar el enlace de redirección |


Enlace de respuesta
Casdoor puede enviar la SAMLResponse mediante una solicitud HTTP POST o una solicitud HTTP GET. Elija lo que soporte su proveedor de servicios:
| SAML reply URL | Binding | Where Casdoor sends the response |
|---|---|---|
| Set | POST | To the reply URL. The reply URL overrides the AssertionConsumerServiceURL of the SAMLRequest |
| Empty | GET | To the AssertionConsumerServiceURL that Casdoor reads from the SAMLRequest |
Cuando Casdoor autentica a los usuarios en un IdP SAML externo, como Azure AD, el IdP externo envía su respuesta SAML al endpoint /api/acs de Casdoor. Este endpoint acepta solicitudes POST entre orígenes (cross-origin), por lo que un IdP en otro dominio puede enviar la respuesta.
Iniciar el inicio de sesión desde Casdoor (SSO iniciado por IdP)
En el SSO iniciado por IdP, el usuario comienza en Casdoor en lugar de en el proveedor de servicios. Casdoor envía al SP una respuesta SAML que no fue solicitada por ningún AuthnRequest. Úselo para enlaces de portal y marcadores.
-
En la pestaña SAML de la aplicación, establezca SAML reply URL en la URL ACS del SP. Sin ella, el inicio de sesión falla con
the SAML reply URL should not be empty for IdP-initiated SSO. -
Asegúrese de que la primera entrada de Redirect URLs sea el ID de entidad del SP. Casdoor la utiliza como audiencia de la aserción.
-
Guarde la aplicación. La pestaña SAML mostrará entonces la IdP-initiated SSO URL:
<casdoor-host>/login/saml/authorize/admin/<application-name> -
Haga clic en Copy IdP-initiated SSO URL y proporcione la URL a sus usuarios.
Un usuario que abra la URL inicia sesión en Casdoor, y Casdoor envía la respuesta SAML a la URL de respuesta mediante el binding HTTP-POST. La respuesta no tiene el atributo InResponseTo, porque no hubo ninguna solicitud previa. Para pasar un RelayState al SP, añádalo a la URL como parámetro de consulta, por ejemplo ?RelayState=/dashboard.
Cerrar sesión de los usuarios en el SP (cierre de sesión único)
Casdoor admite el cierre de sesión único SAML (SLO) en ambas direcciones. Para activarlo, establezca SAML single logout URL en la pestaña SAML de la aplicación en la URL SingleLogoutService del SP.
Los metadatos de la aplicación anuncian el SingleLogoutService de Casdoor, con los bindings HTTP-Redirect y HTTP-POST, en:
<casdoor-backend-host>/api/saml/logout/admin/<application-name>
Cada aserción lleva un SessionIndex en su AuthnStatement, que identifica la sesión de Casdoor del inicio de sesión.
Cierre de sesión iniciado por SP
Cuando un usuario cierra sesión en el SP, el SP envía un LogoutRequest al SingleLogoutService de Casdoor, mediante GET o POST, en el parámetro SAMLRequest y un RelayState opcional:
- Casdoor verifica la solicitud. Su
Issuerdebe estar en Redirect URLs, debe contener unNameID, y la aplicación debe tener una SAML single logout URL. - Casdoor finaliza las sesiones de Casdoor indicadas por los valores
SessionIndexde la solicitud. Sin unSessionIndex, solo finaliza la sesión del navegador que envió la solicitud, y solo si elNameIDpertenece a su usuario. - Casdoor cierra la sesión del usuario en las otras aplicaciones de esas sesiones, mediante cierres de sesión back-channel de OIDC y solicitudes de cierre de sesión SAML.
- Casdoor responde con un
LogoutResponsefirmado sobre el binding de la solicitud: una redirección a la SAML single logout URL paraGET, o un formulario que el navegador envía allí paraPOST.
Cierre de sesión iniciado por IdP
Cuando un usuario cierra sesión en Casdoor, a través de /api/logout o /api/sso-logout, Casdoor envía un LogoutRequest firmado a la SAML single logout URL de cada aplicación SAML a la que el usuario inició sesión en las sesiones finalizadas. Lo mismo ocurre cuando Casdoor finaliza sesiones por otras razones, por ejemplo, cuando se prohíbe a un usuario iniciar sesión, o cuando un nuevo inicio de sesión supera el límite de sesiones. Casdoor envía estas solicitudes desde el servidor, como con OIDC back-channel logout, no a través del navegador. Cuando el SP envía su LogoutResponse al mismo endpoint SingleLogoutService, Casdoor verifica que su Issuer esté en Redirect URLs y que su estado sea Success.
Perfil de usuario en la respuesta
Por defecto, la SAMLResponse contiene tres atributos del usuario:
| Nombre de atributo XML | Campo de usuario |
|---|---|
| correo electrónico | |
| Nombre para mostrar | nombre para mostrar |
| Name | name |
Si el proveedor de servicios solo necesita el NameID y no atributos, active Disable SAML attributes en la aplicación. Casdoor omitirá entonces los atributos de la respuesta. Esto evita problemas de espacio de nombres XML con proveedores de servicios que validan estrictamente la respuesta.
Añadir atributos SAML
Si el proveedor de servicios requiere otros atributos, añádalos a la tabla SAML attributes de la aplicación. Un valor puede contener las siguientes variables: $user.owner, $user.name, $user.displayName, $user.email, $user.id, $user.phone, $user.roles, $user.permissions y $user.groups.
Por ejemplo, las dos filas siguientes:
| Name | Formato del nombre | Value |
|---|---|---|
https://www.aliyun.com/SAML-Role/Attributes/RoleSessionName | Unspecified | $user.name |
https://www.aliyun.com/SAML-Role/Attributes/Role | Unspecified | acs:ram::1879818006829152:role/$user.roles,acs:ram::1879818006829152:saml-provider/testa |
Producen estos atributos en la respuesta:
<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>
Controlar la firma de la aserción
Casdoor siempre firma la respuesta SAML. Para firmar también la aserción dentro de la respuesta, active Enable SAML assertion signature en la aplicación. Esta opción está desactivada por defecto.
Las versiones 2.81.0 a 2.247.x siempre firmaban también la aserción. Algunos proveedores de servicios, como Sentry, rechazan las respuestas con una aserción firmada, por lo que desde la versión 2.248.0, Casdoor firma solo el sobre de la respuesta a menos que la opción esté activada. La respuesta firmada mantiene la autenticidad de la aserción también.
Prueba con un proveedor de servicios en Go
gosaml2 es una implementación de SAML 2.0 para proveedores de servicios en Go. El siguiente programa la utiliza para probar Casdoor como IdP.
El ejemplo supone que Casdoor está en http://localhost:7001/ y la aplicación app-built-in de la organización built-in.
-
Añade
http://localhost:6900/acs/exampleyhttp://localhost:6900/saml/acs/examplea los Redirect URLs deapp-built-in. -
Ejecuta el programa:
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)
}
}La consola muestra:
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 -
Abre la URL. Aparece la página de inicio de sesión de Casdoor.

-
Inicia sesión. El programa imprime la respuesta SAML.

Véase también
- Keycloak (SAML)
- AWS Client VPN (SAML)
- Proveedores SAML: Inicia sesión en Casdoor con un IdP SAML externo.
- SAML 2.0 en Wikipedia