Pular para o conteúdo principal

Visão Geral

Casdoor agora pode ser usado como um SAML IdP. Até este ponto, o Casdoor suportou as principais funcionalidades do SAML 2.0.

Configuração no SP

Em geral, o SP requer três campos obrigatórios: Single Sign-On, Issuer e Public Certificate. A maioria dos SPs pode obter esses campos fazendo o upload do arquivo de Metadados XML ou da URL de Metadados XML para preenchimento automático.

Os metadados do ponto de extremidade SAML no Casdoor são <Endpoint of casdoor>/api/saml/metadata?application=admin/<application name>. Suponha que o ponto de extremidade do Casdoor seja https://door.casdoor.com, e ele contém uma aplicação chamada app-built-in. O ponto de extremidade de Metadados XML será:

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

Você também pode encontrar os metadados na página de edição da aplicação. Clique no botão para copiar a URL e cole-a no navegador para baixar os Metadados XML.

metadados

Configuração no Casdoor IdP

Casdoor suporta tanto GET quanto POST SAMLResponse. O Casdoor precisa saber quais tipos de solicitações o SP suporta quando o Casdoor envia o SAMLResponse para o SP. Você precisa configurar a aplicação no Casdoor com base no tipo de SAMLResponse suportado pelo seu SP.

informação

Se você preencher a URL de Resposta, o Casdoor enviará o SAMLResponse por Solicitação POST. Se a URL de Resposta estiver vazia, o Casdoor usará a solicitação GET. Você pode se perguntar como o Casdoor sabe a URL de Resposta do SP se a URL de Resposta estiver vazia. Na verdade, o Casdoor pode obter a URL chamada AssertionConsumerServiceURL analisando o SAMLRequest e enviar a solicitação com SAMLResponse para AssertionConsumerServiceURL. A URL de Resposta substituirá a AssertionConsumerServiceURL no SAMLRequest.

  • URL de Resposta: Digite a URL do ACS que verifica a resposta SAML.

    URL de Resposta

  • URL de Redirecionamento: Digite um nome único. Isto pode ser chamado de Audience ou Entity ID no seu SP. Certifique-se de preencher a mesma URL de Redirecionamento aqui como no seu SP.

    Entity ID

SAML attributes

Some SP will require you to provide external attributes in SAML Response, you can add those in SAML attributes table. And you can insert user's field to it.

For examle

NomeName 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>
informação

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

Perfil do usuário

Após o login bem-sucedido, o perfil do usuário na SAMLResponse retornada do Casdoor tem três campos. Os atributos no XML e os atributos do usuário no Casdoor são mapeados da seguinte forma:

Nome do Atributo XMLCampo do usuário
Emailemail
DisplayNamedisplayName
Namename

Veja https://en.wikipedia.org/wiki/SAML_2.0 para mais informações sobre SAML e suas diferentes versões.

Um exemplo

gosaml2 é uma implementação do SAML 2.0 para Provedores de Serviço baseada em etree e goxmldsig, uma implementação pura em Go de assinaturas digitais XML. Usamos esta biblioteca para testar o SAML 2.0 no Casdoor como mostrado abaixo.

Suponha que você possa acessar o Casdoor através de http://localhost:7001/, e seu Casdoor contém uma aplicação chamada app-built-in, que pertence a uma organização chamada built-in. As URLs, http://localhost:6900/acs/example e http://localhost:6900/saml/acs/example, devem ser adicionadas às URLs de Redirecionamento em 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)
}
}

Execute o código acima, e o console exibirá a seguinte mensagem.

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

Clique na URL para autenticar, e a página de login do Casdoor será exibida.

login

Após autenticar, você receberá as mensagens de resposta como mostrado abaixo.

resposta