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; }
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(); }
/// <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); }
/// <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; }
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); } }
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 { }); } }
/// <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); }
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; } }
/// <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; }
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; } } } }
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); } }
/// <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); } }
/// <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; }
/// <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) { }