diff --git a/connector/saml/saml.go b/connector/saml/saml.go
index 8b55252a812837979550fc4a2414804564e96348..a24df1c81fe97b572a5d2139bc2e8756d669532e 100644
--- a/connector/saml/saml.go
+++ b/connector/saml/saml.go
@@ -130,9 +130,7 @@ func (c *Config) Open(logger logrus.FieldLogger) (connector.Connector, error) {
 	return c.openConnector(logger)
 }
 
-func (c *Config) openConnector(logger logrus.FieldLogger) (interface {
-	connector.SAMLConnector
-}, error) {
+func (c *Config) openConnector(logger logrus.FieldLogger) (*provider, error) {
 	requiredFields := []struct {
 		name, val string
 	}{
@@ -274,8 +272,11 @@ func (p *provider) HandlePOST(s connector.Scopes, samlResponse, inResponseTo str
 	if err != nil {
 		return ident, fmt.Errorf("decode response: %v", err)
 	}
+
+	rootElementSigned := true
 	if p.validator != nil {
-		if rawResp, err = verify(p.validator, rawResp); err != nil {
+		rawResp, rootElementSigned, err = verifyResponseSig(p.validator, rawResp)
+		if err != nil {
 			return ident, fmt.Errorf("verify signature: %v", err)
 		}
 	}
@@ -285,24 +286,26 @@ func (p *provider) HandlePOST(s connector.Scopes, samlResponse, inResponseTo str
 		return ident, fmt.Errorf("unmarshal response: %v", err)
 	}
 
-	if p.issuer != "" && resp.Issuer != nil && resp.Issuer.Issuer != p.issuer {
-		return ident, fmt.Errorf("expected Issuer value %s, got %s", p.issuer, resp.Issuer.Issuer)
-	}
+	if rootElementSigned {
+		if p.issuer != "" && resp.Issuer != nil && resp.Issuer.Issuer != p.issuer {
+			return ident, fmt.Errorf("expected Issuer value %s, got %s", p.issuer, resp.Issuer.Issuer)
+		}
 
-	// Verify InResponseTo value matches the expected ID associated with
-	// the RelayState.
-	if resp.InResponseTo != inResponseTo {
-		return ident, fmt.Errorf("expected InResponseTo value %s, got %s", inResponseTo, resp.InResponseTo)
-	}
+		// Verify InResponseTo value matches the expected ID associated with
+		// the RelayState.
+		if resp.InResponseTo != inResponseTo {
+			return ident, fmt.Errorf("expected InResponseTo value %s, got %s", inResponseTo, resp.InResponseTo)
+		}
 
-	// Destination is optional.
-	if resp.Destination != "" && resp.Destination != p.redirectURI {
-		return ident, fmt.Errorf("expected destination %q got %q", p.redirectURI, resp.Destination)
+		// Destination is optional.
+		if resp.Destination != "" && resp.Destination != p.redirectURI {
+			return ident, fmt.Errorf("expected destination %q got %q", p.redirectURI, resp.Destination)
 
-	}
+		}
 
-	if err = p.validateStatus(&resp); err != nil {
-		return ident, err
+		if err = p.validateStatus(&resp); err != nil {
+			return ident, err
+		}
 	}
 
 	assertion := resp.Assertion
@@ -481,41 +484,57 @@ func (p *provider) validateConditions(assertion *assertion) error {
 	return nil
 }
 
-// verify checks the signature info of a XML document and returns
-// the signed elements.
-// The Validate function of the goxmldsig library only looks for
-// signatures on the root element level. But a saml Response is valid
-// if the complete message is signed, or only the Assertion is signed,
-// or but elements are signed. Therefore we first check a possible
-// signature of the Response than of the Assertion. If one of these
-// is successful the Response is considered as valid.
-func verify(validator *dsig.ValidationContext, data []byte) (signed []byte, err error) {
+// verifyResponseSig attempts to verify the signature of a SAML response or
+// the assertion.
+//
+// If the root element is properly signed, this method returns it.
+//
+// The SAML spec requires supporting responses where the root element is
+// unverified, but the sub <Assertion> elements are signed. In these cases,
+// this method returns rootVerified=false to indicate that the <Assertion>
+// elements should be trusted, but all other elements MUST be ignored.
+//
+// Note: we still don't support multiple <Assertion> tags. If there are
+// multiple present this code will only process the first.
+func verifyResponseSig(validator *dsig.ValidationContext, data []byte) (signed []byte, rootVerified bool, err error) {
 	doc := etree.NewDocument()
 	if err = doc.ReadFromBytes(data); err != nil {
-		return nil, fmt.Errorf("parse document: %v", err)
+		return nil, false, fmt.Errorf("parse document: %v", err)
 	}
-	verified := false
+
 	response := doc.Root()
 	transformedResponse, err := validator.Validate(response)
 	if err == nil {
-		verified = true
+		// Root element is verified, return it.
 		doc.SetRoot(transformedResponse)
+		signed, err = doc.WriteToBytes()
+		return signed, true, err
 	}
+
 	// Ensures xmlns are copied down to the assertion element when they are defined in the root
+	//
+	// TODO: Only select from child elements of the root.
 	assertion, err := etreeutils.NSSelectOne(response, "urn:oasis:names:tc:SAML:2.0:assertion", "Assertion")
 	if err != nil {
-		return nil, fmt.Errorf("response does not contain an Assertion element")
+		return nil, false, fmt.Errorf("response does not contain an Assertion element")
 	}
 	transformedAssertion, err := validator.Validate(assertion)
-	if err == nil {
-		verified = true
-		response.RemoveChild(assertion)
-		response.AddChild(transformedAssertion)
+	if err != nil {
+		return nil, false, fmt.Errorf("response does not contain a valid signature element: %v", err)
 	}
-	if verified != true {
-		return nil, fmt.Errorf("response does not contain a valid Signature element")
+
+	// Verified an assertion but not the response. Can't trust any child elements,
+	// except the assertion. Remove them all.
+	for _, el := range response.ChildElements() {
+		response.RemoveChild(el)
 	}
-	return doc.WriteToBytes()
+
+	// We still return the full <Response> element, even though it's unverified
+	// because the <Assertion> element is not a valid XML document on its own.
+	// It still requires the root element to define things like namespaces.
+	response.AddChild(transformedAssertion)
+	signed, err = doc.WriteToBytes()
+	return signed, false, err
 }
 
 func uuidv4() string {
diff --git a/connector/saml/saml_test.go b/connector/saml/saml_test.go
index cba0fe12862e8d4e56fc5c4362cda00f047cf4be..bb7fa1b216f23a1dbde71cc8aa4f4c0b104daa55 100644
--- a/connector/saml/saml_test.go
+++ b/connector/saml/saml_test.go
@@ -6,24 +6,216 @@ import (
 	"encoding/pem"
 	"errors"
 	"io/ioutil"
+	"sort"
 	"strings"
 	"testing"
 	"time"
 
 	"github.com/Sirupsen/logrus"
-
+	"github.com/kylelemons/godebug/pretty"
 	dsig "github.com/russellhaering/goxmldsig"
 
 	"github.com/coreos/dex/connector"
 )
 
-const (
-	defaultIssuer      = "http://www.okta.com/exk91cb99lKkKSYoy0h7"
-	defaultRedirectURI = "http://localhost:5556/dex/callback"
+// responseTest maps a SAML 2.0 response object to a set of expected values.
+//
+// Tests are defined in the "testdata" directory and are self-signed using xmlsec1.
+//
+// To add a new test, define a new, unsigned SAML 2.0 response that exercises some
+// case, then sign it using the "testdata/gen.sh" script.
+//
+//     cp testdata/good-resp.tmpl testdata/( testname ).tmpl
+//     vim ( testname ).tmpl # Modify your template for your test case.
+//     vim testdata/gen.sh   # Add a xmlsec1 command to the generation script.
+//     ./testdata/gen.sh     # Sign your template.
+//
+// To install xmlsec1 on Fedora run:
+//
+//     sudo dnf install xmlsec1 xmlsec1-openssl
+//
+// On mac:
+//
+//     brew install Libxmlsec1
+//
+type responseTest struct {
+	// CA file and XML file of the response.
+	caFile   string
+	respFile string
 
-	// Response ID embedded in our testdata.
-	testDataResponseID = "_fd1b3ef9-ec09-44a7-a66b-0d39c250f6a0"
-)
+	// Values that should be used to validate the signature.
+	now          string
+	inResponseTo string
+	redirectURI  string
+
+	// Attribute customization.
+	usernameAttr string
+	emailAttr    string
+	groupsAttr   string
+
+	// Expected outcome of the test.
+	wantErr   bool
+	wantIdent connector.Identity
+}
+
+func TestGoodResponse(t *testing.T) {
+	test := responseTest{
+		caFile:       "testdata/ca.crt",
+		respFile:     "testdata/good-resp.xml",
+		now:          "2017-04-04T04:34:59.330Z",
+		usernameAttr: "Name",
+		emailAttr:    "email",
+		inResponseTo: "6zmm5mguyebwvajyf2sdwwcw6m",
+		redirectURI:  "http://127.0.0.1:5556/dex/callback",
+		wantIdent: connector.Identity{
+			UserID:        "eric.chiang+okta@coreos.com",
+			Username:      "Eric",
+			Email:         "eric.chiang+okta@coreos.com",
+			EmailVerified: true,
+		},
+	}
+	test.run(t)
+}
+
+func TestGroups(t *testing.T) {
+	test := responseTest{
+		caFile:       "testdata/ca.crt",
+		respFile:     "testdata/good-resp.xml",
+		now:          "2017-04-04T04:34:59.330Z",
+		usernameAttr: "Name",
+		emailAttr:    "email",
+		groupsAttr:   "groups",
+		inResponseTo: "6zmm5mguyebwvajyf2sdwwcw6m",
+		redirectURI:  "http://127.0.0.1:5556/dex/callback",
+		wantIdent: connector.Identity{
+			UserID:        "eric.chiang+okta@coreos.com",
+			Username:      "Eric",
+			Email:         "eric.chiang+okta@coreos.com",
+			EmailVerified: true,
+			Groups:        []string{"Admins", "Everyone"},
+		},
+	}
+	test.run(t)
+}
+
+// TestOkta tests against an actual response from Okta.
+func TestOkta(t *testing.T) {
+	test := responseTest{
+		caFile:       "testdata/okta-ca.pem",
+		respFile:     "testdata/okta-resp.xml",
+		now:          "2017-04-04T04:34:59.330Z",
+		usernameAttr: "Name",
+		emailAttr:    "email",
+		inResponseTo: "6zmm5mguyebwvajyf2sdwwcw6m",
+		redirectURI:  "http://127.0.0.1:5556/dex/callback",
+		wantIdent: connector.Identity{
+			UserID:        "eric.chiang+okta@coreos.com",
+			Username:      "Eric",
+			Email:         "eric.chiang+okta@coreos.com",
+			EmailVerified: true,
+		},
+	}
+	test.run(t)
+}
+
+func TestBadStatus(t *testing.T) {
+	test := responseTest{
+		caFile:       "testdata/ca.crt",
+		respFile:     "testdata/bad-status.xml",
+		now:          "2017-04-04T04:34:59.330Z",
+		usernameAttr: "Name",
+		emailAttr:    "email",
+		inResponseTo: "6zmm5mguyebwvajyf2sdwwcw6m",
+		redirectURI:  "http://127.0.0.1:5556/dex/callback",
+		wantErr:      true,
+	}
+	test.run(t)
+}
+
+func TestInvalidCA(t *testing.T) {
+	test := responseTest{
+		caFile:       "testdata/bad-ca.crt", // Not the CA that signed this response.
+		respFile:     "testdata/good-resp.xml",
+		now:          "2017-04-04T04:34:59.330Z",
+		usernameAttr: "Name",
+		emailAttr:    "email",
+		inResponseTo: "6zmm5mguyebwvajyf2sdwwcw6m",
+		redirectURI:  "http://127.0.0.1:5556/dex/callback",
+		wantErr:      true,
+	}
+	test.run(t)
+}
+
+func TestUnsignedResponse(t *testing.T) {
+	test := responseTest{
+		caFile:       "testdata/ca.crt",
+		respFile:     "testdata/good-resp.tmpl", // Use the unsigned template, not the signed document.
+		now:          "2017-04-04T04:34:59.330Z",
+		usernameAttr: "Name",
+		emailAttr:    "email",
+		inResponseTo: "6zmm5mguyebwvajyf2sdwwcw6m",
+		redirectURI:  "http://127.0.0.1:5556/dex/callback",
+		wantErr:      true,
+	}
+	test.run(t)
+}
+
+func TestExpiredAssertion(t *testing.T) {
+	test := responseTest{
+		caFile:       "testdata/ca.crt",
+		respFile:     "testdata/assertion-signed.xml",
+		now:          "2020-04-04T04:34:59.330Z", // Assertion has expired.
+		usernameAttr: "Name",
+		emailAttr:    "email",
+		inResponseTo: "6zmm5mguyebwvajyf2sdwwcw6m",
+		redirectURI:  "http://127.0.0.1:5556/dex/callback",
+		wantErr:      true,
+	}
+	test.run(t)
+}
+
+// TestAssertionSignedNotResponse ensures the connector validates SAML 2.0
+// responses where the assertion is signed but the root element, the
+// response, isn't.
+func TestAssertionSignedNotResponse(t *testing.T) {
+	test := responseTest{
+		caFile:       "testdata/ca.crt",
+		respFile:     "testdata/assertion-signed.xml",
+		now:          "2017-04-04T04:34:59.330Z",
+		usernameAttr: "Name",
+		emailAttr:    "email",
+		inResponseTo: "6zmm5mguyebwvajyf2sdwwcw6m",
+		redirectURI:  "http://127.0.0.1:5556/dex/callback",
+		wantIdent: connector.Identity{
+			UserID:        "eric.chiang+okta@coreos.com",
+			Username:      "Eric",
+			Email:         "eric.chiang+okta@coreos.com",
+			EmailVerified: true,
+		},
+	}
+	test.run(t)
+}
+
+// TestTwoAssertionFirstSigned tries to catch an edge case where an attacker
+// provides a second assertion that's not signed.
+func TestTwoAssertionFirstSigned(t *testing.T) {
+	test := responseTest{
+		caFile:       "testdata/ca.crt",
+		respFile:     "testdata/two-assertions-first-signed.xml",
+		now:          "2017-04-04T04:34:59.330Z",
+		usernameAttr: "Name",
+		emailAttr:    "email",
+		inResponseTo: "6zmm5mguyebwvajyf2sdwwcw6m",
+		redirectURI:  "http://127.0.0.1:5556/dex/callback",
+		wantIdent: connector.Identity{
+			UserID:        "eric.chiang+okta@coreos.com",
+			Username:      "Eric",
+			Email:         "eric.chiang+okta@coreos.com",
+			EmailVerified: true,
+		},
+	}
+	test.run(t)
+}
 
 func loadCert(ca string) (*x509.Certificate, error) {
 	data, err := ioutil.ReadFile(ca)
@@ -37,6 +229,63 @@ func loadCert(ca string) (*x509.Certificate, error) {
 	return x509.ParseCertificate(block.Bytes)
 }
 
+func (r responseTest) run(t *testing.T) {
+	c := Config{
+		CA:           r.caFile,
+		UsernameAttr: r.usernameAttr,
+		EmailAttr:    r.emailAttr,
+		GroupsAttr:   r.groupsAttr,
+		RedirectURI:  r.redirectURI,
+		// Never logging in, don't need this.
+		SSOURL: "http://foo.bar/",
+	}
+	now, err := time.Parse(timeFormat, r.now)
+	if err != nil {
+		t.Fatalf("parse test time: %v", err)
+	}
+
+	conn, err := c.openConnector(logrus.New())
+	if err != nil {
+		t.Fatal(err)
+	}
+	conn.now = func() time.Time { return now }
+	resp, err := ioutil.ReadFile(r.respFile)
+	if err != nil {
+		t.Fatal(err)
+	}
+	samlResp := base64.StdEncoding.EncodeToString(resp)
+
+	scopes := connector.Scopes{
+		OfflineAccess: false,
+		Groups:        true,
+	}
+	ident, err := conn.HandlePOST(scopes, samlResp, r.inResponseTo)
+	if err != nil {
+		if !r.wantErr {
+			t.Fatalf("handle response: %v", err)
+		}
+		return
+	}
+
+	if r.wantErr {
+		t.Fatalf("wanted error")
+	}
+	sort.Strings(ident.Groups)
+	sort.Strings(r.wantIdent.Groups)
+	if diff := pretty.Compare(ident, r.wantIdent); diff != "" {
+		t.Error(diff)
+	}
+}
+
+const (
+	defaultIssuer      = "http://www.okta.com/exk91cb99lKkKSYoy0h7"
+	defaultRedirectURI = "http://localhost:5556/dex/callback"
+
+	// Response ID embedded in our testdata.
+	testDataResponseID = "_fd1b3ef9-ec09-44a7-a66b-0d39c250f6a0"
+)
+
+// Depricated: Use testing framework established above.
 func runVerify(t *testing.T, ca string, resp string, shouldSucceed bool) {
 	cert, err := loadCert(ca)
 	if err != nil {
@@ -51,7 +300,7 @@ func runVerify(t *testing.T, ca string, resp string, shouldSucceed bool) {
 		t.Fatal(err)
 	}
 
-	if _, err := verify(validator, data); err != nil {
+	if _, _, err := verifyResponseSig(validator, data); err != nil {
 		if shouldSucceed {
 			t.Fatal(err)
 		}
@@ -62,6 +311,7 @@ func runVerify(t *testing.T, ca string, resp string, shouldSucceed bool) {
 	}
 }
 
+// Depricated: Use testing framework established above.
 func newProvider(issuer string, redirectURI string) *provider {
 	if issuer == "" {
 		issuer = defaultIssuer
@@ -106,28 +356,6 @@ func TestVerifyUnsignedMessageAndUnsignedAssertion(t *testing.T) {
 	runVerify(t, "testdata/idp-cert.pem", "testdata/idp-resp.xml", false)
 }
 
-func TestHandlePOST(t *testing.T) {
-	p := newProvider("", "")
-	scopes := connector.Scopes{
-		OfflineAccess: false,
-		Groups:        true,
-	}
-	data, err := ioutil.ReadFile("testdata/idp-resp.xml")
-	if err != nil {
-		t.Fatal(err)
-	}
-	ident, err := p.HandlePOST(scopes, base64.StdEncoding.EncodeToString(data), testDataResponseID)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if ident.UserID != "eric.chiang+okta@coreos.com" {
-		t.Fatalf("unexpected UserID %q", ident.UserID)
-	}
-	if ident.Username != "admin" {
-		t.Fatalf("unexpected Username: %q", ident.UserID)
-	}
-}
-
 func TestValidateStatus(t *testing.T) {
 	p := newProvider("", "")
 	var err error
diff --git a/connector/saml/testdata/assertion-signed.tmpl b/connector/saml/testdata/assertion-signed.tmpl
new file mode 100644
index 0000000000000000000000000000000000000000..239bf271502ad828ef0d887133de03436c9310e8
--- /dev/null
+++ b/connector/saml/testdata/assertion-signed.tmpl
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" Destination="http://127.0.0.1:5556/dex/callback" ID="id19906521125278359305566047" InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+  <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+  <saml2p:Status xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
+    <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
+  </saml2p:Status>
+  <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="id199065211253338521862321146" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+    <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/2000/09/xmldsig#rsa-sha1"/>
+        <Reference URI="#id199065211253338521862321146">
+          <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/2000/09/xmldsig#sha1"/> 
+          <DigestValue/> 
+        </Reference> 
+        </SignedInfo> 
+      <SignatureValue/> 
+      <KeyInfo> 
+        <X509Data/> 
+      </KeyInfo> 
+    </Signature>
+    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+    <saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">eric.chiang+okta@coreos.com</saml2:NameID>
+      <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+        <saml2:SubjectConfirmationData InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" NotOnOrAfter="2017-04-04T04:39:59.330Z" Recipient="http://127.0.0.1:5556/dex/callback"/>
+      </saml2:SubjectConfirmation>
+    </saml2:Subject>
+    <saml2:Conditions xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" NotBefore="2017-04-04T04:29:59.330Z" NotOnOrAfter="2017-04-04T04:39:59.330Z">
+      <saml2:AudienceRestriction>
+        <saml2:Audience>http://127.0.0.1:5556/dex/callback</saml2:Audience>
+      </saml2:AudienceRestriction>
+    </saml2:Conditions>
+    <saml2:AuthnStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" AuthnInstant="2017-04-04T04:34:59.330Z" SessionIndex="6zmm5mguyebwvajyf2sdwwcw6m">
+      <saml2:AuthnContext>
+        <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
+      </saml2:AuthnContext>
+    </saml2:AuthnStatement>
+    <saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">eric.chiang+okta@coreos.com</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="Name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Eric</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Everyone</saml2:AttributeValue>
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Admins</saml2:AttributeValue>
+      </saml2:Attribute>
+    </saml2:AttributeStatement>
+  </saml2:Assertion>
+</saml2p:Response>
diff --git a/connector/saml/testdata/assertion-signed.xml b/connector/saml/testdata/assertion-signed.xml
new file mode 100644
index 0000000000000000000000000000000000000000..308676d47aa030a961cf58b1d1599059fc7af420
--- /dev/null
+++ b/connector/saml/testdata/assertion-signed.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" Destination="http://127.0.0.1:5556/dex/callback" ID="id19906521125278359305566047" InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+  <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+  <saml2p:Status xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
+    <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
+  </saml2p:Status>
+  <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="id199065211253338521862321146" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+    <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/2000/09/xmldsig#rsa-sha1"/>
+        <Reference URI="#id199065211253338521862321146">
+          <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/2000/09/xmldsig#sha1"/> 
+          <DigestValue>kDdpmKMPp7zjUeMTuntXJFpT6cs=</DigestValue> 
+        </Reference> 
+        </SignedInfo> 
+      <SignatureValue>Q12w9zPo9Bqn3W2OT7lbFbhfIDQrp7SXd/+9ZWpY4mv3ApgaOcNX2VtpSE0EjorU
+1NyrktVOkCYueJm/HVQF7gyF85KRlPBDLBZOwxbnnmrRFoCk+U2kjIt8k8eZ7NsD
+jLFGFgEveS359uvaHZR1Exbr0PBYwS7aXR3fpmjMjZ9T8f8Oe3Nt/9nWPgz/dFhb
+Aa+AniWuupfq2v6YMLZ+9GLiO0sOr8UVkW8AYOm2Bin30epikXT1Axi/VxWz/fjP
+nMUkgusFnhkgmIf/YncAv4S9GY6DcaV2iEj6cL70S7pcgaeRFi3iozigl+9a+lFo
+dt3Jy8Jq/N3OAyDP2DxLEw==</SignatureValue> 
+      <KeyInfo> 
+        <X509Data>
+<X509Certificate>MIIDGTCCAgGgAwIBAgIJAKLbLcQajEf8MA0GCSqGSIb3DQEBCwUAMCMxDDAKBgNV
+BAoMA0RFWDETMBEGA1UEAwwKY29yZW9zLmNvbTAeFw0xNzA0MDQwNzAwNTNaFw0z
+NzAzMzAwNzAwNTNaMCMxDDAKBgNVBAoMA0RFWDETMBEGA1UEAwwKY29yZW9zLmNv
+bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKH3dKWbRqCIZD2m3aHI
+4lfBT+u/4DECde74Ggq9WugdTucVQzDZUTaI7wzn17JM9hdPmXvaSRG9BaB1H3uO
+ZCs/fmdhBERRhPvuEVfAZaFfQfR7vn7WvUzT7zwMLLB8+EHzL3fOSGM2QnCOMeUD
+AB27Pb0fuBW43NXaTD9rwfFCHvo1UP+TBJIPnV65HMeMGIrtGLt7MZTPuPm3LnYA
+faXLf2vWSzL5nAgnJvUgceZXmyuciBfXpt8c1jIsj4y3tBoRTRqaxuaW1Eo7WMKF
+a7s6KvTBKErPKuzAoIcVB4ir6jm1ticAgB72SScKtPJJdEPemTXRNNzkiw7VbpY9
+QacCAwEAAaNQME4wHQYDVR0OBBYEFNHyGYyY2+eZ1l7ZLPZsnc3GOtj/MB8GA1Ud
+IwQYMBaAFNHyGYyY2+eZ1l7ZLPZsnc3GOtj/MAwGA1UdEwQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAHVXB5QmZfki9QpKzoiBNfpQ/mo6XWhExLGBTJXEWJT3P7JP
+oR4Z0+85bp0fUK338s+WjyqTn0U55Jtp0B65Qxy6ythkZat/6NPp/S7gto2De6pS
+hSGygokQioVQnoYQeK0MXl2QbtrWwNiM4HC+9yohbUfjwv8yI7opwn/rjB6X/4De
+oX2YzwTBJgoIXF7zMKYFF0DrKQjbTQr/a7kfNjq4930o7VhFph9Qpdv0EWM3svTd
+esSffLKbWcabtyMtCr5QyEwZiozd567oWFWZYeHQyEtd+w6tAFmz9ZslipdQEa/j
+1xUtrScuXt19sUfOgjUvA+VUNeMLDdpHUKHNW/Q=</X509Certificate>
+</X509Data> 
+      </KeyInfo> 
+    </Signature>
+    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+    <saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">eric.chiang+okta@coreos.com</saml2:NameID>
+      <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+        <saml2:SubjectConfirmationData InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" NotOnOrAfter="2017-04-04T04:39:59.330Z" Recipient="http://127.0.0.1:5556/dex/callback"/>
+      </saml2:SubjectConfirmation>
+    </saml2:Subject>
+    <saml2:Conditions xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" NotBefore="2017-04-04T04:29:59.330Z" NotOnOrAfter="2017-04-04T04:39:59.330Z">
+      <saml2:AudienceRestriction>
+        <saml2:Audience>http://127.0.0.1:5556/dex/callback</saml2:Audience>
+      </saml2:AudienceRestriction>
+    </saml2:Conditions>
+    <saml2:AuthnStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" AuthnInstant="2017-04-04T04:34:59.330Z" SessionIndex="6zmm5mguyebwvajyf2sdwwcw6m">
+      <saml2:AuthnContext>
+        <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
+      </saml2:AuthnContext>
+    </saml2:AuthnStatement>
+    <saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">eric.chiang+okta@coreos.com</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="Name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Eric</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Everyone</saml2:AttributeValue>
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Admins</saml2:AttributeValue>
+      </saml2:Attribute>
+    </saml2:AttributeStatement>
+  </saml2:Assertion>
+</saml2p:Response>
diff --git a/connector/saml/testdata/bad-ca.crt b/connector/saml/testdata/bad-ca.crt
new file mode 100644
index 0000000000000000000000000000000000000000..e78434947a36cd96ba38c185c6bdc6462488eeba
--- /dev/null
+++ b/connector/saml/testdata/bad-ca.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDGTCCAgGgAwIBAgIJAINei+KBx541MA0GCSqGSIb3DQEBCwUAMCMxDDAKBgNV
+BAoMA0JBRDETMBEGA1UEAwwKY29yZW9zLmNvbTAeFw0xNzA0MDQwNzAwNTNaFw0z
+NzAzMzAwNzAwNTNaMCMxDDAKBgNVBAoMA0JBRDETMBEGA1UEAwwKY29yZW9zLmNv
+bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKfSVQCQMJhwdeesQqZo
+YHktgGjKA//p176kWoqVEX8+cVgKc1IEAzN73L0KsBcNkaItbZycQxkku8NGUYvt
+inEK8V61vjK3IQBOV2+qKOeWvHPXd280I2JSGy768ELpZcaEmnA0CVbMaLdHLFQ/
+tcRocDcMKDhNexlsJ/cDPwzSkky6FU6UnaSih+I432UeJs/hRvAs1YJ3+G6uSVQ7
+xo2Fk2i+qd3IvRWOBagwEhEFcd/MfAu4+w+UYW4W1BC9zJoO2ETBgUVJzaiUGZ5z
+rX/KNAX/+kAQWQLKW1sVgRKOI2yfyIVaUzF6V2uxwHrbeV75Pr3ClVdvuUWRcXKH
+Wn8CAwEAAaNQME4wHQYDVR0OBBYEFLw+L3SLMIR2wfd7IQG1m3rlgGP7MB8GA1Ud
+IwQYMBaAFLw+L3SLMIR2wfd7IQG1m3rlgGP7MAwGA1UdEwQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBABH2mDQuf+JqjHtBCp9coi1WuX5xJuoSKyOAvlz7QJk0bb+W
+oONg+ETQ7jT7KheiFQorghdulZerv+L1dmLU5ut/Zbf1zoaWLslOgVPpOy6LP0aS
+uaa31jm7Qpig47+kTZEpPN6vUPpmAD70/uo3NgRNj8pztkWr08fEIbX/3ukHvFUE
+XPxYxgF5tFj8EY6cdflzlC/0TYmJiHt/viv/yQfrvMBRvsVHfjfzNRxbNwfEdKuf
+YIs5KeP2al7APsmF5d/UFGzoQGXaKEOpCRJ+Oj3spooLhhzWqV4gPZLVgU0DD6ja
+GPb2XgLA9mdEmMukHU0RMeb8R+r8RvytWKvuJQE=
+-----END CERTIFICATE-----
diff --git a/connector/saml/testdata/bad-ca.key b/connector/saml/testdata/bad-ca.key
new file mode 100644
index 0000000000000000000000000000000000000000..e8282053239b058c7b11b656a951bcdba3c3e96d
--- /dev/null
+++ b/connector/saml/testdata/bad-ca.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCn0lUAkDCYcHXn
+rEKmaGB5LYBoygP/6de+pFqKlRF/PnFYCnNSBAMze9y9CrAXDZGiLW2cnEMZJLvD
+RlGL7YpxCvFetb4ytyEATldvqijnlrxz13dvNCNiUhsu+vBC6WXGhJpwNAlWzGi3
+RyxUP7XEaHA3DCg4TXsZbCf3Az8M0pJMuhVOlJ2koofiON9lHibP4UbwLNWCd/hu
+rklUO8aNhZNovqndyL0VjgWoMBIRBXHfzHwLuPsPlGFuFtQQvcyaDthEwYFFSc2o
+lBmec61/yjQF//pAEFkCyltbFYESjiNsn8iFWlMxeldrscB623le+T69wpVXb7lF
+kXFyh1p/AgMBAAECggEAHh/PSk6XqoVlZLSzMhPCXX4hcq3wkdtz8rCl4AJqJaEb
+z2Xw1WQK/w7YzMZCXaD951KoPlh+YuEJI0BYGvoEw83nDc0p2wisT9XANDcjKI8S
+POkMc1W0lE2Qu5onzpr+vefHoSR2GLKQiXWpK2ZURnFI01jHT3P5CNM1SU2336ES
+XT1GXlxTz59BS04bySS3s8PQZTtmFvQAjtjOWkg+nzTYgEO7xU5968Px+jdlO+xf
+ZKtjlRKRNRmVlylUvCmIT6kIzIdyjuBqw4yx0bM1Av9QwpPuDkRWBeiT8o5xeY+L
+yOSxUCg24CGgAl6mGVXWh+BC9Z3h8dXg9eMervT9gQKBgQDS6QffOBr+j19FiQwH
+t+5h2klOR/mu8TX6oW8Dc6o5YsnLt0uQqa2jLq8kYRkOBVg68mMFvZXmhPoKv4hk
+rOfDKjVfPz9ShrvuY301BAp/hdi/hNP+MAt683UlcnpwLOaASZMr+MjdnVVzfF6X
+iNlV2RE3pAxSFkVlMPJJTmPPEQKBgQDLsxbYFj4JBKhMehdcsqjUtDuzLBPqisVa
+cWKACxPAXIjztsEXF4F7sQk7q68uzLU80uPBVAJjf6lWwK9tcUdcBFHCXdqj8ZXB
+77W4gZSkqHY0T6DJF+NZRF+z4cOg3qtDjTvqhetl5yyiY9IPyiSckNAz40pWD/0X
+U/0nObuwjwKBgQCpWpUHmHWUkmtd2n3edMLlr/HM+d5zqxw89APAMdAt5DVFbxku
+QBE9Ru87tvv3VjNSoe8BXQpQ39Yna0SKEozHGc1hfdfK3IVrFlgjieskGsXAg1f2
+c33EbFlUiGfoSyWLPYj/dfVUflFvOh56b1iUpog8tW1vPJLcfkEOu/NJAQKBgQCu
+LAp7Z8FRarcQ9VAmhekQPq/RSv4YjOGkrNChVVdlInpDkV9XBFVF0yFm8SzQYl8R
+i+0McG2+b/j2YbleZf6zMkpKXH/HsJjxg6qpAbt8c0LnBbMgXxmZSXpfT8o7MknU
+b93scOfPcTRcAegqchiN+tDbnRwBrJgmqz0JnjbbBwKBgCXOWMgS8Azvvw+lUqua
+yLdcAilAaqchgVBkI5ATZQodopEP+Gvevvzh6G8uQJp9fGrL/fR/tNg2viwCF/X8
+ROATx1z98/ItA3kyYhiNt/A6EqOb8SVOMq/eeMpvk+RB6gA9YdMf5H9XClW4vxLy
+jaw+YQ6hOyMTmFfUI2/FumFE
+-----END PRIVATE KEY-----
diff --git a/connector/saml/testdata/bad-status.tmpl b/connector/saml/testdata/bad-status.tmpl
new file mode 100644
index 0000000000000000000000000000000000000000..093ae9481bcc6178f6a0c4059e63658734e8fbb7
--- /dev/null
+++ b/connector/saml/testdata/bad-status.tmpl
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" Destination="http://127.0.0.1:5556/dex/callback" ID="id19906521125278359305566047" InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+  <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/2000/09/xmldsig#rsa-sha1"/>
+      <Reference>
+        <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/2000/09/xmldsig#sha1"/> 
+        <DigestValue/> 
+      </Reference> 
+      </SignedInfo> 
+    <SignatureValue/> 
+    <KeyInfo> 
+      <X509Data/> 
+    </KeyInfo> 
+  </Signature>
+  <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+  <saml2p:Status xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
+
+    <!-- Status code indicates an error. Ensure this fails to authenticate a user -->
+
+    <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:AuthnFailed"/>
+  </saml2p:Status>
+  <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="id199065211253338521862321146" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+    <saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">eric.chiang+okta@coreos.com</saml2:NameID>
+      <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+        <saml2:SubjectConfirmationData InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" NotOnOrAfter="2017-04-04T04:39:59.330Z" Recipient="http://127.0.0.1:5556/dex/callback"/>
+      </saml2:SubjectConfirmation>
+    </saml2:Subject>
+    <saml2:Conditions xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" NotBefore="2017-04-04T04:29:59.330Z" NotOnOrAfter="2017-04-04T04:39:59.330Z">
+      <saml2:AudienceRestriction>
+        <saml2:Audience>http://127.0.0.1:5556/dex/callback</saml2:Audience>
+      </saml2:AudienceRestriction>
+    </saml2:Conditions>
+    <saml2:AuthnStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" AuthnInstant="2017-04-04T04:34:59.330Z" SessionIndex="6zmm5mguyebwvajyf2sdwwcw6m">
+      <saml2:AuthnContext>
+        <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
+      </saml2:AuthnContext>
+    </saml2:AuthnStatement>
+    <saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">eric.chiang+okta@coreos.com</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="Name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Eric</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Everyone</saml2:AttributeValue>
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Admins</saml2:AttributeValue>
+      </saml2:Attribute>
+    </saml2:AttributeStatement>
+  </saml2:Assertion>
+</saml2p:Response>
diff --git a/connector/saml/testdata/bad-status.xml b/connector/saml/testdata/bad-status.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7de16ed5c3e9c60b0044e89d4782bbe4ea818986
--- /dev/null
+++ b/connector/saml/testdata/bad-status.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" Destination="http://127.0.0.1:5556/dex/callback" ID="id19906521125278359305566047" InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+  <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/2000/09/xmldsig#rsa-sha1"/>
+      <Reference>
+        <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/2000/09/xmldsig#sha1"/> 
+        <DigestValue>96Mymeqjk6Mm0azcGKf6nD6SFWY=</DigestValue> 
+      </Reference> 
+      </SignedInfo> 
+    <SignatureValue>AbzrvvisCPqcZ0OnkYNaFeuC8wIkivlIL479c3HJmFJycXLxm6LzS7wILw47huzP
+/8r2FnZ3MT/qJdibz53zNFXBADu2af/lSx9bkuxZpYN5J91cgCjUt68xF8Xvo4d8
+jqOKq3H3C7DqU52QyF+XoPKHaBWUcefJoeLQEwUm9C+U6mSP5AZ82m1DoqyhOuWk
+UYTjVUjVro+J1x9Bp/dyZ8OczaN+S9vIYm6AbsV5klYPQug951da5KJ/K8fvure9
+OIHaLnEb4BtQb7qDA8+3jPU7c88XvP+27FtSqiWM0vGGSc9pq4kS5hHmsrdbIkyl
+Ajr+mNXxlNnXRQNEsqE+Gw==</SignatureValue> 
+    <KeyInfo> 
+      <X509Data>
+<X509Certificate>MIIDGTCCAgGgAwIBAgIJAKLbLcQajEf8MA0GCSqGSIb3DQEBCwUAMCMxDDAKBgNV
+BAoMA0RFWDETMBEGA1UEAwwKY29yZW9zLmNvbTAeFw0xNzA0MDQwNzAwNTNaFw0z
+NzAzMzAwNzAwNTNaMCMxDDAKBgNVBAoMA0RFWDETMBEGA1UEAwwKY29yZW9zLmNv
+bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKH3dKWbRqCIZD2m3aHI
+4lfBT+u/4DECde74Ggq9WugdTucVQzDZUTaI7wzn17JM9hdPmXvaSRG9BaB1H3uO
+ZCs/fmdhBERRhPvuEVfAZaFfQfR7vn7WvUzT7zwMLLB8+EHzL3fOSGM2QnCOMeUD
+AB27Pb0fuBW43NXaTD9rwfFCHvo1UP+TBJIPnV65HMeMGIrtGLt7MZTPuPm3LnYA
+faXLf2vWSzL5nAgnJvUgceZXmyuciBfXpt8c1jIsj4y3tBoRTRqaxuaW1Eo7WMKF
+a7s6KvTBKErPKuzAoIcVB4ir6jm1ticAgB72SScKtPJJdEPemTXRNNzkiw7VbpY9
+QacCAwEAAaNQME4wHQYDVR0OBBYEFNHyGYyY2+eZ1l7ZLPZsnc3GOtj/MB8GA1Ud
+IwQYMBaAFNHyGYyY2+eZ1l7ZLPZsnc3GOtj/MAwGA1UdEwQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAHVXB5QmZfki9QpKzoiBNfpQ/mo6XWhExLGBTJXEWJT3P7JP
+oR4Z0+85bp0fUK338s+WjyqTn0U55Jtp0B65Qxy6ythkZat/6NPp/S7gto2De6pS
+hSGygokQioVQnoYQeK0MXl2QbtrWwNiM4HC+9yohbUfjwv8yI7opwn/rjB6X/4De
+oX2YzwTBJgoIXF7zMKYFF0DrKQjbTQr/a7kfNjq4930o7VhFph9Qpdv0EWM3svTd
+esSffLKbWcabtyMtCr5QyEwZiozd567oWFWZYeHQyEtd+w6tAFmz9ZslipdQEa/j
+1xUtrScuXt19sUfOgjUvA+VUNeMLDdpHUKHNW/Q=</X509Certificate>
+</X509Data> 
+    </KeyInfo> 
+  </Signature>
+  <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+  <saml2p:Status xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
+
+    <!-- Status code indicates an error. Ensure this fails to authenticate a user -->
+
+    <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:AuthnFailed"/>
+  </saml2p:Status>
+  <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="id199065211253338521862321146" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+    <saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">eric.chiang+okta@coreos.com</saml2:NameID>
+      <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+        <saml2:SubjectConfirmationData InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" NotOnOrAfter="2017-04-04T04:39:59.330Z" Recipient="http://127.0.0.1:5556/dex/callback"/>
+      </saml2:SubjectConfirmation>
+    </saml2:Subject>
+    <saml2:Conditions xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" NotBefore="2017-04-04T04:29:59.330Z" NotOnOrAfter="2017-04-04T04:39:59.330Z">
+      <saml2:AudienceRestriction>
+        <saml2:Audience>http://127.0.0.1:5556/dex/callback</saml2:Audience>
+      </saml2:AudienceRestriction>
+    </saml2:Conditions>
+    <saml2:AuthnStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" AuthnInstant="2017-04-04T04:34:59.330Z" SessionIndex="6zmm5mguyebwvajyf2sdwwcw6m">
+      <saml2:AuthnContext>
+        <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
+      </saml2:AuthnContext>
+    </saml2:AuthnStatement>
+    <saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">eric.chiang+okta@coreos.com</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="Name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Eric</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Everyone</saml2:AttributeValue>
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Admins</saml2:AttributeValue>
+      </saml2:Attribute>
+    </saml2:AttributeStatement>
+  </saml2:Assertion>
+</saml2p:Response>
diff --git a/connector/saml/testdata/ca.crt b/connector/saml/testdata/ca.crt
new file mode 100644
index 0000000000000000000000000000000000000000..00f1cf04b9feecf1fe2d69194f0037d22e469917
--- /dev/null
+++ b/connector/saml/testdata/ca.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDGTCCAgGgAwIBAgIJAKLbLcQajEf8MA0GCSqGSIb3DQEBCwUAMCMxDDAKBgNV
+BAoMA0RFWDETMBEGA1UEAwwKY29yZW9zLmNvbTAeFw0xNzA0MDQwNzAwNTNaFw0z
+NzAzMzAwNzAwNTNaMCMxDDAKBgNVBAoMA0RFWDETMBEGA1UEAwwKY29yZW9zLmNv
+bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKH3dKWbRqCIZD2m3aHI
+4lfBT+u/4DECde74Ggq9WugdTucVQzDZUTaI7wzn17JM9hdPmXvaSRG9BaB1H3uO
+ZCs/fmdhBERRhPvuEVfAZaFfQfR7vn7WvUzT7zwMLLB8+EHzL3fOSGM2QnCOMeUD
+AB27Pb0fuBW43NXaTD9rwfFCHvo1UP+TBJIPnV65HMeMGIrtGLt7MZTPuPm3LnYA
+faXLf2vWSzL5nAgnJvUgceZXmyuciBfXpt8c1jIsj4y3tBoRTRqaxuaW1Eo7WMKF
+a7s6KvTBKErPKuzAoIcVB4ir6jm1ticAgB72SScKtPJJdEPemTXRNNzkiw7VbpY9
+QacCAwEAAaNQME4wHQYDVR0OBBYEFNHyGYyY2+eZ1l7ZLPZsnc3GOtj/MB8GA1Ud
+IwQYMBaAFNHyGYyY2+eZ1l7ZLPZsnc3GOtj/MAwGA1UdEwQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAHVXB5QmZfki9QpKzoiBNfpQ/mo6XWhExLGBTJXEWJT3P7JP
+oR4Z0+85bp0fUK338s+WjyqTn0U55Jtp0B65Qxy6ythkZat/6NPp/S7gto2De6pS
+hSGygokQioVQnoYQeK0MXl2QbtrWwNiM4HC+9yohbUfjwv8yI7opwn/rjB6X/4De
+oX2YzwTBJgoIXF7zMKYFF0DrKQjbTQr/a7kfNjq4930o7VhFph9Qpdv0EWM3svTd
+esSffLKbWcabtyMtCr5QyEwZiozd567oWFWZYeHQyEtd+w6tAFmz9ZslipdQEa/j
+1xUtrScuXt19sUfOgjUvA+VUNeMLDdpHUKHNW/Q=
+-----END CERTIFICATE-----
diff --git a/connector/saml/testdata/ca.key b/connector/saml/testdata/ca.key
new file mode 100644
index 0000000000000000000000000000000000000000..05a43130e50ff3d3c172cc3c44bf64e23bd14aa9
--- /dev/null
+++ b/connector/saml/testdata/ca.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCh93Slm0agiGQ9
+pt2hyOJXwU/rv+AxAnXu+BoKvVroHU7nFUMw2VE2iO8M59eyTPYXT5l72kkRvQWg
+dR97jmQrP35nYQREUYT77hFXwGWhX0H0e75+1r1M0+88DCywfPhB8y93zkhjNkJw
+jjHlAwAduz29H7gVuNzV2kw/a8HxQh76NVD/kwSSD51euRzHjBiK7Ri7ezGUz7j5
+ty52AH2ly39r1ksy+ZwIJyb1IHHmV5srnIgX16bfHNYyLI+Mt7QaEU0amsbmltRK
+O1jChWu7Oir0wShKzyrswKCHFQeIq+o5tbYnAIAe9kknCrTySXRD3pk10TTc5IsO
+1W6WPUGnAgMBAAECggEBAJUJUDPHIwE7IAo/Drf9UpFvl2wWPmS6n+yKLeRuA0WN
+Gnq27QH5Jqro7BdTCv7NpLEklNYLsar55UCWJacbCn9lSJo2Aqge3yC3GwxFRP9t
+2RHwAAVU8hHM/tmhVkn8ZLDC5o32qlNorVBG+BCEZ0n0bsYlds2+Mq8x1XGSZX7q
+Yyjt02q2VCEDPVUGqR2ONEE98Bv++mUfXzZjGohBPre67PuvEppEwo/uf4ILuyYB
+lusSYcmPD2IBE/7FcRPefb2uDP9c6Tjo8PHXpK5hDBCtLz8lXheYMuTp9GqJmcOk
+kw8af2jNkMUEpFho0RqnrJNQ3A7M5PXQiWxwYSL/2RkCgYEAz4Kg0qm4Oe5jl+4r
+R986nElujo9g9Ad2sy9yT6fqceWoMKf68wh6bMx7HWXRqASS7bJ8wmS9EwgaWLBO
+mjqZax99F1UiFk3+5lNEaYB1OlFaWRsZSapoX6b2JyfEbODqSgKVIaYVTYBHLip3
+3ab/EKNUrNbW9bLSXgbt3aT2kU0CgYEAx9BiErhZqkgmip+4omCWuTr6Lj/awftB
+CVTfwLBYkh7SZcRAWc2bx7a1Bs1rvlczhGYsOlrZXnQRSM4fuUxUb+N5TCzZI9V/
+Prc2r2Lps3AB5CDPLZoyv0efBjSLqAA1tYKTvAHREi9Wfe5PNdfKiwrz6KmIwV3c
++s2YSWcU5MMCgYEArmzvIiTnZkqsDJl2aAOMELLo64w5wuZDMHtBaxOKThLtPXj1
+yDPoNGvtUNi1UrYFiyftFrn29HhrLQGGEL4RF6pwS5yT+ou1J4X2i3gfEdYwS5Yr
+u3AyK7T8VA1pXtvwFCX3lUE1xt989aFdAEPPQv0HwAEWz5Bwo/jPGPABEkECgYBy
+vDWUikbygHuhHhXnJ49kzXjbFc+Hk77EnPferWQug4RM62QILQhGpaNNRKeZpHjw
+jbrXx1MJ6ZwDMlkFDc9ucDA2jYoiCXYHjSzZiPKpFqf/VtegV+rL61RlO8b1sSkm
+ENTEIEbtKkGADldtk3u6W4+zCaZ9YmiBm4zWmVpmAQKBgHvNRcbITib+sbQE+cJM
+4TtrAHFTLWtGCd+n6rKrE8gjt7ypbBOMlOau60LZ2Pbt3DrqOLtDoOalvZhYraOb
+rkoPbDAVaXAmUJ8tw2M07PPLpJuruLSFw16VrBaDiyubO8H/hvnuF4kKpRvt8ty0
+DBogMo9McFczyisRKebmANLw
+-----END PRIVATE KEY-----
diff --git a/connector/saml/testdata/gen.sh b/connector/saml/testdata/gen.sh
new file mode 100755
index 0000000000000000000000000000000000000000..dec6b158b0824046f9ff13c27caa398350bd81c6
--- /dev/null
+++ b/connector/saml/testdata/gen.sh
@@ -0,0 +1,47 @@
+#!/bin/bash -ex
+
+# Always run from the testdata directory
+cd "$(dirname "$0")"
+
+# Uncomment these commands to regenerate the CA files.
+#
+# openssl req \
+#     -nodes \
+#     -newkey rsa:2048 \
+#     -keyout ca.key \
+#     -new -x509 -days 7300 \
+#     -extensions v3_ca \
+#     -out ca.crt \
+#     -subj "/O=DEX/CN=coreos.com"
+# 
+# openssl req \
+#     -nodes \
+#     -newkey rsa:2048 \
+#     -keyout bad-ca.key \
+#     -new -x509 -days 7300 \
+#     -extensions v3_ca \
+#     -out bad-ca.crt \
+#     -subj "/O=BAD/CN=coreos.com"
+
+# Sign these files using xmlsec1.
+#
+# Templates MUST have a <Signature> element already embedded in them so
+# xmlsec1 can know where to embed the signature.
+#
+# See: https://sgros.blogspot.com/2013/01/signing-xml-document-using-xmlsec1.html
+
+xmlsec1 --sign --privkey-pem ca.key,ca.crt --output good-resp.xml good-resp.tmpl
+xmlsec1 --sign --privkey-pem ca.key,ca.crt --output bad-status.xml bad-status.tmpl
+
+# Sign a specific sub element, not just the root.
+#
+# Values match up to the <Response URI="#(ID)"> element in the documents.
+xmlsec1 --sign --privkey-pem ca.key,ca.crt  \
+    --id-attr:ID Assertion \
+    --output assertion-signed.xml assertion-signed.tmpl
+
+xmlsec1 --sign --privkey-pem ca.key,ca.crt \
+    --id-attr:ID Assertion \
+    --output two-assertions-first-signed.xml \
+    two-assertions-first-signed.tmpl
+
diff --git a/connector/saml/testdata/good-resp.tmpl b/connector/saml/testdata/good-resp.tmpl
new file mode 100644
index 0000000000000000000000000000000000000000..b3c3c55eb1c5372236552bba3381c0b740f655d8
--- /dev/null
+++ b/connector/saml/testdata/good-resp.tmpl
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" Destination="http://127.0.0.1:5556/dex/callback" ID="id19906521125278359305566047" InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+  <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/2000/09/xmldsig#rsa-sha1"/>
+      <Reference>
+        <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/2000/09/xmldsig#sha1"/> 
+        <DigestValue/> 
+      </Reference> 
+      </SignedInfo> 
+    <SignatureValue/> 
+    <KeyInfo> 
+      <X509Data/> 
+    </KeyInfo> 
+  </Signature>
+  <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+  <saml2p:Status xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
+    <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
+  </saml2p:Status>
+  <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="id199065211253338521862321146" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+    <saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">eric.chiang+okta@coreos.com</saml2:NameID>
+      <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+        <saml2:SubjectConfirmationData InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" NotOnOrAfter="2017-04-04T04:39:59.330Z" Recipient="http://127.0.0.1:5556/dex/callback"/>
+      </saml2:SubjectConfirmation>
+    </saml2:Subject>
+    <saml2:Conditions xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" NotBefore="2017-04-04T04:29:59.330Z" NotOnOrAfter="2017-04-04T04:39:59.330Z">
+      <saml2:AudienceRestriction>
+        <saml2:Audience>http://127.0.0.1:5556/dex/callback</saml2:Audience>
+      </saml2:AudienceRestriction>
+    </saml2:Conditions>
+    <saml2:AuthnStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" AuthnInstant="2017-04-04T04:34:59.330Z" SessionIndex="6zmm5mguyebwvajyf2sdwwcw6m">
+      <saml2:AuthnContext>
+        <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
+      </saml2:AuthnContext>
+    </saml2:AuthnStatement>
+    <saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">eric.chiang+okta@coreos.com</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="Name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Eric</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Everyone</saml2:AttributeValue>
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Admins</saml2:AttributeValue>
+      </saml2:Attribute>
+    </saml2:AttributeStatement>
+  </saml2:Assertion>
+</saml2p:Response>
diff --git a/connector/saml/testdata/good-resp.xml b/connector/saml/testdata/good-resp.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3e9b34169c42329b24b484696e900c048b085755
--- /dev/null
+++ b/connector/saml/testdata/good-resp.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" Destination="http://127.0.0.1:5556/dex/callback" ID="id19906521125278359305566047" InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+  <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/2000/09/xmldsig#rsa-sha1"/>
+      <Reference>
+        <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/2000/09/xmldsig#sha1"/> 
+        <DigestValue>ew38E1LGMwYT+0gUZNq0RacD3GM=</DigestValue> 
+      </Reference> 
+      </SignedInfo> 
+    <SignatureValue>TQ84pCaZAyEDBGkNafTMfwPUWujFvmdoXzyYMXZURIlKhA8Pv1bIZfzQ5MgbQr1W
+z2Ye99/hss24Y4ueNT9nS+53LvDekhNctFGYfgdMjrbxs8Awo3KnbvveDib5zGvk
+fWd/0/QLvlbFd/3670QGb5JQE1nD9mlAqPonyQgoufk63gEM84+tU71cAM7XKiy6
+09MC0y4s967qRAiLAtfgKbvi+46HkF/g+WsS74Wa8cu/A863URt56W0cogRjHWpQ
+B+q8/FyVeJRE0NlrOjhnsgTU2QJtvkxYYvqIpRDbMv53NLKeAFvRhOcyJxhFXtSj
+LF/oPMjbmHji4ylFiAlQWw==</SignatureValue> 
+    <KeyInfo> 
+      <X509Data>
+<X509Certificate>MIIDGTCCAgGgAwIBAgIJAKLbLcQajEf8MA0GCSqGSIb3DQEBCwUAMCMxDDAKBgNV
+BAoMA0RFWDETMBEGA1UEAwwKY29yZW9zLmNvbTAeFw0xNzA0MDQwNzAwNTNaFw0z
+NzAzMzAwNzAwNTNaMCMxDDAKBgNVBAoMA0RFWDETMBEGA1UEAwwKY29yZW9zLmNv
+bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKH3dKWbRqCIZD2m3aHI
+4lfBT+u/4DECde74Ggq9WugdTucVQzDZUTaI7wzn17JM9hdPmXvaSRG9BaB1H3uO
+ZCs/fmdhBERRhPvuEVfAZaFfQfR7vn7WvUzT7zwMLLB8+EHzL3fOSGM2QnCOMeUD
+AB27Pb0fuBW43NXaTD9rwfFCHvo1UP+TBJIPnV65HMeMGIrtGLt7MZTPuPm3LnYA
+faXLf2vWSzL5nAgnJvUgceZXmyuciBfXpt8c1jIsj4y3tBoRTRqaxuaW1Eo7WMKF
+a7s6KvTBKErPKuzAoIcVB4ir6jm1ticAgB72SScKtPJJdEPemTXRNNzkiw7VbpY9
+QacCAwEAAaNQME4wHQYDVR0OBBYEFNHyGYyY2+eZ1l7ZLPZsnc3GOtj/MB8GA1Ud
+IwQYMBaAFNHyGYyY2+eZ1l7ZLPZsnc3GOtj/MAwGA1UdEwQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAHVXB5QmZfki9QpKzoiBNfpQ/mo6XWhExLGBTJXEWJT3P7JP
+oR4Z0+85bp0fUK338s+WjyqTn0U55Jtp0B65Qxy6ythkZat/6NPp/S7gto2De6pS
+hSGygokQioVQnoYQeK0MXl2QbtrWwNiM4HC+9yohbUfjwv8yI7opwn/rjB6X/4De
+oX2YzwTBJgoIXF7zMKYFF0DrKQjbTQr/a7kfNjq4930o7VhFph9Qpdv0EWM3svTd
+esSffLKbWcabtyMtCr5QyEwZiozd567oWFWZYeHQyEtd+w6tAFmz9ZslipdQEa/j
+1xUtrScuXt19sUfOgjUvA+VUNeMLDdpHUKHNW/Q=</X509Certificate>
+</X509Data> 
+    </KeyInfo> 
+  </Signature>
+  <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+  <saml2p:Status xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
+    <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
+  </saml2p:Status>
+  <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="id199065211253338521862321146" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+    <saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">eric.chiang+okta@coreos.com</saml2:NameID>
+      <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+        <saml2:SubjectConfirmationData InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" NotOnOrAfter="2017-04-04T04:39:59.330Z" Recipient="http://127.0.0.1:5556/dex/callback"/>
+      </saml2:SubjectConfirmation>
+    </saml2:Subject>
+    <saml2:Conditions xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" NotBefore="2017-04-04T04:29:59.330Z" NotOnOrAfter="2017-04-04T04:39:59.330Z">
+      <saml2:AudienceRestriction>
+        <saml2:Audience>http://127.0.0.1:5556/dex/callback</saml2:Audience>
+      </saml2:AudienceRestriction>
+    </saml2:Conditions>
+    <saml2:AuthnStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" AuthnInstant="2017-04-04T04:34:59.330Z" SessionIndex="6zmm5mguyebwvajyf2sdwwcw6m">
+      <saml2:AuthnContext>
+        <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
+      </saml2:AuthnContext>
+    </saml2:AuthnStatement>
+    <saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">eric.chiang+okta@coreos.com</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="Name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Eric</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Everyone</saml2:AttributeValue>
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Admins</saml2:AttributeValue>
+      </saml2:Attribute>
+    </saml2:AttributeStatement>
+  </saml2:Assertion>
+</saml2p:Response>
diff --git a/connector/saml/testdata/idp-resp-signed-assertion0.xml b/connector/saml/testdata/idp-resp-signed-assertion0.xml
new file mode 100644
index 0000000000000000000000000000000000000000..01feb1ca47d1a4a38accefb6970e5a1ee6db400b
--- /dev/null
+++ b/connector/saml/testdata/idp-resp-signed-assertion0.xml
@@ -0,0 +1,57 @@
+<Response xmlns="urn:oasis:names:tc:SAML:2.0:protocol" Destination="http://localhost:5556/dex/callback" ID="id108965453120986171998428970" InResponseTo="_fd1b3ef9-ec09-44a7-a66b-0d39c250f6a0" IssueInstant="2016-12-20T22:18:23.771Z" Version="2.0">
+  <Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</Issuer>
+  <Status>
+    <StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
+  </Status>
+  <Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="pfxe4534a5f-0f40-2f3a-599d-4dfd123f7d0a" IssueInstant="2016-12-20T22:18:23.771Z" Version="2.0">
+    <Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+  <ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
+    <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
+  <ds:Reference URI="#pfxe4534a5f-0f40-2f3a-599d-4dfd123f7d0a"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>HFNooGfpAONF7T96W3bFsXkH51k=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>dI0QBihhNT5rtRYE9iB0lEKXkE7Yr4+QueOItRH2RcKwAXJ6DA/m3D/S7qwXk00Hn8ZpHu48ZO+HJpyweEEh2UuUWJCCTwwggagKybbSoRx3UTnSuNAFTdoDWTGt89z8j4+gRMC0sepYwppF3u87vJKRVBh8HjFfrHmWsZKwNtfoeXOOFCeatwxcI1sKCoBs2fTn78683ThoAJe3pygipSHY5WPt4dfT/yAY5Ars+OPY/N02M80OfIygZXdJwND0tVPJIF3M9DaehSkvCBHs7QA7DARsRXcuXdsYY7R8wHzqDVJZ4OvcsprONamm5AgUIpql1CjT94rFwWOFyxF2tg==</ds:SignatureValue>
+<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIEUTCCAzmgAwIBAgIJAJdmunb39nFKMA0GCSqGSIb3DQEBCwUAMHgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQwwCgYDVQQKEwNJRFAxFDASBgNVBAsTC1NTT1Byb3ZpZGVyMRMwEQYDVQQDEwpkZXYtOTY5MjQ0MRswGQYJKoZIhvcNAQkBFgxpbmZvQGlkcC5vcmcwHhcNMTcwMTI0MTczMTI3WhcNMjcwMTIyMTczMTI3WjB4MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEChMDSURQMRQwEgYDVQQLEwtTU09Qcm92aWRlcjETMBEGA1UEAxMKZGV2LTk2OTI0NDEbMBkGCSqGSIb3DQEJARYMaW5mb0BpZHAub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0X/AE1tmDmhGRROAWaJ82XSORivRfgNt9Fb4rLrf6nIJsQN3vNb1Nk4DSUEDdQuvHNaEemSVkSPgfq5qnhh37bJaghr0728J8dOyYzV5eArPvsbyCRcnhXQzpCK2zvHwjgxNJMsNJLbnYpG/U+dCdCtcOOn9JEhKO8wKn06y2tcrvC1uuVs7bodukPUNq82KJTyvCQP8jh1hEZXeR2siJFDeJj1n2FNTMeCKIqOb42J/i+sBTlyK3mV5Ni++hI/ssIYVbPwrMIBd6sKLVAgInshBHOj/7XcXW/rMf468YtBKs4XnXsE3hLoU02aWCRDlVHa4hm3jfIAqEADOUumklQIDAQABo4HdMIHaMB0GA1UdDgQWBBRjN/dQSvhZxIsHTXmDKQJkPrjp0TCBqgYDVR0jBIGiMIGfgBRjN/dQSvhZxIsHTXmDKQJkPrjp0aF8pHoweDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDDAKBgNVBAoTA0lEUDEUMBIGA1UECxMLU1NPUHJvdmlkZXIxEzARBgNVBAMTCmRldi05NjkyNDQxGzAZBgkqhkiG9w0BCQEWDGluZm9AaWRwLm9yZ4IJAJdmunb39nFKMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAIqHUglIUAA+BKMW6B0Q+cqIgDr9fWlsvDwIVK7/cvUeGIH3icSsje9AVZ4nQOJpxmC/E06HfuDXmbT1wG16jNo01mPW9qaOGRJuQqlZdegCSF385o/OHcbaEKBRwyYuvLfu80EREj8wcMUKFpExoaxK7K8DS7hh3w7exLB80jyhIaDEYc1hdyAl+206XpOXSYBetsg7I622R2+ajSL7ygUxQjmKQ5DyInPdXzCFCL6Ew/BN0dwzfnBEEK223ruOWBLpj13zMC077dor/NgYyHZU6iqiDS2eYO5jhVMve/mP9734+6N34seQRmekfmsf2dJcEQhPVYr/j0DeJc3men4=</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature>
+    <Subject>
+      <NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">eric.chiang+okta@coreos.com</NameID>
+      <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+        <SubjectConfirmationData InResponseTo="_fd1b3ef9-ec09-44a7-a66b-0d39c250f6a0" NotOnOrAfter="2116-12-20T22:23:23.772Z" Recipient="http://localhost:5556/dex/callback"/>
+      </SubjectConfirmation>
+    </Subject>
+    <Conditions NotBefore="2016-12-20T22:13:23.772Z" NotOnOrAfter="2116-12-20T22:23:23.772Z">
+      <AudienceRestriction>
+        <Audience>http://localhost:5556/dex/callback</Audience>
+      </AudienceRestriction>
+    </Conditions>
+    <AuthnStatement AuthnInstant="2016-12-20T22:18:23.771Z" SessionIndex="_fd1b3ef9-ec09-44a7-a66b-0d39c250f6a0">
+      <AuthnContext>
+        <AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</AuthnContextClassRef>
+      </AuthnContext>
+    </AuthnStatement>
+  </Assertion>
+  <!-- Attacker, unsigned assertion below -->
+  <Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="id10896545312129779529177535" IssueInstant="2016-12-20T22:18:23.771Z" Version="2.0">
+    <Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</Issuer>
+    <Subject>
+      <NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">eric.chiang+attacker@coreos.com</NameID>
+      <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+        <SubjectConfirmationData InResponseTo="_fd1b3ef9-ec09-44a7-a66b-0d39c250f6a0" NotOnOrAfter="2116-12-20T22:23:23.772Z" Recipient="http://localhost:5556/dex/callback"/>
+      </SubjectConfirmation>
+    </Subject>
+    <Conditions NotBefore="2016-12-20T22:13:23.772Z" NotOnOrAfter="2116-12-20T22:23:23.772Z">
+      <AudienceRestriction>
+        <Audience>http://localhost:5556/dex/callback</Audience>
+      </AudienceRestriction>
+    </Conditions>
+    <AuthnStatement AuthnInstant="2016-12-20T22:18:23.771Z" SessionIndex="_fd1b3ef9-ec09-44a7-a66b-0d39c250f6a0">
+      <AuthnContext>
+        <AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</AuthnContextClassRef>
+      </AuthnContext>
+    </AuthnStatement>
+    <AttributeStatement>
+      <Attribute Name="user" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
+        <AttributeValue xsi:type="xs:string">attacker</AttributeValue>
+      </Attribute>
+      <Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
+        <AttributeValue xsi:type="xs:string">eric.chiang+attacker@coreos.com</AttributeValue>
+      </Attribute>
+    </AttributeStatement>
+  </Assertion>
+</Response>
diff --git a/connector/saml/testdata/okta-resp.xml b/connector/saml/testdata/okta-resp.xml
index 9dff8e101bbe13d1ef48e257a50ad82b972d54fa..8b4955b0d857f0d4a6e7786043ff27f32e61416a 100644
--- a/connector/saml/testdata/okta-resp.xml
+++ b/connector/saml/testdata/okta-resp.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?><saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="http://localhost:5556/dex/callback" ID="id108965453120986171998428970" InResponseTo="_fd1b3ef9-ec09-44a7-a66b-0d39c250f6a0" IssueInstant="2016-12-20T22:18:23.771Z" Version="2.0"><saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><ds:Reference URI="#id108965453120986171998428970"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>Phu93l0D97JSMIYDZBdVeNLN0pwBVHhzUDWxbh4sc6g=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>M2gMHOmnMAFgh2apq/2jHwDYmisUkYMUqxrWkQJf3RHFotl4EeDlcqq/FzOboJc3NcbKBqQY3CWsWhWh5cNWHDgNneaahW4czww+9DCM0R/zz5c6GuMYFEh5df2sDn/dWk/jbKMiAMgPdKJ2x/+5Xk9q4axC52TdQrrbZtzAAAn4CgrT6Kf11qfMl5wpDarg3qPw7ANxWn2DKzCsvCkOIwM2+AXh+sEXmTvvZIQ0vpv098FH/ZTGt4sCwb1bmRZ3UZLhBcxVc/sjuEW/sQ6pbQHkjrXIR5bxXzGNUxYpcGjrp9HGF+In0BAc+Ds/A0H142e1rgtcX8LH2pbG8URJSQ==</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIDpDCCAoygAwIBAgIGAVjgvNroMA0GCSqGSIb3DQEBBQUAMIGSMQswCQYDVQQGEwJVUzETMBEG
+<?xml version="1.0" encoding="UTF-8"?><saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="http://127.0.0.1:5556/dex/callback" ID="id19906521125278359305566047" InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"><saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><ds:Reference URI="#id19906521125278359305566047"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"/></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>/jttoTHVc1zHB8tgDVQtiNLAhKAiL24V5Np/SNViPag=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>y1v4Q0No1l82Y32SHL8weC4mXPWRmhy0SdWPd4Dw1gMWW2aGdnMt11VGom4z1/42HxKB0EBje/UPJeagcpEgJ2JQTdb1SvZrQaxwcWexH0Qyw2Tim9kv66dgr0Uo6PRmkYw/ewcimgdNZUOieffUG1Wc+YWtllmE4nz6NR3aLT9WScbC5smbXk2HwWP9xSg3loKMYTUSH32sRePw76QdGbVExUYyFjnB+oY9mIzBHvCTjZw6JGqEaMBmzReCgLZEBdeo0BuitTWCJY5bayJEpasJCQE4iurcKsz6wMheBbEAcQBqiExSUU8dJgQPhD9y5nMBEGC4cvdq4xbvWBKfVQ==</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIDpDCCAoygAwIBAgIGAVjgvNroMA0GCSqGSIb3DQEBBQUAMIGSMQswCQYDVQQGEwJVUzETMBEG
 A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
 MBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi05NjkyNDQxHDAaBgkqhkiG9w0BCQEW
 DWluZm9Ab2t0YS5jb20wHhcNMTYxMjA4MjMxOTIzWhcNMjYxMjA4MjMyMDIzWjCBkjELMAkGA1UE
@@ -14,7 +14,7 @@ eg2DRW6I9/v/mfN2KAQEDqF9aSNlNFWZWmb52kukMv3tLWw0puaevicIZ/nZrW+D3CLDVVfWHeVt
 u/Jh63cVya/VEoP1SVa0XQLf/ial+XuwdBBL1yc+7o2XHOfluDaXw/v2FWYpZtICf3a39giGaNWp
 eCT4g2TDWM4Jf/X7/mRbLX9tQO7XRural1CXx8VIMcmbKNbUtQiO8yEtVQ+FJKOsl7KOSzkgqNiL
 rJy+Y0D9biLZVKp07KWAY2FPCEtCkBrvo8BhvWbxWMA8CVQNAiTylM27Pc6kbc64pNr7C1Jx1wuE
-mVy9Fgb4PA2N3hPeD7mBmGGp7CfDbGcy</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml2p:Status xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"><saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></saml2p:Status><saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="id10896545312129779529177535" IssueInstant="2016-12-20T22:18:23.771Z" Version="2.0"><saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><ds:Reference URI="#id10896545312129779529177535"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>ufwWUjecX6I/aQb4WW9P9ZMLG3C8hN6LaZyyb/EATIs=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>jKtNBzxAL67ssuzWkkbf0yzqRyZ51y2JjBQ9C6bW8io/JOYQB2v7Bix7Eu/RjJslO7OBqD+3tPrK7ZBOy2+LFuAh3cDNa3U5NhO0raLrn/2YoJXfjj3XX3hyQv6GVxo0EY1KJNXOzWxjp9RVDpHslPTIL1yDC/oy0Mlzxu6pXBEerz9J2/Caenq66Skb5/DAT8FvrJ2s1bxuMagShs3APhC1hD8mvktZ+ZcN8ujs2SebteGK4IoOCx+e8+v2CyycBv1l5l+v5I+D2HnbAw4LfvHnW4rZOJT2AvoI47p1YBK1qDsJutG3jUPKy4Yx5YF73Xi1oytr+rrHyx/lfFPd2A==</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIDpDCCAoygAwIBAgIGAVjgvNroMA0GCSqGSIb3DQEBBQUAMIGSMQswCQYDVQQGEwJVUzETMBEG
+mVy9Fgb4PA2N3hPeD7mBmGGp7CfDbGcy</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml2p:Status xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"><saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></saml2p:Status><saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="id199065211253338521862321146" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"><saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><ds:Reference URI="#id199065211253338521862321146"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"/></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>W9osU1+7JHYa6E3Y3tvOCBN/jAGVTl39Wngwkq+4jKI=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>OWa1WvK9+/HOgfm37RwpzUYryJl3ryzdqRUEMlV3ZdLcCz7ZnQ26PCoZD7KxdxUjRci81Ev3OsT8pMCj+sDbFbvBhdRrVvS0sJEgqIFftgD3CYH6OaNGmahSum5Cz+p7xNow/XNQcxjEI2luAtMs+l9JlH8eNPvVVE8RSnXdq9G+y6Iu6RKBVESN9Lgwc6+L2XpqzalZv4d3D+c5dyFCjtNXLOLCJtu3F5w+dYM3KuYJ913S7fbXB2Tv7yRioc9Ssuehft5YacPY9ACsi0PZYAs9Gh4wlzu2yI+7cBfA6hn+h3T/uLu3DMWtHelKtkyOvJS2kFYJlFDio+h7uUbi9A==</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIDpDCCAoygAwIBAgIGAVjgvNroMA0GCSqGSIb3DQEBBQUAMIGSMQswCQYDVQQGEwJVUzETMBEG
 A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
 MBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi05NjkyNDQxHDAaBgkqhkiG9w0BCQEW
 DWluZm9Ab2t0YS5jb20wHhcNMTYxMjA4MjMxOTIzWhcNMjYxMjA4MjMyMDIzWjCBkjELMAkGA1UE
@@ -30,4 +30,4 @@ eg2DRW6I9/v/mfN2KAQEDqF9aSNlNFWZWmb52kukMv3tLWw0puaevicIZ/nZrW+D3CLDVVfWHeVt
 u/Jh63cVya/VEoP1SVa0XQLf/ial+XuwdBBL1yc+7o2XHOfluDaXw/v2FWYpZtICf3a39giGaNWp
 eCT4g2TDWM4Jf/X7/mRbLX9tQO7XRural1CXx8VIMcmbKNbUtQiO8yEtVQ+FJKOsl7KOSzkgqNiL
 rJy+Y0D9biLZVKp07KWAY2FPCEtCkBrvo8BhvWbxWMA8CVQNAiTylM27Pc6kbc64pNr7C1Jx1wuE
-mVy9Fgb4PA2N3hPeD7mBmGGp7CfDbGcy</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">eric.chiang+okta@coreos.com</saml2:NameID><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml2:SubjectConfirmationData InResponseTo="_fd1b3ef9-ec09-44a7-a66b-0d39c250f6a0" NotOnOrAfter="2016-12-20T22:23:23.772Z" Recipient="http://localhost:5556/dex/callback"/></saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore="2016-12-20T22:13:23.772Z" NotOnOrAfter="2016-12-20T22:23:23.772Z" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><saml2:AudienceRestriction><saml2:Audience>http://localhost:5556/dex/callback</saml2:Audience></saml2:AudienceRestriction></saml2:Conditions><saml2:AuthnStatement AuthnInstant="2016-12-20T22:18:23.771Z" SessionIndex="_fd1b3ef9-ec09-44a7-a66b-0d39c250f6a0" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement></saml2:Assertion></saml2p:Response>
+mVy9Fgb4PA2N3hPeD7mBmGGp7CfDbGcy</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">eric.chiang+okta@coreos.com</saml2:NameID><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml2:SubjectConfirmationData InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" NotOnOrAfter="2017-04-04T04:39:59.330Z" Recipient="http://127.0.0.1:5556/dex/callback"/></saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore="2017-04-04T04:29:59.330Z" NotOnOrAfter="2017-04-04T04:39:59.330Z" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><saml2:AudienceRestriction><saml2:Audience>http://127.0.0.1:5556/dex/callback</saml2:Audience></saml2:AudienceRestriction></saml2:Conditions><saml2:AuthnStatement AuthnInstant="2017-04-04T04:34:59.330Z" SessionIndex="6zmm5mguyebwvajyf2sdwwcw6m" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement><saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><saml2:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"><saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">eric.chiang+okta@coreos.com</saml2:AttributeValue></saml2:Attribute><saml2:Attribute Name="Name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"><saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Eric</saml2:AttributeValue></saml2:Attribute><saml2:Attribute Name="groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"><saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Everyone</saml2:AttributeValue><saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Admins</saml2:AttributeValue></saml2:Attribute></saml2:AttributeStatement></saml2:Assertion></saml2p:Response>
diff --git a/connector/saml/testdata/two-assertions-first-signed.tmpl b/connector/saml/testdata/two-assertions-first-signed.tmpl
new file mode 100644
index 0000000000000000000000000000000000000000..22f07cdaec404820babc7e5f3d191bbc1750af3a
--- /dev/null
+++ b/connector/saml/testdata/two-assertions-first-signed.tmpl
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" Destination="http://127.0.0.1:5556/dex/callback" ID="id19906521125278359305566047" InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+  <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+  <saml2p:Status xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
+    <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
+  </saml2p:Status>
+  <!--
+      First assertion is signed but in the wrong place (wrapped by "AttackersElement").
+      Previously triggered an edge case where the signature validation would find this
+      assertion and validate the signature, but latter XML parsing would grab second
+      one provided by the attacker.
+  -->
+  <AttackersElement>
+  <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="id199065211253338521862321146" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+    <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/2000/09/xmldsig#rsa-sha1"/>
+        <Reference URI="#id199065211253338521862321146">
+          <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/2000/09/xmldsig#sha1"/> 
+          <DigestValue/> 
+        </Reference> 
+        </SignedInfo> 
+      <SignatureValue/> 
+      <KeyInfo> 
+        <X509Data/> 
+      </KeyInfo> 
+    </Signature>
+    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+    <saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">eric.chiang+okta@coreos.com</saml2:NameID>
+      <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+        <saml2:SubjectConfirmationData InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" NotOnOrAfter="2017-04-04T04:39:59.330Z" Recipient="http://127.0.0.1:5556/dex/callback"/>
+      </saml2:SubjectConfirmation>
+    </saml2:Subject>
+    <saml2:Conditions xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" NotBefore="2017-04-04T04:29:59.330Z" NotOnOrAfter="2017-04-04T04:39:59.330Z">
+      <saml2:AudienceRestriction>
+        <saml2:Audience>http://127.0.0.1:5556/dex/callback</saml2:Audience>
+      </saml2:AudienceRestriction>
+    </saml2:Conditions>
+    <saml2:AuthnStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" AuthnInstant="2017-04-04T04:34:59.330Z" SessionIndex="6zmm5mguyebwvajyf2sdwwcw6m">
+      <saml2:AuthnContext>
+        <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
+      </saml2:AuthnContext>
+    </saml2:AuthnStatement>
+    <saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">eric.chiang+okta@coreos.com</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="Name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Eric</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Everyone</saml2:AttributeValue>
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Admins</saml2:AttributeValue>
+      </saml2:Attribute>
+    </saml2:AttributeStatement>
+  </saml2:Assertion>
+  </AttackersElement>
+  <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="foobar" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+    <saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">eric.chiang+okta@coreos.com</saml2:NameID>
+      <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+        <saml2:SubjectConfirmationData InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" NotOnOrAfter="2017-04-04T04:39:59.330Z" Recipient="http://127.0.0.1:5556/dex/callback"/>
+      </saml2:SubjectConfirmation>
+    </saml2:Subject>
+    <saml2:Conditions xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" NotBefore="2017-04-04T04:29:59.330Z" NotOnOrAfter="2017-04-04T04:39:59.330Z">
+      <saml2:AudienceRestriction>
+        <saml2:Audience>http://127.0.0.1:5556/dex/callback</saml2:Audience>
+      </saml2:AudienceRestriction>
+    </saml2:Conditions>
+    <saml2:AuthnStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" AuthnInstant="2017-04-04T04:34:59.330Z" SessionIndex="6zmm5mguyebwvajyf2sdwwcw6m">
+      <saml2:AuthnContext>
+        <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
+      </saml2:AuthnContext>
+    </saml2:AuthnStatement>
+    <saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">eric.chiang+okta@coreos.com</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="Name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">
+
+          I AM AN ATTACKER TRYING TO GET YOU TO USE THIS ASSERTION!!!
+
+        </saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Everyone</saml2:AttributeValue>
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Admins</saml2:AttributeValue>
+      </saml2:Attribute>
+    </saml2:AttributeStatement>
+  </saml2:Assertion>
+</saml2p:Response>
diff --git a/connector/saml/testdata/two-assertions-first-signed.xml b/connector/saml/testdata/two-assertions-first-signed.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ccc363b45b3138afcaa3ed13b5516156798040f9
--- /dev/null
+++ b/connector/saml/testdata/two-assertions-first-signed.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" Destination="http://127.0.0.1:5556/dex/callback" ID="id19906521125278359305566047" InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+  <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+  <saml2p:Status xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
+    <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
+  </saml2p:Status>
+  <!--
+      First assertion is signed but in the wrong place (wrapped by "AttackersElement").
+      Previously triggered an edge case where the signature validation would find this
+      assertion and validate the signature, but latter XML parsing would grab second
+      one provided by the attacker.
+  -->
+  <AttackersElement>
+  <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="id199065211253338521862321146" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+    <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/2000/09/xmldsig#rsa-sha1"/>
+        <Reference URI="#id199065211253338521862321146">
+          <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/2000/09/xmldsig#sha1"/> 
+          <DigestValue>kDdpmKMPp7zjUeMTuntXJFpT6cs=</DigestValue> 
+        </Reference> 
+        </SignedInfo> 
+      <SignatureValue>Q12w9zPo9Bqn3W2OT7lbFbhfIDQrp7SXd/+9ZWpY4mv3ApgaOcNX2VtpSE0EjorU
+1NyrktVOkCYueJm/HVQF7gyF85KRlPBDLBZOwxbnnmrRFoCk+U2kjIt8k8eZ7NsD
+jLFGFgEveS359uvaHZR1Exbr0PBYwS7aXR3fpmjMjZ9T8f8Oe3Nt/9nWPgz/dFhb
+Aa+AniWuupfq2v6YMLZ+9GLiO0sOr8UVkW8AYOm2Bin30epikXT1Axi/VxWz/fjP
+nMUkgusFnhkgmIf/YncAv4S9GY6DcaV2iEj6cL70S7pcgaeRFi3iozigl+9a+lFo
+dt3Jy8Jq/N3OAyDP2DxLEw==</SignatureValue> 
+      <KeyInfo> 
+        <X509Data>
+<X509Certificate>MIIDGTCCAgGgAwIBAgIJAKLbLcQajEf8MA0GCSqGSIb3DQEBCwUAMCMxDDAKBgNV
+BAoMA0RFWDETMBEGA1UEAwwKY29yZW9zLmNvbTAeFw0xNzA0MDQwNzAwNTNaFw0z
+NzAzMzAwNzAwNTNaMCMxDDAKBgNVBAoMA0RFWDETMBEGA1UEAwwKY29yZW9zLmNv
+bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKH3dKWbRqCIZD2m3aHI
+4lfBT+u/4DECde74Ggq9WugdTucVQzDZUTaI7wzn17JM9hdPmXvaSRG9BaB1H3uO
+ZCs/fmdhBERRhPvuEVfAZaFfQfR7vn7WvUzT7zwMLLB8+EHzL3fOSGM2QnCOMeUD
+AB27Pb0fuBW43NXaTD9rwfFCHvo1UP+TBJIPnV65HMeMGIrtGLt7MZTPuPm3LnYA
+faXLf2vWSzL5nAgnJvUgceZXmyuciBfXpt8c1jIsj4y3tBoRTRqaxuaW1Eo7WMKF
+a7s6KvTBKErPKuzAoIcVB4ir6jm1ticAgB72SScKtPJJdEPemTXRNNzkiw7VbpY9
+QacCAwEAAaNQME4wHQYDVR0OBBYEFNHyGYyY2+eZ1l7ZLPZsnc3GOtj/MB8GA1Ud
+IwQYMBaAFNHyGYyY2+eZ1l7ZLPZsnc3GOtj/MAwGA1UdEwQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAHVXB5QmZfki9QpKzoiBNfpQ/mo6XWhExLGBTJXEWJT3P7JP
+oR4Z0+85bp0fUK338s+WjyqTn0U55Jtp0B65Qxy6ythkZat/6NPp/S7gto2De6pS
+hSGygokQioVQnoYQeK0MXl2QbtrWwNiM4HC+9yohbUfjwv8yI7opwn/rjB6X/4De
+oX2YzwTBJgoIXF7zMKYFF0DrKQjbTQr/a7kfNjq4930o7VhFph9Qpdv0EWM3svTd
+esSffLKbWcabtyMtCr5QyEwZiozd567oWFWZYeHQyEtd+w6tAFmz9ZslipdQEa/j
+1xUtrScuXt19sUfOgjUvA+VUNeMLDdpHUKHNW/Q=</X509Certificate>
+</X509Data> 
+      </KeyInfo> 
+    </Signature>
+    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+    <saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">eric.chiang+okta@coreos.com</saml2:NameID>
+      <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+        <saml2:SubjectConfirmationData InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" NotOnOrAfter="2017-04-04T04:39:59.330Z" Recipient="http://127.0.0.1:5556/dex/callback"/>
+      </saml2:SubjectConfirmation>
+    </saml2:Subject>
+    <saml2:Conditions xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" NotBefore="2017-04-04T04:29:59.330Z" NotOnOrAfter="2017-04-04T04:39:59.330Z">
+      <saml2:AudienceRestriction>
+        <saml2:Audience>http://127.0.0.1:5556/dex/callback</saml2:Audience>
+      </saml2:AudienceRestriction>
+    </saml2:Conditions>
+    <saml2:AuthnStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" AuthnInstant="2017-04-04T04:34:59.330Z" SessionIndex="6zmm5mguyebwvajyf2sdwwcw6m">
+      <saml2:AuthnContext>
+        <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
+      </saml2:AuthnContext>
+    </saml2:AuthnStatement>
+    <saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">eric.chiang+okta@coreos.com</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="Name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Eric</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Everyone</saml2:AttributeValue>
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Admins</saml2:AttributeValue>
+      </saml2:Attribute>
+    </saml2:AttributeStatement>
+  </saml2:Assertion>
+  </AttackersElement>
+  <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="foobar" IssueInstant="2017-04-04T04:34:59.330Z" Version="2.0">
+    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk91cb99lKkKSYoy0h7</saml2:Issuer>
+    <saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">eric.chiang+okta@coreos.com</saml2:NameID>
+      <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+        <saml2:SubjectConfirmationData InResponseTo="6zmm5mguyebwvajyf2sdwwcw6m" NotOnOrAfter="2017-04-04T04:39:59.330Z" Recipient="http://127.0.0.1:5556/dex/callback"/>
+      </saml2:SubjectConfirmation>
+    </saml2:Subject>
+    <saml2:Conditions xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" NotBefore="2017-04-04T04:29:59.330Z" NotOnOrAfter="2017-04-04T04:39:59.330Z">
+      <saml2:AudienceRestriction>
+        <saml2:Audience>http://127.0.0.1:5556/dex/callback</saml2:Audience>
+      </saml2:AudienceRestriction>
+    </saml2:Conditions>
+    <saml2:AuthnStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" AuthnInstant="2017-04-04T04:34:59.330Z" SessionIndex="6zmm5mguyebwvajyf2sdwwcw6m">
+      <saml2:AuthnContext>
+        <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
+      </saml2:AuthnContext>
+    </saml2:AuthnStatement>
+    <saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
+      <saml2:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">eric.chiang+okta@coreos.com</saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="Name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">
+
+          I AM AN ATTACKER TRYING TO GET YOU TO USE THIS ASSERTION!!!
+
+        </saml2:AttributeValue>
+      </saml2:Attribute>
+      <saml2:Attribute Name="groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Everyone</saml2:AttributeValue>
+        <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Admins</saml2:AttributeValue>
+      </saml2:Attribute>
+    </saml2:AttributeStatement>
+  </saml2:Assertion>
+</saml2p:Response>