Colin Young

I am trying to create a WCF service that authenticates users via Windows authentication over wsHttpBinding, but in even though all the articles I've read on the subject claim that wsHttp uses Windows authentication "out of the box" or that it "comes for free" it simply isn't working for me. I can connect when the client and server are both local, but as soon as I deploy the client to another machine, it is no longer able to connect. I get a "username must be provided" message. If I browse to the .svc file from the remote machine, I get the description page, so I'm at least confident that I have network connectivity between the machines.

The basic requirements are:

1. The service is able to authenticate the client as the user credentials of the logged in user running the client.

2. The client does not prompt the user for their login name or password, and that information is not stored on the client, encrypted or otherwise.

It seems to me that this is a pretty basic requirement for almost any enterprise application (one of my colleagues described it as the most common type of authentication anyone would want to do), so I don't understand why I am having so much trouble implementing it since all the authors of WCF articles seem to think it is too trivial to bother providing an example for. I have had a couple people suggest that I need to implement a ServiceAuthorizationManager and override CheckAccessCore, but best I can tell, that is not where my problem is (I have a custom policy implemented, and when testing locally, it does create a claim set and those claims do appear work as I expect).

I would appreciate it if somebody could provide a complete example (and I mean complete -- IIS configuration, client and service config, code, etc.) of how to accomplish my goal. If it doesn't look like we have a problem with the configuration, any tips about where we should start looking for the problem are also appreciated.

I am developing/testing on Windows XP and deploying to Windows Server 2003. (We do have reasons for using http even though we are operating in an intranet environment. All users of the client will be authenticated against the domain, and all will be in the same domain.)

Thanks.

Colin

web.config (service):

Code Snippet

<system.serviceModel>
<services>
<service behaviorConfiguration="Behavior_INotebookUploadService" name="BiogenIdec.Library.Notebook.Common.TransferService.NotebookUploadService">
<endpoint name="NotebookUpload"
address="http://cam-d045723.corp.biogen.com/NoMaDServices/NotebookUploadService.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_INotebookUploadService"
contract="BiogenIdec.Library.Notebook.Common.TransferService.INotebookUploadService"/>
<endpoint name="MetaData" address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_INotebookUploadService" maxReceivedMessageSize ="50000000" messageEncoding="Mtom" maxBufferPoolSize="50000000">
<readerQuotas maxArrayLength="50000000"/>
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="Behavior_INotebookUploadService">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceAuthorization principalPermissionMode="Custom">
<authorizationPolicies>
<add policyType="BiogenIdec.Library.Notebook.Common.TransferService.Claims.ClaimsAuthorizationPolicy, Notebook Common" />
</authorizationPolicies>
</serviceAuthorization>
<serviceCredentials>
<windowsAuthentication allowAnonymousLogons="false" includeWindowsGroups="false" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>



app.config (client):

Code Snippet

<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="NotebookUpload" hostNameComparisonMode="StrongWildcard" maxReceivedMessageSize="50000000" messageEncoding="Mtom" maxBufferPoolSize="50000000">
<readerQuotas maxArrayLength="50000000" />
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="uploadBehavior">
<clientCredentials>
<windows allowedImpersonationLevel="Delegation" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint name="NotebookUpload"
behaviorConfiguration="uploadBehavior"
address="http://cam-d045723.corp.biogen.com/NoMaDServices/NotebookUploadService.svc"
binding="wsHttpBinding" bindingConfiguration="NotebookUpload"
contract="BiogenIdec.Library.Notebook.Common.NotebookUpload.INotebookUploadService">
</endpoint>
</client>
</system.serviceModel>






Re: Windows Communication Foundation (Indigo) Help Configuring wsHttp for Windows Authentication

Serge Calderara

hello,

Yes as you said this security stuff for identified the client and authorise it to access the service located on a remote server is a common solution that everyone needs.

have you try to add following Element in your client just for test

<identity>
<userPrincipalName value="your login name" />
</identity>

Ther is another way but I am not really sure of it..and did not test it fully yes. It was mention that username and password for authentication MUST be pass throught code only but not sure how and if it has to be done for all cases of authentication scenarios

let me know if you mange to make it work, I am inerresting to hear from it.

serge




Re: Windows Communication Foundation (Indigo) Help Configuring wsHttp for Windows Authentication

Colin Young

Tried that before, and just tried it again. No luck.

I've tried hard-coding the domain/user-id/password in code and that doesn't work either (Windows credentials on wcf.ChannelFactory.Credentials.Windows.ClientCredential or wcf.ClientCredentials.Windows.ClientCredential).

Colin





Re: Windows Communication Foundation (Indigo) Help Configuring wsHttp for Windows Authentication

Colin Young

Okay, so it turns out (and I should point out in my defense that it took 3 of us an entire afternoon to figure this out) that because of the way we store our environment specific configuration files, the config file I was running on the client was not the config file that I was editing. As it turns out, there were a whole bunch of other things we solved while tracking down this problem (e.g. running the service as a specific user, securing the directories it accesses, etc.) so it wasn't a complete waste of time.

In any case I'm hapy to see that WCF actually does function the way I expected it to Smile

Colin





Re: Windows Communication Foundation (Indigo) Help Configuring wsHttp for Windows Authentication

Serge Calderara

Nice to hear that.

So how did you handle your windows authetication then finally

Was it enought to specify it in config file

How does it work then if from the client machine your a logged as BOB and then you try to acces the Server machine where your WCF service is running as MyServiceLocalAcount for instance, when BOB is authenticated from server side and whne BOB is not authenticated from Server side

And finnaly did you pass through code the Credential or not

COuld you describe me your global setting you are using..

Thnaks for help

serge






Re: Windows Communication Foundation (Indigo) Help Configuring wsHttp for Windows Authentication

Colin Young

We are running with aspNetCompatibilityEnabled="true". We set identity impersonate="true" in system.web on the server. It is also necessarty to add the appropriate attribute to the service to allow it to run in asp.Net compatibility mode. This causes the WCF service to run as the provided user (apparently there are other ways to do that, but they involve setting up SPNs and adding Active Directory users, which we don't have the ability to do here). Security mode is set to message and clientCredentialType="Windows"

On the client we set the security mode to message and set clientCredentialType="Windows" for the message. That's it.

On the server, in the AuthorizationPolicy I get the WindowsIdentity from the properties collection of the evaluationContext. That gives me the identity of the user running the client that is making the service call that I can use to set up the claims collection.

Let me know if you need any more explanation. There are a couple articles at theserverside.net by Michele Leroux Bustamante (http://www.theserverside.net/tt/articles/showarticle.tss id=ClaimsBasedSecurityModel2) that were extremely helpful, in spite of some of the early difficulties I encountered. She also has a book out through O'Reilly that is very good. Juval Lowy also has a book out on WCF that also looks good, but I haven't spent nearly as much time with it.

Colin