/// <summary> /// This gets called on the STS to serialize the token /// The token looks like this /// <MyDecisionToken Id="someId here"> /// <Decision>True</Decision> /// <Key>key bytes</Key> /// <Signature>...</Signature> /// </MyDecisionToken> /// </summary> /// <param name="writer">The xml writer.</param> /// <param name="token">The security token that will be written.</param> /// <exception cref="ArgumentException">When the token is null.</exception> public override void WriteToken(XmlWriter writer, SecurityToken token) { Console.WriteLine("CustomTokenHandler.WriteToken called"); MyDecisionToken decisionToken = token as MyDecisionToken; if (decisionToken == null) { throw new ArgumentException("The given token must be a MyDecisionToken", "token"); } EnvelopedSignatureWriter envWriter = new EnvelopedSignatureWriter(writer, decisionToken.SigningCredentials, decisionToken.Id, WSSecurityTokenSerializer.DefaultInstance); // Start the tokenName envWriter.WriteStartElement(TokenName, TokenNamespace); envWriter.WriteAttributeString(Id, token.Id); // Write the decision element Console.WriteLine("- decision being written: {0}", decisionToken.Decision); envWriter.WriteElementString(Decision, TokenNamespace, Convert.ToString(decisionToken.Decision)); // Write the key envWriter.WriteElementString(Key, TokenNamespace, Convert.ToBase64String(((MyDecisionToken)token).RetrieveKeyBytes())); // Close the TokenName element envWriter.WriteEndElement(); }
public void CreateSignatureWithoutSpecifyingDigest(EnvelopedSignatureTheoryData theoryData) { var context = TestUtilities.WriteHeader($"{this}.CreateSignatureWithoutSpecifyingDigest", theoryData); try { using (var buffer = new MemoryStream()) { var writer = new EnvelopedSignatureWriter(XmlWriter.Create(buffer), theoryData.SigningCredentials, theoryData.ReferenceId); writer.WriteStartElement("EntityDescriptor", "urn:oasis:names:tc:SAML:2.0:metadata"); writer.WriteAttributeString("entityID", "issuer"); writer.WriteEndElement(); // read and verify signatures EnvelopedSignatureReader envelopedReader = new EnvelopedSignatureReader(XmlUtilities.CreateDictionaryReader(Encoding.UTF8.GetString(buffer.ToArray()))); while (envelopedReader.Read()) { ; } envelopedReader.Signature.Verify(theoryData.SigningCredentials.Key, theoryData.SigningCredentials.Key.CryptoProviderFactory); theoryData.ExpectedException.ProcessNoException(context); } } catch (Exception ex) { theoryData.ExpectedException.ProcessException(ex, context); } TestUtilities.AssertFailIfErrors(context); }
public void RoundTripWsMetadata(EnvelopedSignatureTheoryData theoryData) { var context = TestUtilities.WriteHeader($"{this}.RoundTripWsMetadata", theoryData); try { var settings = new XmlWriterSettings { Encoding = new UTF8Encoding(false) }; var buffer = new MemoryStream(); var esw = new EnvelopedSignatureWriter(XmlWriter.Create(buffer, settings), theoryData.SigningCredentials, theoryData.ReferenceId); theoryData.Action.DynamicInvoke(esw); var metadata = Encoding.UTF8.GetString(buffer.ToArray()); var configuration = new WsFederationConfiguration(); var reader = XmlReader.Create(new StringReader(metadata)); configuration = new WsFederationMetadataSerializer().ReadMetadata(reader); configuration.Signature.Verify(theoryData.SigningCredentials.Key, theoryData.SigningCredentials.Key.CryptoProviderFactory); theoryData.ExpectedException.ProcessNoException(context); } catch (Exception ex) { theoryData.ExpectedException.ProcessException(ex, context); } TestUtilities.AssertFailIfErrors(context); }
public void WriteSaml2ProxyRestriction(Saml2TheoryData theoryData) { TestUtilities.WriteHeader($"{this}.WriteSaml2ProxyRestriction", theoryData); var context = new CompareContext($"{this}.WriteSaml2ProxyRestriction, {theoryData.TestId}"); try { var ms = new MemoryStream(); var writer = XmlDictionaryWriter.CreateTextWriter(ms, Encoding.UTF8, false); var envelopedWriter = new EnvelopedSignatureWriter(writer, Default.AsymmetricSigningCredentials, "ref#1"); (theoryData.Saml2Serializer as Saml2SerializerPublic).WriteProxyRestrictionPublic(writer, theoryData.ProxyRestriction); writer.Flush(); var xml = Encoding.UTF8.GetString(ms.ToArray()); IdentityComparer.AreEqual(xml, theoryData.Xml, context); theoryData.ExpectedException.ProcessNoException(); } catch (Exception ex) { theoryData.ExpectedException.ProcessException(ex); } TestUtilities.AssertFailIfErrors(context); }
/// <summary> /// /// </summary> /// <param name="writer"></param> /// <param name="configuration"></param> /// <returns></returns> public static void WriteMetadata(this WsFederationMetadataSerializer serializer, XmlWriter writer, WsFederationConfiguration configuration) { if (writer == null) { throw new ArgumentNullException(nameof(writer)); } if (configuration == null) { throw new ArgumentNullException(nameof(configuration)); } if (string.IsNullOrEmpty(configuration.Issuer)) { throw XmlUtil.LogWriteException(nameof(configuration.Issuer) + " is null or empty"); } if (string.IsNullOrEmpty(configuration.TokenEndpoint)) { throw XmlUtil.LogWriteException(nameof(configuration.TokenEndpoint) + " is null or empty"); } X509SecurityKey securityKey = configuration.SigningKeys.FirstOrDefault() as X509SecurityKey; var entityDescriptorId = "_" + Guid.NewGuid().ToString(); EnvelopedSignatureWriter envelopeWriter = null; if (securityKey != null) { envelopeWriter = new EnvelopedSignatureWriter( writer, configuration.SigningCredentials, "#" + entityDescriptorId); writer = envelopeWriter; } writer.WriteStartDocument(); // <EntityDescriptor> writer.WriteStartElement(Elements.EntityDescriptor, WsFederationConstants.MetadataNamespace); // @entityID writer.WriteAttributeString(Attributes.EntityId, configuration.Issuer); // @ID writer.WriteAttributeString(Attributes.Id, entityDescriptorId); // if (envelopeWriter != null) // envelopeWriter.WriteSignature(); WriteSecurityTokenServiceTypeRoleDescriptor(configuration, writer); // </EntityDescriptor> writer.WriteEndElement(); writer.WriteEndDocument(); }
protected virtual void WriteEntitiesDescriptor(XmlWriter writer, EntitiesDescriptor entitiesDescriptor) { if (writer == null) { throw new ArgumentNullException(nameof(writer)); } if (entitiesDescriptor == null) { throw new ArgumentNullException(nameof(entitiesDescriptor)); } if (!entitiesDescriptor.ChildEntities.Any() && !entitiesDescriptor.ChildEntityGroups.Any()) { throw new ArgumentNullException(nameof(entitiesDescriptor)); } var entityReference = "_" + Guid.NewGuid(); if (entitiesDescriptor.SigningCredentials != null) { writer = new EnvelopedSignatureWriter(writer, entitiesDescriptor.SigningCredentials, entityReference); } writer.WriteStartElement(Saml2MetadataConstants.Elements.EntitiesDescriptor, Saml2MetadataConstants.Namespace); writer.WriteAttributeString(Saml2MetadataConstants.Attributes.Id, null, entityReference); foreach (var entity in entitiesDescriptor.ChildEntities) { if (!string.IsNullOrEmpty(entity.FederationId)) { if (!StringComparer.Ordinal.Equals(entity.FederationId, entitiesDescriptor.Name)) { throw new MetadataSerializationException($"Invalid federation ID of {entity.FederationId}"); } } } writer.WriteAttributeIfPresent(Saml2MetadataConstants.Attributes.EntityGroupName, null, entitiesDescriptor.Name); WriteCustomAttributes(writer, entitiesDescriptor); foreach (var childEntity in entitiesDescriptor.ChildEntities) { WriteEntityDescriptor(writer, childEntity); } foreach (var childEntityDescriptor in entitiesDescriptor.ChildEntityGroups) { WriteEntitiesDescriptor(writer, childEntityDescriptor); } WriteCustomElements(writer, entitiesDescriptor); writer.WriteEndElement(); }
public void Constructor(EnvelopedSignatureTheoryData theoryData) { TestUtilities.WriteHeader($"{this}.Constructor", theoryData); try { var envelopedWriter = new EnvelopedSignatureWriter(theoryData.XmlWriter, theoryData.SigningCredentials, theoryData.ReferenceId, theoryData.InclusiveNamespacesPrefixList); theoryData.ExpectedException.ProcessNoException(); } catch (Exception ex) { theoryData.ExpectedException.ProcessException(ex); } }
private static string CreateSignedXmlWithEmbededTokens(IList <SecurityToken> samlTokens, SigningCredentials xmlSigningCredentials, SigningCredentials tokenSigningCredentials) { var ms = new MemoryStream(); var writer = XmlDictionaryWriter.CreateTextWriter(ms, Encoding.UTF8, false); var samlTokenHandler = new SamlSecurityTokenHandler(); var saml2TokenHandler = new Saml2SecurityTokenHandler(); var envelopedWriter = new EnvelopedSignatureWriter(writer, xmlSigningCredentials, "ref#1"); envelopedWriter.WriteStartElement("local", "elementName", "http://elementnamespace"); envelopedWriter.WriteElementString("localElement", "SamlWillBeEmbeded"); foreach (var token in samlTokens) { if (token is SamlSecurityToken) { samlTokenHandler.WriteToken(envelopedWriter, token); } else { saml2TokenHandler.WriteToken(envelopedWriter, token); } } envelopedWriter.WriteStartElement("local", "elementName2", "http://elementnamespace"); envelopedWriter.WriteElementString("localElement", "SamlWillBeEmbeded2"); foreach (var token in samlTokens) { if (token is SamlSecurityToken) { samlTokenHandler.WriteToken(envelopedWriter, token); } else { saml2TokenHandler.WriteToken(envelopedWriter, token); } } envelopedWriter.WriteEndElement(); envelopedWriter.WriteEndElement(); envelopedWriter.Flush(); var xml = Encoding.UTF8.GetString(ms.ToArray()); return(xml); }
public void RoundTripSamlPSignatureAfterAssertion() { var context = new CompareContext($"{this}.RoundTripSamlPSignatureAfterAssertion"); ExpectedException expectedException = ExpectedException.NoExceptionExpected; var samlpTokenKey = KeyingMaterial.RsaSigningCreds_4096_Public.Key; var samlpTokenSigningCredentials = KeyingMaterial.RsaSigningCreds_4096; var samlpKey = KeyingMaterial.RsaSigningCreds_2048_Public.Key; var samlpSigningCredentials = KeyingMaterial.RsaSigningCreds_2048; try { // write samlp var settings = new XmlWriterSettings { Encoding = new UTF8Encoding(false) }; var buffer = new MemoryStream(); var esw = new EnvelopedSignatureWriter(XmlWriter.Create(buffer, settings), samlpSigningCredentials, "id-uAOhNLe7abGB6WGPk"); esw.WriteStartElement("ns0", "Response", "urn:oasis:names:tc:SAML:2.0:protocol"); esw.WriteAttributeString("ns1", "urn:oasis:names:tc:SAML:2.0:assertion"); esw.WriteAttributeString("ns2", "http://www.w3.org/2000/09/xmldsig#"); esw.WriteAttributeString("Destination", "https://tnia.eidentita.cz/fpsts/processRequest.aspx"); esw.WriteAttributeString("ID", "id-uAOhNLe7abGB6WGPk"); esw.WriteAttributeString("InResponseTo", "ida5714d006fcc430c92aacf34ab30b166"); esw.WriteAttributeString("IssueInstant", "2019-04-08T10:30:49Z"); esw.WriteAttributeString("Version", "2.0"); esw.WriteStartElement("ns1", "Issuer"); esw.WriteAttributeString("Format", "urn:oasis:names:tc:SAML:2.0:nameid-format:entity"); esw.WriteString("https://mojeid.regtest.nic.cz/saml/idp.xml"); esw.WriteEndElement(); esw.WriteStartElement("ns0", "Status", null); esw.WriteStartElement("ns0", "StatusCode", null); esw.WriteAttributeString("Value", "urn:oasis:names:tc:SAML:2.0:status:Success"); esw.WriteEndElement(); esw.WriteEndElement(); Saml2Serializer samlSerializer = new Saml2Serializer(); Saml2Assertion assertion = CreateAssertion(samlpTokenSigningCredentials); samlSerializer.WriteAssertion(esw, assertion); esw.WriteSignature(); esw.WriteEndElement(); var xml = Encoding.UTF8.GetString(buffer.ToArray()); // read samlp and verify signatures XmlReader reader = XmlUtilities.CreateDictionaryReader(xml); IXmlElementReader tokenReaders = new TokenReaders(new List <SecurityTokenHandler> { new Saml2SecurityTokenHandler() }); EnvelopedSignatureReader envelopedReader = new EnvelopedSignatureReader(reader, tokenReaders); while (envelopedReader.Read()) { ; } foreach (var item in tokenReaders.Items) { if (item is Saml2SecurityToken samlToken) { samlToken.Assertion.Signature.Verify(samlpTokenKey); } } envelopedReader.Signature.Verify(samlpKey, samlpKey.CryptoProviderFactory); expectedException.ProcessNoException(context); } catch (Exception ex) { expectedException.ProcessException(ex, context); } TestUtilities.AssertFailIfErrors(context); }
/// <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> /// Serializes a given SamlAssertion to the XmlWriter. /// </summary> /// <param name="writer">XmlWriter to use for the serialization.</param> /// <param name="assertion">Assertion to be serialized into the XmlWriter.</param> /// <exception cref="ArgumentNullException">The input parameter 'writer' or 'assertion' is null.</exception> protected virtual void WriteAssertion(XmlWriter writer, SamlAssertion assertion) { if (writer == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer"); } if (assertion == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("assertion"); } SamlAssertion SamlAssertion = assertion as SamlAssertion; if (SamlAssertion != null) { if (SamlAssertion.CanWriteSourceData) { SamlAssertion.WriteSourceData(writer); return; } } if (assertion.SigningCredentials != null) { writer = new EnvelopedSignatureWriter(writer, assertion.SigningCredentials, assertion.AssertionId, new WrappedSerializer(this, assertion)); } writer.WriteStartElement(SamlConstants.Prefix, SamlConstants.ElementNames.Assertion, SamlConstants.Namespace); writer.WriteAttributeString(SamlConstants.AttributeNames.MajorVersion, null, Convert.ToString(SamlConstants.MajorVersionValue, CultureInfo.InvariantCulture)); writer.WriteAttributeString(SamlConstants.AttributeNames.MinorVersion, null, Convert.ToString(SamlConstants.MinorVersionValue, CultureInfo.InvariantCulture)); writer.WriteAttributeString(SamlConstants.AttributeNames.AssertionId, null, assertion.AssertionId); writer.WriteAttributeString(SamlConstants.AttributeNames.Issuer, null, assertion.Issuer); writer.WriteAttributeString(SamlConstants.AttributeNames.IssueInstant, null, assertion.IssueInstant.ToUniversalTime().ToString(DateTimeFormats.Generated, CultureInfo.InvariantCulture)); // Write out conditions if (assertion.Conditions != null) { WriteConditions(writer, assertion.Conditions); } // Write out advice if there is one if (assertion.Advice != null) { WriteAdvice(writer, assertion.Advice); } // Write statements. for (int i = 0; i < assertion.Statements.Count; i++) { WriteStatement(writer, assertion.Statements[i]); } writer.WriteEndElement(); }
protected virtual void WriteEntityDescriptor(XmlWriter writer, EntityDescriptor entityDescriptor) { if (writer == null) { throw new ArgumentNullException(nameof(writer)); } if (entityDescriptor == null) { throw new ArgumentNullException(nameof(entityDescriptor)); } if (!entityDescriptor.RoleDescriptors.Any()) { throw new MetadataSerializationException("Missing RoleDescriptors"); } var entityReference = "_" + Guid.NewGuid(); if (entityDescriptor.SigningCredentials != null) { writer = new EnvelopedSignatureWriter(writer, entityDescriptor.SigningCredentials, entityReference); } writer.WriteStartElement(Saml2MetadataConstants.Elements.EntityDescriptor, Saml2MetadataConstants.Namespace); writer.WriteAttributeIfPresent(Saml2MetadataConstants.Attributes.Id, null, entityReference); if (entityDescriptor.EntityId?.Id == null) { throw new MetadataSerializationException("Missing entity id"); } writer.WriteAttributeString(Saml2MetadataConstants.Attributes.EntityId, null, entityDescriptor.EntityId.Id); writer.WriteAttributeIfPresent(WSFederationMetadataConstants.Attributes.FederationId, WSFederationMetadataConstants.Namespace, entityDescriptor.FederationId); WriteCustomAttributes(writer, entityDescriptor); foreach (var roleDescriptor in entityDescriptor.RoleDescriptors) { if (roleDescriptor is ServiceProviderSingleSignOnDescriptor spSsoDescriptor) { WriteServiceProviderSingleSignOnDescriptor(writer, spSsoDescriptor); } if (roleDescriptor is IdentityProviderSingleSignOnDescriptor idpSsoDescriptor) { WriteIdentityProviderSingleSignOnDescriptor(writer, idpSsoDescriptor); } if (roleDescriptor is ApplicationServiceDescriptor serviceDescriptor) { WriteApplicationServiceDescriptor(writer, serviceDescriptor); } if (roleDescriptor is SecurityTokenServiceDescriptor secDescriptor) { WriteSecurityTokenServiceDescriptor(writer, secDescriptor); } } if (entityDescriptor.Organization != null) { WriteOrganization(writer, entityDescriptor.Organization); } foreach (var person in entityDescriptor.Contacts) { WriteContactPerson(writer, person); } WriteCustomElements(writer, entityDescriptor); writer.WriteEndElement(); }