|
//-----------------------------------------------------------------------------
// 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<IEndpointBehavior> IssuerChannelBehaviors
{
get
{
return this.federatedTokenProvider.IssuerChannelBehaviors;
}
}
public Collection<XmlElement> 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(new XmlTextReader(stream) { DtdProcessing = DtdProcessing.Prohibit });
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<FederatedTokenProviderState>
{
internal const SecurityKeyEntropyMode defaultKeyEntropyMode = SecurityKeyEntropyMode.CombinedEntropy;
static int MaxRsaSecurityTokenCacheSize = 1024;
IChannelFactory<IRequestChannel> channelFactory;
Binding issuerBinding;
KeyedByTypeCollection<IEndpointBehavior> channelBehaviors;
Collection<XmlElement> requestProperties = new Collection<XmlElement>();
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<RsaSecurityToken> rsaSecurityTokens = new List<RsaSecurityToken>();
SafeFreeCredentials credentialsHandle;
bool ownCredentialsHandle;
public CoreFederatedTokenProvider(SafeFreeCredentials credentialsHandle) : base()
{
this.credentialsHandle = credentialsHandle;
this.channelBehaviors = new KeyedByTypeCollection<IEndpointBehavior>();
this.addTargetServiceAppliesTo = true;
this.keyEntropyMode = defaultKeyEntropyMode;
}
public Binding IssuerBinding
{
get
{
return this.issuerBinding;
}
set
{
this.CommunicationObject.ThrowIfDisposedOrImmutable();
this.issuerBinding = value;
}
}
public Collection<XmlElement> 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<IEndpointBehavior> 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<ChannelParameterCollection>();
if (newParameters != null)
{
newParameters.Add(new SspiIssuanceChannelParameter(true, this.credentialsHandle));
}
}
ReplaceSspiIssuanceChannelParameter(result.GetProperty<ChannelParameterCollection>(), 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<FederatedTokenProviderState>(this.CreateNegotiationState(target, via, timeout), callback, state);
}
protected override FederatedTokenProviderState EndCreateNegotiationState(IAsyncResult result)
{
return CompletedAsyncResult<FederatedTokenProviderState>.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>(
EndpointAddress10.FromEndpointAddress(negotiationState.TargetAddress),
DataContractSerializerDefaults.CreateSerializer(typeof(EndpointAddress10), DataContractSerializerDefaults.MaxItemsInObjectGraph));
}
else if (this.MessageVersion.Addressing == AddressingVersion.WSAddressingAugust2004)
{
rst.SetAppliesTo<EndpointAddressAugust2004>(
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<XmlElement> newRequestProperties = new Collection<XmlElement>();
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<IAuthorizationPolicy>.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<IAuthorizationPolicy> GetServiceAuthorizationPolicies(AcceleratedTokenProviderState negotiationState)
{
EndpointIdentity identity;
if (this.identityVerifier.TryGetIdentity(negotiationState.TargetAddress, out identity))
{
List<Claim> claims = new List<Claim>(1);
claims.Add(identity.IdentityClaim);
List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>(1);
policies.Add(new UnconditionalPolicy(SecurityUtils.CreateIdentity(identity.IdentityClaim.Resource.ToString()),
new DefaultClaimSet(ClaimSet.System, claims)));
return policies.AsReadOnly();
}
else
{
return EmptyReadOnlyCollection<IAuthorizationPolicy>.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<IAuthorizationPolicy> 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<IAuthorizationPolicy>.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; }
}
}
}
}
|