feat: handle error when parsing samlResponse (#1744)

* fix: handle err from parse samlResponse

* fix: lint
This commit is contained in:
Yaodong Yu 2023-04-16 00:36:25 +08:00 committed by GitHub
parent 7503e05a4a
commit 47dc3715f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 53 additions and 39 deletions

View File

@ -339,7 +339,7 @@ func (c *ApiController) Login() {
userInfo := &idp.UserInfo{} userInfo := &idp.UserInfo{}
if provider.Category == "SAML" { if provider.Category == "SAML" {
// SAML // SAML
userInfo.Id, err = object.ParseSamlResponse(form.SamlResponse, provider.Type) userInfo.Id, err = object.ParseSamlResponse(form.SamlResponse, provider, c.Ctx.Request.Host)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
@ -546,7 +546,7 @@ func (c *ApiController) Login() {
func (c *ApiController) GetSamlLogin() { func (c *ApiController) GetSamlLogin() {
providerId := c.Input().Get("id") providerId := c.Input().Get("id")
relayState := c.Input().Get("relayState") relayState := c.Input().Get("relayState")
authURL, method, err := object.GenerateSamlLoginUrl(providerId, relayState, c.GetAcceptLanguage()) authURL, method, err := object.GenerateSamlRequest(providerId, relayState, c.Ctx.Request.Host, c.GetAcceptLanguage())
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
} }

View File

@ -23,29 +23,32 @@ import (
"regexp" "regexp"
"strings" "strings"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/i18n"
saml2 "github.com/russellhaering/gosaml2" saml2 "github.com/russellhaering/gosaml2"
dsig "github.com/russellhaering/goxmldsig" dsig "github.com/russellhaering/goxmldsig"
) )
func ParseSamlResponse(samlResponse string, providerType string) (string, error) { func ParseSamlResponse(samlResponse string, provider *Provider, host string) (string, error) {
samlResponse, _ = url.QueryUnescape(samlResponse) samlResponse, _ = url.QueryUnescape(samlResponse)
sp, err := buildSp(&Provider{Type: providerType}, samlResponse) sp, err := buildSp(provider, samlResponse, host)
if err != nil { if err != nil {
return "", err return "", err
} }
assertionInfo, err := sp.RetrieveAssertionInfo(samlResponse)
assertionInfo, err := sp.RetrieveAssertionInfo(samlResponse)
if err != nil {
return "", err
}
return assertionInfo.NameID, err return assertionInfo.NameID, err
} }
func GenerateSamlLoginUrl(id, relayState, lang string) (auth string, method string, err error) { func GenerateSamlRequest(id, relayState, host, lang string) (auth string, method string, err error) {
provider := GetProvider(id) provider := GetProvider(id)
if provider.Category != "SAML" { if provider.Category != "SAML" {
return "", "", fmt.Errorf(i18n.Translate(lang, "saml_sp:provider %s's category is not SAML"), provider.Name) return "", "", fmt.Errorf(i18n.Translate(lang, "saml_sp:provider %s's category is not SAML"), provider.Name)
} }
sp, err := buildSp(provider, "")
sp, err := buildSp(provider, "", host)
if err != nil { if err != nil {
return "", "", err return "", "", err
} }
@ -67,35 +70,22 @@ func GenerateSamlLoginUrl(id, relayState, lang string) (auth string, method stri
return auth, method, nil return auth, method, nil
} }
func buildSp(provider *Provider, samlResponse string) (*saml2.SAMLServiceProvider, error) { func buildSp(provider *Provider, samlResponse string, host string) (*saml2.SAMLServiceProvider, error) {
origin := conf.GetConfigString("origin") _, origin := getOriginFromHost(host)
certStore := dsig.MemoryX509CertificateStore{ certStore, err := buildSpCertificateStore(provider, samlResponse)
Roots: []*x509.Certificate{},
}
certEncodedData := ""
if samlResponse != "" {
certEncodedData = parseSamlResponse(samlResponse, provider.Type)
} else if provider.IdP != "" {
certEncodedData = provider.IdP
}
certData, err := base64.StdEncoding.DecodeString(certEncodedData)
if err != nil { if err != nil {
return nil, err return nil, err
} }
idpCert, err := x509.ParseCertificate(certData)
if err != nil {
return nil, err
}
certStore.Roots = append(certStore.Roots, idpCert)
sp := &saml2.SAMLServiceProvider{ sp := &saml2.SAMLServiceProvider{
ServiceProviderIssuer: fmt.Sprintf("%s/api/acs", origin), ServiceProviderIssuer: fmt.Sprintf("%s/api/acs", origin),
AssertionConsumerServiceURL: fmt.Sprintf("%s/api/acs", origin), AssertionConsumerServiceURL: fmt.Sprintf("%s/api/acs", origin),
IDPCertificateStore: &certStore,
SignAuthnRequests: false, SignAuthnRequests: false,
IDPCertificateStore: &certStore,
SPKeyStore: dsig.RandomKeyStoreForTest(), SPKeyStore: dsig.RandomKeyStoreForTest(),
} }
if provider.Endpoint != "" { if provider.Endpoint != "" {
sp.IdentityProviderSSOURL = provider.Endpoint sp.IdentityProviderSSOURL = provider.Endpoint
sp.IdentityProviderIssuer = provider.IssuerUrl sp.IdentityProviderIssuer = provider.IssuerUrl
@ -104,10 +94,45 @@ func buildSp(provider *Provider, samlResponse string) (*saml2.SAMLServiceProvide
sp.SignAuthnRequests = true sp.SignAuthnRequests = true
sp.SPKeyStore = buildSpKeyStore() sp.SPKeyStore = buildSpKeyStore()
} }
return sp, nil return sp, nil
} }
func parseSamlResponse(samlResponse string, providerType string) string { func buildSpKeyStore() dsig.X509KeyStore {
keyPair, err := tls.LoadX509KeyPair("object/token_jwt_key.pem", "object/token_jwt_key.key")
if err != nil {
panic(err)
}
return &dsig.TLSCertKeyStore{
PrivateKey: keyPair.PrivateKey,
Certificate: keyPair.Certificate,
}
}
func buildSpCertificateStore(provider *Provider, samlResponse string) (dsig.MemoryX509CertificateStore, error) {
certEncodedData := ""
if samlResponse != "" {
certEncodedData = getCertificateFromSamlResponse(samlResponse, provider.Type)
} else if provider.IdP != "" {
certEncodedData = provider.IdP
}
certData, err := base64.StdEncoding.DecodeString(certEncodedData)
if err != nil {
return dsig.MemoryX509CertificateStore{}, err
}
idpCert, err := x509.ParseCertificate(certData)
if err != nil {
return dsig.MemoryX509CertificateStore{}, err
}
certStore := dsig.MemoryX509CertificateStore{
Roots: []*x509.Certificate{idpCert},
}
return certStore, nil
}
func getCertificateFromSamlResponse(samlResponse string, providerType string) string {
de, err := base64.StdEncoding.DecodeString(samlResponse) de, err := base64.StdEncoding.DecodeString(samlResponse)
if err != nil { if err != nil {
panic(err) panic(err)
@ -122,14 +147,3 @@ func parseSamlResponse(samlResponse string, providerType string) string {
res := regexp.MustCompile(expression).FindStringSubmatch(deStr) res := regexp.MustCompile(expression).FindStringSubmatch(deStr)
return res[1] return res[1]
} }
func buildSpKeyStore() dsig.X509KeyStore {
keyPair, err := tls.LoadX509KeyPair("object/token_jwt_key.pem", "object/token_jwt_key.key")
if err != nil {
panic(err)
}
return &dsig.TLSCertKeyStore{
PrivateKey: keyPair.PrivateKey,
Certificate: keyPair.Certificate,
}
}