Active Directory Federation Services (AD FS) 2.0 provides administrators with the option to define custom rules that they can use to determine the behavior of identity claims with the claim rule language. You can use the claim rule language syntax in this topic to create a custom rule that enumerates, adds, deletes, and modifies claims to meet the needs of your organization. You can build custom rules by typing in the claim rule language syntax in the Send Claims Using a Custom Claim rule template.
For more detailed information about claim rules and claim rule templates, see The Role of Claim Rules.
Note |
|
To watch a five-minute video of Stuart Kwan (Principal Group Program Manager for Federated Identity) explaining basic concepts of the claim rule language, click An Introduction to the Claim Rule Language (http://go.microsoft.com/fwlink/?LinkId=163262) to open the video in a new window. |
For more information about how to use custom rules, see When to Use a Custom Claim Rule.
AD FS 2.0 also provides a set of predefined claim issuance and claim acceptance rule templates that you can use to implement common claim rules. In the Edit Claim Rules dialog box for a given trust, you can create a predefined rule—and view the claim rule language syntax that makes up that rule—by clicking the View Rule Language tab for that rule. Using the information in this section and the View Rule Language technique can provide insight into how to construct your own custom rules.
The AD FS 2.0 claim rule language acts as the administrative building block for the behavior of incoming and outgoing claims, while the claims engine acts as the processing engine for the logic in the claim rule language that defines the custom rule. For more information about how all rules are processed by the claims engine, see The Role of the Claims Engine.
How custom rules are processed
Custom rules are processed based on the issuance statements (issue or add) that you program into the claim rule. Depending on the desired outcome, either the issue statement or add statement can be written into the rule to populate the input claim set and/or the output claim set. A custom rule that uses the add statement will explicitly populate claim values only to the input claim set while a custom claim rule that uses the issue statement will populate claim values in both the input claim set and in the output claim set. This can be useful when a claim value is intended to be used only by future rules in the set of claim rules.
For example, in the following illustration, the incoming claim is added to the input claim set by the claims issuance engine. When the first custom claim rule executes and the criteria of domain\user has been satisfied, the claims issuance engine processes the logic in the rule using the add statement, and the value of Editor is added to the input claim set. Because the value of Editor is present in the input claim set, Rule 2 can successfully process the issue statement in its logic and generate a new value of Hello which is added to both the output claim set and to the input claim set for use by the next rule in the rule set. Rule 3 can now use all of the values present in the input claim set as input for processing its logic.
Using the claim rule language to create custom rules
In its most basic form, a rule takes the following form: "If a set of conditions is true, issue one or more claims." Several variations of this basic rule are possible, and you can even combine them to form a more advanced syntax. The following examples show a few of the syntax constructions for conditions and issue statements that you can use to create custom rules.
Condition examples
You can use conditions in a rule to check input claims and determine if the issuance statement of the rule should be executed. Conditions are optional in rules. For example, this rule does not have a condition.
=> issue(type = "http://test/role", value = "employee");
Typical conditions, such as the conditions that are described in the following table, are constructed to simply check for a claim with a specified claim type or for a claim with a specified claim type and claim value.
|
Condition description
|
Condition syntax example
|
|
This rule has a condition to check for an input claim with a specified claim type. If a matching claim is in the input claims, the rule copies the matching claim or claims to the output claims set.
|
c:[type == "http://test/name"] => issue(claim = c);
|
|
This rule has a condition to check for an input claim with a specified claim type and claim value. If a matching claim is in the input claims, the rule copies the matching claim or claims to the output claims set.
|
c:[type == "http://test/name", value == "Terry"] => issue(claim = c);
|
More complex conditions are possible, including conditions to check for multiple claims, conditions to check the issuer of a claim, and conditions to check for values that match a regular expression pattern.
Issuance statement examples
The issuance statement of a rule defines what claims will be issued by the rule when the conditions are matched. Issuance statements may issue claims by using literal values in the rule, values from claims that match the conditions, and attribute stores. The following table describes some common syntax constructions for issuance statements in claim rules.
|
Issuance statement description
|
Issuance statement syntax example
|
|
The following rule always emits the same claim whenever a user has the specified claim type and value:
|
c:[type == "http://test/employee", value == "true"] => issue(type = "http://test/role", value = "employee");
|
|
The following rule converts one claim type into another. Notice that the value of the claim that matches the condition "c" is used in the issuance statement.
|
c:[type == "http://test/group"] => issue(type = "http://test/role", value = c.Value);
|
|
The following rule uses the value of an incoming claim to query the Active Directory attribute store:
|
c:[Type == "http://test/name"]
=> issue(store = "Enterprise AD Attribute Store",
types = ("http://test/email"),
query = ";mail;{0}",
param = c.Value)
|
|
The following rule uses the value of an incoming claim to query a previously configured Structured Query Language (SQL) attribute store:
|
c:[type == "http://test/name"]
=> issue(store = "Custom SQL store",
types = ("http://test/email","http://test/displayname"),
query = "SELECT mail, displayname FROM users WHERE name='{0}'",
param = c.value);
|
Understanding the components of the claim rule language
The components that describe the claim issuance language are explained in this section.
Rule statements
A rule statement consists of a condition, an imply operator, and a rule body. Rules are separated from each other with semicolons.
Condition
A condition represents a logical expression that must be evaluated to true in order to execute the rule body part. If this part is missing, a logical true is assumed; that is, the rule’s body is always executed. The conditions part contains a list of conditions that are combined together with the conjunction logical operator (“&&”). All conditions in the list must be evaluated to true for the whole conditional part to be evaluated to true. The condition can be either a claims selection operator or aggregate function call. These two are mutually exclusive, which means that aggregate functions and claim selectors cannot be combined in a single rule conditions part.
Rule body
The rule body can contain only a single issuance statement. If the claim selectors are used in the conditions part, the rule body is executed as many times as there are claims in the conditions part output collection. If a single claim selector is used, the conditions part output collection is equal to the claim selector return value. If more than one claim selector is used, the conditions part output is equal to a Cartesian product between individual output claim sets as produced by the claims selectors, going from left to right.
Claim issuance actions
The rule body represents a claim issuance action. There are two claim issuance actions that the language recognizes:
-
Issue statement: The issue statement creates a claim that goes to both input and output claim sets. For example, the following statement issues a new claim based on its input claim set:
c:[type == "Name"] => issue(type = "Greeting", value = "Hello " + c.value);
-
Add statement: The add statement creates a new claim that is added only to the input claim set collection. For example, the following statement adds a new claim to the input claim set:
[type == "Name", value == "domain\user"] => add(type = "Role", value = "Editor");
There are three forms of issuance statements, regarding arguments and the statement behavior:
-
Claim copy: The claim copy creates a copy of the existing claim in the output claim set. This issuance form only makes sense when combined with the “issue” issuance statement. When it is combined with “add” issuance statement, it does not have any effect.
-
New claim: Creates a new claim, given the values for various claim properties. Claim.Type must be specified; all other claim properties are optional. The order of arguments for this form is ignored.
-
New claims with values from an attribute store: This form creates claims with values that are retrieved from an attribute store. It is possible to create multiple claim types by using a single issuance statement, which is important for attribute stores that make network or disk input/output (I/O) operations during the attribute retrieval. Therefore, it is desirable to limit the number of roundtrips between the policy engine and the attribute store. It is also legal to create multiple claims for a given claim type. When the attribute store returns multiple values for a given claim type, the issuance statement automatically creates a claim for each returned claim value. An attribute store implementation uses the param arguments to substitute the placeholders in the query argument with values that are provided in param arguments. The placeholders use the same syntax as the .NET String.Format() function (for example, {1}, {2}, and so on). The order of the arguments for this form of issuance is important, and it must be the order which is prescribed in the following grammar.
Expressions
Expressions are used on the right side for both claims selector constraints and issuance statement parameters. There are various kinds of expressions that the language supports. All expressions in the language are string based, which means that they take strings as input and produce strings. Numbers or other data types, such as date/time, in expressions are not supported. The following are the types of expressions that are supported by the language:
-
String literal: String value, delimited by the quote (“) character on both sides.
-
String concatenation of expressions: The result is a string that is produced by concatenation of the left and right values.
-
Function call: The function is identified by an identifier, and the parameters are passed as a comma-delimited list of expressions enclosed in brackets (“()”).
-
Claim’s property access in the form of a variable name DOT property name: The result of the value of the identified claim’s property for a given variable valuation. The variable must first be bound to a claims selector before it can be used in this way. It is illegal to use the variable that is bound to a claims selector inside the constraints for that same claims selector.
The following claim properties are available for access:
-
Claim.Type
-
Claim.Value
-
Claim.Issuer
-
Claim.OriginalIssuer
-
Claim.ValueType
-
Claim.Properties[property_name] (This property returns an empty string if the property_name cannot be found in the claim’s properties collection.)
You can use the RegexReplace function to call inside an expression. This function takes an input expression and matches it with the given pattern. If the pattern matches, the output of the match is replaced with the replacement value.
Aggregate functions
Aggregate functions are used to implement scenarios in which you need to take the set of claims that a claim selector produces and aggregate them into a single value. In the issuance language, the single value that aggregate functions produce is always a number. If the returned number is greater than “0”, the condition is evaluated as logical true and the rule’s body is executed.
The aggregate function “exists” evaluates to “1” if there is at least one claim that is matched by the claim selector argument. It evaluates to “0” if the result from the claim selector is empty. The “origin” claim is issued exactly once, if there is at least one claim in the input claim set collection that has the issuer set to “MSFT”, no matter how many claims have the issuer set to “MSFT”.
exists([issuer == "MSFT"])
=> issue(type = "origin", value = "Microsoft");
Additional references