RemoteTokenFactory.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / infocard / Service / managed / Microsoft / InfoCards / RemoteTokenFactory.cs / 3 / RemoteTokenFactory.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
//
// Presharp uses the c# pragma mechanism to supress its warnings. 
// These are not recognised by the base compiler so we need to explictly
// disable the following warnings. See http://winweb/cse/Tools/PREsharp/userguide/default.asp 
// for details. 
//
#pragma warning disable 1634, 1691      // unknown message, unknown pragma 



namespace Microsoft.InfoCards 
{
    using System; 
    using System.Security; 
    using System.Security.Cryptography;
    using System.Security.Cryptography.Xml; 
    using System.Security.Cryptography.X509Certificates;
    using System.IdentityModel.Tokens;
    using System.ServiceModel;
    using System.ServiceModel.Description; 
    using System.ServiceModel.Channels;
    using System.ServiceModel.Security; 
    using System.ServiceModel.Security.Tokens; 
    using System.Runtime.Serialization;
    using System.Xml; 
    using System.Globalization;
    using System.IO;
    using System.Collections.ObjectModel;
    using System.Collections.Generic; 
    using Microsoft.InfoCards.Diagnostics;
    using IDT = Microsoft.InfoCards.Diagnostics.InfoCardTrace; 
    using System.Net.Security; 
    using System.Net;
    using System.IdentityModel.Claims; 


    //
    // Summary 
    //  This class is used to make request to an Indigo STS for security tokens.
    // 
    internal class RemoteTokenFactory : TokenFactoryBase 
    {
        internal const string MetadataExchangeClientKey = "MetadataExchangeClientKey"; 

        ServiceEndpoint m_endPoint;
        ChannelFactory m_channelFactory;
        object m_channelChangeSync; 
        IWebProxy m_proxy;
        ProtocolProfile m_protocolProfile; 
 
        //
        // Capture the list of claims that we will request for from the IP/STS. 
        // I.e. the claims that will be disclosed to the recipient.
        //
        // The bool specifies if Recipient policy specified that claim as optional or not.
        // We need to track this because we need to add an "optional" attribute in the RST 
        // we send to the IP/STS
        // 
        Dictionary m_disclosedClaims; 

        public RemoteTokenFactory( ServiceEndpoint endPoint, IWebProxy proxy ) 
        {
            m_endPoint = endPoint;
            m_channelChangeSync = new object();
            m_proxy = proxy; 
        }
 
        protected override TokenDescriptor ProduceToken( 
                            InfoCard card,
                            TokenCreationParameter parameter, 
                            TokenFactoryCredential credential,
                            InfoCardPolicy policy,
                            bool discloseOptional )
        { 

            IDT.ThrowInvalidArgumentConditional( null == card, "card" ); 
            IDT.ThrowInvalidArgumentConditional( null == parameter, "parameter" ); 
            IDT.ThrowInvalidArgumentConditional( null == credential, "credential" );
            IDT.ThrowInvalidArgumentConditional( null == policy, "policy" ); 

            DisplayToken displayToken;
            RequestSecurityToken rst;
            RSACryptoServiceProvider identityKey = null; 
            byte[] clientEntropyForSymmetric = null;
            SymmetricAlgorithm sessionKey = null; 
            RSAKeyValue rsaKeyValue = null; 
            string internalTokenReference = string.Empty;
            string externalTokenReference = string.Empty; 
            GenericXmlSecurityToken tok = null;
            ISts sts;

            // 
            // Retrieve the protocol profile from the incoming policy.
            // 
            m_protocolProfile = policy.ProtocolVersionProfile; 

 
            TokenDescriptor token;

            bool needUseKey = false;
            RSATokenProvider endorsingSigTokenProvider = null; 

            try 
            { 
                //
                // Create the appropriate keys. 
                // Note : We will always create the asymmetric key pair.
                // The IP can decide to not use it and send us a new key in the proof token
                //
                if ( SecurityKeyTypeInternal.AsymmetricKey == policy.KeyType ) 
                {
                    // 
                    // Use asymmetric keys - this requires the ledger 
                    // to be in memory [which is the case -- in GetTokenRequest.cs
                    // we fetch the ledgerentry before calling CreateToken]. 
                    // However, a pointer to the ledger entry would be required
                    // if future optimization work removes the global ledger entry
                    //
                    identityKey = card.GetPublicCryptography( policy.Recipient.GetIdentifier() ); 
                    needUseKey = true;
                    IDT.Assert( null == clientEntropyForSymmetric, "Null in in asymmetric case" ); 
                } 
                else if ( SecurityKeyTypeInternal.SymmetricKey == policy.KeyType )
                { 
                    //
                    // We will always send entropy to the IP/STS in the symmetric case.
                    // Generate it here. If the IP/STS used combined entropy,
                    // then we need this information while we are processing the RSTR. 
                    //
                    clientEntropyForSymmetric = new byte[ policy.GetIntelligentKeySize( false ) / 8 ]; 
                    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); 
                    rng.GetNonZeroBytes( clientEntropyForSymmetric );
                    IDT.Assert( null == identityKey, "Null in symmetric case" ); 

                }
                else
                { 
                    IDT.Assert( null == identityKey, "Null in no proof key case" );
                    IDT.Assert( null == clientEntropyForSymmetric, "Null in no proof key case" ); 
                    IDT.Assert( SecurityKeyTypeInternal.NoKey == policy.KeyType, "Null in no proof key case" ); 
                }
 
                if ( null == m_endPoint )
                {
                    m_endPoint = DoMexExchange( parameter, m_proxy );
                } 

                BindingElementCollection bindingElements = m_endPoint.Binding.CreateBindingElements(); 
 
                SecurityBindingElement sbe = bindingElements.Find();
 
                if( null == sbe )
                {
                    throw IDT.ThrowHelperError( new TrustExchangeException( SR.GetString( SR.IndigoNoSuitableEndpointsForAddress, m_endPoint.Address.Uri ) ) );
                } 

                if( sbe.MessageSecurityVersion.TrustVersion == TrustVersion.WSTrust13 ) 
                { 
                    m_protocolProfile.WSTrust = XmlNames.WSTrustOasis2007.Instance;
                } 
                else
                {
                    m_protocolProfile.WSTrust = XmlNames.WSTrustXmlSoap2005.Instance;
                } 

                Binding stsBinding = m_endPoint.Binding; 
                EndpointAddress stsAddress = m_endPoint.Address; 

                if ( needUseKey ) 
                {
                    //
                    // We will be sending a UseKey element with the public part of a pair wise key pair to be used
                    // as a proof token.  We must prove posession of the private key as well.  To do that we add 
                    // an endorsing signature to the message.  The code below is how we inform the security stack
                    // that such a signature is necessary.  This will cause the security stack to ask our 
                    // private ClientCredentials for an RSASecurityToken later to be used to make the signature. 
                    //
 
                    SupportingTokenParameters requirements;
                    if( sbe.OptionalOperationSupportingTokenParameters.ContainsKey( m_protocolProfile.WSTrust.RequestSecurityTokenAction ) )
                    {
                        requirements = sbe.OptionalOperationSupportingTokenParameters[ m_protocolProfile.WSTrust.RequestSecurityTokenAction ]; 
                    }
                    else 
                    { 
                        requirements = new SupportingTokenParameters();
                        sbe.OptionalOperationSupportingTokenParameters[ m_protocolProfile.WSTrust.RequestSecurityTokenAction ] = requirements; 
                    }

                    bool addRsaRequirements = true;
                    foreach ( SecurityTokenParameters stp in requirements.Endorsing ) 
                    {
                        if ( stp is RsaSecurityTokenParameters ) 
                        { 
                            addRsaRequirements = false;
                            break; 
                        }
                    }

                    if ( addRsaRequirements ) 
                    {
                        RsaSecurityTokenParameters rsaParams = new RsaSecurityTokenParameters(); 
                        rsaParams.InclusionMode = SecurityTokenInclusionMode.Never; 
                        rsaParams.RequireDerivedKeys = false;
                        requirements.Endorsing.Add( rsaParams ); 
                    }
                    stsBinding = new CustomBinding( bindingElements );
                }
 
                stsBinding = new CustomBinding(
                                Utility.UpdateProxyForHttpAndRestrictTransportBinding( 
                                       stsBinding.CreateBindingElements(), 
                                       m_proxy,
                                       false ) ); // Client auth on transport is allowed for IP/STS leg 

                List disclosedClaimUris;

                InfoCardServiceClientCredentials creds = new InfoCardServiceClientCredentials( credential, m_protocolProfile ); 

                if ( needUseKey ) 
                { 
                    //
                    // The client credentials will need an rsa token in order to add the endorsing signature. 
                    // We need to keep a reference to this here so that we can make certain that it gets disposed.
                    //
                    endorsingSigTokenProvider = new RSATokenProvider( policy, card );
                    creds.EndorsingSignatureTokenProvider = endorsingSigTokenProvider; 
                }
 
                ChannelFactory channelFactory = null; 
                bool channelFactorySucceeded = false;
 
                //
                // Huge try catch around use of the channel factory
                //
                try 
                {
                    IDT.Assert( false == channelFactorySucceeded, "Will set to true upon sucess" ); 
 
                    //
                    // We must syncronize the creation and cleanup of the channel factory to prevent races 
                    //  on the cancel thread.
                    //

                    lock ( m_channelChangeSync ) 
                    {
                        if ( base.IsAborted ) 
                        { 
                            throw IDT.ThrowHelperError( new UserCancelledException() );
                        } 


                        channelFactory = new ChannelFactory( stsBinding, stsAddress );
 
                        //
                        // Disallow NTLM. This is necessary http with message security case. 
                        // 
                        // Waiting on CSDMain bug 28343 for transport level auth to not release NTLM creds
                        // 
                        // Specifically here in IP/STS scenario, setting AllowNtlm to false
                        // is useful mainly for managed card backed by Kerberos case.
                        // However there is no harm to set for ALL credential types
                        // 
                        creds.Windows.AllowNtlm = false;
 
 
                        ClientCredentials existingCreds = channelFactory.Endpoint.Behaviors.Find();
                        if ( null != existingCreds ) 
                        {
                            channelFactory.Endpoint.Behaviors.Remove( existingCreds );
                        }
                        channelFactory.Endpoint.Behaviors.Remove(); 
                        channelFactory.Endpoint.Behaviors.Add( creds );
 
                        X509Certificate2Collection certificateCollection = null; 
                        bool chainValidated = false;
 

                        //
                        // Set authorization credentials
                        // 
                        //
                        // We implement our own validation to implement some special behaviour: 
                        // e.g. {chaining up to LM or CU Trusted CA} OR {Peer Trust}, Offline validation, 
                        // IgnoreRevocationUnknown etc).
                        // 
                        //
                        // [In IssuedTokenForCertificate, MutualCertificate, UserNameForCertificate cases]:
                        // Note that since Indigo considers this identity to be retrieved out-of-band
                        // we cannot use their custom certificate validation extensibility points. 
                        //
                        switch ( parameter.CredentialType ) 
                        { 
                            case TokenFactoryCredentialType.UserNamePasswordCredential:
                                creds.UserName.UserName = ((UserNameTokenFactoryCredential)credential).UserName; 
                                creds.UserName.Password = ((UserNameTokenFactoryCredential)credential).Password;
                                certificateCollection = GetCertificateChainFromAddress( stsAddress );
                                InfoCardX509Validator.ValidateChainOrPeer( certificateCollection[ 0 ], certificateCollection, out chainValidated );
                                creds.ServiceCertificate.DefaultCertificate = certificateCollection[ 0 ]; 
                                break;
 
                            case TokenFactoryCredentialType.KerberosCredential: 

                               break; 

                            case TokenFactoryCredentialType.X509CertificateCredential:
                                creds.ClientCertificate.Certificate = ((X509CertificateTokenFactoryCredential)credential).Certificate;
                                certificateCollection = GetCertificateChainFromAddress( stsAddress ); 
                                InfoCardX509Validator.ValidateChainOrPeer( certificateCollection[ 0 ], certificateCollection, out chainValidated );
                                creds.ServiceCertificate.DefaultCertificate = certificateCollection[ 0 ]; 
                                break; 

                            case TokenFactoryCredentialType.SelfIssuedCredential: 
                                creds.IsSelfIssuedCred = true;
                                SelfIssuedTokenFactoryCredential sic = ((SelfIssuedTokenFactoryCredential)credential);
                                creds.SelectedCard = sic.LocalCard;
 
                                certificateCollection = GetCertificateChainFromAddress( stsAddress );
                                X509Certificate2 certificate = certificateCollection[ 0 ]; 
 
                                InfoCardX509Validator.ValidateChainOrPeer( certificate, certificateCollection, out chainValidated );
 
                                Recipient.RecipientCertParameters recipientParams;

                                string recipientId = Recipient.CertGetRecipientIdHash(
                                                                   certificate, 
                                                                   certificateCollection,
                                                                   chainValidated, 
                                                                   out recipientParams ); 
                                string recipientOrganizationId = Recipient.CertGetRecipientOrganizationIdHash(
                                                                   certificate, 
                                                                   certificateCollection,
                                                                   chainValidated );
                                //
                                // Pass the issuer cert and recipientId into this function. 
                                // (So do not use policy.RecipientIdentifier as that belongs to the recipient)
                                // In this case the immediate token recipient is same as the RP 
                                EnsureSelfIssuedCardHasLedgerEntryForIssuer( 
                                    sic.LocalCard,
                                    certificate, 
                                    recipientId,
                                    recipientOrganizationId,
                                    recipientParams,
                                    recipientOrganizationId ); 

                                creds.ServiceCertificate.DefaultCertificate = certificate; 
 
                                break;
                            default: 
                                IDT.ThrowInvalidArgumentConditional( true, "CredentialType" );
                                break;

                        } 

                        // 
                        // In IssuedTokenForSslNegotiated, UserNameForSslNegotiated, MutualSslNegotiated, 
                        // the client initiates a new SSL handshake to exchange certs. (This could be over http still).
                        // In these cases, the Indigo validator will get invoked. 
                        // So we are overriding the Indigo validator given that we have some
                        // special behavior, e.g. {chaining up to LM or CU Trusted CA} OR {Peer Trust}, Offline validation,
                        // IgnoreRevocationUnknown etc.
                        // 
                        creds.ServiceCertificate.Authentication.CertificateValidationMode =
                            X509CertificateValidationMode.Custom; 
                        creds.ServiceCertificate.Authentication.CustomCertificateValidator = 
                            InfoCardX509Validator.Create( certificateCollection );
 

                        //
                        // Now that the channelfactory is setup
                        //  we will capture the object value in a member before we, 
                        //  begin communicating on the channel.
                        // 
                        m_channelFactory = channelFactory; 
                    }//lock( m_channelChangeSync )
 


                    try
                    { 

                        sts = channelFactory.CreateChannel(); 
 

                        if ( null != identityKey ) 
                        {
                            rsaKeyValue = new RSAKeyValue( identityKey );
                        }
 

                        // 
                        // Disclosed claims is all required claims in the card/policy + 
                        // optional claims
                        // 
                        m_disclosedClaims = card.GetClaimsToBeDisclosed( policy, discloseOptional );

                        disclosedClaimUris = new List( m_disclosedClaims.Count );
                        disclosedClaimUris.AddRange( m_disclosedClaims.Keys ); 

 
                        rst = CreateRst( stsBinding.MessageVersion.Addressing, 
                                        policy,
                                        card, 
                                        discloseOptional,
                                        rsaKeyValue,
                                        clientEntropyForSymmetric,
                                        new CultureInfo( credential.LCID ) ); 

                        Message rstMessage = Message.CreateMessage( stsBinding.MessageVersion, 
                                               m_protocolProfile.WSTrust.RequestSecurityTokenAction, 
                                               rst );
 
                        //
                        // Process the Request for security token
                        //
 

                        Message rstrMessage = null; 
 
                        if( XmlNames.WSSpecificationVersion.WSTrustXmlSoap2005 == m_protocolProfile.WSTrust.Version )
                        { 
                            rstrMessage = sts.ProcessRequestSecurityTokenFeb2005( rstMessage );
                        }
                        else if( XmlNames.WSSpecificationVersion.WSTrustOasis2007 == m_protocolProfile.WSTrust.Version )
                        { 
                            rstrMessage = sts.ProcessRequestSecurityTokenWSTrust13( rstMessage );
                        } 
                        else 
                        {
                            IDT.Assert( false, "Unsupported version of WS-Trust detected" ); 
                        }

                        WSIdentityFaultException.ThrowIfFaultMessage( rstrMessage, CultureInfo.GetCultureInfo( credential.LCID ) );
 
                        //
                        // Retrive the keys from the proof token 
                        // 
                        if ( SecurityKeyTypeInternal.SymmetricKey == policy.KeyType )
                        { 
                            //
                            // Find the symmetric key in the proof key.
                            //
                            tok = RequestSecurityTokenResponseHelper.ProcessSymmetricTokenData( 
                                rstrMessage.GetReaderAtBodyContents(), m_protocolProfile.TokenSerializer,
                                null, clientEntropyForSymmetric, m_protocolProfile, out displayToken ); 
                            if ( tok.ProofToken.SecurityKeys.Count < 1 ) 
                            {
                                throw IDT.ThrowHelperError( new TrustExchangeException( SR.GetString( SR.NoSymmetricKeyFound ) ) ); 
                            }
                            foreach ( SecurityKey key in tok.ProofToken.SecurityKeys )
                            {
                                InMemorySymmetricSecurityKey symKey = key as InMemorySymmetricSecurityKey; 

                                if ( null != symKey ) 
                                { 
                                    IDT.TraceDebug( "IPSTSCLIENT: Found a symmetric key in the proof token" );
                                    sessionKey = new RijndaelManaged(); 
                                    sessionKey.Key = ((InMemorySymmetricSecurityKey)key).GetSymmetricKey();
                                    break;
                                }
                            } 
                            if ( null == sessionKey )
                            { 
 
                                throw IDT.ThrowHelperError( new TrustExchangeException( SR.GetString( SR.NoSymmetricKeyFound ) ) );
                            } 

                        }
                        else if ( SecurityKeyTypeInternal.AsymmetricKey == policy.KeyType )
                        { 
                            tok = RequestSecurityTokenResponseHelper.ProcessAsymmetricTokenData( rstrMessage.GetReaderAtBodyContents(), identityKey, m_protocolProfile.TokenSerializer, null, m_protocolProfile, out displayToken );
                        } 
                        else 
                        {
                            IDT.Assert( SecurityKeyTypeInternal.NoKey == policy.KeyType, "Bad enum member for SecurityKeyTypeInternal" ); 
                            tok = RequestSecurityTokenResponseHelper.ProcessBearerTokenData( rstrMessage.GetReaderAtBodyContents(), m_protocolProfile.TokenSerializer, null, m_protocolProfile, out displayToken );
                        }

                        // 
                        // Close can throw CommunicationException (or exceptions derived from that) and TimeoutException
                        // 
                        channelFactory.Close(); 
                        channelFactorySucceeded = true;
                    } 
                    finally
                    {
                        lock ( m_channelChangeSync )
                        { 
                            if ( !channelFactorySucceeded )
                            { 
                                // 
                                // Abort on failure
                                // 
                                channelFactory.Abort();
                            }

                            // 
                            // We have finished our communications, either via cancel, error, or success
                            //  we should unset the member var so cancels can not cancel the operation. 
                            // 
                            m_channelFactory = null;
                        } 
                    }

                }
                catch ( EndpointNotFoundException e ) 
                {
                    throw IDT.ThrowHelperError( new TrustExchangeException( 
                        SR.GetString( SR.EndpointNotFound ), e ) ); 
                }
                catch ( InfoCardBaseException ) 
                {
                    //
                    // Don't want to wrap it again in a TrustExchangeException!
                    // Could be for example if failed in selfIssued token factory 
                    // when doing self-issued for managed.
                    // 
                    throw; 
                }
                catch ( Exception e ) 
                {
                    if ( IDT.IsFatal( e ) )
                    {
                        throw; 
                    }
 
                    throw IDT.ThrowHelperError( new TrustExchangeException( 
                         SR.GetString( SR.ProblemRetrievingTokenFromIdentityProvider ), e ) );
                } 



                XmlElement protectedToken = tok.TokenXml; 

                // 
                // If the token is not encrypted, then we need to do it ourselves. 
                // If no certificate was specified for the immediate token recipient
                // then the token cannot be encrypted. 
                //

                X509RecipientIdentity x509Id = policy.ImmediateTokenRecipient as X509RecipientIdentity;
                if (  null != x509Id 
                    && !IsEncryptedXml( protectedToken )
                    && AppliesToBehaviorDecision.DoNotSend 
                       == AppliesToBehaviorDecisionTable.GetAppliesToBehaviorDecisionForRst( policy, card.RequireAppliesto ) ) 
                {
                    try 
                    {
                        string keyWrapAlgorithm;

                        // 
                        // Choosing the keyWrapAlgorithm is split into 3 cases for clarity.
                        // (I.e. the below code is not condensed further for clarity purposes.) 
                        // 

                        if ( SecurityKeyTypeInternal.SymmetricKey == policy.KeyType ) 
                        {
                            //
                            // Choose default for the key wrap algorithm
                            // 
                            keyWrapAlgorithm = SecurityAlgorithmSuite.Default.DefaultAsymmetricKeyWrapAlgorithm;
                        } 
                        else if ( SecurityKeyTypeInternal.AsymmetricKey == policy.KeyType ) 
                        {
                            keyWrapAlgorithm = 
                                !String.IsNullOrEmpty( policy.OptionalRstParams.EncryptWith ) ?
                                policy.OptionalRstParams.EncryptWith : SecurityAlgorithmSuite.Default.DefaultAsymmetricKeyWrapAlgorithm;
                        }
                        else 
                        {
                            // 
                            // Ignore encryptWith as there is no proof key! 
                            //
 
                            keyWrapAlgorithm = SecurityAlgorithmSuite.Default.DefaultAsymmetricKeyWrapAlgorithm;
                        }

                            protectedToken = EncryptionUtility.EncryptSecurityToken( 
                                protectedToken,
                                x509Id.LeafCertificate, 
                                !String.IsNullOrEmpty( policy.OptionalRstParams.EncryptionAlgorithm ) ? 
                                    policy.OptionalRstParams.EncryptionAlgorithm : SecurityAlgorithmSuite.Default.DefaultEncryptionAlgorithm,
                                keyWrapAlgorithm, 
                                policy.ProtocolVersionProfile );


                    } 
                    catch ( Exception e )
                    { 
                        if ( IDT.IsFatal( e ) ) 
                        {
                            throw; 
                        }
                        throw IDT.ThrowHelperError( new TrustExchangeException( SR.ServiceTokenEncryptionFailed, e ) );
                    }
                } 

 
 
                GetKeyIdentifierClauses( tok, policy.ProtocolVersionProfile, out internalTokenReference, out externalTokenReference );
 
                FillOutDisplayToken( card, displayToken );

                token = new TokenDescriptor(
                                tok.Id, 
                                tok.ValidFrom,
                                tok.ValidTo, 
                                protectedToken, 
                                displayToken,
                                sessionKey, 
                                internalTokenReference,
                                externalTokenReference,
                                disclosedClaimUris );
 
                //
                // Clear out references whose ownership has been transferred to the TokenDescriptor. 
                // 
                sessionKey = null;
                tok = null; 

            }
            finally
            { 
                //
                // Have to make certain that we dispose of the identity key. 
                // If we don't dispose of this then the finalizer will run and 
                // throw since it will attempt to dispose as the wrong identity.
                // 
                if ( null != identityKey )
                {
                    ((IDisposable)identityKey).Dispose();
                    identityKey = null; 
                }
                if ( null != rsaKeyValue ) 
                { 
                    ((IDisposable)(rsaKeyValue.Key)).Dispose();
                    rsaKeyValue.Key = null; 

                }
                if ( null != sessionKey )
                { 
                    ((IDisposable)sessionKey).Dispose();
                    sessionKey = null; 
                } 
                if ( null != endorsingSigTokenProvider )
                { 
                    ((IDisposable)endorsingSigTokenProvider).Dispose();
                    endorsingSigTokenProvider = null;
                }
            } 

            return token; 
        } 

 
        protected override void OnAbort()
        {
            lock ( m_channelChangeSync )
            { 
                if ( !base.IsAborted && null != m_channelFactory )
                { 
                    m_channelFactory.Abort(); 
                }
            } 
        }


        // 
        // Summary
        //   Retrieve certificate from the EndPointAddress of the service 
        // 
        // Parameters
        //   address - address from which to extract the certificate 
        //
        // Returns
        //  The selected certificate chain in a X509Certificate2Collection
        // 
        X509Certificate2Collection GetCertificateChainFromAddress( EndpointAddress address )
        { 
            if ( null == address || null == address.Identity ) 
            {
                throw IDT.ThrowHelperError( new TrustExchangeException( SR.GetString( SR.NoCertificateInEndPoint ) ) ); 
            }

            X509CertificateEndpointIdentity identity = address.Identity as X509CertificateEndpointIdentity;
            if ( null == identity || null == identity.Certificates || identity.Certificates.Count < 1 ) 
            {
                throw IDT.ThrowHelperError( new TrustExchangeException( SR.GetString( SR.NoCertificateInEndPoint ) ) ); 
            } 
            return identity.Certificates;
        } 

        //
        // Summary
        //    Do a mex exchange to retrieve the WSDL 
        //
        // Parameters 
        //   param - parameters from which to extract the mex uri 
        //   proxy - proxy value for the user
        // 
        // Returns
        //  The selected service end point
        //
        public static ServiceEndpoint DoMexExchange( TokenCreationParameter param, IWebProxy proxy ) 
        {
 
            ServiceEndpoint endPoint = null; 
            bool foundMexEndpoint = false;
 

            if ( null == param || null == param.Epr )
            {
                throw IDT.ThrowHelperError( new TrustExchangeException( SR.GetString( SR.InvalidServiceUri ) ) ); 
            }
 
            EndpointAddress address = Utility.DeriveMexAddress( param.Epr ); 
            if ( null == address )
            { 
                throw IDT.ThrowHelperError( new TrustExchangeException( SR.GetString( SR.InvalidServiceUri ) ) );
            }

            // 
            // Do a WS-MetaDataExchange over SOAP to retrieve the endpoint binding
            // 
            InfoCardMetadataExchangeClient mex = new InfoCardMetadataExchangeClient(); 
            mex.Proxy = proxy;
            MetadataSet metadataSet = null; 
            mex.ResolveMetadataReferences = true;
            mex.MaximumResolvedReferences = InfoCardConstants.MaximumMexChainLength;
            IDT.TraceDebug( "IPSTSCLIENT: Retrieving metadata over SOAP from {0}", address.Uri );
            Exception ex = null; 

            try 
            { 
                metadataSet = mex.GetMetadata( address );
                foundMexEndpoint = true; 
            }
            catch ( Exception e )
            {
                if ( IDT.IsFatal( e ) ) 
                {
                    throw; 
                } 
            }
 
            //
            // Do a WS-MetaDataExchange over HTTP to retrieve the endpoint binding
            //
            if ( !foundMexEndpoint ) 
            {
                IDT.TraceDebug( "IPSTSCLIENT: Retrieving metadata over HTTP from {0}", address.Uri ); 
                try 
                {
                    metadataSet = mex.GetMetadata( address.Uri, MetadataExchangeClientMode.HttpGet ); 
                    foundMexEndpoint = true;
                }
                catch ( Exception e )
                { 
                    if ( IDT.IsFatal( e ) )
                    { 
                        throw; 
                    }
                    ex = e; 
                }
            }

            // 
            // Throw an exception if none of the above methods succeeded.
            // The inner exception is the last exception thrown when trying to retrieve Mex 
            // 
            if ( !foundMexEndpoint )
            { 
                throw IDT.ThrowHelperError( new TrustExchangeException( SR.GetString( SR.EndpointNotFound ), ex ) );
            }

            WsdlImporter imp = new WsdlImporter( metadataSet ); 

            // 
            // Remember the original MEC so that later on the SecurityBindingElementConverter can use it 
            //
            imp.State.Add( MetadataExchangeClientKey, mex ); 

            ServiceEndpointCollection serviceEndpoints = imp.ImportAllEndpoints();

            // 
            // Find the correct endpoint from the collection
            // 
            if ( null != serviceEndpoints ) 
            {
                foreach ( ServiceEndpoint ep in serviceEndpoints ) 
                {

                    if ( Utility.CompareUri( ep.Address.Uri, param.Epr.Uri ) )
                    { 
                        ISecurityCapabilities capabilities = ep.Binding.GetProperty( new BindingParameterCollection() );
                        if ( null != capabilities ) 
                        { 
                            if ( capabilities.SupportedRequestProtectionLevel == System.Net.Security.ProtectionLevel.EncryptAndSign
                                && capabilities.SupportedResponseProtectionLevel == System.Net.Security.ProtectionLevel.EncryptAndSign 
                                && capabilities.SupportsServerAuthentication )
                            {
                                endPoint = ep;
                                break; 
                            }
                        } 
                    } 
                }
            } 
            else
            {
                throw IDT.ThrowHelperError( new TrustExchangeException(
                    SR.GetString( SR.IndigoNoSuitableEndpointsForAddress, param.Epr.Uri.AbsoluteUri ) ) ); 
            }
 
            if ( null == endPoint ) 
            {
                throw IDT.ThrowHelperError( new TrustExchangeException( 
                    SR.GetString( SR.IndigoNoSuitableEndpointsForAddress, param.Epr.Uri.AbsoluteUri ) ) );
            }

            ValidateEndpointAddressIdentityFromMex( endPoint ); 

            return endPoint; 
 
        }
 
        //
        // Summary:
        //  Validate the identity specified in the EndpointAddress after mex
        // 
        // Params:
        //  endPoint - the endPoint retrieved from Mex 
        // 
        static void ValidateEndpointAddressIdentityFromMex( ServiceEndpoint endPoint )
        { 

            EndpointIdentity ei = endPoint.Address.Identity;
            Uri stsAddress = endPoint.Address.Uri;
 
            //
            // Only null, Dns, X509, Spn identities are allowed 
            // 
            if( null != ei &&
                null != ei.IdentityClaim && 
                null != ei.IdentityClaim.ClaimType &&
                ClaimTypes.Dns != ei.IdentityClaim.ClaimType &&
                ClaimTypes.Spn != ei.IdentityClaim.ClaimType &&
                ClaimTypes.Thumbprint != ei.IdentityClaim.ClaimType ) 
            {
                throw IDT.ThrowHelperError( new TrustExchangeException( 
                        SR.GetString( SR.IndigoNoSuitableEndpointsForAddress, endPoint.Address.Uri ) ) ); 
            }
 
            if( null == ei ||
                null == ei.IdentityClaim ||
                null == ei.IdentityClaim.ClaimType )
            { 
                //
                // Default to WCF behavior 
                // 
            }
            else if( ClaimTypes.Dns == ei.IdentityClaim.ClaimType ) 
            {
                if( !NativeMcppMethods.DnsNameCompareWrapper(
                    ei.IdentityClaim.Resource.ToString(),
                    stsAddress.DnsSafeHost ) ) 
                {
                    throw IDT.ThrowHelperError( new TrustExchangeException( 
                        SR.GetString( SR.IndigoNoSuitableEndpointsForAddress, endPoint.Address.Uri ) ) ); 
                }
            } 
            else if( ClaimTypes.Spn == ei.IdentityClaim.ClaimType )
            {
                string spnFromMex = ei.IdentityClaim.Resource.ToString();
                string expectedSpn = String.Format( 
                    CultureInfo.InvariantCulture,
                    "host/{0}", 
                    stsAddress.DnsSafeHost ); 
                if( !expectedSpn.Equals( spnFromMex, StringComparison.OrdinalIgnoreCase ) )
                { 
                    throw IDT.ThrowHelperError( new TrustExchangeException(
                        SR.GetString( SR.IndigoNoSuitableEndpointsForAddress, endPoint.Address.Uri ) ) );
                }
            } 
            else
            { 
                IDT.Assert( ClaimTypes.Thumbprint == ei.IdentityClaim.ClaimType, "Should be Thumbprint" ); 
            }
        } 



        // 
        // Summary
        // Create the RST for the request 
        // 
        // Parameters
        //  policy - The policy of the RP. 
        //  card - The card to be used for creating the token.
        //  val - The public key to be used by the IP in case of asymmetric keys
        //  clientEntropyForSymmetric - entropy we pass to IP/STS in symmetric case
        // 
        RequestSecurityToken CreateRst( AddressingVersion version, InfoCardPolicy policy,
            InfoCard card, bool discloseOptional, RSAKeyValue val, byte[] clientEntropyForSymmetric, CultureInfo displayCulture ) 
        { 
            IDT.ThrowInvalidArgumentConditional( null == policy, "policy" );
            IDT.ThrowInvalidArgumentConditional( null == card, "card" ); 

            RequestSecurityTokenParameters rstParams = new RequestSecurityTokenParameters( version, card, policy, discloseOptional,
                val, m_disclosedClaims, "ProcessRequestSecurityToken", clientEntropyForSymmetric, displayCulture );
 
            return new RequestSecurityTokenForRemoteTokenFactory( rstParams );
        } 
 
        //
        // Summary 
        //   Retrive the KeyIdentifierClauses from the RSTR
        //
        // Parameters
        //   tok - The token returned by the IP 
        //   internalTokenReference - Return the xml for the InternalTokenReference
        //   externalTokenReference - Return the xml for the ExternalTokenReference 
        // 
        void GetKeyIdentifierClauses( GenericXmlSecurityToken tok, ProtocolProfile profile, out string internalTokenReference, out string externalTokenReference )
        { 

            if ( null == tok.InternalTokenReference || null == tok.ExternalTokenReference )
            {
                throw IDT.ThrowHelperError( new TrustExchangeException( SR.GetString( SR.IPSTSClientInvalidTokenReference ) ) ); 
            }
 
            try 
            {
                using ( StringWriter writer = new StringWriter( CultureInfo.InvariantCulture ) ) 
                {
                    profile.TokenSerializer.WriteKeyIdentifierClause( XmlDictionaryWriter.CreateDictionaryWriter( new XmlTextWriter( writer ) ), tok.InternalTokenReference );
                    writer.Flush();
                    internalTokenReference = writer.GetStringBuilder().ToString(); 
                }
 
                using ( StringWriter writer = new StringWriter( CultureInfo.InvariantCulture ) ) 
                {
                    profile.TokenSerializer.WriteKeyIdentifierClause( XmlDictionaryWriter.CreateDictionaryWriter( new XmlTextWriter( writer ) ), tok.ExternalTokenReference ); 
                    writer.Flush();
                    externalTokenReference = writer.GetStringBuilder().ToString();
                }
            } 
            catch ( XmlException e )
            { 
                throw IDT.ThrowHelperError( new TrustExchangeException( SR.GetString( SR.IPSTSClientInvalidTokenReference ), e ) ); 
            }
        } 

        void EnsureSelfIssuedCardHasLedgerEntryForIssuer(
                 InfoCard card,
                 X509Certificate2 issuerCert, 
                 string recipientId,
                 string recipientOrgId, 
                 Recipient.RecipientCertParameters recipientParams, 
                 string immediateTokenRecipientOrganizationIdentifier )
        { 
            IDT.DebugAssert( null != card, "null card" );
            IDT.DebugAssert( null != issuerCert, "null issuer cert" );
            LedgerEntryCollection ledger = card.GetLedger();
 
            StoreConnection connection = StoreConnection.GetConnection();
            try 
            { 
                ledger.Get( connection );
 

                if ( !ledger.ContainsKey( recipientId ) )
                {
                    connection.BeginTransaction(); 
                    try
                    { 
                        // 
                        // We are going to generate a token with this card
                        // so we will need to decrypt the master key (if it is decrypted) 
                        // The claims are already decrypted (since the card was received from the agent)
                        // so we can skip that step in this case.
                        //
                        InfoCardMasterKey masterKey = card.GetMasterKey( connection ); 

                        if ( card.IsPinProtected ) 
                        { 
                            //
                            // If card is pin protected, the Pin value must be populated. 
                            //
                            IDT.Assert( !String.IsNullOrEmpty( card.Pin ), "Should not be null here" );
                            masterKey.Decrypt( masterKey.GetPinHelper( card.Pin ) );
                        } 
                        else
                        { 
                            // 
                            // We have a self-issued card without a pin
                            // 
                            ;
                        }

                        // 
                        // Must save recipient before Ledger entry - see 40019 for details
                        // 
                        Recipient recipient = new Recipient( 
                                                      issuerCert,
                                                      recipientId, 
                                                      recipientOrgId,
                                                      false, // cert is not cached
                                                      0,
                                                      recipientParams ); 
                        recipient.Save( connection );
 
                        // 
                        // Now save the ledger entry
                        // 
                        LedgerEntry entry = LedgerEntry.NewLedgerEntry( card.Id, recipient, card.Key, immediateTokenRecipientOrganizationIdentifier );
                        ledger.Add( entry );
                        entry.Save( connection );
                        connection.CommitTransaction(); 
                    }
                    catch 
                    { 
                        connection.RollbackTransaction();
                        throw; 
                    }

                }
                else 
                {
                    IDT.Assert( immediateTokenRecipientOrganizationIdentifier == recipientOrgId, "For the self issued case the RP should be same as token recipient" ); 
                } 

            } 
            finally
            {
                connection.Close();
            } 
        }
 
        // 
        // Summary
        // STS's don't have to pass back claim names in the DisplayToken.  This method looks up the names of the 
        // claims in the managed card based on the claim id.
        //
        // Parameters
        // card          - The card in which to look up the claim names. 
        // displayToken  - The token for which claim names should be looked up.
        // 
        private void FillOutDisplayToken( InfoCard card, DisplayToken displayToken ) 
        {
            if ( null != displayToken.ClaimList ) 
            {
                InfoCardClaimCollection claims = card.GetClaims();

                foreach ( DisplayClaim claim in displayToken.ClaimList ) 
                {
                    // 
                    // If no claim name was given see if we can lookup one up in the original card 
                    // from which we obtained the token.
                    // 
                    if ( String.IsNullOrEmpty( claim.Name ) )
                    {
                        string name = null;
                        string id = claim.Id; 

                        if ( !String.IsNullOrEmpty( claim.Id ) ) 
                        { 
                            //
                            // Since there is an id, attempt to look up the name in the infocard. 
                            //
                            if ( claims.ContainsKey( id ) )
                            {
                                // 
                                // This may end up being null so there is a check below for that.
                                // 
                                name = claims[ id ].DisplayTag; 
                            }
 
                            if ( String.IsNullOrEmpty( name ) )
                            {
                                //
                                // There isn't a name so just use the id. 
                                //
                                name = id; 
                            } 
                        }
                        else 
                        {
                            //
                            // There wasn't an id so we can't look up a name at all.
                            // 
                            name = SR.GetString( SR.ServiceDisplayTokenNoClaimName );
                        } 
 
                        claim.Name = name;
                    } 
                }
            }
        }
 
        //
        // Summary 
        // Determines whether the given xml content is encrypted via XmlEnc or not. 
        //
        // Parameters 
        // content   - the content to check for encryption.
        //
        // Returns
        // true if the content is encrypted via XmlEnc otherwise false. 
        private bool IsEncryptedXml( XmlElement content )
        { 
            return (XmlNames.XmlEnc.EncryptedData == content.LocalName) 
                && (XmlNames.XmlEnc.Namespace == content.NamespaceURI);
        } 

        [ServiceContract(
            Namespace = XmlNames.WSIdentity.Namespace,
           Name = XmlNames.WSIdentity.RequestBrowserToken )] 
        internal interface ISts
        { 
            [OperationContract( Name = "ProcessRequestSecurityTokenFeb2005", 
                                    Action = XmlNames.WSTrustXmlSoap2005.c_RequestSecurityTokenAction,
                                    ReplyAction = XmlNames.WSTrustXmlSoap2005.c_RequestSecurityTokenResponseAction, 
                                    ProtectionLevel = ProtectionLevel.EncryptAndSign )]
            Message ProcessRequestSecurityTokenFeb2005( Message rstMessage );

            [OperationContract( Name = "ProcessRequestSecurityTokenWSTrust13", 
                                    Action = XmlNames.WSTrustOasis2007.c_RequestSecurityTokenAction,
                                    ReplyAction = XmlNames.WSTrustOasis2007.c_RequestSecurityTokenResponseAction, 
                                    ProtectionLevel = ProtectionLevel.EncryptAndSign )] 
            Message ProcessRequestSecurityTokenWSTrust13( Message rstMessage );
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK