Reputation: 1039
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
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
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