TechOnTip Weblog

Run book for Technocrats

The Claims Rule Language in Active Directory Federation Services

Posted by Brajesh Panda on March 10, 2014

Original Article: http://windowsitpro.com/active-directory/claims-rule-language-active-directory-federation-services

May 16, 2013
Joji Oshima

Advertisement

Microsoft Active Directory Federation Services (AD FS) uses the Claims Rule Language to issue and transform claims between claims providers and relying parties. Dynamic Access Control, introduced with Windows Server 2012, also uses this common language. The flow of claims follows a basic pipeline. The rules we create define which claims are accepted, processed, and eventually sent to the relying party. In this article, I’ll go over the basics of how AD FS builds claims then dive deep into the language that makes it all work. At the end, you should be able to read a claim rule, understand its function, and write custom rules.

The Basics

Before diving into the language used to manipulate and issue claims, it’s important to understand the basics. A claim is information about a user from a trusted source. The trusted source is asserting that the information is true, and that source has authenticated the user in some manner. The claims provider is the source of the claim. This can be information pulled from an attribute store such as Active Directory (AD), or it can be a partner’s federation service. The relying party is the destination for the claims. This can be an application such as Microsoft SharePoint or another partner’s federation service.

A simple scenario would be AD FS authenticating the user, pulling attributes about the user from AD, and directing the user to the application to consume. The scenario can be more complex by adding partner federation services. In any scenario, we’re taking information from some location and sending it somewhere else. Figure 1 shows a sample relationship between federation servers and an application.


Figure 1: Sample Relationship Between Federation Servers and an Application

 
 

Claim Sets

You need to understand claim sets in relation to the claims pipeline. When claims come in, they’re part of the incoming claim set. The claims engine is responsible for processing each claim rule. It examines the incoming claim set for possible matches and issues claims as necessary. Each issued claim becomes part of the outgoing claim set. Because we have claim rules for claims providers and relying parties, there are claim sets associated with each of them.

  1. Claims come in to the claims provider trust as the incoming claim set.
  2. Claim rules are processed, and the output becomes part of the outgoing claim set.
  3. The outgoing claim set moves to the respective relying party trust and becomes the incoming claim set for the relying party.
  4. Claim rules are processed, and the output becomes part of the outgoing claim set.

     
     

    General Syntax of the Claims Rule Language

    A claim rule consists of two parts: a condition statement and an issuance statement. If the condition statement evaluates true, the issuance statement will execute. The sample claim rule that Figure 2 shows takes an incoming Contoso department claim and issues an Adatum department claim with the same value. These claim types are uniform resource identifiers (URIs) in the HTTP format. URIs aren’t URLs and don’t need to be pages that are accessible on the Internet.


    Figure 2: A Simple Claim Rule

     
     

    Condition Statements

    When a rule fires, the claims engine evaluates all data currently in the incoming claim set against the condition statement. Any property of the claim can be used in the condition statement, but the most common are the claim type and the claim value. The format of the condition statement is c:[query], where the variable c represents a claim currently in the incoming claim set.

    The simple condition statement

    c:[type == "http://contoso.com/department"]

    checks for an incoming claim with the claim type http://contoso.com/department, and the condition statement

    c:[type == "http://contoso.com/department", value == "sales"]

    checks for an incoming claim with the claim type http://contoso.com/department with the value of sales. Condition statements are optional. If you know you want to issue a claim to everyone, you can simply create a rule with the issuance statement.

    Issuance Statements

    There are two types of issuance statements. The first is ADD, which adds the claim to the incoming claim set, but not the outgoing set. A typical use for ADD is to store data that will be pulled in subsequent claim rules. The second is ISSUE, which adds the claim to the incoming and outgoing claim sets. The ISSUE example

    => issue(type = “http://contoso.com/department”, value = “marketing”);

    issues a claim with the type http://contoso.com/department with the value of marketing. The ADD example

    => add(type = “http://contoso.com/partner”, value = “adatum”);

    adds a claim with the type http://contoso.com/partner with the value of adatum. The issuance statement can pull information from the claim found in the condition statement, or it can use static information. The static data example

    c:[type == "http://contoso.com/emailaddress"]
    => issue(type = “http://contoso.com/role”, value = “Exchange User”);

    checks for an incoming claim type http://contoso.com/emailaddress and, if it finds it, issues a claim http://contoso.com/role with the value of Exchange User. The static data example

    c:[type == "http://contoso.com/role"]
    => issue(claim = c);

    checks for an incoming claim type http://contoso.com/role and, if it finds it, issues the exact same claim to the outgoing claim set. An example of pulling data from the claim,

    c:[type == "http://contoso.com/role"]
    => issue(type = “http://adatum.com/role”, value = c.Value);

    checks for an incoming claim type http://contoso.com/role and, if it finds it, issues the exact same claim to the outgoing claim set.

    Multiple Conditions

    Another possibility is to use multiple conditions in the condition statement. The issuance statement will fire only if all conditions are met. Each separate condition is joined with the && operator. For example,

    c1:[type == "http://contoso.com/role", value=="Editor"] &&
    c2:[type == "http://contoso.com/role", value=="Manager"]
    => issue(type = “http://contoso.com/role”, value = “Managing Editor”);

    checks for an incoming claim with the type http://contoso.com/role with a value of Editor and another incoming claim with the type http://contoso.com/role with a value of Manager. If the claims engine finds both, it will issue a claim with the type http://contoso.com/role with the value of Managing Editor.

    The values of claims in any condition can be accessed and joined using the + operator. For example,

    c1:[type == "http://contoso.com/location"] &&
    c2:[type == "http://contoso.com/role"]
    => issue(type = “http://contoso/targetedrole”, value = c1.Value + ” ” c2.Value);

    checks for an incoming claim with the type http://contoso.com/location and separate incoming claim with the type http://contoso.com/role. If it finds both, it will issue a claim with the type http://contoso.com/targetedrole, combining the values of the incoming roles.

    Aggregate Functions

    Up to this point, each claim rule checks individual claims or groups of claims and fires each time there’s a match. There are some circumstances in which this behavior isn’t ideal, however. For example, you might want to look at the entire incoming claim set and make a condition statement based on that. In such cases, you can use the EXISTS, NOT EXISTS, and COUNT functions. The EXISTS function checks whether there are any incoming claims that match; if there are, it fires a rule. The NOT EXISTS function checks whether there are any incoming claims that match; if there aren’t, it fires a rule. The COUNT function counts the number of matches in the incoming claim set.

    The EXISTS example

    EXISTS([type == "http://contoso.com/emailaddress"])
    => issue(type = “http://contoso/role”, value = “Exchange User”);

    checks for any incoming claims with the type http://contoso.com/emailaddress and, if it finds any, issues a single claim with the type http://contoso.com/role and the value of Exchange User. The NOT EXISTS example

    NOT EXISTS([type == "http://contoso.com/location"])
    => add(type = “http://contoso/location”, value = “Unknown”);

    checks for any incoming claims with the type http://contoso.com/location and, if it doesn’t find any, adds a single claim with the type http://contoso.com/location with the value of Unknown. The COUNT example

    COUNT([type == "http://contoso.com/proxyAddresses"]) >= 2
    => issue(type = “http://contoso.com/MultipleEmails”, value = “True”);

    checks for any incoming claims with the type http://contoso.com/proxyAddresses and, if there are two or more, issues a single claim with the type http://contoso.com/MultipleEmails with the value of True.

    Querying Attribute Stores

    By default, AD is the only attribute store created when you install AD FS. You can query LDAP servers or SQL Server systems to pull data to be used in a claim. To utilize another attribute store, you first create the attribute store and enter the appropriate connection string. Figure 3 shows how to create an LDAP server as an attribute store.


    Figure 3: Creating an LDAP Server as an Attribute Store

    Once you create the store, you can query the store from a claim rule. For an LDAP attribute store, the query should be in this format:

    query = <query_filter>;<attributes>

    The parameter sent into the query is represented with the {0} operator. If multiple parameters are sent, they would be {1}, {2}, etc. For example,

    c:[Type == "http://contoso.com/emailaddress"]
    => issue(
      store = “LDAP STORE”,
      types = (“http://contoso.com/attribute1&#8243;, “http://contoso.com/attribute2&#8243;),
      query = “mail={0};attribute1;attribute2″,
      param = c.Value
      );

    queries LDAP STORE for attribute1 and attribute2, where the email address matches, and issues two claims based on the data returned from the query.

    A SQL Server attribute store uses the same basic format of the claim rule language; only the query syntax is different. It follows the standard Transact-SQL format, and the {0} operator is used to pass the parameter. For example,

    c:[Type == "http://contoso.com/emailaddress"]
    => issue(
      store = “SQL STORE”,
      types = (“http://contoso.com/attribute1&#8243;, “http://contoso.com/attribute2&#8243;),
      query = “SELECT attribute1,attribute2 FROM users WHERE email = {0}”,
      param = c.Value
      );

    queries SQL STORE for attribute1 and attribute2, where the email address matches, and issues two claims based on the data returned from the query.

    Regular Expressions

    The use of regular expressions (RegEx) lets you search or manipulate data strings in powerful ways to get a desired result. Without RegEx, any comparisons or replacements must be an exact match. This is sufficient for many situations, but if you need to search or replace based on a pattern, you can use RegEx. RegEx uses pattern matching to search inside strings with great precision. You can also use it to manipulate the data inside the claims.

    To perform a pattern match, you can change the double equals operator (==) to =~ and use special metacharacters in the condition statement. If you’re unfamiliar with RegEx, let’s start with some of the common metacharacters and see what the result is when using them. Table 1 shows basic RegEx metacharacters and their functions.


    RegExReplace

    You can also use RegEx pattern matching in replacement scenarios. This is similar to a find-and-replace algorithm found in many text editors, but it uses pattern matching instead of exact values. To use this in a claim rule, use the RegExReplace() function in the value section of the issuance statement.

    The RegExReplace function accepts three parameters.

  • The first is the string in which you’re searching. You’ll typically want to search the value of the incoming claim (c.Value), but this could be a combination of values (c1.Value + c2.Value).
  • The second is the RegEx pattern you’re searching for in the first parameter.
  • The third is the string value that will replace any matches found.

    The RegExReplace example

    c:[type == "http://contoso.com/role"]
    => issue (Type = “http://contoso.com/role&#8221;, Value =  RegExReplace(c.Value, “(?i)director”, “Manager”);

    passes through any role claims. If any of the claims contain the word Director, RegExReplace will change it to Manager. For example, Director of Finance would pass through as Manager of Finance.

    If you combine the power of RegEx pattern matching with the concepts mentioned earlier in the article, you can accomplish many tasks using the Claims Rule Language.

    Coding Custom Attribute Stores

    AD FS gives you the ability to plug in a custom attribute store if the built-in functionality isn’t sufficient to accomplish your goals. You can use standard .NET code such as toUpper() and toLower() or pull data from any source through the code. This code should be a class library and will need references to the Microsoft.IdentityModel and Microsoft.IdentityServer.ClaimsPolicy assemblies.

    Try Custom!

    Creating custom rules with the Claims Rule Language gives you more flexibility with claims issuance and transformation. It can take a while to familiarize yourself with the syntax, but it becomes much easier with practice. If you want to dive into this language, try writing custom rules instead of using the templates next time.

Posted in Mix & Match | Leave a Comment »

AD FS 2.0 Claims Rule Language Part 2

Posted by Brajesh Panda on February 26, 2014

Original: http://blogs.technet.com/b/askds/archive/2013/05/07/ad-fs-2-0-claims-rule-language-part-2.aspx

Hello, Joji Oshima here to dive deeper into the Claims Rule Language for AD FS. A while back I wrote a getting started poston the claims rule language in AD FS 2.0. If you haven’t seen it, I would start with that article first as I’m going to build on the claims rule language syntax discussed in that earlier post. In this post, I’m going to cover more complex claim rules using Regular Expressions (RegEx) and how to use them to solve real world issues.

An Introduction to Regex

The use of RegEx allows us to search or manipulate data in many ways in order to get a desired result. Without RegEx, when we do comparisons or replacements we must look for an exact match. Most of the time this is sufficient but what if you need to search or replace based on a pattern? Say you want to search for strings that simply start with a particular word. RegEx uses pattern matching to look at a string with more precision. We can use this to control which claims are passed through, and even manipulate the data inside the claims.

Using RegEx in searches

Using RegEx to pattern match is accomplished by changing the standard double equals “==” to “=~” and by using special metacharacters in the condition statement. I’ll outline the more commonly used ones, but there are good resourcesavailable online that go into more detail. For those of you unfamiliar with RegEx, let’s first look at some common RegEx metacharacters used to build pattern templates and what the result would be when using them.

Symbol

Operation

Example rule

^

Match the beginning of a string

c:[type == "http://contoso.com/role", Value =~ "^director"]

=> issue (claim = c);

 
 

Pass through any role claims that start with “director”

$

Match the end of a string

c:[type == "http://contoso.com/email", Value =~ "contoso.com$"]

=> issue (claim = c);

 
 

Pass through any email claims that end with “contoso.com”

|

OR

c:[type == "http://contoso.com/role", Value =~ "^director|^manager"]

=> issue (claim = c);

 
 

Pass through any role claims that start with “director” or “manager”

(?i)

Not case sensitive

c:[type == "http://contoso.com/role", Value =~ "(?i)^director"]

=> issue (claim = c);

 
 

Pass through any role claims that start with “director” regardless of case

x.*y

“x” followed by “y”

c:[type == "http://contoso.com/role", Value =~ "(?i)Seattle.*Manager"]

=> issue (claim = c);

 
 

Pass through any role claims that contain “Seattle” followed by “Manager” regardless of case.

+

Match preceding character

c:[type == "http://contoso.com/employeeId", Value =~ "^0+"]

=> issue (claim = c);

 
 

Pass through any employeeId claims that contain start with at least one “0″

*

Match preceding character zero or more times

Similar to above, more useful in RegExReplace() scenarios.

 
 

Using RegEx in string manipulation

RegEx pattern matching can also be used in replacement scenarios. It is similar to a “find and replace”, but using pattern matching instead of exact values. To use this in a claim rule, we use the RegExReplace() function in the value section of the issuance statement.

The RegExReplace() function accepts three parameters.

  1. The first is the string in which we are searching.
    1. We will typically want to search the value of the incoming claim (c.Value), but this could be a combination of values (c1.Value + c2.Value).
  2. The second is the RegEx pattern we are searching for in the first parameter.
  3. The third is the string value that will replace any matches found.

Example:

c:[type == "http://contoso.com/role"]

=> issue (Type = “http://contoso.com/role“, Value = RegExReplace(c.Value, “(?i)director”, “Manager”);

 
 

Pass through any role claims. If any of the claims contain the word “Director”, RegExReplace() will change it to “Manager”. For example, “Director of Finance” would pass through as “Manager of Finance”.

 
 

Real World Examples

Let’s look at some real world examples of regular expressions in claims rules.

Problem 1:

We want to add claims for all group memberships, including distribution groups.

Solution:

Typically, group membership is added using the wizard and selecting Token-Groups Unqualified Names and map it to the Group or Role claim. This will only pull security groups, not distribution groups, and will not contain Domain Local groups.


We can pull from memberOf, but that will give us the entire distinguished name, which is not what we want. One way to solve this problem is to use three separate claim rules and use RegExReplace() to remove unwanted data.

Phase 1: Pull memberOf, add to working set “phase 1″

 
 

c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]

=> add(store = “Active Directory”, types = (“http://test.com/phase1“), query = “;memberOf;{0}”, param = c.Value);

Example: “CN=Group1,OU=Users,DC=contoso,DC=com” is put into a phase 1 claim.

 
 

Phase 2: Drop everything after the first comma, add to working set “phase 2″

 
 

c:[Type == "http://test.com/phase1"]

=> add(Type = “http://test.com/phase2“, Value = RegExReplace(c.Value, “,[^\n]*”, “”));

Example: We process the value in the phase 1 claim and put “CN=Group1″ into a phase 2 claim.

 
 

Digging Deeper: RegExReplace(c.Value, “,[^\n]*”, “”)

  • c.Value is the value of the phase 1 claim. This is what we are searching in.
  • “,[^\n]*” is the RegEx syntax used to find the first comma, plus everything after it
  • “” is the replacement value. Since there is no string, it effectively removes any matches.

 
 

Phase 3: Drop CN= at the beginning, add to outgoing claim set as the standard role claim

 
 

c:[Type == "http://test.com/phase2"]

=> issue(Type = “http://schemas.microsoft.com/ws/2008/06/identity/claims/role“, Value = RegExReplace(c.Value, “^CN=”, “”));

Example: We process the value in phase 2 claim and put “Group1″ into the role claim

Digging Deeper: RegExReplace(c.Value, “^CN=”, “”)

  • c.Value is the value of the phase 1 claim. This is what we are searching in.
  • “^CN=” is the RegEx syntax used to find “CN=” at the beginning of the string.
  • “” is the replacement value. Since there is no string, it effectively removes any matches.

 
 

Problem 2:

We need to compare the values in two different claims and only allow access to the relying party if they match.

Solution:

In this case we can use RegExReplace(). This is not the typical use of this function, but it works in this scenario. The function will attempt to match the pattern in the first data set with the second data set. If they match, it will issue a new claim with the value of “Yes”. This new claim can then be used to grant access to the relying party. That way, if these values do not match, the user will not have this claim with the value of “Yes”.

 
 

c1:[Type == "http://adatum.com/data1"] &&

c2:[Type == "http://adatum.com/data2"]

=> issue(Type = “http://adatum.com/UserAuthorized“, Value = RegExReplace(c1.Value, c2.Value, “Yes”));

 
 

Example: If there is a data1 claim with the value of “contoso” and a data2 claim with a value of “contoso”, it will issue a UserAuthorized claim with the value of “Yes”. However, if data1 is “adatum” and data2 is “fabrikam”, it will issue a UserAuthorized claim with the value of “adatum”.

 
 

Digging Deeper: RegExReplace(c1.Value, c2.Value, “Yes”)

  • c1.Value is the value of the data1 claim. This is what we are searching in.
  • c2.Value is the value of the data2 claim. This is what we are searching for.
  • “Yes” is the replacement value. Only if c1.Value & c2.Value match will there be a pattern match and the string will be replaced with “Yes”. Otherwise the claim will be issued with the value of the data1 claim.

 
 

Problem 3:

Let’s take a second look at potential issue with our solution to problem 2. Since we are using the value of one of the claims as the RegEx syntax, we must be careful to check for certain RegEx metacharacters that would make the comparison mean something different. The backslash is used in some RegEx metacharacters so any backslashes in the values will throw off the comparison and it will always fail, even if the values match.

Solution:

In order to ensure that our matching claim rule works, we must sanitize the input values by removing any backslashes before doing the comparison. We can do this by taking the data that would go into the initial claims, put it in a holding attribute, and then use RegEx to strip out the backslash. The example below only shows the sanitization of data1, but it would be similar for data2.

Phase 1: Pull attribute1, add to holding attribute “http://adatum.com/data1holder

 
 

c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]

=> add(store = “Active Directory”, types = (“http://adatum.com/data1holder“), query = “;attribute1;{0}”, param = c.Value);

Example: The value in attribute 1 is “Contoso\John” which is placed in the data1holder claim.

 
 

Phase 2: Strip the backslash from the holding claim and issue the new data1 claim

 
 

c:[Type == "http://adatum.com/data1holder", Issuer == "AD AUTHORITY"]

=> issue(type = “http://adatum.com/data1“, Value = RegExReplace(c.Value,”\\”,””);

Example: We process the value in the data1holder claim and put “ContosoJohn” in a data1 claim

Digging Deeper: RegExReplace(c.Value,”\\”,””)

  • c.Value is the value of the data1 claim. This is what we are searching in.
  • “\\” is considered a single backslash. In RegEx, using a backslash in front of a character makes it a literal backslash.
  • “” is the replacement value. Since there is no string, it effectively removes any matches.

 
 

An alternate solution would be to pad each backslash in the data2 value with a second backslash. That way each backslash would be represented as a literal backslash. We could accomplish this by using RegExReplace(c.Value,”\\”,”\\”) against a data2 input value.

 
 

Problem 4:

Employee numbers vary in length, but we need to have exactly 9 characters in the claim value. Employee numbers that are shorter than 9 characters should be padded in the front with leading zeros.

Solution:

In this case we can create a buffer claim, join that with the employee number claim, and then use RegEx to use the right most 9 characters of the combined string.

Phase 1: Create a buffer claim to create the zero-padding

 
 

=> add(Type = “Buffer”, Value = “000000000″);

 
 

Phase 2: Pull the employeeNumber attribute from Active Directory, place it in a holding claim

 
 

c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]

=> add(store = “Active Directory”, types = (“ENHolder”), query = “;employeeNumber;{0}”, param = c.Value);

 
 

Phase 3: Combine the two values, then use RegEx to remove all but the 9 right most characters.

 
 

c1:[Type == "Buffer"]

&& c2:[Type == "ENHolder"]

=> issue(Type = “http://adatum.com/employeeNumber“, Value = RegExReplace(c1.Value + c2.Value, “.*(?=.{9}$)”, “”));

Digging Deeper: RegExReplace(c1.Value + c2.Value, “.*(?=.{9}$)”, “”)

  • c1.Value + c2.Value is the employee number padded with nine zeros. This is what we are searching in.
  • “.*(?=.{9}$)” represents the last nine characters of a string. This is what we are searching for. We could replace the 9 with any number and have it represent the last “X” number of characters.
  • “” is the replacement value. Since there is no string, it effectively removes any matches.

 
 

Problem 5:

Employee numbers contain leading zeros but we need to remove those before sending them to the relying party.

Solution:

In this case we can pull employee number from Active Directory and place it in a holding claim, then use RegEx to use the strip out any leading zeros.

Phase 1: Pull the employeeNumber attribute from Active Directory, place it in a holding claim

 
 

c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]

=> add(store = “Active Directory”, types = (“ENHolder”), query = “;employeeNumber;{0}”, param = c.Value);

 
 

Phase 2: Take the value in ENHolder and remove any leading zeros.

 
 

c:[Type == "ENHolder"]

=> issue(Type = “http://adatum.com/employeeNumber“, Value = RegExReplace(c.Value, “^0*”, “”));

Digging Deeper: RegExReplace(c.Value, “^0*”, “”)

  • c1.Value is the employee number. This is what we are searching in.
  • “^0*” finds any leading zeros. This is what we are searching for. If we only had ^0 it would only match a single leading zero. If we had 0* it would find any zeros in the string.
  • “” is the replacement value. Since there is no string, it effectively removes any matches.

 
 

Conclusion

As you can see, RegEx adds powerful functionality to the claims rule language. It has a high initial learning curve, but once you master it you will find that there are few scenarios that RegEx can’t solve. I would highly recommend searching for an online RegEx syntax tester as it will make learning and testing much easier. I’ll continue to expand the TechNet wiki article so I would check there for more details on the claims rule language.

Understanding Claim Rule Language in AD FS 2.0

AD FS 2.0: Using RegEx in the Claims Rule Language

Regular Expression Syntax

AD FS 2.0 Claims Rule Language Primer

Until next time,

Joji “Claim Jumper” Oshima

 
 

From <http://blogs.technet.com/b/askds/archive/2013/05/07/ad-fs-2-0-claims-rule-language-part-2.aspx>

Posted in Mix & Match | Leave a Comment »

AD FS 2.0 Claims Rule Language Primer – Ask the Directory Services Team – Site Home – TechNet Blogs

Posted by Brajesh Panda on February 26, 2014

Original: https://blogs.technet.com/b/askds/archive/2011/10/07/ad-fs-2-0-claims-rule-language-primer.aspx

 
 

Hi guys, Joji Oshima here again. On the Directory Services team, we get questions regarding the Claims Rule Language in AD FS 2.0 so I would like to go through some of the basics. I’ve written this article for those who have a solid understanding of Claims-based authentication. If you would like to read up on the fundamentals first, here are some good resources.

An Introduction to Claims

http://msdn.microsoft.com/en-us/library/ff359101.aspx

Security Briefs: Exploring Claims-Based Identity

http://msdn.microsoft.com/en-us/magazine/cc163366.aspx

AD FS 2.0 Content Map

http://social.technet.microsoft.com/wiki/contents/articles/2735.aspx

Claims Rules follow a basic pipeline. The rules define which claims are accepted, processed, and eventually sent to the relying party. You define claims rules as a property of the Claims Provider Trust (incoming) and the Relying Party Trust (outgoing).


Basic flowchart for the Claims Pipeline taken from TechNet.

There is also an authorization stage checks if the requestor has access to receive a token for the relying party. You can choose to allow all incoming claims through by setting the Authorization Rules to Permit All. Alternately, you could permit or deny certain users based on their incoming claim set. You can read more about authorization claim rules here and here.

You can create the majority of claims issuance and claims transformations using a Claim Rule Template in AD FS 2.0 Management console, but there are some situations where a custom rule is the only way to get the results you need. For example, if you want to combine values from multiple claims into a single claim, you will need to write a custom rule to accomplish that. To get started, I would recommend creating several rules through the Claim Rule Templates and view the rule language generated. Once you save the template, you can click the View Rule Language button from the Edit Rule window to see how the language works.


 
 


In the screenshot above, the rule translates as follows:

If (there is an incoming claim that matches the type “http://contoso.com/department“)

Then (issue a claim with the type “http://adatum.com/department“, using the Issuer, Original Issuer, Value, and ValueType of the incoming claim)

The claims “http://contoso.com/department” and “http://adatum.com/department” are URIs. These claims can be in the URN or HTTP format. The HTTP format is NOT a URL and does not have to specifically link to actual content on the Internet or intranet.

Claims Rule Language Syntax:

Typically, the claims rule language is structured similarly to an “if statement” in many programming languages.

If (condition is true)

Then (issue a claim with this value)

What this says is “if a condition is true, issue this claim”. A special operator “=>” separates the condition from the issuance statement and a semicolon ends the statement.

Condition statement => issuance statement;

Review some of the claims you created and look at the structure. See if you can pick out each part. Here is the one we looked at in the first section. Let’s break it down in to the basic parts.


The “if statement” condition:

The special operator:

  • =>

The issuance statement:

  • issue(Type = “http://adatum.com/department“, Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, Value = c.Value, ValueType = c.ValueType);

For each rule defined, AD FS checks the input claims, evaluates them against the condition, and issues the claim if the condition is true. You probably notice the variable “C” in the syntax. Think of “C” as an incoming claim that you can check conditions against, and use values from it to add to an outgoing claim. In this example, we are checking if there is an incoming claim that has a type that is “http://contoso.com/department“. We also use the values in this claim to assign the value of Issuer, OriginalIssuer, Value, and ValueType to the outgoing claim.

There are exceptions to this that are discussed later (using ADD instead of ISSUE and issuing a claim without a condition statement).

Issue a claim to everyone:

In the Claims Rule Language, the condition part is optional. Therefore, you can choose to issue or add a claim regardless of what claims are incoming. To do this, start with the special operator “=>“.

Syntax:

You could set similar rules for each Claims Provider Trust so that the Relying Party (or application) can know where the user came from.

Using a Single Condition:

In this example, we will look at a single condition statement. A basic claim rule checks to see if there is an incoming claim with a certain type and if so, issue a claim.

You can create this claim rule using the GUI. Choose the template named “Pass Through or Filter an Incoming Claim” and choose the appropriate incoming claim type.


Screenshot: Entries for a simple pass through claim.

You may also check for multiple values within your condition statement. For example, you can check and see if there is an incoming claim with a specific value. In the following example, we will check for an incoming claim with the type “http://contoso.com/role” that has the value of “Editors” and, if so, issue the exact same claim.

You can create this claim rule using the GUI as well. Choose “Pass Through or Filter an Incoming Claim”, choose the appropriate incoming claim type, select “Pass though only a specific claim value”, then enter the appropriate value.


Screenshot: Entries to pass through the Role claim if the value is “Editors”

Using Multiple Conditions:

Say you want to issue a claim only if the user has an Editor and has an Email claim and, if so, issue the Editor Role claim. To have multiple conditions, we will use multiple “C” variables. We will join the two condition statements with the special operator “&&“.

The first condition (c1) checks to see if you have an incoming role claim with the value of Editors. The second condition (c2) checks to see if there is an incoming email claim. If both conditions are met, it will issue an outgoing claim identical to the incoming c1 claim.

Combining Claim Values:

Say you want to join information together from multiple incoming claims to form a single outgoing claim. The following example will check for an incoming claim type of “http://contoso.com/location” and “http://contoso.com/role“. If it has both, it will issue a new claim, “http://contoso.com/targeted“, combining the two values.

The resulting value is the value of the first claim (c1), plus a space, plus the value of the second claim (c2). You can combine static strings with the values of the claims using the special operator “+“. The example below shows a sample set of incoming claims, and the resulting output claim.

Example Incoming Claims:

http://contoso.com/location” is “Seattle”

http://contoso.com/role” is “Editor”

Example Outgoing Claim:

http://contoso.com/targeted” is “Seattle Editor”

Using ADD instead of ISSUE:

As mentioned in an earlier section, you can ADD a claim instead of ISSUE a claim. You may be wondering what the difference between these two statements are. Using the ADD command instead of the ISSUE command will add a claim to the incoming claim set. This will not add the claim to the outgoing token. Use this for adding placeholder data to use in subsequent claims rules.


This illustration was taken from a TechNet article. Here you can see that the first rule adds a role claim with the value of Editor. It then uses this newly added claim to create a greeting claim. Assuming these are the only two rules, the outgoing token will only have a greeting claim, not a role claim.

I’ve outlined another example below.

Sample Rule 1:

Sample Rule 2:

c:[Type == "http://contoso.com/location", Value=="LAX"]

=> add(Type = “http://contoso.com/region“, Value = “West”);

Sample Rule 3:

In this example, we have two rules that ADD claims to the incoming claim set, and one that issues a claim to the outgoing claim set. This will add a region claim to the incoming claim set and use that to create combine the values to create an area claim. The ADD functionality is very useful with the next section for aggregate functions.

Using aggregate functions (EXISTS and NOT EXISTS):

Using aggregate functions, you can issue or add a single output claim instead of getting an output claim for each match. The aggregate functions in the Claims Rule Language are EXISTS and NOT EXISTS.

Say we want to use the location claim, but not all users have it. Using NOT EXISTS, we can add a universal location claim if the user does not have one.

In Sample Rule 1, we will add a location claim with the value of “Unknown” if the user does not have a location claim. In Sample Rule 2, we will use that value to generate the “http://contoso.com/targeted” claim.

Sample Rule 1:

This way, users without the “http://contoso.com/location” claim can still get the “http://contoso.com/targeted” claim.

Claims Rule Language, beyond this post:

There is more you can do with the Claims Rule Language that goes beyond the scope of this blog post. If you would like to dig deeper by using Custom Attribute Stores and using Regular Expressions in the language, I’ve put up a TechNet Wiki article that contains these advanced topics and other sample syntax. In addition, some other articles may help with these topics.

Understanding Claim Rule Language in AD FS 2.0:

http://social.technet.microsoft.com/wiki/contents/articles/4792.aspx

When to Use a Custom Claim Rule:

http://technet.microsoft.com/en-us/library/ee913558(WS.10).aspx

The Role of the Claim Rule Language:

http://technet.microsoft.com/en-us/library/dd807118(WS.10).aspx

The Role of the Claims Engine:

http://technet.microsoft.com/en-us/library/ee913582(WS.10).aspx

The Role of the Claims Pipeline:

http://technet.microsoft.com/en-us/library/ee913585(WS.10).aspx

Conclusion:

Creating custom rules with the Claims Rule Language gives you more flexibility over the standard templates. Syntax familiarization takes a while, but with some practice, you should be able to write custom rules in no time. Start by writing custom rules instead of using the templates in your lab environment and build on those.

- Joji “small claims court” Oshima

 
 

Inserted from <https://blogs.technet.com/b/askds/archive/2011/10/07/ad-fs-2-0-claims-rule-language-primer.aspx>

Posted in Mix & Match | Leave a Comment »

Exchange Calendar Additional Response HTML Formatting

Posted by Brajesh Panda on February 21, 2014

In last couple of weeks we were setting up our 1st Lync Room System solution from Crestron. To bring awareness about Lync Room System, I used Calendar Additional Response feature in the room mailbox. You can set this txt using shell or MMC GUI

Shell – Set-CalenderResponse – id <Identity> -AddAddtionalResponse $True –AdditionalRespone “TXT”

MMC Gui – Mailbox Properties – Resource Information – Additional Text

Here is the html formatted message for your response & how it looks ;-)

If your meeting request was declined please disregard the rest of this message. <p align="justify"> This message is intended to help with using the new Lync Room System (LRS) in Wilanow Palace. If your meeting request was accepted: Congratulations, you have scheduled a meeting with LRS in this meeting room! LRS is a combination of software and hardware that enables rich meeting scenarios, including video conferencing, white boarding, PowerPoint sharing, and more. We are excited to have you try LRS, and we would love to hear your feedback! To use LRS, you need to schedule a Lync Meeting. Key Scenarios: </p>

<p align="justify"><STRONG>1.) Join Meeting. </STRONG> If you’re reading this mail, you’ve already scheduled a meeting. Just touch the join button on your scheduled meeting to join it. Don’t see a join button? Make your meeting an online meeting in Outlook. </p>

<p align="justify"><STRONG>2.) Launch Whiteboard. </STRONG> You can start white boarding, and then invite participants to share the whiteboard. You can also start white boarding from within a meeting. </p>

<p align="justify"><STRONG>3.) PowerPoint Sharing. </STRONG> You can share your PPT slides with the room. To do this, upload the PPT file into the meeting from your machine (just as in Lync). From the room, you can then watch the PPT presentation, or take control and present. </p>

<p align="justify"><STRONG>4.) Display Modes. </STRONG>Try using different display modes to see which one best fits your meeting. </p>

<p align="justify"> If you run into any issues or have any questions, ideas, or feedback for the feature team, please contact us: Service Desk (ServiceDesk@TechOnTip.com) Thanks! </p>

Your request was accepted.

_____

If your meeting request was declined please disregard the rest of this message.

This message is intended to help with using the new Lync Room System (LRS) in Wilanow Palace. If your meeting request was accepted: Congratulations, you have scheduled a meeting with LRS in this meeting room! LRS is a combination of software and hardware that enables rich meeting scenarios, including video conferencing, white boarding, PowerPoint sharing, and more. We are excited to have you try LRS, and we would love to hear your feedback! To use LRS, you need to schedule a Lync Meeting. Key Scenarios:

1.) Join Meeting. If you’re reading this mail, you’ve already scheduled a meeting. Just touch the join button on your scheduled meeting to join it. Don’t see a join button? Make your meeting an online meeting in Outlook.

2.) Launch Whiteboard. You can start white boarding, and then invite participants to share the whiteboard. You can also start white boarding from within a meeting.

3.) PowerPoint Sharing. You can share your PPT slides with the room. To do this, upload the PPT file into the meeting from your machine (just as in Lync). From the room, you can then watch the PPT presentation, or take control and present.

4.) Display Modes. Try using different display modes to see which one best fits your meeting.

If you run into any issues or have any questions, ideas, or feedback for the feature team, please contact us: Colliers Service Desk (ServiceDesk) Thanks!

_____

Sent by Microsoft Exchange Server 2013

Posted in Mix & Match | Leave a Comment »

How to migrate OU structure from one domain to another

Posted by Brajesh Panda on February 19, 2014

Brajesh Panda:

How to migrate OU structure from one domain to another

Originally posted on iSiek's blog about Microsoft Windows services:

Sometimes you may face an “issue” when you are migrating domain, using ADMT or another tool which does not support OU migration, to the new domain within the same forest or to completely new one.

Do you need then to rebuild everything manually or resign from existing OU scheme? No, you can very simply extract OU structure from one domain and import it to another. To achieve that you need to only use LDIFDE command which is available on any Domain Controller.

In this example, I will show you how to export OUs from one domain to flat text file, modify appropriate part of that file and import it to the new domain.

As you can see below on a screen, in my test environment some Organizational Units already exist. I would like to keep them in my new forest but I do not want to recreate whole structure manually.

View original 375 more words

Posted in Mix & Match | Leave a Comment »

Updating Multi Valued Active Directory Attributes

Posted by Brajesh Panda on February 12, 2014

Example: DepartmentNumber

  • If DepartmentNumber is empty it doesn’t show up with Active Directory Module
    • Get-ADUser <SamAccountName> –properties *
    • Get-ADObjet <DN> -Properties *
  • But Quest Module shows it, does not matter if it is empty or has a value
    • Get-QADUser <SamAccountName> -IncludeAllProperties

Update the DepartmentNumber

DepartmentNumber is a multivalued attribute so value cannot be just set; we need to use a method

  • Add method with Set
    • Get-ADUser <SamAccountName> -Properties * | Set-ADObject -Add @{departmentNumber = ’058′}
    • Get-ADUser <SamAccountName> -Properties * | Set-ADUser -Add @{departmentNumber = ’059′}
  • Remove method with Set
    • Get-ADUser <SamAccountName> -Properties * | Set-ADUser -Remove @{departmentNumber = ’059′}
    • Get-ADUser <SamAccountName> -Properties * | Set-ADUser -Remove @{departmentNumber = ’058′}
  • Replace with Set
  • Clear with Set

Note: op_substraction ( -=) and put method are not supported with active directory module

  • Using Set-QADUser –ObjectAttributes
    • Set-QADUser  -Identity <Identity> -ObjectAttributes @{AttributeName=@{Action=@(‘value1′,’value2′…)}}
      • AttributeName – The LDAP name of the attribute.
      • Action         - The action you want to perform on the attribute value(s). The values
        @(‘value1′,’value2′…) – An array of values.
        • Append  – Adds one or more values to the attribute while preserving any existing entries.
          Clear      – Removes all values and set the attribute value to null.
          Delete    – Removes one or more values from the attribute while preserving any other existing entries.
          Update   – Removes any existing values and then writes one or more new values to the attribute.

Posted in Mix & Match | Leave a Comment »

Office 365: Cannot login to Lync Online IM thru Exchange Online OWA!!

Posted by Brajesh Panda on February 10, 2014

Recently I moved my account to Lync Online. While testing different features noticed, I cannot login to Lync IM thru Exchange Online’s OWA. By the way my mailbox is also in Exchange Online.

Here is a technet article for that; http://technet.microsoft.com/en-us/library/hh533880.aspx

We need to have hosting provider for exchange online integration. After I created that, I am able to login & able to chat with others. Make sure you have switch on pop-up in your browser ;-)

Posted in Mix & Match | Leave a Comment »

Exchange Mailbox Folder Types

Posted by Brajesh Panda on February 10, 2014

While working on Exchange Mailbox Folder Permissions script, came across below Mailbox Folder types… Interesting. Can be retrieve using statistics command and foldertype properties.

Get-MailboxFolderStatistics <Identity> | select folderpath, foldertype | Group-Object foldertype | ft -AutoSize

Posted in Mix & Match | Leave a Comment »

WHOAMI – command

Posted by Brajesh Panda on January 21, 2014

Well lately I learned about this command. Pretty interesting & helpful. Specially finding out UPN, Groups the user account belongs to.

Here is the help file for this command

PS C:\> whoami /?

WhoAmI has three ways of working:

Syntax 1:

WHOAMI [/UPN | /FQDN | /LOGONID]

Syntax 2:

WHOAMI { [/USER] [/GROUPS] [/CLAIMS] [/PRIV] } [/FO format] [/NH]

Syntax 3:

WHOAMI /ALL [/FO format] [/NH]

Description:

This utility can be used to get user name and group information

along with the respective security identifiers (SID), claims,

privileges, logon identifier (logon ID) for the current user

on the local system. I.e. who is the current logged on user?

If no switch is specified, tool displays the user name in NTLM

format (domain\username).

Parameter List:

/UPN Displays the user name in User Principal

Name (UPN) format.

/FQDN Displays the user name in Fully Qualified

Distinguished Name (FQDN) format.

/USER Displays information on the current user

along with the security identifier (SID).

/GROUPS Displays group membership for current user,

type of account, security identifiers (SID)

and attributes.

/CLAIMS Displays claims for current user,

including claim name, flags, type and values.

/PRIV Displays security privileges of the current

user.

/LOGONID Displays the logon ID of the current user.

/ALL Displays the current user name, groups

belonged to along with the security

identifiers (SID), claims and privileges for

the current user access token.

/FO format Specifies the output format to be displayed.

Valid values are TABLE, LIST, CSV.

Column headings are not displayed with CSV

format. Default format is TABLE.

/NH Specifies that the column header should not

be displayed in the output. This is

valid only for TABLE and CSV formats.

/? Displays this help message.

Examples:

WHOAMI

WHOAMI /UPN

WHOAMI /FQDN

WHOAMI /LOGONID

WHOAMI /USER

WHOAMI /USER /FO LIST

WHOAMI /USER /FO CSV

WHOAMI /GROUPS

WHOAMI /GROUPS /FO CSV /NH

WHOAMI /CLAIMS

WHOAMI /CLAIMS /FO LIST

WHOAMI /PRIV

WHOAMI /PRIV /FO TABLE

WHOAMI /USER /GROUPS

WHOAMI /USER /GROUPS /CLAIMS /PRIV

WHOAMI /ALL

WHOAMI /ALL /FO LIST

WHOAMI /ALL /FO CSV /NH

WHOAMI /?

Posted in Mix & Match | Leave a Comment »

Add a Single Line to PowerShell Output like Echo

Posted by Brajesh Panda on January 13, 2014

Write-output "My Output Text"`n | Out-File Latam-Report.txt -Append

Tips

Posted in Mix & Match | Leave a Comment »

UserAccountControl

Posted by Brajesh Panda on December 26, 2013

 

Value Description
512 Enabled Account
514 Disabled Account
544 Enabled, Password Not Required
546 Disabled, Password Not Required
66048 Enabled, Password Doesn’t Expire
66050 Disabled, Password Doesn’t Expire
66080 Enabled, Password Doesn’t Expire & Not Required
66082 Disabled, Password Doesn’t Expire & Not Required
262656 Enabled, Smartcard Required
262658 Disabled, Smartcard Required
262688 Enabled, Smartcard Required, Password Not Required
262690 Disabled, Smartcard Required, Password Not Required
328192 Enabled, Smartcard Required, Password Doesn’t Expire
328194 Disabled, Smartcard Required, Password Doesn’t Expire
328224 Enabled, Smartcard Required, Password Doesn’t Expire & Not Required
328226 Disabled, Smartcard Required, Password Doesn’t Expire & Not Required

Source Credit:

http://www.netvision.com/ad_useraccountcontrol.php

http://support.microsoft.com/kb/305144

http://rajnishbhatia19.blogspot.com/2008/11/active-directory-useraccountcontrol.html

Posted in Mix & Match | Leave a Comment »

Microsoft Direct Access – Two NIC Architecture (Expanded)

Posted by Brajesh Panda on November 6, 2013

This is a two legged Direct Access implementation; where one NIC is in DMZ network & another one in LAN. Expanded version of 2nd option in this diagram http://wp.me/phPxo-nE. Click here to download below visio diagram.

Final Architecture Picture

Posted in Direct Access | 1 Comment »

Bypass On-premise SCP Based Autodiscover for Office 365

Posted by Brajesh Panda on October 17, 2013

While migrating Office 365 mailboxes of one of our partner, I observed if they have local (on premise) Exchange 2010 in their Active Directory Environment, Outlook 2010 will not able to auto discover Office 365 mailbox. Because every time you configure a new outlook profile SCP (Active Directory Integrated Auto Discover) will pull in local Mailbox details. To get out of this situation you have to configure it manually using ExchagneGUID (for server name) + Outlook Anywhere proxy settings. But that’s too much manual work;

But we can disable SCP based autodiscover using below keys & it will able to automatically discover Office 365 mailbox.

[HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Outlook\AutoDiscover]

"PreferLocalXML"=dword:00000000

"ExcludeHttpRedirect"=dword:00000000

"ExcludeHttpsAutodiscoverDomain"=dword:00000000

"ExcludeHttpsRootDomain"=dword:00000001

"ExcludeScpLookup"=dword:00000001

"ExcludeSrvLookup"=dword:00000001

"ExcludeSrvRecord"=dword:00000001

Posted in Mix & Match | Leave a Comment »

Property ArchiveGuid can’t be set on this object because it requires the object to have version 0.10 (14.0.100.0) or later. The object’s current version is 0.1(8.0.535.0)

Posted by Brajesh Panda on October 14, 2013

While enabling Archive mailbox in our Hybrid environment I came across this issue. After investigation I came to know these the mailboxes we migrated directly from Exchange 2007 to Office 365. Well we have 2010 Co-existence servers, but those mailboxes were never moved to exchange 2010 while they are on-premises. Exchange 2007 didn’t have Archiving solution. So we need to update the version number of Mailboxes, so archive commands can work.

Get-RemoteMailbox <Name> | Enable-RemoteMailbox -Archive

Property ArchiveGuid can’t be set on this object because it requires the object to have version 0.10 (14.0.100.0) or later. The object’s current version is 0.1 (8.0.535.0).

Check Exchange Mailbox version thru PowerShell

  • On-Premise Mailbox = Get-Mailbox <Name> | Select ExchangeVersion
  • Office 365 Mailbox = Get-RemoteMailbox <Name> | Select ExchangeVersion

Can also be verified from AD User’s attribute; thru ADSI or AD PowerShell

Get-ADUser SaMAccount -Properties * | select msExchVersion

Here is the version table for mailboxes;

Exchange Version Mailbox Version (ExchangeVersion) AD Attribute (msExchVersion)
2007 0.1 (8.0.535.0) 4535486012416
2010 0.10 (14.0.100.0) 44220983382016

We can change to new 2010 version by editing the attribute thru Active Directory Attribute Editor/ADSIEdit/Powershell

Quest Active Directory PowerShell;

Get-QADUser <SamAccount>| Set-QADUser -ObjectAttributes @{msExchVersion=’44220983382016′}

Default Active Directory Module

$user = Get-ADUser <SamAccountName> -Properties msExchVersion

$user.msExchversion = “44220983382016″

Set-ADUser -Instance $user

Here is the MS KB Article

http://support.microsoft.com/kb/2788366

Posted in Mix & Match | Leave a Comment »

Working with Non-Default Active Directory Properties through PowerShell

Posted by Brajesh Panda on October 14, 2013

Active Directory PowerShell Module’s GET cmdlets or Quest Active Directory PowerShell module’s GET cmdlets do not retrieve all properties of an AD Object.

Same thing, if you want to edit those non-default properties their SET cmdlets do not come with all parameters.

Here are the tricks how to work with them ;-)

How to retrieve all those non-default attributes/properties?

Default AD Module = Get-ADUser <SamAccountName> -properties * | Format-List

Quest AD Module = Get-QADUser <SamAccountName> -IncludeAllProperties | Format-List

How to retrieve specific non-default attribute/property?

Default AD Module = Get-ADUser <SamAccountName> -properties * |select msExchVersion

Quest AD Module = Get-QADUser <SamAccountName> -IncludeAllProperties |select msExchVersion

How to edit specific non-default attribute/property?

Default AD Module;

The Instance parameter provides a way to update a user object by applying the changes made to a copy of the object. When you set the Instance parameter to a copy of an Active Directory user object that has been modified, the Set-ADUser cmdlet makes the same changes to the original user object. To get a copy of the object to modify, use the Get-ADUser object. The Identity parameter is not allowed when you use the Instance parameter

# Retrieve Default + Other specific attributes to variable to a variable

$User = Get-ADUser <SamAccountName> -properties msExchVersion

# Change the value of specific attribute in the variable

$User.msExchversion = "NewValue"

# Update the actual object using the modified variable

Set-ADUser <SamAccountName> -instance $User

Quest AD Module

Use ObjectAttributes parameter

Set-QADUser <SamAccountName> -objectattributes @{msExchVersion=’Newvalue’}

Posted in Mix & Match | Leave a Comment »

 
Follow

Get every new post delivered to your Inbox.

Join 54 other followers

%d bloggers like this: