Filip Nguyen
Filip Nguyen

Reputation: 1039

How to get the Username and Password in the service side of a WCF call?

When I supply credentials at client with following code:

myChannelFactory.Credentials.UserName.UserName = "username";
myChannelFactory.Credentials.UserName.Password = "password";

Then on server side I see that these credentials are available in

operationContext.IncomingMessageHeaders[1]

However is there any more convenenient method to get the UserName and password? All I see in OperationContext is chaos of properties and untyped lists and I cant find anything that indicates where I can get this.

Upvotes: 6

Views: 2388

Answers (2)

casperOne
casperOne

Reputation: 74530

You can use the static Current property on the ServiceSecurityContext class to get the current ServiceSecurityContext for the operation that is being called.

You can then use the PrimaryIdentity property in order to get the identity of the user with the credentials passed in.

However, it will not (nor should it), expose the password. If you truly need the password, then you will have to drop down to the message level and inspect the headers, as you've seen.

Upvotes: 3

Chris Dickson
Chris Dickson

Reputation: 12135

This is entirely dependent on the binding you are using, and there is no general answer.

For example, if you use the NetNamedPipeBinding and do

myChannelFactory.Credentials.UserName.UserName = "username";
myChannelFactory.Credentials.UserName.Password = "password"; 

you are wasting your time: the client side binding will do nothing with this data, it won't be in the message, and it won't be accessible at all on the service side.

The binding will only consume this data if it is configured with security options which specify the use of username/password credentials. All the standard bindings which do so will use the credentials for authentication, the results of which will then surface in the service via the ServiceSecurityContext as casperOne indicated, and won't include the Password data.

In order to support authentication, the data must be carried somewhere in the message headers. Exactly where and in what form will again be binding-dependent. Don't assume that you'll always find them in operationContext.IncomingMessageHeaders[1].

EDIT: You may be able to construct a custom binding which gives you what you are looking for.

CustomBinding binding = new CustomBinding( ... );
binding.Elements.Insert(1, 
  SecurityBindingElement.CreateUserNameOverTransportBindingElement());

On the service side, provide a UserNamePasswordValidator and configure the credentials like this:

serviceHost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = 
  System.ServiceModel.Security.UserNamePasswordValidationMode.Custom;
servicehost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = 
  new MyUserNamePasswordValidator();

The user name and password will then be delivered to the Validate method of MyUserNamePasswordValidator.

WARNING: This is not a secure authentication mechanism unless you are using a secure transport, as the credentials are sent in clear in the message header.

Upvotes: 2

Related Questions