From 5c5c18f2e8c62b72c9c379b6ce7916d9db4a7071 Mon Sep 17 00:00:00 2001 From: Matt Connew Date: Wed, 15 May 2019 16:03:30 -0700 Subject: [PATCH] Adding implementation and tests for TransportWithMessageCredential security mode for NetTcp --- .../ServiceModel/Channels/OutputChannel.cs | 26 +++- .../Channels/SecurityBindingElement.cs | 2 +- .../Channels/SecurityChannelFactory.cs | 10 +- .../Channels/TcpTransportBindingElement.cs | 35 +++++- .../Channels/TransportDuplexSessionChannel.cs | 39 +++++- .../ServiceModel/MessageSecurityOverTcp.cs | 95 ++++++++++++--- .../ServiceModel/MessageSecurityVersion.cs | 12 +- .../src/System/ServiceModel/NetTcpBinding.cs | 32 ++--- .../src/System/ServiceModel/NetTcpSecurity.cs | 35 ++---- .../SecuritySessionSecurityTokenProvider.cs | 22 +++- .../ServiceModel/TcpTransportSecurity.cs | 69 +++++++---- .../tests/Common/Scenarios/Endpoints.cs | 12 ++ ...sportWithMessageCredentialSecurityTests.cs | 4 - ...sportWithMessageCredentialSecurityTests.cs | 111 ++++++++++++++++++ ...tyMessageCredentialsCertTestServiceHost.cs | 52 ++++++++ ...ssageCredentialsUsernameTestServiceHost.cs | 50 ++++++++ .../tools/IISHostedWcfService/Web.config | 2 + .../tools/SelfHostedWcfService/Program.cs | 2 + .../SelfHostedWCFService.sln | 11 +- .../MessageSecurityOverTcpTest.cs | 4 +- 20 files changed, 501 insertions(+), 124 deletions(-) create mode 100644 src/System.Private.ServiceModel/tests/Scenarios/Binding/WS/TransportWithMessageCredentialSecurity/WSNetTcpTransportWithMessageCredentialSecurityTests.cs create mode 100644 src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/testhosts/TcpTransportSecurityMessageCredentialsCertTestServiceHost.cs create mode 100644 src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/testhosts/TcpTransportSecurityMessageCredentialsUsernameTestServiceHost.cs diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/OutputChannel.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/OutputChannel.cs index bfd4ca39e52..31038e133e4 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/OutputChannel.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/OutputChannel.cs @@ -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) @@ -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) { diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/SecurityBindingElement.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/SecurityBindingElement.cs index c1bf8ede676..c34474ff849 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/SecurityBindingElement.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/SecurityBindingElement.cs @@ -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) diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/SecurityChannelFactory.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/SecurityChannelFactory.cs index f4c6f468bf1..235f049ca6b 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/SecurityChannelFactory.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/SecurityChannelFactory.cs @@ -468,15 +468,7 @@ public async Task 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()); } diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/TcpTransportBindingElement.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/TcpTransportBindingElement.cs index 41d63bc2e42..67804bfcff6 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/TcpTransportBindingElement.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/TcpTransportBindingElement.cs @@ -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; } @@ -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); @@ -56,7 +86,10 @@ public override T GetProperty(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(); diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/TransportDuplexSessionChannel.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/TransportDuplexSessionChannel.cs index bfcfbab8473..348f54bbcdc 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/TransportDuplexSessionChannel.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/TransportDuplexSessionChannel.cs @@ -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; @@ -52,6 +52,8 @@ protected TransportDuplexSessionChannel( protected abstract bool IsStreamedOutput { get; } + IAsyncDuplexSession ISessionChannel.Session => Session as IAsyncDuplexSession; + public Message Receive() { return Receive(DefaultReceiveTimeout); @@ -88,6 +90,11 @@ public Message Receive(TimeSpan timeout) } } + public Task ReceiveAsync() + { + return ReceiveAsync(DefaultReceiveTimeout); + } + public async Task ReceiveAsync(TimeSpan timeout) { Message message = null; @@ -111,7 +118,6 @@ public async Task ReceiveAsync(TimeSpan timeout) if (message != null) { message.Close(); - message = null; } Fault(); @@ -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 @@ -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; @@ -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); + } } } } diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/MessageSecurityOverTcp.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/MessageSecurityOverTcp.cs index 800f50b2def..9a3ed740360 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/MessageSecurityOverTcp.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/MessageSecurityOverTcp.cs @@ -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 { @@ -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; } } } diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/MessageSecurityVersion.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/MessageSecurityVersion.cs index f6af39134da..ca49649b057 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/MessageSecurityVersion.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/MessageSecurityVersion.cs @@ -133,7 +133,7 @@ public override SecurityPolicyVersion SecurityPolicyVersion public override string ToString() { - return "WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11"; + return nameof(WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11); } } @@ -158,7 +158,7 @@ public override SecurityPolicyVersion SecurityPolicyVersion public override string ToString() { - return "WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"; + return nameof(WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10); } } @@ -183,7 +183,7 @@ internal override MessageSecurityTokenVersion MessageSecurityTokenVersion public override string ToString() { - return "WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"; + return nameof(WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10); } } @@ -208,7 +208,7 @@ internal override MessageSecurityTokenVersion MessageSecurityTokenVersion public override string ToString() { - return "WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10"; + return nameof(WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10); } } @@ -233,7 +233,7 @@ internal override MessageSecurityTokenVersion MessageSecurityTokenVersion public override string ToString() { - return "WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12"; + return nameof(WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12); } } @@ -258,7 +258,7 @@ internal override MessageSecurityTokenVersion MessageSecurityTokenVersion public override string ToString() { - return "WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10"; + return nameof(WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10); } } } diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/NetTcpBinding.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/NetTcpBinding.cs index ea66a979d81..73a34f548e1 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/NetTcpBinding.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/NetTcpBinding.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. - using System.ComponentModel; using System.ServiceModel.Channels; using System.Xml; @@ -23,24 +22,15 @@ public NetTcpBinding(SecurityMode securityMode) _security.Mode = securityMode; } - public NetTcpBinding(string configurationName) : this() { - if (!String.IsNullOrEmpty(configurationName)) + if (!string.IsNullOrEmpty(configurationName)) { throw ExceptionHelper.PlatformNotSupported(); } } - private NetTcpBinding(TcpTransportBindingElement transport, - BinaryMessageEncodingBindingElement encoding, - NetTcpSecurity security) - : this() - { - _security = security; - } - [DefaultValue(ConnectionOrientedTransportDefaults.TransferMode)] public TransferMode TransferMode { @@ -148,7 +138,7 @@ public override BindingElementCollection CreateBindingElements() { bindingElements.Add(transportSecurity); } - + _transport.ExtendedProtectionPolicy = _security.Transport.ExtendedProtectionPolicy; // add transport (tcp) bindingElements.Add(_transport); @@ -160,21 +150,15 @@ private BindingElement CreateTransportSecurity() return _security.CreateTransportSecurity(); } - private static UnifiedSecurityMode GetModeFromTransportSecurity(BindingElement transport) - { - return NetTcpSecurity.GetModeFromTransportSecurity(transport); - } - - private static bool SetTransportSecurity(BindingElement transport, SecurityMode mode, TcpTransportSecurity transportSecurity) - { - return NetTcpSecurity.SetTransportSecurity(transport, mode, transportSecurity); - } - private SecurityBindingElement CreateMessageSecurity() { - if (_security.Mode == SecurityMode.Message || _security.Mode == SecurityMode.TransportWithMessageCredential) + if (_security.Mode == SecurityMode.Message) + { + throw ExceptionHelper.PlatformNotSupported(nameof(SecurityMode.Message)); + } + if (_security.Mode == SecurityMode.TransportWithMessageCredential) { - throw ExceptionHelper.PlatformNotSupported("NetTcpBinding.CreateMessageSecurity is not supported."); + return _security.CreateMessageSecurity(false); } else { diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/NetTcpSecurity.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/NetTcpSecurity.cs index 461efe890c8..f10ebc3e445 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/NetTcpSecurity.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/NetTcpSecurity.cs @@ -14,7 +14,6 @@ public sealed class NetTcpSecurity internal const SecurityMode DefaultMode = SecurityMode.Transport; private SecurityMode _mode; - private MessageSecurityOverTcp _messageSecurity; public NetTcpSecurity() : this(DefaultMode, new TcpTransportSecurity(), new MessageSecurityOverTcp()) @@ -31,8 +30,8 @@ private NetTcpSecurity(SecurityMode mode, TcpTransportSecurity transportSecurity SecurityMode.Transport.ToString())); _mode = mode; - Transport = transportSecurity == null ? new TcpTransportSecurity() : transportSecurity; - _messageSecurity = messageSecurity == null ? new MessageSecurityOverTcp() : messageSecurity; + Transport = transportSecurity ?? new TcpTransportSecurity(); + Message = messageSecurity ?? new MessageSecurityOverTcp(); } [DefaultValue(DefaultMode)] @@ -51,12 +50,7 @@ public SecurityMode Mode public TcpTransportSecurity Transport { get; set; } - public MessageSecurityOverTcp Message - { - get { return _messageSecurity; } - set { _messageSecurity = value; } - } - + public MessageSecurityOverTcp Message { get; set; } internal BindingElement CreateTransportSecurity() { @@ -74,29 +68,20 @@ internal BindingElement CreateTransportSecurity() } } - internal static UnifiedSecurityMode GetModeFromTransportSecurity(BindingElement transport) + internal SecurityBindingElement CreateMessageSecurity(bool isReliableSessionEnabled) { - if (transport == null) + if (_mode == SecurityMode.Message) { - return UnifiedSecurityMode.None | UnifiedSecurityMode.Message; + throw ExceptionHelper.PlatformNotSupported(); } - else + else if (_mode == SecurityMode.TransportWithMessageCredential) { - return UnifiedSecurityMode.TransportWithMessageCredential | UnifiedSecurityMode.Transport; + return Message.CreateSecurityBindingElement(true, isReliableSessionEnabled, CreateTransportSecurity()); } - } - - internal static bool SetTransportSecurity(BindingElement transport, SecurityMode mode, TcpTransportSecurity transportSecurity) - { - if (mode == SecurityMode.TransportWithMessageCredential) - { - return TcpTransportSecurity.SetTransportProtectionOnly(transport, transportSecurity); - } - else if (mode == SecurityMode.Transport) + else { - return TcpTransportSecurity.SetTransportProtectionAndAuthentication(transport, transportSecurity); + return null; } - return transport == null; } } } diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/Security/SecuritySessionSecurityTokenProvider.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/Security/SecuritySessionSecurityTokenProvider.cs index 09dc4ac0b92..9e014de530c 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/Security/SecuritySessionSecurityTokenProvider.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/Security/SecuritySessionSecurityTokenProvider.cs @@ -750,7 +750,7 @@ protected void ValidateKeySize(GenericXmlSecurityToken issuedToken) } } - internal class RequestChannelFactory : ChannelFactoryBase + internal class RequestChannelFactory : ChannelFactoryBase, IChannelFactory { private ServiceChannelFactory _serviceChannelFactory; @@ -764,6 +764,11 @@ protected override IAsyncRequestChannel OnCreateChannel(EndpointAddress address, return _serviceChannelFactory.CreateChannel(address, via); } + protected internal override Task OnOpenAsync(TimeSpan timeout) + { + return _serviceChannelFactory.OpenHelperAsync(timeout); + } + protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state) { return _serviceChannelFactory.BeginOpen(timeout, callback, state); @@ -774,6 +779,11 @@ protected override void OnEndOpen(IAsyncResult result) _serviceChannelFactory.EndOpen(result); } + protected internal override Task OnCloseAsync(TimeSpan timeout) + { + return _serviceChannelFactory.CloseHelperAsync(timeout); + } + protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state) { return new ChainedCloseAsyncResult(timeout, callback, state, base.OnBeginClose, base.OnEndClose, _serviceChannelFactory); @@ -805,6 +815,16 @@ public override T GetProperty() { return _serviceChannelFactory.GetProperty(); } + + IRequestChannel IChannelFactory.CreateChannel(EndpointAddress to) + { + return CreateChannel(to); + } + + IRequestChannel IChannelFactory.CreateChannel(EndpointAddress to, Uri via) + { + return CreateChannel(to, via); + } } } } diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/TcpTransportSecurity.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/TcpTransportSecurity.cs index 640617f8caf..1d74beaf4db 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/TcpTransportSecurity.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/TcpTransportSecurity.cs @@ -6,6 +6,7 @@ using System.ComponentModel; using System.Net.Security; using System.Security.Authentication; +using System.Security.Authentication.ExtendedProtection; using System.ServiceModel.Channels; using System.ServiceModel.Security; @@ -18,12 +19,14 @@ public sealed class TcpTransportSecurity private TcpClientCredentialType _clientCredentialType; private ProtectionLevel _protectionLevel; + private ExtendedProtectionPolicy _extendedProtectionPolicy; private SslProtocols _sslProtocols; public TcpTransportSecurity() { _clientCredentialType = DefaultClientCredentialType; _protectionLevel = DefaultProtectionLevel; + _extendedProtectionPolicy = ChannelBindingUtility.DefaultPolicy; _sslProtocols = TransportDefaults.SslProtocols; } @@ -41,6 +44,44 @@ public TcpClientCredentialType ClientCredentialType } } + [DefaultValue(DefaultProtectionLevel)] + public ProtectionLevel ProtectionLevel + { + get { return _protectionLevel; } + set + { + if (!ProtectionLevelHelper.IsDefined(value)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(value))); + } + + _protectionLevel = value; + } + } + + 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; + } + } + [DefaultValue(TransportDefaults.SslProtocols)] public SslProtocols SslProtocols { @@ -66,29 +107,26 @@ private SslStreamSecurityBindingElement CreateSslBindingElement(bool requireClie return result; } - private static bool IsSslBindingElement(BindingElement element, TcpTransportSecurity transportSecurity, out bool requireClientCertificate) + private static bool IsSslBindingElement(BindingElement element, TcpTransportSecurity transportSecurity) { - requireClientCertificate = false; SslStreamSecurityBindingElement ssl = element as SslStreamSecurityBindingElement; if (ssl == null) { return false; } - transportSecurity._protectionLevel = ProtectionLevel.EncryptAndSign; - requireClientCertificate = ssl.RequireClientCertificate; + transportSecurity.ProtectionLevel = ProtectionLevel.EncryptAndSign; return true; } internal BindingElement CreateTransportProtectionOnly() { - throw ExceptionHelper.PlatformNotSupported("TcpTransportSecurity.CreateTransportProtectionOnly is not supported."); + return CreateSslBindingElement(false); } internal static bool SetTransportProtectionOnly(BindingElement transport, TcpTransportSecurity transportSecurity) { - bool requireClientCertificate; - return IsSslBindingElement(transport, transportSecurity, out requireClientCertificate); + return IsSslBindingElement(transport, transportSecurity); } internal BindingElement CreateTransportProtectionAndAuthentication() @@ -105,23 +143,6 @@ internal BindingElement CreateTransportProtectionAndAuthentication() } } - internal static bool SetTransportProtectionAndAuthentication(BindingElement transport, TcpTransportSecurity transportSecurity) - { - bool requireClientCertificate = false; - if (transport is WindowsStreamSecurityBindingElement) - { - transportSecurity.ClientCredentialType = TcpClientCredentialType.Windows; - transportSecurity._protectionLevel = ((WindowsStreamSecurityBindingElement)transport).ProtectionLevel; - return true; - } - else if (IsSslBindingElement(transport, transportSecurity, out requireClientCertificate)) - { - transportSecurity.ClientCredentialType = requireClientCertificate ? TcpClientCredentialType.Certificate : TcpClientCredentialType.None; - return true; - } - return false; - } - internal bool InternalShouldSerialize() { return ClientCredentialType != TcpTransportSecurity.DefaultClientCredentialType diff --git a/src/System.Private.ServiceModel/tests/Common/Scenarios/Endpoints.cs b/src/System.Private.ServiceModel/tests/Common/Scenarios/Endpoints.cs index c6fa3d05140..c5f1767131f 100644 --- a/src/System.Private.ServiceModel/tests/Common/Scenarios/Endpoints.cs +++ b/src/System.Private.ServiceModel/tests/Common/Scenarios/Endpoints.cs @@ -670,6 +670,18 @@ public static string TcpSoap11WSA10_Address get { return GetEndpointAddress("TcpSoap11WSA10.svc/tcp-Soap11WSA10", protocol: "net.tcp"); } } + public static string Tcp_SecModeTransWithMessCred_ClientCredTypeCert + { + get { return GetEndpointAddress("TcpTransSecMessCredsCert.svc//tcp-message-credentials-cert", protocol: "net.tcp"); } + } + + public static string Tcp_SecModeTransWithMessCred_ClientCredTypeUserName + { + get + { + return GetEndpointAddress("TcpTransSecMessCredsUserName.svc//tcp-message-credentials-username", protocol: "net.tcp"); + } + } #endregion net.tcp Addresses } diff --git a/src/System.Private.ServiceModel/tests/Scenarios/Binding/WS/TransportWithMessageCredentialSecurity/BasicHttpTransportWithMessageCredentialSecurityTests.cs b/src/System.Private.ServiceModel/tests/Scenarios/Binding/WS/TransportWithMessageCredentialSecurity/BasicHttpTransportWithMessageCredentialSecurityTests.cs index f6977e176ee..56dc3cd8841 100644 --- a/src/System.Private.ServiceModel/tests/Scenarios/Binding/WS/TransportWithMessageCredentialSecurity/BasicHttpTransportWithMessageCredentialSecurityTests.cs +++ b/src/System.Private.ServiceModel/tests/Scenarios/Binding/WS/TransportWithMessageCredentialSecurity/BasicHttpTransportWithMessageCredentialSecurityTests.cs @@ -1,10 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Security.Cryptography.X509Certificates; using System.ServiceModel; -using System.Text; -using System.Threading.Tasks; using Infrastructure.Common; using Xunit; diff --git a/src/System.Private.ServiceModel/tests/Scenarios/Binding/WS/TransportWithMessageCredentialSecurity/WSNetTcpTransportWithMessageCredentialSecurityTests.cs b/src/System.Private.ServiceModel/tests/Scenarios/Binding/WS/TransportWithMessageCredentialSecurity/WSNetTcpTransportWithMessageCredentialSecurityTests.cs new file mode 100644 index 00000000000..3e067f404c6 --- /dev/null +++ b/src/System.Private.ServiceModel/tests/Scenarios/Binding/WS/TransportWithMessageCredentialSecurity/WSNetTcpTransportWithMessageCredentialSecurityTests.cs @@ -0,0 +1,111 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Security.Cryptography.X509Certificates; +using System.ServiceModel; +using System.ServiceModel.Channels; +using System.ServiceModel.Security; +using Infrastructure.Common; +using Xunit; + +public class WSNetTcpTransportWithMessageCredentialSecurityTests : ConditionalWcfTest +{ + [WcfFact] + [Issue(2870, OS = OSID.AnyOSX)] + [Condition(nameof(Root_Certificate_Installed), + nameof(Client_Certificate_Installed), + nameof(SSL_Available))] + [OuterLoop] + public static void NetTcp_SecModeTransWithMessCred_CertClientCredential_Succeeds() + { + string clientCertThumb = null; + EndpointAddress endpointAddress = null; + string testString = "Hello"; + ChannelFactory factory = null; + IWcfService serviceProxy = null; + + try + { + // *** SETUP *** \\ + NetTcpBinding binding = new NetTcpBinding(SecurityMode.TransportWithMessageCredential); + binding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate; + endpointAddress = new EndpointAddress(new Uri(Endpoints.Tcp_SecModeTransWithMessCred_ClientCredTypeCert)); + clientCertThumb = ServiceUtilHelper.ClientCertificate.Thumbprint; + + factory = new ChannelFactory(binding, endpointAddress); + factory.Credentials.ClientCertificate.SetCertificate( + StoreLocation.CurrentUser, + StoreName.My, + X509FindType.FindByThumbprint, + clientCertThumb); + + serviceProxy = factory.CreateChannel(); + + // *** EXECUTE *** \\ + string result = serviceProxy.Echo(testString); + + // *** VALIDATE *** \\ + Assert.Equal(testString, result); + + // *** CLEANUP *** \\ + ((ICommunicationObject)serviceProxy).Close(); + factory.Close(); + } + finally + { + // *** ENSURE CLEANUP *** \\ + ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); + } + } + + [WcfFact] + [Issue(2870, OS = OSID.AnyOSX)] + [Condition(nameof(Root_Certificate_Installed), + nameof(SSL_Available))] + [OuterLoop] + public static void NetTcp_SecModeTransWithMessCred_UserNameClientCredential_Succeeds() + { + string testString = "Hello"; + string result = null; + string username = null; + string password = null; + EndpointAddress endpointAddress = null; + ChannelFactory factory = null; + IWcfService serviceProxy = null; + + try + { + // *** SETUP *** \\ + NetTcpBinding binding = new NetTcpBinding(SecurityMode.TransportWithMessageCredential); + binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName; + endpointAddress = new EndpointAddress(new Uri(Endpoints.Tcp_SecModeTransWithMessCred_ClientCredTypeUserName)); + + factory = new ChannelFactory(binding, endpointAddress); + username = Guid.NewGuid().ToString("n").Substring(0, 8); + char[] usernameArr = username.ToCharArray(); + Array.Reverse(usernameArr); + password = new string(usernameArr); + factory.Credentials.UserName.UserName = username; + factory.Credentials.UserName.Password = password; + + serviceProxy = factory.CreateChannel(); + + // *** EXECUTE *** \\ + result = serviceProxy.Echo(testString); + + // *** VALIDATE *** \\ + Assert.Equal(testString, result); + + // *** CLEANUP *** \\ + ((ICommunicationObject)serviceProxy).Close(); + factory.Close(); + } + finally + { + // *** ENSURE CLEANUP *** \\ + ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory); + } + } +} diff --git a/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/testhosts/TcpTransportSecurityMessageCredentialsCertTestServiceHost.cs b/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/testhosts/TcpTransportSecurityMessageCredentialsCertTestServiceHost.cs new file mode 100644 index 00000000000..ad782cf99a3 --- /dev/null +++ b/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/testhosts/TcpTransportSecurityMessageCredentialsCertTestServiceHost.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Security.Cryptography.X509Certificates; +using System.ServiceModel; +using System.ServiceModel.Activation; +using System.ServiceModel.Channels; +using System.ServiceModel.Security; + +namespace WcfService +{ + public class TcpTransportSecurityMessageCredentialsCertTestServiceHostFactory : ServiceHostFactory + { + protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) + { + TcpTransportSecurityMessageCredentialsCertTestServiceHost serviceHost = new TcpTransportSecurityMessageCredentialsCertTestServiceHost(serviceType, baseAddresses); + return serviceHost; + } + } + + internal class TcpTransportSecurityMessageCredentialsCertTestServiceHost : TestServiceHostBase + { + protected override string Address { get { return "tcp-message-credentials-cert"; } } + + protected override Binding GetBinding() + { + NetTcpBinding binding = new NetTcpBinding(SecurityMode.TransportWithMessageCredential); + binding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate; + + return binding; + } + + protected override void ApplyConfiguration() + { + base.ApplyConfiguration(); + this.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.Custom; + this.Credentials.ClientCertificate.Authentication.CustomCertificateValidator = new MyX509CertificateValidator("DO_NOT_TRUST_WcfBridgeRootCA"); + + string thumbprint = TestHost.CertificateFromFriendlyName(StoreName.My, StoreLocation.LocalMachine, "WCF Bridge - Machine certificate generated by the CertificateManager").Thumbprint; + this.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, + StoreName.My, + X509FindType.FindByThumbprint, + thumbprint); + } + + public TcpTransportSecurityMessageCredentialsCertTestServiceHost(Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses) + { + } + } +} diff --git a/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/testhosts/TcpTransportSecurityMessageCredentialsUsernameTestServiceHost.cs b/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/testhosts/TcpTransportSecurityMessageCredentialsUsernameTestServiceHost.cs new file mode 100644 index 00000000000..2c32361c4d3 --- /dev/null +++ b/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/testhosts/TcpTransportSecurityMessageCredentialsUsernameTestServiceHost.cs @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Security.Cryptography.X509Certificates; +using System.ServiceModel; +using System.ServiceModel.Activation; +using System.ServiceModel.Channels; + +namespace WcfService +{ + public class TcpTransportSecurityMessageCredentialsUserNameTestServiceHostFactory : ServiceHostFactory + { + protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) + { + TcpTransportSecurityMessageCredentialsUserNameTestServiceHost serviceHost = new TcpTransportSecurityMessageCredentialsUserNameTestServiceHost(serviceType, baseAddresses); + return serviceHost; + } + } + + internal class TcpTransportSecurityMessageCredentialsUserNameTestServiceHost : TestServiceHostBase + { + protected override string Address { get { return "Tcp-message-credentials-username"; } } + + protected override Binding GetBinding() + { + NetTcpBinding binding = new NetTcpBinding(SecurityMode.TransportWithMessageCredential); + binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName; + + return binding; + } + + protected override void ApplyConfiguration() + { + base.ApplyConfiguration(); + AuthenticationResourceHelper.ConfigureServiceHostUserNameAuth(this); + + string thumbprint = TestHost.CertificateFromFriendlyName(StoreName.My, StoreLocation.LocalMachine, "WCF Bridge - Machine certificate generated by the CertificateManager").Thumbprint; + this.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, + StoreName.My, + X509FindType.FindByThumbprint, + thumbprint); + } + + public TcpTransportSecurityMessageCredentialsUserNameTestServiceHost(Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses) + { + } + } +} diff --git a/src/System.Private.ServiceModel/tools/IISHostedWcfService/Web.config b/src/System.Private.ServiceModel/tools/IISHostedWcfService/Web.config index 66176c1e9ce..9f24ec9314b 100644 --- a/src/System.Private.ServiceModel/tools/IISHostedWcfService/Web.config +++ b/src/System.Private.ServiceModel/tools/IISHostedWcfService/Web.config @@ -116,6 +116,8 @@ + + diff --git a/src/System.Private.ServiceModel/tools/SelfHostedWcfService/Program.cs b/src/System.Private.ServiceModel/tools/SelfHostedWcfService/Program.cs index d3868c98844..fcbf9e93b6c 100644 --- a/src/System.Private.ServiceModel/tools/SelfHostedWcfService/Program.cs +++ b/src/System.Private.ServiceModel/tools/SelfHostedWcfService/Program.cs @@ -105,6 +105,8 @@ private static void Main() CreateHost("SessionTestsShortTimeoutService.svc", tcpBaseAddress); CreateHost("SessionTestsDuplexService.svc", tcpBaseAddress); CreateHost("TcpSoap11WSA10.svc", tcpBaseAddress); + CreateHost("TcpTransSecMessCredsCert.svc", tcpBaseAddress); + CreateHost("TcpTransSecMessCredsUserName.svc", tcpBaseAddress); CreateHost("DuplexWebSocket.svc", websocketBaseAddress); CreateHost("WebSocketTransport.svc", websocketBaseAddress); CreateHost("WebSocketHttpDuplexBinaryStreamed.svc", websocketBaseAddress); diff --git a/src/System.Private.ServiceModel/tools/SelfHostedWcfService/SelfHostedWCFService.sln b/src/System.Private.ServiceModel/tools/SelfHostedWcfService/SelfHostedWCFService.sln index d2aeed971d1..44236df8c0f 100644 --- a/src/System.Private.ServiceModel/tools/SelfHostedWcfService/SelfHostedWCFService.sln +++ b/src/System.Private.ServiceModel/tools/SelfHostedWcfService/SelfHostedWCFService.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28803.202 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SelfHostedWCFService", "SelfHostedWCFService.csproj", "{4E7F9B04-79A4-43F5-BD3C-781AA57DDB52}" EndProject @@ -11,12 +11,15 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4E7F9B04-79A4-43F5-BD3C-781AA57DDB52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4E7F9B04-79A4-43F5-BD3C-781AA57DDB52}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4E7F9B04-79A4-43F5-BD3C-781AA57DDB52}.Debug|Any CPU.ActiveCfg = Release|Any CPU + {4E7F9B04-79A4-43F5-BD3C-781AA57DDB52}.Debug|Any CPU.Build.0 = Release|Any CPU {4E7F9B04-79A4-43F5-BD3C-781AA57DDB52}.Release|Any CPU.ActiveCfg = Release|Any CPU {4E7F9B04-79A4-43F5-BD3C-781AA57DDB52}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AE292131-42A2-43C3-9DAA-8456DEC5CCAC} + EndGlobalSection EndGlobal diff --git a/src/System.ServiceModel.NetTcp/tests/ServiceModel/MessageSecurityOverTcpTest.cs b/src/System.ServiceModel.NetTcp/tests/ServiceModel/MessageSecurityOverTcpTest.cs index e92f4332a9f..5e57cf9d282 100644 --- a/src/System.ServiceModel.NetTcp/tests/ServiceModel/MessageSecurityOverTcpTest.cs +++ b/src/System.ServiceModel.NetTcp/tests/ServiceModel/MessageSecurityOverTcpTest.cs @@ -27,9 +27,7 @@ public static void Ctor_Default_Properties_Not_Supported() } [WcfTheory] - [InlineData(MessageCredentialType.Certificate)] [InlineData(MessageCredentialType.IssuedToken)] - [InlineData(MessageCredentialType.UserName)] [InlineData(MessageCredentialType.Windows)] public static void ClientCredentialType_Property_Values_Not_Supported(MessageCredentialType credentialType) { @@ -41,6 +39,8 @@ public static void ClientCredentialType_Property_Values_Not_Supported(MessageCre } [WcfTheory] + [InlineData(MessageCredentialType.Certificate)] + [InlineData(MessageCredentialType.UserName)] [InlineData(MessageCredentialType.None)] public static void ClientCredentialType_Property_Values_Supported(MessageCredentialType credentialType) {