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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- HtmlString.cs
- MailWebEventProvider.cs
- AutomationPatternInfo.cs
- InstanceLockedException.cs
- ComUdtElement.cs
- ConsumerConnectionPointCollection.cs
- ReliableDuplexSessionChannel.cs
- DragStartedEventArgs.cs
- XmlEncoding.cs
- SkewTransform.cs
- JoinGraph.cs
- SessionState.cs
- EpmSourceTree.cs
- Timer.cs
- Vector3DAnimationBase.cs
- ContainerCodeDomSerializer.cs
- ImportFileRequest.cs
- Parsers.cs
- CurrencyManager.cs
- RemoteTokenFactory.cs
- MediaEntryAttribute.cs
- TextFormattingConverter.cs
- SamlEvidence.cs
- StyleCollection.cs
- CodeSnippetStatement.cs
- BitmapScalingModeValidation.cs
- UnknownWrapper.cs
- ManagedWndProcTracker.cs
- HtmlForm.cs
- OleDbDataAdapter.cs
- SqlResolver.cs
- SourceFilter.cs
- Matrix3DStack.cs
- RowToParametersTransformer.cs
- SymmetricKeyWrap.cs
- UIAgentMonitorHandle.cs
- PointKeyFrameCollection.cs
- MatrixUtil.cs
- Span.cs
- FormViewRow.cs
- State.cs
- WindowsTokenRoleProvider.cs
- DecimalAnimationBase.cs
- SqlNodeAnnotations.cs
- MachineKeySection.cs
- XmlNodeList.cs
- VariantWrapper.cs
- DBConnectionString.cs
- TableDetailsCollection.cs
- TypeInitializationException.cs
- securitycriticaldataClass.cs
- WebPermission.cs
- GeneralTransform3D.cs
- DataBindingHandlerAttribute.cs
- StackBuilderSink.cs
- ValuePatternIdentifiers.cs
- AuthorizationSection.cs
- BulletedListEventArgs.cs
- Inflater.cs
- ChangesetResponse.cs
- SchemaType.cs
- AndCondition.cs
- PartialClassGenerationTask.cs
- WriteTimeStream.cs
- ZipFileInfo.cs
- Tuple.cs
- BuildProvidersCompiler.cs
- Attributes.cs
- HtmlValidationSummaryAdapter.cs
- ParserExtension.cs
- PrimitiveType.cs
- PersistChildrenAttribute.cs
- RenderData.cs
- FieldBuilder.cs
- BoolExpressionVisitors.cs
- DownloadProgressEventArgs.cs
- CreateUserWizard.cs
- AutomationProperties.cs
- QilInvokeLateBound.cs
- DeleteHelper.cs
- NamespaceQuery.cs
- XPathDocumentNavigator.cs
- PasswordTextNavigator.cs
- PointCollectionValueSerializer.cs
- XamlSerializerUtil.cs
- DynamicResourceExtension.cs
- FixUp.cs
- EditingContext.cs
- SerializerProvider.cs
- ColorTranslator.cs
- xmlsaver.cs
- SynchronousChannel.cs
- WebProxyScriptElement.cs
- StringOutput.cs
- AsyncCodeActivity.cs
- LogStore.cs
- ConfigurationValidatorAttribute.cs
- WebPartTracker.cs
- DurableInstanceProvider.cs
- BoolExpression.cs