Custom Username and Password Authentication in WCF 3.5
A few days ago I wrote about a new feature in WCF 3.5 to detect client's IP address. The other new feature in .NET Framework 3.5 and Windows Communication Foundation 3.5 is the ability to write custom username and password validators in transport level over HTTP.
You probably know that in WCF 3.0 you had three options to use Windows authentication, ASP.NET Membership provider authentication and custom validator authentication in message level to authenticate users. Having the capability to write custom validators in transport level has been a request for developers and the reason seems to be obvious in my opinion!
Fortunately in WCF 3.5 this feature has been added and is easy to use for everyone.
In WCF 3.5 you can write your own username and password validator just by deriving from UserNamePasswordValidator base class available in System.IdentityModel.Selectors and overriding its Validate method.
In the below code I implement my own validator by deriving from UserNamePasswordValidator class and override its Validate method. Here I just write an insecure implementation to show the concepts. There is only one point to mention and that is throwing the SecurityTokenException type when authentication fails.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.ServiceModel;
namespace CustomValidator
{
public class MyCustomValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
// This isn't secure, though!
if ((userName != "Keyvan") || (password != "testPa$$word"))
{
throw new SecurityTokenException("Validation Failed!");
}
}
}
}
Once you write your own custom implementation for the validator, you're able to configure your service to user it.
You can use two different security mechanisms to apply this validator. You can use a message security over transport or transport level security.
So configurations for a service to apply above custom validator should look like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<!-- Other elements are removed -->
<bindings>
<wsHttpBinding>
<binding name="CustomAuthentication">
<security mode="Transport">
<transport clientCredentialType="Basic" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="CustomValidator.ServiceBehavior">
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="CustomValidator.MyCustomValidator, CustomValidator"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
You see that I used a wsHttpBinding binding and applied a transport level security with Basic credential type. Then I configured my behavior with a <userNameAuthentication /> element that has its userNamePasswordValidationMode attribute set to Custom and its customUserNamePasswordValidatorType attribute set to the type of the custom validator that I implemented before.
I personally found this new feature very helpful because usually I don't use ASP.NET membership provider for a WCF application and Windows authentication isn't appropriate for many situations.
[advertisement] Axosoft OnTime 2008 is four developer tools in one: bug tracking, project wiki, feature management, and help desk. It manages your development process so developers can focus on coding. Installed or Hosted – Free Single-user license -- Free 30-day team trial.
21 Comments : 02.02.08
Feedbacks
This feature is avlb in WCF 3.0 as well, it's not specific too WCF 3.5.
If you are using 'Message Mode' Security with clientCredentialType of 'UserName' then you could use code as per below:
client.ClientCredentials.UserName.UserName = @"HKumar";
client.ClientCredentials.UserName.Password = "password";
I have not tried using transport security with custom validator so won't be able to help yet (may bbe in few days !!)
@Harendra:
Did you read the post carefully?!
Hello.
I read your article I still I am confused...
I'm form Portugal and I am starting on .net framework 3.5 development.
Since you are experienced in .net security services, from what I read, I would like to ask you for an advise.
Demand:
My project requisits demand the most abstraction level uppon all layers of project. This means than in the future I should be able to make managment over my authentication method, validation and rules if I like.
Reading:
I read about authentication encapsulated on the header of each xaml message, using a factory. Other factories services could be use depending on tokens, using cardspace. An alternative is using remote services for iis validation either over tcp or https or even over simple http. (What a confusion for a beginner like me)
Goal:
My goal is to implement the most recent technology available. The most Abstration level between any layer would be necessary, since I would be using different clients and services. Form what I could guess, in the future, I would need to define roles, different profiles according to LAN or WAN users, etc. Preferable use of .net3.5
Question:
What are the basics to build this class?
What other classes do I need to create to cooperate with them and with what purpose?
Dificulty:
I still cannot see the picture of the possible architecture diagram for this build. I will start form the basic. I'm not asking you to write me code. I'm hopping that your experience could see it more clear and tell me what to do or help me to decide.
Well, I hope I can help you somehow in the near future. I (we - 8 developers team) are available to commit to you any help you find usefull. (we are all starting .net3.5 and building new project integrating WCF, WPF, WF, and frameworkservices. In the future we will use cardspace as well.)
Sincerelly,
Emanuel
Hey there, thanks for this good intro article. I was wondering, can you share the rest of your web.config and IIS configuration? I can't get IIS to accept this, it complains with all sorts of errors...
Hi,
Thanks for the article. I have got this working now, and my service methods are callable from the client using this method of security. I was wondering if you knew how to retrieve the username from within my service's methods? I need to know who is calling my method to apply authorisation etc. I have looked all over and cannot find any pointers - any help would be much appreciated!
Thanks,
Dan
Thanks for
I too would appreciate it if you could include the entire web.config for using the custom validator. I am unable to edit the config file from your original application and get anything to work.
Thanks
driving = deriving?
@G:
Yes, a missing "e" ;-)
Thanks for posting, this was exactly what I needed!
Thanks for this. I'm running self hosting and don't want to use a service certificate and wondering how I can get around using the HTTPS, but still have service authentication for wsHTTP binding.
With basicHTTP I was able to set security to TransportCredentialsOnly, but wsHTTP doesn't have this option.
Thanks
Hi, I´m starting with WCF, and your post is what I need, but I´m understanding all right, I´m confuse, if I need put this, into CLIENT web.config, or SERVER web.config, or BOTH.
Can you clear my mind ?!
Hi!
I think it can not work over HTTP. Because in System.ServiceModel method GetTransport() always return for <security mode="Transport"> HttpsTransport. Here this method
protected override TransportBindingElement GetTransport()
{
if ((this.security.Mode == SecurityMode.None) || (this.security.Mode == SecurityMode.Message))
{
return base.HttpTransport;
}
this.security.ApplyTransportSecurity(base.HttpsTransport);
return base.HttpsTransport;
}
I have read you article about CustomUsernameAndPassword validation and the article about getting the Client ip address. This is also how we do it. The problem is that you can not combine the two. You can not get the clients IP address when using custom validation cause the statement OperationContext context = OperationContext.Current; will always yield null as a result (at least to my knowledge).
Do you have a way to get the clients IP address in the overridden validate method?
Arne
@arne
I'm not 100% sure but you may be able to extract that info by using web context rather than operation context. You may also want to try using ASP.NET hosting evironment to extract the IP (if your business scneario allows).
In the worst case you should be able to implement a custom listener to extract the IP address.
Hi,
I was following your example. However the code was not responding to the custom password settings. I tried attaching to the w3xp.exe and set a break point on the custom validator code. But the password code is not being hit. Is there anything you can think of that might lead to this behavior.
Steve
Hi keyvan...
I just Saw your article on Custom Username and Password Authentication in WCF 3.5 ,the article looks simple and nice.So, i tried to implement it in my local project ..As i m beginner and have very little knowlege abt WCF , Kindly could please tell me how can client pass credentials to communicate to the service... ...Thanks.. help needed urgently ...
Do you know how to grab this user id later in my services for authorization or for audio purpose?
Hi,
it seems to me that UserNamePasswordValidator doesnt work with transport security mode, only with message security mode where clientCredentialType="UserName"
example could be found here:
Hi,
good article. I did the same. but i got the below error..
"Secure channel cannot be opened because security negotiation with the remote endpoint has failed. This may be due to absent or incorrectly specified EndpointIdentity in the EndpointAddress used to create the channel. Please verify the EndpointIdentity specified or implied by the EndpointAddress correctly identifies the remote endpoint."
How can I rectify this?
Thanks
Thiyagarjan N
Hi Do you have any example on customizing membership provider using own table and using Linq?Anyone got idea?

#1
Pasupathi
02.03.2008 @ 10:25 PM
The article looks simple and good. It would be good if you could add few lines to show how a client can pass this credentials to communicate to the service...