e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
475 lines
21 KiB
C#
475 lines
21 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
namespace System.ServiceModel.Channels
|
|
{
|
|
using System;
|
|
using System.ServiceModel.Description;
|
|
using System.Xml;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Runtime.Serialization;
|
|
using System.ServiceModel;
|
|
using System.ServiceModel.Security;
|
|
using System.ServiceModel.Security.Tokens;
|
|
|
|
using System.Net.Security;
|
|
using System.Text;
|
|
|
|
public sealed class AsymmetricSecurityBindingElement : SecurityBindingElement, IPolicyExportExtension
|
|
{
|
|
internal const bool defaultAllowSerializedSigningTokenOnReply = false;
|
|
|
|
bool allowSerializedSigningTokenOnReply;
|
|
SecurityTokenParameters initiatorTokenParameters;
|
|
MessageProtectionOrder messageProtectionOrder;
|
|
SecurityTokenParameters recipientTokenParameters;
|
|
bool requireSignatureConfirmation;
|
|
bool isCertificateSignatureBinding;
|
|
|
|
AsymmetricSecurityBindingElement(AsymmetricSecurityBindingElement elementToBeCloned)
|
|
: base(elementToBeCloned)
|
|
{
|
|
if (elementToBeCloned.initiatorTokenParameters != null)
|
|
this.initiatorTokenParameters = (SecurityTokenParameters)elementToBeCloned.initiatorTokenParameters.Clone();
|
|
this.messageProtectionOrder = elementToBeCloned.messageProtectionOrder;
|
|
if (elementToBeCloned.recipientTokenParameters != null)
|
|
this.recipientTokenParameters = (SecurityTokenParameters)elementToBeCloned.recipientTokenParameters.Clone();
|
|
this.requireSignatureConfirmation = elementToBeCloned.requireSignatureConfirmation;
|
|
this.allowSerializedSigningTokenOnReply = elementToBeCloned.allowSerializedSigningTokenOnReply;
|
|
this.isCertificateSignatureBinding = elementToBeCloned.isCertificateSignatureBinding;
|
|
}
|
|
|
|
public AsymmetricSecurityBindingElement()
|
|
: this(null, null)
|
|
{
|
|
// empty
|
|
}
|
|
|
|
public AsymmetricSecurityBindingElement(SecurityTokenParameters recipientTokenParameters)
|
|
: this(recipientTokenParameters, null)
|
|
{
|
|
// empty
|
|
}
|
|
|
|
public AsymmetricSecurityBindingElement(SecurityTokenParameters recipientTokenParameters, SecurityTokenParameters initiatorTokenParameters)
|
|
: this(recipientTokenParameters, initiatorTokenParameters, AsymmetricSecurityBindingElement.defaultAllowSerializedSigningTokenOnReply)
|
|
{
|
|
// empty
|
|
}
|
|
|
|
internal AsymmetricSecurityBindingElement(
|
|
SecurityTokenParameters recipientTokenParameters,
|
|
SecurityTokenParameters initiatorTokenParameters,
|
|
bool allowSerializedSigningTokenOnReply)
|
|
: base()
|
|
{
|
|
this.messageProtectionOrder = SecurityBindingElement.defaultMessageProtectionOrder;
|
|
this.requireSignatureConfirmation = SecurityBindingElement.defaultRequireSignatureConfirmation;
|
|
this.initiatorTokenParameters = initiatorTokenParameters;
|
|
this.recipientTokenParameters = recipientTokenParameters;
|
|
this.allowSerializedSigningTokenOnReply = allowSerializedSigningTokenOnReply;
|
|
this.isCertificateSignatureBinding = false;
|
|
}
|
|
|
|
public bool AllowSerializedSigningTokenOnReply
|
|
{
|
|
get
|
|
{
|
|
return this.allowSerializedSigningTokenOnReply;
|
|
}
|
|
set
|
|
{
|
|
this.allowSerializedSigningTokenOnReply = value;
|
|
}
|
|
}
|
|
|
|
public SecurityTokenParameters InitiatorTokenParameters
|
|
{
|
|
get
|
|
{
|
|
return this.initiatorTokenParameters;
|
|
}
|
|
set
|
|
{
|
|
this.initiatorTokenParameters = value;
|
|
}
|
|
}
|
|
|
|
public MessageProtectionOrder MessageProtectionOrder
|
|
{
|
|
get
|
|
{
|
|
return this.messageProtectionOrder;
|
|
}
|
|
set
|
|
{
|
|
if (!MessageProtectionOrderHelper.IsDefined(value))
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
|
|
this.messageProtectionOrder = value;
|
|
}
|
|
}
|
|
|
|
public SecurityTokenParameters RecipientTokenParameters
|
|
{
|
|
get
|
|
{
|
|
return this.recipientTokenParameters;
|
|
}
|
|
set
|
|
{
|
|
this.recipientTokenParameters = value;
|
|
}
|
|
}
|
|
|
|
public bool RequireSignatureConfirmation
|
|
{
|
|
get
|
|
{
|
|
return this.requireSignatureConfirmation;
|
|
}
|
|
set
|
|
{
|
|
this.requireSignatureConfirmation = value;
|
|
}
|
|
}
|
|
|
|
internal override ISecurityCapabilities GetIndividualISecurityCapabilities()
|
|
{
|
|
ProtectionLevel requestProtectionLevel = ProtectionLevel.EncryptAndSign;
|
|
ProtectionLevel responseProtectionLevel = ProtectionLevel.EncryptAndSign;
|
|
bool supportsServerAuthentication = false;
|
|
|
|
if (IsCertificateSignatureBinding)
|
|
{
|
|
requestProtectionLevel = ProtectionLevel.Sign;
|
|
responseProtectionLevel = ProtectionLevel.None;
|
|
}
|
|
else if (RecipientTokenParameters != null)
|
|
{
|
|
supportsServerAuthentication = RecipientTokenParameters.SupportsServerAuthentication;
|
|
}
|
|
|
|
bool supportsClientAuthentication;
|
|
bool supportsClientWindowsIdentity;
|
|
GetSupportingTokensCapabilities(out supportsClientAuthentication, out supportsClientWindowsIdentity);
|
|
if (InitiatorTokenParameters != null)
|
|
{
|
|
supportsClientAuthentication = supportsClientAuthentication || InitiatorTokenParameters.SupportsClientAuthentication;
|
|
supportsClientWindowsIdentity = supportsClientWindowsIdentity || InitiatorTokenParameters.SupportsClientWindowsIdentity;
|
|
}
|
|
|
|
return new SecurityCapabilities(supportsClientAuthentication, supportsServerAuthentication, supportsClientWindowsIdentity,
|
|
requestProtectionLevel, responseProtectionLevel);
|
|
}
|
|
|
|
internal override bool SupportsDuplex
|
|
{
|
|
get { return !this.isCertificateSignatureBinding; }
|
|
}
|
|
|
|
internal override bool SupportsRequestReply
|
|
{
|
|
get
|
|
{
|
|
return !this.isCertificateSignatureBinding;
|
|
}
|
|
}
|
|
|
|
internal bool IsCertificateSignatureBinding
|
|
{
|
|
get { return this.isCertificateSignatureBinding; }
|
|
set { this.isCertificateSignatureBinding = value; }
|
|
}
|
|
|
|
public override void SetKeyDerivation(bool requireDerivedKeys)
|
|
{
|
|
base.SetKeyDerivation(requireDerivedKeys);
|
|
if (this.initiatorTokenParameters != null)
|
|
this.initiatorTokenParameters.RequireDerivedKeys = requireDerivedKeys;
|
|
if (this.recipientTokenParameters != null)
|
|
this.recipientTokenParameters.RequireDerivedKeys = requireDerivedKeys;
|
|
}
|
|
|
|
internal override bool IsSetKeyDerivation(bool requireDerivedKeys)
|
|
{
|
|
if (!base.IsSetKeyDerivation(requireDerivedKeys))
|
|
return false;
|
|
if (this.initiatorTokenParameters != null && this.initiatorTokenParameters.RequireDerivedKeys != requireDerivedKeys)
|
|
return false;
|
|
if (this.recipientTokenParameters != null && this.recipientTokenParameters.RequireDerivedKeys != requireDerivedKeys)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool HasProtectionRequirements(ScopedMessagePartSpecification scopedParts)
|
|
{
|
|
foreach (string action in scopedParts.Actions)
|
|
{
|
|
MessagePartSpecification parts;
|
|
if (scopedParts.TryGetParts(action, out parts))
|
|
{
|
|
if (!parts.IsEmpty())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
internal override SecurityProtocolFactory CreateSecurityProtocolFactory<TChannel>(BindingContext context, SecurityCredentialsManager credentialsManager, bool isForService, BindingContext issuerBindingContext)
|
|
{
|
|
if (context == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
|
|
if (credentialsManager == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("credentialsManager");
|
|
|
|
if (this.InitiatorTokenParameters == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.AsymmetricSecurityBindingElementNeedsInitiatorTokenParameters, this.ToString())));
|
|
if (this.RecipientTokenParameters == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.AsymmetricSecurityBindingElementNeedsRecipientTokenParameters, this.ToString())));
|
|
|
|
bool isDuplexSecurity = !this.isCertificateSignatureBinding && (typeof(IDuplexChannel) == typeof(TChannel) || typeof(IDuplexSessionChannel) == typeof(TChannel));
|
|
|
|
SecurityProtocolFactory protocolFactory;
|
|
|
|
AsymmetricSecurityProtocolFactory forward = new AsymmetricSecurityProtocolFactory();
|
|
forward.ProtectionRequirements.Add(SecurityBindingElement.ComputeProtectionRequirements(this, context.BindingParameters, context.Binding.Elements, isForService));
|
|
forward.RequireConfidentiality = this.HasProtectionRequirements(forward.ProtectionRequirements.IncomingEncryptionParts);
|
|
forward.RequireIntegrity = this.HasProtectionRequirements(forward.ProtectionRequirements.IncomingSignatureParts);
|
|
if (this.isCertificateSignatureBinding)
|
|
{
|
|
if (isForService)
|
|
{
|
|
forward.ApplyIntegrity = forward.ApplyConfidentiality = false;
|
|
}
|
|
else
|
|
{
|
|
forward.ApplyConfidentiality = forward.RequireIntegrity = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
forward.ApplyIntegrity = this.HasProtectionRequirements(forward.ProtectionRequirements.OutgoingSignatureParts);
|
|
forward.ApplyConfidentiality = this.HasProtectionRequirements(forward.ProtectionRequirements.OutgoingEncryptionParts);
|
|
}
|
|
if (isForService)
|
|
{
|
|
base.ApplyAuditBehaviorSettings(context, forward);
|
|
if (forward.RequireConfidentiality || (!this.isCertificateSignatureBinding && forward.ApplyIntegrity))
|
|
{
|
|
forward.AsymmetricTokenParameters = (SecurityTokenParameters)this.RecipientTokenParameters.Clone();
|
|
}
|
|
else
|
|
{
|
|
forward.AsymmetricTokenParameters = null;
|
|
}
|
|
forward.CryptoTokenParameters = this.InitiatorTokenParameters.Clone();
|
|
SetIssuerBindingContextIfRequired(forward.CryptoTokenParameters, issuerBindingContext);
|
|
}
|
|
else
|
|
{
|
|
if (forward.ApplyConfidentiality || (!this.isCertificateSignatureBinding && forward.RequireIntegrity))
|
|
{
|
|
forward.AsymmetricTokenParameters = (SecurityTokenParameters)this.RecipientTokenParameters.Clone();
|
|
}
|
|
else
|
|
{
|
|
forward.AsymmetricTokenParameters = null;
|
|
}
|
|
forward.CryptoTokenParameters = this.InitiatorTokenParameters.Clone();
|
|
SetIssuerBindingContextIfRequired(forward.CryptoTokenParameters, issuerBindingContext);
|
|
}
|
|
if (isDuplexSecurity)
|
|
{
|
|
if (isForService)
|
|
{
|
|
forward.ApplyConfidentiality = forward.ApplyIntegrity = false;
|
|
}
|
|
else
|
|
{
|
|
forward.RequireIntegrity = forward.RequireConfidentiality = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!isForService)
|
|
{
|
|
forward.AllowSerializedSigningTokenOnReply = this.AllowSerializedSigningTokenOnReply;
|
|
}
|
|
}
|
|
|
|
forward.IdentityVerifier = this.LocalClientSettings.IdentityVerifier;
|
|
forward.DoRequestSignatureConfirmation = this.RequireSignatureConfirmation;
|
|
forward.MessageProtectionOrder = this.MessageProtectionOrder;
|
|
base.ConfigureProtocolFactory(forward, credentialsManager, isForService, issuerBindingContext, context.Binding);
|
|
if (!forward.RequireIntegrity)
|
|
forward.DetectReplays = false;
|
|
|
|
if (isDuplexSecurity)
|
|
{
|
|
AsymmetricSecurityProtocolFactory reverse = new AsymmetricSecurityProtocolFactory();
|
|
if (isForService)
|
|
{
|
|
reverse.AsymmetricTokenParameters = this.InitiatorTokenParameters.Clone();
|
|
reverse.AsymmetricTokenParameters.ReferenceStyle = SecurityTokenReferenceStyle.External;
|
|
reverse.AsymmetricTokenParameters.InclusionMode = SecurityTokenInclusionMode.Never;
|
|
reverse.CryptoTokenParameters = (SecurityTokenParameters)this.RecipientTokenParameters.Clone();
|
|
reverse.CryptoTokenParameters.ReferenceStyle = SecurityTokenReferenceStyle.Internal;
|
|
reverse.CryptoTokenParameters.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
|
|
reverse.IdentityVerifier = null;
|
|
}
|
|
else
|
|
{
|
|
reverse.AsymmetricTokenParameters = this.InitiatorTokenParameters.Clone();
|
|
reverse.AsymmetricTokenParameters.ReferenceStyle = SecurityTokenReferenceStyle.External;
|
|
reverse.AsymmetricTokenParameters.InclusionMode = SecurityTokenInclusionMode.Never;
|
|
reverse.CryptoTokenParameters = (SecurityTokenParameters)this.RecipientTokenParameters.Clone();
|
|
reverse.CryptoTokenParameters.ReferenceStyle = SecurityTokenReferenceStyle.Internal;
|
|
reverse.CryptoTokenParameters.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
|
|
reverse.IdentityVerifier = this.LocalClientSettings.IdentityVerifier;
|
|
}
|
|
reverse.DoRequestSignatureConfirmation = this.RequireSignatureConfirmation;
|
|
reverse.MessageProtectionOrder = this.MessageProtectionOrder;
|
|
reverse.ProtectionRequirements.Add(SecurityBindingElement.ComputeProtectionRequirements(this, context.BindingParameters, context.Binding.Elements, isForService));
|
|
if (isForService)
|
|
{
|
|
reverse.ApplyConfidentiality = this.HasProtectionRequirements(reverse.ProtectionRequirements.OutgoingEncryptionParts);
|
|
reverse.ApplyIntegrity = true;
|
|
reverse.RequireIntegrity = reverse.RequireConfidentiality = false;
|
|
}
|
|
else
|
|
{
|
|
reverse.RequireConfidentiality = this.HasProtectionRequirements(reverse.ProtectionRequirements.IncomingEncryptionParts);
|
|
reverse.RequireIntegrity = true;
|
|
reverse.ApplyIntegrity = reverse.ApplyConfidentiality = false;
|
|
}
|
|
base.ConfigureProtocolFactory(reverse, credentialsManager, !isForService, issuerBindingContext, context.Binding);
|
|
if (!reverse.RequireIntegrity)
|
|
reverse.DetectReplays = false;
|
|
|
|
// setup reverse here
|
|
reverse.IsDuplexReply = true;
|
|
|
|
DuplexSecurityProtocolFactory duplex = new DuplexSecurityProtocolFactory();
|
|
duplex.ForwardProtocolFactory = forward;
|
|
duplex.ReverseProtocolFactory = reverse;
|
|
protocolFactory = duplex;
|
|
}
|
|
else
|
|
{
|
|
protocolFactory = forward;
|
|
}
|
|
|
|
return protocolFactory;
|
|
}
|
|
|
|
internal override bool RequiresChannelDemuxer()
|
|
{
|
|
return (base.RequiresChannelDemuxer() || RequiresChannelDemuxer(this.InitiatorTokenParameters));
|
|
}
|
|
|
|
protected override IChannelFactory<TChannel> BuildChannelFactoryCore<TChannel>(BindingContext context)
|
|
{
|
|
ISecurityCapabilities securityCapabilities = this.GetProperty<ISecurityCapabilities>(context);
|
|
bool requireDemuxer = RequiresChannelDemuxer();
|
|
ChannelBuilder channelBuilder = new ChannelBuilder(context, requireDemuxer);
|
|
if (requireDemuxer)
|
|
{
|
|
ApplyPropertiesOnDemuxer(channelBuilder, context);
|
|
}
|
|
|
|
BindingContext issuerBindingContext = context.Clone();
|
|
SecurityCredentialsManager credentialsManager = context.BindingParameters.Find<SecurityCredentialsManager>();
|
|
if (credentialsManager == null)
|
|
{
|
|
credentialsManager = ClientCredentials.CreateDefaultCredentials();
|
|
}
|
|
|
|
SecurityProtocolFactory protocolFactory =
|
|
this.CreateSecurityProtocolFactory<TChannel>(context, credentialsManager, false, issuerBindingContext);
|
|
|
|
return new SecurityChannelFactory<TChannel>(securityCapabilities, context, channelBuilder, protocolFactory);
|
|
}
|
|
|
|
protected override IChannelListener<TChannel> BuildChannelListenerCore<TChannel>(BindingContext context)
|
|
{
|
|
bool requireDemuxer = RequiresChannelDemuxer();
|
|
ChannelBuilder channelBuilder = new ChannelBuilder(context, requireDemuxer);
|
|
if (requireDemuxer)
|
|
{
|
|
ApplyPropertiesOnDemuxer(channelBuilder, context);
|
|
}
|
|
BindingContext issuerBindingContext = context.Clone();
|
|
|
|
SecurityChannelListener<TChannel> channelListener = new SecurityChannelListener<TChannel>(this, context);
|
|
SecurityCredentialsManager credentialsManager = context.BindingParameters.Find<SecurityCredentialsManager>();
|
|
if (credentialsManager == null)
|
|
credentialsManager = ServiceCredentials.CreateDefaultCredentials();
|
|
|
|
SecurityProtocolFactory protocolFactory = this.CreateSecurityProtocolFactory<TChannel>(context, credentialsManager, true, issuerBindingContext);
|
|
channelListener.SecurityProtocolFactory = protocolFactory;
|
|
channelListener.InitializeListener(channelBuilder);
|
|
|
|
return channelListener;
|
|
}
|
|
|
|
public override T GetProperty<T>(BindingContext context)
|
|
{
|
|
if (context == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
|
|
|
|
if (typeof(T) == typeof(ChannelProtectionRequirements))
|
|
{
|
|
AddressingVersion addressing = MessageVersion.Default.Addressing;
|
|
#pragma warning suppress 56506
|
|
MessageEncodingBindingElement encoding = context.Binding.Elements.Find<MessageEncodingBindingElement>();
|
|
if (encoding != null)
|
|
{
|
|
addressing = encoding.MessageVersion.Addressing;
|
|
}
|
|
|
|
ChannelProtectionRequirements myRequirements = base.GetProtectionRequirements(addressing, this.GetIndividualProperty<ISecurityCapabilities>().SupportedRequestProtectionLevel);
|
|
myRequirements.Add(context.GetInnerProperty<ChannelProtectionRequirements>() ?? new ChannelProtectionRequirements());
|
|
return (T)(object)myRequirements;
|
|
}
|
|
else
|
|
{
|
|
return base.GetProperty<T>(context);
|
|
}
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.AppendLine(base.ToString());
|
|
|
|
sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "MessageProtectionOrder: {0}", this.messageProtectionOrder.ToString()));
|
|
sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "RequireSignatureConfirmation: {0}", this.requireSignatureConfirmation.ToString()));
|
|
sb.Append("InitiatorTokenParameters: ");
|
|
if (this.initiatorTokenParameters != null)
|
|
sb.AppendLine(this.initiatorTokenParameters.ToString().Trim().Replace("\n", "\n "));
|
|
else
|
|
sb.AppendLine("null");
|
|
sb.Append("RecipientTokenParameters: ");
|
|
if (this.recipientTokenParameters != null)
|
|
sb.AppendLine(this.recipientTokenParameters.ToString().Trim().Replace("\n", "\n "));
|
|
else
|
|
sb.AppendLine("null");
|
|
|
|
return sb.ToString().Trim();
|
|
}
|
|
|
|
public override BindingElement Clone()
|
|
{
|
|
return new AsymmetricSecurityBindingElement(this);
|
|
}
|
|
|
|
void IPolicyExportExtension.ExportPolicy(MetadataExporter exporter, PolicyConversionContext context)
|
|
{
|
|
SecurityBindingElement.ExportPolicy(exporter, context);
|
|
}
|
|
}
|
|
}
|