(t *testing.T)
| 716 | } |
| 717 | |
| 718 | func TestSPRejectsInjectedComment(t *testing.T) { |
| 719 | test := NewServiceProviderTest(t) |
| 720 | // An actual response from google |
| 721 | TimeNow = func() time.Time { |
| 722 | rv, _ := time.Parse("Mon Jan 2 15:04:05 UTC 2006", "Tue Jan 5 16:55:39 UTC 2016") |
| 723 | return rv |
| 724 | } |
| 725 | Clock = dsig.NewFakeClockAt(TimeNow()) |
| 726 | |
| 727 | SamlResponse := golden.Get(t, "TestSPRejectsInjectedComment_response") |
| 728 | test.IDPMetadata = golden.Get(t, "TestSPRejectsInjectedComment_IDPMetadata") |
| 729 | |
| 730 | s := ServiceProvider{ |
| 731 | Key: test.Key, |
| 732 | Certificate: test.Certificate, |
| 733 | MetadataURL: mustParseURL("https://29ee6d2e.ngrok.io/saml/metadata"), |
| 734 | AcsURL: mustParseURL("https://29ee6d2e.ngrok.io/saml/acs"), |
| 735 | IDPMetadata: &EntityDescriptor{}, |
| 736 | } |
| 737 | err := xml.Unmarshal(test.IDPMetadata, &s.IDPMetadata) |
| 738 | assert.Check(t, err) |
| 739 | |
| 740 | // this is a valid response |
| 741 | { |
| 742 | req := http.Request{PostForm: url.Values{}} |
| 743 | req.PostForm.Set("SAMLResponse", string(SamlResponse)) |
| 744 | assertion, err := s.ParseResponse(&req, []string{"id-fd419a5ab0472645427f8e07d87a3a5dd0b2e9a6"}) |
| 745 | assert.Check(t, err) |
| 746 | assert.Check(t, is.Equal("ross@octolabs.io", assertion.Subject.NameID.Value)) |
| 747 | } |
| 748 | |
| 749 | // this is a valid response but with a comment injected |
| 750 | { |
| 751 | x, _ := base64.StdEncoding.DecodeString(string(SamlResponse)) |
| 752 | y := strings.Replace(string(x), "ross@octolabs.io", "ross@<!-- and a comment -->octolabs.io", 1) |
| 753 | SamlResponse = []byte(base64.StdEncoding.EncodeToString([]byte(y))) |
| 754 | |
| 755 | req := http.Request{PostForm: url.Values{}} |
| 756 | req.PostForm.Set("SAMLResponse", string(SamlResponse)) |
| 757 | assertion, err := s.ParseResponse(&req, []string{"id-fd419a5ab0472645427f8e07d87a3a5dd0b2e9a6"}) |
| 758 | |
| 759 | // Note: I would expect the injected comment to be stripped and for the signature |
| 760 | // to validate. Less ideal, but not insecure is the case where the comment breaks |
| 761 | // the signature, perhaps because xml-c18n isn't being implemented correctly by |
| 762 | // dsig. |
| 763 | if err == nil { |
| 764 | assert.Check(t, is.Equal("ross@octolabs.io", |
| 765 | assertion.Subject.NameID.Value)) |
| 766 | } |
| 767 | } |
| 768 | |
| 769 | // this is an invalid response with a commend injected per CVE-2018-7340 |
| 770 | // ref: https://duo.com/blog/duo-finds-saml-vulnerabilities-affecting-multiple-implementations |
| 771 | // it *MUST NOT* validate |
| 772 | { |
| 773 | x, _ := base64.StdEncoding.DecodeString(string(SamlResponse)) |
| 774 | y := strings.Replace(string(x), "ross@<!-- and a comment -->octolabs.io", "ross@octolabs.io<!-- and a comment -->.example.com", 1) |
| 775 | SamlResponse = []byte(base64.StdEncoding.EncodeToString([]byte(y))) |
nothing calls this directly
no test coverage detected