التخطي إلى المحتوى الرئيسي

نظرة عامة

يمكن الآن استخدام Casdoor كمزود هوية SAML IdP. حتى هذه النقطة، دعم Casdoor الميزات الرئيسية لـ SAML 2.0.

التكوين في مزود الخدمة SP

بشكل عام، يتطلب مزود الخدمة SP ثلاثة حقول مطلوبة: Single Sign-On، Issuer، و Public Certificate. يمكن لمعظم مزودي الخدمة SP الحصول على هذه الحقول عن طريق تحميل ملف XML Metadata أو URL لـ XML Metadata للإكمال التلقائي.

بيانات metadata لنقطة نهاية SAML في Casdoor هي <Endpoint of casdoor>/api/saml/metadata?application=admin/<application name>. لنفترض أن نقطة نهاية Casdoor هي https://door.casdoor.com، وتحتوي على تطبيق يسمى app-built-in. نقطة نهاية بيانات XML Metadata ستكون:

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

يمكنك أيضًا العثور على البيانات metadata في صفحة تحرير التطبيق. انقر على الزر لنسخ الرابط والصقه في المتصفح لتنزيل ملف XML Metadata.

metadata

التكوين في مزود الهوية Casdoor IdP

Casdoor يدعم كلاً من طلبات GET و POST SAMLResponse. Casdoor يحتاج إلى معرفة أنواع الطلبات التي يدعمها مزود الخدمة SP عندما يرسل Casdoor الـ SAMLResponse إلى مزود الخدمة SP. تحتاج إلى تكوين التطبيق في Casdoor بناءً على نوع SAMLResponse الذي يدعمه مزود الخدمة SP الخاص بك.

معلومات

إذا قمت بملء Reply URL، سيرسل Casdoor الـ SAMLResponse بواسطة طلب POST. إذا كان عنوان الرد فارغًا، سيستخدم Casdoor طلب GET. قد تتساءل كيف يعرف Casdoor Reply URL لمزود الخدمة SP إذا كان Reply URL فارغًا. في الواقع، يمكن لـ Casdoor الحصول على الرابط المسمى AssertionConsumerServiceURL عن طريق تحليل SAMLRequest وإرسال الطلب مع SAMLResponse إلى AssertionConsumerServiceURL. سيتم الكتابة فوق Reply URL لـ AssertionConsumerServiceURL في SAMLRequest.

  • عنوان الرد Reply URL: اكتب عنوان URL لخدمة ACS التي تتحقق من استجابة SAML.

    عنوان الرد

  • عنوان إعادة التوجيه Redirect URL: اكتب اسمًا فريدًا. قد يُطلق على هذا Audience أو Entity ID في مزود الخدمة SP الخاص بك. تأكد من ملء نفس Redirect URL هنا كما في مزود الخدمة SP الخاص بك.

    معرف الكيان Entity ID

ملف تعريف المستخدم

بعد تسجيل الدخول بنجاح، يحتوي ملف تعريف المستخدم في الاستجابة SAMLResponse العائدة من Casdoor على ثلاثة حقول. يتم تعيين السمات في XML وسمات المستخدم في Casdoor على النحو التالي:

اسم السمة XMLحقل المستخدم
البريد الإلكترونيemail
اسم العرضdisplayName
الاسمname

راجع https://en.wikipedia.org/wiki/SAML_2.0 لمزيد من المعلومات حول SAML وإصداراته المختلفة.

مثال

gosaml2 هو تنفيذ لـ SAML 2.0 لمزودي الخدمة مبني على etree و goxmldsig، وهو تنفيذ بلغة Go للتوقيعات الرقمية XML. نحن نستخدم هذه المكتبة لاختبار SAML 2.0 في Casdoor كما هو موضح أدناه.

لنفترض أنه يمكنك الوصول إلى Casdoor من خلال http://localhost:7001/، ويحتوي Casdoor الخاص بك على تطبيق يسمى app-built-in، والذي ينتمي إلى منظمة تسمى built-in. يجب إضافة الروابط، http://localhost:6900/acs/example و http://localhost:6900/saml/acs/example، إلى روابط إعادة التوجيه Redirect URLs في 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)
}
}

قم بتشغيل الكود أعلاه، وسيعرض الوحدة الطرفية الرسالة التالية.

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

انقر على الرابط للمصادقة، وستظهر صفحة تسجيل الدخول إلى Casdoor.

تسجيل الدخول

بعد المصادقة، ستتلقى رسائل الاستجابة كما هو موضح أدناه.

الاستجابة