e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
323 lines
14 KiB
C#
323 lines
14 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
namespace System.ServiceModel.Security
|
|
{
|
|
using System.Collections.ObjectModel;
|
|
using System.IdentityModel.Policy;
|
|
using System.IdentityModel.Tokens;
|
|
using System.Runtime;
|
|
using System.ServiceModel;
|
|
using System.ServiceModel.Channels;
|
|
using System.ServiceModel.Description;
|
|
using System.ServiceModel.Diagnostics;
|
|
using System.Xml;
|
|
using SafeFreeCredentials = System.IdentityModel.SafeFreeCredentials;
|
|
|
|
class AcceleratedTokenProvider :
|
|
NegotiationTokenProvider<AcceleratedTokenProviderState>
|
|
{
|
|
internal const SecurityKeyEntropyMode defaultKeyEntropyMode = SecurityKeyEntropyMode.CombinedEntropy;
|
|
SecurityKeyEntropyMode keyEntropyMode = defaultKeyEntropyMode;
|
|
SecurityBindingElement bootstrapSecurityBindingElement;
|
|
Uri privacyNoticeUri;
|
|
int privacyNoticeVersion;
|
|
ChannelParameterCollection channelParameters;
|
|
SafeFreeCredentials credentialsHandle;
|
|
bool ownCredentialsHandle;
|
|
|
|
public AcceleratedTokenProvider(SafeFreeCredentials credentialsHandle)
|
|
: base()
|
|
{
|
|
this.credentialsHandle = credentialsHandle;
|
|
}
|
|
|
|
public SecurityKeyEntropyMode KeyEntropyMode
|
|
{
|
|
get
|
|
{
|
|
return this.keyEntropyMode;
|
|
}
|
|
set
|
|
{
|
|
this.CommunicationObject.ThrowIfDisposedOrImmutable();
|
|
SecurityKeyEntropyModeHelper.Validate(value);
|
|
this.keyEntropyMode = value;
|
|
}
|
|
}
|
|
|
|
public SecurityBindingElement BootstrapSecurityBindingElement
|
|
{
|
|
get { return this.bootstrapSecurityBindingElement; }
|
|
set
|
|
{
|
|
this.CommunicationObject.ThrowIfDisposedOrImmutable();
|
|
if (value == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
|
|
}
|
|
this.bootstrapSecurityBindingElement = (SecurityBindingElement) value.Clone();
|
|
}
|
|
}
|
|
|
|
public Uri PrivacyNoticeUri
|
|
{
|
|
get { return this.privacyNoticeUri; }
|
|
set
|
|
{
|
|
this.CommunicationObject.ThrowIfDisposedOrImmutable();
|
|
this.privacyNoticeUri = value;
|
|
}
|
|
}
|
|
|
|
public int PrivacyNoticeVersion
|
|
{
|
|
get { return this.privacyNoticeVersion; }
|
|
set
|
|
{
|
|
this.CommunicationObject.ThrowIfDisposedOrImmutable();
|
|
this.privacyNoticeVersion = value;
|
|
}
|
|
}
|
|
|
|
public ChannelParameterCollection ChannelParameters
|
|
{
|
|
get { return this.channelParameters; }
|
|
set
|
|
{
|
|
this.CommunicationObject.ThrowIfDisposedOrImmutable();
|
|
this.channelParameters = value;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// SC/Trust workshop change to turn off context
|
|
protected override bool IsMultiLegNegotiation
|
|
{
|
|
get { return false; }
|
|
}
|
|
|
|
public override XmlDictionaryString RequestSecurityTokenAction
|
|
{
|
|
get
|
|
{
|
|
return this.StandardsManager.SecureConversationDriver.IssueAction;
|
|
}
|
|
}
|
|
|
|
public override XmlDictionaryString RequestSecurityTokenResponseAction
|
|
{
|
|
get
|
|
{
|
|
return this.StandardsManager.SecureConversationDriver.IssueResponseAction;
|
|
}
|
|
}
|
|
|
|
public override void OnOpen(TimeSpan timeout)
|
|
{
|
|
if (this.BootstrapSecurityBindingElement == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.BootstrapSecurityBindingElementNotSet, this.GetType())));
|
|
}
|
|
base.OnOpen(timeout);
|
|
}
|
|
|
|
public override void OnOpening()
|
|
{
|
|
base.OnOpening();
|
|
if (this.credentialsHandle == null)
|
|
{
|
|
if (this.BootstrapSecurityBindingElement == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.BootstrapSecurityBindingElementNotSet, this.GetType())));
|
|
}
|
|
this.credentialsHandle = SecurityUtils.GetCredentialsHandle(this.BootstrapSecurityBindingElement, this.IssuerBindingContext);
|
|
this.ownCredentialsHandle = true;
|
|
}
|
|
}
|
|
|
|
public override void OnClose(TimeSpan timeout)
|
|
{
|
|
base.OnClose(timeout);
|
|
FreeCredentialsHandle();
|
|
}
|
|
|
|
public override void OnAbort()
|
|
{
|
|
base.OnAbort();
|
|
FreeCredentialsHandle();
|
|
}
|
|
|
|
void FreeCredentialsHandle()
|
|
{
|
|
if (this.credentialsHandle != null)
|
|
{
|
|
if (this.ownCredentialsHandle)
|
|
{
|
|
this.credentialsHandle.Close();
|
|
}
|
|
this.credentialsHandle = null;
|
|
}
|
|
}
|
|
|
|
protected override IChannelFactory<IRequestChannel> GetNegotiationChannelFactory(IChannelFactory<IRequestChannel> transportChannelFactory, ChannelBuilder channelBuilder)
|
|
{
|
|
ISecurityCapabilities securityCapabilities = this.bootstrapSecurityBindingElement.GetProperty<ISecurityCapabilities>(this.IssuerBindingContext);
|
|
SecurityCredentialsManager securityCredentials = this.IssuerBindingContext.BindingParameters.Find<SecurityCredentialsManager>();
|
|
if (securityCredentials == null)
|
|
{
|
|
securityCredentials = ClientCredentials.CreateDefaultCredentials();
|
|
}
|
|
|
|
this.bootstrapSecurityBindingElement.ReaderQuotas = this.IssuerBindingContext.GetInnerProperty<XmlDictionaryReaderQuotas>();
|
|
if (this.bootstrapSecurityBindingElement.ReaderQuotas == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.EncodingBindingElementDoesNotHandleReaderQuotas)));
|
|
}
|
|
|
|
TransportBindingElement transportBindingElement = this.IssuerBindingContext.RemainingBindingElements.Find<TransportBindingElement>();
|
|
if (transportBindingElement != null)
|
|
this.bootstrapSecurityBindingElement.MaxReceivedMessageSize = transportBindingElement.MaxReceivedMessageSize;
|
|
|
|
SecurityProtocolFactory securityProtocolFactory = this.bootstrapSecurityBindingElement.CreateSecurityProtocolFactory<IRequestChannel>(this.IssuerBindingContext.Clone(), securityCredentials, false, this.IssuerBindingContext.Clone());
|
|
MessageSecurityProtocolFactory soapBindingFactory = (securityProtocolFactory as MessageSecurityProtocolFactory);
|
|
if (soapBindingFactory != null)
|
|
{
|
|
soapBindingFactory.ApplyConfidentiality = soapBindingFactory.ApplyIntegrity
|
|
= soapBindingFactory.RequireConfidentiality = soapBindingFactory.RequireIntegrity = true;
|
|
|
|
MessagePartSpecification bodyPart = new MessagePartSpecification(true);
|
|
soapBindingFactory.ProtectionRequirements.IncomingSignatureParts.AddParts(bodyPart, RequestSecurityTokenAction);
|
|
soapBindingFactory.ProtectionRequirements.IncomingEncryptionParts.AddParts(bodyPart, RequestSecurityTokenAction);
|
|
soapBindingFactory.ProtectionRequirements.OutgoingSignatureParts.AddParts(bodyPart, RequestSecurityTokenResponseAction);
|
|
soapBindingFactory.ProtectionRequirements.OutgoingEncryptionParts.AddParts(bodyPart, RequestSecurityTokenResponseAction);
|
|
}
|
|
securityProtocolFactory.PrivacyNoticeUri = this.PrivacyNoticeUri;
|
|
securityProtocolFactory.PrivacyNoticeVersion = this.PrivacyNoticeVersion;
|
|
return new SecurityChannelFactory<IRequestChannel>(
|
|
securityCapabilities, this.IssuerBindingContext, channelBuilder, securityProtocolFactory, transportChannelFactory);
|
|
|
|
}
|
|
|
|
protected override IRequestChannel CreateClientChannel(EndpointAddress target, Uri via)
|
|
{
|
|
IRequestChannel result = base.CreateClientChannel(target, via);
|
|
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));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
protected override bool CreateNegotiationStateCompletesSynchronously(EndpointAddress target, Uri via)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
protected override AcceleratedTokenProviderState CreateNegotiationState(EndpointAddress target, Uri via, TimeSpan timeout)
|
|
{
|
|
byte[] keyEntropy;
|
|
if (this.keyEntropyMode == SecurityKeyEntropyMode.ClientEntropy || this.keyEntropyMode == SecurityKeyEntropyMode.CombinedEntropy)
|
|
{
|
|
keyEntropy = new byte[this.SecurityAlgorithmSuite.DefaultSymmetricKeyLength / 8];
|
|
CryptoHelper.FillRandomBytes(keyEntropy);
|
|
}
|
|
else
|
|
{
|
|
keyEntropy = null;
|
|
}
|
|
return new AcceleratedTokenProviderState(keyEntropy);
|
|
}
|
|
|
|
protected override IAsyncResult BeginCreateNegotiationState(EndpointAddress target, Uri via, TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
return new CompletedAsyncResult<AcceleratedTokenProviderState>(CreateNegotiationState(target, via, timeout), callback, state);
|
|
}
|
|
|
|
protected override AcceleratedTokenProviderState EndCreateNegotiationState(IAsyncResult result)
|
|
{
|
|
return CompletedAsyncResult<AcceleratedTokenProviderState>.End(result);
|
|
}
|
|
|
|
protected override BodyWriter GetFirstOutgoingMessageBody(AcceleratedTokenProviderState negotiationState, out MessageProperties messageProperties)
|
|
{
|
|
messageProperties = null;
|
|
RequestSecurityToken rst = new RequestSecurityToken(this.StandardsManager);
|
|
rst.Context = negotiationState.Context;
|
|
rst.KeySize = this.SecurityAlgorithmSuite.DefaultSymmetricKeyLength;
|
|
rst.TokenType = this.SecurityContextTokenUri;
|
|
byte[] requestorEntropy = negotiationState.GetRequestorEntropy();
|
|
if (requestorEntropy != null)
|
|
{
|
|
rst.SetRequestorEntropy(requestorEntropy);
|
|
}
|
|
rst.MakeReadOnly();
|
|
return rst;
|
|
}
|
|
|
|
protected override BodyWriter GetNextOutgoingMessageBody(Message incomingMessage, AcceleratedTokenProviderState negotiationState)
|
|
{
|
|
ThrowIfFault(incomingMessage, this.TargetAddress);
|
|
if (incomingMessage.Headers.Action != RequestSecurityTokenResponseAction.Value)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new SecurityNegotiationException(SR.GetString(SR.InvalidActionForNegotiationMessage, incomingMessage.Headers.Action)), incomingMessage);
|
|
}
|
|
// get the claims corresponding to the server
|
|
SecurityMessageProperty serverContextProperty = incomingMessage.Properties.Security;
|
|
ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies;
|
|
if (serverContextProperty != null && serverContextProperty.ServiceSecurityContext != null)
|
|
{
|
|
authorizationPolicies = serverContextProperty.ServiceSecurityContext.AuthorizationPolicies;
|
|
}
|
|
else
|
|
{
|
|
authorizationPolicies = EmptyReadOnlyCollection<IAuthorizationPolicy>.Instance;
|
|
}
|
|
RequestSecurityTokenResponse rstr = null;
|
|
XmlDictionaryReader bodyReader = incomingMessage.GetReaderAtBodyContents();
|
|
using (bodyReader)
|
|
{
|
|
if (this.StandardsManager.MessageSecurityVersion.TrustVersion == TrustVersion.WSTrustFeb2005)
|
|
rstr = RequestSecurityTokenResponse.CreateFrom(this.StandardsManager, 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)
|
|
{
|
|
// More than one RSTR is found. So throw an exception.
|
|
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);
|
|
}
|
|
byte[] keyEntropy = negotiationState.GetRequestorEntropy();
|
|
GenericXmlSecurityToken serviceToken = rstr.GetIssuedToken(null, null, this.keyEntropyMode, keyEntropy, this.SecurityContextTokenUri, authorizationPolicies, this.SecurityAlgorithmSuite.DefaultSymmetricKeyLength, false);
|
|
negotiationState.SetServiceToken(serviceToken);
|
|
return null;
|
|
}
|
|
}
|
|
}
|