/// <summary> /// Creates a Saml2Assertion from a ClaimsIdentity. /// </summary> /// <returns>Saml2Assertion</returns> public static Saml2Assertion ToSaml2Assertion(this ClaimsIdentity identity, EntityId issuer) { if (identity == null) { throw new ArgumentNullException("identity"); } if (issuer == null) { throw new ArgumentNullException("issuer"); } var assertion = new Saml2Assertion(new Saml2NameIdentifier(issuer.Id)); assertion.Subject = new Saml2Subject(new Saml2NameIdentifier( identity.Claims.Single(c => c.Type == ClaimTypes.NameIdentifier).Value)); foreach (var claim in identity.Claims.Where(c => c.Type != ClaimTypes.NameIdentifier).GroupBy(c => c.Type)) { assertion.Statements.Add(new Saml2AttributeStatement(new Saml2Attribute(claim.Key, claim.Select(c => c.Value)))); }; assertion.Conditions = new Saml2Conditions() { NotOnOrAfter = DateTime.UtcNow.AddMinutes(2) }; return assertion; }
/// <summary> /// Creates a Saml2Assertion from a ClaimsIdentity. /// </summary> /// <param name="identity">Claims to include in Assertion.</param> /// <param name="issuer">Issuer to include in assertion.</param> /// <param name="audience">Audience to set as audience restriction.</param> /// <returns>Saml2Assertion</returns> public static Saml2Assertion ToSaml2Assertion( this ClaimsIdentity identity, EntityId issuer, Uri audience) { if (identity == null) { throw new ArgumentNullException(nameof(identity)); } if (issuer == null) { throw new ArgumentNullException(nameof(issuer)); } var assertion = new Saml2Assertion(new Saml2NameIdentifier(issuer.Id)) { Subject = new Saml2Subject(new Saml2NameIdentifier( identity.Claims.Single(c => c.Type == ClaimTypes.NameIdentifier).Value)), }; assertion.Statements.Add( new Saml2AuthenticationStatement( new Saml2AuthenticationContext( new Uri("urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified"))) { SessionIndex = identity.Claims.SingleOrDefault( c => c.Type == AuthServicesClaimTypes.SessionIndex)?.Value }); var attributeClaims = identity.Claims.Where( c => c.Type != ClaimTypes.NameIdentifier && c.Type != AuthServicesClaimTypes.SessionIndex).GroupBy(c => c.Type); if (attributeClaims.Any()) { assertion.Statements.Add( new Saml2AttributeStatement( attributeClaims.Select( ac => new Saml2Attribute(ac.Key, ac.Select(c => c.Value))))); } assertion.Conditions = new Saml2Conditions() { NotOnOrAfter = DateTime.UtcNow.AddMinutes(2) }; if(audience != null) { assertion.Conditions.AudienceRestrictions.Add( new Saml2AudienceRestriction(audience)); } return assertion; }
private void ValidateRecipient(Saml2Assertion assertion) { var actual = assertion.Subject.SubjectConfirmations[0].SubjectConfirmationData.Recipient; if (actual != allowedRecipient) throw new SecurityTokenException(string.Format("Message=Recipient not valid, Expected={0}, Actual={1}", allowedRecipient, actual)); }
/// <summary> /// Initializes a new instance of <see cref="Saml2Evidence"/> class from a <see cref="Saml2Assertion"/>. /// </summary> /// <param name="assertion"><see cref="Saml2Assertion"/> containing the evidence.</param> public Saml2Evidence(Saml2Assertion assertion) { if (null == assertion) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("assertion"); } this.assertions.Add(assertion); }
private void ValidateNotOnOrAfter(Saml2Assertion assertion) { DateTime now = DateTime.UtcNow; if (assertion.Subject.SubjectConfirmations[0].SubjectConfirmationData.NotOnOrAfter == null) throw new SecurityTokenExpiredException(string.Format("Message=NotOnOrAfter is missing")); var subjectNotOnOrAfter = assertion.Subject.SubjectConfirmations[0].SubjectConfirmationData.NotOnOrAfter + Configuration.MaxClockSkew.Negate(); if (subjectNotOnOrAfter < now) throw new SecurityTokenExpiredException(string.Format("Message=NotOnOrAfter invalid on SubjectConfirmationData, NotOnOrAfter={0}, now={1}", subjectNotOnOrAfter, now)); }
public string ToXml(Saml2Assertion assertion) { var tokenHandlers = new Saml2SecurityTokenHandler(); var stringBuilder = new StringBuilder(); using (var xmlWriter = new XmlTextWriter(new StringWriter(stringBuilder))) { var token = new Saml2SecurityToken(assertion); tokenHandlers.WriteToken(xmlWriter, token); return stringBuilder.ToString(); } }
public static SecurityToken MakeBootstrapSecurityToken() { Saml2NameIdentifier identifier = new Saml2NameIdentifier("http://localhost/Echo"); Saml2Assertion assertion = new Saml2Assertion(identifier); assertion.Issuer = new Saml2NameIdentifier("idp1.test.oio.dk"); assertion.Subject = new Saml2Subject(new Saml2NameIdentifier("Casper", new Uri("urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"))); Saml2Attribute atribute = new Saml2Attribute("dk:gov:saml:attribute:AssuranceLevel", "2"); atribute.NameFormat = new Uri("urn:oasis:names:tc:SAML:2.0:attrname-format:basic"); assertion.Statements.Add(new Saml2AttributeStatement(atribute)); return new Saml2SecurityToken(assertion); }
public void Saml2AssertionExtensions_ToXElement_Subject() { var subjectName = "JohnDoe"; var assertion = new Saml2Assertion( new Saml2NameIdentifier("http://idp.example.com")) { Subject = new Saml2Subject(new Saml2NameIdentifier(subjectName)) }; var subject = assertion.ToXElement(); subject.Element(Saml2Namespaces.Saml2 + "Subject"). Element(Saml2Namespaces.Saml2 + "NameID").Value.Should().Be(subjectName); }
/// <summary> /// Initializes an instance of <see cref="Saml2SecurityToken"/> from a <see cref="Saml2Assertion"/>. /// </summary> /// <param name="assertion">A <see cref="Saml2Assertion"/> to initialize from.</param> /// <param name="keys">A collection of <see cref="SecurityKey"/> to include in the token.</param> /// <param name="issuerToken">A <see cref="SecurityToken"/> representing the issuer.</param> public Saml2SecurityToken(Saml2Assertion assertion, ReadOnlyCollection <SecurityKey> keys, SecurityToken issuerToken) { if (null == assertion) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("assertion"); } if (null == keys) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("keys"); } this.assertion = assertion; this.keys = keys; this.issuerToken = issuerToken; }
public void Saml2AssertionExtensions_ToXElement_Conditions() { var assertion = new Saml2Assertion( new Saml2NameIdentifier("http://idp.example.com")) { Conditions = new Saml2Conditions() { NotOnOrAfter = new DateTime(2099, 07, 25, 19, 52, 42, DateTimeKind.Utc) } }; var subject = assertion.ToXElement(); subject.Element(Saml2Namespaces.Saml2 + "Conditions") .Attribute("NotOnOrAfter").Value.Should().Be("2099-07-25T19:52:42Z"); }
/// <summary> /// Creates a Saml2Assertion from a ClaimsIdentity. /// </summary> /// <returns>Saml2Assertion</returns> public static Saml2Assertion ToSaml2Assertion(this ClaimsIdentity identity, string issuer) { if (identity == null) { throw new ArgumentNullException("identity"); } var assertion = new Saml2Assertion(new Saml2NameIdentifier(issuer)); assertion.Subject = new Saml2Subject(new Saml2NameIdentifier( identity.Claims.Single(c => c.Type == ClaimTypes.NameIdentifier).Value)); assertion.Conditions = new Saml2Conditions() { NotOnOrAfter = DateTime.UtcNow.AddMinutes(2) }; return assertion; }
private Saml2Assertion NewAssertion() { var assertion = new Saml2Assertion(new Saml2NameIdentifier(certificate.Subject)); assertion.Id = new Saml2Id(); assertion.IssueInstant = DateTime.Now; assertion.Subject = new Saml2Subject(new Saml2NameIdentifier("CPS") { Value = "id3" }); assertion.Statements.Add(new Saml2AttributeStatement(new Saml2Attribute("identifiantFacturation", "id1"))); assertion.Statements.Add(new Saml2AttributeStatement(new Saml2Attribute("codeSpecialiteAMO", "id2"))); var saml2SubjectConfirmation = new Saml2SubjectConfirmation(new Uri("urn:oasis:names:tc:SAML:2.0:cm:bearer")); saml2SubjectConfirmation.SubjectConfirmationData = new Saml2SubjectConfirmationData(); saml2SubjectConfirmation.SubjectConfirmationData.Recipient = new Uri("http://identityserver3"); saml2SubjectConfirmation.SubjectConfirmationData.NotOnOrAfter = DateTime.UtcNow; assertion.Subject.SubjectConfirmations.Add(saml2SubjectConfirmation); assertion.SigningCredentials = new X509SigningCredentials(certificate); return assertion; }
public void Saml2AssertionExtensions_ToXElement_Xml_BasicAttributes() { // Grab the current time before and after creating the assertion to // handle the unlikely event that the second part of the date time // is incremented during the test run. We don't want any heisenbugs. var before = DateTime.UtcNow.ToSaml2DateTimeString(); var issuer = "http://idp.example.com"; var assertion = new Saml2Assertion(new Saml2NameIdentifier(issuer)); var after = DateTime.UtcNow.ToSaml2DateTimeString(); var subject = assertion.ToXElement(); subject.ToString().Should().StartWith( @"<saml2:Assertion xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion"); subject.Attribute("Version").Value.Should().Be("2.0"); subject.Attribute("ID").Value.Should().NotBeBlank(); subject.Attribute("IssueInstant").Value.Should().Match( i => i == before || i == after); }
private string GetExpected(Saml2Assertion assertion) { return string.Format(@" <Assertion ID=""{0}"" IssueInstant=""{1}"" Version=""2.0"" xmlns=""urn:oasis:names:tc:SAML:2.0:assertion""> <Issuer>{2}</Issuer> <Signature xmlns=""http://www.w3.org/2000/09/xmldsig#""> <SignedInfo> <CanonicalizationMethod Algorithm=""http://www.w3.org/2001/10/xml-exc-c14n#"" /> <SignatureMethod Algorithm=""http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"" /> <Reference URI=""#{0}""> <Transforms> <Transform Algorithm=""http://www.w3.org/2000/09/xmldsig#enveloped-signature"" /> <Transform Algorithm=""http://www.w3.org/2001/10/xml-exc-c14n#"" /> </Transforms> <DigestMethod Algorithm=""http://www.w3.org/2001/04/xmlenc#sha256"" /> ", assertion.Id.Value, assertion.IssueInstant.ToUniversalTime().ToString(Generated), certificate.IssuerName.Name ) .RemoveNewLineSymbols() .RemoveXmlIndentation(); }
internal ReadOnlyCollection<SecurityKey> ResolveSecurityKeys(Saml2Assertion assertion, SecurityTokenResolver resolver) { Saml2Subject subject = assertion.Subject; Saml2SubjectConfirmation confirmation = subject.SubjectConfirmations[0]; if (confirmation.SubjectConfirmationData != null) { this.ValidateConfirmationData(confirmation.SubjectConfirmationData); } List<SecurityKey> list = new List<SecurityKey>(); foreach (SecurityKeyIdentifier identifier in confirmation.SubjectConfirmationData.KeyIdentifiers) { SecurityKey key = null; foreach (SecurityKeyIdentifierClause clause in identifier) { if ((resolver != null) && resolver.TryResolveSecurityKey(clause, out key)) { list.Add(key); break; } } if (key == null) { if (identifier.CanCreateKey) { key = identifier.CreateKey(); list.Add(key); continue; } list.Add(new SecurityKeyElement(identifier, resolver)); } } return list.AsReadOnly(); }
/// <summary> /// Resolves the Signing Key Identifier to a SecurityToken. /// </summary> /// <param name="assertion">The Assertion for which the Issuer token is to be resolved.</param> /// <param name="issuerResolver">The current SecurityTokenResolver associated with this handler.</param> /// <returns>Instance of SecurityToken</returns> /// <exception cref="ArgumentNullException">Input parameter 'assertion' is null.</exception> /// <exception cref="SecurityTokenException">Unable to resolve token.</exception> protected virtual SecurityToken ResolveIssuerToken(Saml2Assertion assertion, SecurityTokenResolver issuerResolver) { if (null == assertion) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("assertion"); } SecurityToken token; if (this.TryResolveIssuerToken(assertion, issuerResolver, out token)) { return token; } else { string exceptionMessage = SR.GetString(assertion.SigningCredentials == null ? SR.ID4141 : SR.ID4142); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(exceptionMessage)); } }
public void Saml2Response_GetClaims_CorrectEncryptedSingleAssertion_UsingWIF() { 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 = """ + MethodBase.GetCurrentMethod().Name + @""" 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 = new Saml2Assertion(new Saml2NameIdentifier("https://idp.example.com")); assertion.Subject = new Saml2Subject(new Saml2NameIdentifier("WIFUser")); assertion.Subject.SubjectConfirmations.Add(new Saml2SubjectConfirmation(new Uri("urn:oasis:names:tc:SAML:2.0:cm:bearer"))); assertion.Conditions = new Saml2Conditions { NotOnOrAfter = new DateTime(2100, 1, 1) }; var token = new Saml2SecurityToken(assertion); var handler = new Saml2SecurityTokenHandler(); assertion.SigningCredentials = new X509SigningCredentials(SignedXmlHelper.TestCert, signatureAlgorithm: SecurityAlgorithms.RsaSha1Signature, digestAlgorithm: SecurityAlgorithms.Sha1Digest); assertion.EncryptingCredentials = new EncryptedKeyEncryptingCredentials( SignedXmlHelper.TestCert2, keyWrappingAlgorithm: SecurityAlgorithms.RsaOaepKeyWrap, keySizeInBits: 256, encryptionAlgorithm: SecurityAlgorithms.Aes192Encryption); string assertionXml = String.Empty; using (var sw = new StringWriter()) { using (var xw = XmlWriter.Create(sw, new XmlWriterSettings { OmitXmlDeclaration = true })) { handler.WriteToken(xw, token); } assertionXml = sw.ToString(); } var responseWithAssertion = string.Format(response, assertionXml); var claims = Saml2Response.Read(responseWithAssertion).GetClaims(Options.FromConfiguration); claims.Count().Should().Be(1); claims.First().FindFirst(ClaimTypes.NameIdentifier).Value.Should().Be("WIFUser"); }
public WrappedSerializer(Saml2SecurityTokenHandler parent, Saml2Assertion assertion) { this.assertion = assertion; this.parent = parent; }
/// <summary> /// Deserializes the SAML Signing KeyInfo /// </summary> /// <param name="reader">A <see cref="XmlReader"/> positioned at a than can be positioned at a ds:KeyInfo element.</param> /// <param name="assertion">The <see cref="Saml2Assertion"/> that is having the signature checked.</param> /// <returns>The <see cref="SecurityKeyIdentifier"/> that defines the key to use to check the signature.</returns> /// <exception cref="ArgumentNullException">Input parameter 'reader' is null.</exception> protected virtual SecurityKeyIdentifier ReadSigningKeyInfo(XmlReader reader, Saml2Assertion assertion) { if (null == reader) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader"); } SecurityKeyIdentifier ski; if (this.KeyInfoSerializer.CanReadKeyIdentifier(reader)) { ski = this.KeyInfoSerializer.ReadKeyIdentifier(reader); } else { KeyInfo keyInfo = new KeyInfo(this.KeyInfoSerializer); keyInfo.ReadXml(XmlDictionaryReader.CreateDictionaryReader(reader)); ski = keyInfo.KeyIdentifier; } // no key info if (ski.Count == 0) { return new SecurityKeyIdentifier(new Saml2SecurityKeyIdentifierClause(assertion)); } return ski; }
/// <summary> /// Serializes the provided SamlAssertion to the XmlWriter. /// </summary> /// <param name="writer">A <see cref="XmlWriter"/> to serialize the <see cref="Saml2Assertion"/>.</param> /// <param name="data">The <see cref="Saml2Assertion"/> to serialize.</param> /// <exception cref="ArgumentNullException">The <paramref name="writer"/> or <paramref name="data"/> parameters are null.</exception> /// <exception cref="InvalidOperationException"> The <paramref name="data"/> has both <see cref="EncryptingCredentials"/> and <see cref="ReceivedEncryptingCredentials"/> properties null.</exception> /// <exception cref="InvalidOperationException">The <paramref name="data"/> must have a <see cref="Saml2Subject"/> if no <see cref="Saml2Statement"/> are present.</exception> /// <exception cref="InvalidOperationException">The SAML2 authentication, attribute, and authorization decision <see cref="Saml2Statement"/> require a <see cref="Saml2Subject"/>.</exception> /// <exception cref="CryptographicException">Token encrypting credentials must have a Symmetric Key specified.</exception> protected virtual void WriteAssertion(XmlWriter writer, Saml2Assertion data) { if (null == writer) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer"); } if (null == data) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("data"); } XmlWriter originalWriter = writer; MemoryStream plaintextStream = null; XmlDictionaryWriter plaintextWriter = null; // If an EncryptingCredentials is present then check if this is not of type ReceivedEncryptinCredentials. // ReceivedEncryptingCredentials mean that it was credentials that were hydrated from a token received // on the wire. We should not directly use this while re-serializing a token. if ((null != data.EncryptingCredentials) && !(data.EncryptingCredentials is ReceivedEncryptingCredentials)) { plaintextStream = new MemoryStream(); writer = plaintextWriter = XmlDictionaryWriter.CreateTextWriter(plaintextStream, Encoding.UTF8, false); } else if (data.ExternalEncryptedKeys == null || data.ExternalEncryptedKeys.Count > 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID4173))); } // If we've saved off the token stream, re-emit it. if (data.CanWriteSourceData) { data.WriteSourceData(writer); } else { // Wrap the writer if necessary for a signature // We do not dispose this writer, since as a delegating writer it would // dispose the inner writer, which we don't properly own. EnvelopedSignatureWriter signatureWriter = null; if (null != data.SigningCredentials) { #pragma warning suppress 56506 writer = signatureWriter = new EnvelopedSignatureWriter(writer, data.SigningCredentials, data.Id.Value, new WrappedSerializer(this, data)); } if (null == data.Subject) { // An assertion with no statements MUST contain a <Subject> element. [Saml2Core, line 585] if (data.Statements == null || 0 == data.Statements.Count) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID4106))); } // Furthermore, the built-in statement types all require the presence of a subject. // [Saml2Core, lines 1050, 1168, 1280] foreach (Saml2Statement statement in data.Statements) { if (statement is Saml2AuthenticationStatement || statement is Saml2AttributeStatement || statement is Saml2AuthorizationDecisionStatement) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException(SR.GetString(SR.ID4119))); } } } // <Assertion> writer.WriteStartElement(Saml2Constants.Elements.Assertion, Saml2Constants.Namespace); // @ID - required writer.WriteAttributeString(Saml2Constants.Attributes.ID, data.Id.Value); // @IssueInstant - required writer.WriteAttributeString(Saml2Constants.Attributes.IssueInstant, XmlConvert.ToString(data.IssueInstant.ToUniversalTime(), DateTimeFormats.Generated)); // @Version - required writer.WriteAttributeString(Saml2Constants.Attributes.Version, data.Version); // <Issuer> 1 this.WriteIssuer(writer, data.Issuer); // <ds:Signature> 0-1 if (null != signatureWriter) { signatureWriter.WriteSignature(); } // <Subject> 0-1 if (null != data.Subject) { this.WriteSubject(writer, data.Subject); } // <Conditions> 0-1 if (null != data.Conditions) { this.WriteConditions(writer, data.Conditions); } // <Advice> 0-1 if (null != data.Advice) { this.WriteAdvice(writer, data.Advice); } // <Statement|AuthnStatement|AuthzDecisionStatement|AttributeStatement>, 0-OO foreach (Saml2Statement statement in data.Statements) { this.WriteStatement(writer, statement); } writer.WriteEndElement(); } // Finish off the encryption if (null != plaintextWriter) { ((IDisposable)plaintextWriter).Dispose(); plaintextWriter = null; EncryptedDataElement encryptedData = new EncryptedDataElement(); encryptedData.Type = XmlEncryptionConstants.EncryptedDataTypes.Element; encryptedData.Algorithm = data.EncryptingCredentials.Algorithm; encryptedData.KeyIdentifier = data.EncryptingCredentials.SecurityKeyIdentifier; // Get the encryption key, which must be symmetric SymmetricSecurityKey encryptingKey = data.EncryptingCredentials.SecurityKey as SymmetricSecurityKey; if (encryptingKey == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(SR.GetString(SR.ID3064))); } // Do the actual encryption SymmetricAlgorithm symmetricAlgorithm = encryptingKey.GetSymmetricAlgorithm(data.EncryptingCredentials.Algorithm); encryptedData.Encrypt(symmetricAlgorithm, plaintextStream.GetBuffer(), 0, (int)plaintextStream.Length); ((IDisposable)plaintextStream).Dispose(); originalWriter.WriteStartElement(Saml2Constants.Elements.EncryptedAssertion, Saml2Constants.Namespace); encryptedData.WriteXml(originalWriter, this.KeyInfoSerializer); foreach (EncryptedKeyIdentifierClause clause in data.ExternalEncryptedKeys) { this.KeyInfoSerializer.WriteKeyIdentifierClause(originalWriter, clause); } originalWriter.WriteEndElement(); } }
/// <summary> /// Reads the <saml:Assertion> element. /// </summary> /// <param name="reader">A <see cref="XmlReader"/> positioned at a <see cref="Saml2Assertion"/> element.</param> /// <returns>A <see cref="Saml2Assertion"/> instance.</returns> protected virtual Saml2Assertion ReadAssertion(XmlReader reader) { if (null == reader) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader"); } if (this.Configuration == null) { throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID4274)); } if (this.Configuration.IssuerTokenResolver == null) { throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID4275)); } if (this.Configuration.ServiceTokenResolver == null) { throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID4276)); } XmlDictionaryReader plaintextReader = XmlDictionaryReader.CreateDictionaryReader(reader); Saml2Assertion assertion = new Saml2Assertion(new Saml2NameIdentifier("__TemporaryIssuer__")); // If it's an EncryptedAssertion, we need to retrieve the plaintext // and repoint our reader if (reader.IsStartElement(Saml2Constants.Elements.EncryptedAssertion, Saml2Constants.Namespace)) { EncryptingCredentials encryptingCredentials = null; plaintextReader = CreatePlaintextReaderFromEncryptedData( plaintextReader, Configuration.ServiceTokenResolver, this.KeyInfoSerializer, assertion.ExternalEncryptedKeys, out encryptingCredentials); assertion.EncryptingCredentials = encryptingCredentials; } // Throw if wrong element if (!plaintextReader.IsStartElement(Saml2Constants.Elements.Assertion, Saml2Constants.Namespace)) { plaintextReader.ReadStartElement(Saml2Constants.Elements.Assertion, Saml2Constants.Namespace); } // disallow empty if (plaintextReader.IsEmptyElement) { #pragma warning suppress 56504 // bogus - thinks plaintextReader.LocalName, plaintextReader.NamespaceURI need validation throw DiagnosticUtility.ThrowHelperXml(plaintextReader, SR.GetString(SR.ID3061, plaintextReader.LocalName, plaintextReader.NamespaceURI)); } // Construct a wrapped serializer so that the EnvelopedSignatureReader's // attempt to read the <ds:KeyInfo> will hit our ReadKeyInfo virtual. WrappedSerializer wrappedSerializer = new WrappedSerializer(this, assertion); // SAML supports enveloped signature, so we need to wrap our reader. // We do not dispose this reader, since as a delegating reader it would // dispose the inner reader, which we don't properly own. EnvelopedSignatureReader realReader = new EnvelopedSignatureReader(plaintextReader, wrappedSerializer, this.Configuration.IssuerTokenResolver, false, false, false); try { // Process @attributes string value; // @xsi:type XmlUtil.ValidateXsiType(realReader, Saml2Constants.Types.AssertionType, Saml2Constants.Namespace); // @Version - required - must be "2.0" string version = realReader.GetAttribute(Saml2Constants.Attributes.Version); if (string.IsNullOrEmpty(version)) { throw DiagnosticUtility.ThrowHelperXml(realReader, SR.GetString(SR.ID0001, Saml2Constants.Attributes.Version, Saml2Constants.Elements.Assertion)); } if (!StringComparer.Ordinal.Equals(assertion.Version, version)) { throw DiagnosticUtility.ThrowHelperXml(realReader, SR.GetString(SR.ID4100, version)); } // @ID - required value = realReader.GetAttribute(Saml2Constants.Attributes.ID); if (string.IsNullOrEmpty(value)) { throw DiagnosticUtility.ThrowHelperXml(realReader, SR.GetString(SR.ID0001, Saml2Constants.Attributes.ID, Saml2Constants.Elements.Assertion)); } assertion.Id = new Saml2Id(value); // @IssueInstant - required value = realReader.GetAttribute(Saml2Constants.Attributes.IssueInstant); if (string.IsNullOrEmpty(value)) { throw DiagnosticUtility.ThrowHelperXml(realReader, SR.GetString(SR.ID0001, Saml2Constants.Attributes.IssueInstant, Saml2Constants.Elements.Assertion)); } assertion.IssueInstant = XmlConvert.ToDateTime(value, DateTimeFormats.Accepted); // Process <elements> realReader.Read(); // <Issuer> 1 assertion.Issuer = this.ReadIssuer(realReader); // <ds:Signature> 0-1 realReader.TryReadSignature(); // <Subject> 0-1 if (realReader.IsStartElement(Saml2Constants.Elements.Subject, Saml2Constants.Namespace)) { assertion.Subject = this.ReadSubject(realReader); } // <Conditions> 0-1 if (realReader.IsStartElement(Saml2Constants.Elements.Conditions, Saml2Constants.Namespace)) { assertion.Conditions = this.ReadConditions(realReader); } // <Advice> 0-1 if (realReader.IsStartElement(Saml2Constants.Elements.Advice, Saml2Constants.Namespace)) { assertion.Advice = this.ReadAdvice(realReader); } // <Statement|AuthnStatement|AuthzDecisionStatement|AttributeStatement>, 0-OO while (realReader.IsStartElement()) { Saml2Statement statement; if (realReader.IsStartElement(Saml2Constants.Elements.Statement, Saml2Constants.Namespace)) { statement = this.ReadStatement(realReader); } else if (realReader.IsStartElement(Saml2Constants.Elements.AttributeStatement, Saml2Constants.Namespace)) { statement = this.ReadAttributeStatement(realReader); } else if (realReader.IsStartElement(Saml2Constants.Elements.AuthnStatement, Saml2Constants.Namespace)) { statement = this.ReadAuthenticationStatement(realReader); } else if (realReader.IsStartElement(Saml2Constants.Elements.AuthzDecisionStatement, Saml2Constants.Namespace)) { statement = this.ReadAuthorizationDecisionStatement(realReader); } else { break; } assertion.Statements.Add(statement); } realReader.ReadEndElement(); if (null == assertion.Subject) { // An assertion with no statements MUST contain a <Subject> element. [Saml2Core, line 585] if (0 == assertion.Statements.Count) { throw DiagnosticUtility.ThrowHelperXml(reader, SR.GetString(SR.ID4106)); } // Furthermore, the built-in statement types all require the presence of a subject. // [Saml2Core, lines 1050, 1168, 1280] foreach (Saml2Statement statement in assertion.Statements) { if (statement is Saml2AuthenticationStatement || statement is Saml2AttributeStatement || statement is Saml2AuthorizationDecisionStatement) { throw DiagnosticUtility.ThrowHelperXml(reader, SR.GetString(SR.ID4119)); } } } // Reading the end element will complete the signature; // capture the signing creds assertion.SigningCredentials = realReader.SigningCredentials; // Save the captured on-the-wire data, which can then be used // to re-emit this assertion, preserving the same signature. assertion.CaptureSourceData(realReader); return assertion; } catch (Exception e) { if (System.Runtime.Fx.IsFatal(e)) throw; Exception wrapped = TryWrapReadException(realReader, e); if (null == wrapped) { throw; } else { throw wrapped; } } }
private Saml2Assertion NewAssertion(X509Certificate2 x509Certificate2 = null, ClaimsIdentity id = null) { var cert = x509Certificate2 ?? certificate; var assertion = new Saml2Assertion(new Saml2NameIdentifier("b")); assertion.Id = new Saml2Id(); assertion.IssueInstant = DateTime.Now; assertion.Subject = new Saml2Subject(new Saml2NameIdentifier("CPS") { Value = "id3" }); assertion.Statements.Add(new Saml2AttributeStatement(new Saml2Attribute("identifiantFacturation", "id1"))); assertion.Statements.Add(new Saml2AttributeStatement(new Saml2Attribute("codeSpecialiteAMO", "id2"))); if (id != null) foreach (var claim in id.Claims) { assertion.Statements.Add(new Saml2AttributeStatement(new Saml2Attribute(claim.Type, claim.Value))); } var saml2SubjectConfirmation = new Saml2SubjectConfirmation(new Uri("urn:oasis:names:tc:SAML:2.0:cm:bearer")); saml2SubjectConfirmation.SubjectConfirmationData = new Saml2SubjectConfirmationData(); saml2SubjectConfirmation.SubjectConfirmationData.Recipient = new Uri("http://allowed_recipient1"); saml2SubjectConfirmation.SubjectConfirmationData.NotOnOrAfter = DateTime.UtcNow.AddHours(1); // valid for 1 hour assertion.Subject.SubjectConfirmations.Add(saml2SubjectConfirmation); assertion.Conditions = new Saml2Conditions(); assertion.Conditions.AudienceRestrictions.Add(new Saml2AudienceRestriction(new Uri("http://audience"))); assertion.SigningCredentials = new X509SigningCredentials(cert); return assertion; }
// Looks like this is called for HOK tokens, so why it is called for the SV token????? // This is called by ReadToken and this will be needed in order to support other confirmation methods protected override ReadOnlyCollection<SecurityKey> ResolveSecurityKeys(Saml2Assertion assertion, SecurityTokenResolver resolver) { CustomTextTraceSource ts = new CustomTextTraceSource("CommercialVehicleCollisionWebservice.CustomSaml2SecurityTokenHandler.ResolveSecurityKeys", "MyTraceSource", SourceLevels.Information); // In model 2, the SAML assertion is , by design, always using the // sender-vouches confirmation method so we always return an empty collection return new ReadOnlyCollection<SecurityKey>(new SecurityKey[0]); #region Modify to include Holder-of-Key and Bearer //Saml2Subject subject = assertion.Subject; //if (subject == null) //{ // throw new SecurityTokenException("null Saml2Subject"); //} //if (subject.SubjectConfirmations.Count == 0) //{ // throw new SecurityTokenException("Empty SubjectConfirmations"); //} //if (subject.SubjectConfirmations.Count > 1) //{ // throw new SecurityTokenException("More than 1 SubjectConfirmations"); //} //Saml2SubjectConfirmation confirmation = subject.SubjectConfirmations[0]; //// enable sender-vouches confirmation method //if (Saml2Constants.ConfirmationMethods.Bearer == confirmation.Method || Saml2Constants.ConfirmationMethods.SenderVouches == confirmation.Method) //{ // if ((confirmation.SubjectConfirmationData != null) && (confirmation.SubjectConfirmationData.KeyIdentifiers.Count != 0)) // { // throw DiagnosticUtil.ExceptionUtil.ThrowHelperError(new SecurityTokenException("A Saml2SecurityToken cannot be created from the Saml2Assertion because it specifies the Bearer confirmation method but identifies keys in the SubjectConfirmationData.")); // } // return Common.EmptyReadOnlyCollection<SecurityKey>.Instance; //} ////if (!(Saml2Constants.ConfirmationMethods.HolderOfKey == confirmation.Method)) ////{ //// throw DiagnosticUtil.ExceptionUtil.ThrowHelperError(new SecurityTokenException(SR.GetString("ID4136", new object[] { confirmation.Method }))); ////} ////if ((confirmation.SubjectConfirmationData == null) || (confirmation.SubjectConfirmationData.KeyIdentifiers.Count == 0)) ////{ //// throw DiagnosticUtil.ExceptionUtil.ThrowHelperError(new SecurityTokenException(SR.GetString("ID4134", new object[0]))); ////} //List<SecurityKey> list = new List<SecurityKey>(); //if (confirmation.SubjectConfirmationData != null) //{ // foreach (SecurityKeyIdentifier identifier in confirmation.SubjectConfirmationData.KeyIdentifiers) // { // SecurityKey key = null; // foreach (SecurityKeyIdentifierClause clause in identifier) // { // if ((resolver != null) && resolver.TryResolveSecurityKey(clause, out key)) // { // list.Add(key); // break; // } // } // if (key == null) // { // if (identifier.CanCreateKey) // { // key = identifier.CreateKey(); // list.Add(key); // continue; // } // list.Add(new SecurityKeyElement(identifier, resolver)); // } // } //} //return list.AsReadOnly(); #endregion }
private ValidatedTokenRequest Request(Saml2Assertion saml) { var serialized = serializer.ToXml(saml); //Console.WriteLine(serialized); return Request(serialized.ToBase64Url()); }
/// <summary> /// Initializes an instance of <see cref="Saml2SecurityToken"/> from a <see cref="Saml2Assertion"/>. /// </summary> /// <param name="assertion">A <see cref="Saml2Assertion"/> to initialize from.</param> public Saml2SecurityToken(Saml2Assertion assertion) : this(assertion, EmptyReadOnlyCollection <SecurityKey> .Instance, null) { }
public DerivedSaml2SecurityToken(Saml2Assertion samlAssertion) : base(samlAssertion) { }
// TODO: The WSP and ADS incoming SAML token handlers share code. Extract base class protected override ReadOnlyCollection<SecurityKey> ResolveSecurityKeys(Saml2Assertion assertion, SecurityTokenResolver resolver) { Saml2Subject subject = assertion.Subject; Saml2SubjectConfirmation confirmation = subject.SubjectConfirmations[0]; if (Saml2Constants.ConfirmationMethods.SenderVouches == confirmation.Method) { // empty ReadOnlyCollection return new ReadOnlyCollection<SecurityKey>(new SecurityKey[0]); } // let the base class handle assertion with the bearer or // holder-of-key confirmation methods return base.ResolveSecurityKeys(assertion, resolver); }
/// <summary> /// Resolves the Signing Key Identifier to a SecurityToken. /// </summary> /// <param name="assertion">The Assertion for which the Issuer token is to be resolved.</param> /// <param name="issuerResolver">The current SecurityTokenResolver associated with this handler.</param> /// <param name="token">Resolved token.</param> /// <returns>True if token is resolved.</returns> protected virtual bool TryResolveIssuerToken(Saml2Assertion assertion, SecurityTokenResolver issuerResolver, out SecurityToken token) { if (null == assertion) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("assertion"); } if (assertion.SigningCredentials != null && assertion.SigningCredentials.SigningKeyIdentifier != null && issuerResolver != null) { SecurityKeyIdentifier keyIdentifier = assertion.SigningCredentials.SigningKeyIdentifier; return issuerResolver.TryResolveToken(keyIdentifier, out token); } else { token = null; return false; } }
/// <summary> /// Creates a <see cref="SecurityToken"/> based on a information contained in the <see cref="SecurityTokenDescriptor"/>. /// </summary> /// <param name="tokenDescriptor">The <see cref="SecurityTokenDescriptor"/> that has creation information.</param> /// <returns>A <see cref="SecurityToken"/> instance.</returns> /// <exception cref="ArgumentNullException">Thrown if 'tokenDescriptor' is null.</exception> public override SecurityToken CreateToken(SecurityTokenDescriptor tokenDescriptor) { if (null == tokenDescriptor) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("tokenDescriptor"); } // Assertion/issuer Saml2Assertion assertion = new Saml2Assertion(this.CreateIssuerNameIdentifier(tokenDescriptor)); // Subject assertion.Subject = this.CreateSamlSubject(tokenDescriptor); // Signature assertion.SigningCredentials = this.GetSigningCredentials(tokenDescriptor); // Conditions assertion.Conditions = this.CreateConditions(tokenDescriptor.Lifetime, tokenDescriptor.AppliesToAddress, tokenDescriptor); // Advice assertion.Advice = this.CreateAdvice(tokenDescriptor); // Statements IEnumerable<Saml2Statement> statements = this.CreateStatements(tokenDescriptor); if (null != statements) { foreach (Saml2Statement statement in statements) { assertion.Statements.Add(statement); } } // encrypting credentials assertion.EncryptingCredentials = this.GetEncryptingCredentials(tokenDescriptor); SecurityToken token = new Saml2SecurityToken(assertion); return token; }
/// <summary> /// Resolves the collection of <see cref="SecurityKey"/> referenced in a <see cref="Saml2Assertion"/>. /// </summary> /// <param name="assertion"><see cref="Saml2Assertion"/> to process.</param> /// <param name="resolver"><see cref="SecurityTokenResolver"/> to use in resolving the <see cref="SecurityKey"/>.</param> /// <returns>A read only collection of <see cref="SecurityKey"/> contained in the assertion.</returns> protected virtual ReadOnlyCollection<SecurityKey> ResolveSecurityKeys(Saml2Assertion assertion, SecurityTokenResolver resolver) { if (null == assertion) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("assertion"); } // Must have Subject Saml2Subject subject = assertion.Subject; if (null == subject) { // No Subject throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4130))); } // Must have one SubjectConfirmation if (0 == subject.SubjectConfirmations.Count) { // No SubjectConfirmation throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4131))); } if (subject.SubjectConfirmations.Count > 1) { // More than one SubjectConfirmation throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4132))); } // Extract the keys for the given method ReadOnlyCollection<SecurityKey> securityKeys; Saml2SubjectConfirmation subjectConfirmation = subject.SubjectConfirmations[0]; // For bearer, ensure there are no keys, set the collection to empty // For HolderOfKey, ensure there is at least one key, resolve and create collection if (Saml2Constants.ConfirmationMethods.Bearer == subjectConfirmation.Method) { if (null != subjectConfirmation.SubjectConfirmationData && 0 != subjectConfirmation.SubjectConfirmationData.KeyIdentifiers.Count) { // Bearer but has keys throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4133))); } securityKeys = EmptyReadOnlyCollection<SecurityKey>.Instance; } else if (Saml2Constants.ConfirmationMethods.HolderOfKey == subjectConfirmation.Method) { if (null == subjectConfirmation.SubjectConfirmationData || 0 == subjectConfirmation.SubjectConfirmationData.KeyIdentifiers.Count) { // Holder-of-key but no keys throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4134))); } List<SecurityKey> holderKeys = new List<SecurityKey>(); SecurityKey key; foreach (SecurityKeyIdentifier keyIdentifier in subjectConfirmation.SubjectConfirmationData.KeyIdentifiers) { key = null; // Try the resolver first foreach (SecurityKeyIdentifierClause clause in keyIdentifier) { if (null != resolver && resolver.TryResolveSecurityKey(clause, out key)) { holderKeys.Add(key); break; } } // If that doesn't work, try to create the key (e.g. bare RSA or X509 raw) if (null == key) { if (keyIdentifier.CanCreateKey) { key = keyIdentifier.CreateKey(); holderKeys.Add(key); } else { holderKeys.Add(new SecurityKeyElement(keyIdentifier, resolver)); } } } securityKeys = holderKeys.AsReadOnly(); } else { // SenderVouches, as well as other random things, aren't accepted throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4136, subjectConfirmation.Method))); } return securityKeys; }
private void ValidateMethod(Saml2Assertion assertion) { // TODO - not covereted, see ValidateAsync_3_5_Given_SAML_With_Unsupported_Method_Throw unit test var method = assertion.Subject.SubjectConfirmations[0].Method; if (method != ConfirmationMethods.Bearer) throw new SecurityTokenException(string.Format("Message=Unsupported method, Expected={0}, Actual={1}", ConfirmationMethods.Bearer, method)); }
public void Saml2AssertionExtensions_ToXElement_Issuer() { var issuer = "http://idp.example.com"; var assertion = new Saml2Assertion(new Saml2NameIdentifier(issuer)); var subject = assertion.ToXElement(); subject.Element(Saml2Namespaces.Saml2 + "Issuer").Value.Should().Be(issuer); }