Rule Engine

The Identity Panel Rule Engine is a high performance expression language that takes a context object as an argument and returns a value.

Like many DSLs (Domain Specific Language), the Rule Engine is not Turing Complete, which means it is not a full programming language. However, the Rule Engine is extensible, and new functions for the Rule Engine can be written in any .NET programming language.

The Rule Engine is used to handle advanced trigger and value transformation logic for many aspects of Identity Panel:

Because the Rule Engine is used to support so many features, and because it represents one of the major points of extensibility for the Panel platform, users who want to do advanced administration tasks should familiarize themselves with Rule Engine syntax.

Rule DSL

Rules are composed of one or more sub-rules, which may be nested as deep as necessary. At the base level, there are five primitive Rule types. For every settings field which supports the Rule Engine, a helper interface may be accessed by double-clicking or ctrl+clicking inside the text box.

Rule Help

Testing Rules

Because the Rule Engine allows the development of fairly complex logic, it will often be necessary to test whether a given rule produces the correct value for the input. For this reason the Panel Extensions solution includes a Unit Test project called SoftwareIDM.RuleTests. This test project includes a range of unit tests illustrating the use of different kinds of rules, and new unit tests may be added at your convenience to validate rules before adding them to settings.

Value Lookup

Special values are helpers to support fast lookup of values that the user should not have to remember. Special values are inserted into the rule as a dotted set of names, then converted to the real value when the rule is evaluated.

Examples of special values are:

  • Numeric values of History Counters
  • Guid Ids of Silo Search Indices (which match ObjectRecord.SearchIndex and indicate the provider and data set, such as a MIM Active Directory MA)
  • Names of attributes used by different objects that have been saved

Value Lookup

The syntax for special values is:

special.List Name.Value Name

For example, the Import Add counter from Management Agent run history would be:

special.History Counter.Import Add

Note that identifiers for special values (and Object Properties) may contain letters, numbers, colons, spaces, and hyphens. Parts of an identifier are always separated by periods.

The lookup lists and translation logic for special values are supported by classes that implement the ISpecialValues interface. You can also create your own special value helpers by implementing this interface and adding the dll to the modules list in config.json.

Interface Declaration

public interface ISpecialValues
{
    string Name { get; }

    Dictionary<string, object> Values { get; }
}

Sample Implementation

/// <summary>
/// Lookup numeric values of Modification type Flags Enum
/// </summary>
public class ModTypeSpecial : ISpecialValues
{
    public string Name
    {
        get { return "Object Change Type"; }
    }

    Dictionary<string, object> values;
    public Dictionary<string, object> Values
    {
        get
        {
            if (values == null)
            {
                values = new Dictionary<string, object>
                {
                    { "None", (long)(int)ModType.None },
                    { "Add",  (long)(int)ModType.Add },
                    { "Add Disconnect",  (long)(int)ModType.AddDisconnect },
                    { "Clear Pending",  (long)(int)ModType.ClearPendingStatus },
                    { "Connect",  (long)(int)ModType.Connect },
                    { "Data Retention",  (int)ModType.DataRetention },
                    { "Delete",  (long)(int)ModType.Delete },
                    { "Disconnect",  (long)(int)ModType.Disconnect },
                    { "Error",  (long)(int)ModType.Error },
                    { "Move",  (long)(int)ModType.Move },
                    { "Set Pending",  (long)(int)ModType.PendingStatus },
                    { "Rename",  (long)(int)ModType.Rename },
                    { "Update",  (long)(int)ModType.Update }
                };
            }

            return values;
        }
    }
}

The first time a special value is accessed, the Values dictionary is cached in memory so that subsequent lookups are low latency.

Literal Values

Rules support literal values for strings, integers, hexadecimal integers, decimal numbers, booleans, null values, timestamps, and datetimes. Wherever possible the Rule Engine supports automatic type conversion between values.

Examples:

  • "John Doe"
  • "Value \"Quoted\" with \r\nEscape \tCharacters"
  • 5
  • -2.3
  • 0x200
  • true
  • null
  • "0.12:00:00.000"
  • "2015-01-01 00:00:00.000"

Literal Help

Operators and Parentheticals

The Rule Engine supports operators for boolean expressions and string concatenation. There is no order of precedence for operators. They are simply applied in greedy fashion from left to right. For this reason, when you use multiple operators it is usually wise to enclose them with parentheses to indicate the desired order of application.

Concatenation and Addition

Rules may be joined with the '+' operator to perform string concatenation or numeric addition.

The '+' operator will perform numeric addition if both left and right arguments are intrinsically numeric (long or double).

In all other cases the arguments are converted to strings and concatenated.

To force concatenation, you may first concatenate with an empty string e.g. (1 + "") + 2

Comparison

  • <
  • >
  • <=
  • >=
  • ==

Boolean Boolean operators support short-circuit evaluation.

  • &&
  • ||

Examples:

  • BitAnd(context.Attributes.userAccountControl, 512) > 0
  • context.DN == "John Doe"
  • Length(context.Attributes.employeeID) >= 5
  • 5 <= Length(context.Attributes.employeeID)
  • "John Doe started " + Now() + " with Emplid " + 12345

Operator Help

Function Calls

One of the most complex and powerful kinds of rule is a function call.

Functions may take either position based or named parameter arguments. The last argument of a function may be a list or dictionary.

The panel platform includes dozens of pre-built functions for manipulating primitive types like string or number, and for working with lists. It is also possible to create your own functions by implementing the IRuleFunctions interface.

Functions are documented inline using the ClassDoc and MemberDoc attributes. This inline documentation is used to construct the help interface.

Examples:

Left("string", 3) Mid(str="string", start=2, count=3)

Function Help

Object Properties

The Rule Engine uses dotted notation to lookup values on objects. Any .NET object can have it's properties traversed. The same dotted notation is used for:

  • Field value lookup
  • Property value lookup
  • List<T> indexing
  • Dictionary<T,P> indexing

Object properties may optionally start with the keyword context. This can be used to make the rule type more visually apparent.

In the case of list indexes, positive numbers count from the beginning of the list, and negative numbers count backwards from the end of the list. It is also possible to use special values as indices in a field traversal.

For dictionary indexing, only primitive types like String, Integer, Guid, and DateTime are supported as indices.

Object Properties Help

Examples:

Attributes.sAMAccountName

Attributes.First Name

Counters.2 > 10

Counters.special.Sync Counters.Import Update > 10

context.Changes.0.Attributes.sAMAccountName.Value

context.Changes.-1.Attributes.Account Name.Value

Copyright © SoftwareIDM

Table of Contents