File: System\ServiceModel\Security\Tokens\IssuedSecurityTokenParameters.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
 
 
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 System.Xml;
 
    public class IssuedSecurityTokenParameters : SecurityTokenParameters
    {
        const string wsidPrefix = "wsid";
        const string wsidNamespace = "http://schemas.xmlsoap.org/ws/2005/05/identity";
        static readonly string 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;
        }
 
        Collection<XmlElement> additionalRequestParameters = new Collection<XmlElement>();
        Collection<AlternativeIssuerEndpoint> alternativeIssuerEndpoints = new Collection<AlternativeIssuerEndpoint>();
        MessageSecurityVersion defaultMessageSecurityVersion;
        EndpointAddress issuerAddress;
        EndpointAddress issuerMetadataAddress;
        Binding issuerBinding;
        int keySize;
        SecurityKeyType keyType = defaultKeyType;
        Collection<ClaimTypeRequirement> claimTypeRequirements = new Collection<ClaimTypeRequirement>();
        bool useStrTransform = defaultUseStrTransform;
        string tokenType;
 
        protected IssuedSecurityTokenParameters(IssuedSecurityTokenParameters other)
            : base(other)
        {
            this.defaultMessageSecurityVersion = other.defaultMessageSecurityVersion;
            this.issuerAddress = other.issuerAddress;
            this.keyType = other.keyType;
            this.tokenType = other.tokenType;
            this.keySize = other.keySize;
            this.useStrTransform = other.useStrTransform;
 
            foreach (XmlElement parameter in other.additionalRequestParameters)
            {
                this.additionalRequestParameters.Add((XmlElement)parameter.Clone());
            }
            foreach (ClaimTypeRequirement c in other.claimTypeRequirements)
            {
                this.claimTypeRequirements.Add(c);
            }
            if (other.issuerBinding != null)
            {
                this.issuerBinding = new CustomBinding(other.issuerBinding);
            }
            this.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()
        {
            this.tokenType = tokenType;
            this.issuerAddress = issuerAddress;
            this.issuerBinding = issuerBinding;
        }
 
        internal protected override bool HasAsymmetricKey { get { return this.KeyType == SecurityKeyType.AsymmetricKey; } }
 
        public Collection<XmlElement> AdditionalRequestParameters
        {
            get
            {
                return this.additionalRequestParameters;
            }
        }
 
        public MessageSecurityVersion DefaultMessageSecurityVersion
        {
            get
            {
                return this.defaultMessageSecurityVersion;
            }
 
            set
            {
                defaultMessageSecurityVersion = value;
            }
        }
 
        internal Collection<AlternativeIssuerEndpoint> AlternativeIssuerEndpoints
        {
            get
            {
                return this.alternativeIssuerEndpoints;
            }
        }
 
        public EndpointAddress IssuerAddress
        {
            get
            {
                return this.issuerAddress;
            }
            set
            {
                this.issuerAddress = value;
            }
        }
 
        public EndpointAddress IssuerMetadataAddress
        {
            get
            {
                return this.issuerMetadataAddress;
            }
            set
            {
                this.issuerMetadataAddress = value;
            }
        }
 
        public Binding IssuerBinding
        {
            get
            {
                return this.issuerBinding;
            }
            set
            {
                this.issuerBinding = value;
            }
        }
 
        public SecurityKeyType KeyType
        {
            get
            {
                return this.keyType;
            }
            set
            {
                SecurityKeyTypeHelper.Validate(value);
                this.keyType = value;
            }
        }
 
        public int KeySize
        {
            get
            {
                return this.keySize;
            }
            set
            {
                if (value < 0)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.ValueMustBeNonNegative)));
                this.keySize = value;
            }
        }
 
        public bool UseStrTransform
        {
            get
            {
                return this.useStrTransform;
            }
            set
            {
                this.useStrTransform = value;
            }
        }
 
        public Collection<ClaimTypeRequirement> ClaimTypeRequirements
        {
            get
            {
                return this.claimTypeRequirements;
            }
        }
 
        public string TokenType
        {
            get
            {
                return this.tokenType;
            }
            set
            {
                this.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 protected override SecurityKeyIdentifierClause CreateKeyIdentifierClause(SecurityToken token, SecurityTokenReferenceStyle referenceStyle)
        {
            if (token is GenericXmlSecurityToken)
                return base.CreateGenericXmlTokenKeyIdentifierClause(token, referenceStyle);
            else
                return this.CreateKeyIdentifierClause<SamlAssertionKeyIdentifierClause, SamlAssertionKeyIdentifierClause>(token, referenceStyle);
        }
 
        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))
                    this.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));
                                    }
 
                                    this.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 (this.tokenType != null)
            {
                result.Add(driver.CreateTokenTypeElement(tokenType));
            }
 
            result.Add(driver.CreateKeyTypeElement(this.keyType));
 
            if (this.keySize != 0)
            {
                result.Add(driver.CreateKeySizeElement(keySize));
            }
            if (this.claimTypeRequirements.Count > 0)
            {
                Collection<XmlElement> claimsElements = new Collection<XmlElement>();
                XmlDocument doc = new XmlDocument();
                foreach (ClaimTypeRequirement claimType in this.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 (this.additionalRequestParameters.Count > 0)
            {
                Collection<XmlElement> trustNormalizedParameters = NormalizeAdditionalParameters(this.additionalRequestParameters,
                                                                                                 driver,
                                                                                                 (this.claimTypeRequirements.Count > 0));
 
                foreach (XmlElement parameter in trustNormalizedParameters)
                {
                    result.Add(parameter);
                }
            }
 
            return result;
        }
 
        private Collection<XmlElement> NormalizeAdditionalParameters(Collection<XmlElement> additionalParameters,
                                                                     TrustDriver driver,
                                                                     bool clientSideClaimTypeRequirementsSpecified)
        {
            // Ensure STS trust version is one of the currently supported versions: Feb 05 / Trust 1.3
            Fx.Assert(((driver.StandardsManager.TrustVersion == TrustVersion.WSTrustFeb2005) ||
                                           (driver.StandardsManager.TrustVersion == TrustVersion.WSTrust13)),
                                           "Unsupported trust version specified for the STS.");
 
            // We have a mismatch. Make a local copy of additionalParameters for making any potential modifications 
            // as part of normalization
            Collection<XmlElement> tmpCollection = new Collection<XmlElement>();
            foreach (XmlElement e in additionalParameters)
            {
                tmpCollection.Add(e);
            }
 
 
            // 1. For Trust 1.3 EncryptionAlgorithm, CanonicalizationAlgorithm and KeyWrapAlgorithm should not be
            //    specified as top-level element if "SecondaryParameters" element already specifies this.
            if (driver.StandardsManager.TrustVersion == TrustVersion.WSTrust13)
            {
                Fx.Assert(driver.GetType() == typeof(WSTrustDec2005.DriverDec2005), "Invalid Trust Driver specified for Trust 1.3.");
 
                XmlElement encryptionAlgorithmElement = null;
                XmlElement canonicalizationAlgorithmElement = null;
                XmlElement keyWrapAlgorithmElement = null;
                XmlElement secondaryParameter = null;
 
                for (int i = 0; i < tmpCollection.Count; ++i)
                {
                    string algorithm;
 
                    if (driver.IsEncryptionAlgorithmElement(tmpCollection[i], out algorithm))
                    {
                        encryptionAlgorithmElement = tmpCollection[i];
                    }
                    else if (driver.IsCanonicalizationAlgorithmElement(tmpCollection[i], out algorithm))
                    {
                        canonicalizationAlgorithmElement = tmpCollection[i];
                    }
                    else if (driver.IsKeyWrapAlgorithmElement(tmpCollection[i], out algorithm))
                    {
                        keyWrapAlgorithmElement = tmpCollection[i];
                    }
                    else if (((WSTrustDec2005.DriverDec2005)driver).IsSecondaryParametersElement(tmpCollection[i]))
                    {
                        secondaryParameter = tmpCollection[i];
                    }
                }
 
                if (secondaryParameter != null)
                {
                    foreach (XmlNode node in secondaryParameter.ChildNodes)
                    {
                        XmlElement child = node as XmlElement;
                        if (child != null)
                        {
                            string algorithm = null;
 
                            if (driver.IsEncryptionAlgorithmElement(child, out algorithm) && (encryptionAlgorithmElement != null))
                            {
                                tmpCollection.Remove(encryptionAlgorithmElement);
                            }
                            else if (driver.IsCanonicalizationAlgorithmElement(child, out algorithm) && (canonicalizationAlgorithmElement != null))
                            {
                                tmpCollection.Remove(canonicalizationAlgorithmElement);
                            }
                            else if (driver.IsKeyWrapAlgorithmElement(child, out algorithm) && (keyWrapAlgorithmElement != null))
                            {
                                tmpCollection.Remove(keyWrapAlgorithmElement);
                            }
                        }
                    }
                }
            }
 
            // 2. Check for Mismatch.
            //      a. Trust Feb 2005 -> Trust 1.3. do the following,
            //          (i) Copy EncryptionAlgorithm and CanonicalizationAlgorithm as the top-level elements.
            //              Note, this is in contradiction to step 1. But we don't have a choice here as we cannot say from the 
            //              Additional Parameters section in the config what came from the service and what came from the client.
            //          (ii) Convert SignWith and EncryptWith elements to Trust 1.3 namespace.
            //      b. For Trust 1.3 -> Trust Feb 2005, do the following,
            //          (i) Find EncryptionAlgorithm, CanonicalizationAlgorithm from inside the "SecondaryParameters" element. 
            //              If found, then promote these as the top-level elements replacing the existing values.
            //          (ii) Convert the SignWith and EncryptWith elements to the Trust Feb 2005 namespace and drop the KeyWrapAlgorithm
            //               element.
 
            // make an optimistic check to detect mismatched trust-versions between STS and RP
            bool mismatch = (((driver.StandardsManager.TrustVersion == TrustVersion.WSTrustFeb2005) &&
                              !CollectionContainsElementsWithTrustNamespace(additionalParameters, TrustFeb2005Strings.Namespace)) ||
                             ((driver.StandardsManager.TrustVersion == TrustVersion.WSTrust13) &&
                              !CollectionContainsElementsWithTrustNamespace(additionalParameters, TrustDec2005Strings.Namespace)));
            // if no mismatch, return unmodified collection
            if (!mismatch)
            {
                return tmpCollection;
            }
 
            // 2.a
            // If we are talking to a Trust 1.3 STS, replace any Feb '05 algorithm parameters with their Trust 1.3 counterparts
            if (driver.StandardsManager.TrustVersion == TrustVersion.WSTrust13)
            {
                SecurityStandardsManager trustFeb2005StandardsManager = SecurityStandardsManager.DefaultInstance;
                // the following cast is guaranteed to succeed
                WSTrustFeb2005.DriverFeb2005 trustFeb2005Driver = (WSTrustFeb2005.DriverFeb2005)trustFeb2005StandardsManager.TrustDriver;
 
                for (int i = 0; i < tmpCollection.Count; i++)
                {
                    string algorithmParameter = string.Empty;
 
                    if (trustFeb2005Driver.IsSignWithElement(tmpCollection[i], out algorithmParameter))
                    {
                        tmpCollection[i] = driver.CreateSignWithElement(algorithmParameter);
                    }
                    else if (trustFeb2005Driver.IsEncryptWithElement(tmpCollection[i], out algorithmParameter))
                    {
                        tmpCollection[i] = driver.CreateEncryptWithElement(algorithmParameter);
                    }
                    else if (trustFeb2005Driver.IsEncryptionAlgorithmElement(tmpCollection[i], out algorithmParameter))
                    {
                        tmpCollection[i] = driver.CreateEncryptionAlgorithmElement(algorithmParameter);
                    }
                    else if (trustFeb2005Driver.IsCanonicalizationAlgorithmElement(tmpCollection[i], out algorithmParameter))
                    {
                        tmpCollection[i] = driver.CreateCanonicalizationAlgorithmElement(algorithmParameter);
                    }
                }
            }
            else
            {
                // 2.b
                // We are talking to a Feb 05 STS. Filter out any SecondaryParameters element.
                Collection<XmlElement> childrenToPromote = null;
                WSSecurityTokenSerializer trust13Serializer = new WSSecurityTokenSerializer(SecurityVersion.WSSecurity11,
                                                                                            TrustVersion.WSTrust13,
                                                                                            SecureConversationVersion.WSSecureConversation13,
                                                                                            true, null, null, null);
                SecurityStandardsManager trust13StandardsManager = new SecurityStandardsManager(MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12, trust13Serializer);
                // the following cast is guaranteed to succeed
                WSTrustDec2005.DriverDec2005 trust13Driver = (WSTrustDec2005.DriverDec2005)trust13StandardsManager.TrustDriver;
 
                foreach (XmlElement parameter in tmpCollection)
                {
                    // check if SecondaryParameters is present
                    if (trust13Driver.IsSecondaryParametersElement(parameter))
                    {
                        childrenToPromote = new Collection<XmlElement>();
                        // walk SecondaryParameters and collect any 'non-standard' children
                        foreach (XmlNode innerNode in parameter.ChildNodes)
                        {
                            XmlElement innerElement = innerNode as XmlElement;
                            if ((innerElement != null) && CanPromoteToRoot(innerElement, trust13Driver, clientSideClaimTypeRequirementsSpecified))
                            {
                                childrenToPromote.Add(innerElement);
                            }
                        }
 
                        // remove SecondaryParameters element
                        tmpCollection.Remove(parameter);
 
                        // we are done - break out of the loop
                        break;
                    }
                }
 
                // Probe of standard Trust elements and remember them.
                if ((childrenToPromote != null) && (childrenToPromote.Count > 0))
                {
                    XmlElement encryptionElement = null;
                    string encryptionAlgorithm = String.Empty;
 
                    XmlElement canonicalizationElement = null;
                    string canonicalizationAlgoritm = String.Empty;
 
                    XmlElement requiredClaimsElement = null;
                    Collection<XmlElement> requiredClaims = null;
 
                    Collection<XmlElement> processedElements = new Collection<XmlElement>();
 
                    foreach (XmlElement e in childrenToPromote)
                    {
                        if ((encryptionElement == null) && trust13Driver.IsEncryptionAlgorithmElement(e, out encryptionAlgorithm))
                        {
                            encryptionElement = driver.CreateEncryptionAlgorithmElement(encryptionAlgorithm);
                            processedElements.Add(e);
                        }
                        else if ((canonicalizationElement == null) && trust13Driver.IsCanonicalizationAlgorithmElement(e, out canonicalizationAlgoritm))
                        {
                            canonicalizationElement = driver.CreateCanonicalizationAlgorithmElement(canonicalizationAlgoritm);
                            processedElements.Add(e);
                        }
                        else if ((requiredClaimsElement == null) && trust13Driver.TryParseRequiredClaimsElement(e, out requiredClaims))
                        {
                            requiredClaimsElement = driver.CreateRequiredClaimsElement(requiredClaims);
                            processedElements.Add(e);
                        }
                    }
 
                    for (int i = 0; i < processedElements.Count; ++i)
                    {
                        childrenToPromote.Remove(processedElements[i]);
                    }
 
                    XmlElement keyWrapAlgorithmElement = null;
 
                    // Replace the appropriate elements.
                    for (int i = 0; i < tmpCollection.Count; ++i)
                    {
                        string algorithmParameter;
                        Collection<XmlElement> reqClaims;
 
                        if (trust13Driver.IsSignWithElement(tmpCollection[i], out algorithmParameter))
                        {
                            tmpCollection[i] = driver.CreateSignWithElement(algorithmParameter);
                        }
                        else if (trust13Driver.IsEncryptWithElement(tmpCollection[i], out algorithmParameter))
                        {
                            tmpCollection[i] = driver.CreateEncryptWithElement(algorithmParameter);
                        }
                        else if (trust13Driver.IsEncryptionAlgorithmElement(tmpCollection[i], out algorithmParameter) && (encryptionElement != null))
                        {
                            tmpCollection[i] = encryptionElement;
                            encryptionElement = null;
                        }
                        else if (trust13Driver.IsCanonicalizationAlgorithmElement(tmpCollection[i], out algorithmParameter) && (canonicalizationElement != null))
                        {
                            tmpCollection[i] = canonicalizationElement;
                            canonicalizationElement = null;
                        }
                        else if (trust13Driver.IsKeyWrapAlgorithmElement(tmpCollection[i], out algorithmParameter) && (keyWrapAlgorithmElement == null))
                        {
                            keyWrapAlgorithmElement = tmpCollection[i];
                        }
                        else if (trust13Driver.TryParseRequiredClaimsElement(tmpCollection[i], out reqClaims) && (requiredClaimsElement != null))
                        {
                            tmpCollection[i] = requiredClaimsElement;
                            requiredClaimsElement = null;
                        }
                    }
 
                    if (keyWrapAlgorithmElement != null)
                    {
                        // Remove KeyWrapAlgorithmElement as this is not define in Trust Feb 2005.
                        tmpCollection.Remove(keyWrapAlgorithmElement);
                    }
 
                    // Add the remaining elements to the additionaParameters list to the end.
                    if (encryptionElement != null) tmpCollection.Add(encryptionElement);
                    if (canonicalizationElement != null) tmpCollection.Add(canonicalizationElement);
                    if (requiredClaimsElement != null) tmpCollection.Add(requiredClaimsElement);
 
                    if (childrenToPromote.Count > 0)
                    {
                        // There are some non-standard elements. Just bump them to the top-level element.
                        for (int i = 0; i < childrenToPromote.Count; ++i)
                        {
                            tmpCollection.Add(childrenToPromote[i]);
                        }
                    }
                }
 
            }
 
            return tmpCollection;
        }
 
        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;
        }
 
        private bool CanPromoteToRoot(XmlElement innerElement, WSTrustDec2005.DriverDec2005 trust13Driver, bool clientSideClaimTypeRequirementsSpecified)
        {
            SecurityKeyType dummyOutParamForKeyType;
            int dummyOutParamForKeySize;
            string dummyStringOutParam;
            Collection<XmlElement> dummyOutParamForRequiredClaims = null;
 
            // check if SecondaryParameters has claim requirements specified
            if (trust13Driver.TryParseRequiredClaimsElement(innerElement, out dummyOutParamForRequiredClaims))
            {
                // if client has not specified any claim requirements, promote claim requirements 
                // in SecondaryParameters to root level (and subsequently fix up the trust namespace)
                return !clientSideClaimTypeRequirementsSpecified;
            }
 
            // KeySize, KeyType and TokenType were converted to top-level property values when the WSDL was
            // imported, so drop it here. We check for EncryptWith and SignWith as these are Client specific algorithm values and we
            // don't have to promote the service specified values. KeyWrapAlgorithm was never sent in the RST
            // in V1 and hence we are dropping it here as well.
            return (!trust13Driver.TryParseKeyTypeElement(innerElement, out dummyOutParamForKeyType) &&
                    !trust13Driver.TryParseKeySizeElement(innerElement, out dummyOutParamForKeySize) &&
                    !trust13Driver.TryParseTokenTypeElement(innerElement, out dummyStringOutParam) &&
                    !trust13Driver.IsSignWithElement(innerElement, out dummyStringOutParam) &&
                    !trust13Driver.IsEncryptWithElement(innerElement, out dummyStringOutParam) &&
                    !trust13Driver.IsKeyWrapAlgorithmElement(innerElement, out dummyStringOutParam));
        }
 
        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(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 != 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 == 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)
        {
            foreach (XmlElement requestParameter in additionalRequestParameters)
            {
                if ((requestParameter.LocalName == ((System.ServiceModel.Security.WSTrust.Driver)standardsManager.TrustDriver).DriverDictionary.Claims.Value) &&
                    (requestParameter.NamespaceURI == ((System.ServiceModel.Security.WSTrust.Driver)standardsManager.TrustDriver).DriverDictionary.Namespace.Value))
                {
                    return requestParameter;
                }
 
                if ((requestParameter.LocalName == DXD.TrustDec2005Dictionary.SecondaryParameters.Value) &&
                    (requestParameter.NamespaceURI == DXD.TrustDec2005Dictionary.Namespace.Value))
                {
                    Collection<XmlElement> secondaryParameters = new Collection<XmlElement>();
                    foreach (XmlNode node in requestParameter.ChildNodes)
                    {
                        XmlElement nodeAsElement = node as XmlElement;
                        if (nodeAsElement != null)
                        {
                            secondaryParameters.Add(nodeAsElement);
                        }
                    }
                    XmlElement claimTypeRequirement = GetClaimTypeRequirement(secondaryParameters, standardsManager);
                    if (claimTypeRequirement != null)
                    {
                        return claimTypeRequirement;
                    }
                }
            }
 
            return null;
        }
 
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.ToString());
 
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "TokenType: {0}", this.tokenType == null ? "null" : this.tokenType));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "KeyType: {0}", this.keyType.ToString()));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "KeySize: {0}", this.keySize.ToString(CultureInfo.InvariantCulture)));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "IssuerAddress: {0}", this.issuerAddress == null ? "null" : this.issuerAddress.ToString()));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "IssuerMetadataAddress: {0}", this.issuerMetadataAddress == null ? "null" : this.issuerMetadataAddress.ToString()));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "DefaultMessgeSecurityVersion: {0}", this.defaultMessageSecurityVersion == null ? "null" : this.defaultMessageSecurityVersion.ToString()));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "UseStrTransform: {0}", this.useStrTransform.ToString()));
 
            if (this.issuerBinding == null)
            {
                sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "IssuerBinding: null"));
            }
            else
            {
                sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "IssuerBinding:"));
                BindingElementCollection bindingElements = this.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 (this.claimTypeRequirements.Count == 0)
            {
                sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "ClaimTypeRequirements: none"));
            }
            else
            {
                sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "ClaimTypeRequirements:"));
                for (int i = 0; i < this.claimTypeRequirements.Count; i++)
                {
                    sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "  {0}, optional={1}", this.claimTypeRequirements[i].ClaimType, this.claimTypeRequirements[i].IsOptional));
                }
            }
 
            return sb.ToString().Trim();
        }
 
        protected internal override void InitializeSecurityTokenRequirement(SecurityTokenRequirement requirement)
        {
            requirement.TokenType = this.TokenType;
            requirement.RequireCryptographicToken = true;
            requirement.KeyType = this.KeyType;
 
            ServiceModelSecurityTokenRequirement serviceModelSecurityTokenRequirement = requirement as ServiceModelSecurityTokenRequirement;
            if (serviceModelSecurityTokenRequirement != null)
            {
                serviceModelSecurityTokenRequirement.DefaultMessageSecurityVersion = this.DefaultMessageSecurityVersion;
            }
            else
            {
                requirement.Properties[ServiceModelSecurityTokenRequirement.DefaultMessageSecurityVersionProperty] = this.DefaultMessageSecurityVersion;
            }
 
            if (this.KeySize > 0)
            {
                requirement.KeySize = this.KeySize;
            }
            requirement.Properties[ServiceModelSecurityTokenRequirement.IssuerAddressProperty] = this.IssuerAddress;
            if (this.IssuerBinding != null)
            {
                requirement.Properties[ServiceModelSecurityTokenRequirement.IssuerBindingProperty] = this.IssuerBinding;
            }
            requirement.Properties[ServiceModelSecurityTokenRequirement.IssuedSecurityTokenParametersProperty] = this.Clone();
        }
    }
}