Skip to content

Commit

Permalink
Adding implementation and tests for TransportWithMessageCredential se…
Browse files Browse the repository at this point in the history
…curity mode for NetTcp
  • Loading branch information
mconnew committed May 31, 2019
1 parent 8bb5c47 commit d8724e1
Show file tree
Hide file tree
Showing 20 changed files with 501 additions and 124 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace System.ServiceModel.Channels
{
public abstract class OutputChannel : ChannelBase, IOutputChannel
public abstract class OutputChannel : ChannelBase, IOutputChannel, IAsyncOutputChannel
{
protected OutputChannel(ChannelManagerBase manager)
: base(manager)
Expand Down Expand Up @@ -92,6 +92,30 @@ public void Send(Message message, TimeSpan timeout)
OnSend(message, timeout);
}

public Task SendAsync(Message message)
{
return SendAsync(message, DefaultSendTimeout);
}

public Task SendAsync(Message message, TimeSpan timeout)
{
if (message == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(message));
}

if (timeout < TimeSpan.Zero)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new ArgumentOutOfRangeException(nameof(timeout), timeout, SR.SFxTimeoutOutOfRange0));
}

ThrowIfDisposedOrNotOpen();

AddHeadersTo(message);
EmitTrace(message);
return OnSendAsync(message, timeout);
}

private void EmitTrace(Message message)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,7 @@ static public TransportSecurityBindingElement CreateCertificateOverTransportBind
// reflected in the corresponding IsSecureConversationBinding() method.
static public SecurityBindingElement CreateSecureConversationBindingElement(SecurityBindingElement bootstrapSecurity)
{
throw ExceptionHelper.PlatformNotSupported("SecurityBindingElement.CreateSecureConversatationBindingElement is not supported.");
return CreateSecureConversationBindingElement(bootstrapSecurity, SecureConversationSecurityTokenParameters.defaultRequireCancellation, null);
}

static public SecurityBindingElement CreateSecureConversationBindingElement(SecurityBindingElement bootstrapSecurity, bool requireCancellation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -468,15 +468,7 @@ public async Task<Message> RequestAsync(Message message, TimeSpan timeout)
TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
SecurityProtocolCorrelationState correlationState;
(correlationState, message) = await SecurityProtocol.SecureOutgoingMessageAsync(message, timeoutHelper.RemainingTime(), null);
Message reply;
if (InnerChannel is IAsyncRequestChannel asyncRequestChannel)
{
reply = await asyncRequestChannel.RequestAsync(message, timeoutHelper.RemainingTime());
}
else
{
reply = await Task.Factory.FromAsync(InnerChannel.BeginRequest, InnerChannel.EndRequest, message, timeoutHelper.RemainingTime(), null);
}
Message reply = await Task.Factory.FromAsync(InnerChannel.BeginRequest, InnerChannel.EndRequest, message, timeoutHelper.RemainingTime(), null);

return ProcessReply(reply, correlationState, timeoutHelper.RemainingTime());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,26 @@
// See the LICENSE file in the project root for more information.


using System.Security.Authentication.ExtendedProtection;

namespace System.ServiceModel.Channels
{
public class TcpTransportBindingElement : ConnectionOrientedTransportBindingElement
{
ExtendedProtectionPolicy _extendedProtectionPolicy;

public TcpTransportBindingElement()
: base()
{
ConnectionPoolSettings = new TcpConnectionPoolSettings();
_extendedProtectionPolicy = ChannelBindingUtility.DefaultPolicy;
}

protected TcpTransportBindingElement(TcpTransportBindingElement elementToBeCloned)
: base(elementToBeCloned)
{
ConnectionPoolSettings = elementToBeCloned.ConnectionPoolSettings.Clone();
_extendedProtectionPolicy = elementToBeCloned._extendedProtectionPolicy;
}

public TcpConnectionPoolSettings ConnectionPoolSettings { get; }
Expand All @@ -26,6 +32,30 @@ public override string Scheme
get { return "net.tcp"; }
}

public ExtendedProtectionPolicy ExtendedProtectionPolicy
{
get
{
return _extendedProtectionPolicy;
}
set
{
if (value == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(value));
}

if (value.PolicyEnforcement == PolicyEnforcement.Always &&
!ExtendedProtectionPolicy.OSSupportsExtendedProtection)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new PlatformNotSupportedException(SR.ExtendedProtectionNotSupported));
}

_extendedProtectionPolicy = value;
}
}

public override BindingElement Clone()
{
return new TcpTransportBindingElement(this);
Expand Down Expand Up @@ -56,7 +86,10 @@ public override T GetProperty<T>(BindingContext context)
{
return (T)(object)new BindingDeliveryCapabilitiesHelper();
}

else if (typeof(T) == typeof(ExtendedProtectionPolicy))
{
return (T)(object)ExtendedProtectionPolicy;
}
else if (typeof(T) == typeof(ITransportCompressionSupport))
{
return (T)(object)new TransportCompressionSupportHelper();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

namespace System.ServiceModel.Channels
{
public abstract class TransportDuplexSessionChannel : TransportOutputChannel, IDuplexSessionChannel
public abstract class TransportDuplexSessionChannel : TransportOutputChannel, IDuplexSessionChannel, IAsyncDuplexSessionChannel
{
private bool _isInputSessionClosed;
private bool _isOutputSessionClosed;
Expand Down Expand Up @@ -52,6 +52,8 @@ protected TransportDuplexSessionChannel(

protected abstract bool IsStreamedOutput { get; }

IAsyncDuplexSession ISessionChannel<IAsyncDuplexSession>.Session => Session as IAsyncDuplexSession;

public Message Receive()
{
return Receive(DefaultReceiveTimeout);
Expand Down Expand Up @@ -88,6 +90,11 @@ public Message Receive(TimeSpan timeout)
}
}

public Task<Message> ReceiveAsync()
{
return ReceiveAsync(DefaultReceiveTimeout);
}

public async Task<Message> ReceiveAsync(TimeSpan timeout)
{
Message message = null;
Expand All @@ -111,7 +118,6 @@ public async Task<Message> ReceiveAsync(TimeSpan timeout)
if (message != null)
{
message.Close();
message = null;
}

Fault();
Expand Down Expand Up @@ -159,6 +165,23 @@ public bool EndTryReceive(IAsyncResult result, out Message message)
}
}

public async Task<(bool, Message)> TryReceiveAsync(TimeSpan timeout)
{
try
{
return (true, await ReceiveAsync(timeout));
}
catch(TimeoutException e)
{
if (WcfEventSource.Instance.ReceiveTimeoutIsEnabled())
{
WcfEventSource.Instance.ReceiveTimeout(e.Message);
}

return (false, null);
}
}

public bool TryReceive(TimeSpan timeout, out Message message)
{
try
Expand Down Expand Up @@ -694,7 +717,7 @@ private void OnOutputSessionClosed(ref TimeoutHelper timeoutHelper)
}
}

public class ConnectionDuplexSession : IDuplexSession
public class ConnectionDuplexSession : IDuplexSession, IAsyncDuplexSession
{
private static UriGenerator s_uriGenerator;
private string _id;
Expand Down Expand Up @@ -763,6 +786,16 @@ public void CloseOutputSession(TimeSpan timeout)
{
Channel.CloseOutputSession(timeout);
}

public Task CloseOutputSessionAsync()
{
return CloseOutputSessionAsync(Channel.DefaultCloseTimeout);
}

public Task CloseOutputSessionAsync(TimeSpan timeout)
{
return Channel.CloseOutputSessionAsync(timeout);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,35 @@


using System.ComponentModel;
using System.Runtime;
using System.Runtime.CompilerServices;
using System.ServiceModel.Channels;
using System.ServiceModel.Security;

namespace System.ServiceModel
{
public sealed class MessageSecurityOverTcp
{
internal const MessageCredentialType DefaultClientCredentialType = MessageCredentialType.Windows;
private MessageCredentialType _messageCredentialType;
private MessageCredentialType _clientCredentialType;
private SecurityAlgorithmSuite _algorithmSuite;

public MessageSecurityOverTcp()
{
_messageCredentialType = DefaultClientCredentialType;
_clientCredentialType = DefaultClientCredentialType;
_algorithmSuite = SecurityAlgorithmSuite.Default;
}

[DefaultValue(MessageSecurityOverTcp.DefaultClientCredentialType)]
[DefaultValue(DefaultClientCredentialType)]
public MessageCredentialType ClientCredentialType
{
get
{
if (_messageCredentialType != MessageCredentialType.None)
{
throw ExceptionHelper.PlatformNotSupported("MessageSecurityOverTcp.ClientCredentialType is not supported for values other than 'MessageCredentialType.None'.");
}
else
get {
if (_clientCredentialType == MessageCredentialType.IssuedToken || _clientCredentialType == MessageCredentialType.Windows)
{
return _messageCredentialType;
throw ExceptionHelper.PlatformNotSupported($"MessageSecurityOverTcp.ClientCredentialType is not supported for value {_clientCredentialType}.");
}

return _clientCredentialType;
}
set
{
Expand All @@ -39,20 +41,75 @@ public MessageCredentialType ClientCredentialType
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(value)));
}

if (value != MessageCredentialType.None)
if (value == MessageCredentialType.IssuedToken || value == MessageCredentialType.Windows)
{
throw ExceptionHelper.PlatformNotSupported("MessageSecurityOverTcp.ClientCredentialType is not supported for values other than 'MessageCredentialType.None'.");
}
else
{
_messageCredentialType = value;
throw ExceptionHelper.PlatformNotSupported($"MessageSecurityOverTcp.ClientCredentialType is not supported for value {value}.");
}

_clientCredentialType = value;
}
}

internal bool InternalShouldSerialize()
[DefaultValue(typeof(SecurityAlgorithmSuite), nameof(SecurityAlgorithmSuite.Default))]
public SecurityAlgorithmSuite AlgorithmSuite
{
return ClientCredentialType != NetTcpDefaults.MessageSecurityClientCredentialType;
get { return _algorithmSuite; }
set
{
_algorithmSuite = value ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(value));
}
}

[MethodImpl(MethodImplOptions.NoInlining)]
internal SecurityBindingElement CreateSecurityBindingElement(bool isSecureTransportMode, bool isReliableSession, BindingElement transportBindingElement)
{
SecurityBindingElement result;
SecurityBindingElement oneShotSecurity;
if (isSecureTransportMode)
{
switch (_clientCredentialType)
{
case MessageCredentialType.None:
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.ClientCredentialTypeMustBeSpecifiedForMixedMode));
case MessageCredentialType.UserName:
oneShotSecurity = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
break;
case MessageCredentialType.Certificate:
oneShotSecurity = SecurityBindingElement.CreateCertificateOverTransportBindingElement();
break;
case MessageCredentialType.Windows:
throw ExceptionHelper.PlatformNotSupported($"{nameof(MessageCredentialType)}.{nameof(MessageCredentialType.Windows)}");
case MessageCredentialType.IssuedToken:
throw ExceptionHelper.PlatformNotSupported($"{nameof(MessageCredentialType)}.{nameof(MessageCredentialType.IssuedToken)}");
default:
Fx.Assert("unknown ClientCredentialType");
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
}
result = SecurityBindingElement.CreateSecureConversationBindingElement(oneShotSecurity);
}
else
{
throw ExceptionHelper.PlatformNotSupported();
}

// set the algorithm suite and issued token params if required
result.DefaultAlgorithmSuite = oneShotSecurity.DefaultAlgorithmSuite = this.AlgorithmSuite;

result.IncludeTimestamp = true;
if (!isReliableSession)
{
result.LocalClientSettings.ReconnectTransportOnFailure = false;
}
else
{
throw ExceptionHelper.PlatformNotSupported();
}

// since a session is always bootstrapped, configure the transition sct to live for a short time only
result.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11;
oneShotSecurity.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11;

return result;
}
}
}
Loading

0 comments on commit d8724e1

Please sign in to comment.