AD FS 2.0 Issuance Authorization Rules: ensure two attributes match

I previously posted a couple of examples of AD FS 2.0 Issuance Authorization (AuthZ) Rules that I’ve used.  Troy posted a comment asking whether or not there is a way to ensure that two attributes match.  His specific example was can we only grant access if we can guarantee that UPN and e-mail are the same.

The short answer is yes, you can do this.  Although it wasn’t easy!  Smile

At first I figured we’d use a combination of exists and regex however that won’t work because there’s no way of injecting variables into the regex and if you did something like exists(Type = sometype, Value =~ someregex) && (Type = sometype, Value =~ someregex) that would match anything that matched the regex, e.g. paul@contoso.com and chuck@fabrikam.com.

My colleague Rahul Gangwar, an AD FS and WIF expert, pointed me in the right direction.  He said to use two rules.  One to create a temporary claim that is a concatenation and the second to parse it for equality.  How to deduce equality in a regex?  As I’ve already stated you can’t compare two values using the same regex and you can’t use repetition.  You can, however, use back-references.

So after several attempts, and thanks to the indispensable RegEx Builder, I finally worked out a regex that matches two e-mail addresses with a delimiter:

(?i)(^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4});\1

With the background described let’s look at how we achieve Troy’s ask.  We need two AuthZ rules:

  1. Concatenate
  2. Match

Here they are:

Concatenate equality values

c1:[Type == “http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn“]
&& c2:[Type == “http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress“]
=> add(Type = “http://tmp/emailupn“, Value = c1.Value + “;” + c2.Value);

Compare values

c:[Type == “http://tmp/emailupn”, Value =~ “(?i)(^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4});\1”]
=> issue(Type = “http://schemas.microsoft.com/authorization/claims/permit”, Value = “true”);

The first rule, concatenate equality values, adds the UPN claim and the Email Address claim, delimited by a semi-colon, into a single temporary claim of the arbitrary type http://tmp/emailupn.

The second rule, compare values, issues a permit claim if the UPN and the e-mail address match.  The match is case-insensitive, i.e. paul.williams@contoso.com and Paul.Williams@contoso.com are the same.

Summary

I probably shouldn’t have used UPN and email as an example for this technique as it’s a bit of a tricky example.  But I wanted to address the comment.  After all, Troy was good enough to read my post and comment.  The approach is sound and can be used for other values too.  You just need to adopt the regex, e.g. (?i)(\w+);\1 would match any two words, so you could check two simple string values.  I think it wise to always perform a case-insensitive match via (?i) and let me give you a tip – don’t double escape like you would in C# or Java…

Advertisements

About Paul Williams

IT consultant working for Microsoft specialising in Identity Management and Directory Services.
This entry was posted in AD FS and tagged , , , , , . Bookmark the permalink.

4 Responses to AD FS 2.0 Issuance Authorization Rules: ensure two attributes match

  1. Maikel says:

    Great blog!
    Do you also know if it is possible to configure the error handling for the access denied message?
    Now it depends on the protocol that the RP uses, WS-Federation uses the ADFS2.0 error.aspx and SAML sends the message back to the RP for handling.

    Regards,
    Maikel.

  2. TS says:

    Hi,
    thats the Solution i searched for, but i didnt work for me with ADFS 3, should it?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s