WS-Security UsernameToken Profile describes how a client can authenticate to a web service using a "username" and a password. Two variations of the password are defined as part of the specification which includes "PasswordText" and "PasswordDigest". Neither WCF nor WIF out of box support "PasswordDigest" however there are some interop scenarios which might require "PasswordDigest". For example, WSE 3.0 supports "PasswordDigest" and if you have to interop your WSE 3.0 clients with WCF services you might need PasswordDigest functionality. In this post I’ll show you a basic implementation of PasswordDigest closely integrated with WCF API. Please note, this could be much easier to implement using the SecurityTokenHandler based API shipped with WIF.
I have created a new assembly and added all the security extensions in this new assembly named Microsoft.ServiceModel.SecurityExtensions.dll.
Microsoft.ServiceModel.SecurityExtensions.dll extends WCF to support Password Digest authentication while retaining WCF’s public programming model. You need to reference this assembly in all your web service projects where you want to enable PasswordDigest authentication. The security extensions are very closely aligned to the standard WCF model of userName/Password validation so you should be able to leverage all of your existing knowledge.
Please note this is a trivial implementation primarily focused on WCF integration rather than spec implementation. This example doesn’t contain any countermeasure code against replay attacks. You can add such functionality by maintaining a cache of used nonces on the server side and then checking against the replay.
To use these extensions in your web service(s), you need to do following:
Specify the type attribute of serviceCredentials to Microsoft.ServiceModel.SecurityExtensions.ServiceCredentialsEx for the extensions to kick in.
Specify your custom validator using the standard WCF syntax. Your custom validator MUST inherit from Microsoft.ServiceModel.SecurityExtensions.UserNamePasswordDigestValidator
<serviceCredentials type="Microsoft.ServiceModel.SecurityExtensions.ServiceCredentialsEx, Microsoft.ServiceModel.SecurityExtensions, Version=126.96.36.199, Culture=neutral, PublicKeyToken=null">
customUserNamePasswordValidatorType="PasswordDigest.MyValidator, PasswordDigest, Version=188.8.131.52, Culture=neutral, PublicKeyToken=null"/>
Finally implement your custom validator by inheriting from Microsoft.ServiceModel.SecurityExtensions.UserNamePasswordDigestValidator. This class integrates with various extensions and implements the logic of PasswordDigest validation.
I have attached the source code and sample project with this post.