Exemple #1
0
func TestParseResponse(t *testing.T) {
	// we'll need to change this function later, so keep a copy of it for the reset
	newTokenCopy := newToken
	Convey("Given a WS-Fed response message", t, func() {
		config := Config{}
		config.MetadataURL = "https://signin.blackbaud.com/wsfederation/metadata"
		config.MetadataCertsAreTrusted = true
		config.Realm = "http://account.blackbaud.com"
		sso := New(&config)
		Convey("When ParseResponse is called", func() {
			// change this function after signature validation, so that we can pass
			// the expiration check
			newToken = func(wresult string, realm string) (Token, error) {
				doc := etree.NewDocument()
				err := doc.ReadFromString(wresult)
				if err != nil {
					return nil, err
				}
				conditions := doc.FindElement("//Conditions")
				notOnOrAfterVal := conditions.SelectAttr("NotOnOrAfter")
				notOnOrAfterVal.Value = "3015-09-26T16:28:56.681Z"
				return &SAMLv11{XMLDoc: doc, Realm: realm}, nil
			}
			claims, err := sso.ParseResponse(wresult)
			Convey("Then a Claim is returned without error", func() {
				So(err, ShouldBeNil)
				So(claims.Subject.ID, ShouldEqual, "6ef81ad2-99f8-4c42-996c-def1d98db711")
			})
		})
		Convey("When ParseResponse is called with the wrong audience/realm combo", func() {
			// change this function after signature validation, so that we can pass
			// the expiration check
			newToken = func(wresult string, realm string) (Token, error) {
				doc := etree.NewDocument()
				err := doc.ReadFromString(wresult)
				if err != nil {
					return nil, err
				}
				conditions := doc.FindElement("//Conditions")
				notOnOrAfterVal := conditions.SelectAttr("NotOnOrAfter")
				notOnOrAfterVal.Value = "3015-09-26T16:28:56.681Z"
				return &SAMLv11{XMLDoc: doc, Realm: "http://wrongaudience.com"}, nil
			}
			_, err := sso.ParseResponse(wresult)
			Convey("Then an error should occur", func() {
				So(err, ShouldNotBeNil)
				So(err.Error(), ShouldEqual, "go-wsfed: Audience check failed")
			})
		})
		Convey("When ParseResponse is called with an old response", func() {
			_, err := sso.ParseResponse(wresult)
			Convey("Then an error should occur", func() {
				So(err, ShouldNotBeNil)
				So(err.Error(), ShouldEqual, "go-wsfed: Expiration check failed")
			})
		})
		Convey("When ParseResponse is called with an invalid signature response", func() {
			wresultModified := `<trust:RequestSecurityTokenResponseCollection xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512"><trust:RequestSecurityTokenResponse><trust:Lifetime><wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2015-09-26T15:28:56.681Z</wsu:Created><wsu:Expires xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2015-09-26T16:28:56.681Z</wsu:Expires></trust:Lifetime><wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"><wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing"><wsa:Address>http://account.blackbaud.com/</wsa:Address></wsa:EndpointReference></wsp:AppliesTo><trust:RequestedSecurityToken><saml:Assertion MajorVersion="1" MinorVersion="1" AssertionID="_79b4fd7d-e0cd-406e-86a7-19ca73d360f8" Issuer="Blackbaud Authentication Service" IssueInstant="2015-09-26T15:28:56.681Z" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"><saml:Conditions NotBefore="2015-09-26T15:28:56.681Z" NotOnOrAfter="2015-09-26T16:28:56.681Z"><saml:AudienceRestrictionCondition><saml:Audience>http://account.blackbaud.com/</saml:Audience></saml:AudienceRestrictionCondition></saml:Conditions><saml:AttributeStatement><saml:Subject></saml:Subject></saml:AttributeStatement><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference URI="#_79b4fd7d-e0cd-406e-86a7-19ca73d360f8"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>pC1Oa1rmYaYBxVW6bZJnUm7aIFHoGa1a6z0MIKVcWoc=</DigestValue></Reference></SignedInfo><SignatureValue>gQObr3Indcv1709DpW3AZUhZevHnYWGzpB6edlGh4tHpViiu6h8f1uATeIvqMxi/bttcrfQk+Rls3K8GmE7BgAXBuewKR2chObRB+CFPvnteLQOVm5DQGY4C8mEqRTJvL4LLBajw03YulFvg95WLHIzqjguTmKf4gYx++uAS7n9zuAHrQ5XF/5B1ae6PER+dJsc2vNLdxrOuJNPYJZ0L5PJhF8bmAMHcwFYd3JfgDH8dJ0rxpfXr4MVinx94Alo9U2lzWuHu/yMQ8pr8qsNllDVq0yP5J7epSq5iO6RbkN2FQjFdsjmuNstteOn/vs8xc00lhDWvttnDH65RPUtgDA==</SignatureValue><KeyInfo><X509Data><X509Certificate>MIIDFzCCAgOgAwIBAgIQYyFH4hyHqIZJFSvhaTufDDAJBgUrDgMCHQUAMCAxHjAcBgNVBAMTFVRlc3RCQkF1dGhTaWduaW5nQ2VydDAeFw0xMzExMDUxNjUzNTlaFw0zOTEyMzEyMzU5NTlaMCAxHjAcBgNVBAMTFVRlc3RCQkF1dGhTaWduaW5nQ2VydDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMyjnT+N3cypXtoTfr8HTNXcThqPKSQyioqIt0A7ZEQjByErcFdx5LyPSxyUWNg9r9Ay3T/qUqmCD4roK/LruT8W+02SLgZLGJ4cecuQqOryABVn3SeTCuViLVRFkAbGVWXqEI2woFq226xCyKEbYMIr0Lxisuo8nEQ0XSAYh2tiT6XXMf2aHomBxxUk9tkfyjBqim+OBZxglKQ+jQgA35CDi6NezJaSE13oNuo7iMlOyYV3+jPh/tohYKxhAod2biMa5oKDmVc3C6zvKZyoSVMQE0jRs2SzZW/TzBXkHfBAtoSRCarWtTv+ode+XYcQw0Hi5p5FKYmKx/sdx4RvLG0CAwEAAaNVMFMwUQYDVR0BBEowSIAQZY/UuhZiXYqsNv1VH1ec3aEiMCAxHjAcBgNVBAMTFVRlc3RCQkF1dGhTaWduaW5nQ2VydIIQYyFH4hyHqIZJFSvhaTufDDAJBgUrDgMCHQUAA4IBAQBokHC1xp2I4+K7SzGQiXehlLcjDX4+9wWX+8ZzByOKyTIfc+3DthoU1aWiuG1ioFyL8ttRLm10n3PSXR7hJtXY4JnyxfolZy+c6+n3AsYnstaZipZgnCxJ2+P1e+MzbOoMFuBceg+vpW0dJex2MrJ5h/khwFNVvhoPnGT8W7j6Q+Lw6VeexbbLBNPtpmHlrK5/7RjjZdZTvFbEMqBz1hl4Ny1Gz+mLq4fsNxC4eoW5kq/MyVbigX8kwOonr4dh68OSOLoYJ9ml62wE0uhiamM89zaFeui6e/R/xAqsTlnl10qDBDVKcGHyIrmgBUkHYknQxCnHoFW/N+w8KmhryAko</X509Certificate></X509Data></KeyInfo></Signature></saml:Assertion></trust:RequestedSecurityToken><trust:RequestedAttachedReference><o:SecurityTokenReference k:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1" xmlns:k="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><o:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID">_79b4fd7d-e0cd-406e-86a7-19ca73d360f8</o:KeyIdentifier></o:SecurityTokenReference></trust:RequestedAttachedReference><trust:RequestedUnattachedReference><o:SecurityTokenReference k:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1" xmlns:k="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><o:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID">_79b4fd7d-e0cd-406e-86a7-19ca73d360f8</o:KeyIdentifier></o:SecurityTokenReference></trust:RequestedUnattachedReference><trust:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</trust:TokenType><trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType><trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType></trust:RequestSecurityTokenResponse></trust:RequestSecurityTokenResponseCollection>`
			_, err := sso.ParseResponse(wresultModified)
			Convey("Then an error should occur", func() {
				So(err, ShouldNotBeNil)
				So(err.Error(), ShouldStartWith, "signedxml: ")
			})
		})
		Convey("When ParseResponse is called with an unsupported Token", func() {
			newToken = func(wresult string, realm string) (Token, error) {
				return nil, errors.New("fake token error")
			}
			_, err := sso.ParseResponse(wresult)
			Convey("Then an error should occur", func() {
				So(err, ShouldNotBeNil)
				So(err.Error(), ShouldEqual, "fake token error")
			})
		})
		Reset(func() {
			newToken = newTokenCopy
		})
	})
}
Exemple #2
0
import (
	"errors"

	"github.com/ma314smith/etree"
)

// Token abstracts the different assertions available for WS-Fed
type Token interface {
	Validate() error
	GetClaims() (Claims, error)
}

// newToken pareses the assertion from a wresult string and returns the
// corresponding token type
var newToken = func(wresult string, realm string) (Token, error) {
	doc := etree.NewDocument()
	err := doc.ReadFromString(wresult)
	if err != nil {
		return nil, err
	}

	assertion := doc.FindElement("//Assertion")
	if assertion == nil {
		return nil, errors.New("go-wsfed: unable to find Assertion element")
	}

	majorVersion := assertion.SelectAttrValue("MajorVersion", "")
	minorVersion := assertion.SelectAttrValue("MinorVersion", "")

	switch {
	case majorVersion == "1" && minorVersion == "1":