overview scenarios accessing claims windows 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 Authentication
When 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 on Thread.CurrentPrincipal. And the only way to get to the client’s username is via the ServiceSecurityContext. 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.IdentityModel library.
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 on Thread.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.

Pingback: WCF and Identity in .NET 4.5: Client Certificate Authentication | www.leastprivilege.com
Hi Dominick, thanks for this post.
Only one doubt, where should I place this code:
idConfig.SecurityTokenHandlers.AddOrReplace(
new GenericUserNameSecurityTokenHandler(
(uname, password) =>
{
try
{
var validator = new PasswordValidator();
validator.Validate(uname, password);
return true;
}
catch (SecurityTokenValidationException)
{
return false;
}
}));
thanks in advance,
Eric
This must be in the hosting code.
In IIS hosting you need a service host factory for that.
by hosting code do you mean for example, the constructor of the Service??
No – i mean the code that creates the ServiceHost.
would that be in the client??
No.
One last thing, and sorry for bothering.
I’ve got a WPF client, I need to authenticate it against a WCF service, and my custom user-password validator gets invoked with all the required validation logic, but then I don’t want that process to get triggered per each request against the service. I saw your videos about identity and access control, in fact, I did it several times, and saw the idea of caching the claims using the FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie but that dosen’t work when the client is a WPF one. I don’t have a STS so my theorical idea of “what to do” is once authenticated the client, I create a token in the service that serves as the identifier that gets cached and is used in the client-server communication with a client claims-based identity using all the pipeline(ClaimsAuthenticationManager, etc). I just can’t find how since WriteSessionTokenToCookie seems to be fitting just asp.net clients needs. So a nearly have the what but no idea of how, and would appreciate so much any help.
Thanks again,
Eric.
Well – a similar concept to the session cookie in WCF is called WS-SecureConversation. This can be enabled on certain bindings – but is not recommended since this creates a session with server affinity.
Unfortunately it is not as straightforward in WCF as it is in ASP.NET/Web API.
Either you cache as much as possible in your validator logic. Or you have to roll your own mechanism like i did here:
https://github.com/thinktecture/Thinktecture.IdentityModel.45/tree/master/Samples/Web%20API/Clients/SessionTokenClient
Pingback: WCF and Identity in .NET 4.5: External Authentication with WS-Trust | www.leastprivilege.com
Hi Dominick,
I am trying to do the same thing as above in IIS hosted app. What are the required components needed in web.config after using a custom security token handler?
I tried
but it is not getting invoked.
Greatly appreciate your help on this.
There should be no difference between IIS hosted and self hosted from a WCF point of view. You certainly need to enable anonymous access in IIS since you do the password handling inside your service.
Hi Dominick,
In WCF I have the ServiceHostFactory which I can use to add the custom token handler( GenericUserNameSecurityTokenHandler is great!!!), but, know I need to use it in and ASP.NET MVC4 app and there is no ServiceHostFactory because I have no WCF layer. So, how can I specify the custom token handler and write the code where I pass in the logic of the custom validation???
thanks in advance
MVC does not use token handlers. You would write your validation code on the login page.
ok, but, after successfully logged in (maybe not using Membership), is the ClaimsAuthenticationManager’s derived class enough to set the ClaimsPrincipal once and for all, using the mechanism you showed in the Identity course, and by just declaring the class holding the transformation logic in the Web.config??
No. You need to either run claims transformation on every request, or set a WIF authentication session cookie.
http://brockallen.com/2013/01/26/replacing-forms-authentication-with-wifs-session-authentication-module-sam-to-enable-claims-aware-identity/
then the WriteSessionTokenToCookie(sessionCookie) will be all to avoid the transformation logic on any request???
That’s caching the claims principal across round trips, yes.
Thanks a lot…
Hi Dominick,
I have just finished your PluralSight courses on 4.5 claims and am trying to get username security to work with my service. Currently, I’m just developing on the one local machine. Client and Host talk fine until I (try to) enable security. I get the error:
An error occurred while making the HTTP request to https://localhost:8735/slsync. This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server.
Do I need to create a SSL cert and configure port 8735 to use it? You didn’t mention this in the course but maybe it’s assumed knowledge? Or is this just a config matter? I’m a bit lost here…
btw, great course, thanks.
Yes you need to create an SSL cert and associate it with the port. I assumed that knowledge ;)
For the cert you can use makecert.exe and for the port mapping netsh.exe
Thanks Dominick. I’m getting there :)
SSL is sorted. Now I get the error:
Unrecognized configuration section system.identityModel
In my config I have:
What am I missing?
Oh. Your blog doesn’t like the angle brackets. I’ve swapped them for square ones…
[system.identityModel]
[identityConfiguration]
[securityTokenHandlers]
[remove type="System.IdentityModel.Tokens.WindowsUserNameSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/]
[add type="Host.CustomUserNameSecurityTokenHandler, Host"/]
[/securityTokenHandlers]
[/identityConfiguration]
[/system.identityModel]
You have to register the config section. Google is your friend ;)
Thanks Dominick.
In case it helps others, here’s the answers to my road-blocks.
1. To use transport security, you need a ssl cert and it needs to be associated with the port you are using. Here are the commands I used for this:
makecert -r -pe -n CN=”localhost” -eku 1.3.6.1.5.5.7.3.1 -ss my -sr localmachine -sky exchange -sp “Microsoft RSA SChannel Cryptographic Provider” -sy 12
then
netsh http add sslcert ipport=0.0.0.0:8735 certhash=81b4cea0ce214d3b8a6f63364ad04008547c1717 appid={00112233-4455-6677-8899-AABBCCDDEEFF}
where certhash is the thumbprint of the cert and the appid is any guid.
You also need to copy the certificate from your localmachine personal certificates to your localmachine TrustedRootCertificationAuthorities. Otherwise, wcf will reject the connection.
Hanselman’s blog helps: http://www.hanselman.com/blog/WorkingWithSSLAtDevelopmentTimeIsEasierWithIISExpress.aspx
2. You need to register the system.identitymodel config section at the top of your app.config with:
[configSections]
[section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/]
[section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/]
[/configSections]
(angle brackets replaced with square brackets so it will post here)
3. The easy way to register GenericUserNameSecurityTokenHandler is in your app.config and put the handler in your wcf library because then it will work in your local host and your iis host exactly the same. It looks like this:
[system.identityModel]
[identityConfiguration]
[claimsAuthenticationManager type="SLSyncService.ClaimsTransformer, SLSyncService"/]
[securityTokenHandlers]
[remove type="System.IdentityModel.Tokens.WindowsUserNameSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/]
[add type="SLSyncService.CustomUserNameSecurityTokenHandler, SLSyncService"/]
[/securityTokenHandlers]
[/identityConfiguration]
[/system.identityModel]
(there’s a claims transformer there to incase that helps).
4. To host the library in iis is super simple. Use something like this in your service.svc:
[%@ ServiceHost Language="C#" Debug="true" Service="SLSyncService.PatientService" %]
BUT…
5. After enabling https in iisexpress, I just couldn’t get the https version to work! Eventually (!) I worked out it was a bug in iisexpress 8 and reinstalling it from the control panel fixed it. Grr.
6. The service reference changes when you host in iis – it no longer uses the base address in your config but the service.svc address. Took me a while to get this one (I guess I’m a bit slow). If you regenerate your service reference you’ll get it though.
7. Then, after doing all this I wanted to put it on the new azure websites… I just published and it worked. I fell out of my chair – not one gotcha!
Anyways, it took me a few days to learn this. Hopefully reporting a little of my journey may help someone else.