When implementing a federation solution, or replacing an existing legacy solution, let’s consider how “thinking about the problem differently” can improve things.
A current client has an existing “legacy” SSO and federation platform that is relatively complex. It’s a Siteminder implementation with the CA federation components added. While the solution does work, the client wants to eliminate licensing costs and simplify their infrastructure. We are implementing AD FS for them to serve as the federation engine. Longer term goals include migrating the set of SSO applications to SAML 2.0, and apps will be claims aware wherever possible. If not possible, some applications may be converted to Kerberos or Windows Integrated authentication.
Part of my architectural philosophy focuses on simplification. Simplicity, when implemented wisely, is more stable and reliable, is easier to support, and (should be) easier to understand.
While there are some definite benefits and strengths to the Siteminder architecture that's in place, the customer wasn’t leveraging the feature set available in the CA solution. Those features aren’t actually needed to meet their project goals. Why pay for features you’re not using and have no intention of ever using?
In the new solution, AD FS takes over the policy logic via its federation engine and the downstream federated applications handle their own authorization logic (just as they did with the legacy solution.). Non-federation capable apps are reverse-proxied behind a Siteminder ISAPI filter and use a simple header variable with an employee ID number as its value. This isn’t a secure or modern way of doing things.
Going through the proxy and checking the status of the Siteminder cookie constantly is all well and good, but how will we solve the employee ID header value pass-through? Is SSL “enough”? I’m not comfortable with this level of security (or lack of it) but we’ve got to work for now with what the downstream applications support.
One key to my solution is that it’s not dependent upon AD FS--if our client decides to migrate to another product, or outsource the Identity Provider functionality to a cloud vendor, this solution will work without any additional code or modifications! The client administrator simply updates two lines in a configuration file and they are ready to consume SAML assertions from a new Identity Provider!
Let’s look at the key architectural and design elements of this solution:
- I didn’t use WIF (Windows Identity Foundation). While WIF is the core of claims-based development for .NET applications, it didn’t fit with the key concepts of my design. I’ve already mentioned one--that we’re avoiding being tied to AD FS.
- I wanted to increase performance by using compiled code rather than interpreted ASP. I planned to write the application in C#, but wanted it as an assembly. There are other reasons for compiling the code which we’ll see shortly.
- The code is a custom HTTP handler, rather than a filter or some other interface. Processing takes place without requiring any html or aspx files or scripts. The interface to the handler accepts connections addressed to a virtual file type.
- The solution is simply a Service Provider or “SP” in SAML 2.0 terminology, what Microsoft would call a “Relying Party” in AD FS parlance. Note that additional components of a typical federation platform are not present as they aren’t part of the design goal--we’re solving one particular problem, not trying to create a multi-component federation solution. Notably, I did intend for the design to support multiple Identity Provider federation partners.
- I wanted the solution to be a lightweight and as independent from other components as possible. When I say “lightweight,””, for example, consider that the code does not use nor require a SQL database back-end! There’s no need for one, as I’ll discuss further! Consider how this can improve performance--there is simply no wait for a database connection, query, and response. Whole categories of failure modes are eliminated by this simplification.
- Of course the code is extensible--if another downstream application interface is desired, it can be added to the code without a rewrite of what’s already in place.
- Other than the obvious requirement that the HTTP handler’s server be IIS and support .NET 3.5 or newer, I haven’t tied the code to any particular web server application language--the web server my SP code interfaces with might leverage VB, C# or perhaps PHP, Python, or whatever else. Whether the application we’re making SAML-aware is on the same IIS server or on a separate server running Weblogic or Apache--the solution is platform “agnostic.””.
- As you can guess, I didn’t want the solution needing to reside on a single Active Directory domain with the IdP, nor to even need Active Directory. Consider that as a stand-alone SP there isn’t any inherent requirement that the application being federated to even use a directory! Granted, one of the connection options I added is an LDAP lookup that creates an ASPX user context token, as that was needed by one implementation.
- Related to item 5, the SP is configured via a simple web.config file--the simpler the better, was my design goal. An IIS server with the prerequisites present: .NET 3.5 or higher, a service account ready to assign to the App Pool, information about the IdP (or multiple IdP’s!) can be configured and operational in under 5 minutes!
- Scalability. I hoped that while adhering to the design goals described here that I could create an easily scalable solution. We’ll see the pros and cons of my “simplicity” approach. No central configuration database does mean one configuration file to manage one every SP server added (each server has a web.config), but the system will perform very well with only a few servers, and the problem of how to keep a few files synchronized has been solved thoroughly and should be well understood. Even if you had a central configuration database, some elements of the n-server configuration still have to be dealt with on each system.
Currently only IdP-initiated SSO is supported with the POST binding. This is really not much of a limitation since an IdP is sure to support this--it’s the most common SAML binding used. The code may be updated to support SP-initiated SSO or even HTTP Redirect binding (query-string support capability is already present), but I have no intention of supporting Artifact resolution or SOAP binding--they just add complexity and aren’t that common. Across all my federation projects, I’ve never yet had anyone insist on Artifact resolution or anyone even ask for SOAP.
The .dll is currently a modest 20 kb in size. Typical SAML assertion processing time is as low as 5 ms with an observed average of about 20-27 ms. These measurements were taken on various VM configurations including a “Micro” Amazon AWS EC2 instance.This processing time includes the complete consumption of the SAML 2.0 assertion including required steps such as verification of cryptographic signature(s) and all logic regarding the hand-off to the downstream application.