WCF Routing with Message Security - wcf

I have a WCF service with Message Security Authentication.
I want to set up a routing service for Load Balancing.
For some reason it doesn't work, I've enabled includeExceptionDetailInFaults to see exceptions, so in the client I see:
The client certificate is not provided. Specify a client certificate
in ClientCredentials.
It seems that the certificate isn't forwarded from router->service.
Currently the client/router/service is on the same machine, so I have all the certificates, but if I deploy them on a different machine will the Router have to have the private keys?
In addition, if I want to establish a non-secured connection between the router and service (offload the security), how can I provide the Identity of the caller?
EDIT :
For all Client/Router(both server&client)/Server the security configured the same :
<security mode="Message">
<message clientCredentialType="Certificate" negotiateServiceCredential="false"
algorithmSuite="Default" establishSecurityContext="false" />
</security>

There are many articles that says Microsoft didn't support this scenario and it is true.
This article explains how to write your own custom solution to provide security to all client/router/service.

The client certificate is not provided. Specify a client certificate in ClientCredentials.
I have seen this error when the service certificate doesn't match the host domain name.
If you are still seeing this issue can you post some of your configuration entries?

1) As first try to set certificate in the client side by code.
ChannelFactory<IService1> factory =
new ChannelFactory<IService1>("Service1_Endpoint");
factory.Credentials.ServiceCertificate.SetDefaultCertificate(
System.Security.Cryptography.X509Certificates.StoreLocation.CurrentUser,
System.Security.Cryptography.X509Certificates.StoreName.My,
System.Security.Cryptography.X509Certificates.X509FindType.FindBySubjectName,
"<SeriveCerificateName>");
If you really have problem with certificate you promptly get exception at the application startup.
2) If there is no exception then check thumbprints of the service certificate on both sides.

This blog post explains that Microsoft didn't support this scenarion-
http://blogs.microsoft.co.il/blogs/applisec/archive/2011/12/12/wcf-routing-and-message-security.aspx

Related

How to use wsHttpBinding with Message security through a load balancer

I have a load-balanced service that uses Message security:
<wsHttpBinding>
<binding>
<security mode="Message">
<message clientCredentialType="Windows" establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
All of my calls to this service open and close their own channel, so there's no benefit to establishing a security context.
I am calling the service with a WSHttpBinding that matches the service config:
ws.Security.Mode = SecurityMode.Message;
ws.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
ws.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
ws.Security.Message.EstablishSecurityContext = false;
This works sometimes, but sometimes I get errors such as
The security context token is expired or is not valid. The message was not processed.
or
The request for security token has invalid or malformed elements.
I finally found that setting EstablishSecurityContext to false doesn't actually prevent security context tokens from being used. Our load balancer doesn't currently use sticky sessions, and I'm trying to avoid going that route.
I did find that I should be able to set NegotiateServiceCredential to false on the client to allow for the load balancer without sticky sessions. My service is already running under an AD account, and I can see it in the WSDL:
<Upn>User#Domain</Upn>
However, when I try to add the service identity to my client
EndpointIDentity.CreateUpnIdentity("User#Domain")
I get the following error:
Authenticating to a service running under a user account which requires Kerberos multilegs, is not supported.
How do I get past this to be able to make a call to my service through the load balancer?
According to the documentation for NegotiateServiceCredential, you must run the service using an SPN identity instead of UPN:
If this property is set to false, and the binding is configured to use
Windows as a client credential type, the service account must be
associated with a Service Principal Name (SPN). To do this, run the
service under the NETWORK SERVICE account, or LOCAL SYSTEM account.
Alternatively, use the SetSpn.exe tool to create an SPN for the
service account. In either case, the client must use the correct SPN
in the <servicePrincipalName> element, or by using the EndpointAddress
constructor.
Once you configure the SPN that your service is running under, your WSDL should display SPN instead of UPN, then you'll have to modify your client such that: EndpointIdentity.CreateSpnIdentity("service_spn_name")
Update:
The following command should properly configure the SPN:
setspn -A YourSvc/host.server.com domain\AppPoolAcccountName
YourSvc = a name identifying your svc
host.server.com = fully qualified hostname of the server your service is hosted on
See docs for setspn

Kerberos authentication on a self-hosted WCF Data Service

We have a WCF Data Service which is self-hosted under a Windows service (not using IIS) which we are currently working to secure using SSL and Windows Authentication.
After some time playing around with netsh and server certificates, we now have the service secured with SSL and we have also enabled Windows Authentication on the webHttpBinding in our app.config - however we are now seeing some strange behaviour when attempting to authenticate certain users - some can log in fine, others have their credentials rejected and are prompted with HTTP 400 errors.
After some testing and digging around it would appear that we might be running into this problem, where the authentication header used by Kerberos may be greater than the maximum permitted header length (which I believe is 16k) for certain users - and although there is a documented workaround for IIS, there does not appear to be an equivalent setting we can use for a self-hosted service, or in our app.config - unless I'm missing something? We tried setting the maxReceivedMessageSize and maxBufferSize fields to their maximum values to see if that would make any difference, but apparently not.
Binding config:
<webHttpBinding>
<binding name="DataServicesBinding"
maxReceivedMessageSize="2147483647"
maxBufferSize="2147483647">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
We've managed to work around this issue temporarily by setting the clientCredentialType in our binding to use Ntlm instead, but we'd like to get Kerberos working if possible for obvious reasons.
So, as it turns out, this was caused by our service not being configured with a SPN (Service Principal Name). This can be done using the setspn tool with Windows Server. (See this MSDN article for more information.)
Once the SPN was applied, Kerberos authentication started to work as expected.
Use wireshark to see what the client sends. Make sure that this input is correct and then come back.

How to use Message security and UserName clientCredentialType without Certificate in WCF Service?

i have a WCF service with wsHttpBinding which my clients are my windows application and my website. both those clients are consumer of the my service. in the my service, i used a Message security and UserName clientCredentialType for clients authentication. i do not want use any certificate for this authentication. how do i? or you suggest to me other solution for this sake?
WsHttpBinding message security with UserName client creadentials demands server certificate. The only option is to use Windows client credentials but in such case your client and service must be in the same AD domain (or trusted domains). If you want to secure message (encrypt and sign) you need such infrastructure.
Edit:
Based on your comment you don't need message security, you only want to use UserNameToken profile to transport client credentials over insecured channel. This is possible in WCF 4 (and in older versions with special KB). Try this custom binding:
<customBinding>
<binding name="UsernamePasswordOverHttp">
<textMessageEncoding messageVersion="Soap11" />
<security
authenticationMode="UserNameOverTransport"
messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
allowInsecureTransport="true" />
<httpTransport />
</binding>
</customBinding>
Be aware that there can be some problem with autogenerating WSDL for such service.
Edit 2:
Another possibility is to use ClearUserNameBidning.
thanks for your example. i used your example but i received this error:
The Scheme cannot be computed for this binding because this CustomBinding lacks a TransportBindingElement. Every binding must have at least one binding element that derives from TransportBindingElement.
and other my question: for this solution i use from which project type in VS2010? a WCF Service Library in project or a WCF Service website. which one?
thank you for your answers.

WCF using Transport always attempts to use HTTPS when I don't want it to

I keep getting the following error "Could not find a base address that matches scheme https for the endpoint with binding WebHttpBinding. Registered base address schemes are [http]." This started because I went to Basic Transport Authentication by adding:
<webHttpBinding>
<binding name="secureBasic">
<security mode="Transport">
<transport clientCredentialType="Basic" />
</security>
</binding>
</webHttpBinding>
After googling the common fix seemed to be the following code, but I had no success with it:
<baseAddressPrefixFilters>
<add prefix="http://mywebsiteurl"/>
</baseAddressPrefixFilters>
Still, nothing works. All I want is to use basic http authentication on a non-https connection. I have configured absolutely nothing and it appears by default WCF wants to force a HTTPS connetion. Anyone run into this?
If you tell WCF to use transport security mode, you must use a transport protocol that supports secure communication. HTTP doesn't support secure communication because it's a plaintext protocol (anyone that intercepts your communication can simply read what is being transmitted). HTTPS does support secure communication so your only option for a webHttpBinding with transport security is to use HTTPS (which you can configure in IIS).
Here is a blog post describing your error and how to solve it using TransportCredentialOnly. It's about basicHttpBinding but the same holds for your webHttpBinding.
If you want only transport level authentication (= Basic authentication) but you don't want transport level secure communication (= HTTPS) you have to set security mode to TransportCredentialOnly.

WsHttpBinding with security mode TransportWithMessageCredential in IIS 7 not working

We are currently migrating a WCF service from IIS 6 to IIS 7. The service contains some non-SSL endpoints for internal streaming purposes and some exposed endpoints secured with SSL.
The public, secure endpoints are implemented using wsHttpBinding and security mode="TransportWithMessageCredential". The binding reads as follows:
<wsHttpBinding>
<binding name="CustomSecurityBinding">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
The credentials are authenticated against a custom user repository for validation.
After deploying the service to IIS 7 (64bit Win2k8), all services (basicHttpBindings) respond correctly, expect for the wsHttpBindings. If triggered using https, we always get a HTTP 400 status code (Bad Request).
After enabling tracing in IIS, we could kinda narrow down the problem, although the message from the trace did not really help:
MODULE_SET_RESPONSE_ERROR_STATUS Warning
ModuleName="ManagedPipelineHandler", Notification="EXECUTE_REQUEST_HANDLER",
HttpStatus="400", HttpReason="Bad Request", HttpSubStatus="0", ErrorCode="Der
Vorgang wurde erfolgreich beendet. (0x0)", ConfigExceptionInfo=""
Steps done so far:
re-installed WCF extensions in IIS 7 (ServiceModelReg.exe -r -y)
enabled https protocol for host, added self-signed certificate to host
played around with dns/identity setting in wcf configuration
added a base address to wcf service config
After 2 hours of googling and trying to make this work, i ask you as a last resort of hope: Does anybody know this strange behaviour of IIS 7?
Have you verified that the SSL binding is configured in applicationHost.config (%windir%\system32\inetsrv\config\schema\IIS_Schema.xml) and that the HTTP.sys store contains a valid certificate has and store name for the binding? Secondly, the true error could be masked by the 400 error, have you tried altering your wsHttpBinding in configuration to increase the maxBufferPoolSize and maxReceivedMessageSize to some extremely high values and see if this continues?