HTTP/HTTPS holds good (add no session management) for lot of people today & they prefer using them as their transport protocol for WCF Services. Many a time users connecting with your service are outside your domain so you will like to authenticate them with username / password. This is where WCF makes things difficult.
There is some support shown here for self hosted service (but I have my own reservations over that as IIS is the most preferred hosting mechanism when it comes to HTTP). Let me split this post into 2 parts – assigning credentials to client & authenticating those credentials on server (N.B. my writing is on top of custom binding + channel interface, no Add Service Reference used).
1) Adding credentials on client side via channel factory interface:
ClientCredentials is part of System.ServiceModel.Description.ClientCredentials (System.ServiceModel). Problem is ChannelFactory has a readonly ClientCredentials Property (not when you generate proxy by inheriting from ClientBase this is simplified for you). Luckily there is a workaround. To start with you can instantiate it & assign required values
ClientCredentials loginCredentials = new ClientCredentials();
loginCredentials.UserName.UserName = “Niraj”;
loginCredentials.UserName.Password = “Password123”;
Now ClientCredentials are by default endpoint behaviors, so you have remove the default one & attach the newly created one. Below code shows that
var defaultCredentials = factory.Endpoint.Behaviors.Find<ClientCredentials>();
factory.Endpoint.Behaviors.Remove(defaultCredentials); //remove default ones
factory.Endpoint.Behaviors.Add(loginCredentials); //add required ones
2) Authenticating Credentials on Server Side: This is where things get tricky and you need to use something probably you have heard of but haven’t tried yet, a WCF security mode called – TransportWithMessageCredential (N.B. It’s not currently possible to handle this scenario using Basic Authentication of IIS (transport clientCredentialType), though you can easily do it for REST).
Step 1 is your customize your binding (this has to be done on both Server & Client configurations)
<bindings>
<basicHttpBinding>
<binding name=”usernameHttps”>
<security mode=”TransportWithMessageCredential”>
<message clientCredentialType=”UserName”/>
</security>
</binding>
</basicHttpBinding>
</bindings>
Note that the above would force you to use HTTPS but anyways that’s a recommended approach also. Now it’s time to go to your service and specify the service credentials as shown below, here we use custom authenticator but you could as well used provider model of ASP.NET,
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode=”Custom”
customUserNamePasswordValidatorType=”…” />
</serviceCredentials>
public class CustomPass : UserNamePasswordValidator //System.IdentityModel.dll
{
public override void Validate(string userName, string password)
{
//your validation here, throw exception if invalid user
}
}
That’s it. You are all set. Fire you client & you have username authentication over HTTPS. Hope that helps.
(N.B. You can check my blog entry about how to configure HTTPS for WCF on IIS)
I don’t get step 1, why this way if you just can set it like this:
factory.Credentials.UserName.UserName = “somthing”;
factory.Credentials.UserName.Password = “somthing”;
Regards,
CA
Hi CA,
I already mentioned that while using channel factory interface, – “Problem is ChannelFactory has a readonly ClientCredentials Property”. I guess what you are saying will only work if you are using Add Service Reference & ClientBase inheritance, which would handle it for you behind the covers. In my scenario I have some limitation on using Add Service Reference.
True that ClientCredetials is readonly, but Credentials.UserName “Gets a credential object that you can use to set the user name and password…”
can you please provide a sample code. I am not able to make this concept work. thanks
Chen, can you mail across your code to me (mail id is in contact page).
Thanks for posting.
I tried but not working Do I have to use HTTPS ?
Only work’s for me with HTTPS, otherwise custom validator is not used.
BreakPoint doesnt hit the CustomUserNamePasswordValidator Class
Custom validator belongs to development server‘s or IIS process (depend on how you configured the service‘s project). Put breakpoint on row where you are calling the service and attach to WebDev.WebServer (if you are working with development server) or w3p (when project is using IIS virtual directory). Breakpoints will hit after that.
Can you please send the sample code to my mail Id..
I’m stuck with what to set customUserNamePasswordValidatorType to. I’ve put my custom authenticator in it’s own file called Authentication.cs and it’s the same namespace as my service. I’ve tried the following values:
=”MyNameSpace.Authentication”
=”MyNameSpace.Authentication, Authentication”
=”Authentication”
=”MyNameSpace, Authentication”
All of the above produce errors along the lines of “cannot find”.
It’s always the way… just after my last post where I ask for help, I’ve found the solution to my problem. Solution to my little problem is simply this
customUserNamePasswordValidatorType=”MyAssembly.MyCustomValidator, MyAssembly”
I really must be tired to not have figured that out earlier…
Hi there :
I am bit late to the party. Just got few queries as follows :
1. Can I implement this whole thing @Anonymous authentication on IIS?
2. Do you put the section :
on web.config of the WCF service?
Any help would be appreciated
by section I mean the following :
How do I instantiate ‘factory’? I don’t understand where that gets defined. Thanks!
Just wanted to point out that this solution uses a message-level security, so the clients need to include credentials WS-Security headers which is not always possible. To use HTTP Basic Authentication with basicHttpHinding the only solution is this: https://msdn.microsoft.com/en-us/library/ff649647.aspx
Very Nice… It really works.