File: FrameworkFork\System.ServiceModel\System\ServiceModel\Security\WSSecurityTokenSerializer.cs
Web Access
Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Collections.Generic;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Runtime;
using System.ServiceModel;
using System.ServiceModel.Security.Tokens;
using Microsoft.Xml;
using System.ServiceModel.Diagnostics;
using System.Diagnostics;
 
namespace System.ServiceModel.Security
{
    public class WSSecurityTokenSerializer : SecurityTokenSerializer
    {
        private const int DefaultMaximumKeyDerivationOffset = 64; // bytes 
        private const int DefaultMaximumKeyDerivationLabelLength = 128; // bytes
        private const int DefaultMaximumKeyDerivationNonceLength = 128; // bytes
 
        private static WSSecurityTokenSerializer s_instance;
        private readonly bool _emitBspRequiredAttributes;
        private readonly SecurityVersion _securityVersion;
        private readonly List<SerializerEntries> _serializerEntries;
        private WSSecureConversation _secureConversation;
        private readonly List<TokenEntry> _tokenEntries;
        private int _maximumKeyDerivationOffset;
        private int _maximumKeyDerivationLabelLength;
        private int _maximumKeyDerivationNonceLength;
 
        private KeyInfoSerializer _keyInfoSerializer;
 
        public WSSecurityTokenSerializer()
            : this(SecurityVersion.WSSecurity11)
        {
        }
 
        public WSSecurityTokenSerializer(bool emitBspRequiredAttributes)
            : this(SecurityVersion.WSSecurity11, emitBspRequiredAttributes)
        {
        }
 
        public WSSecurityTokenSerializer(SecurityVersion securityVersion)
            : this(securityVersion, false)
        {
        }
 
        public WSSecurityTokenSerializer(SecurityVersion securityVersion, bool emitBspRequiredAttributes)
            : this(securityVersion, emitBspRequiredAttributes, null)
        {
        }
 
        public WSSecurityTokenSerializer(SecurityVersion securityVersion, bool emitBspRequiredAttributes, SamlSerializer samlSerializer)
            : this(securityVersion, emitBspRequiredAttributes, samlSerializer, null, null)
        {
        }
 
        public WSSecurityTokenSerializer(SecurityVersion securityVersion, bool emitBspRequiredAttributes, SamlSerializer samlSerializer, SecurityStateEncoder securityStateEncoder, IEnumerable<Type> knownTypes)
            : this(securityVersion, emitBspRequiredAttributes, samlSerializer, securityStateEncoder, knownTypes, DefaultMaximumKeyDerivationOffset, DefaultMaximumKeyDerivationLabelLength, DefaultMaximumKeyDerivationNonceLength)
        {
        }
 
        public WSSecurityTokenSerializer(SecurityVersion securityVersion, TrustVersion trustVersion, SecureConversationVersion secureConversationVersion, bool emitBspRequiredAttributes, SamlSerializer samlSerializer, SecurityStateEncoder securityStateEncoder, IEnumerable<Type> knownTypes)
            : this(securityVersion, trustVersion, secureConversationVersion, emitBspRequiredAttributes, samlSerializer, securityStateEncoder, knownTypes, DefaultMaximumKeyDerivationOffset, DefaultMaximumKeyDerivationLabelLength, DefaultMaximumKeyDerivationNonceLength)
        {
        }
 
        public WSSecurityTokenSerializer(SecurityVersion securityVersion, bool emitBspRequiredAttributes, SamlSerializer samlSerializer, SecurityStateEncoder securityStateEncoder, IEnumerable<Type> knownTypes,
            int maximumKeyDerivationOffset, int maximumKeyDerivationLabelLength, int maximumKeyDerivationNonceLength)
            : this(securityVersion, TrustVersion.Default, SecureConversationVersion.Default, emitBspRequiredAttributes, samlSerializer, securityStateEncoder, knownTypes, maximumKeyDerivationOffset, maximumKeyDerivationLabelLength, maximumKeyDerivationNonceLength)
        {
        }
 
        public WSSecurityTokenSerializer(SecurityVersion securityVersion, TrustVersion trustVersion, SecureConversationVersion secureConversationVersion, bool emitBspRequiredAttributes, SamlSerializer samlSerializer, SecurityStateEncoder securityStateEncoder, IEnumerable<Type> knownTypes,
            int maximumKeyDerivationOffset, int maximumKeyDerivationLabelLength, int maximumKeyDerivationNonceLength)
        {
            if (securityVersion == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("securityVersion"));
 
            if (maximumKeyDerivationOffset < 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("maximumKeyDerivationOffset", SRServiceModel.ValueMustBeNonNegative));
            }
            if (maximumKeyDerivationLabelLength < 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("maximumKeyDerivationLabelLength", SRServiceModel.ValueMustBeNonNegative));
            }
            if (maximumKeyDerivationNonceLength <= 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("maximumKeyDerivationNonceLength", SRServiceModel.ValueMustBeGreaterThanZero));
            }
 
            _securityVersion = securityVersion;
            _emitBspRequiredAttributes = emitBspRequiredAttributes;
            _maximumKeyDerivationOffset = maximumKeyDerivationOffset;
            _maximumKeyDerivationNonceLength = maximumKeyDerivationNonceLength;
            _maximumKeyDerivationLabelLength = maximumKeyDerivationLabelLength;
 
            _serializerEntries = new List<SerializerEntries>();
 
            if (secureConversationVersion == SecureConversationVersion.WSSecureConversationFeb2005)
            {
                _secureConversation = new WSSecureConversationFeb2005(this, securityStateEncoder, knownTypes, maximumKeyDerivationOffset, maximumKeyDerivationLabelLength, maximumKeyDerivationNonceLength);
            }
            else if (secureConversationVersion == SecureConversationVersion.WSSecureConversation13)
            {
                _secureConversation = new WSSecureConversationDec2005(this, securityStateEncoder, knownTypes, maximumKeyDerivationOffset, maximumKeyDerivationLabelLength, maximumKeyDerivationNonceLength);
            }
            else
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
            }
 
            if (securityVersion == SecurityVersion.WSSecurity10)
            {
                _serializerEntries.Add(new WSSecurityJan2004(this, samlSerializer));
            }
            else if (securityVersion == SecurityVersion.WSSecurity11)
            {
                _serializerEntries.Add(new WSSecurityXXX2005(this, samlSerializer));
            }
            else
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("securityVersion", SRServiceModel.MessageSecurityVersionOutOfRange));
            }
            _serializerEntries.Add(_secureConversation);
            IdentityModel.TrustDictionary trustDictionary;
            if (trustVersion == TrustVersion.WSTrustFeb2005)
            {
                _serializerEntries.Add(new WSTrustFeb2005(this));
                trustDictionary = new IdentityModel.TrustFeb2005Dictionary(new CollectionDictionary(DXD.TrustDec2005Dictionary.Feb2005DictionaryStrings));
            }
            else if (trustVersion == TrustVersion.WSTrust13)
            {
                _serializerEntries.Add(new WSTrustDec2005(this));
                trustDictionary = new IdentityModel.TrustDec2005Dictionary(new CollectionDictionary(DXD.TrustDec2005Dictionary.Dec2005DictionaryString));
            }
            else
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
            }
 
            _tokenEntries = new List<TokenEntry>();
 
            for (int i = 0; i < _serializerEntries.Count; ++i)
            {
                SerializerEntries serializerEntry = _serializerEntries[i];
                serializerEntry.PopulateTokenEntries(_tokenEntries);
            }
 
            IdentityModel.DictionaryManager dictionaryManager = new IdentityModel.DictionaryManager(ServiceModelDictionary.CurrentVersion);
            dictionaryManager.SecureConversationDec2005Dictionary = new IdentityModel.SecureConversationDec2005Dictionary(new CollectionDictionary(DXD.SecureConversationDec2005Dictionary.SecureConversationDictionaryStrings));
            dictionaryManager.SecurityAlgorithmDec2005Dictionary = new IdentityModel.SecurityAlgorithmDec2005Dictionary(new CollectionDictionary(DXD.SecurityAlgorithmDec2005Dictionary.SecurityAlgorithmDictionaryStrings));
 
            _keyInfoSerializer = new WSKeyInfoSerializer(_emitBspRequiredAttributes, dictionaryManager, trustDictionary, this, securityVersion, secureConversationVersion);
        }
 
        public static WSSecurityTokenSerializer DefaultInstance
        {
            get
            {
                if (s_instance == null)
                    s_instance = new WSSecurityTokenSerializer();
                return s_instance;
            }
        }
 
        public bool EmitBspRequiredAttributes
        {
            get { return _emitBspRequiredAttributes; }
        }
 
        public SecurityVersion SecurityVersion
        {
            get { return _securityVersion; }
        }
 
        public int MaximumKeyDerivationOffset
        {
            get { return _maximumKeyDerivationOffset; }
        }
 
        public int MaximumKeyDerivationLabelLength
        {
            get { return _maximumKeyDerivationLabelLength; }
        }
 
        public int MaximumKeyDerivationNonceLength
        {
            get { return _maximumKeyDerivationNonceLength; }
        }
 
        internal WSSecureConversation SecureConversation
        {
            get { return _secureConversation; }
        }
 
        private bool ShouldWrapException(Exception e)
        {
            if (Fx.IsFatal(e))
            {
                return false;
            }
            return ((e is ArgumentException) || (e is FormatException) || (e is InvalidOperationException));
        }
 
        protected override bool CanReadTokenCore(XmlReader reader)
        {
            XmlDictionaryReader localReader = XmlDictionaryReader.CreateDictionaryReader(reader);
            for (int i = 0; i < _tokenEntries.Count; i++)
            {
                TokenEntry tokenEntry = _tokenEntries[i];
                if (tokenEntry.CanReadTokenCore(localReader))
                    return true;
            }
            return false;
        }
 
        protected override SecurityToken ReadTokenCore(XmlReader reader, SecurityTokenResolver tokenResolver)
        {
            XmlDictionaryReader localReader = XmlDictionaryReader.CreateDictionaryReader(reader);
            for (int i = 0; i < _tokenEntries.Count; i++)
            {
                TokenEntry tokenEntry = _tokenEntries[i];
                if (tokenEntry.CanReadTokenCore(localReader))
                {
                    try
                    {
                        return tokenEntry.ReadTokenCore(localReader, tokenResolver);
                    }
#pragma warning disable 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (!ShouldWrapException(e))
                        {
                            throw;
                        }
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SRServiceModel.ErrorDeserializingTokenXml, e));
                    }
                }
            }
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(string.Format(SRServiceModel.CannotReadToken, reader.LocalName, reader.NamespaceURI, localReader.GetAttribute(XD.SecurityJan2004Dictionary.ValueType, null))));
        }
 
        protected override bool CanWriteTokenCore(SecurityToken token)
        {
            for (int i = 0; i < _tokenEntries.Count; i++)
            {
                TokenEntry tokenEntry = _tokenEntries[i];
                if (tokenEntry.SupportsCore(token.GetType()))
                    return true;
            }
            return false;
        }
 
        protected override void WriteTokenCore(XmlWriter writer, SecurityToken token)
        {
            throw new NotImplementedException();
        }
 
        protected override bool CanReadKeyIdentifierCore(XmlReader reader)
        {
            try
            {
                return _keyInfoSerializer.CanReadKeyIdentifier(reader);
            }
            catch (System.IdentityModel.SecurityMessageSerializationException ex)
            {
                throw FxTrace.Exception.AsError(new MessageSecurityException(ex.Message));
            }
        }
 
        protected override SecurityKeyIdentifier ReadKeyIdentifierCore(XmlReader reader)
        {
            try
            {
                return _keyInfoSerializer.ReadKeyIdentifier(reader);
            }
            catch (System.IdentityModel.SecurityMessageSerializationException ex)
            {
                throw FxTrace.Exception.AsError(new MessageSecurityException(ex.Message));
            }
        }
 
        protected override bool CanWriteKeyIdentifierCore(SecurityKeyIdentifier keyIdentifier)
        {
            try
            {
                return _keyInfoSerializer.CanWriteKeyIdentifier(keyIdentifier);
            }
            catch (System.IdentityModel.SecurityMessageSerializationException ex)
            {
                throw FxTrace.Exception.AsError(new MessageSecurityException(ex.Message));
            }
        }
 
        protected override void WriteKeyIdentifierCore(XmlWriter writer, SecurityKeyIdentifier keyIdentifier)
        {
            try
            {
                _keyInfoSerializer.WriteKeyIdentifier(writer, keyIdentifier);
            }
            catch (System.IdentityModel.SecurityMessageSerializationException ex)
            {
                throw FxTrace.Exception.AsError(new MessageSecurityException(ex.Message));
            }
        }
 
        protected override bool CanReadKeyIdentifierClauseCore(XmlReader reader)
        {
            try
            {
                return _keyInfoSerializer.CanReadKeyIdentifierClause(reader);
            }
            catch (System.IdentityModel.SecurityMessageSerializationException ex)
            {
                throw FxTrace.Exception.AsError(new MessageSecurityException(ex.Message));
            }
        }
 
        protected override SecurityKeyIdentifierClause ReadKeyIdentifierClauseCore(XmlReader reader)
        {
            try
            {
                return _keyInfoSerializer.ReadKeyIdentifierClause(reader);
            }
            catch (System.IdentityModel.SecurityMessageSerializationException ex)
            {
                throw FxTrace.Exception.AsError(new MessageSecurityException(ex.Message));
            }
        }
 
        protected override bool CanWriteKeyIdentifierClauseCore(SecurityKeyIdentifierClause keyIdentifierClause)
        {
            try
            {
                return _keyInfoSerializer.CanWriteKeyIdentifierClause(keyIdentifierClause);
            }
            catch (System.IdentityModel.SecurityMessageSerializationException ex)
            {
                throw FxTrace.Exception.AsError(new MessageSecurityException(ex.Message));
            }
        }
 
        protected override void WriteKeyIdentifierClauseCore(XmlWriter writer, SecurityKeyIdentifierClause keyIdentifierClause)
        {
            try
            {
                _keyInfoSerializer.WriteKeyIdentifierClause(writer, keyIdentifierClause);
            }
            catch (System.IdentityModel.SecurityMessageSerializationException ex)
            {
                throw FxTrace.Exception.AsError(new MessageSecurityException(ex.Message));
            }
        }
 
        internal Type[] GetTokenTypes(string tokenTypeUri)
        {
            if (tokenTypeUri != null)
            {
                for (int i = 0; i < _tokenEntries.Count; i++)
                {
                    TokenEntry tokenEntry = _tokenEntries[i];
 
                    if (tokenEntry.SupportsTokenTypeUri(tokenTypeUri))
                    {
                        return tokenEntry.GetTokenTypes();
                    }
                }
            }
            return null;
        }
 
        protected internal virtual string GetTokenTypeUri(Type tokenType)
        {
            if (tokenType != null)
            {
                for (int i = 0; i < _tokenEntries.Count; i++)
                {
                    TokenEntry tokenEntry = _tokenEntries[i];
 
                    if (tokenEntry.SupportsCore(tokenType))
                    {
                        return tokenEntry.TokenTypeUri;
                    }
                }
            }
            return null;
        }
 
        public virtual bool TryCreateKeyIdentifierClauseFromTokenXml(XmlElement element, SecurityTokenReferenceStyle tokenReferenceStyle, out SecurityKeyIdentifierClause securityKeyIdentifierClause)
        {
            if (element == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("element");
 
            securityKeyIdentifierClause = null;
 
            try
            {
                securityKeyIdentifierClause = CreateKeyIdentifierClauseFromTokenXml(element, tokenReferenceStyle);
            }
            catch (XmlException e)
            {
                return false;
            }
 
            return true;
        }
 
        public virtual SecurityKeyIdentifierClause CreateKeyIdentifierClauseFromTokenXml(XmlElement element, SecurityTokenReferenceStyle tokenReferenceStyle)
        {
            if (element == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("element");
 
            for (int i = 0; i < _tokenEntries.Count; i++)
            {
                TokenEntry tokenEntry = _tokenEntries[i];
                if (tokenEntry.CanReadTokenCore(element))
                {
                    try
                    {
                        return tokenEntry.CreateKeyIdentifierClauseFromTokenXmlCore(element, tokenReferenceStyle);
                    }
#pragma warning disable 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (!ShouldWrapException(e))
                        {
                            throw;
                        }
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(string.Format(SRServiceModel.ErrorDeserializingKeyIdentifierClauseFromTokenXml), e));
                    }
                }
            }
 
            // PreSharp Bug: Parameter 'element' to this public method must be validated: A null-dereference can occur here.
#pragma warning disable 56506
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(string.Format(SRServiceModel.CannotReadToken, element.LocalName, element.NamespaceURI, element.GetAttribute(SecurityJan2004Strings.ValueType, null))));
        }
 
        internal abstract new class TokenEntry
        {
            private Type[] _tokenTypes = null;
            public virtual IAsyncResult BeginReadTokenCore(XmlDictionaryReader reader,
                SecurityTokenResolver tokenResolver, AsyncCallback callback, object state)
            {
                SecurityToken result = this.ReadTokenCore(reader, tokenResolver);
                return new CompletedAsyncResult<SecurityToken>(result, callback, state);
            }
 
            protected abstract XmlDictionaryString LocalName { get; }
            protected abstract XmlDictionaryString NamespaceUri { get; }
            public Type TokenType { get { return GetTokenTypes()[0]; } }
            public abstract string TokenTypeUri { get; }
            protected abstract string ValueTypeUri { get; }
 
            protected abstract Type[] GetTokenTypesCore();
 
            public Type[] GetTokenTypes()
            {
                if (_tokenTypes == null)
                    _tokenTypes = GetTokenTypesCore();
                return _tokenTypes;
            }
 
            public bool SupportsCore(Type tokenType)
            {
                Type[] tokenTypes = GetTokenTypes();
                for (int i = 0; i < tokenTypes.Length; ++i)
                {
                    if (tokenTypes[i].IsAssignableFrom(tokenType))
                        return true;
                }
                return false;
            }
 
            public virtual bool SupportsTokenTypeUri(string tokenTypeUri)
            {
                return (this.TokenTypeUri == tokenTypeUri);
            }
 
            protected static SecurityKeyIdentifierClause CreateDirectReference(XmlElement issuedTokenXml, string idAttributeLocalName, string idAttributeNamespace, Type tokenType)
            {
                string id = issuedTokenXml.GetAttribute(idAttributeLocalName, idAttributeNamespace);
                if (id == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(string.Format(SRServiceModel.RequiredAttributeMissing, idAttributeLocalName, issuedTokenXml.LocalName)));
                }
                return new LocalIdKeyIdentifierClause(id, tokenType);
            }
 
            public virtual bool CanReadTokenCore(XmlElement element)
            {
                string valueTypeUri = null;
 
                if (element.HasAttribute(SecurityJan2004Strings.ValueType, null))
                {
                    valueTypeUri = element.GetAttribute(SecurityJan2004Strings.ValueType, null);
                }
 
                return element.LocalName == LocalName.Value && element.NamespaceURI == NamespaceUri.Value && valueTypeUri == this.ValueTypeUri;
            }
 
            public virtual bool CanReadTokenCore(XmlDictionaryReader reader)
            {
                return reader.IsStartElement(this.LocalName, this.NamespaceUri) &&
                       reader.GetAttribute(XD.SecurityJan2004Dictionary.ValueType, null) == this.ValueTypeUri;
            }
 
            public virtual SecurityToken EndReadTokenCore(IAsyncResult result)
            {
                return CompletedAsyncResult<SecurityToken>.End(result);
            }
 
            public abstract SecurityKeyIdentifierClause CreateKeyIdentifierClauseFromTokenXmlCore(XmlElement issuedTokenXml, SecurityTokenReferenceStyle tokenReferenceStyle);
 
            public abstract SecurityToken ReadTokenCore(XmlDictionaryReader reader, SecurityTokenResolver tokenResolver);
 
            public abstract void WriteTokenCore(XmlDictionaryWriter writer, SecurityToken token);
        }
 
        internal abstract new class SerializerEntries
        {
            public virtual void PopulateTokenEntries(IList<TokenEntry> tokenEntries) { }
        }
 
        internal class CollectionDictionary : IXmlDictionary
        {
            private List<XmlDictionaryString> _dictionaryStrings;
 
            public CollectionDictionary(List<XmlDictionaryString> dictionaryStrings)
            {
                if (dictionaryStrings == null)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("dictionaryStrings"));
 
                _dictionaryStrings = dictionaryStrings;
            }
 
            public bool TryLookup(string value, out XmlDictionaryString result)
            {
                if (value == null)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("value"));
 
                for (int i = 0; i < _dictionaryStrings.Count; ++i)
                {
                    if (_dictionaryStrings[i].Value.Equals(value))
                    {
                        result = _dictionaryStrings[i];
                        return true;
                    }
                }
                result = null;
                return false;
            }
 
            public bool TryLookup(int key, out XmlDictionaryString result)
            {
                for (int i = 0; i < _dictionaryStrings.Count; ++i)
                {
                    if (_dictionaryStrings[i].Key == key)
                    {
                        result = _dictionaryStrings[i];
                        return true;
                    }
                }
                result = null;
                return false;
            }
 
            public bool TryLookup(XmlDictionaryString value, out XmlDictionaryString result)
            {
                if (value == null)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("value"));
 
                for (int i = 0; i < _dictionaryStrings.Count; ++i)
                {
                    if ((_dictionaryStrings[i].Key == value.Key) &&
                        (_dictionaryStrings[i].Value.Equals(value.Value)))
                    {
                        result = _dictionaryStrings[i];
                        return true;
                    }
                }
                result = null;
                return false;
            }
        }
    }
}