Using ADFS 2.0 SQL Attribute Store for “advanced” claims

November 30, 2011 at 11:20 PMHenrik Nilsson

It’s getting late so I’ll just briefly describe this unless you figured this out already…

It started out with MSFTie Ken St. Cyr published a blog post  about a Powershell Attribute Store, a really great idea except he pointed out this could be used for provisioning which is not such a great idea so I made a comment on it. He replied and complained that the ADFS Claims Rule Language lacked more advanced functionality so I just had to show you how the SQL Attribute store can be used for this. Sorry Ken, I just had to make this blog post and I hope you don’t mind me mentioning your great blog and our conversation!?

First of all make sure you have a working connection to a SQL database from ADFS using SQL Attribute store!

Here’s a simple one just to make a claim (Given Name in this case) upper case, other function could be used as well:

c:[Type == ""]
=> issue(
store = "SQL",
types = (""),
query = "SELECT UPPER({0})", param = c.Value

And here’s how the famous IsOver21 claim can be created as a scalar valued function in SQL
(far from perfect especially date conversion but it works with Swedish date format like 1979-12-23):

@BirthDate nvarchar(10)
RETURNS nvarchar(3)
DECLARE @Age int, @ReturnValue nvarchar(3)

IF @Age >= 21
SET @ReturnValue = 'Yes'
SET @ReturnValue = 'No'



You can then use it like this in ADFS (please use more properly named claim types though) and note how the function needs to be prefixed with dbo:

c:[Type == ""] 
=> issue(
store = "SQL",
types = (""),
query = "SELECT dbo.IsOver21({0})", param = c.Value);
Have fun!

Posted in: Claims | ADFS | Federation

Tags: ,

New Lotus Notes/Domino 8 MA

November 24, 2011 at 12:25 AMHenrik Nilsson
A new ECMA2 based connector for FIM 2010 R2 is already available in beta at Connect here.


New functionality:
• Support for additional object types: mail-in database, Resource (meeting rooms and on line meetings).
• Support for renames using the AdminP process.
• Dynamic schema discovery for custom attributes.
• Delta import for add and updates.

Posted in: FIM 2010 R2 | Forefront Identity Manager | Lotus Notes

Tags: ,

FIM 2010 R2 released as Release Candidate (RC)

November 23, 2011 at 6:22 PMHenrik Nilsson

Read about the news here.

Posted in: FIM 2010 R2 | Forefront Identity Manager


Important about FIM Hotfix Rollup Package (build 4.0.3594.2)

November 17, 2011 at 1:19 AMHenrik Nilsson

Fellow FIM MVP David Lundell has written a great article about the problem of using wildcards (% and _) in FIM XPath queries (Sets, Groups, Search Scopes etc.). The problem lies in that Microsoft has made the choice to treat these wildcard characters as literals instead of wildcards meaning that installing FIM Hotfix Rollup Package 4.0.3594.0 could break your FIM implementation.

Go ahead and read Davids article:

What the %_ is the deal with wildcards in FIM Queries in the latest hotfix?

Posted in: Forefront Identity Manager

Tags: , , ,

ADFS 2.0 Home Realm Discovery Deluxe

November 3, 2011 at 9:06 PMHenrik Nilsson

I’ve been doing some work on Home Realm Discovery lately and I wish to show you how HRD can be performed on the ADFS 2.0 server when you have done the wise decision to centralize all your Claims Providers in ADFS than in each and every application that likely will save you a lot of head ache in the future.

The Problem

This is what users sees when there are 1 ore more Claim Providers configured in ADFS, The ADFS 2.0 Home Realm Discovery Page…


This might be ok if the user is sure what Claims Provider Trust to use but what if only 1% of the users  normally located in a branch office realm are supposed to sign in on another Claim Provider – this will force the remaining 99% at the main office realm to go thru this page and do the selection also.

The whr query parameter?

In ADFS 1.0 you could add a query parameter at the end of your url to select Home Realm and bypass the Home Realm Discovery page when requesting the application like this:

Unfortunately WIF won’t forward the whr query parameter to an IdP unless you add or change Global.asax in your WIF enabled application. Add this to Global.asax in the WIF application to make it work:

<%@ Application Language="C#" %>
<%@ Import Namespace="Microsoft.IdentityModel.Web" %>

<script runat="server">

void Application_Start(object sender, EventArgs e)
FederatedAuthentication.WSFederationAuthenticationModule.RedirectingToIdentityProvider +=

new EventHandler<RedirectingToIdentityProviderEventArgs>(WSFederationAuthenticationModule_RedirectingToIdentityProvider);

public void WSFederationAuthenticationModule_RedirectingToIdentityProvider(object sender, RedirectingToIdentityProviderEventArgs e)
e.SignInRequestMessage.HomeRealm = Request["whr"];

ADFS 2.0 on the other hand handles the whr query parameter very well and before the Home Realm Discovery page is shown but remember it must match the entityId of the selected Claim Provider exactly including casing.

The ADFS Home Realm Discovery page

From the UI (the picture above) you can see that it has a dropdown list containing the Claims Providers available and then there’s a submit button. The code behind class (not shown due to copyright) of the HomeRealmDiscovery page inherits from the HomeRealmDiscoveryPage class that gives us a property, ClaimsProviders that holds a DataTable object with the display name [name] and entity id [id] columns of available Claims Providers that is used to populate the dropdown list. The HomeRealmDiscoveryPage class also gives us the SelectHomeRealm method that will set the home realm to the entity id of the Claims Provider selected in the dropdown list unless it’s the local ADFS that’s selected, in that case an empty string will be passed to the SelectHomeRealm method.

You can easily change the Home Realm Discovery page used in /adfs/ls/web.config file, allowing you to keep the original untouched.

<homeRealmDiscovery page="HomeRealmDiscovery.aspx" />

The Home Realm Discovery Cookie

As you probably know, the local ADFS 2.0 is acting as a relying party when a remote Claims Provider is selected as home realm, an authentication request is created and sent to the remote Claims Provider and when a response is coming back on a successful sign on the MSISIPSelectionPersistent cookie is by default created as a persistent cookie (in opposite to session cookies it will stay after browser is closed) that will live for 30days in the browser.

How and if the cookie is created and it’s lifetime can be configured in the persistIdentityProviderInformation element in the /adfs/ls/web.config file.

<persistIdentityProviderInformation enabled="true" lifetimeInDays="30" />
The enabled attribute controls whether the cookie should be created as a persistent cookie (true) or as a session cookie (false) and the lifetimeInDays attribute how long the cookie will live when persisted. unfortunately it looks like the persisted cookie won’t be extended with each successful login but I’m not 100% sure of this, maybe somebody could tell me!?

Possible solutions to the problem

Now that you know most of what there is to know about Home Realm Discovery lets go back to the problem stated above where branch office users will be signing in using a different Claims Provider but where everyone has to select anyway.

One solution could be to distribute url’s with the whr query parameter to everyone with different values depending on Home Realm to use but this is a bit unpractical, almost as unpractical as doing the manual selection at the Home Realm Discovery page.

Another solution would be if we could find out something about the user like for example where he’s connecting from, like for example the IP-Address the user’s machine is having and from that make the decision automatically for the user. This is possible since we can get that information from the HTTP request object in a web application. I’m not saying this is a perfect solution since a branch office user might be visiting the main office when the automatic selection is being made and then will be asked to sign in at the wrong Claims Provider.

There are of course more solutions and depending on your requirements there are things that can be made to simplify Home Realm Discovery but I’m going to show you how this can be done by detecting the IP-address of the user as mentioned earlier.

Automatic Home Realm Discovery from user IP-Address - Deluxe

From what I told you before you now know that using the whr query parameter with a slightly modified WIF application will bypass the Home Realm Discovery page and you also know that we easily can replace the Home Realm Discovery page with our own.

Lets just copy the /adfs/ls/HomeRealmDiscovery.aspx and it’s code behind /adfs/ls/HomeRealmDiscovery.aspx.cs and instead name them HomeRealmDiscoveryDeluxe.aspx and HomeRealmDiscoveryDeluxe.aspx.cs.

Before we continue we need something that could help us store the entity Id of our claims providers we wish to assign automatically to users but also an IP address range for knowing between what IP addresses our users should have it’s own IP address for automatically getting a Home Realm. I’ve chosen to call this class AutomatedClaimsProvider and of course it contains some logic to do the IP address calculations. Copy the code below into a new class file named AutomatedClaimsProvider.cs in the App_Code directory (adfs/ls/App_Code)

using System;
using System.Net;

/// <summary>
/// Summary description for IPRange
/// </summary>
public class AutomatedClaimsProvider
/// <summary>
/// Public Constructor
/// </summary>
/// <param name="entityId">Entity Id of the claims provider.</param>
/// <param name="fromIpAddress">IP Address starting the range.</param>
/// <param name="toIpAddress">IP Address ending the range.</param>
public AutomatedClaimsProvider(string entityId, string fromIpAddress, string toIpAddress)
if (IpAddressToLongBackwards(fromIpAddress) > IpAddressToLongBackwards(toIpAddress))
throw new ArgumentException("fromIP can not be bigger then toIpAddress.", fromIpAddress);

EntityId = entityId;
FromIpAddress = fromIpAddress;
ToIpAddress = toIpAddress;

/// <summary>
/// Claim Provider EntityID
/// </summary>
public string EntityId { get; set; }

/// <summary>
/// IP Address starting the range.
/// </summary>
public string FromIpAddress { get; set; }

/// <summary>
/// IP Address ending the range.
/// </summary>
public string ToIpAddress { get; set; }

/// <summary>
/// Function returning true if in IP is within the specified ip range.
/// </summary>
/// <param name="ipAddress">The ip to check.</param>
/// <returns>true if ip is in range otherwise false.</returns>
public bool IsInRange(string ipAddress)
var ip = IpAddressToLongBackwards(ipAddress);
return ip >= IpAddressToLongBackwards(FromIpAddress) && ip <= IpAddressToLongBackwards(ToIpAddress);
// Convert IPAddress to long backwards for comparison.
private static long IpAddressToLongBackwards(string ipAddress)
IPAddress ip;
if (!IPAddress.TryParse(ipAddress, out ip))
throw new ArgumentException(string.Format("The value '{0}' could not be parsed as an IP address.", ipAddress));

var byteIp = ip.GetAddressBytes();
var longIp = (long)byteIp[0] << 24;
longIp += (long)byteIp[1] << 16;
longIp += (long)byteIp[2] << 8;
longIp += byteIp[3];

return longIp;

So far so good but this was just a utility so lets do the real stuff by implementing our Deluxe Home Realm Discovery page we copied earlier. Open the HomeRealmDiscoveryDeluxe.aspx.cs file and add this using statement at the top together with the others.
using System.Collections.Generic;

…Then add this method that will automate the Home Realm Discovery if the user address can be found within the defined IP ranges.

protected void Page_Load(object sender, EventArgs e)
// First we need somewhere to keep our claim providers and while were on it, lets store some Claim Providers,
// this would be better to store in web.config, but for the sake of this example this will have to do.
var claimProviders = new List<AutomatedClaimsProvider>
new AutomatedClaimsProvider("", "", ""), // Local IdP – Empty String.
new AutomatedClaimsProvider(@"", "", ""),
new AutomatedClaimsProvider(@"", "", "")

// Get users IPAddress.
var ipAddress = Request.UserHostAddress;

// Check each AutomatedClaimsProvider if the ip is within its ip range then set Home Realm..
foreach (var claimsProvider in claimProviders.Where(claimsProvider => claimsProvider.IsInRange(ipAddress)))
// Match found, Set Home Realm to found identity provider.

// No match, fall back on Home Realm Discovery page functionality.

The ranges – AutomatedClaimProviders should of course not be hard-coded like this but be placed in web.config or some other suitable place. Simply what this method will do is call the SelectHomeRealm not when the user clicks the Home realm Discovery page submit button but when a match on IP range for a Claims Provider is found.

Everything is now in place except one little detail and that is that we have to select the HomeRealmDiscoveryDeluxe.aspx as our Home Realm discovery page in web.config

<homeRealmDiscovery page="HomeRealmDiscoveryDeluxe.aspx" />


What else can be done

Well, that depend on requirements and of course what information is available but I’ve also made Home Realm Discovery decisions based on what the user has written in the user name field since a customer of mine used their email addresses as user name by putting it in the userPrincipalName attribute in AD. What happens in that case is that when the user have written their user name (email) and leaves the user name textbox a modal dialog is shown using ajax that propose the user to sign in using a predefined claims provider based on the email address.

Posted in: ADFS | Federation | WIF | Windows Identity Foundation | Home Realm Discovery

Tags: , , ,