I have implemented a scenario which uses netTcpBinding and WsHttpBinding with Transport Security(https) as communication binding type in WCF. Then I compared the performance results. Interestingly, netTcpBinding was slower than wsHttpBinding. I have read a a lot of documents about binding performance and I know that the netTcpBinding provides the fastest communication because of binary encoding.
Can you explain what may cause this situation in my tests? Thanks.
Test environment: IIS 7
public static WSHttpBinding GetWSHttpForSSLBinding()
{
WSHttpBinding binding = new WSHttpBinding();
binding.TransactionFlow = true;
binding.MaxReceivedMessageSize = 2147483647;
binding.MessageEncoding = WSMessageEncoding.Text;
binding.Security.Mode = SecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.ReaderQuotas.MaxStringContentLength = 2147483647;
binding.OpenTimeout = TimeSpan.MaxValue;
binding.CloseTimeout = TimeSpan.MaxValue;
binding.SendTimeout = TimeSpan.MaxValue;
binding.ReceiveTimeout = TimeSpan.MaxValue;
return binding;
}
public static NetTcpBinding GetTcpBinding()
{
NetTcpBinding binding = new NetTcpBinding();
binding.TransactionFlow = true;
binding.MaxReceivedMessageSize = 2147483647;
binding.PortSharingEnabled = true;
binding.Security.Mode = SecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
binding.Security.Transport.ProtectionLevel = ProtectionLevel.EncryptAndSign;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
binding.Security.Message.AlgorithmSuite = SecurityAlgorithmSuite.TripleDesSha256;
binding.ReaderQuotas.MaxStringContentLength = 2147483647;
binding.ReaderQuotas.MaxArrayLength = 2147483647;
binding.OpenTimeout = TimeSpan.MaxValue;
binding.CloseTimeout = TimeSpan.MaxValue;
binding.SendTimeout = TimeSpan.MaxValue;
binding.ReceiveTimeout = TimeSpan.MaxValue;
return binding;
}
Your net.tcp binding uses authentication but ws http binding doesn't. Alse repeat your test with several operation calls from single proxy and with bigger message load. First call is always slow because of channel creation and connection establishment.
Are you talking about latency or throughput. Does a client create a connection and then immediately close it or does it span over multiple calls.
NetTcp has optimization over a same connection and payload size would be smaller since it uses BinaryEncoding vs TextEncoding for wshttp.
If you are looking at latency - NetTcp does windows auth with causes an AD lookup vs on wshttp you are using SSL auth.
Related
Our environment is based on server application which exposes service through WCF. Out customer uses a load balancer - F5. Client application hits it through secured channel and later it uses non-secured HTTP channel. Both client and server uses WsHttpBinding.
Client <> HTTPS <> F5 <> HTTP <> Server
I managed to work with such configuration, but our service uses custom authorization based on JWT tokens and then problem occurs.
I've tested many configurations, but there were various errors.
Currently configuration of client:
var binding = new WSHttpBinding();
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.NegotiateServiceCredential = true;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
Server configuration looks like:
var binding = new WSHttpBinding();
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
host.Description.Behaviors.Find<ServiceBehaviorAttribute>().AddressFilterMode = AddressFilterMode.Any;
binding.Security.Mode = SecurityMode.None;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.NegotiateServiceCredential = true;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
host.Description.Behaviors.Find<ServiceAuthorizationBehavior>().ServiceAuthorizationManager = new JWTAuthorizationManager();
Client application sets authorization headers in such way:
channelFactory.Credentials.UserName.UserName = userId;
credentialBehaviour.UserName.Password = token;
Current status is that request goes to the service, but in CheckAccess() method from JWTAuthorizationManager HttpRequestHeader.Authorization is empty. Moreover System.ServiceModel.MustUnderstandSoapException is thrown. When I switched Security.Mode of client to Transport same thing happens but exception isn't thrown.
I'm not familiar with the details of this technology and I'm not sure what really happens.
UPDATE:
I've checked what is received by service. I see that Security header exists in the message, but service can't interpret this because of Security Mode set to None. I can't set this to Message because it requires certificate on the server machine, we don't want this.
I managed with this problem using CustomBinding at the server side:
var binding = new CustomBinding();
var securityHeader = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
securityHeader.AllowInsecureTransport = true;
securityHeader.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;
securityHeader.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
securityHeader.IncludeTimestamp = true;
var textEncoding = new TextMessageEncodingBindingElement();
textEncoding.MessageVersion = MessageVersion.Soap12WSAddressing10;
binding.Elements.Add(textEncoding);
var httpTransport = new HttpTransportBindingElement();
httpTransport.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
httpTransport.MaxReceivedMessageSize = int.MaxValue;
httpTransport.MaxBufferPoolSize = int.MaxValue;
binding.Elements.Add(httpTransport);
I'm trying to talk to this service here:
https://dmrsit1gateway1.skat.dk/B2B/USImportoer/Service?WSDL
It's a Oracle Weblogic service using x509 certificates.
Whenever I send a request I receive a SecurityAccessDeniedException with the additional info:
{"Failed to derive subject from token.javax.security.auth.login.LoginException: javax.security.auth.callback.UnsupportedCallbackException: Unsupported callback class: NameCallback javax.security.auth.callback.NameCallback#15d38692"}
Somehow my requests does not seem to conform with what's expected.
This is my latest attempt:
var binding = new CustomBinding();
var sec = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
var x509token = new X509SecurityTokenParameters();
sec.EnableUnsecuredResponse = true;
sec.EndpointSupportingTokenParameters.Signed.Add(x509token);
sec.IncludeTimestamp = true;
sec.SecurityHeaderLayout = SecurityHeaderLayout.LaxTimestampLast;
sec.AllowInsecureTransport = true;
binding.Elements.Add(sec);
binding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8));
HttpsTransportBindingElement httpsBindingElement = new HttpsTransportBindingElement();
httpsBindingElement.RequireClientCertificate = true;
binding.Elements.Add(httpsBindingElement);
string endpoint = "https://dmrsit1gateway1.skat.dk:443/B2B/USImportoer/Service?WSDL";
var client = new USImportoerServiceTypeClient(binding, new EndpointAddress(new Uri(endpoint), new DnsEndpointIdentity("REDACTED"), new AddressHeaderCollection()));
client.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindByThumbprint, "REDACTED");
client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindByThumbprint, "REDACTED");
var response = client.getUSDispensationTypeListeHent(input);
Any input how to troubleshoot this would be highly appreciated.
I'm trying to call a C# dll from classic ASP - this dll calls a webservice. I've been asked by someone that runs that ASP site to create this dll for him and had tons of problems doing that. He told me he has a *.crt file, and that the dll should use that to call his SSL-based webservice.
So since this is classic ASP, had to make it a COM object and also configure the service and endpoint through code, like so:
BasicHttpBinding binding = new BasicHttpBinding();
binding.Name = "Service1Binding";
binding.CloseTimeout = System.TimeSpan.Parse("00:01:00");
binding.OpenTimeout = System.TimeSpan.Parse("00:01:00");
binding.ReceiveTimeout = System.TimeSpan.Parse("00:10:00");
binding.SendTimeout = System.TimeSpan.Parse("00:01:00");
binding.AllowCookies = false;
binding.BypassProxyOnLocal = false;
binding.HostNameComparisonMode = System.ServiceModel.HostNameComparisonMode.StrongWildcard;
binding.MaxBufferSize = 65536;
binding.MaxBufferPoolSize = 524288;
binding.MaxReceivedMessageSize = 65536;
binding.MessageEncoding = System.ServiceModel.WSMessageEncoding.Text;
binding.TextEncoding = System.Text.Encoding.UTF8;
binding.TransferMode = System.ServiceModel.TransferMode.Buffered;
binding.UseDefaultWebProxy = true;
binding.ReaderQuotas.MaxDepth = 32;
binding.ReaderQuotas.MaxStringContentLength = 8192;
binding.ReaderQuotas.MaxArrayLength = 16384;
binding.ReaderQuotas.MaxBytesPerRead = 4096;
binding.ReaderQuotas.MaxNameTableCharCount = 16384;
binding.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.None;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
binding.Security.Transport.Realm = "";
binding.Security.Mode = BasicHttpSecurityMode.TransportWithMessageCredential;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
binding.Security.Message.AlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Default;
EndpointAddress endpoint =
new EndpointAddress("https://webservice.XXXX.com/Service1.svc");
var cert = new X509Certificate2(certPath); //local path to *.crt file
Service1.ServiceClient client = new Service1.ServiceClient(binding, endpoint);
client.ClientCredentials.ClientCertificate.Certificate = cert;
var result = client.HelloWorld();
At first i got a Forbidden exception, so I changed the Security.Mode to be BasicHttpSecurityMode.TransportWithMessageCredential. Now, I'm getting this error:
The private key is not present in the X.509 certificate
Is it looking for the cert in the store, or using the path I gave it? How can i make this work?
I have the following class that configures security, encoding, and token parameters but I am having trouble adding a BasicHttpBinding to specify a MaxReceivedMessageSize. Any insight would be appreciated.
public class MultiAuthenticationFactorBinding
{
public static Binding CreateMultiFactorAuthenticationBinding()
{
HttpsTransportBindingElement httpTransport = new HttpsTransportBindingElement();
CustomBinding binding = new CustomBinding();
binding.Name = "myCustomBinding";
TransportSecurityBindingElement messageSecurity = TransportSecurityBindingElement.CreateUserNameOverTransportBindingElement();
messageSecurity.AllowInsecureTransport = true;
messageSecurity.EnableUnsecuredResponse = true;
messageSecurity.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12;
messageSecurity.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
messageSecurity.IncludeTimestamp = true;
messageSecurity.SetKeyDerivation(false);
TextMessageEncodingBindingElement Quota = new TextMessageEncodingBindingElement(MessageVersion.Soap11, System.Text.Encoding.UTF8);
Quota.ReaderQuotas.MaxDepth = 32;
Quota.ReaderQuotas.MaxStringContentLength = Int32.MaxValue;
Quota.ReaderQuotas.MaxArrayLength = 16384;
Quota.ReaderQuotas.MaxBytesPerRead = 4096;
Quota.ReaderQuotas.MaxNameTableCharCount = 16384;
X509SecurityTokenParameters clientX509SupportingTokenParameters = new X509SecurityTokenParameters();
clientX509SupportingTokenParameters.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
clientX509SupportingTokenParameters.RequireDerivedKeys = false;
messageSecurity.EndpointSupportingTokenParameters.Endorsing.Add(clientX509SupportingTokenParameters);
//binding.ReceiveTimeout = new TimeSpan(0,0,300);
binding.Elements.Add(Quota);
binding.Elements.Add(messageSecurity);
binding.Elements.Add(httpTransport);
return binding;
}
}
If you need to specify MaxReceivedMessageSize you can do it on your transport binding element - HttpsTransportBindingElement. You can't add binding to binding.
Just Found this to create a BasicHttpBinding
BasicHttpBinding Basicbinding = new BasicHttpBinding(BasicHttpSecurityMode.None);
Basicbinding.MaxReceivedMessageSize = 10000000;
I would like to be able to use username/password authentication with nettcpbinding, is that possible? (UserNamePasswordValidator or something like that), no windows authentication.
I'm configuring everything with code, so please only use code and not app.config in any examples.
This is what I came up with, I have no idea if some of the code is not required:
Service host:
ServiceHost host = new ServiceHost(concreteType);
var binding = new NetTcpBinding(SecurityMode.TransportWithMessageCredential, true);
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
host.AddServiceEndpoint(serviceType, binding, "net.tcp://someaddress:9000/" + name);
host.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new CustomUserNameValidator();
host.Credentials.ServiceCertificate.Certificate = new X509Certificate2("mycertificate.p12", "password");
host.Credentials.UserNameAuthentication.UserNamePasswordValidationMode =
UserNamePasswordValidationMode.Custom;
And client side:
var binding = new NetTcpBinding(SecurityMode.TransportWithMessageCredential, true);
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
var factory = new ChannelFactory<ISwitchService>(binding,
new EndpointAddress(
new Uri("net.tcp://someaddress:9000/switch")));
factory.Credentials.UserName.UserName = "myUserName";
factory.Credentials.UserName.Password = "myPassword";