I'm working on a project where I need the following.
I have an existing application that I have to use the authentication and authorization from (on the server side). I also need to store some metadata about the user in the WCF Service's Thread Principal (a site object). I do this so that I can get at it in the WCF service if I absolutely have to; some business logic may require it. So my plan was to do the following...
Create a custom ServiceAuthorizationManager for the server and in there I will log in the user and get the roles from the existing application. I will cache the "Site" object, and upon further reqests pull from the cache. I'll also need a CustomPrincipal object to hold my custom data. I want to impersonate the user so that I can use the builtin roles filtering in WCF like this:
[PrincipalPermission(SecurityAction.Demand, Role = "Role1")]
public string[] RolesForUser(string username){}
I attempted to use the ASP.NET authorization with a custom roles provider, but I wasn't able to set anything on the Current Principal. I also attempted to use a custom IAuthorizationPolicy, but problems arose. These problems dealt with being able to use the WCFClient.exe application, when it was discovering (using the mex endpoing) it wouldn't give any credentials, so the login would fail. I eventually decided that a ServiceAuthorizationManager was the right way to go, but I'm open to other suggestions.
On the client I will gather the credentials and put them into the WCF proxy class, as follows.
proxy.ChannelFactory.Credentials.UserName.UserName = userName;
proxy.ChannelFactory.Credentials.UserName.Password = password;
As I started to go down this route, I noticed that I wasn't able to get the username/password in the CheckAccessCore method of my manager class. Further investigation showed that I should really be authenticating in a custom UserNamePasswordValidator. So I created one of those. The problem is that the validate method never got called.
Further investigation showed that in order for the validate method to be called my WCF service has to have either message or transport level security. The problem with that is that I can't figure out how to have a message or transport level security without an X.509 certificate. This product is going into several hundred incredibly locked down machines, and installing a certificate is not possible.
Is there a way to do what I'm asking without installing a certificate?
Actually it's possible, but you will need to implement your own binding.
Yaron Naveh developed a WCF binding that enables clear text username/password over HTTP. His article includes the code for the binding.
Short answer; you can't. As soon as you use username/password you need some sort of secure channel.
However you don't need certificates on the clients; only on the server.
I don't know the details of your network infrastructure, but if you are in a Windows domain, you should consider using Windows credentials.
It is possible to use a Message security without certificates if you use Windows credentials. This is the default behavior of the wsHttpBinding (out of the box).
Using the out-of-the-box solutions (without implementing your own binding) WCF encourage (requires) you to use a secure channel whenever authentication credentials are included in the messages.
Using a custom binding that allows you to specify credentials in clear text is surely a solution, but I would think twice before using it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With