Пример #1
0
        public void Saml2Response_Validate_FalseOnReplyFromWrongIdp()
        {
            // A valid response is received, but it is not from the idp that we
            // did send the AuthnRequest to.
            var idp = IdentityProvider.ConfiguredIdentityProviders.First().Value;

            var request = idp.CreateAuthenticateRequest();

            var responseXML =
                @"<?xml version=""1.0"" encoding=""UTF-8""?>
            <saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            ID = ""Saml2Response_Validate_TrueOnCorrectInResponseTo"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z""
            InResponseTo = """ + request.Id + @""">
                <saml2p:Issuer>https://idp.anotheridp.com</saml2p:Issuer>
                <saml2p:Status>
                    <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Requester"" />
                </saml2p:Status>
            </saml2p:Response>";

            responseXML = SignedXmlHelper.SignXml(responseXML);

            var response = Saml2Response.Read(responseXML);

            response.Validate(SignedXmlHelper.TestCert).Should().BeFalse();
        }
Пример #2
0
        public void Saml2Response_Validate_TrueOnMissingInResponseTo_IfAllowed()
        {
            KentorAuthServicesSection.Current.IdentityProviders.First().AllowConfigEdit(true);
            KentorAuthServicesSection.Current.IdentityProviders.First().AllowUnsolicitedAuthnResponse = true;
            KentorAuthServicesSection.Current.IdentityProviders.First().AllowConfigEdit(false);
            var idp = IdentityProvider.ConfiguredIdentityProviders.First().Value;

            var request = idp.CreateAuthenticateRequest();

            var responseXML =
                @"<?xml version=""1.0"" encoding=""UTF-8""?>
            <saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
            ID = ""Saml2Response_Validate_TrueOnCorrectInResponseTo"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z"">
                <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                <saml2p:Status>
                    <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Requester"" />
                </saml2p:Status>
            </saml2p:Response>";

            responseXML = SignedXmlHelper.SignXml(responseXML);

            var response = Saml2Response.Read(responseXML);

            response.Validate(SignedXmlHelper.TestCert).Should().BeTrue();
        }
Пример #3
0
        public void Saml2Response_GetClaims_ThrowsOnResponseNotValid()
        {
            var response =
                @"<?xml version=""1.0"" encoding=""UTF-8""?>
            <saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            ID = ""Saml2Response_GetClaims_ThrowsOnResponseNotValid"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z""
            Issuer = ""https://some.issuer.example.com"">
                <saml2p:Status>
                    <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""
                Version=""2.0"" ID=""Saml2Response_GetClaims_ThrowsOnResponseNotValid_Assertion""
                IssueInstant=""2013-09-25T00:00:00Z"">
                    <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                    <saml2:Subject>
                        <saml2:NameID>SomeUser</saml2:NameID>
                        <saml2:SubjectConfirmation Method=""urn:oasis:names:tc:SAML:2.0:cm:bearer"" />
                    </saml2:Subject>
                </saml2:Assertion>
            </saml2p:Response>";

            response = SignedXmlHelper.SignXml(response);
            response = response.Replace("2013-09-25", "2013-09-26");

            var r = Saml2Response.Read(response);

            r.Validate(SignedXmlHelper.TestCert);
            Action a = () => r.GetClaims();

            a.ShouldThrow <InvalidOperationException>()
            .WithMessage("The Saml2Response didn't pass validation");
        }
Пример #4
0
        public void Saml2Response_GetClaims_ThrowsOnNotValidated()
        {
            var response =
                @"<?xml version=""1.0"" encoding=""UTF-8""?>
            <saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
            ID = ""Saml2Response_GetClaims_ThrowsOnNotValidated"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z"">
                <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                <saml2p:Status>
                    <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Success"" />
                </saml2p:Status>
                <saml2:Assertion
                Version=""2.0"" ID=""Saml2Response_GetClaims_ThrowsOnNotValidated_Assertion""
                IssueInstant=""2013-09-25T00:00:00Z"">
                    <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                    <saml2:Subject>
                        <saml2:NameID>SomeUser</saml2:NameID>
                        <saml2:SubjectConfirmation Method=""urn:oasis:names:tc:SAML:2.0:cm:bearer"" />
                    </saml2:Subject>
                </saml2:Assertion>
            </saml2p:Response>";

            Action a = () => Saml2Response.Read(response).GetClaims();

            a.ShouldThrow <InvalidOperationException>()
            .WithMessage("The Saml2Response must be validated first.");
        }
Пример #5
0
        public void Saml2Response_GetClaims_ThrowsOnExpired()
        {
            var response =
                @"<?xml version=""1.0"" encoding=""UTF-8""?>
            <saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            ID = ""Saml2Response_GetClaims_ThrowsOnExpired"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z""
            Issuer = ""https://some.issuer.example.com"">
                <saml2p:Status>
                    <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""
                Version=""2.0"" ID=""Saml2Response_GetClaims_ThrowsOnExpired_Assertion""
                IssueInstant=""2013-09-25T00:00:00Z"">
                    <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                    <saml2:Subject>
                        <saml2:NameID>SomeUser</saml2:NameID>
                        <saml2:SubjectConfirmation Method=""urn:oasis:names:tc:SAML:2.0:cm:bearer"" />
                    </saml2:Subject>
                    <saml2:Conditions NotOnOrAfter=""2013-06-30T08:00:00Z"" />
                </saml2:Assertion>
            </saml2p:Response>";

            response = SignedXmlHelper.SignXml(response);
            var r = Saml2Response.Read(response);

            r.Validate(SignedXmlHelper.TestCert);

            Action a = () => r.GetClaims();

            a.ShouldThrow <SecurityTokenExpiredException>();
        }
Пример #6
0
        public void Saml2Response_Read_ThrowsWrongRootNodeName()
        {
            Action a = () => Saml2Response.Read("<saml2p:NotResponse xmlns:saml2p=\"urn:oasis:names:tc:SAML:2.0:protocol\" />");

            a.ShouldThrow <XmlException>()
            .WithMessage("Expected a SAML2 assertion document");
        }
Пример #7
0
        public void Saml2Response_Read_ThrowsOnNonXml()
        {
            Action a = () => Saml2Response.Read("not xml");

            a.ShouldThrow <XmlException>()
            .WithMessage("Data at the root level is invalid. Line 1, position 1.");
        }
Пример #8
0
        public void Saml2Response_Read_BasicParams()
        {
            string response =
                @"<?xml version=""1.0"" encoding=""UTF-8""?>
                <saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            ID = ""Saml2Response_Read_BasicParams"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z""
            InResponseTo = ""InResponseToId""
            Destination=""http://destination.example.com"">
                <saml2p:Status>
                    <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Requester"" />
                </saml2p:Status>
            </saml2p:Response>";

            var expected = new
            {
                Id             = new Saml2Id("Saml2Response_Read_BasicParams"),
                IssueInstant   = new DateTime(2013, 01, 01, 0, 0, 0, DateTimeKind.Utc),
                Status         = Saml2StatusCode.Requester,
                Issuer         = (string)null,
                DestinationUri = new Uri("http://destination.example.com"),
                MessageName    = "SAMLResponse",
                InResponseTo   = new Saml2Id("InResponseToId"),
            };

            Saml2Response.Read(response).ShouldBeEquivalentTo(expected,
                                                              opt => opt.Excluding(s => s.XmlDocument));
        }
Пример #9
0
        public void Saml2Response_Validate_FalseOnAssertionInjectionWithAssertionSignature()
        {
            var response =
                @"<saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
            ID = ""Saml2Response_Validate_FalseOnAssertionInjectionWithAssertionSignature"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z"">
                <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                <saml2p:Status>
                    <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Success"" />
                </saml2p:Status>
                {0}
                {1}
            </saml2p:Response>";

            var assertion1 = @"<saml2:Assertion xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
                Version=""2.0"" ID=""Saml2Response_Validate_FalseOnAssertionInjectionWithAssertionSignature_Assertion1""
                IssueInstant=""2013-09-25T00:00:00Z"">
                    <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                    <saml2:Subject>
                        <saml2:NameID>SomeUser</saml2:NameID>
                        <saml2:SubjectConfirmation Method=""urn:oasis:names:tc:SAML:2.0:cm:bearer"" />
                    </saml2:Subject>
                    <saml2:Conditions NotOnOrAfter=""2100-01-01T00:00:00Z"" />
                </saml2:Assertion>";

            var assertionToInject = @"<saml2:Assertion xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
                Version=""2.0"" ID=""Saml2Response_Validate_FalseOnAssertionInjectionWithAssertionSignature_Assertion2""
                IssueInstant=""2013-09-25T00:00:00Z"">
                    <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                    <saml2:Subject>
                        <saml2:NameID>SomeUser2</saml2:NameID>
                        <saml2:SubjectConfirmation Method=""urn:oasis:names:tc:SAML:2.0:cm:bearer"" />
                    </saml2:Subject>
                    <saml2:Conditions NotOnOrAfter=""2100-01-01T00:00:00Z"" />
                </saml2:Assertion>";

            var signedAssertion1 = SignedXmlHelper.SignXml(assertion1);

            var signedAssertion1Doc = new XmlDocument {
                PreserveWhitespace = true
            };

            signedAssertion1Doc.LoadXml(signedAssertion1);

            var signatureToCopy = signedAssertion1Doc.DocumentElement["Signature", SignedXml.XmlDsigNamespaceUrl];

            var assertionToInjectDoc = new XmlDocument {
                PreserveWhitespace = true
            };

            assertionToInjectDoc.LoadXml(assertionToInject);

            assertionToInjectDoc.DocumentElement.AppendChild(assertionToInjectDoc.ImportNode(signatureToCopy, true));

            var signedAssertionToInject = assertionToInjectDoc.OuterXml;

            var signedResponse = string.Format(response, signedAssertion1, signedAssertionToInject);

            Saml2Response.Read(signedResponse).Validate(SignedXmlHelper.TestCert).Should().BeFalse();
        }
Пример #10
0
        public void Saml2Response_Validate_FalseOnTamperedAssertionWithMessageSignature()
        {
            var response =
                @"<saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
            ID = ""Saml2Response_Validate_FalseOnTamperedAssertionWithMessageSignature"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z"">
                <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                <saml2p:Status>
                    <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""
                Version=""2.0"" ID=""Saml2Response_Validate_FalseOnTamperedAssertionWithMessageSignature_Assertion1""
                IssueInstant=""2013-09-25T00:00:00Z"">
                    <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                    <saml2:Subject>
                        <saml2:NameID>SomeUser</saml2:NameID>
                        <saml2:SubjectConfirmation Method=""urn:oasis:names:tc:SAML:2.0:cm:bearer"" />
                    </saml2:Subject>
                    <saml2:Conditions NotOnOrAfter=""2100-01-01T00:00:00Z"" />
                </saml2:Assertion>
            </saml2p:Response>";

            var signedResponse = SignedXmlHelper.SignXml(response).Replace("SomeUser", "SomeOtherUser");

            Saml2Response.Read(signedResponse).Validate(SignedXmlHelper.TestCert).Should().BeFalse();
        }
Пример #11
0
        public void Saml2Response_Read_ThrowsWrongRootNamespace()
        {
            Action a = () => Saml2Response.Read("<saml2p:Response xmlns:saml2p=\"something\" /> ");

            a.ShouldThrow <XmlException>()
            .WithMessage("Expected a SAML2 assertion document");
        }
Пример #12
0
        public void Saml2Response_Validate_TrueOnCorrectSignedSingleAssertionInResponseMessage()
        {
            var response =
                @"<saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
            ID = ""Saml2Response_Validate_TrueOnCorrectSignedSingleAssertionInResponseMessage"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z"">
                <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                <saml2p:Status>
                    <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Success"" />
                </saml2p:Status>
                {0}
            </saml2p:Response>";

            var assertion =
                @"<saml2:Assertion xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
                Version=""2.0"" ID=""Saml2Response_Validate_TrueOnCorrectSignedSingleAssertionInResponseMessagee_Assertion1""
                IssueInstant=""2013-09-25T00:00:00Z"">
                    <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                    <saml2:Subject>
                        <saml2:NameID>SomeUser</saml2:NameID>
                        <saml2:SubjectConfirmation Method=""urn:oasis:names:tc:SAML:2.0:cm:bearer"" />
                    </saml2:Subject>
                    <saml2:Conditions NotOnOrAfter=""2100-01-01T00:00:00Z"" />
                </saml2:Assertion>";


            var signedAssertion = SignedXmlHelper.SignXml(assertion);
            var signedResponse  = string.Format(response, signedAssertion);

            Saml2Response.Read(signedResponse).Validate(SignedXmlHelper.TestCert).Should().BeTrue();
        }
Пример #13
0
        public void Saml2Response_Validate_FalseOnMissingSignatureInResponseAndAnyAssertion()
        {
            var response =
                @"<?xml version=""1.0"" encoding=""UTF-8""?>
            <saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
            ID = ""Saml2Response_Validates_FalseOnMissingSignatureInResponseAndAnyAssertion"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z"">
                <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                <saml2p:Status>
                    <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""
                Version=""2.0"" ID=""Saml2Response_Validates_FalseOnMissingSignatureInResponseAndAnyAssertion_Assertion1""
                IssueInstant=""2013-09-25T00:00:00Z"">
                    <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                    <saml2:Subject>
                        <saml2:NameID>SomeUser</saml2:NameID>
                        <saml2:SubjectConfirmation Method=""urn:oasis:names:tc:SAML:2.0:cm:bearer"" />
                    </saml2:Subject>
                    <saml2:Conditions NotOnOrAfter=""2100-01-01T00:00:00Z"" />
                </saml2:Assertion>
                <saml2:Assertion xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
                Version=""2.0"" ID=""Saml2Response_Validates_FalseOnMissingSignatureInResponseAndAnyAssertion_Assertion2""
                IssueInstant=""2013-09-25T00:00:00Z"">
                    <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                    <saml2:Subject>
                        <saml2:NameID>SomeUser</saml2:NameID>
                        <saml2:SubjectConfirmation Method=""urn:oasis:names:tc:SAML:2.0:cm:bearer"" />
                    </saml2:Subject>
                    <saml2:Conditions NotOnOrAfter=""2100-01-01T00:00:00Z"" />
                </saml2:Assertion>
            </saml2p:Response>";

            Saml2Response.Read(response).Validate(null).Should().BeFalse();
        }
Пример #14
0
        public void Saml2Response_Validate_FalseOnReplayedInResponseTo()
        {
            var idp = IdentityProvider.ConfiguredIdentityProviders.First().Value;

            var request = idp.CreateAuthenticateRequest();

            var responseXML =
                @"<?xml version=""1.0"" encoding=""UTF-8""?>
            <saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
            ID = ""Saml2Response_Validate_TrueOnCorrectInResponseTo"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z""
            InResponseTo = """ + request.Id + @""">
                <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                <saml2p:Status>
                    <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Requester"" />
                </saml2p:Status>
            </saml2p:Response>";

            responseXML = SignedXmlHelper.SignXml(responseXML);

            var response = Saml2Response.Read(responseXML);

            response.Validate(SignedXmlHelper.TestCert).Should().BeTrue();

            response = Saml2Response.Read(responseXML);
            response.Validate(SignedXmlHelper.TestCert).Should().BeFalse();
        }
Пример #15
0
        public void Saml2Response_ToXml()
        {
            string response = @"<?xml version=""1.0"" encoding=""UTF-8""?><saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol"" ID=""Saml2Response_ToXml"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z""><saml2p:Status><saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Requester"" /></saml2p:Status></saml2p:Response>";

            var subject = Saml2Response.Read(response).ToXml();

            subject.Should().Be(response);
        }
Пример #16
0
        public void Saml2Response_Read_ThrowsOnWrongVersion()
        {
            Action a = () => Saml2Response.Read("<saml2p:Response xmlns:saml2p=\""
                                                + Saml2Namespaces.Saml2P + "\" Version=\"wrong\" />");

            a.ShouldThrow <XmlException>()
            .WithMessage("Wrong or unsupported SAML2 version");
        }
Пример #17
0
        public void Saml2Response_Validate_FalseOnMissingSignature()
        {
            var response =
                @"<?xml version=""1.0"" encoding=""UTF-8""?>
            <saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            ID = ""Saml2Response_Validates_FalseOnMissingSignature"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z""
            Issuer = ""https://some.issuer.example.com"">
                <saml2p:Status>
                    <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Requester"" />
                </saml2p:Status>
            </saml2p:Response>";

            Saml2Response.Read(response).Validate(null).Should().BeFalse();
        }
Пример #18
0
        public void Saml2Response_GetClaims_CreateIdentities()
        {
            var response =
                @"<?xml version=""1.0"" encoding=""UTF-8""?>
            <saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
            ID = ""Saml2Response_GetClaims_CreateIdentities"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z"">
                <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                <saml2p:Status>
                    <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Success"" />
                </saml2p:Status>
                <saml2:Assertion
                Version=""2.0"" ID=""Saml2Response_GetClaims_CreateIdentities1""
                IssueInstant=""2013-09-25T00:00:00Z"">
                    <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                    <saml2:Subject>
                        <saml2:NameID>SomeUser</saml2:NameID>
                        <saml2:SubjectConfirmation Method=""urn:oasis:names:tc:SAML:2.0:cm:bearer"" />
                    </saml2:Subject>
                    <saml2:Conditions NotOnOrAfter=""2100-01-01T00:00:00Z"" />
                </saml2:Assertion>
                <saml2:Assertion
                Version=""2.0"" ID=""Saml2Response_GetClaims_CreateIdentities2""
                IssueInstant=""2013-09-25T00:00:00Z"">
                    <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                    <saml2:Subject>
                        <saml2:NameID>SomeOtherUser</saml2:NameID>
                        <saml2:SubjectConfirmation Method=""urn:oasis:names:tc:SAML:2.0:cm:bearer"" />
                    </saml2:Subject>
                    <saml2:Conditions NotOnOrAfter=""2100-01-01T00:00:00Z"" />
                </saml2:Assertion>            
            </saml2p:Response>";

            var c1 = new ClaimsIdentity("Federation");

            c1.AddClaim(new Claim(ClaimTypes.NameIdentifier, "SomeUser", null, "https://idp.example.com"));
            var c2 = new ClaimsIdentity("Federation");

            c2.AddClaim(new Claim(ClaimTypes.NameIdentifier, "SomeOtherUser", null, "https://idp.example.com"));

            var expected = new ClaimsIdentity[] { c1, c2 };

            var r = Saml2Response.Read(SignedXmlHelper.SignXml(response));

            r.Validate(SignedXmlHelper.TestCert);

            r.GetClaims().ShouldBeEquivalentTo(expected, opt => opt.IgnoringCyclicReferences());
        }
Пример #19
0
        public CommandResult Run(HttpRequestData request, IOptions options)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

            var binding = Saml2Binding.Get(request);

            if (binding != null)
            {
                string unpackedPayload = null;
                try
                {
                    unpackedPayload = binding.Unbind(request);
                    var samlResponse = Saml2Response.Read(unpackedPayload);

                    return(ProcessResponse(options, samlResponse));
                }
                catch (FormatException ex)
                {
                    throw new BadFormatSamlResponseException(
                              "The SAML Response did not contain valid BASE64 encoded data.", ex);
                }
                catch (XmlException ex)
                {
                    var newEx = new BadFormatSamlResponseException(
                        "The SAML response contains incorrect XML", ex);

                    // Add the payload to the exception
                    newEx.Data.Add("Saml2Response", unpackedPayload);
                    throw newEx;
                }
                catch (Exception ex)
                {
                    // Add the payload to the existing exception
                    ex.Data.Add("Saml2Response", unpackedPayload);
                    throw;
                }
            }

            throw new NoSamlResponseFoundException();
        }
Пример #20
0
        public void Saml2Response_Read_Issuer()
        {
            var response =
                @"<?xml version=""1.0"" encoding=""UTF-8""?>
            <saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            ID = ""Saml2Respons_Read_Issuer"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z"">
            <saml2:Issuer xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion"">
                https://some.issuer.example.com
            </saml2:Issuer>
                <saml2p:Status>
                    <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Requester"" />
                </saml2p:Status>
            </saml2p:Response>";

            Saml2Response.Read(response).Issuer.Should().Be("https://some.issuer.example.com");
        }
Пример #21
0
        public void Saml2Response_Validate_TrueOnCorrectMessage()
        {
            var response =
                @"<?xml version=""1.0"" encoding=""UTF-8""?>
            <saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            ID = ""Saml2Response_Validate_TrueOnCorrectMessage"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z""
            Issuer = ""https://some.issuer.example.com"">
                <saml2p:Status>
                    <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Requester"" />
                </saml2p:Status>
            </saml2p:Response>";

            var signedResponse = SignedXmlHelper.SignXml(response);

            Saml2Response.Read(signedResponse).Validate(SignedXmlHelper.TestCert).Should().BeTrue();
        }
Пример #22
0
        public void Saml2Response_Validate_FalseOnTamperedMessage()
        {
            var response =
                @"<saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
            ID = ""Saml2Response_Validate_FalseOnTamperedMessage"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z"">
                <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                <saml2p:Status>
                    <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Success"" />
                </saml2p:Status>
            </saml2p:Response>";

            var signedResponse = SignedXmlHelper.SignXml(response);

            signedResponse = signedResponse.Replace("2013-01-01", "2013-01-02");

            Saml2Response.Read(signedResponse).Validate(SignedXmlHelper.TestCert).Should().BeFalse();
        }
Пример #23
0
        public void Saml2Response_Validate_ReturnsExistingResultOnSecondValidateCall()
        {
            var response =
                @"<saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
            ID = ""Saml2Response_Validate_TrueOnCorrectSignedResponseMessage"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z"">
                <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                <saml2p:Status>
                    <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Requester"" />
                </saml2p:Status>
            </saml2p:Response>";

            var signedResponse = SignedXmlHelper.SignXml(response);

            var samlResponse = Saml2Response.Read(signedResponse);

            samlResponse.Validate(SignedXmlHelper.TestCert).Should().BeTrue();
            samlResponse.Validate(SignedXmlHelper.TestCert).Should().BeTrue();
        }
Пример #24
0
        public void Saml2Response_Read_BasicParams()
        {
            string response =
                @"<?xml version=""1.0"" encoding=""UTF-8""?>
                <saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            ID = ""Saml2Response_Read_BasicParams"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z"">
                <saml2p:Status>
                    <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Requester"" />
                </saml2p:Status>
            </saml2p:Response>";

            var expected = new
            {
                Id           = "Saml2Response_Read_BasicParams",
                IssueInstant = new DateTime(2013, 01, 01, 0, 0, 0, DateTimeKind.Utc),
                Status       = Saml2StatusCode.Requester,
                Issuer       = (string)null
            };

            Saml2Response.Read(response).ShouldBeEquivalentTo(expected);
        }
        public static Saml2Response GetSamlToken(string tokenAsBase64String)
        {
            var xml = Encoding.UTF8.GetString(Convert.FromBase64String(tokenAsBase64String));

            var token = Saml2Response.Read(xml);

            IdentityProvider identityProvider;

            if (!samlOptions.IdentityProviders.TryGetValue(token.Issuer, out identityProvider))
            {
                throw new HttpException(401, "Unkown identity provider"); // Probably not the right thing to do...
            }
            Debug.WriteLine(token.Issuer.Id);

            // token.Validate has been made private in the latest AuthServices release so I can't validate the response
            // It will eventually be validated when I do the CreateClaims thing but would be nice to do it explicitly

            //if (!token.Validate(samlOptions))
            //{
            //    throw new HttpException(401, "Invalid SAML token signature");
            //}
            return(token);
        }
Пример #26
0
        public CommandResult Run(HttpRequestData request, IOptions options)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

            var binding = Saml2Binding.Get(request);

            if (binding != null)
            {
                try
                {
                    var samlResponse = Saml2Response.Read(binding.Unbind(request));

                    return(ProcessResponse(options, samlResponse));
                }
                catch (FormatException ex)
                {
                    throw new BadFormatSamlResponseException(
                              "The SAML Response did not contain valid BASE64 encoded data.", ex);
                }
                catch (XmlException ex)
                {
                    throw new BadFormatSamlResponseException(
                              "The SAML response contains incorrect XML", ex);
                }
            }

            throw new NoSamlResponseFoundException();
        }
Пример #27
0
        public void Saml2Response_Validate_FalseOnMissingReferenceInSignature()
        {
            var response =
                @"<saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
            xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
            ID = ""Saml2Response_Validate_FalseOnMissingReference"" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z"">
                <saml2:Issuer>https://idp.example.com</saml2:Issuer>
                <saml2p:Status>
                    <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Requester"" />
                </saml2p:Status>
            </saml2p:Response>";

            var xmlDoc = new XmlDocument();

            xmlDoc.LoadXml(response);

            var signedXml = new SignedXml(xmlDoc);

            signedXml.SigningKey = (RSACryptoServiceProvider)SignedXmlHelper.TestCert.PrivateKey;

            // The .NET implementation prevents creation of signatures without references (which is good)
            // but for this naughty test we want to create such a signature. Let's replace the real implementation
            // with a shim that bypasses the control. Code copied from reference source at
            // http://referencesource.microsoft.com/#System.Security/cryptography/xml/signedinfo.cs
            using (ShimsContext.Create())
            {
                Func <SignedInfo, XmlDocument, XmlElement> signedInfoGetXml =
                    (SignedInfo signedInfo, XmlDocument document) =>
                {
                    // Create the root element
                    XmlElement signedInfoElement = document.CreateElement("SignedInfo", SignedXml.XmlDsigNamespaceUrl);
                    if (!String.IsNullOrEmpty(signedInfo.Id))
                    {
                        signedInfoElement.SetAttribute("Id", signedInfo.Id);
                    }

                    // Add the canonicalization method, defaults to SignedXml.XmlDsigNamespaceUrl

                    // *** GetXml(XmlDocument, string) is internal, call it by reflection. ***
                    // XmlElement canonicalizationMethodElement = signedInfo.CanonicalizationMethodObject.GetXml(document, "CanonicalizationMethod");
                    var transformGetXml = typeof(Transform).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
                                          .Single(m => m.Name == "GetXml" && m.GetParameters().Length == 2);
                    XmlElement canonicalizationMethodElement = (XmlElement)transformGetXml.Invoke(signedInfo.CanonicalizationMethodObject,
                                                                                                  new object[] { document, "CanonicalizationMethod" });

                    signedInfoElement.AppendChild(canonicalizationMethodElement);

                    // Add the signature method
                    if (String.IsNullOrEmpty(signedInfo.SignatureMethod))
                    {
                        throw new CryptographicException("Cryptography_Xml_SignatureMethodRequired");
                    }

                    XmlElement signatureMethodElement = document.CreateElement("SignatureMethod", SignedXml.XmlDsigNamespaceUrl);
                    signatureMethodElement.SetAttribute("Algorithm", signedInfo.SignatureMethod);
                    // Add HMACOutputLength tag if we have one
                    if (signedInfo.SignatureLength != null)
                    {
                        XmlElement hmacLengthElement = document.CreateElement(null, "HMACOutputLength", SignedXml.XmlDsigNamespaceUrl);
                        XmlText    outputLength      = document.CreateTextNode(signedInfo.SignatureLength);
                        hmacLengthElement.AppendChild(outputLength);
                        signatureMethodElement.AppendChild(hmacLengthElement);
                    }

                    signedInfoElement.AppendChild(signatureMethodElement);

                    //*** This is the part of the original source that we want to bypass. ***
                    //// Add the references
                    //if (m_references.Count == 0)
                    //    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_ReferenceElementRequired"));

                    //for (int i = 0; i < m_references.Count; ++i) {
                    //    Reference reference = (Reference)m_references[i];
                    //    signedInfoElement.AppendChild(reference.GetXml(document));
                    //}

                    return(signedInfoElement);
                };

                System.Security.Cryptography.Xml.Fakes.ShimSignedInfo.AllInstances.GetXml =
                    (SignedInfo signedInfo) =>
                {
                    // Copy from SignedInfo.GetXml(XmlDocument)
                    XmlDocument document = new XmlDocument();
                    document.PreserveWhitespace = true;

                    return(signedInfoGetXml(signedInfo, document));
                };

                signedXml.ComputeSignature();

                // Can't call SignedXml.GetXml(); as it calls original SignedInfo.GetXml(XmlDocument). This is
                // pasted / expanded code from SignedXml.GetXml that calls the above shim instead.

                // Create the Signature
                XmlElement signatureElement = (XmlElement)xmlDoc.CreateElement("Signature", SignedXml.XmlDsigNamespaceUrl);
                if (!String.IsNullOrEmpty(signedXml.Signature.Id))
                {
                    signatureElement.SetAttribute("Id", signedXml.Signature.Id);
                }

                // Add the SignedInfo
                if (signedXml.Signature.SignedInfo == null)
                {
                    throw new CryptographicException("Cryptography_Xml_SignedInfoRequired");
                }

                signatureElement.AppendChild(signedInfoGetXml(signedXml.Signature.SignedInfo, xmlDoc));

                // Add the SignatureValue
                if (signedXml.Signature.SignatureValue == null)
                {
                    throw new CryptographicException("Cryptography_Xml_SignatureValueRequired");
                }

                XmlElement signatureValueElement = xmlDoc.CreateElement("SignatureValue", SignedXml.XmlDsigNamespaceUrl);
                signatureValueElement.AppendChild(xmlDoc.CreateTextNode(Convert.ToBase64String(signedXml.Signature.SignatureValue)));

                var m_signatureValueId = (string)typeof(Signature).GetField("m_signatureValueId", BindingFlags.Instance | BindingFlags.NonPublic)
                                         .GetValue(signedXml.Signature);

                if (!String.IsNullOrEmpty(m_signatureValueId))
                {
                    signatureValueElement.SetAttribute("Id", m_signatureValueId);
                }

                signatureElement.AppendChild(signatureValueElement);

                // Add the KeyInfo
                if (signedXml.Signature.KeyInfo.Count > 0)
                {
                    signatureElement.AppendChild((XmlElement)typeof(KeyInfo).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
                                                 .Single(m => m.Name == "GetXml" && m.GetParameters().Length == 1)
                                                 .Invoke(signedXml.Signature.KeyInfo, new object[] { xmlDoc }));
                }

                // Add the Objects
                foreach (Object obj in signedXml.Signature.ObjectList)
                {
                    DataObject dataObj = obj as DataObject;
                    if (dataObj != null)
                    {
                        signatureElement.AppendChild((XmlElement)
                                                     typeof(DataObject).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)
                                                     .Single(m => m.Name == "GetXml" && m.GetParameters().Length == 1)
                                                     .Invoke(dataObj, new object[] { xmlDoc }));
                    }
                }

                xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(signatureElement, true));

                var samlResponse = Saml2Response.Read(xmlDoc.OuterXml);

                samlResponse.Validate(SignedXmlHelper.TestKey).Should().BeFalse();
            }
        }
Пример #28
0
        public void Saml2Response_Read_ThrowsOnNonXml()
        {
            Action a = () => Saml2Response.Read("not xml");

            a.ShouldThrow <XmlException>();
        }