package sso import ( "fmt" "net/url" "testing" "time" "github.com/beevik/etree" "github.com/crewjam/saml" "github.com/fleetdm/fleet/v4/server/fleet" dsig "github.com/russellhaering/goxmldsig" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestDecodeSuccessfulSalesforceResponse(t *testing.T) { const samlResponse = ` https://kolide-dev-ed.my.salesforce.com syKA9xe4vLJ+W1WxYrTDV8gjXdc= SHXNEnRlRmTOpgfAtS14VNwAFmzR8u23rLNcr/K8Oh5e3l9LTtbL9QtvLsyYNUFoizDs4fbHfyBH DcBD3zCEXFVnvS+3TA3SpUMH+4usdTsLkRhS1K5Ira/MK/aumR43IdMFilMcecF8J4YAblRtJIyh KvSd1VKukUoTDv7YOMEwco4hxzL+gVrE9HzHfAv/fSyxOMXohEHLPO8QedBsX4ZKIr4ZuOPuViiJ Au+01A8AO01gbZWuXmTKmI/WDH66tBQUcPRF2RBWwvzirpY86N4Sdv58VLdM5IMa/hhvLHMOHlGM +kERr7KqLhMNFTTw9VnoybBmniR0ioAg2lwpZA== MIIErDCCA5SgAwIBAgIOAVuhH3WkAAAAAB5NpvIwDQYJKoZIhvcNAQELBQAwgZAxKDAmBgNVBAMM H1NlbGZTaWduZWRDZXJ0XzI0QXByMjAxN18xODAwNDQxGDAWBgNVBAsMDzAwRDZBMDAwMDAwMTd0 ODEXMBUGA1UECgwOU2FsZXNmb3JjZS5jb20xFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xCzAJBgNV BAgMAkNBMQwwCgYDVQQGEwNVU0EwHhcNMTcwNDI0MTgwMDQ1WhcNMTgwNDI0MTIwMDAwWjCBkDEo MCYGA1UEAwwfU2VsZlNpZ25lZENlcnRfMjRBcHIyMDE3XzE4MDA0NDEYMBYGA1UECwwPMDBENkEw MDAwMDAxN3Q4MRcwFQYDVQQKDA5TYWxlc2ZvcmNlLmNvbTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNj bzELMAkGA1UECAwCQ0ExDDAKBgNVBAYTA1VTQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAIOR7h8BF2eFOlQHhV/1S7uOBN22Jv7PDCXMz2fU0uLc+mrv9xDGj6ElfW+9dSdXaCbQzD3+ Xq4reS4pYRafJZ/27OtygXl3rpoPjSlhRiW+oYVuDcCURJpu0KuZ4I0fm5q1BDYqxcBxNPSe85OH E3+ucmKqvPozhQgYLPCregMIomC3yyANZnLCoGfCv9TpQl6/+I182tST4WPNhVPxKxijoPU4Rh6x Y34Ez8+Jr8KdmzmYSNe4ukkIASplpvG7rKka824Hf8zI1BWnjWLDxb5IAxgUBbdr4x8d8C3kPfTf +3/6yC5wSOm9NSs0BA4OJNowtXZFryMzFfXzDzjl69kCAwEAAaOCAQAwgf0wHQYDVR0OBBYEFO+D koP6qkysi9ZC74yTPuJVVg2yMA8GA1UdEwEB/wQFMAMBAf8wgcoGA1UdIwSBwjCBv4AU74OSg/qq TKyL1kLvjJM+4lVWDbKhgZakgZMwgZAxKDAmBgNVBAMMH1NlbGZTaWduZWRDZXJ0XzI0QXByMjAx N18xODAwNDQxGDAWBgNVBAsMDzAwRDZBMDAwMDAwMTd0ODEXMBUGA1UECgwOU2FsZXNmb3JjZS5j b20xFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xCzAJBgNVBAgMAkNBMQwwCgYDVQQGEwNVU0GCDgFb oR91pAAAAAAeTabyMA0GCSqGSIb3DQEBCwUAA4IBAQAVhYBv5GJvhltks2j7Zc9wdFHW7yB4/hPF o05y0yiOf71tLjOlBucSyxtmXLPjrECJvIJwKhsAIgYXnVp7ditxfauCcxczJgfeL1/dxH/Ge8eP kmH6SdsO71cJL8dXEzOsoF+PAVQzUhqh8zxIipntL0wwNGTD0zIVQeTSozm0KF0SsSHIfbNy279u ReGonC61i4Ouk5AMKA7Re9fVeUs6tqM2at22h9Zaj/r/OhXoDcZhzkd8Wq0ER/UKLZA1CyJHgwOC 7REEZOuKrqgfWcYt4dGo5q6gqGHHPMv0N7s/MxqCvJCwGA8eJGvOO56I321vhWHQ6ZSJDWUqQFM/ Ze7A https://kolide-dev-ed.my.salesforce.com BOhmqkd//KYBmBJIZfUqgEx6iLc= UaSyePoQdNc8ApcL7Ak7NhWuZY9ilmqbJDbkIFjfYoikPWpiqq0Z5DHxPVCHgRi42KC9oclXPjWh v8acBZrMZlqn0yVaEeVwozcKYGwxh7mhnWnU2zrd4hnnfDZbwyU3pchUVNXyndPmfwnRR8wBDcID +/uL10u6zBzGbtzvx1rG33Od8f4h+RDDOTRVX1iVKw5pbnvjrrYcY1gqI5OQKBoki1X6LhZE4qk5 77DG3U9Z3qut2GTYzupRp9nszbOv1l0jXuavy+94zZ3K3oqeLNH3ZW1fB8XG8b3nX9rFEYzto5CQ SSQaUypAljmg9XrmfVoljUDpabRWKWi0eiEvxQ== MIIErDCCA5SgAwIBAgIOAVuhH3WkAAAAAB5NpvIwDQYJKoZIhvcNAQELBQAwgZAxKDAmBgNVBAMM H1NlbGZTaWduZWRDZXJ0XzI0QXByMjAxN18xODAwNDQxGDAWBgNVBAsMDzAwRDZBMDAwMDAwMTd0 ODEXMBUGA1UECgwOU2FsZXNmb3JjZS5jb20xFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xCzAJBgNV BAgMAkNBMQwwCgYDVQQGEwNVU0EwHhcNMTcwNDI0MTgwMDQ1WhcNMTgwNDI0MTIwMDAwWjCBkDEo MCYGA1UEAwwfU2VsZlNpZ25lZENlcnRfMjRBcHIyMDE3XzE4MDA0NDEYMBYGA1UECwwPMDBENkEw MDAwMDAxN3Q4MRcwFQYDVQQKDA5TYWxlc2ZvcmNlLmNvbTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNj bzELMAkGA1UECAwCQ0ExDDAKBgNVBAYTA1VTQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAIOR7h8BF2eFOlQHhV/1S7uOBN22Jv7PDCXMz2fU0uLc+mrv9xDGj6ElfW+9dSdXaCbQzD3+ Xq4reS4pYRafJZ/27OtygXl3rpoPjSlhRiW+oYVuDcCURJpu0KuZ4I0fm5q1BDYqxcBxNPSe85OH E3+ucmKqvPozhQgYLPCregMIomC3yyANZnLCoGfCv9TpQl6/+I182tST4WPNhVPxKxijoPU4Rh6x Y34Ez8+Jr8KdmzmYSNe4ukkIASplpvG7rKka824Hf8zI1BWnjWLDxb5IAxgUBbdr4x8d8C3kPfTf +3/6yC5wSOm9NSs0BA4OJNowtXZFryMzFfXzDzjl69kCAwEAAaOCAQAwgf0wHQYDVR0OBBYEFO+D koP6qkysi9ZC74yTPuJVVg2yMA8GA1UdEwEB/wQFMAMBAf8wgcoGA1UdIwSBwjCBv4AU74OSg/qq TKyL1kLvjJM+4lVWDbKhgZakgZMwgZAxKDAmBgNVBAMMH1NlbGZTaWduZWRDZXJ0XzI0QXByMjAx N18xODAwNDQxGDAWBgNVBAsMDzAwRDZBMDAwMDAwMTd0ODEXMBUGA1UECgwOU2FsZXNmb3JjZS5j b20xFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xCzAJBgNVBAgMAkNBMQwwCgYDVQQGEwNVU0GCDgFb oR91pAAAAAAeTabyMA0GCSqGSIb3DQEBCwUAA4IBAQAVhYBv5GJvhltks2j7Zc9wdFHW7yB4/hPF o05y0yiOf71tLjOlBucSyxtmXLPjrECJvIJwKhsAIgYXnVp7ditxfauCcxczJgfeL1/dxH/Ge8eP kmH6SdsO71cJL8dXEzOsoF+PAVQzUhqh8zxIipntL0wwNGTD0zIVQeTSozm0KF0SsSHIfbNy279u ReGonC61i4Ouk5AMKA7Re9fVeUs6tqM2at22h9Zaj/r/OhXoDcZhzkd8Wq0ER/UKLZA1CyJHgwOC 7REEZOuKrqgfWcYt4dGo5q6gqGHHPMv0N7s/MxqCvJCwGA8eJGvOO56I321vhWHQ6ZSJDWUqQFM/ Ze7A john@kolide.co kolide urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified 0056A000000Q6Rl john@kolide.co john@kolide.co false ` setFakeClock(t, "2017-04-27T15:03:16.749Z") acsURL, err := url.Parse("https://localhost:8080/api/v1/kolide/sso/callback") require.NoError(t, err) p := dummySAMLProvider(acsURL) p.IDPMetadata = testSalesforceMetadata() p.IDPMetadata.EntityID = "https://kolide-dev-ed.my.salesforce.com" auth, err := ParseAndVerifySAMLResponse(p, []byte(samlResponse), "4982b430-73e1-4ad2-885a-4a775a91f820", acsURL) require.NoError(t, err) require.NotNil(t, auth) assert.Equal(t, "john@kolide.co", auth.UserID()) } func TestDecodeWithCommentInName(t *testing.T) { t.Skip("TODO(lucas): Must be fixed on the crewjam/saml upstream, PR in review: https://github.com/crewjam/saml/pull/611") // Testing for vuln described at // https://duo.com/blog/duo-finds-saml-vulnerabilities-affecting-multiple-implementations // Relevant XML snippets: // // john@kolide.co const samlResponse = ` https://kolide-dev-ed.my.salesforce.com syKA9xe4vLJ+W1WxYrTDV8gjXdc= SHXNEnRlRmTOpgfAtS14VNwAFmzR8u23rLNcr/K8Oh5e3l9LTtbL9QtvLsyYNUFoizDs4fbHfyBH DcBD3zCEXFVnvS+3TA3SpUMH+4usdTsLkRhS1K5Ira/MK/aumR43IdMFilMcecF8J4YAblRtJIyh KvSd1VKukUoTDv7YOMEwco4hxzL+gVrE9HzHfAv/fSyxOMXohEHLPO8QedBsX4ZKIr4ZuOPuViiJ Au+01A8AO01gbZWuXmTKmI/WDH66tBQUcPRF2RBWwvzirpY86N4Sdv58VLdM5IMa/hhvLHMOHlGM +kERr7KqLhMNFTTw9VnoybBmniR0ioAg2lwpZA== MIIErDCCA5SgAwIBAgIOAVuhH3WkAAAAAB5NpvIwDQYJKoZIhvcNAQELBQAwgZAxKDAmBgNVBAMM H1NlbGZTaWduZWRDZXJ0XzI0QXByMjAxN18xODAwNDQxGDAWBgNVBAsMDzAwRDZBMDAwMDAwMTd0 ODEXMBUGA1UECgwOU2FsZXNmb3JjZS5jb20xFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xCzAJBgNV BAgMAkNBMQwwCgYDVQQGEwNVU0EwHhcNMTcwNDI0MTgwMDQ1WhcNMTgwNDI0MTIwMDAwWjCBkDEo MCYGA1UEAwwfU2VsZlNpZ25lZENlcnRfMjRBcHIyMDE3XzE4MDA0NDEYMBYGA1UECwwPMDBENkEw MDAwMDAxN3Q4MRcwFQYDVQQKDA5TYWxlc2ZvcmNlLmNvbTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNj bzELMAkGA1UECAwCQ0ExDDAKBgNVBAYTA1VTQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAIOR7h8BF2eFOlQHhV/1S7uOBN22Jv7PDCXMz2fU0uLc+mrv9xDGj6ElfW+9dSdXaCbQzD3+ Xq4reS4pYRafJZ/27OtygXl3rpoPjSlhRiW+oYVuDcCURJpu0KuZ4I0fm5q1BDYqxcBxNPSe85OH E3+ucmKqvPozhQgYLPCregMIomC3yyANZnLCoGfCv9TpQl6/+I182tST4WPNhVPxKxijoPU4Rh6x Y34Ez8+Jr8KdmzmYSNe4ukkIASplpvG7rKka824Hf8zI1BWnjWLDxb5IAxgUBbdr4x8d8C3kPfTf +3/6yC5wSOm9NSs0BA4OJNowtXZFryMzFfXzDzjl69kCAwEAAaOCAQAwgf0wHQYDVR0OBBYEFO+D koP6qkysi9ZC74yTPuJVVg2yMA8GA1UdEwEB/wQFMAMBAf8wgcoGA1UdIwSBwjCBv4AU74OSg/qq TKyL1kLvjJM+4lVWDbKhgZakgZMwgZAxKDAmBgNVBAMMH1NlbGZTaWduZWRDZXJ0XzI0QXByMjAx N18xODAwNDQxGDAWBgNVBAsMDzAwRDZBMDAwMDAwMTd0ODEXMBUGA1UECgwOU2FsZXNmb3JjZS5j b20xFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xCzAJBgNVBAgMAkNBMQwwCgYDVQQGEwNVU0GCDgFb oR91pAAAAAAeTabyMA0GCSqGSIb3DQEBCwUAA4IBAQAVhYBv5GJvhltks2j7Zc9wdFHW7yB4/hPF o05y0yiOf71tLjOlBucSyxtmXLPjrECJvIJwKhsAIgYXnVp7ditxfauCcxczJgfeL1/dxH/Ge8eP kmH6SdsO71cJL8dXEzOsoF+PAVQzUhqh8zxIipntL0wwNGTD0zIVQeTSozm0KF0SsSHIfbNy279u ReGonC61i4Ouk5AMKA7Re9fVeUs6tqM2at22h9Zaj/r/OhXoDcZhzkd8Wq0ER/UKLZA1CyJHgwOC 7REEZOuKrqgfWcYt4dGo5q6gqGHHPMv0N7s/MxqCvJCwGA8eJGvOO56I321vhWHQ6ZSJDWUqQFM/ Ze7A https://kolide-dev-ed.my.salesforce.com BOhmqkd//KYBmBJIZfUqgEx6iLc= UaSyePoQdNc8ApcL7Ak7NhWuZY9ilmqbJDbkIFjfYoikPWpiqq0Z5DHxPVCHgRi42KC9oclXPjWh v8acBZrMZlqn0yVaEeVwozcKYGwxh7mhnWnU2zrd4hnnfDZbwyU3pchUVNXyndPmfwnRR8wBDcID +/uL10u6zBzGbtzvx1rG33Od8f4h+RDDOTRVX1iVKw5pbnvjrrYcY1gqI5OQKBoki1X6LhZE4qk5 77DG3U9Z3qut2GTYzupRp9nszbOv1l0jXuavy+94zZ3K3oqeLNH3ZW1fB8XG8b3nX9rFEYzto5CQ SSQaUypAljmg9XrmfVoljUDpabRWKWi0eiEvxQ== MIIErDCCA5SgAwIBAgIOAVuhH3WkAAAAAB5NpvIwDQYJKoZIhvcNAQELBQAwgZAxKDAmBgNVBAMM H1NlbGZTaWduZWRDZXJ0XzI0QXByMjAxN18xODAwNDQxGDAWBgNVBAsMDzAwRDZBMDAwMDAwMTd0 ODEXMBUGA1UECgwOU2FsZXNmb3JjZS5jb20xFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xCzAJBgNV BAgMAkNBMQwwCgYDVQQGEwNVU0EwHhcNMTcwNDI0MTgwMDQ1WhcNMTgwNDI0MTIwMDAwWjCBkDEo MCYGA1UEAwwfU2VsZlNpZ25lZENlcnRfMjRBcHIyMDE3XzE4MDA0NDEYMBYGA1UECwwPMDBENkEw MDAwMDAxN3Q4MRcwFQYDVQQKDA5TYWxlc2ZvcmNlLmNvbTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNj bzELMAkGA1UECAwCQ0ExDDAKBgNVBAYTA1VTQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAIOR7h8BF2eFOlQHhV/1S7uOBN22Jv7PDCXMz2fU0uLc+mrv9xDGj6ElfW+9dSdXaCbQzD3+ Xq4reS4pYRafJZ/27OtygXl3rpoPjSlhRiW+oYVuDcCURJpu0KuZ4I0fm5q1BDYqxcBxNPSe85OH E3+ucmKqvPozhQgYLPCregMIomC3yyANZnLCoGfCv9TpQl6/+I182tST4WPNhVPxKxijoPU4Rh6x Y34Ez8+Jr8KdmzmYSNe4ukkIASplpvG7rKka824Hf8zI1BWnjWLDxb5IAxgUBbdr4x8d8C3kPfTf +3/6yC5wSOm9NSs0BA4OJNowtXZFryMzFfXzDzjl69kCAwEAAaOCAQAwgf0wHQYDVR0OBBYEFO+D koP6qkysi9ZC74yTPuJVVg2yMA8GA1UdEwEB/wQFMAMBAf8wgcoGA1UdIwSBwjCBv4AU74OSg/qq TKyL1kLvjJM+4lVWDbKhgZakgZMwgZAxKDAmBgNVBAMMH1NlbGZTaWduZWRDZXJ0XzI0QXByMjAx N18xODAwNDQxGDAWBgNVBAsMDzAwRDZBMDAwMDAwMTd0ODEXMBUGA1UECgwOU2FsZXNmb3JjZS5j b20xFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xCzAJBgNVBAgMAkNBMQwwCgYDVQQGEwNVU0GCDgFb oR91pAAAAAAeTabyMA0GCSqGSIb3DQEBCwUAA4IBAQAVhYBv5GJvhltks2j7Zc9wdFHW7yB4/hPF o05y0yiOf71tLjOlBucSyxtmXLPjrECJvIJwKhsAIgYXnVp7ditxfauCcxczJgfeL1/dxH/Ge8eP kmH6SdsO71cJL8dXEzOsoF+PAVQzUhqh8zxIipntL0wwNGTD0zIVQeTSozm0KF0SsSHIfbNy279u ReGonC61i4Ouk5AMKA7Re9fVeUs6tqM2at22h9Zaj/r/OhXoDcZhzkd8Wq0ER/UKLZA1CyJHgwOC 7REEZOuKrqgfWcYt4dGo5q6gqGHHPMv0N7s/MxqCvJCwGA8eJGvOO56I321vhWHQ6ZSJDWUqQFM/ Ze7A john@kolide.co kolide urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified 0056A000000Q6Rl john@kolide.co john@kolide.co false ` setFakeClock(t, "2017-04-27T15:03:16.747Z") acsURL, err := url.Parse("https://localhost:8080/api/v1/kolide/sso/callback") require.NoError(t, err) p := dummySAMLProvider(acsURL) p.IDPMetadata = testSalesforceMetadata() p.IDPMetadata.EntityID = "https://kolide-dev-ed.my.salesforce.com" auth, err := ParseAndVerifySAMLResponse(p, []byte(samlResponse), "4982b430-73e1-4ad2-885a-4a775a91f820", acsURL) require.NoError(t, err) require.NotNil(t, auth) assert.Equal(t, "john@kolide.co", auth.UserID()) } type nopSignatureVerified struct{} func (n *nopSignatureVerified) VerifySignature(validationContext *dsig.ValidationContext, el *etree.Element) error { return nil } func dummySAMLProvider(acsURL *url.URL) *saml.ServiceProvider { return &saml.ServiceProvider{ ValidateAudienceRestriction: func(assertion *saml.Assertion) error { return nil }, SignatureVerifier: &nopSignatureVerified{}, AcsURL: *acsURL, // We set the Salesforce test metadata because the library requires setting certificates, // but the dummySAMLProvider performs no signature verification. IDPMetadata: testSalesforceMetadata(), } } func setFakeClock(t *testing.T, date string) { tm, err := time.Parse("2006-01-02T15:04:05.000Z", date) require.NoError(t, err) saml.TimeNow = func() time.Time { return tm } clock := dsig.NewFakeClockAt(tm) saml.Clock = clock } func TestDecodeSuccessfulGoogleResponse(t *testing.T) { const samlResponse = ` https://accounts.google.com/o/saml2?idpid=C0171bstf https://accounts.google.com/o/saml2?idpid=C0171bstf nZmgK9XtjyT7sBApU0tyZbUE4WWMwCsDz8j6IZE5Ixw= DHdU+LnOX/u8Hujx+IpDmozt9u2ROD9UU2Ob5El0ZjEpAESqyY2Pj9Y4Kd01IsDTf/gFKJWOyVMz PP3io5P4eiA96p+0g0YNuO6ickVF9BHAJyjET38C3pB95rgqUb7rLaD6XdfAXFQ7l2dalHS9yLa/ KBtT3f3ykYPb74NrAhihV8Z0gvPpyWqBDg23B76tIerWn26LooZkPNXPTGv/sy8ocY5oz56plKvZ OmVdwpzwH7/7i/UEnNv6sis3/es0Omm5gxeKLP40vWb9lTm1HmvLTV3sZiHZQQmUwmfcsZL6gyVE eaJNDQP4yOw+vXKdeyAlVC6jtt06MgY9V0zj5g== ST=California,C=US,OU=Google For Work,CN=Google,L=Mountain View,O=Google Inc. MIIDdDCCAlygAwIBAgIGAV1SKeijMA0GCSqGSIb3DQEBCwUAMHsxFDASBgNVBAoTC0dvb2dsZSBJ bmMuMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MQ8wDQYDVQQDEwZHb29nbGUxGDAWBgNVBAsTD0dv b2dsZSBGb3IgV29yazELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWEwHhcNMTcwNzE3 MjAwNzQzWhcNMjIwNzE2MjAwNzQzWjB7MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEWMBQGA1UEBxMN TW91bnRhaW4gVmlldzEPMA0GA1UEAxMGR29vZ2xlMRgwFgYDVQQLEw9Hb29nbGUgRm9yIFdvcmsx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAzLXNn7VmJBkvVNYHffTzDoow/8eSklauVeYjhELY6dtFv56wAQsFNeMovFUPxPeG 7Fci50/KStvoNZOdKqZFCwYkfI2ssXuMpBP37x2iprV7moVwGdGJb52elMNe0DesgTPbJ/IWIvzF 3GYxqYCHUlHuzJEzBYsdtvM8T/PClBxiLXRNbnjotzleFqb25w3XRfayOZg5GdQPeEmceWXDBhCa eQyEPOrUTZ+//pZXSuKnOyaFfESNFNgvQJlYQQukjnhPtf674eWT6OdgZHyq8EBbZKfEhs5+KiAN U43bDh9rpTJCB7rAKk1BFAW3r72pggwN9Z/sfp/C5B7uKAM5hwIDAQABMA0GCSqGSIb3DQEBCwUA A4IBAQAZXypikbbRzichNXLdK96M/do9nGS5Q3xVgA2uxTzm/6qNkAfOSGSk8OcLrppPonbohkeZ WVnNB5VZZava4DoSZ6OZsvKc1FM0wKvPJd83KUb7Syk1bV7TkT8DPEclfsLnn5s5g0oHlhsqkNly 0WPFTAoGHXYyOKGEARPoC/o+ZfgfvoMNyZkSQHiRboVVP2cT1ckJt4iCA65hNGXte29hSGmnX7QG QyrBRp8n4UR9PjoeIy0tTCmG0tqu/NackFH4PkamY84Etxe9uH0StmkhID46QTT4Cv2+jqCaklg+ 7VYqXbY64Wc/k0sK7WI1o3IVLWAPNb8ajV6Eo0Y8u+1N john@edilok.net kolide.edilok.net john@edilok.net urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified ` setFakeClock(t, "2017-07-18T14:47:08.035Z") acsURL, err := url.Parse("https://localhost:8080/api/v1/kolide/sso/callback") require.NoError(t, err) p := dummySAMLProvider(acsURL) p.IDPMetadata.EntityID = "https://accounts.google.com/o/saml2?idpid=C0171bstf" auth, err := ParseAndVerifySAMLResponse(p, []byte(samlResponse), "SGJhi1g5D4/npOwXaw8t6A==", acsURL) require.NoError(t, err) require.NotNil(t, auth) assert.Equal(t, "john@edilok.net", auth.UserID()) } func TestDecodeAttributes(t *testing.T) { const samlResponse = ` http://localhost:9080/simplesaml/saml2/idp/metadata.php HtQ1uTkyzTwwNZ6XJQT8ROuQsfaw99TiQktm2EhKPWk= EawypjAfab8xnhmF994nIq8oSqd/DenA4HGj7A85MRlAGa5W3fftFwmovXPhbGZeDZsQtAGssnvtJgZ7FEraWF9oYGxqdZQZ2Oethx6uKxaryxKmp22erd8ctd0JMMmK5vu2PFqLCoP2qFvmruM4ruYHbee5sl8EMWHJ/FExuq4bWoeAa08ZCYdJnPawO2AyIzJtAku2nXQwz1756VrV1mX7tenaADxqMexCJdyXSuDG1I1nXp/qnRIOjUbfsfIN0WkG8jY9MDdUUi8ah0UYgdv2kQn1d/FYoI1/AuPXRl72QLtN4jFbg0ZZJAX5wtP66vvbC29cK6SN3h1ghSFFCg== MIIDXTCCAkWgAwIBAgIJALmVVuDWu4NYMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMjMxMTQzNDQ3WhcNNDgwNjI1MTQzNDQ3WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUCFozgNb1h1M0jzNRSCjhOBnR+uVbVpaWfXYIR+AhWDdEe5ryY+CgavOg8bfLybyzFdehlYdDRgkedEB/GjG8aJw06l0qF4jDOAw0kEygWCu2mcH7XOxRt+YAH3TVHa/Hu1W3WjzkobqqqLQ8gkKWWM27fOgAZ6GieaJBN6VBSMMcPey3HWLBmc+TYJmv1dbaO2jHhKh8pfKw0W12VM8P1PIO8gv4Phu/uuJYieBWKixBEyy0lHjyixYFCR12xdh4CA47q958ZRGnnDUGFVE1QhgRacJCOZ9bd5t9mr8KLaVBYTCJo5ERE8jymab5dPqe5qKfJsCZiqWglbjUo9twIDAQABo1AwTjAdBgNVHQ4EFgQUxpuwcs/CYQOyui+r1G+3KxBNhxkwHwYDVR0jBBgwFoAUxpuwcs/CYQOyui+r1G+3KxBNhxkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAAiWUKs/2x/viNCKi3Y6blEuCtAGhzOOZ9EjrvJ8+COH3Rag3tVBWrcBZ3/uhhPq5gy9lqw4OkvEws99/5jFsX1FJ6MKBgqfuy7yh5s1YfM0ANHYczMmYpZeAcQf2CGAaVfwTTfSlzNLsF2lW/ly7yapFzlYSJLGoVE+OHEu8g5SlNACUEfkXw+5Eghh+KzlIN7R6Q7r2ixWNFBC/jWf7NKUfJyX8qIG5md1YUeT6GBW9Bm2/1/RiO24JTaYlfLdKK9TYb8sG5B+OLab2DImG99CJ25RkAcSobWNF5zD0O6lgOo3cEdB/ksCq3hmtlC/DlLZ/D8CJ+7VuZnS1rR2naQ== http://localhost:9080/simplesaml/saml2/idp/metadata.php AuiXXRBMG03hyrsjxHQeaI82pfb6JQ/8FJMqu1zC46o= Tsjsa0xPER51uAOlM+smsX+kBkqy/0xXlFEohzdflfP6N0qtjEla/jOC9M5j1F+bfkjeP3Lo2cp5OvU2PeQRWpfp+CTfF1tZCuP+F/Du0n4wfKMAU6bjNhq8LYEjC/LbNIyLnDNxT33lZp9udBWPmXwe4U92jcCEY54Tnql7xdqh/ez7J1A3TjNbsbTc9D9NWD9ZG7QR8+GcNVAq5fOxcElxSFrgZJGhoUO+PPes4C9oiB44f6FTcEoKHD9gYycMB9kich1lguG0DO9v+daZZ9HQyeoUaF50W231TM2Iax1YGD3QLZg674X90HGG7YKuRIenocVCyZgljzS2tAeNog== MIIDXTCCAkWgAwIBAgIJALmVVuDWu4NYMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMjMxMTQzNDQ3WhcNNDgwNjI1MTQzNDQ3WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUCFozgNb1h1M0jzNRSCjhOBnR+uVbVpaWfXYIR+AhWDdEe5ryY+CgavOg8bfLybyzFdehlYdDRgkedEB/GjG8aJw06l0qF4jDOAw0kEygWCu2mcH7XOxRt+YAH3TVHa/Hu1W3WjzkobqqqLQ8gkKWWM27fOgAZ6GieaJBN6VBSMMcPey3HWLBmc+TYJmv1dbaO2jHhKh8pfKw0W12VM8P1PIO8gv4Phu/uuJYieBWKixBEyy0lHjyixYFCR12xdh4CA47q958ZRGnnDUGFVE1QhgRacJCOZ9bd5t9mr8KLaVBYTCJo5ERE8jymab5dPqe5qKfJsCZiqWglbjUo9twIDAQABo1AwTjAdBgNVHQ4EFgQUxpuwcs/CYQOyui+r1G+3KxBNhxkwHwYDVR0jBBgwFoAUxpuwcs/CYQOyui+r1G+3KxBNhxkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAAiWUKs/2x/viNCKi3Y6blEuCtAGhzOOZ9EjrvJ8+COH3Rag3tVBWrcBZ3/uhhPq5gy9lqw4OkvEws99/5jFsX1FJ6MKBgqfuy7yh5s1YfM0ANHYczMmYpZeAcQf2CGAaVfwTTfSlzNLsF2lW/ly7yapFzlYSJLGoVE+OHEu8g5SlNACUEfkXw+5Eghh+KzlIN7R6Q7r2ixWNFBC/jWf7NKUfJyX8qIG5md1YUeT6GBW9Bm2/1/RiO24JTaYlfLdKK9TYb8sG5B+OLab2DImG99CJ25RkAcSobWNF5zD0O6lgOo3cEdB/ksCq3hmtlC/DlLZ/D8CJ+7VuZnS1rR2naQ== sso_user@example.com https://localhost:8080 urn:oasis:names:tc:SAML:2.0:ac:classes:Password 1 group1 SSO User 1 sso_user@example.com ` setFakeClock(t, "2022-08-10T19:42:34.000Z") acsURL, err := url.Parse("https://localhost:8080/api/v1/fleet/sso/callback") require.NoError(t, err) p := dummySAMLProvider(acsURL) p.IDPMetadata.EntityID = "http://localhost:9080/simplesaml/saml2/idp/metadata.php" auth, err := ParseAndVerifySAMLResponse(p, []byte(samlResponse), "idJpL4A6IM6MMBQ9eH", acsURL) require.NoError(t, err) require.NotNil(t, auth) assert.Equal(t, "sso_user@example.com", auth.UserID()) assert.Equal(t, "SSO User 1", auth.UserDisplayName()) } func TestEmptyResponse(t *testing.T) { var auth resp assert.Equal(t, "", auth.UserID()) assert.Equal(t, "", auth.UserDisplayName()) assert.Empty(t, auth.AssertionAttributes()) } func TestUserDisplayName(t *testing.T) { cases := []struct { attrName string values []saml.AttributeValue out string }{ {"name", []saml.AttributeValue{{Value: "Name Surname"}}, "Name Surname"}, {"displayname", []saml.AttributeValue{{Value: "Name Surname"}}, "Name Surname"}, {"displayName", []saml.AttributeValue{{Value: "Name Surname"}}, "Name Surname"}, {"cn", []saml.AttributeValue{{Value: "Name Surname"}}, "Name Surname"}, {"urn:oid:2.5.4.3", []saml.AttributeValue{{Value: "Name Surname"}}, "Name Surname"}, {"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", []saml.AttributeValue{{Value: "Name Surname"}}, "Name Surname"}, {"name", []saml.AttributeValue{{Value: ""}}, ""}, {"", []saml.AttributeValue{{Value: ""}}, ""}, {"displayname", []saml.AttributeValue{{Value: ""}, {Value: "Name Surname"}}, "Name Surname"}, } for _, c := range cases { t.Run(fmt.Sprintf("%s attribute with %v values", c.attrName, c.values), func(t *testing.T) { var auth resp auth.assertion = &saml.Assertion{ AttributeStatements: []saml.AttributeStatement{{Attributes: []saml.Attribute{{Name: c.attrName, Values: c.values}}}}, } assert.Equal(t, c.out, auth.UserDisplayName()) }) } } func TestDecodeOktaResponseWithCustomAttrs(t *testing.T) { const samlResponse = ` http://www.okta.com/exk8glknbnr9Lpdkl5d7 YjhYEzGsKy0vrLtgepjdmeAYf8ZkSiPMsKvSV/QSXZY= REDACTED REDACTED http://www.okta.com/exk8glknbnr9Lpdkl5d7 /W9NXsxZTI5GljYgaUNnl21ZlgF4L4A/npt/mpOyOeg= REDACTED REDACTED foo@example.com example.com urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport observer maintainer bar ` setFakeClock(t, "2023-02-27T17:41:53.505Z") acsURL, err := url.Parse("https://example.com/api/v1/fleet/sso/callback") require.NoError(t, err) p := dummySAMLProvider(acsURL) p.IDPMetadata.EntityID = "http://www.okta.com/exk8glknbnr9Lpdkl5d7" auth, err := ParseAndVerifySAMLResponse(p, []byte(samlResponse), "id1Juy6Mx2IHYxLwsi", acsURL) require.NoError(t, err) require.NotNil(t, auth) assert.Equal(t, "foo@example.com", auth.UserID()) attrs := auth.AssertionAttributes() assert.Equal(t, []fleet.SAMLAttribute{ { Name: "FLEET_JIT_USER_ROLE_TEAM_1", Values: []fleet.SAMLAttributeValue{{ Type: "xs:string", Value: "observer", }}, }, { Name: "FLEET_JIT_USER_ROLE_TEAM_2", Values: []fleet.SAMLAttributeValue{{ Type: "xs:string", Value: "maintainer", }}, }, { Name: "foo", Values: []fleet.SAMLAttributeValue{{ Type: "xs:string", Value: "bar", }}, }, }, attrs) }