//----------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- namespace System.ServiceModel.Security.Tokens { using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.IdentityModel.Claims; using System.IdentityModel.Policy; using System.IdentityModel.Selectors; using System.IdentityModel.Tokens; using System.Runtime; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Security.Principal; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Description; using System.ServiceModel.Diagnostics; using System.ServiceModel.Dispatcher; using System.ServiceModel.Security; using System.Xml; using SafeCloseHandle = System.IdentityModel.SafeCloseHandle; using SafeFreeCredentials = System.IdentityModel.SafeFreeCredentials; using SafeNativeMethods = System.ServiceModel.ComIntegration.SafeNativeMethods; using Win32Error = System.ServiceModel.ComIntegration.Win32Error; using WSTrustFeb2005Constants = System.IdentityModel.Protocols.WSTrust.WSTrustFeb2005Constants; using WSTrust13Constants = System.IdentityModel.Protocols.WSTrust.WSTrust13Constants; using WSTrust14Constants = System.IdentityModel.Protocols.WSTrust.WSTrust14Constants; using System.IO; using System.Text; public class IssuedSecurityTokenProvider : SecurityTokenProvider, ICommunicationObject { CoreFederatedTokenProvider federatedTokenProvider; MessageSecurityVersion messageSecurityVersion; SecurityTokenSerializer securityTokenSerializer; SecurityTokenHandlerCollectionManager tokenHandlerCollectionManager = null; public IssuedSecurityTokenProvider() : this(null) { } internal IssuedSecurityTokenProvider(SafeFreeCredentials credentialsHandle) { this.federatedTokenProvider = new CoreFederatedTokenProvider(credentialsHandle); this.messageSecurityVersion = MessageSecurityVersion.Default; } public event EventHandler Closed { add { this.federatedTokenProvider.Closed += value; } remove { this.federatedTokenProvider.Closed -= value; } } public event EventHandler Closing { add { this.federatedTokenProvider.Closing += value; } remove { this.federatedTokenProvider.Closing -= value; } } public event EventHandler Faulted { add { this.federatedTokenProvider.Faulted += value; } remove { this.federatedTokenProvider.Faulted -= value; } } public event EventHandler Opened { add { this.federatedTokenProvider.Opened += value; } remove { this.federatedTokenProvider.Opened -= value; } } public event EventHandler Opening { add { this.federatedTokenProvider.Opening += value; } remove { this.federatedTokenProvider.Opening -= value; } } public Binding IssuerBinding { get { return this.federatedTokenProvider.IssuerBinding; } set { this.federatedTokenProvider.IssuerBinding = value; } } public KeyedByTypeCollection IssuerChannelBehaviors { get { return this.federatedTokenProvider.IssuerChannelBehaviors; } } public Collection TokenRequestParameters { get { return this.federatedTokenProvider.RequestProperties; } } public EndpointAddress IssuerAddress { get { return this.federatedTokenProvider.IssuerAddress; } set { this.federatedTokenProvider.IssuerAddress = value; } } public EndpointAddress TargetAddress { get { return this.federatedTokenProvider.TargetAddress; } set { this.federatedTokenProvider.TargetAddress = value; } } public SecurityKeyEntropyMode KeyEntropyMode { get { return this.federatedTokenProvider.KeyEntropyMode; } set { this.federatedTokenProvider.KeyEntropyMode = value; } } public IdentityVerifier IdentityVerifier { get { return this.federatedTokenProvider.IdentityVerifier; } set { this.federatedTokenProvider.IdentityVerifier = value; } } public bool CacheIssuedTokens { get { return this.federatedTokenProvider.CacheServiceTokens; } set { this.federatedTokenProvider.CacheServiceTokens = value; } } public TimeSpan MaxIssuedTokenCachingTime { get { return this.federatedTokenProvider.MaxServiceTokenCachingTime; } set { this.federatedTokenProvider.MaxServiceTokenCachingTime = value; } } public MessageSecurityVersion MessageSecurityVersion { get { return this.messageSecurityVersion; } set { if (value == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("value")); } this.messageSecurityVersion = value; } } public SecurityTokenSerializer SecurityTokenSerializer { get { return this.securityTokenSerializer; } set { this.securityTokenSerializer = value; } } public SecurityAlgorithmSuite SecurityAlgorithmSuite { get { return this.federatedTokenProvider.SecurityAlgorithmSuite; } set { this.federatedTokenProvider.SecurityAlgorithmSuite = value; } } public int IssuedTokenRenewalThresholdPercentage { get { return this.federatedTokenProvider.ServiceTokenValidityThresholdPercentage; } set { this.federatedTokenProvider.ServiceTokenValidityThresholdPercentage = value; } } public CommunicationState State { get { return this.federatedTokenProvider.State; } } public virtual TimeSpan DefaultOpenTimeout { get { return ServiceDefaults.OpenTimeout; } } public virtual TimeSpan DefaultCloseTimeout { get { return ServiceDefaults.CloseTimeout; } } public override bool SupportsTokenCancellation { get { return this.federatedTokenProvider.SupportsTokenCancellation; } } internal ChannelParameterCollection ChannelParameters { get { return this.federatedTokenProvider.ChannelParameters; } set { this.federatedTokenProvider.ChannelParameters = value; } } internal SecurityTokenHandlerCollectionManager TokenHandlerCollectionManager { get { return this.tokenHandlerCollectionManager; } set { this.tokenHandlerCollectionManager = value; } } // communication object methods public void Abort() { this.federatedTokenProvider.Abort(); } public void Close() { this.federatedTokenProvider.Close(); } public void Close(TimeSpan timeout) { this.federatedTokenProvider.Close(timeout); } public IAsyncResult BeginClose(AsyncCallback callback, object state) { return this.federatedTokenProvider.BeginClose(callback, state); } public IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state) { return this.federatedTokenProvider.BeginClose(timeout, callback, state); } public void EndClose(IAsyncResult result) { this.federatedTokenProvider.EndClose(result); } void OnOpenCore() { if (this.securityTokenSerializer == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.TokenSerializerNotSetonFederationProvider))); } this.federatedTokenProvider.StandardsManager = new SecurityStandardsManager(this.messageSecurityVersion, this.securityTokenSerializer); } public void Open() { OnOpenCore(); this.federatedTokenProvider.Open(); } public void Open(TimeSpan timeout) { OnOpenCore(); this.federatedTokenProvider.Open(timeout); } public IAsyncResult BeginOpen(AsyncCallback callback, object state) { OnOpenCore(); return this.federatedTokenProvider.BeginOpen(callback, state); } public IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state) { OnOpenCore(); return this.federatedTokenProvider.BeginOpen(timeout, callback, state); } public void EndOpen(IAsyncResult result) { this.federatedTokenProvider.EndOpen(result); } public void Dispose() { this.Close(); } // token provider methods protected override IAsyncResult BeginGetTokenCore(TimeSpan timeout, AsyncCallback callback, object state) { return this.federatedTokenProvider.BeginGetToken(timeout, callback, state); } protected override SecurityToken GetTokenCore(TimeSpan timeout) { return this.federatedTokenProvider.GetToken(timeout); } protected override SecurityToken EndGetTokenCore(IAsyncResult result) { return this.federatedTokenProvider.EndGetToken(result); } internal void SetupActAsOnBehalfOfParameters(System.IdentityModel.Protocols.WSTrust.FederatedClientCredentialsParameters actAsOnBehalfOfParameters) { if (actAsOnBehalfOfParameters == null) return; if (actAsOnBehalfOfParameters.IssuedSecurityToken != null) { throw System.IdentityModel.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.AuthFailed)); } if (actAsOnBehalfOfParameters.OnBehalfOf != null) { if (MessageSecurityVersion.TrustVersion == TrustVersion.WSTrust13) { if (TokenRequestParameterExists(WSTrust13Constants.ElementNames.OnBehalfOf, WSTrust13Constants.NamespaceURI)) { throw System.IdentityModel.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.DuplicateFederatedClientCredentialsParameters, WSTrust13Constants.ElementNames.OnBehalfOf)); } TokenRequestParameters.Add(CreateXmlTokenElement(actAsOnBehalfOfParameters.OnBehalfOf, WSTrust13Constants.Prefix, WSTrust13Constants.ElementNames.OnBehalfOf, WSTrust13Constants.NamespaceURI, SecurityTokenHandlerCollectionManager.Usage.OnBehalfOf)); } else if (MessageSecurityVersion.TrustVersion == TrustVersion.WSTrustFeb2005) { if (TokenRequestParameterExists(WSTrustFeb2005Constants.ElementNames.OnBehalfOf, WSTrustFeb2005Constants.NamespaceURI)) { throw System.IdentityModel.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.DuplicateFederatedClientCredentialsParameters, WSTrustFeb2005Constants.ElementNames.OnBehalfOf)); } TokenRequestParameters.Add(CreateXmlTokenElement(actAsOnBehalfOfParameters.OnBehalfOf, WSTrustFeb2005Constants.Prefix, WSTrustFeb2005Constants.ElementNames.OnBehalfOf, WSTrustFeb2005Constants.NamespaceURI, SecurityTokenHandlerCollectionManager.Usage.OnBehalfOf)); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.UnsupportedTrustVersion, MessageSecurityVersion.TrustVersion.Namespace))); } } if (actAsOnBehalfOfParameters.ActAs != null) { if (TokenRequestParameterExists(WSTrust14Constants.ElementNames.ActAs, WSTrust14Constants.NamespaceURI)) { throw System.IdentityModel.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.DuplicateFederatedClientCredentialsParameters, WSTrust14Constants.ElementNames.ActAs)); } TokenRequestParameters.Add(CreateXmlTokenElement(actAsOnBehalfOfParameters.ActAs, WSTrust14Constants.Prefix, WSTrust14Constants.ElementNames.ActAs, WSTrust14Constants.NamespaceURI, SecurityTokenHandlerCollectionManager.Usage.ActAs)); } } bool TokenRequestParameterExists(string localName, string xmlNamespace) { foreach (XmlElement element in TokenRequestParameters) { if (element.LocalName == localName && element.NamespaceURI == xmlNamespace) { return true; } } return false; } XmlElement CreateXmlTokenElement(SecurityToken token, string prefix, string name, string ns, string usage) { Stream stream = new MemoryStream(); using (XmlDictionaryWriter xmlWriter = XmlDictionaryWriter.CreateTextWriter(stream, Encoding.UTF8, false)) { xmlWriter.WriteStartElement(prefix, name, ns); WriteToken(xmlWriter, token, usage); xmlWriter.WriteEndElement(); xmlWriter.Flush(); } stream.Seek(0, SeekOrigin.Begin); XmlDocument dom = new XmlDocument(); dom.PreserveWhitespace = true; dom.Load(stream); stream.Close(); return dom.DocumentElement; } void WriteToken(XmlWriter xmlWriter, SecurityToken token, string usage) { SecurityTokenHandlerCollection tokenHandlerCollection = null; if (this.tokenHandlerCollectionManager.ContainsKey(usage)) { tokenHandlerCollection = this.tokenHandlerCollectionManager[usage]; } else { tokenHandlerCollection = this.tokenHandlerCollectionManager[SecurityTokenHandlerCollectionManager.Usage.Default]; } if (tokenHandlerCollection != null && tokenHandlerCollection.CanWriteToken(token)) { tokenHandlerCollection.WriteToken(xmlWriter, token); } else { SecurityTokenSerializer.WriteToken(xmlWriter, token); } } private class CoreFederatedTokenProvider : IssuanceTokenProviderBase { internal const SecurityKeyEntropyMode defaultKeyEntropyMode = SecurityKeyEntropyMode.CombinedEntropy; static int MaxRsaSecurityTokenCacheSize = 1024; IChannelFactory channelFactory; Binding issuerBinding; KeyedByTypeCollection channelBehaviors; Collection requestProperties = new Collection(); IdentityVerifier identityVerifier = IdentityVerifier.CreateDefault(); bool addTargetServiceAppliesTo; SecurityKeyEntropyMode keyEntropyMode; SecurityKeyType keyType; bool isKeyTypePresentInRstProperties; int keySize; bool isKeySizePresentInRstProperties; int defaultPublicKeySize = 1024; MessageVersion messageVersion; ChannelParameterCollection channelParameters; readonly List rsaSecurityTokens = new List(); SafeFreeCredentials credentialsHandle; bool ownCredentialsHandle; public CoreFederatedTokenProvider(SafeFreeCredentials credentialsHandle) : base() { this.credentialsHandle = credentialsHandle; this.channelBehaviors = new KeyedByTypeCollection(); this.addTargetServiceAppliesTo = true; this.keyEntropyMode = defaultKeyEntropyMode; } public Binding IssuerBinding { get { return this.issuerBinding; } set { this.CommunicationObject.ThrowIfDisposedOrImmutable(); this.issuerBinding = value; } } public Collection RequestProperties { get { return this.requestProperties; } } public SecurityKeyEntropyMode KeyEntropyMode { get { return this.keyEntropyMode; } set { this.CommunicationObject.ThrowIfDisposedOrImmutable(); SecurityKeyEntropyModeHelper.Validate(value); this.keyEntropyMode = value; } } public IdentityVerifier IdentityVerifier { get { return this.identityVerifier; } set { this.CommunicationObject.ThrowIfDisposedOrImmutable(); this.identityVerifier = value; } } public ChannelParameterCollection ChannelParameters { get { return this.channelParameters; } set { this.CommunicationObject.ThrowIfDisposedOrImmutable(); this.channelParameters = value; } } public KeyedByTypeCollection IssuerChannelBehaviors { get { return this.channelBehaviors; } } public override XmlDictionaryString RequestSecurityTokenAction { get { return this.StandardsManager.TrustDriver.RequestSecurityTokenAction; } } public override XmlDictionaryString RequestSecurityTokenResponseAction { get { return this.StandardsManager.TrustDriver.RequestSecurityTokenResponseAction; } } protected override MessageVersion MessageVersion { get { return this.messageVersion; } } protected override bool RequiresManualReplyAddressing { get { // the proxy adds reply headers automatically return false; } } bool TryGetKeyType(out SecurityKeyType keyType) { if (this.requestProperties != null) { for (int i = 0; i < this.requestProperties.Count; ++i) { if (this.StandardsManager.TrustDriver.TryParseKeyTypeElement(this.requestProperties[i], out keyType)) { return true; } } } keyType = SecurityKeyType.SymmetricKey; return false; } bool TryGetKeySize(out int keySize) { if (this.requestProperties != null) { for (int i = 0; i < this.requestProperties.Count; ++i) { if (this.StandardsManager.TrustDriver.TryParseKeySizeElement(this.requestProperties[i], out keySize)) { return true; } } } keySize = 0; return false; } public override void OnOpen(TimeSpan timeout) { if (this.IssuerAddress == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.StsAddressNotSet, this.TargetAddress))); } if (this.IssuerBinding == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.StsBindingNotSet, this.IssuerAddress))); } if (this.SecurityAlgorithmSuite == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecurityAlgorithmSuiteNotSet, typeof(IssuedSecurityTokenProvider)))); } this.channelFactory = this.StandardsManager.TrustDriver.CreateFederationProxy(this.IssuerAddress, this.IssuerBinding, this.IssuerChannelBehaviors); this.messageVersion = this.IssuerBinding.MessageVersion; // if an appliesTo is specified in the request properties, then do not add the target service EPR as // appliesTo for (int i = 0; i < this.requestProperties.Count; ++i) { if (this.StandardsManager.TrustDriver.IsAppliesTo(this.requestProperties[i].LocalName, this.requestProperties[i].NamespaceURI)) { this.addTargetServiceAppliesTo = false; break; } } this.isKeyTypePresentInRstProperties = TryGetKeyType(out this.keyType); if (!this.isKeyTypePresentInRstProperties) { this.keyType = SecurityKeyType.SymmetricKey; } this.isKeySizePresentInRstProperties = TryGetKeySize(out this.keySize); if (!this.isKeySizePresentInRstProperties && this.keyType != SecurityKeyType.BearerKey) { this.keySize = (this.keyType == SecurityKeyType.SymmetricKey) ? this.SecurityAlgorithmSuite.DefaultSymmetricKeyLength : this.defaultPublicKeySize; } base.OnOpen(timeout); } public override void OnOpening() { base.OnOpening(); if (this.credentialsHandle == null) { if (this.IssuerBinding == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.StsBindingNotSet, this.IssuerAddress))); } this.credentialsHandle = SecurityUtils.GetCredentialsHandle(this.IssuerBinding, this.IssuerChannelBehaviors); this.ownCredentialsHandle = true; } } public override void OnAbort() { if (this.channelFactory != null && this.channelFactory.State == CommunicationState.Opened) { this.channelFactory.Abort(); this.channelFactory = null; } CleanUpRsaSecurityTokenCache(); FreeCredentialsHandle(); base.OnAbort(); } public override void OnClose(TimeSpan timeout) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); if (this.channelFactory != null && this.channelFactory.State == CommunicationState.Opened) { this.channelFactory.Close(timeoutHelper.RemainingTime()); this.channelFactory = null; CleanUpRsaSecurityTokenCache(); FreeCredentialsHandle(); base.OnClose(timeoutHelper.RemainingTime()); } } void FreeCredentialsHandle() { if (this.credentialsHandle != null) { if (this.ownCredentialsHandle) { this.credentialsHandle.Close(); } this.credentialsHandle = null; } } protected override bool WillInitializeChannelFactoriesCompleteSynchronously(EndpointAddress target) { return (this.channelFactory.State != CommunicationState.Opened); } protected override void InitializeChannelFactories(EndpointAddress target, TimeSpan timeout) { if (this.channelFactory.State == CommunicationState.Created) { this.channelFactory.Open(timeout); } } protected override IAsyncResult BeginInitializeChannelFactories(EndpointAddress target, TimeSpan timeout, AsyncCallback callback, object state) { if (this.channelFactory.State == CommunicationState.Created) { return this.channelFactory.BeginOpen(timeout, callback, state); } else { return new CompletedAsyncResult(callback, state); } } protected override void EndInitializeChannelFactories(IAsyncResult result) { if (result is CompletedAsyncResult) { CompletedAsyncResult.End(result); } else { this.channelFactory.EndOpen(result); } } protected override IRequestChannel CreateClientChannel(EndpointAddress target, Uri via) { IRequestChannel result = this.channelFactory.CreateChannel(this.IssuerAddress); if (this.channelParameters != null) { this.channelParameters.PropagateChannelParameters(result); } if (this.ownCredentialsHandle) { ChannelParameterCollection newParameters = result.GetProperty(); if (newParameters != null) { newParameters.Add(new SspiIssuanceChannelParameter(true, this.credentialsHandle)); } } ReplaceSspiIssuanceChannelParameter(result.GetProperty(), new SspiIssuanceChannelParameter(true, this.credentialsHandle)); return result; } void ReplaceSspiIssuanceChannelParameter( ChannelParameterCollection channelParameters, SspiIssuanceChannelParameter sicp ) { if (channelParameters != null) { for (int i = 0; i < channelParameters.Count; ++i) { if (channelParameters[i] is SspiIssuanceChannelParameter) { channelParameters.RemoveAt(i); } } channelParameters.Add(sicp); } } protected override bool CreateNegotiationStateCompletesSynchronously(EndpointAddress target, Uri via) { return true; } protected override IAsyncResult BeginCreateNegotiationState(EndpointAddress target, Uri via, TimeSpan timeout, AsyncCallback callback, object state) { return new CompletedAsyncResult(this.CreateNegotiationState(target, via, timeout), callback, state); } protected override FederatedTokenProviderState EndCreateNegotiationState(IAsyncResult result) { return CompletedAsyncResult.End(result); } protected override FederatedTokenProviderState CreateNegotiationState(EndpointAddress target, Uri via, TimeSpan timeout) { if ((this.keyType == SecurityKeyType.SymmetricKey) || (this.keyType == SecurityKeyType.BearerKey)) { byte[] keyEntropy; if (this.KeyEntropyMode == SecurityKeyEntropyMode.CombinedEntropy || this.KeyEntropyMode == SecurityKeyEntropyMode.ClientEntropy) { keyEntropy = new byte[this.keySize / 8]; CryptoHelper.FillRandomBytes(keyEntropy); } else { keyEntropy = null; } return new FederatedTokenProviderState(keyEntropy); } else if (this.keyType == SecurityKeyType.AsymmetricKey) { return new FederatedTokenProviderState(CreateAndCacheRsaSecurityToken()); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); } } protected override BodyWriter GetFirstOutgoingMessageBody(FederatedTokenProviderState negotiationState, out MessageProperties messageProperties) { messageProperties = null; RequestSecurityToken rst = new RequestSecurityToken(this.StandardsManager); if (this.addTargetServiceAppliesTo) { if (this.MessageVersion.Addressing == AddressingVersion.WSAddressing10) { rst.SetAppliesTo( EndpointAddress10.FromEndpointAddress(negotiationState.TargetAddress), DataContractSerializerDefaults.CreateSerializer(typeof(EndpointAddress10), DataContractSerializerDefaults.MaxItemsInObjectGraph)); } else if (this.MessageVersion.Addressing == AddressingVersion.WSAddressingAugust2004) { rst.SetAppliesTo( EndpointAddressAugust2004.FromEndpointAddress(negotiationState.TargetAddress), DataContractSerializerDefaults.CreateSerializer(typeof(EndpointAddressAugust2004), DataContractSerializerDefaults.MaxItemsInObjectGraph)); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ProtocolException(SR.GetString(SR.AddressingVersionNotSupported, this.MessageVersion.Addressing))); } } rst.Context = negotiationState.Context; if (!this.isKeySizePresentInRstProperties) { rst.KeySize = this.keySize; } Collection newRequestProperties = new Collection(); if (this.requestProperties != null) { for (int i = 0; i < this.requestProperties.Count; ++i) { newRequestProperties.Add(this.requestProperties[i]); } } if (!isKeyTypePresentInRstProperties) { XmlElement keyTypeElement = this.StandardsManager.TrustDriver.CreateKeyTypeElement(this.keyType); newRequestProperties.Insert(0, keyTypeElement); } if (this.keyType == SecurityKeyType.SymmetricKey) { byte[] requestorEntropy = negotiationState.GetRequestorEntropy(); rst.SetRequestorEntropy(requestorEntropy); } else if (this.keyType == SecurityKeyType.AsymmetricKey) { RsaKeyIdentifierClause rsaClause = new RsaKeyIdentifierClause(negotiationState.Rsa); SecurityKeyIdentifier keyIdentifier = new SecurityKeyIdentifier(rsaClause); newRequestProperties.Add(this.StandardsManager.TrustDriver.CreateUseKeyElement(keyIdentifier, this.StandardsManager)); RsaSecurityTokenParameters rsaParameters = new RsaSecurityTokenParameters(); rsaParameters.InclusionMode = SecurityTokenInclusionMode.Never; rsaParameters.RequireDerivedKeys = false; SupportingTokenSpecification rsaSpec = new SupportingTokenSpecification(negotiationState.RsaSecurityToken, EmptyReadOnlyCollection.Instance, SecurityTokenAttachmentMode.Endorsing, rsaParameters); messageProperties = new MessageProperties(); SecurityMessageProperty security = new SecurityMessageProperty(); security.OutgoingSupportingTokens.Add(rsaSpec); messageProperties.Security = security; } if (this.keyType == SecurityKeyType.SymmetricKey && this.KeyEntropyMode == SecurityKeyEntropyMode.CombinedEntropy) { newRequestProperties.Add(this.StandardsManager.TrustDriver.CreateComputedKeyAlgorithmElement(this.StandardsManager.TrustDriver.ComputedKeyAlgorithm)); } rst.RequestProperties = newRequestProperties; rst.MakeReadOnly(); return rst; } protected ReadOnlyCollection GetServiceAuthorizationPolicies(AcceleratedTokenProviderState negotiationState) { EndpointIdentity identity; if (this.identityVerifier.TryGetIdentity(negotiationState.TargetAddress, out identity)) { List claims = new List(1); claims.Add(identity.IdentityClaim); List policies = new List(1); policies.Add(new UnconditionalPolicy(SecurityUtils.CreateIdentity(identity.IdentityClaim.Resource.ToString()), new DefaultClaimSet(ClaimSet.System, claims))); return policies.AsReadOnly(); } else { return EmptyReadOnlyCollection.Instance; } } protected override BodyWriter GetNextOutgoingMessageBody(Message incomingMessage, FederatedTokenProviderState negotiationState) { ThrowIfFault(incomingMessage, this.IssuerAddress); if ((this.StandardsManager.MessageSecurityVersion.TrustVersion == TrustVersion.WSTrustFeb2005 && incomingMessage.Headers.Action != this.StandardsManager.TrustDriver.RequestSecurityTokenResponseAction.Value) || (this.StandardsManager.MessageSecurityVersion.TrustVersion == TrustVersion.WSTrust13 && incomingMessage.Headers.Action != this.StandardsManager.TrustDriver.RequestSecurityTokenResponseFinalAction.Value) || incomingMessage.Headers.Action == null) { throw TraceUtility.ThrowHelperError(new SecurityNegotiationException(SR.GetString(SR.InvalidActionForNegotiationMessage, incomingMessage.Headers.Action)), incomingMessage); } RequestSecurityTokenResponse rstr = null; XmlDictionaryReader bodyReader = incomingMessage.GetReaderAtBodyContents(); using (bodyReader) { if (this.StandardsManager.MessageSecurityVersion.TrustVersion == TrustVersion.WSTrustFeb2005) rstr = this.StandardsManager.TrustDriver.CreateRequestSecurityTokenResponse(bodyReader); else if (this.StandardsManager.MessageSecurityVersion.TrustVersion == TrustVersion.WSTrust13) { RequestSecurityTokenResponseCollection rstrc = this.StandardsManager.TrustDriver.CreateRequestSecurityTokenResponseCollection(bodyReader); foreach (RequestSecurityTokenResponse rstrItem in rstrc.RstrCollection) { if (rstr != null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.MoreThanOneRSTRInRSTRC))); rstr = rstrItem; } } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); } incomingMessage.ReadFromBodyContentsToEnd(bodyReader); } if (rstr.Context != negotiationState.Context) { throw TraceUtility.ThrowHelperError(new SecurityNegotiationException(SR.GetString(SR.BadSecurityNegotiationContext)), incomingMessage); } GenericXmlSecurityToken serviceToken; if ((this.keyType == SecurityKeyType.SymmetricKey) || (this.keyType == SecurityKeyType.BearerKey)) { ReadOnlyCollection authorizationPolicies = GetServiceAuthorizationPolicies(negotiationState); byte[] keyEntropy = negotiationState.GetRequestorEntropy(); serviceToken = rstr.GetIssuedToken(null, null, this.KeyEntropyMode, keyEntropy, null, authorizationPolicies, this.keySize, this.keyType == SecurityKeyType.BearerKey); } else if (this.keyType == SecurityKeyType.AsymmetricKey) { serviceToken = rstr.GetIssuedToken(null, EmptyReadOnlyCollection.Instance, negotiationState.Rsa); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); } negotiationState.SetServiceToken(serviceToken); return null; } // SC/Trust workshop change to turn off context protected override bool IsMultiLegNegotiation { get { return false; } } // This is to address RSACryptoServiceProvider finalizer exception issue // Step 1. Create Rsa and force deterministic keypair gen in this calling context. // Step 2. Cache if the calling thread is under impersonation context. The cache will // be disposed on Close/Abort assuming same calling context thread as the one calling open. RsaSecurityToken CreateAndCacheRsaSecurityToken() { RsaSecurityToken token; // Cache only under impersonation context. // 1) set cacheSize less than 0, to ignore this new behavior at all. // 2) set cacheSize to 0, if token provider should not dispose issued tokens on close/abort. // 3) other than that, the token provider will track and dispose issued tokens as much. if (MaxRsaSecurityTokenCacheSize >= 0 && IsImpersonatedContext()) { // This will force deterministic keypair gen in this context. token = RsaSecurityToken.CreateSafeRsaSecurityToken(this.keySize); if (MaxRsaSecurityTokenCacheSize > 0) { lock (this.rsaSecurityTokens) { // Remove/Dispose the first token if cache is full. // The first token (if not disposed) will rely on GC for finalization. if (this.rsaSecurityTokens.Count >= MaxRsaSecurityTokenCacheSize) { this.rsaSecurityTokens.RemoveAt(0); } this.rsaSecurityTokens.Add(token); } } } else { token = new RsaSecurityToken(new RSACryptoServiceProvider(this.keySize)); } return token; } void CleanUpRsaSecurityTokenCache() { lock (this.rsaSecurityTokens) { for (int i = 0; i < this.rsaSecurityTokens.Count; ++i) { this.rsaSecurityTokens[i].Dispose(); } this.rsaSecurityTokens.Clear(); } } // This api simply check if the calling thread is process primary thread. // We are not trying to be smart if the impersonation to the same user as // process token since privileges could be different. bool IsImpersonatedContext() { SafeCloseHandle tokenHandle = null; if (!SafeNativeMethods.OpenCurrentThreadToken( SafeNativeMethods.GetCurrentThread(), TokenAccessLevels.Query, true, out tokenHandle)) { int error = Marshal.GetLastWin32Error(); Utility.CloseInvalidOutSafeHandle(tokenHandle); if (error == (int)Win32Error.ERROR_NO_TOKEN) { return false; } System.ServiceModel.Dispatcher.ErrorBehavior.ThrowAndCatch(new Win32Exception(error)); return true; } tokenHandle.Close(); return true; } protected override void ValidateKeySize(GenericXmlSecurityToken issuedToken) { if (this.keyType == SecurityKeyType.BearerKey) { // We do not have a proof key associated with bearer // key type. So skip key size validation. return; } base.ValidateKeySize(issuedToken); } } class FederatedTokenProviderState : AcceleratedTokenProviderState { RsaSecurityToken rsaToken; public FederatedTokenProviderState(byte[] entropy) : base(entropy) { } public FederatedTokenProviderState(RsaSecurityToken rsaToken) : base(null) { this.rsaToken = rsaToken; } public RSA Rsa { get { return this.rsaToken.Rsa; } } public RsaSecurityToken RsaSecurityToken { get { return this.rsaToken; } } } } }