Active Directory Federation Services 2 has an amazing amount of power when it comes
to claims transformation. To understand how it works lets take a look at a set
of claims rules and the flow of data from ADFS to the Relying Party:
We can have multiple rules to transform claims, and each one takes precedence via
an Order:
In the case above, Transform Rule 2 transformed the claims that Rule
1 requested from the attribute store, which in this case was Active Directory.
This becomes extremely useful because there are times when some of the data you need
to pull out of Active Directory isn’t in a useable format. There are a couple
options to fix this:
-
Make the receiving application deal with it
-
Modify it before sending it off
-
Ignore it
Lets take a look at the second option (imagine an entire blog post on just ignoring
it…). ADFS allows us to transform claims before they are sent off in the token
by way of the Claims
Rule Language. It follows the pattern: "If a set of conditions is true,
issue one or more claims." As such, it’s a big Boolean system. Syntactically,
it’s pretty straightforward.
To issue a claim by implicitly passing true:
=> issue(Type = "http://MyAwesomeUri/claims/AwesomeRole", Value = "Awesome
Employee");
What that did was ignored the fact that there weren’t any conditions and will always
pass a value.
To check a condition:
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
Value == "SomeRole"]
=> issue(Type = "http://MyAwesomeUri/claims/AwesomeRole",
Value = "AwesomeRole");
Breaking down the query, we are checking that a claim created in a previous step has
a specific type; in this case role and the claim’s value is SomeRole.
Based on that we are going to append a new claim to the outgoing list with a new type
and a new value.
That’s pretty useful in it’s own right, but ADFS can actually go even further by allowing
you to pull data out of custom data stores by way of Custom Attribute Stores.
There are four options to choose from when getting data:
-
Active Directory (default)
-
LDAP (Any directory that you can query via LDAP)
-
SQL Server (awesome)
-
Custom built store via custom .NET assembly
Let’s get some data from a SQL database. First we need to create the attribute
store. Go to Trust Relationships/Attribute Stores in the ADFS MMC Console (or
you could also use PowerShell):
Then add an attribute store:
All you need is a connection string to the database in question:
The next step is to create the query to pull data from the database. It’s surprisingly
straightforward. This is a bit of a contrived example, but lets grab the certificate
name and the certificate hash from a database table where the certificate name is
equal to the value of the http://MyCertUri/UserCertName claim type:
c:[type == http://MyCertUri/UserCertName]
=> issue(store = "MyAttributeStore",
types = ("http://test/CertName",
"http://test/CertHash"),
query = "SELECT CertificateName,
CertificateHash FROM UserCertificates WHERE CertificateName='{0}'", param = c.value);
For each column you request in the SQL query, you need a claim type as well.
Also, unlike most SQL queries, to use parameters we need to use a format similar to
String.Format instead of using @MyVariable syntaxes.
In a nutshell this is how you deal with claims transformation. For a more in
depth article on how to do this check out TechNet: http://technet.microsoft.com/en-us/library/dd807118(WS.10).aspx.