//------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ namespace System.IdentityModel.Tokens { using System.Collections.Generic; using System.Collections.ObjectModel; using System.Runtime; using System.Security.Claims; using System.Security.Cryptography; using System.Xml; /// /// SecurityTokenHandler for RsaSecurityTokens. /// public class RsaSecurityTokenHandler : SecurityTokenHandler { static string[] _tokenTypeIdentifiers = new string[] { SecurityTokenTypes.Rsa }; /// /// Creates an instance of /// public RsaSecurityTokenHandler() { } /// /// Checks the reader if this is a representation of an RsaSecurityToken. /// /// XmlReader over the incoming SecurityToken. /// 'True' if the reader points to an RsaSecurityToken, false otherwise. /// The input argument 'reader' is null. public override bool CanReadToken(XmlReader reader) { if (reader == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader"); } return reader.IsStartElement(XmlSignatureConstants.Elements.KeyInfo, XmlSignatureConstants.Namespace); } /// /// Gets the settings that indicate if the token handler can validate tokens. /// Returns true by default. /// public override bool CanValidateToken { get { return true; } } /// /// Gets a boolean indicating if the handler can write tokens. /// Returns true by default. /// public override bool CanWriteToken { get { return true; } } /// /// Gets the RSA Security Token type as defined in WS-Security Token profile. /// public override string[] GetTokenTypeIdentifiers() { return _tokenTypeIdentifiers; } /// /// Deserializes an RSA security token from XML. /// /// An XML reader positioned at the start of the token /// An instance of . /// The input argument 'reader' is null. /// The 'reader' is not positioned at a RSA token. /// or the SecurityContextToken cannot be read. public override SecurityToken ReadToken(XmlReader reader) { if (null == reader) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader"); } XmlDictionaryReader dicReader = XmlDictionaryReader.CreateDictionaryReader(reader); if (!dicReader.IsStartElement(XmlSignatureConstants.Elements.KeyInfo, XmlSignatureConstants.Namespace)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new XmlException( SR.GetString( SR.ID4065, XmlSignatureConstants.Elements.KeyInfo, XmlSignatureConstants.Namespace, dicReader.LocalName, dicReader.NamespaceURI))); } dicReader.ReadStartElement(); if (!dicReader.IsStartElement(XmlSignatureConstants.Elements.KeyValue, XmlSignatureConstants.Namespace)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new XmlException( SR.GetString( SR.ID4065, XmlSignatureConstants.Elements.KeyValue, XmlSignatureConstants.Namespace, dicReader.LocalName, dicReader.NamespaceURI))); } dicReader.ReadStartElement(); RSA rsa = new RSACryptoServiceProvider(); rsa.FromXmlString(dicReader.ReadOuterXml()); dicReader.ReadEndElement(); // dicReader.ReadEndElement(); // return new RsaSecurityToken(rsa); } /// /// Gets the System.Type of the SecurityToken that this token handler handles. /// Return type of by default. /// public override Type TokenType { get { return typeof(RsaSecurityToken); } } /// /// Validates a . /// /// The to validate. /// A of representing the identities contained in the token. /// The parameter 'token' is null. /// The token is not assignable from . /// Configuration is null. public override ReadOnlyCollection ValidateToken(SecurityToken token) { if (token == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("token"); } RsaSecurityToken rsaToken = (RsaSecurityToken)token; if (rsaToken == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("token", SR.GetString(SR.ID0018, typeof(RsaSecurityToken))); } if (this.Configuration == null) { throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID4274)); } try { // Export the Public Key of the RSA as a Claim. ClaimsIdentity identity = new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Rsa, rsaToken.Rsa.ToXmlString(false), ClaimValueTypes.RsaKeyValue, ClaimsIdentity.DefaultIssuer) }, AuthenticationTypes.Signature); identity.AddClaim(new Claim(ClaimTypes.AuthenticationInstant, XmlConvert.ToString(DateTime.UtcNow, DateTimeFormats.Generated), ClaimValueTypes.DateTime)); identity.AddClaim(new Claim(ClaimTypes.AuthenticationMethod, AuthenticationMethods.Signature)); if (this.Configuration.SaveBootstrapContext) { identity.BootstrapContext = new BootstrapContext(token, this); } this.TraceTokenValidationSuccess(token); List identities = new List(1); identities.Add(identity); return identities.AsReadOnly(); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } this.TraceTokenValidationFailure(token, e.Message); throw e; } } /// /// Serializes an RSA security token to XML. /// /// The XML writer. /// An RSA security token. /// The input argument 'writer' is null. /// The input argument 'token' is either null or not of type /// . public override void WriteToken(XmlWriter writer, SecurityToken token) { if (writer == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer"); } if (token == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("token"); } RsaSecurityToken rsaToken = token as RsaSecurityToken; if (rsaToken == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("token", SR.GetString(SR.ID0018, typeof(RsaSecurityToken))); } RSAParameters rsaParams = rsaToken.Rsa.ExportParameters(false); writer.WriteStartElement(XmlSignatureConstants.Elements.KeyInfo, XmlSignatureConstants.Namespace); writer.WriteStartElement(XmlSignatureConstants.Elements.KeyValue, XmlSignatureConstants.Namespace); // // RSA.ToXmlString shouldn't be used here because it doesn't write namespaces. The modulus and exponent are written manually. // writer.WriteStartElement(XmlSignatureConstants.Elements.RsaKeyValue, XmlSignatureConstants.Namespace); writer.WriteStartElement(XmlSignatureConstants.Elements.Modulus, XmlSignatureConstants.Namespace); byte[] modulus = rsaParams.Modulus; writer.WriteBase64(modulus, 0, modulus.Length); writer.WriteEndElement(); // writer.WriteStartElement(XmlSignatureConstants.Elements.Exponent, XmlSignatureConstants.Namespace); byte[] exponent = rsaParams.Exponent; writer.WriteBase64(exponent, 0, exponent.Length); writer.WriteEndElement(); // writer.WriteEndElement(); // writer.WriteEndElement(); // writer.WriteEndElement(); // } } }