diff --git a/attribute.go b/attribute.go index 6b63cd5..c0cf8df 100644 --- a/attribute.go +++ b/attribute.go @@ -26,7 +26,11 @@ func (vals Values) Get(k string) string { return "" } if v, ok := vals[k]; ok && len(v.Values) > 0 { - return string(v.Values[0].Value) + if len(v.Values[0].ValueXML) != 0 { + return string(v.Values[0].ValueXML) + } else { + return string(v.Values[0].Value) + } } return "" } @@ -57,7 +61,11 @@ func (vals Values) GetAll(k string) []string { if v, ok := vals[k]; ok && len(v.Values) > 0 { for i := 0; i < len(v.Values); i++ { - av = append(av, string(v.Values[i].Value)) + if len(v.Values[i].ValueXML) != 0 { + av = append(av, string(v.Values[i].ValueXML)) + } else { + av = append(av, string(v.Values[i].Value)) + } } } diff --git a/saml_test.go b/saml_test.go index 0a4d575..0a8f895 100644 --- a/saml_test.go +++ b/saml_test.go @@ -180,6 +180,7 @@ func TestSAML(t *testing.T) { require.Equal(t, "Phoebe", assertionInfo.Values.Get("FirstName")) require.Equal(t, "Simon", assertionInfo.Values.Get("LastName")) require.Equal(t, "phoebesimon", assertionInfo.Values.Get("Login")) + require.Equal(t, "sales@acme.comsupport@acme.com", assertionInfo.Values.Get("emailAddress")) assertionInfoModifiedAudience := signResponse(t, assertionInfoModifiedAudienceResponse, sp) diff --git a/test_constants.go b/test_constants.go index 4707275..6cdce3c 100644 --- a/test_constants.go +++ b/test_constants.go @@ -52,7 +52,7 @@ TxkXxsoKNW0awJNpWRbU81QpheMFfENIzLam4Itc/5kSZAaSy/9e2QKfo4jBo/MMbCq2vM9TyeJQ DJpRaioUTd2lGh4TLUxAxCxtUk/pascL+3Nn936LFmUCLxaxnbeGzPOXAhscCtU1H0nFsXRnKx5a cPXYSKFZZZktieSkww2Oi8dg2DYaQhGQMSFMVqgVfwEu4bvCRBvdSiNXdWGCZQmFVzBZZ/9rOLzP pvTFTPnpkavJm81FLlUhiE/oFgKlCDLWDknSpXAI0uZGERcwPca6xvIMh86LjQKjbVci9FYDStXC -qRnqQ+TccSu/B6uONFsDEngGcXSKfB+aphoebe.simon@scaleft.com123urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransportPhoebeSimonphoebe.simon@scaleft.comphoebesimon` +qRnqQ+TccSu/B6uONFsDEngGcXSKfB+aphoebe.simon@scaleft.com123urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransportPhoebeSimonphoebe.simon@scaleft.comphoebesimonsales@acme.comsupport@acme.com` const manInTheMiddledResponse = ` http://www.okta.com/exk5zt0r12Edi4rD20h7ijTqmVmDy7ssK+rvmJaCQ6AQaFaXz+HIN/r6O37B0eQ=G09fAYXGDLK+/jAekHsNL0RLo40Xm6+VwXmUj0IDIrvIIv/mJU5VD6ylOLnPezLDBVY9BJst1YCz+8krdvmQ8Stkd6qiN2bN/5KpCdika111YGpeNdMmg/E57ZG3S895hTNJQYOfCwhPFUtQuXLkspOaw81pcqOTr+bVSofJ8uQP7cVQa/ANxbjKAj0fhAuxAvZfiqPms5Stv4sNGpzULUDJl87CoEleHExGmpTsI7Qt3EvGToPMZXPHF4MGvuC0Z2ZD4iI6Pr7xk98t54PJtAX2qJu1tZqBJmL0Qcq5spl9W3yC1tAZuDeFLm1C4/T9crO2Q5WILP/tkw/yJ+ZttQ==MIIDpDCCAoygAwIBAgIGAVLIBhAwMA0GCSqGSIb3DQEBBQUAMIGSMQswCQYDVQQGEwJVUzETMBEG diff --git a/types/response.go b/types/response.go index 2a54c46..5e292a5 100644 --- a/types/response.go +++ b/types/response.go @@ -1,11 +1,11 @@ // Copyright 2016 Russell Haering et al. -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // https://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -47,15 +47,15 @@ type Response struct { } type LogoutResponse struct { - XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol LogoutResponse"` - ID string `xml:"ID,attr"` - InResponseTo string `xml:"InResponseTo,attr"` - Destination string `xml:"Destination,attr"` - Version string `xml:"Version,attr"` - IssueInstant time.Time `xml:"IssueInstant,attr"` - Status *Status `xml:"Status"` - Issuer *Issuer `xml:"Issuer"` - SignatureValidated bool `xml:"-"` // not read, not dumped + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol LogoutResponse"` + ID string `xml:"ID,attr"` + InResponseTo string `xml:"InResponseTo,attr"` + Destination string `xml:"Destination,attr"` + Version string `xml:"Version,attr"` + IssueInstant time.Time `xml:"IssueInstant,attr"` + Status *Status `xml:"Status"` + Issuer *Issuer `xml:"Issuer"` + SignatureValidated bool `xml:"-"` // not read, not dumped } type Status struct { @@ -168,18 +168,19 @@ type Attribute struct { } type AttributeValue struct { - XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion AttributeValue"` - Type string `xml:"xsi:type,attr"` - Value string `xml:",chardata"` + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion AttributeValue"` + Type string `xml:"xsi:type,attr"` + Value string `xml:",chardata"` + ValueXML string `xml:",innerxml"` } type AuthnStatement struct { - XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion AuthnStatement"` - //Section 4.1.4.2 - https://docs.oasis-open.org/security/saml/v2.0/saml-profiles-2.0-os.pdf - //If the identity provider supports the Single Logout profile, defined in Section 4.4 - //, any such authentication statements MUST include a SessionIndex attribute to enable - //per-session logout requests by the service provider. - SessionIndex string `xml:"SessionIndex,attr,omitempty"` + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion AuthnStatement"` + //Section 4.1.4.2 - https://docs.oasis-open.org/security/saml/v2.0/saml-profiles-2.0-os.pdf + //If the identity provider supports the Single Logout profile, defined in Section 4.4 + //, any such authentication statements MUST include a SessionIndex attribute to enable + //per-session logout requests by the service provider. + SessionIndex string `xml:"SessionIndex,attr,omitempty"` AuthnInstant *time.Time `xml:"AuthnInstant,attr,omitempty"` SessionNotOnOrAfter *time.Time `xml:"SessionNotOnOrAfter,attr,omitempty"` AuthnContext *AuthnContext `xml:"AuthnContext"`