Kerberos authentication on a self-hosted WCF Data Service - wcf

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.

Related

How to expose WCF service with Basic and Windows authentication options, so Negotiation works

Some clients need to be able to connect to our WCF SOAP services using Basic authentication, while others need to use Windows authentication. We normally host our services in IIS, although we do provide a less-developed Windows Service hosting option.
It's my understanding that it is not possible to configure one endpoint to support both Basic and Windows authentication. So we have two endpoints per service.
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicBinding" contract="SomeContract" bindingNamespace="http://www.somewhere.com/Something" />
<endpoint address="win" binding="basicHttpBinding" bindingConfiguration="WindowsBinding" contract="SomeContract" bindingNamespace="http://www.somewhere.com/Something" />
...
<bindings>
<basicHttpBinding>
<binding name="BasicBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"/>
<message clientCredentialType="UserName"/>
</security>
</binding>
<binding name="WindowsBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
These are in the same Web Application in IIS. That Web Application has both Basic and Windows authentication enabled (else one of the above bindings wouldn't work).
When a client uses the Windows-authenticated endpoint (with "win" on the end of URL), this typically works fine. When the initial request doesn't contain any authentication information, a negotiation takes place between the client and IIS, they settle on Windows authentication and all goes well.
When a client uses the Basic-authenticated endpoint (without "win" on the end of URL), this works if they include the Authorization HTTP header with the correct encoded credentials in it. However, if they do not include any authentication information in the initial request, the negotiation ends up choosing Windows authentication. This gets the request past IIS security, but WCF then refuses the request, because it's going to a Basic-authenticated endpoint.
I am rather hazy on exactly what's happening in the negotiation. But it seems to me that IIS offers all authentication methods enabled for the Web Application (i.e. Basic and Windows), even though the particular WCF endpoint URL for the request only supports Basic.
I would like to know if there is anything we can do in IIS to make the negotiation come up with the right answer: that is, if the request is to a Basic-authenticated endpoint, tell the client to use Basic. Of course, we still want the negotiation to end up choosing Windows, when the request went to the Windows-authenticated endpoint.
If there isn't, then do you think we would be better off concentrating on our Windows Service-hosted version of the services? Or would that have similar problems somehow?
Final note: we do use Basic with HTTP for some internal uses, but we do know that this is an insecure combination. So we typically turn on HTTPS for production use; I've left that out here, for simplicity.
Yes, clientCredentialType="InheritedFromHost" solves the problem for me. This, new in .Net 4.5, means that one can now use the same endpoint URL for more than one authentication type. IIS settings control what authentication is allowed, meaning no longer possible to get IIS and WCF settings in conflict.

What's the difference in WCF between Ntlm and NTLM, and how can I fix it?

I've got a WCF service that's running on IIS 6, with integrated authentication and impersonation using NTLM.
Relevant portions of Web.Config
<system.web>
<identity impersonate="true"/>
<customErrors mode="Off"></customErrors>
</system.web>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
...
</system.web>
...
<wsHttpBinding>
<binding name="wsHttpEndpointBinding">
<security mode="Transport">
<transport clientCredentialType="Ntlm" />
</security>
</binding>
</wsHttpBinding>
I just added the aspNetCompatibility because I want to know who the user is that's logged in (at least as far as IIS is concerned). From the few searches I've done that's how you get the user.
Well, after adding that line and publishing my server I get what's possibly the stupidest error I've seen:
The HTTP request is unauthorized with client authentication scheme 'Ntlm'. The authentication header received from the server was 'NTLM'.
I thought, "Well obviously they're doing a very case-sensitive comparison." So I searched my entire client solution for Ntlm and replaced all non-variable occurrences with NTLM. No luck.
My primary goal, of course is to get whatever user was authenticated through IIS+NTLM. If I'm going about it the wrong way, I'd be happy to know of an easier/better way. Otherwise, how do I tell my client (or my server) that it's OK to go ahead and authenticate?
One other possibility if you are running across this error is that you are experiencing an issue with the loopback check with NTLM. I have a service which runs self-contained on a non-domain (workgroup) server. WCF is configured using BasicHttpBinding with Transport security mode and Ntlm client credentials. When trying to access the service using https://servername it works great. If I try to access it using the FQDN (https://servername.domain.com) it fails with the same error:
The HTTP request is unauthorized with client authentication scheme 'Ntlm'. The authentication header received from the server was 'NTLM'.
If you look inside the Windows security log you will see an Audit Failure with event ID 4625. In this you will see the following failure information:
Failure Information:
Failure Reason: An Error occured during Logon.
Status: 0xc000006d
Sub Status: 0x0
To resolve this you need to either add the back connect host names (preferred) or disable the loopback check. This was a security enhancement added for NTLM in Windows Server 2003 SP1 and later to close out an attack vector against the protocol. The fix, however, causes a lot of unclear error messages like this one from WCF and continues to haunt me in many obscure ways to this day.
Start Here . This should resolve your issue

Which authentication mode of basichhtpbinding can be used to secure a WCF Service using Streaming?

Details about my service:
A file upload service
Transfermode is set to stream
Service is hosted in IIS 7.
I need to provide secuirty to my service. I have tried with ntlm and windows secuirty.I was getting the following error when i am trying to secure my service
"HTTP request streaming cannot be used in conjunction with HTTP authentication. Either disable request streaming or specify anonymous HTTP authentication."
I have found a description stating that:
Description:
You can't do transport auth. with streaming. If you have to use HTTP request streaming, you'll have to run without security.
So i wish to know how can i secure my service? Which secuirty mode can i use with basichttpbinding?Can anyone pls help me on this?
You can try using TransportWithMessageCredential:
<bindings>
<basicHttpBinding>
<binding name="securedStream" transferMode="streamed">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
</bindings>
This will pass credentials in SOAP header. Now you must either pass user's name and password - default validation is against Windows accounts but you can also use Membership provider or custom password validator.
If you really want NTLM or Windows then it means you are running both client and server in the same network / domain. In such case use Net.tcp instead.

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?

Can IIS-hosted WCF service be configured for BOTH Windows Auth and Anonymous?

I've got a small WCF webservice working with the built-in WCF Service Host and with hosting by the Visual Studio 2008 built-in development webserver.
I these hosting enviroments I have relied on the WCF Test Client for invoking the service methods.
Now I am running into problems with my next phase of testing:
I have it hosted in IIS 5.1 on my WinXP dev machine and I think maybe the problem is I cannot continue to use WCF Test Client anymore. Here is what's happening:
Case 1: "Anonymous Access" is CHECKED (ENABLED)
WCF Test Client UI comes up properly, exposing the WebMethods and the INVOKE button.
Yet when I click INVOKE it fails to connect with a backend data store (a 3rd party product) that requires Windows authentication. I could post the error I get back from the product.DLL but I don't think it is relevant.
Case 2: "Anonymous Access" is un-CHECKED (DISABLED)
WCF Test Client UI fails to even initialize properly. My researching of this tells me that MEX (WS-Metadata Exchange) requires "Anonymous Access" and (apparently) WCF Test Client requires MEX. Here are key snippets of the error being returned:
Error: Cannot obtain Metadata from http://localhost/wcfiishost
The remote server returned an error: (401) Unauthorized.HTTP GET Error
URI: http://localhost/wcfiishost
There was an error downloading 'http://localhost/wcfiishost'.
The request failed with the error message:
Security settings for this service require 'Anonymous' Authentication but it is not enabled for the IIS application that hosts this service
The are lots of explanations of binding options, message security, etc. and stuff I honestly do not understand. Here is my take on where I am but I would love your opinions:
(a) Because I know my WCF webservice MUST be configured to use Windows Authentication, I conclude I cannot continue to use the WCF Test Client when hosting my service in IIS. That it has effectively outlived it's usefulness to me. I will just have to take the time to write a web client because WCFTestClient won't work without Anonymous.
(or)
(b) It is possible to use WCF Test Client if it and the hosted service are configured propertly (I just don't know what the special configuration techniques are for this).
Which is correct? Time to stop using WCFTestClient or is there a way to have it both ways? Thanks in advance for your advice.
EDIT: 11 June 09
Is there anything else I can provide to help someone else help me on this question?
I just tried to have the same setup - but in my case, everything seems to work just fine.
ASP.NET web site
WCF service, using basicHttpBinding without any special settings at all
IIS Application with anonymous = enabled and Windows authentication = enabled (both turned on)
I can easily connect to it with the WcfTestClient and retrieve the metadata, and I can then call it, no problem.
Inside my service function, I check to see whether the current user is a known user or not, it is correctly identified as a Windows authenticated user:
ServiceSecurityContext ssc = ServiceSecurityContext.Current;
if (ssc.IsAnonymous)
{
return "anonymous user";
}
else
{
if(ssc.WindowsIdentity != null)
{
return ssc.WindowsIdentity.Name;
}
if (ssc.PrimaryIdentity != null)
{
return ssc.PrimaryIdentity.Name;
}
}
return "(no known user)";
I don't really know, what more to check for (except I'm on Vista with IIS7). Any chance you could include this code to check for the user in your service code? Just to see....
Marc
Marc, your setup is not even close to Johns.
John uses WSHttpBinding that uses Windows Credentials for Message mode transport. The Windows Authentication isn't being used with BasicHttpBinding. Furthermore, John had AnonymousAuthentication disabled, which is why the Metadata Exchange (mex) is failing.
The call won't even reach inside the service side function, because we get a Error 401 (Unauthorized) when we try to call.
Just know John, I have the same issue, and I'm trying to somehow set up separate bindings per endpoint. Hopefully that will work.
When I set the title/subject of this question and reached a dead end here, I opened up the same issue in the MSDN forum with a different emphasis on the title (content of question essentially the same).
For me, the real issue was how to use WCFTestClient in IIS without Anonymous Authentication being set (because my service needed Integrated Windows Authentication only).
Mex apparently requires Anonymous and by default WCFTestClient seems to need Mex. The key seems to be accomodating both my doctoring up the web.config file carefully.
Anyway, I got it working with this web.config below (the MSDN link is here:
<?xml version="1.0"?>
<configuration>
<endpoint address=""
binding="wsHttpBinding"
bindingConfiguration="wsBindingConfig"
contract="sdkTrimFileServiceWCF.IFileService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="basic"
binding="basicHttpBinding"
bindingConfiguration="bindingConfig"
contract="sdkTrimFileServiceWCF.IFileService" />
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="bindingConfig">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</basicHttpBinding>
<wsHttpBinding>
<binding name="wsBindingConfig">
<security mode="Transport">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
</serviceBehaviors>
</behaviors>