public void Saml2SubjectExtensions_ToXElement_SubjectConfirmationData()
        {
            var destination = new Uri("http://sp.example.com");
            var inResponseTo = new Saml2Id("abc123");
            var notOnOrAfter = DateTime.UtcNow.AddMinutes(2);
            var notBefore = DateTime.UtcNow;

            var saml2SubjectConfirmationData = new Saml2SubjectConfirmationData
            {
                NotOnOrAfter = notOnOrAfter,
                InResponseTo = inResponseTo,
                Recipient = destination,
                NotBefore = notBefore
            };

            var confirmation = saml2SubjectConfirmationData.ToXElement();

            confirmation.Attribute("NotOnOrAfter").Value.Should().Be(notOnOrAfter.ToSaml2DateTimeString());

            confirmation.Attribute("NotBefore").Value.Should().Be(notBefore.ToSaml2DateTimeString());

            confirmation.Attribute("Recipient").Value.Should().Be(destination.OriginalString);

            confirmation.Attribute("InResponseTo").Value.Should().Be(inResponseTo.Value);
        }
 /// <summary>
 /// Creates a PendingAuthnRequestData
 /// </summary>
 /// <param name="idp">The EntityId of the IDP the request was sent to</param>
 /// <param name="returnUrl">The Url to redirect back to after a succesful login</param>
 /// <param name="messageId">ID of the SAML message, used to match InResponseTo</param>
 /// <param name="relayData">Aux data that can be stored across the authentication request.</param>
 public StoredRequestState(EntityId idp, Uri returnUrl, Saml2Id messageId, object relayData)
 {
     Idp = idp;
     ReturnUrl = returnUrl;
     MessageId = messageId;
     RelayData = relayData;
 }
Пример #3
0
        private Saml2Response(XmlDocument xml)
        {
            xmlDocument = xml;

            id = new Saml2Id(xml.DocumentElement.Attributes["ID"].Value);

            var parsedInResponseTo = xml.DocumentElement.Attributes["InResponseTo"].GetValueIfNotNull();
            if (parsedInResponseTo != null)
            {
                inResponseTo = new Saml2Id(parsedInResponseTo);
            }

            issueInstant = DateTime.Parse(xml.DocumentElement.Attributes["IssueInstant"].Value,
                CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);

            var statusString = xml.DocumentElement["Status", Saml2Namespaces.Saml2PName]
                ["StatusCode", Saml2Namespaces.Saml2PName].Attributes["Value"].Value;

            status = StatusCodeHelper.FromString(statusString);

            statusMessage = xml.DocumentElement["Status", Saml2Namespaces.Saml2PName]
                ["StatusMessage", Saml2Namespaces.Saml2PName].GetTrimmedTextIfNotNull();

            issuer = new EntityId(xmlDocument.DocumentElement["Issuer", Saml2Namespaces.Saml2Name].GetTrimmedTextIfNotNull());

            var destinationUrlString = xmlDocument.DocumentElement.Attributes["Destination"].GetValueIfNotNull();

            if (destinationUrlString != null)
            {
                destinationUrl = new Uri(destinationUrlString);
            }
        }
 public void PendingAuthnInMemoryStorage_Remove_FalseOnIdNeverIssued()
 {
     var id = new Saml2Id();
     StoredRequestState responseData;
     var container = new PendingAuthnInMemoryStorage();
     container.TryRemove(id, out responseData).Should().BeFalse();
 }
 public void PendingAuthnRequests_Add_ThrowsOnExisting()
 {
     var id = new Saml2Id();
     var requestData = new StoredRequestState(new EntityId("testidp"), new Uri("http://localhost/Return.aspx"));
     PendingAuthnRequests.Add(id, requestData);
     Action a = () => PendingAuthnRequests.Add(id, requestData);
     a.ShouldThrow<InvalidOperationException>();
 }
 public void PendingAuthnRequests_Add_ThrowsOnExisting()
 {
     var id = new Saml2Id();
     var requestIdp = "testidp";
     PendingAuthnRequests.Add(id, requestIdp);
     Action a = () => PendingAuthnRequests.Add(id, requestIdp);
     a.ShouldThrow<InvalidOperationException>();
 }
 public void PendingAuthnRequests_Remove_FalseOnRemovedTwice()
 {
     var id = new Saml2Id();
     var requestData = new StoredRequestState(new EntityId("testidp"), new Uri("http://localhost/Return.aspx"));
     StoredRequestState responseData;
     PendingAuthnRequests.Add(id, requestData);
     PendingAuthnRequests.TryRemove(id, out responseData).Should().BeTrue();
     PendingAuthnRequests.TryRemove(id, out responseData).Should().BeFalse();
 }
Пример #8
0
        /// <summary>
        /// Initializes a new instance of <see cref="Saml2Evidence"/> class from a <see cref="Saml2Id"/>.
        /// </summary>
        /// <param name="idReference"><see cref="Saml2Id"/> containing the evidence.</param>
        public Saml2Evidence(Saml2Id idReference)
        {
            if (null == idReference)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("idReference");
            }

            this.assertionIdReferences.Add(idReference);
        }
 public void PendingAuthnRequests_Remove_FalseOnRemovedTwice()
 {
     var id = new Saml2Id();
     var requestIdp = "testIdp";
     string responseIdp;
     PendingAuthnRequests.Add(id, requestIdp);
     PendingAuthnRequests.TryRemove(id, out responseIdp).Should().BeTrue();
     PendingAuthnRequests.TryRemove(id, out responseIdp).Should().BeFalse();
 }
 public void PendingAuthnRequests_AddRemove()
 {
     var id = new Saml2Id();
     var requestIdp = "testidp";
     PendingAuthnRequests.Add(id, requestIdp);
     string responseIdp;
     PendingAuthnRequests.TryRemove(id, out responseIdp).Should().BeTrue();
     responseIdp.Should().Be(requestIdp);
 }
Пример #11
0
 /// <summary>
 /// Create a response with the supplied data.
 /// </summary>
 /// <param name="issuer">Issuer of the response.</param>
 /// <param name="issuerCertificate">The certificate to use when signing
 /// this response in XML form.</param>
 /// <param name="destinationUri">The destination Uri for the message</param>
 /// <param name="claimsIdentities">Claims identities to be included in the 
 /// response. Each identity is translated into a separate assertion.</param>
 public Saml2Response(string issuer, X509Certificate2 issuerCertificate,
     Uri destinationUri, params ClaimsIdentity[] claimsIdentities)
 {
     this.issuer = issuer;
     this.claimsIdentities = claimsIdentities;
     this.issuerCertificate = issuerCertificate;
     this.destinationUri = destinationUri;
     id = new Saml2Id("id" + Guid.NewGuid().ToString("N"));
     status = Saml2StatusCode.Success;
 }
Пример #12
0
        public Saml2Request()
        {
            Id = new Saml2Id();
            Version = Saml2Constants.VersionNumber;
            IssueInstant = DateTime.UtcNow;
#if DEBUG
            Debug.WriteLine("Message ID: " + Id);
#endif

        }
 /// <summary>
 /// Ctor
 /// </summary>
 /// <param name="idp">The EntityId of the IDP the request was sent to</param>
 /// <param name="returnUrl">The Url to redirect back to after a succesful login</param>
 /// <param name="messageId">ID of the SAML message, used to match InResponseTo</param>
 /// <param name="relayData">Aux data that can be stored across the authentication request.</param>
 public StoredRequestState(
     EntityId idp,
     Uri returnUrl,
     Saml2Id messageId,
     IDictionary<string,string> relayData)
 {
     Idp = idp;
     ReturnUrl = returnUrl;
     MessageId = messageId;
     RelayData = relayData;
 }
 /// <summary>
 /// Stores the StoredRequestState using the Saml2Id
 /// </summary>
 /// <param name="id">The Saml2Id used as key to store the pending authentication data.</param>
 /// <param name="idp">The state of the pending authentication request.</param>
 public void Add(Saml2Id id, StoredRequestState idp)
 {
     lock (container)
     {
         if (container.ContainsKey(id))
         {
             throw new InvalidOperationException("AuthnRequest id can't be reused.");
         }
         container.Add(id, idp);
     }
 }
Пример #15
0
 internal static void Add(Saml2Id id, StoredRequestState idp)
 {
     lock (pendingAuthnRequest)
     {
         if (pendingAuthnRequest.ContainsKey(id))
         {
             throw new InvalidOperationException("AuthnRequest id can't be reused.");
         }
         pendingAuthnRequest.Add(id, idp);
     }
 }
 //private static readonly Dictionary<Saml2Id, StoredRequestState> pendingAuthnRequest = new Dictionary<Saml2Id, StoredRequestState>();
 internal static void Add(Saml2Id id, StoredRequestState idp)
 {
     lock (pendingRequestCache)
     {
         if (pendingRequestCache.Contains(id.Value))
         {
             throw new InvalidOperationException("AuthnRequest id can't be reused.");
         }
         pendingRequestCache.Add(id.Value, idp, new CacheItemPolicy { });
     }
 }
Пример #17
0
        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="xml">Root xml element.</param>
        /// <param name="relayState"></param>
        public Saml2Response(XmlElement xml, string relayState)
        {
            if(xml == null)
            {
                throw new ArgumentNullException(nameof(xml));
            }

            if (xml.LocalName != "Response"
                || xml.NamespaceURI != Saml2Namespaces.Saml2P)
            {
                throw new XmlException("Expected a SAML2 assertion document");
            }

            if (xml.Attributes["Version"].Value != "2.0")
            {
                throw new XmlException("Wrong or unsupported SAML2 version");
            }

            xmlElement = xml;
            RelayState = relayState;

            id = new Saml2Id(xml.Attributes["ID"].Value);

            var parsedInResponseTo = xml.Attributes["InResponseTo"].GetValueIfNotNull();
            if (parsedInResponseTo != null)
            {
                InResponseTo = new Saml2Id(parsedInResponseTo);
            }

            issueInstant = DateTime.Parse(xml.Attributes["IssueInstant"].Value,
                CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);

            var statusString = xml["Status", Saml2Namespaces.Saml2PName]
                ["StatusCode", Saml2Namespaces.Saml2PName].Attributes["Value"].Value;

            status = StatusCodeHelper.FromString(statusString);

            statusMessage = xml["Status", Saml2Namespaces.Saml2PName]
                ["StatusMessage", Saml2Namespaces.Saml2PName].GetTrimmedTextIfNotNull();
            if (xml["Status", Saml2Namespaces.Saml2PName]["StatusCode", Saml2Namespaces.Saml2PName]["StatusCode", Saml2Namespaces.Saml2PName] != null)
            {
                secondLevelStatus = xml["Status", Saml2Namespaces.Saml2PName]["StatusCode", Saml2Namespaces.Saml2PName]["StatusCode", Saml2Namespaces.Saml2PName].Attributes["Value"].Value;
            }

            Issuer = new EntityId(xmlElement["Issuer", Saml2Namespaces.Saml2Name].GetTrimmedTextIfNotNull());

            var destinationUrlString = xmlElement.Attributes["Destination"].GetValueIfNotNull();

            if (destinationUrlString != null)
            {
                DestinationUrl = new Uri(destinationUrlString);
            }
        }
 public void PendingAuthnInMemoryStorage_AddRemove()
 {
     var id = new Saml2Id();
     var requestData = new StoredRequestState(new EntityId("testidp"), new Uri("http://localhost/Return.aspx"));
     var container = new PendingAuthnInMemoryStorage();
     container.Add(id, requestData);
     StoredRequestState responseData;
     container.TryRemove(id, out responseData).Should().BeTrue();
     responseData.Should().Be(requestData);
     responseData.Idp.Id.Should().Be("testidp");
     responseData.ReturnUrl.Should().Be("http://localhost/Return.aspx");
 }
 /// <summary>
 /// Returns the Stored Request State while simultaneously deleting it from storage. 
 /// </summary>
 /// <param name="id"></param>
 /// <param name="idp"></param>
 /// <returns></returns>
 public bool TryRemove(Saml2Id id, out StoredRequestState idp)
 {
     lock (PendingAuthnInMemoryContainer.Container)
     {
         if (id != null && PendingAuthnInMemoryContainer.Container.ContainsKey(id))
         {
             idp = PendingAuthnInMemoryContainer.Container[id];
             return PendingAuthnInMemoryContainer.Container.Remove(id);
         }
         idp = null;
         return false;
     }
 }
 public void PendingAuthnRequests_AddRemove()
 {
     var relayState = RelayStateGenerator.CreateSecureKey();
     var saml2Id = new Saml2Id();
     var requestData = new StoredRequestState(new EntityId("testidp"), new Uri("http://localhost/Return.aspx"), saml2Id);
     PendingAuthnRequests.Add(relayState, requestData);
     StoredRequestState responseData;
     PendingAuthnRequests.TryRemove(relayState, out responseData).Should().BeTrue();
     responseData.Should().Be(requestData);
     responseData.Idp.Id.Should().Be("testidp");
     responseData.ReturnUrl.Should().Be("http://localhost/Return.aspx");
     responseData.MessageId.Should().Be(saml2Id);
 }
Пример #21
0
 internal static bool TryRemove(Saml2Id id, out StoredRequestState idp)
 {
     lock (pendingAuthnRequest)
     {
         if (id != null && pendingAuthnRequest.ContainsKey(id))
         {
             idp = pendingAuthnRequest[id];
             return pendingAuthnRequest.Remove(id);
         }
         idp = null;
         return false;
     }
 }
 /// <summary>
 /// Returns the Stored Request State while simultaneously deleting it from storage. 
 /// </summary>
 /// <param name="id">The Saml2Id key used to retrieve the pending authentication data.</param>
 /// <param name="idp">The state of the pending authentication request.</param>
 /// <returns></returns>
 public bool TryRemove(Saml2Id id, out StoredRequestState idp)
 {
     lock (container)
     {
         if (id != null && container.ContainsKey(id))
         {
             idp = container[id];
             return container.Remove(id);
         }
         idp = null;
         return false;
     }
 }
 internal static bool TryRemove(Saml2Id id, out StoredRequestState idp)
 {
     lock (pendingRequestCache)
     {
         if (id != null && pendingRequestCache.Contains(id.Value))
         {
             idp = pendingRequestCache[id.Value] as StoredRequestState;
             pendingRequestCache.Remove(id.Value);
             return true;
         }
         idp = null;
         return false;
     }
 }
Пример #24
0
 /// <summary>
 /// Create a response with the supplied data.
 /// </summary>
 /// <param name="issuer">Issuer of the response.</param>
 /// <param name="issuerCertificate">The certificate to use when signing
 /// this response in XML form.</param>
 /// <param name="destinationUrl">The destination Uri for the message</param>
 /// <param name="inResponseTo">In response to id</param>
 /// <param name="claimsIdentities">Claims identities to be included in the 
 /// response. Each identity is translated into a separate assertion.</param>
 public Saml2Response(EntityId issuer, X509Certificate2 issuerCertificate,
     Uri destinationUrl, string inResponseTo, params ClaimsIdentity[] claimsIdentities)
 {
     this.issuer = issuer;
     this.claimsIdentities = claimsIdentities;
     this.issuerCertificate = issuerCertificate;
     this.destinationUrl = destinationUrl;
     if (inResponseTo != null)
     {
         this.inResponseTo = new Saml2Id(inResponseTo);
     }
     id = new Saml2Id("id" + Guid.NewGuid().ToString("N"));
     status = Saml2StatusCode.Success;
 }
Пример #25
0
        public Saml2Response ToSaml2Response()
        {
            var claims =
                new Claim[] { new Claim(ClaimTypes.NameIdentifier, NameId) }
                .Concat((AttributeStatements ?? Enumerable.Empty<AttributeStatementModel>()).Select(att => new Claim(att.Type, att.Value)));
            var identity = new ClaimsIdentity(claims);

            Saml2Id saml2Id = null;
            if (!String.IsNullOrEmpty(InResponseTo))
            {
                saml2Id = new Saml2Id(InResponseTo);
            }

            return new Saml2Response(
                new EntityId(UrlResolver.MetadataUrl.ToString()),
                CertificateHelper.SigningCertificate, new Uri(AssertionConsumerServiceUrl),
                saml2Id, RelayState, identity);
        }
        public StoredRequestState(byte[] data)
        {
            using (var ms = new MemoryStream(data))
            using (var r = new BinaryReader(ms, Encoding.UTF8, true))
            {
                var idp = r.ReadString();
                if(!string.IsNullOrEmpty(idp))
                {
                    Idp = new EntityId(idp);
                }

                var returnUrl = r.ReadString();
                if(!string.IsNullOrEmpty(returnUrl))
                {
                    ReturnUrl = new Uri(returnUrl);
                }

                var messageId = r.ReadString();
                if(!string.IsNullOrEmpty(messageId))
                {
                    MessageId = new Saml2Id(messageId);
                }

                var hasRelayData = r.ReadBoolean();
                if(hasRelayData)
                {
                    RelayData = new Dictionary<string, string>();
                    var count = r.ReadInt32();
                    for(int i = 0; i < count; i++)
                    {
                        var key = r.ReadString();
                        string value = null;
                        var hasValue = r.ReadBoolean();
                        if (hasValue)
                        {
                            value = r.ReadString();
                        }
                        RelayData[key] = value;
                    }
                }
            }
        }
Пример #27
0
        internal virtual void Read(string xml, bool validateXmlSignature = false)
        {
#if DEBUG
            Debug.WriteLine("Saml2P: " + xml);
#endif
            
            XmlDocument = xml.ToXmlDocument();

            if (XmlDocument.DocumentElement.NamespaceURI != Saml2Constants.ProtocolNamespace.OriginalString)
            {
                throw new Saml2ResponseException("Not SAML2 Protocol.");
            }

            ValidateElementName();

            Id = new Saml2Id(XmlDocument.DocumentElement.Attributes[Saml2Constants.Message.Id].GetValueOrNull());

            Version = XmlDocument.DocumentElement.Attributes[Saml2Constants.Message.Version].GetValueOrNull();
            if (Version != Saml2Constants.VersionNumber)
            {
                throw new Saml2ResponseException("Invalid SAML2 version.");
            }

            IssueInstant = DateTime.Parse(XmlDocument.DocumentElement.Attributes[Saml2Constants.Message.IssueInstant].GetValueOrNull(), CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);

            var issuerString = XmlDocument.DocumentElement[Saml2Constants.Message.Issuer, Saml2Constants.AssertionNamespace.OriginalString].GetTextOrNull();
            if (!string.IsNullOrEmpty(issuerString))
            {
                Issuer = new EndpointReference(issuerString);
            }

            var destinationString = XmlDocument.DocumentElement.Attributes[Saml2Constants.Message.Destination].GetValueOrNull();
            if (!string.IsNullOrEmpty(destinationString))
            {
                Destination = new EndpointAddress(destinationString);
            }
        }
Пример #28
0
        /// <summary>
        /// Reads the request properties present in Saml2RequestBase
        /// Also validates basic properties of the request
        /// </summary>
        /// <param name="xml">The xml document to parse</param>
        protected void ReadBaseProperties(XmlElement xml)
        {
            if (xml == null)
            {
                throw new ArgumentNullException(nameof(xml));
            }
            ValidateCorrectDocument(xml);
            Id = new Saml2Id(xml.Attributes["ID"].Value);

            var destination = xml.Attributes["Destination"];
            if(destination != null)
            {
                DestinationUrl = new Uri(destination.Value);
            }

            var issuerNode = xml["Issuer", Saml2Namespaces.Saml2Name];
            if(issuerNode != null)
            {
                Issuer = new EntityId(issuerNode.InnerXml);
            }
        }
Пример #29
0
 /// <summary>
 /// Create a response with the supplied data.
 /// </summary>
 /// <param name="issuer">Issuer of the response.</param>
 /// <param name="issuerCertificate">The certificate to use when signing
 /// this response in XML form.</param>
 /// <param name="destinationUrl">The destination Uri for the message</param>
 /// <param name="inResponseTo">In response to id</param>
 /// <param name="relayState">RelayState associated with the message.</param>
 /// <param name="claimsIdentities">Claims identities to be included in the 
 /// response. Each identity is translated into a separate assertion.</param>
 public Saml2Response(
     EntityId issuer,
     X509Certificate2 issuerCertificate,
     Uri destinationUrl,
     Saml2Id inResponseTo,
     string relayState,
     params ClaimsIdentity[] claimsIdentities)
 {
     Issuer = issuer;
     this.claimsIdentities = claimsIdentities;
     SigningCertificate = issuerCertificate;
     DestinationUrl = destinationUrl;
     RelayState = relayState;
     InResponseTo = inResponseTo;
     id = new Saml2Id("id" + Guid.NewGuid().ToString("N"));
     status = Saml2StatusCode.Success;
 }
Пример #30
0
 /// <summary>
 /// Create a response with the supplied data.
 /// </summary>
 /// <param name="issuer">Issuer of the response.</param>
 /// <param name="signingCertificate">The certificate to use when signing
 /// this response in XML form.</param>
 /// <param name="destinationUrl">The destination Uri for the message</param>
 /// <param name="inResponseTo">In response to id</param>
 /// <param name="claimsIdentities">Claims identities to be included in the 
 /// response. Each identity is translated into a separate assertion.</param>
 public Saml2Response(
     EntityId issuer,
     X509Certificate2 signingCertificate,
     Uri destinationUrl,
     Saml2Id inResponseTo,
     params ClaimsIdentity[] claimsIdentities)
     : this(issuer, signingCertificate, destinationUrl, inResponseTo, null, claimsIdentities)
 { }