Search code examples
asp.netsamlwif

How do I get a SecurityTokenHandler to load its configuration from web.config?


I have been struggling with trying to add a SAML2 SSO entry point to an asp.net 4.6 web application using WIF -- a technology I was totally unfamiliar with before starting. What has worked so far is to create everything programmatically, for which purpose I have subclassed various object types such as Saml2SecurityTokenHandler and X509CertificateValidator and IssuerNameRegistry, and for this handler I build up a SecurityTokenHandlerConfiguration object from scratch. But it has come to my attention that the right way to do this is to have the SecurityTokenHandlerConfiguration load from web.config, or rather app.config as this is in a side assembly rather than the website itself.

If I can get that to work, I can remove a lot of the programmatic stuff I've been duct-taping together. So I started putting the requisite sections in web.config. I added the identityModel sections to the configSections tag, and added something like this to my config:

<system.identityModel>
  <identityConfiguration>
    <tokenReplayDetection enabled="true" />
    <audienceUris>
      <add value="http://myurl.com" />
    </audienceUris>
    <issuerNameRegistry type="System.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089">
      <trustedIssuers>
        <add thumbprint="1234123412341234ABCDABCDABCDABCD00000001" name="theirurl.com" />
      </trustedIssuers>
    </issuerNameRegistry>
  </identityConfiguration>
</system.identityModel>

I also tried setting it up like this, which looks like it ought to fit right into what I need:

<system.identityModel>
  <identityConfiguration>
    <securityTokenHandlers>
      <securityTokenHandlerConfiguration>
        <tokenReplayDetection enabled="true" />
        <audienceUris mode="Always">
          <add value="http://myurl.com" />
        </audienceUris>
        <issuerNameRegistry type="System.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089">
          <trustedIssuers>
            <add thumbprint="1234123412341234ABCDABCDABCDABCD00000001" name="theirurl.com" />
          </trustedIssuers>
        </issuerNameRegistry>
      </securityTokenHandlerConfiguration>
    </securityTokenHandlers>
  </identityConfiguration>
</system.identityModel>

The problem is that I can't seem to bridge the gap between the configuration and the code. Nothing seems to load this automatically, and I can't find any useful information about how to load it manually. It seems that this whole section is just being ignored. If there's a "load config" step that's needed, I can't find where it's described.

How do I construct an instance of a Saml2SecurityTokenHandler, and have its Configuration be loaded from the stuff in app.config?

Update

I am no longer pursuing this approach. I'd still kind of like to know how this works, but there's no importance to it any more.


Solution

  • By creating an instance of IdentityConfiguration it will read your settings from configuration. The default constructor will perform this but there is also a constructor overload that lets you specify this explicitly (new IdentityConfiguration(true)). That one also grants you an exception if there is no <system.identityModel> configuration element.

    If you haven't cleared the collection of SecurityTokenHandlers you will be able to access a variety of of them via your IdentityConfiguration instance's SecurityTokenHandlers property. This was true for me so I have to search for the handler I'm looking for.

    In my case I wanted to read the TokenLifeTime property of the SessionSecurityTokenHandler (additionally using System.Linq):

    System.IdentityModel.Tokens.SessionSecurityTokenHandler sessionSecurityTokenHandler =
        new IdentityConfiguration(true)
        .SecurityTokenHandlers
        .SingleOrDefault(sth => sth.TokenType == typeof(System.IdentityModel.Tokens.SessionSecurityToken))
        as System.IdentityModel.Tokens.SessionSecurityTokenHandler;
    
    TimeSpan tokenLifeTime = sessionSecurityTokenHandler.TokenLifetime;
    

    My configuration looks like this:

    <system.identityModel>
        <identityConfiguration>
            <securityTokenHandlers>
                <remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
                <add type="System.IdentityModel.Tokens.SessionSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
                    <sessionTokenRequirement lifetime="01:00"  />
                </add>
            </securityTokenHandlers>
        </identityConfiguration>
    </system.identityModel>
    

    From the securityTokenHandlers documentation:

    By default, the collection is populated with the following handler types: SamlSecurityTokenHandler, Saml2SecurityTokenHandler, KerberosSecurityTokenHandler, WindowsUserNameSecurityTokenHandler, RsaSecurityTokenHandler, X509SecurityTokenHandler, and EncryptedSecurityTokenHandler. You can modify the collection by using the add, remove, and clear elements. You must ensure that only a single handler of any particular type exists in the collection. For example, if you derive a handler from the Saml2SecurityTokenHandler class, either your handler or the Saml2SecurityTokenHandler may be configured in a single collection, but not both.