WCF and Identity in .NET 4.5: UserName/Password Authentication

http://leastprivilege.com/2012/07/16/wcf-and-identity-in-net-4-5-usernamepassword-authentication/

I use this configuration:

<system.serviceModel>

<services>

<service name=“Common.ClaimsService“>

<endpoint address=“usernamemixed“

binding=“netHttpBinding“

contract=“Common.IClaimsService“ />

</service>

</services>

<bindings>

<netHttpBinding>

<binding>

<security mode=“TransportWithMessageCredential“>

<message clientCredentialType=“UserName“ />

</security>

</binding>

</netHttpBinding>

</bindings>

</system.serviceModel>

In the client, you now have to explicitly pass in a username and password:

var factory = new ChannelFactory<IClaimsService>(“*”);

factory.Credentials.UserName.UserName = “username”;

factory.Credentials.UserName.Password = “password”;

var proxy = factory.CreateChannel();

var id = proxy.GetIdentity();

By default WCF will check the credentials against the Windows account database, and if authentication is successful, you get a full fledged WindowsPrincipal/WindowsIdentity in your service (just as with Windows integrated authentication).

Custom AuthenticationWhen you want to authenticate against a custom credential store, you need to configure a custom password validator that in the <serviceCredentials /> behavior:

<behaviors>

<serviceBehaviors>

<behavior>

<serviceCredentials>

<userNameAuthentication userNamePasswordValidationMode=“Custom“

customUserNamePasswordValidatorType=“Type, Assembly“ />

</serviceCredentials>

</behavior>

</serviceBehaviors>

</behaviors>

A sample implementation looks like this:

public class PasswordValidator : UserNamePasswordValidator

{

public override void Validate(string userName, string password)

{

if (userName != password)

{

throw new SecurityTokenValidationException();

}

}

}

Now when you run that, you’ll notice that you get an anonymous WindowsPrincipal onThread.CurrentPrincipal. And the only way to get to the client’s username is via theServiceSecurityContext. So this “old” approach is not really compatible with the claims world.

Enabling “WIF” Mode

In WIF mode you have much better claims integration, but there are also some changes you need to do to your authentication code. But first of all, enable WIF mode:

<serviceBehaviors>

<behavior>

<serviceCredentials useIdentityConfiguration=“true“ />

</behavior>

</serviceBehaviors>

The standard token handler again authenticates against Windows accounts. When you want to authenticate against your custom credential store, you need to supply a custom security token handler. This is not as simple as writing a password validator like the one above, but fortunately I have a really simpler wrapper in our Thinktecture.IdentityModellibrary.

You could configure your token handler also in configuration, but you can also do it via code:

host.Credentials.UseIdentityConfiguration = true;

var idConfig = new IdentityConfiguration();

idConfig.SecurityTokenHandlers.AddOrReplace(

new GenericUserNameSecurityTokenHandler((uname, password) =>
uname == password));

host.Credentials.IdentityConfiguration = idConfig;

…or if you simply want to wrap an existing password validator:

idConfig.SecurityTokenHandlers.AddOrReplace(

new GenericUserNameSecurityTokenHandler(

(uname, password) =>

{

try

{

var validator = new PasswordValidator();

validator.Validate(uname, password);

return true;

}

catch (SecurityTokenValidationException)

{

return false;

}

}));

The final step is to tell WCF to put the ClaimsPrincipal coming from the token handler onThread.CurrentPrincipal using the following service behavior:

<serviceAuthorization principalPermissionMode=“Always“ />

The end result is a ClaimsPrincipal containing the username, authentication method and authentication instant claims. Also the claims transformation/validation/authorization pipeline will be called if configured.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s