Yossi Dahan [BizTalk]

Google
 

Tuesday, November 25, 2008

Configuring the Geneva Framework based STS to work with custom UserNamePasswordValidator

It took me a little while (and quite a bit of help from others on this thread) to get to a relatively simple implementation, so I thought I’d summarise the steps I’ve taken –

At the risk of sounding the obvious I would definitely recommend making sure the overall STS scenario works well using windows authentication before changing it to support custom authentication.

 

Once that’s done change the STS’ bindings’ clientCredentialType to UserName and the establishSecurityContext to false.

      <ws2007HttpBinding>

        <binding name="UserNameAuthentication">

          <security mode="Message">

            <message establishSecurityContext="false" clientCredentialType="UserName"/>

          </security>

        </binding>

      </ws2007HttpBinding>

The equivalent changes need to be made on the clinet’s binding going to the STS. these may not be obvious at first glance – on the client you will have the endpoint representing the RP and using ws2007FederationHttpBinding; inside this binding’s configuration you will find the issuer element, which is somewhat similar to an endpoint; this represents the STS’ endpoint and as such has a binding (ws2007HttpBinding) and a binding configuration; it is in that binding’s configuration that you need to change the credential type. setting it on the wrong bindings, as I did initially would send you back a couple of hours :-)

Next, as we’re using username authentication for the STS, a service certificate must be used so that the credentials can be encrypted. This is done through configuration of a service behaviour on the STS service as such:

    <behaviors>

      <serviceBehaviors>

        <behavior name="STSBehaviour">

          <serviceCredentials>

            <serviceCertificate findValue="STS" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>

          </serviceCredentials>

          <serviceMetadata httpGetEnabled="true"/>

          <serviceDebug includeExceptionDetailInFaults="true"/> <!—use for debug only -->

        </behavior>

      </serviceBehaviors>

(don’t forget to wire the behaviour to the service...)

As the test certificate I’m using are not valid, I needed to disable validation on the client side; I could not find a way to do this through configuration, as at the client there isn’t an endpoint as such for the STS service, just the issuer element in the ws2007FederationHttpBinding, so I’ve done this in the client code (this is a temporary measure for development only!) –

            proxy.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;

            proxy.ClientCredentials.ServiceCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck;

 

The current version of the Geneva Framework, unlike Zermatt before it, does not support the userNameAuthentication element in the serviceCredetial service behaviour. (to be accurate you can kind of force it to do so, but that’s planned to be blocked in the near future, so for all intents and purposes you should not include this element, see more information in the thread mentioned above)

In order to implement authentication a customer SecurityTokenHandler needs to be added; to do so created a class that inherits from WindowsUserNameSecurityTokenHandler and overridden the ValidateToken method; again – several samples of such implementation exist on the thread but the idea is to validate the username and password (made available through the SecurityToken parameter to the method) in whatever way you wish and then, ideally, add some claims to the ClaimsIdentityCollection output; this should generally include the identity, authentication method and authentication instant, but you can add whatever you wish.

To wire the custom handler to the STS service a bit more configuration is required on the STS side -

  <microsoft.identityModel>

    <securityTokenHandlers>

      <remove type="Microsoft.IdentityModel.Tokens.WindowsUserNameSecurityTokenHandler, Microsoft.IdentityModel,Version=0.5.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

      <add type="MyUserNameSecurityTokenHandler, MyUserNameSecurityTokenHandlerAsembly"/>

    </securityTokenHandlers>

  </microsoft.identityModel>

This replaces the built-in WindowsUserNameSecurityTokenHandelr with my class that inherits from WindowsUserNameSecurityTokenHandler and adds custom implementation.

Note: I needed to add the definition of this section as such –

<section name="microsoft.identityModel" type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel,Version=0.5.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

I hope that makes sense….

Labels: ,

3 Comments:

  • Been busy for hours to get this working. Your post made it work instantly, thanks!

    By Anonymous Benny Michielsen, at 05/02/2009 09:22  

  • Hi,

    I'm not using the geneva framework, but a 'raw' sts scenario using ws2007FederationHttpBinding.

    It is working fine using message security and windows credentials.

    I now want to add UserName credentials as an option such that both Windows and UserName credentials can co-exist.

    My understanding is lacking regards how to set up the extra endpoints etc....

    If there was no STS I would just set up an extra endpoint on the service with a different binding config, and have the client use that new endpoint when wanting to UserName credentials. Right?

    With an STS involved, what goes where?

    A new endpoint on the STS to allow UserName creds?
    A new endpoint on the service to allow UserName creds?

    That doesn't seem quite right to me - I still only want the Service to accept STS tokens, but I want the STS to accept windows or username creds..

    So I'm thinking I need:
    A new endpoint on the STS that uses clientCredtialType=UserName
    No new endpoint on the Service
    A new endpoint on the Client that uses ws2007FederationBinding, whose 'STS redirect' points to the new STS endpoint I created.

    Sound right?

    By Blogger adam11235, at 02/04/2009 01:15  

  • Yes it does, Adam -

    as you've said - you shouldn't need username set-up on the service side, as you'd expect to use the same token.

    The STS would need to expose the relevant endpoint, know how to validate the credenials etc. and then produce exactly the same token it would have otherwise.

    The question now is how the client knows to get to the correct endpoint on the STS.

    Generally the service endpoint directs you at the correct issuer and metadata, I would expect the STS to then publish both endpoints and your client would have to "pick" the right one.

    By Blogger Yossi Dahan, at 02/04/2009 08:40  

Post a Comment

<< Home