How do configure username/password authentication for WCF netTcpBinding? - wcf

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";

Related

How to use WebProxy with RestSharp?

I would like to know how to use WebProxy with RestSharp. I am using version 108.0.1 and the code given below returns 407 when running locally from my workstation, which should use my credentials.
var client = new RestClient("https://www.google.com");
var proxy = new System.Net.WebProxy("http://mycorpproxy.com");
proxy.UseDefaultCredentials = true;
client.Options.Proxy = proxy;
var request = new RestRequest();
request.Method = Method.Get;
var response = client.Execute(request);
You need to specify the proxy in the options when you create the client, not after. In v107, the options object properties were init-only, but it fails on legacy SDKs, so we had to revert it to setters, but setting the options that are used to create an HttpClient instance after the client is created has no effect.
var proxy = new WebProxy("http://mycorpproxy.com") {
UseDefaultCredentials = true
};
var options = new RestClientOptions("https://www.google.com") {
Proxy = proxy
};
var client = new RestClient(options);

WCF service behind loadbalancer with custom authorization

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);

WSE2 to WCF: Signing a SOAP message

I need to covert code from WSE2 to WCF and need a few tips on how to implement signing a SOAP message with a X509Certificate2 object.
WSE2 code:
X509SecurityToken tok = new X509SecurityToken(cert);
SoapContext cont = cfs.RequestSoapContext;
cont.Security.Tokens.Add(tok);
cont.Security.Elements.Add(new MessageSignature(tok));
"cert" is my X509Certificate2 object and "cfs" is my Web Services client object.
How can I make this work without WSE2, how to do the same in WCF?
You can use a custom binding for that, but first you must figure out which kind of binding you need. Look here and here. On custom binding you can add security token for signing. My asymmetric binding looks like this: (but you can also use symmetric binding)
AsymmetricSecurityBindingElement asymmetricBinding = SecurityBindingElement.CreateMutualCertificateDuplexBindingElement(
MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
asymmetricBinding.InitiatorTokenParameters = new X509SecurityTokenParameters
{
InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient
};
asymmetricBinding.RecipientTokenParameters = new X509SecurityTokenParameters
{
InclusionMode = SecurityTokenInclusionMode.Never
};
asymmetricBinding.EndpointSupportingTokenParameters.SignedEncrypted.Add(new UserNameSecurityTokenParameters
{
InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient
});
asymmetricBinding.IncludeTimestamp = true;
asymmetricBinding.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
asymmetricBinding.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt;
var textMessageEncoding = new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8));
var httpsTransport = new HttpsTransportBindingElement();
CustomBinding b = new CustomBinding(asymmetricBinding, textMessageEncoding, httpsTransport);
Then you can set certificates on ClientCredentials of the EndpointClient
var wsClient = new YourEndpointClient(b, new EndpointAddress(yourWsEndPointAddress));
wsClient.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2(cert);
wsClient.ClientCredentials.ServiceCertificate.DefaultCertificate = new X509Certificate2(cert);

WCF to WebLogic communication

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.

Programmatic WCF Message Security with Certificates

I've written a self-hosted WCF service using WSHttpBindings and I'm trying to implement message-level security using certificates I've generated myself. Unfortunately I'm getting a buried exception (via the Service Trace Viewer) stating "The credentials supplied to the package were not recognized."
A couple notes:
This has to be done in code, not
in configuration
(Server/Client)Cert are certificates
that are in the local machine store
with accessible private keys to my
user while debugging.
I've googled the hell out of this and
found a good resource for setting up
WCF message based security here
I'm not sure what I'm missing. Most of this stuff seems straight forward except for creating the endpoint identities. It fails with the same message whether I use DnsEndpointIdentities, cert based ones, or no identities at all.
Can anyone point me in the right direction?
Server side:
var binding = new WSHttpBinding
{
Security =
{
Mode = SecurityMode.Message,
Message =
{
ClientCredentialType = MessageCredentialType.Certificate,
AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15
}
}
};
_host = new ServiceHost(this)
{
Credentials =
{
ServiceCertificate =
{
Certificate = ServiceCert
},
ClientCertificate =
{
Certificate = ClientCert,
Authentication =
{
TrustedStoreLocation = StoreLocation.LocalMachine,
RevocationMode = X509RevocationMode.NoCheck,
CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust
}
}
}
};
var address = new Uri(string.Format(#"http://serviceaddress"));
var ep = _host.AddServiceEndpoint(typeof (IService), binding, address);
ep.Address = new EndpointAddress(address, EndpointIdentity.CreateX509CertificateIdentity(ServiceCert));
_host.Open();
Client side:
var binding = new WSHttpBinding
{
Security =
{
Mode = SecurityMode.Message,
Message =
{
ClientCredentialType = MessageCredentialType.Certificate,
AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15
}
}
};
var address = new Uri(#"http://serviceaddress");
var endpoint = new EndpointAddress(address, EndpointIdentity.CreateX509CertificateIdentity(ServerCert));
var channelFactory = new ChannelFactory<IService>(binding, endpoint)
{
Credentials =
{
ServiceCertificate =
{
DefaultCertificate = ServerCert,
Authentication =
{
RevocationMode = X509RevocationMode.NoCheck,
TrustedStoreLocation = StoreLocation.LocalMachine,
CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust
}
},
ClientCertificate =
{
Certificate = ClientCert
}
}
};
var channel = channelFactory.CreateChannel();
this msdn article helped tremendously. I think the root of the problem was setting the following message security parameters to false:
httpBinding.Security.Message.NegotiateServiceCredential = false;
httpBinding.Security.Message.EstablishSecurityContext = false;
So now the overall code for the server side looks more like:
var httpBinding = new WSHttpBinding(SecurityMode.Message);
httpBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
httpBinding.Security.Message.NegotiateServiceCredential = false;
httpBinding.Security.Message.EstablishSecurityContext = false;
var httpUri = new Uri("http://serviceaddress");
_host = new ServiceHost(this, httpUri);
_host.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople, X509FindType.FindByThumbprint, serverThumbprint);
_host.Credentials.ClientCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck;
_host.Credentials.ClientCertificate.Authentication.TrustedStoreLocation = StoreLocation.LocalMachine;
_host.AddServiceEndpoint(typeof(IMetaService), httpBinding, httpUri);
_host.Open();
and the client side:
var httpBinding = new WSHttpBinding(SecurityMode.Message);
httpBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
httpBinding.Security.Message.NegotiateServiceCredential = false;
httpBinding.Security.Message.EstablishSecurityContext = false;
var httpUri = new Uri("http://serviceaddress");
var httpEndpoint = new EndpointAddress(httpUri, EndpointIdentity.CreateDnsIdentity("name of server cert"));
var newFactory = new ChannelFactory<IMetaService>(httpBinding, httpEndpoint);
newFactory.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople, X509FindType.FindByThumbprint, "client certificate thumbprint");
newFactory.Credentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople, X509FindType.FindByThumbprint, "server certificate thumbprint");
var channel = newFactory.CreateChannel();