Saltar al contenido principal

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.

SAML metadata of the application

Configurar la aplicación de Casdoor​

En la página de edición de la aplicación, establezca dos campos:

FieldValue
Redirect URLsThe 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 URLLa 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

Redirect URLs field with the entity ID

SAML reply URL field

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 URLBindingWhere Casdoor sends the response
SetPOSTTo the reply URL. The reply URL overrides the AssertionConsumerServiceURL of the SAMLRequest
EmptyGETTo the AssertionConsumerServiceURL that Casdoor reads from the SAMLRequest
nota

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.

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

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

  3. Guarde la aplicación. La pestaña SAML mostrará entonces la IdP-initiated SSO URL:

    <casdoor-host>/login/saml/authorize/admin/<application-name>
  4. 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:

  1. Casdoor verifica la solicitud. Su Issuer debe estar en Redirect URLs, debe contener un NameID, y la aplicación debe tener una SAML single logout URL.
  2. Casdoor finaliza las sesiones de Casdoor indicadas por los valores SessionIndex de la solicitud. Sin un SessionIndex, solo finaliza la sesión del navegador que envió la solicitud, y solo si el NameID pertenece a su usuario.
  3. 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.
  4. Casdoor responde con un LogoutResponse firmado sobre el binding de la solicitud: una redirección a la SAML single logout URL para GET, o un formulario que el navegador envía allí para POST.

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 XMLCampo de usuario
Emailcorreo electrónico
Nombre para mostrarnombre para mostrar
Namename

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:

NameFormato del nombreValue
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

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.

  1. Añade http://localhost:6900/acs/example y http://localhost:6900/saml/acs/example a los Redirect URLs de app-built-in.

  2. 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
  3. Abre la URL. Aparece la página de inicio de sesión de Casdoor.

    Casdoor sign-in page

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

    SAML response in the console

Véase también​