I am willing to bet that 90% of the time you have created claims you never really noticed that there are actually 3 tabs for claims that you can use.
Most of the time, we are just messing with the “Issuance Transform Rules.” When you walk through the “Add a Relying Party” Wizard, you may not notice the claim that gets created automatically in “Issuance Authorization Rules.”
Here is a screen shot of the rule that says “Allow everyone”
If we look at the claim, we can see that it is of type permit and the value it true
You can also create a rule that says “Deny someone with this value of a claim.” For instance, I can add a rule that says “Deny access to this Relying Party if anyone tries to log in and has a claim of type Name with a value that looks like “Andy”
By the way, the =~ syntax is saying If a claim of type Name has a value that matches the regular expression, then issue the claim of type deny with a value of “DenyUsersWithClaim.”
You can also issue a strict deny all by doing a straight deny like this
=> issue(Type = "http://schemas.microsoft.com/authorization/claims/deny", Value = "true");
So this is all great but what if you need to combine some of these rules and perhaps make an exception for a handful of users. When I first started messing with this, I figured these authorization claim rules would act like a firewall policy. It would start at the top, and then would act on the first rule that it matched, and then processing would stop. THIS IS NOT THE CASE. What made me really think this was the case was that there is an option to rearrange the order of the claims.
You wish it were so easy! It turns out that if there is a “Deny” rule that matches a users claim anywhere, it will always win, no matter where on the list it is. So in this case, even though permit all is first, if I have a claim that says my “Name” is “Andy” then I will get a denied access error.
We have to get a little tricky. Lets say we want to deny everyone from a particular Identity Provider except for 3 separate users. How would we go about it. Here is one way.
First, lets figure out an easy way to determine at the claims authorization rule, which IDP the user came from. If you go to “Trust Relationships | Claims Provider Trusts” You will see a trust for Active Directory and any other IDP’s that you have added. For the sake of demonstration, lets say you have one called Contoso. Right click on the Contoso IDP and select “Edit Claim Rules”
You can add a claim using a custom rule. Choose “Send Claims Using a Custom Rule.” You can use any namespace that you want. I would suggest using one namespace for custom claims and sticking with it. For this demo, I am using http://sso.contoso.com/users
This rule will add a claim to all users that log in from the Contoso STS that says “Company” = “Contoso”
All right so now we have the claim for people from Contoso, but we want to create exemptions for email@example.com, firstname.lastname@example.org, and email@example.com.
To do this, we need to go back to our Relying Party Authorization Rules and add a new custom rule.
Here’s how this rule breaks down. For a bit more details, I would highly suggest reading through the claims rule language primer.
Here’s the actual claim rule
c1:[Type == "http://sso.contoso.com/users/Company", Value =~ "^(?i)Contoso$"]
&& c2:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn", Value =~ "(?<!foo|bar|andy)@contoso.com"]
=> issue(Type = "http://schemas.microsoft.com/authorization/claims/deny", Value = "DenyUsersWithClaim");
Here’s the basic logic of the claim rule
If ((claim.Company matches “Contoso”) AND (claim.upn –NOTEQUAL (firstname.lastname@example.org OR email@example.com OR firstname.lastname@example.org)) Then (Issue “DenyUsersWithClaim”)
Perhaps the trickiest part here is the REGEX that filters out the exceptions. Basically, the “!” says “not match” and the “|” symbol is the Alternation operator – or functionally the "-or” operator.
Now, all users from Contoso will get denied access except for the 3 that match the regex.