File: FrameworkFork\System.ServiceModel\System\ServiceModel\Security\Tokens\IssuedSecurityTokenParameters.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.
 
 
namespace System.ServiceModel.Security.Tokens
{
    using System.Collections.ObjectModel;
    using System.Globalization;
    using System.IdentityModel.Selectors;
    using System.IdentityModel.Tokens;
    using System.Runtime;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Security;
    using System.Text;
    using Microsoft.Xml;
 
    public class IssuedSecurityTokenParameters : SecurityTokenParameters
    {
        private const string wsidPrefix = "wsid";
        private const string wsidNamespace = "http://schemas.xmlsoap.org/ws/2005/05/identity";
        private static readonly string s_wsidPPIClaim = String.Format(CultureInfo.InvariantCulture, "{0}/claims/privatepersonalidentifier", wsidNamespace);
        internal const SecurityKeyType defaultKeyType = SecurityKeyType.SymmetricKey;
        internal const bool defaultUseStrTransform = false;
 
        internal struct AlternativeIssuerEndpoint
        {
            public EndpointAddress IssuerAddress;
            public EndpointAddress IssuerMetadataAddress;
            public Binding IssuerBinding;
        }
 
        private Collection<XmlElement> _additionalRequestParameters = new Collection<XmlElement>();
        private Collection<AlternativeIssuerEndpoint> _alternativeIssuerEndpoints = new Collection<AlternativeIssuerEndpoint>();
        private MessageSecurityVersion _defaultMessageSecurityVersion;
        private EndpointAddress _issuerAddress;
        private EndpointAddress _issuerMetadataAddress;
        private Binding _issuerBinding;
        private int _keySize;
        private SecurityKeyType _keyType = defaultKeyType;
        private Collection<ClaimTypeRequirement> _claimTypeRequirements = new Collection<ClaimTypeRequirement>();
        private bool _useStrTransform = defaultUseStrTransform;
        private string _tokenType;
 
        protected IssuedSecurityTokenParameters(IssuedSecurityTokenParameters other)
            : base(other)
        {
            _defaultMessageSecurityVersion = other._defaultMessageSecurityVersion;
            _issuerAddress = other._issuerAddress;
            _keyType = other._keyType;
            _tokenType = other._tokenType;
            _keySize = other._keySize;
            _useStrTransform = other._useStrTransform;
 
            foreach (XmlElement parameter in other._additionalRequestParameters)
            {
                _additionalRequestParameters.Add((XmlElement)parameter.Clone());
            }
            foreach (ClaimTypeRequirement c in other._claimTypeRequirements)
            {
                _claimTypeRequirements.Add(c);
            }
            if (other._issuerBinding != null)
            {
                _issuerBinding = new CustomBinding(other._issuerBinding);
            }
            _issuerMetadataAddress = other._issuerMetadataAddress;
        }
 
        public IssuedSecurityTokenParameters()
            : this(null, null, null)
        {
            // empty
        }
 
        public IssuedSecurityTokenParameters(string tokenType)
            : this(tokenType, null, null)
        {
            // empty
        }
 
        public IssuedSecurityTokenParameters(string tokenType, EndpointAddress issuerAddress)
            : this(tokenType, issuerAddress, null)
        {
            // empty
        }
 
        public IssuedSecurityTokenParameters(string tokenType, EndpointAddress issuerAddress, Binding issuerBinding)
            : base()
        {
            _tokenType = tokenType;
            _issuerAddress = issuerAddress;
            _issuerBinding = issuerBinding;
        }
 
        internal protected override bool HasAsymmetricKey { get { return this.KeyType == SecurityKeyType.AsymmetricKey; } }
 
        public Collection<XmlElement> AdditionalRequestParameters
        {
            get
            {
                return _additionalRequestParameters;
            }
        }
 
        public MessageSecurityVersion DefaultMessageSecurityVersion
        {
            get
            {
                return _defaultMessageSecurityVersion;
            }
 
            set
            {
                _defaultMessageSecurityVersion = value;
            }
        }
 
        internal Collection<AlternativeIssuerEndpoint> AlternativeIssuerEndpoints
        {
            get
            {
                return _alternativeIssuerEndpoints;
            }
        }
 
        public EndpointAddress IssuerAddress
        {
            get
            {
                return _issuerAddress;
            }
            set
            {
                _issuerAddress = value;
            }
        }
 
        public EndpointAddress IssuerMetadataAddress
        {
            get
            {
                return _issuerMetadataAddress;
            }
            set
            {
                _issuerMetadataAddress = value;
            }
        }
 
        public Binding IssuerBinding
        {
            get
            {
                return _issuerBinding;
            }
            set
            {
                _issuerBinding = value;
            }
        }
 
        public SecurityKeyType KeyType
        {
            get
            {
                return _keyType;
            }
            set
            {
                SecurityKeyTypeHelper.Validate(value);
                _keyType = value;
            }
        }
 
        public int KeySize
        {
            get
            {
                return _keySize;
            }
            set
            {
                if (value < 0)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SRServiceModel.ValueMustBeNonNegative));
                _keySize = value;
            }
        }
 
        public bool UseStrTransform
        {
            get
            {
                return _useStrTransform;
            }
            set
            {
                _useStrTransform = value;
            }
        }
 
        public Collection<ClaimTypeRequirement> ClaimTypeRequirements
        {
            get
            {
                return _claimTypeRequirements;
            }
        }
 
        public string TokenType
        {
            get
            {
                return _tokenType;
            }
            set
            {
                _tokenType = value;
            }
        }
 
        internal protected override bool SupportsClientAuthentication { get { return true; } }
        internal protected override bool SupportsServerAuthentication { get { return true; } }
        internal protected override bool SupportsClientWindowsIdentity { get { return false; } }
 
        protected override SecurityTokenParameters CloneCore()
        {
            return new IssuedSecurityTokenParameters(this);
        }
        internal void SetRequestParameters(Collection<XmlElement> requestParameters, TrustDriver trustDriver)
        {
            if (requestParameters == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("requestParameters");
 
            if (trustDriver == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("trustDriver");
 
            Collection<XmlElement> unknownRequestParameters = new Collection<XmlElement>();
 
            foreach (XmlElement element in requestParameters)
            {
                int keySize;
                string tokenType;
                SecurityKeyType keyType;
                Collection<XmlElement> requiredClaims;
                if (trustDriver.TryParseKeySizeElement(element, out keySize))
                    _keySize = keySize;
                else if (trustDriver.TryParseKeyTypeElement(element, out keyType))
                    this.KeyType = keyType;
                else if (trustDriver.TryParseTokenTypeElement(element, out tokenType))
                    this.TokenType = tokenType;
                // Only copy RP policy to client policy for TrustFeb2005
                else if (trustDriver.StandardsManager.TrustVersion == TrustVersion.WSTrustFeb2005)
                {
                    if (trustDriver.TryParseRequiredClaimsElement(element, out requiredClaims))
                    {
                        Collection<XmlElement> unrecognizedRequiredClaims = new Collection<XmlElement>();
                        foreach (XmlElement claimRequirement in requiredClaims)
                        {
                            if (claimRequirement.LocalName == "ClaimType" && claimRequirement.NamespaceURI == wsidNamespace)
                            {
                                string claimValue = claimRequirement.GetAttribute("Uri", string.Empty);
                                if (!string.IsNullOrEmpty(claimValue))
                                {
                                    ClaimTypeRequirement claimTypeRequirement;
                                    string optional = claimRequirement.GetAttribute("Optional", string.Empty);
                                    if (String.IsNullOrEmpty(optional))
                                    {
                                        claimTypeRequirement = new ClaimTypeRequirement(claimValue);
                                    }
                                    else
                                    {
                                        claimTypeRequirement = new ClaimTypeRequirement(claimValue, XmlConvert.ToBoolean(optional));
                                    }
 
                                    _claimTypeRequirements.Add(claimTypeRequirement);
                                }
                            }
                            else
                            {
                                unrecognizedRequiredClaims.Add(claimRequirement);
                            }
                        }
                        if (unrecognizedRequiredClaims.Count > 0)
                            unknownRequestParameters.Add(trustDriver.CreateRequiredClaimsElement(unrecognizedRequiredClaims));
                    }
                    else
                    {
                        unknownRequestParameters.Add(element);
                    }
                }
            }
 
            unknownRequestParameters = trustDriver.ProcessUnknownRequestParameters(unknownRequestParameters, requestParameters);
            if (unknownRequestParameters.Count > 0)
            {
                for (int i = 0; i < unknownRequestParameters.Count; ++i)
                    this.AdditionalRequestParameters.Add(unknownRequestParameters[i]);
            }
        }
 
        public Collection<XmlElement> CreateRequestParameters(MessageSecurityVersion messageSecurityVersion, SecurityTokenSerializer securityTokenSerializer)
        {
            return CreateRequestParameters(SecurityUtils.CreateSecurityStandardsManager(messageSecurityVersion, securityTokenSerializer).TrustDriver);
        }
 
        internal Collection<XmlElement> CreateRequestParameters(TrustDriver driver)
        {
            if (driver == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("driver");
 
            Collection<XmlElement> result = new Collection<XmlElement>();
 
            if (_tokenType != null)
            {
                result.Add(driver.CreateTokenTypeElement(_tokenType));
            }
 
            result.Add(driver.CreateKeyTypeElement(_keyType));
 
            if (_keySize != 0)
            {
                result.Add(driver.CreateKeySizeElement(_keySize));
            }
            if (_claimTypeRequirements.Count > 0)
            {
                Collection<XmlElement> claimsElements = new Collection<XmlElement>();
                XmlDocument doc = new XmlDocument();
                foreach (ClaimTypeRequirement claimType in _claimTypeRequirements)
                {
                    XmlElement element = doc.CreateElement(wsidPrefix, "ClaimType", wsidNamespace);
                    XmlAttribute attr = doc.CreateAttribute("Uri");
                    attr.Value = claimType.ClaimType;
                    element.Attributes.Append(attr);
                    if (claimType.IsOptional != ClaimTypeRequirement.DefaultIsOptional)
                    {
                        attr = doc.CreateAttribute("Optional");
                        attr.Value = XmlConvert.ToString(claimType.IsOptional);
                        element.Attributes.Append(attr);
                    }
                    claimsElements.Add(element);
                }
                result.Add(driver.CreateRequiredClaimsElement(claimsElements));
            }
 
            if (_additionalRequestParameters.Count > 0)
            {
                Collection<XmlElement> trustNormalizedParameters = NormalizeAdditionalParameters(_additionalRequestParameters,
                                                                                                 driver,
                                                                                                 (_claimTypeRequirements.Count > 0));
 
                foreach (XmlElement parameter in trustNormalizedParameters)
                {
                    result.Add(parameter);
                }
            }
 
            return result;
        }
 
        private Collection<XmlElement> NormalizeAdditionalParameters(Collection<XmlElement> additionalParameters,
                                                                     TrustDriver driver,
                                                                     bool clientSideClaimTypeRequirementsSpecified)
        {
            throw new NotImplementedException();
        }
 
        private bool CollectionContainsElementsWithTrustNamespace(Collection<XmlElement> collection, string trustNamespace)
        {
            for (int i = 0; i < collection.Count; i++)
            {
                if ((collection[i] != null) && (collection[i].NamespaceURI == trustNamespace))
                {
                    return true;
                }
            }
            return false;
        }
 
        internal void AddAlgorithmParameters(SecurityAlgorithmSuite algorithmSuite, SecurityStandardsManager standardsManager, SecurityKeyType issuedKeyType)
        {
            this._additionalRequestParameters.Insert(0, standardsManager.TrustDriver.CreateEncryptionAlgorithmElement(algorithmSuite.DefaultEncryptionAlgorithm));
            this._additionalRequestParameters.Insert(0, standardsManager.TrustDriver.CreateCanonicalizationAlgorithmElement(algorithmSuite.DefaultCanonicalizationAlgorithm));
 
            if (this._keyType == SecurityKeyType.BearerKey)
            {
                // As the client does not have a proof token in the Bearer case
                // we don't have any specific algorithms to request for.
                return;
            }
 
            string signWithAlgorithm = (this._keyType == SecurityKeyType.SymmetricKey) ? algorithmSuite.DefaultSymmetricSignatureAlgorithm : algorithmSuite.DefaultAsymmetricSignatureAlgorithm;
            this._additionalRequestParameters.Insert(0, standardsManager.TrustDriver.CreateSignWithElement(signWithAlgorithm));
            string encryptWithAlgorithm;
            if (issuedKeyType == SecurityKeyType.SymmetricKey)
            {
                encryptWithAlgorithm = algorithmSuite.DefaultEncryptionAlgorithm;
            }
            else
            {
                encryptWithAlgorithm = algorithmSuite.DefaultAsymmetricKeyWrapAlgorithm;
            }
            this._additionalRequestParameters.Insert(0, standardsManager.TrustDriver.CreateEncryptWithElement(encryptWithAlgorithm));
 
            if (standardsManager.TrustVersion != TrustVersion.WSTrustFeb2005)
            {
                this._additionalRequestParameters.Insert(0, ((WSTrustDec2005.DriverDec2005)standardsManager.TrustDriver).CreateKeyWrapAlgorithmElement(algorithmSuite.DefaultAsymmetricKeyWrapAlgorithm));
            }
 
            return;
        }
 
        internal bool DoAlgorithmsMatch(SecurityAlgorithmSuite algorithmSuite, SecurityStandardsManager standardsManager, out Collection<XmlElement> otherRequestParameters)
        {
            bool doesSignWithAlgorithmMatch = false;
            bool doesEncryptWithAlgorithmMatch = false;
            bool doesEncryptionAlgorithmMatch = false;
            bool doesCanonicalizationAlgorithmMatch = false;
            bool doesKeyWrapAlgorithmMatch = false;
            otherRequestParameters = new Collection<XmlElement>();
            bool trustNormalizationPerformed = false;
 
            Collection<XmlElement> trustVersionNormalizedParameterCollection;
 
            // For Trust 1.3 we move all the additional parameters into the secondaryParameters
            // element. So the list contains just one element called SecondaryParameters that 
            // contains all the other elements as child elements.
            if ((standardsManager.TrustVersion == TrustVersion.WSTrust13) &&
                (this.AdditionalRequestParameters.Count == 1) &&
                (((WSTrustDec2005.DriverDec2005)standardsManager.TrustDriver).IsSecondaryParametersElement(this.AdditionalRequestParameters[0])))
            {
                trustNormalizationPerformed = true;
                trustVersionNormalizedParameterCollection = new Collection<XmlElement>();
                foreach (XmlElement innerElement in this.AdditionalRequestParameters[0])
                {
                    trustVersionNormalizedParameterCollection.Add(innerElement);
                }
            }
            else
            {
                trustVersionNormalizedParameterCollection = this.AdditionalRequestParameters;
            }
 
            for (int i = 0; i < trustVersionNormalizedParameterCollection.Count; i++)
            {
                string algorithm;
                XmlElement element = trustVersionNormalizedParameterCollection[i];
                if (standardsManager.TrustDriver.IsCanonicalizationAlgorithmElement(element, out algorithm))
                {
                    if (algorithmSuite.DefaultCanonicalizationAlgorithm != algorithm)
                    {
                        return false;
                    }
                    doesCanonicalizationAlgorithmMatch = true;
                }
                else if (standardsManager.TrustDriver.IsSignWithElement(element, out algorithm))
                {
                    if ((this._keyType == SecurityKeyType.SymmetricKey && algorithm != algorithmSuite.DefaultSymmetricSignatureAlgorithm)
                        || (this._keyType == SecurityKeyType.AsymmetricKey && algorithm != algorithmSuite.DefaultAsymmetricSignatureAlgorithm))
                    {
                        return false;
                    }
                    doesSignWithAlgorithmMatch = true;
                }
                else if (standardsManager.TrustDriver.IsEncryptWithElement(element, out algorithm))
                {
                    if ((this._keyType == SecurityKeyType.SymmetricKey && algorithm != algorithmSuite.DefaultEncryptionAlgorithm)
                        || (this._keyType == SecurityKeyType.AsymmetricKey && algorithm != algorithmSuite.DefaultAsymmetricKeyWrapAlgorithm))
                    {
                        return false;
                    }
                    doesEncryptWithAlgorithmMatch = true;
                }
                else if (standardsManager.TrustDriver.IsEncryptionAlgorithmElement(element, out algorithm))
                {
                    if (algorithm != algorithmSuite.DefaultEncryptionAlgorithm)
                    {
                        return false;
                    }
                    doesEncryptionAlgorithmMatch = true;
                }
                else if (standardsManager.TrustDriver.IsKeyWrapAlgorithmElement(element, out algorithm))
                {
                    if (algorithm != algorithmSuite.DefaultAsymmetricKeyWrapAlgorithm)
                    {
                        return false;
                    }
                    doesKeyWrapAlgorithmMatch = true;
                }
                else
                {
                    otherRequestParameters.Add(element);
                }
            }
 
            // Undo normalization if performed
            // move all back into secondaryParameters
            if (trustNormalizationPerformed)
            {
                otherRequestParameters = this.AdditionalRequestParameters;
            }
 
            if (this._keyType == SecurityKeyType.BearerKey)
            {
                // As the client does not have a proof token in the Bearer case
                // we don't have any specific algorithms to request for.
                return true;
            }
            if (standardsManager.TrustVersion == TrustVersion.WSTrustFeb2005)
            {
                // For V1 compatibility check all algorithms
                return (doesSignWithAlgorithmMatch && doesCanonicalizationAlgorithmMatch && doesEncryptionAlgorithmMatch && doesEncryptWithAlgorithmMatch);
            }
            else
            {
                return (doesSignWithAlgorithmMatch && doesCanonicalizationAlgorithmMatch && doesEncryptionAlgorithmMatch && doesEncryptWithAlgorithmMatch && doesKeyWrapAlgorithmMatch);
            }
        }
 
        internal static IssuedSecurityTokenParameters CreateInfoCardParameters(SecurityStandardsManager standardsManager, SecurityAlgorithmSuite algorithm)
        {
            IssuedSecurityTokenParameters result = new IssuedSecurityTokenParameters(SecurityXXX2005Strings.SamlTokenType);
            result.KeyType = SecurityKeyType.AsymmetricKey;
            result.ClaimTypeRequirements.Add(new ClaimTypeRequirement(s_wsidPPIClaim));
            result.IssuerAddress = null;
            result.AddAlgorithmParameters(algorithm, standardsManager, result.KeyType);
            return result;
        }
 
        internal static bool IsInfoCardParameters(IssuedSecurityTokenParameters parameters, SecurityStandardsManager standardsManager)
        {
            if (parameters == null)
                return false;
            if (parameters.TokenType != SecurityXXX2005Strings.SamlTokenType)
                return false;
            if (parameters.KeyType != SecurityKeyType.AsymmetricKey)
                return false;
 
            if (parameters.ClaimTypeRequirements.Count == 1)
            {
                ClaimTypeRequirement claimTypeRequirement = parameters.ClaimTypeRequirements[0] as ClaimTypeRequirement;
                if (claimTypeRequirement == null)
                    return false;
                if (claimTypeRequirement.ClaimType != s_wsidPPIClaim)
                    return false;
            }
            else if ((parameters.AdditionalRequestParameters != null) && (parameters.AdditionalRequestParameters.Count > 0))
            {
                // Check the AdditionalRequest Parameters to see if ClaimTypeRequirements got imported there.
                bool claimTypeRequirementMatched = false;
                XmlElement claimTypeRequirement = GetClaimTypeRequirement(parameters.AdditionalRequestParameters, standardsManager);
                if (claimTypeRequirement != null && claimTypeRequirement.ChildNodes.Count == 1)
                {
                    XmlElement claimTypeElement = claimTypeRequirement.ChildNodes[0] as XmlElement;
                    if (claimTypeElement != null)
                    {
                        XmlNode claimType = claimTypeElement.Attributes.GetNamedItem("Uri");
                        if (claimType != null && claimType.Value == s_wsidPPIClaim)
                        {
                            claimTypeRequirementMatched = true;
                        }
                    }
                }
 
                if (!claimTypeRequirementMatched)
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
            if (parameters.IssuerAddress != null)
                return false;
            if (parameters.AlternativeIssuerEndpoints != null && parameters.AlternativeIssuerEndpoints.Count > 0)
            {
                return false;
            }
            return true;
        }
 
        // The method walks through the entire set of AdditionalRequestParameters and return the Claims Type requirement alone.
        internal static XmlElement GetClaimTypeRequirement(Collection<XmlElement> additionalRequestParameters, SecurityStandardsManager standardsManager)
        {
            throw new NotImplementedException();
        }
 
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.ToString());
 
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "TokenType: {0}", _tokenType == null ? "null" : _tokenType));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "KeyType: {0}", _keyType.ToString()));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "KeySize: {0}", _keySize.ToString(CultureInfo.InvariantCulture)));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "IssuerAddress: {0}", _issuerAddress == null ? "null" : _issuerAddress.ToString()));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "IssuerMetadataAddress: {0}", _issuerMetadataAddress == null ? "null" : _issuerMetadataAddress.ToString()));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "DefaultMessgeSecurityVersion: {0}", _defaultMessageSecurityVersion == null ? "null" : _defaultMessageSecurityVersion.ToString()));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "UseStrTransform: {0}", _useStrTransform.ToString()));
 
            if (_issuerBinding == null)
            {
                sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "IssuerBinding: null"));
            }
            else
            {
                sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "IssuerBinding:"));
                BindingElementCollection bindingElements = _issuerBinding.CreateBindingElements();
                for (int i = 0; i < bindingElements.Count; i++)
                {
                    sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "  BindingElement[{0}]:", i.ToString(CultureInfo.InvariantCulture)));
                    sb.AppendLine("    " + bindingElements[i].ToString().Trim().Replace("\n", "\n    "));
                }
            }
 
            if (_claimTypeRequirements.Count == 0)
            {
                sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "ClaimTypeRequirements: none"));
            }
            else
            {
                sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "ClaimTypeRequirements:"));
                for (int i = 0; i < _claimTypeRequirements.Count; i++)
                {
                    sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "  {0}, optional={1}", _claimTypeRequirements[i].ClaimType, _claimTypeRequirements[i].IsOptional));
                }
            }
 
            return sb.ToString().Trim();
        }
    }
}