|
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Channels
{
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IdentityModel.Claims;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Runtime;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Security;
using System.ServiceModel.Security.Tokens;
using System.Xml;
class PeerSecurityManager
{
PeerAuthenticationMode authenticationMode;
bool enableSigning;
internal string password;
DuplexSecurityProtocolFactory securityProtocolFactory;
// Double-checked locking pattern requires volatile for read/write synchronization
volatile byte[] authenticatorHash;
object thisLock;
//public EventHandler OnNeighborOpened;
public EventHandler OnNeighborAuthenticated;
string meshId = String.Empty;
ChannelProtectionRequirements protection;
PeerSecurityCredentialsManager credManager;
SecurityTokenManager tokenManager;
// Double-checked locking pattern requires volatile for read/write synchronization
volatile SelfSignedCertificate ssc;
XmlDictionaryReaderQuotas readerQuotas;
// Audit
ServiceSecurityAuditBehavior auditBehavior;
PeerSecurityManager(PeerAuthenticationMode authMode, bool signing)
{
this.authenticationMode = authMode;
this.enableSigning = signing;
thisLock = new object();
}
public PeerAuthenticationMode AuthenticationMode
{
get
{
return authenticationMode;
}
}
public string Password
{
get
{
return password;
}
}
public X509Certificate2 SelfCert
{
get
{
return credManager.Certificate;
}
}
public bool MessageAuthentication
{
get
{
return this.enableSigning;
}
}
internal string MeshId
{
get
{
return this.meshId;
}
set
{
this.meshId = value;
}
}
internal SelfSignedCertificate GetCertificate()
{
if (this.ssc == null)
{
lock (ThisLock)
{
if (ssc == null)
ssc = SelfSignedCertificate.Create("CN=" + Guid.NewGuid().ToString(), this.Password);
}
}
return ssc;
}
object ThisLock
{
get { return thisLock; }
}
static PeerSecurityCredentialsManager GetCredentialsManager(PeerAuthenticationMode mode, bool signing, BindingContext context)
{
if (mode == PeerAuthenticationMode.None && !signing)
return null;
ClientCredentials clientCredentials = context.BindingParameters.Find<ClientCredentials>();
if (clientCredentials != null)
{
return new PeerSecurityCredentialsManager(clientCredentials.Peer, mode, signing);
}
ServiceCredentials serviceCredentials = context.BindingParameters.Find<ServiceCredentials>();
if (serviceCredentials != null)
{
return new PeerSecurityCredentialsManager(serviceCredentials.Peer, mode, signing);
}
SecurityCredentialsManager credman = context.BindingParameters.Find<SecurityCredentialsManager>();
if (credman == null)
{
PeerExceptionHelper.ThrowArgument_InsufficientCredentials(PeerPropertyNames.Credentials);
}
return new PeerSecurityCredentialsManager(credman.CreateSecurityTokenManager(), mode, signing);
}
static void Convert(PeerSecuritySettings security, out PeerAuthenticationMode authMode, out bool signing)
{
authMode = PeerAuthenticationMode.None;
signing = false;
if (security.Mode == SecurityMode.Transport || security.Mode == SecurityMode.TransportWithMessageCredential)
{
switch (security.Transport.CredentialType)
{
case PeerTransportCredentialType.Password:
authMode = PeerAuthenticationMode.Password;
break;
case PeerTransportCredentialType.Certificate:
authMode = PeerAuthenticationMode.MutualCertificate;
break;
}
}
if (security.Mode == SecurityMode.Message || security.Mode == SecurityMode.TransportWithMessageCredential)
{
signing = true;
}
}
static public PeerSecurityManager Create(PeerSecuritySettings security, BindingContext context, XmlDictionaryReaderQuotas readerQuotas)
{
PeerAuthenticationMode authMode = PeerAuthenticationMode.None;
bool signing = false;
Convert(security, out authMode, out signing);
return Create(authMode, signing, context, readerQuotas);
}
static public PeerSecurityManager Create(PeerAuthenticationMode authenticationMode, bool signMessages, BindingContext context, XmlDictionaryReaderQuotas readerQuotas)
{
if (authenticationMode == PeerAuthenticationMode.None && !signMessages)
return CreateDummy();
// test FIPS mode
if (authenticationMode == PeerAuthenticationMode.Password)
{
try
{
using (HMACSHA256 algo = new HMACSHA256())
{
using (SHA256Managed sha = new SHA256Managed()) { }
}
}
catch (InvalidOperationException e)
{
DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
PeerExceptionHelper.ThrowInvalidOperation_InsufficientCryptoSupport(e);
}
}
ChannelProtectionRequirements reqs = context.BindingParameters.Find<ChannelProtectionRequirements>();
PeerSecurityCredentialsManager credman = GetCredentialsManager(authenticationMode, signMessages, context);
if (credman.Credential != null)
{
//for compatibility with existing code:
ValidateCredentialSettings(authenticationMode, signMessages, credman.Credential);
}
PeerSecurityManager manager = Create(authenticationMode, signMessages, credman, reqs, readerQuotas);
credman.Parent = manager;
manager.ApplyAuditBehaviorSettings(context);
return manager;
}
static void ValidateCredentialSettings(PeerAuthenticationMode authenticationMode, bool signMessages, PeerCredential credential)
{
X509CertificateValidator validator;
if (authenticationMode == PeerAuthenticationMode.None && !signMessages)
return;
switch (authenticationMode)
{
case PeerAuthenticationMode.Password:
{
if (String.IsNullOrEmpty(credential.MeshPassword))
PeerExceptionHelper.ThrowArgument_InsufficientCredentials(PeerPropertyNames.Password);
}
break;
case PeerAuthenticationMode.MutualCertificate:
{
if (credential.Certificate == null)
{
PeerExceptionHelper.ThrowArgument_InsufficientCredentials(PeerPropertyNames.Certificate);
}
if (!credential.PeerAuthentication.TryGetCertificateValidator(out validator))
{
PeerExceptionHelper.ThrowArgument_InsufficientCredentials(PeerPropertyNames.PeerAuthentication);
}
}
break;
}
if (signMessages)
{
if (!credential.MessageSenderAuthentication.TryGetCertificateValidator(out validator))
{
PeerExceptionHelper.ThrowArgument_InsufficientCredentials(PeerPropertyNames.MessageSenderAuthentication);
}
}
}
void ApplyAuditBehaviorSettings(BindingContext context)
{
ServiceSecurityAuditBehavior auditBehavior = context.BindingParameters.Find<ServiceSecurityAuditBehavior>();
if (auditBehavior != null)
{
this.auditBehavior = auditBehavior.Clone();
}
else
{
this.auditBehavior = new ServiceSecurityAuditBehavior();
}
}
public void ApplyServiceSecurity(ServiceDescription description)
{
if (this.AuthenticationMode == PeerAuthenticationMode.None)
return;
description.Behaviors.Add(credManager.CloneForTransport());
}
internal static PeerSecurityManager CreateDummy()
{
PeerSecurityManager manager = new PeerSecurityManager(PeerAuthenticationMode.None, false);
return manager;
}
static public PeerSecurityManager Create(PeerAuthenticationMode authenticationMode, bool messageAuthentication, PeerSecurityCredentialsManager credman, ChannelProtectionRequirements reqs, XmlDictionaryReaderQuotas readerQuotas)
{
PeerSecurityManager manager = null;
X509CertificateValidator connectionValidator = null;
X509CertificateValidator messageValidator = null;
PeerCredential credential = credman.Credential;
if (null == credential && credman == null)
{
if (authenticationMode != PeerAuthenticationMode.None || messageAuthentication)
PeerExceptionHelper.ThrowArgument_InsufficientCredentials(PeerPropertyNames.Credentials);
//create one that doesnt have any credentials in it.
return CreateDummy();
}
manager = new PeerSecurityManager(authenticationMode, messageAuthentication);
manager.credManager = credman;
manager.password = credman.Password;
manager.readerQuotas = readerQuotas;
if (reqs != null)
{
manager.protection = new ChannelProtectionRequirements(reqs);
}
manager.tokenManager = credman.CreateSecurityTokenManager();
if (credential == null)
return manager;
switch (authenticationMode)
{
case PeerAuthenticationMode.None:
break;
case PeerAuthenticationMode.Password:
{
manager.password = credential.MeshPassword;
if (String.IsNullOrEmpty(manager.credManager.Password))
{
PeerExceptionHelper.ThrowArgument_InsufficientCredentials(PeerPropertyNames.Password);
}
connectionValidator = X509CertificateValidator.None;
}
break;
case PeerAuthenticationMode.MutualCertificate:
{
if (manager.credManager.Certificate == null)
{
PeerExceptionHelper.ThrowArgument_InsufficientCredentials(PeerPropertyNames.Certificate);
}
if (!credential.PeerAuthentication.TryGetCertificateValidator(out connectionValidator))
{
PeerExceptionHelper.ThrowArgument_InsufficientCredentials(PeerPropertyNames.PeerAuthentication);
}
}
break;
}
if (messageAuthentication)
{
if (credential.MessageSenderAuthentication != null)
{
if (!credential.MessageSenderAuthentication.TryGetCertificateValidator(out messageValidator))
{
PeerExceptionHelper.ThrowArgument_InsufficientCredentials(PeerPropertyNames.MessageSenderAuthentication);
}
}
else
{
PeerExceptionHelper.ThrowArgument_InsufficientCredentials(PeerPropertyNames.MessageSenderAuthentication);
}
}
return manager;
}
void ApplySigningRequirements(ScopedMessagePartSpecification spec)
{
//following are the headers that we add and want signed.
MessagePartSpecification partSpec = new MessagePartSpecification(
new XmlQualifiedName(PeerStrings.Via, PeerStrings.Namespace),
new XmlQualifiedName(PeerOperationNames.Flood, PeerStrings.Namespace),
new XmlQualifiedName(PeerOperationNames.PeerTo, PeerStrings.Namespace),
new XmlQualifiedName(PeerStrings.MessageId, PeerStrings.Namespace));
foreach (string action in spec.Actions)
{
spec.AddParts(partSpec, action);
}
spec.AddParts(partSpec, MessageHeaders.WildcardAction);
}
public void Open()
{
CreateSecurityProtocolFactory();
}
void CreateSecurityProtocolFactory()
{
SecurityProtocolFactory incomingProtocolFactory;
SecurityProtocolFactory outgoingProtocolFactory;
ChannelProtectionRequirements protectionRequirements;
lock (ThisLock)
{
if (null != securityProtocolFactory)
return;
TimeoutHelper timeoutHelper = new TimeoutHelper(ServiceDefaults.SendTimeout);
if (!enableSigning)
{
outgoingProtocolFactory = new PeerDoNothingSecurityProtocolFactory();
incomingProtocolFactory = new PeerDoNothingSecurityProtocolFactory();
}
else
{
X509Certificate2 cert = credManager.Certificate;
if (cert != null)
{
SecurityBindingElement securityBindingElement = SecurityBindingElement.CreateCertificateSignatureBindingElement();
securityBindingElement.ReaderQuotas = this.readerQuotas;
BindingParameterCollection bpc = new BindingParameterCollection();
if (protection == null)
{
protectionRequirements = new ChannelProtectionRequirements();
}
else
{
protectionRequirements = new ChannelProtectionRequirements(protection);
}
ApplySigningRequirements(protectionRequirements.IncomingSignatureParts);
ApplySigningRequirements(protectionRequirements.OutgoingSignatureParts);
bpc.Add(protectionRequirements);
bpc.Add(this.auditBehavior);
bpc.Add(credManager);
BindingContext context = new BindingContext(new CustomBinding(securityBindingElement), bpc);
outgoingProtocolFactory = securityBindingElement.CreateSecurityProtocolFactory<IOutputChannel>(context, credManager, false, null);
}
else
{
outgoingProtocolFactory = new PeerDoNothingSecurityProtocolFactory();
}
SecurityTokenResolver resolver;
X509SecurityTokenAuthenticator auth = tokenManager.CreateSecurityTokenAuthenticator(PeerSecurityCredentialsManager.PeerClientSecurityTokenManager.CreateRequirement(SecurityTokenTypes.X509Certificate, true), out resolver) as X509SecurityTokenAuthenticator;
if (auth != null)
{
SecurityBindingElement securityBindingElement = SecurityBindingElement.CreateCertificateSignatureBindingElement();
securityBindingElement.ReaderQuotas = this.readerQuotas;
BindingParameterCollection bpc = new BindingParameterCollection();
if (protection == null)
{
protectionRequirements = new ChannelProtectionRequirements();
}
else
{
protectionRequirements = new ChannelProtectionRequirements(protection);
}
ApplySigningRequirements(protectionRequirements.IncomingSignatureParts);
ApplySigningRequirements(protectionRequirements.OutgoingSignatureParts);
bpc.Add(protectionRequirements);
bpc.Add(this.auditBehavior);
bpc.Add(credManager);
BindingContext context = new BindingContext(new CustomBinding(securityBindingElement), bpc);
incomingProtocolFactory = securityBindingElement.CreateSecurityProtocolFactory<IOutputChannel>(context, credManager, true, null);
}
else
{
incomingProtocolFactory = new PeerDoNothingSecurityProtocolFactory();
}
}
DuplexSecurityProtocolFactory tempFactory = new DuplexSecurityProtocolFactory(outgoingProtocolFactory, incomingProtocolFactory);
tempFactory.Open(true, timeoutHelper.RemainingTime());
securityProtocolFactory = tempFactory;
}
}
public SecurityProtocolFactory GetProtocolFactory<TChannel>()
{
if (securityProtocolFactory == null)
{
CreateSecurityProtocolFactory();
}
if (typeof(TChannel) == typeof(IOutputChannel))
{
if (enableSigning && securityProtocolFactory.ForwardProtocolFactory is PeerDoNothingSecurityProtocolFactory)
PeerExceptionHelper.ThrowArgument_InsufficientCredentials(PeerPropertyNames.MessageSenderAuthentication);
return securityProtocolFactory.ForwardProtocolFactory;
}
else if (typeof(TChannel) == typeof(IInputChannel))
{
if (enableSigning && securityProtocolFactory.ReverseProtocolFactory is PeerDoNothingSecurityProtocolFactory)
PeerExceptionHelper.ThrowArgument_InsufficientCredentials(PeerPropertyNames.MessageSenderAuthentication);
return securityProtocolFactory.ReverseProtocolFactory;
}
else
{
if (enableSigning && ((securityProtocolFactory.ReverseProtocolFactory is PeerDoNothingSecurityProtocolFactory)
|| (securityProtocolFactory.ForwardProtocolFactory is PeerDoNothingSecurityProtocolFactory)))
PeerExceptionHelper.ThrowArgument_InsufficientCredentials(PeerPropertyNames.MessageSenderAuthentication);
return securityProtocolFactory;
}
}
public SecurityProtocol CreateSecurityProtocol<TChannel>(EndpointAddress target, TimeSpan timespan)
{
TimeoutHelper timeoutHelper = new TimeoutHelper(timespan);
SecurityProtocolFactory factory = GetProtocolFactory<TChannel>();
Fx.Assert(factory != null, "SecurityProtocolFactory is NULL!");
SecurityProtocol instance = factory.CreateSecurityProtocol(target, null, /*listenerSecurityState*/null, /*isReturnLegSecurityRequired*/false, timeoutHelper.RemainingTime());
if (instance != null)
instance.Open(timeoutHelper.RemainingTime());
return instance;
}
public void CheckIfCompatibleNodeSettings(object other)
{
string mismatch = null;
PeerSecurityManager that = other as PeerSecurityManager;
if (that == null)
mismatch = PeerBindingPropertyNames.Security;
else if (this.authenticationMode != that.authenticationMode)
mismatch = PeerBindingPropertyNames.SecurityDotMode;
else if (this.authenticationMode == PeerAuthenticationMode.None)
return;
else if (!this.tokenManager.Equals(that.tokenManager))
{
if (this.credManager != null)
this.credManager.CheckIfCompatible(that.credManager);
else
{
Fx.Assert(typeof(PeerSecurityCredentialsManager.PeerClientSecurityTokenManager).IsAssignableFrom(tokenManager.GetType()), "");
mismatch = PeerBindingPropertyNames.Credentials;
}
}
if (mismatch != null)
PeerExceptionHelper.ThrowInvalidOperation_PeerConflictingPeerNodeSettings(mismatch);
}
public bool HasCompatibleMessageSecurity(PeerSecurityManager that)
{
return (this.MessageAuthentication == that.MessageAuthentication);
}
public byte[] GetAuthenticator()
{
if (authenticationMode != PeerAuthenticationMode.Password)
return null;
if (authenticatorHash == null)
{
lock (ThisLock)
{
if (authenticatorHash == null)
{
authenticatorHash = PeerSecurityHelpers.ComputeHash(credManager.Certificate, credManager.Password);
}
}
}
return authenticatorHash;
}
public bool Authenticate(ServiceSecurityContext context, byte[] message)
{
Claim claim = null;
if (context == null)
{
return (authenticationMode == PeerAuthenticationMode.None);
}
if (authenticationMode == PeerAuthenticationMode.Password)
{
if (!(context != null))
{
throw Fx.AssertAndThrow("No SecurityContext attached in security mode!");
}
claim = FindClaim(context);
return PeerSecurityHelpers.Authenticate(claim, this.credManager.Password, message);
}
else
{
if (message != null)
{
PeerExceptionHelper.ThrowInvalidOperation_UnexpectedSecurityTokensDuringHandshake();
}
return true;
}
}
public static Claim FindClaim(ServiceSecurityContext context)
{
Claim result = null;
Fx.Assert(context != null, "ServiceSecurityContext is null!");
for (int i = 0; i < context.AuthorizationContext.ClaimSets.Count; ++i)
{
ClaimSet claimSet = context.AuthorizationContext.ClaimSets[i];
IEnumerator<Claim> claims = claimSet.FindClaims(ClaimTypes.Rsa, null).GetEnumerator();
if (claims.MoveNext())
{
result = claims.Current;
break;
}
}
return result;
}
public void ApplyClientSecurity(ChannelFactory<IPeerProxy> factory)
{
factory.Endpoint.Behaviors.Remove<ClientCredentials>();
if (authenticationMode != PeerAuthenticationMode.None)
{
factory.Endpoint.Behaviors.Add(this.credManager.CloneForTransport());
}
}
public BindingElement GetSecurityBindingElement()
{
SslStreamSecurityBindingElement security = null;
if (this.AuthenticationMode != PeerAuthenticationMode.None)
{
security = new SslStreamSecurityBindingElement();
security.IdentityVerifier = new PeerIdentityVerifier();
security.RequireClientCertificate = true;
}
return security;
}
public PeerHashToken GetSelfToken()
{
if (!(this.authenticationMode == PeerAuthenticationMode.Password))
{
throw Fx.AssertAndThrow("unexpected call to GetSelfToken");
}
return new PeerHashToken(this.credManager.Certificate, this.credManager.Password);
}
public PeerHashToken GetExpectedTokenForClaim(Claim claim)
{
return new PeerHashToken(claim, this.password);
}
public void OnNeighborOpened(object sender, EventArgs args)
{
IPeerNeighbor neighbor = sender as IPeerNeighbor;
EventHandler handler = this.OnNeighborAuthenticated;
if (handler == null)
{
neighbor.Abort(PeerCloseReason.LeavingMesh, PeerCloseInitiator.LocalNode);
return;
}
if (this.authenticationMode == PeerAuthenticationMode.Password)
{
if (!(neighbor.Extensions.Find<PeerChannelAuthenticatorExtension>() == null))
{
throw Fx.AssertAndThrow("extension already exists!");
}
PeerChannelAuthenticatorExtension extension = new PeerChannelAuthenticatorExtension(this, handler, args, this.MeshId);
neighbor.Extensions.Add(extension);
if (neighbor.IsInitiator)
extension.InitiateHandShake();
}
else
{
neighbor.TrySetState(PeerNeighborState.Authenticated);
handler(sender, args);
}
}
public Message ProcessRequest(IPeerNeighbor neighbor, Message request)
{
if (this.authenticationMode != PeerAuthenticationMode.Password || request == null)
{
Abort(neighbor);
return null;
}
PeerChannelAuthenticatorExtension extension = neighbor.Extensions.Find<PeerChannelAuthenticatorExtension>();
Claim claim = FindClaim(ServiceSecurityContext.Current);
if (!(extension != null && claim != null))
{
throw Fx.AssertAndThrow("No suitable claim found in the context to do security negotiation!");
}
return extension.ProcessRst(request, claim);
}
void Abort(IPeerNeighbor neighbor)
{
neighbor.Abort(PeerCloseReason.AuthenticationFailure, PeerCloseInitiator.LocalNode);
}
}
class PeerSecurityCredentialsManager : SecurityCredentialsManager, IEndpointBehavior, IServiceBehavior
{
SecurityTokenManager manager;
PeerCredential credential;
bool messageAuth;
PeerAuthenticationMode mode = PeerAuthenticationMode.Password;
SelfSignedCertificate ssl;
PeerSecurityManager parent;
public PeerSecurityCredentialsManager(SecurityTokenManager manager, PeerAuthenticationMode mode, bool messageAuth)
: base()
{
this.manager = manager;
this.mode = mode;
this.messageAuth = messageAuth;
}
public PeerSecurityCredentialsManager(PeerCredential credential, PeerAuthenticationMode mode, bool messageAuth)
: base()
{
this.credential = credential;
this.mode = mode;
this.messageAuth = messageAuth;
}
public PeerSecurityManager Parent
{
get
{
return this.parent;
}
set
{
parent = value;
}
}
public override SecurityTokenManager CreateSecurityTokenManager()
{
if (manager != null)
return new PeerClientSecurityTokenManager(this.parent, manager, mode, messageAuth);
else
return new PeerClientSecurityTokenManager(this.parent, credential, mode, messageAuth);
}
public PeerSecurityCredentialsManager() : base() { }
public PeerSecurityCredentialsManager CloneForTransport()
{
PeerSecurityCredentialsManager cloner = new PeerSecurityCredentialsManager();
if (this.credential != null)
cloner.credential = new PeerCredential(this.credential);
cloner.mode = this.mode;
cloner.messageAuth = this.messageAuth;
cloner.manager = this.manager;
cloner.parent = parent;
return cloner;
}
internal PeerCredential Credential
{
get
{
return this.credential;
}
}
internal string Password
{
get
{
if (this.credential != null)
return credential.MeshPassword;
ServiceModelSecurityTokenRequirement req = PeerClientSecurityTokenManager.CreateRequirement(SecurityTokenTypes.UserName);
UserNameSecurityTokenProvider tokenProvider = this.manager.CreateSecurityTokenProvider(req) as UserNameSecurityTokenProvider;
if (tokenProvider == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("TokenProvider");
UserNameSecurityToken token = tokenProvider.GetToken(ServiceDefaults.SendTimeout) as UserNameSecurityToken;
if (token == null || String.IsNullOrEmpty(token.Password))
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("password");
return token.Password;
}
}
internal X509Certificate2 Certificate
{
get
{
X509Certificate2 result = null;
if (mode == PeerAuthenticationMode.Password)
{
if (ssl != null)
result = ssl.GetX509Certificate();
}
if (this.credential != null)
{
result = credential.Certificate;
}
else
{
ServiceModelSecurityTokenRequirement req = PeerClientSecurityTokenManager.CreateRequirement(SecurityTokenTypes.X509Certificate);
X509SecurityTokenProvider tokenProvider = this.manager.CreateSecurityTokenProvider(req) as X509SecurityTokenProvider;
if (tokenProvider == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("TokenProvider");
X509SecurityToken token = tokenProvider.GetToken(ServiceDefaults.SendTimeout) as X509SecurityToken;
if (token == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("token");
result = token.Certificate;
}
if (result == null && mode == PeerAuthenticationMode.Password)
{
ssl = this.parent.GetCertificate();
result = ssl.GetX509Certificate();
}
return result;
}
}
void IEndpointBehavior.Validate(ServiceEndpoint serviceEndpoint)
{
}
void IEndpointBehavior.AddBindingParameters(ServiceEndpoint serviceEndpoint, BindingParameterCollection bindingParameters)
{
if (bindingParameters != null)
bindingParameters.Add(this);
}
void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint, EndpointDispatcher endpointDispatcher)
{
}
void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime behavior)
{
}
void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
{
}
void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
{
if (parameters == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parameters");
}
parameters.Add(this);
}
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
{
}
public override bool Equals(object other)
{
PeerSecurityCredentialsManager that = other as PeerSecurityCredentialsManager;
if (that == null)
return false;
if (this.credential != null)
{
return this.credential.Equals(that.credential, mode, messageAuth);
}
else
{
return this.manager.Equals(that.manager);
}
}
public void CheckIfCompatible(PeerSecurityCredentialsManager that)
{
if (that == null)
PeerExceptionHelper.ThrowInvalidOperation_PeerConflictingPeerNodeSettings(PeerBindingPropertyNames.Credentials);
if (this.mode == PeerAuthenticationMode.None)
return;
if (this.mode == PeerAuthenticationMode.Password)
{
if (this.Password != that.Password)
PeerExceptionHelper.ThrowInvalidOperation_PeerConflictingPeerNodeSettings(PeerBindingPropertyNames.Password);
}
if (!this.Certificate.Equals(that.Certificate))
PeerExceptionHelper.ThrowInvalidOperation_PeerConflictingPeerNodeSettings(PeerBindingPropertyNames.Certificate);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public class PeerClientSecurityTokenManager : SecurityTokenManager
{
SecurityTokenManager delegateManager;
PeerCredential credential;
PeerAuthenticationMode mode;
bool messageAuth;
SelfSignedCertificate ssc;
PeerSecurityManager parent;
public PeerClientSecurityTokenManager(PeerSecurityManager parent, PeerCredential credential, PeerAuthenticationMode mode, bool messageAuth)
{
this.credential = credential;
this.mode = mode;
this.messageAuth = messageAuth;
this.parent = parent;
}
public PeerClientSecurityTokenManager(PeerSecurityManager parent, SecurityTokenManager manager, PeerAuthenticationMode mode, bool messageAuth)
{
this.delegateManager = manager;
this.mode = mode;
this.messageAuth = messageAuth;
this.parent = parent;
}
internal static ServiceModelSecurityTokenRequirement CreateRequirement(string tokenType)
{
return CreateRequirement(tokenType, false);
}
internal static ServiceModelSecurityTokenRequirement CreateRequirement(string tokenType, bool forMessageValidation)
{
InitiatorServiceModelSecurityTokenRequirement requirement = new InitiatorServiceModelSecurityTokenRequirement();
requirement.TokenType = tokenType;
requirement.TransportScheme = PeerStrings.Scheme;
if (forMessageValidation)
requirement.Properties[SecurityTokenRequirement.PeerAuthenticationMode] = SecurityMode.Message;
else
requirement.Properties[SecurityTokenRequirement.PeerAuthenticationMode] = SecurityMode.Transport;
return requirement;
}
UserNameSecurityTokenProvider GetPasswordTokenProvider()
{
if (delegateManager != null)
{
ServiceModelSecurityTokenRequirement requirement = CreateRequirement(SecurityTokenTypes.UserName);
UserNameSecurityTokenProvider tokenProvider = delegateManager.CreateSecurityTokenProvider(requirement) as UserNameSecurityTokenProvider;
if (tokenProvider == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SecurityTokenManagerCannotCreateProviderForRequirement, requirement)));
return tokenProvider;
}
else
return new UserNameSecurityTokenProvider(string.Empty, credential.MeshPassword);
}
public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
{
if (delegateManager != null)
return delegateManager.CreateSecurityTokenSerializer(version);
else
{
MessageSecurityTokenVersion wsVersion = version as MessageSecurityTokenVersion;
if (wsVersion != null)
{
return new WSSecurityTokenSerializer(wsVersion.SecurityVersion, wsVersion.TrustVersion, wsVersion.SecureConversationVersion, wsVersion.EmitBspRequiredAttributes, null, null, null);
}
else
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SecurityTokenManagerCannotCreateSerializerForVersion, version)));
}
}
}
public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
{
ServiceModelSecurityTokenRequirement requirement = tokenRequirement as ServiceModelSecurityTokenRequirement;
if (requirement != null)
{
if (IsX509TokenRequirement(requirement))
{
if (IsForConnectionValidator(requirement))
{
SecurityTokenProvider result = null;
if (this.ssc != null)
{
result = new X509SecurityTokenProvider(this.ssc.GetX509Certificate());
}
else
{
if (this.delegateManager != null)
{
requirement.Properties[SecurityTokenRequirement.PeerAuthenticationMode] = SecurityMode.Transport;
requirement.TransportScheme = PeerStrings.Scheme;
result = delegateManager.CreateSecurityTokenProvider(tokenRequirement);
}
else
{
if (this.credential.Certificate != null)
result = new X509SecurityTokenProvider(this.credential.Certificate);
}
}
if (result == null && mode == PeerAuthenticationMode.Password)
{
this.ssc = parent.GetCertificate();
result = new X509SecurityTokenProvider(this.ssc.GetX509Certificate());
}
return result;
}
else
{
X509CertificateValidator validator;
if (this.delegateManager != null)
{
requirement.TransportScheme = PeerStrings.Scheme;
requirement.Properties[SecurityTokenRequirement.PeerAuthenticationMode] = SecurityMode.Message;
return delegateManager.CreateSecurityTokenProvider(tokenRequirement);
}
if (!this.credential.MessageSenderAuthentication.TryGetCertificateValidator(out validator))
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("TokenType");
return new PeerX509TokenProvider(validator, this.credential.Certificate);
}
}
else if (IsPasswordTokenRequirement(requirement))
{
return GetPasswordTokenProvider();
}
else
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("TokenType");
}
}
else
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("tokenRequirement");
}
}
bool IsPasswordTokenRequirement(ServiceModelSecurityTokenRequirement requirement)
{
return ((requirement != null) && (requirement.TokenType == SecurityTokenTypes.UserName));
}
bool IsX509TokenRequirement(ServiceModelSecurityTokenRequirement requirement)
{
return (requirement != null && requirement.TokenType == SecurityTokenTypes.X509Certificate);
}
bool IsForConnectionValidator(ServiceModelSecurityTokenRequirement requirement)
{
return (requirement.TransportScheme == "net.tcp" && requirement.SecurityBindingElement == null && requirement.MessageSecurityVersion == null);
}
public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
{
ServiceModelSecurityTokenRequirement requirement = tokenRequirement as ServiceModelSecurityTokenRequirement;
outOfBandTokenResolver = null;
if (requirement != null)
{
if (IsX509TokenRequirement(requirement))
{
if (mode == PeerAuthenticationMode.Password && IsForConnectionValidator(requirement))
{
return new X509SecurityTokenAuthenticator(X509CertificateValidator.None);
}
if (delegateManager != null)
{
if (IsForConnectionValidator(requirement))
{
requirement.TransportScheme = PeerStrings.Scheme;
requirement.Properties[SecurityTokenRequirement.PeerAuthenticationMode] = SecurityMode.Transport;
}
else
{
requirement.TransportScheme = PeerStrings.Scheme;
requirement.Properties[SecurityTokenRequirement.PeerAuthenticationMode] = SecurityMode.Message;
}
return delegateManager.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
}
else
{
X509CertificateValidator validator = null;
if (IsForConnectionValidator(requirement))
{
if (this.mode == PeerAuthenticationMode.MutualCertificate)
{
if (!this.credential.PeerAuthentication.TryGetCertificateValidator(out validator))
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SecurityTokenManagerCannotCreateProviderForRequirement, requirement)));
}
else
validator = X509CertificateValidator.None;
}
else
{
if (!this.credential.MessageSenderAuthentication.TryGetCertificateValidator(out validator))
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SecurityTokenManagerCannotCreateProviderForRequirement, requirement)));
}
return new X509SecurityTokenAuthenticator(validator);
}
}
else
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("tokenRequirement");
}
}
else
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("tokenRequirement");
}
}
public override bool Equals(object other)
{
PeerClientSecurityTokenManager that = other as PeerClientSecurityTokenManager;
if (that == null)
return false;
if (this.credential != null)
{
if (that.credential == null || !this.credential.Equals(that.credential, this.mode, this.messageAuth))
return false;
return true;
}
else
{
return this.delegateManager.Equals(that.delegateManager);
}
}
internal bool HasCompatibleMessageSecuritySettings(PeerClientSecurityTokenManager that)
{
if (this.credential != null)
return (that.credential != null && this.credential.Equals(that.credential));
else
return this.delegateManager.Equals(that.delegateManager);
}
public override int GetHashCode()
{
if (credential != null)
return credential.GetHashCode();
else if (delegateManager != null)
return delegateManager.GetHashCode();
else
return 0;
}
}
}
}
|