Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding implementation and tests for TransportWithMessageCredential seccurity mode for NetTcp #3657

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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