diff options
Diffstat (limited to 'odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/mapping.rst')
-rw-r--r-- | odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/mapping.rst | 1609 |
1 files changed, 0 insertions, 1609 deletions
diff --git a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/mapping.rst b/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/mapping.rst deleted file mode 100644 index 33635502..00000000 --- a/odl-aaa-moon/aaa/aaa-authn-api/src/main/docs/mapping.rst +++ /dev/null @@ -1,1609 +0,0 @@ -Operation Model -=============== - -The assertions from an IdP are stored in an associative array. A -sequence of rules are applied, the first rule which returns success is -considered a match. During the execution of each rule values from the -assertion can be tested and transformed with the results selectively -stored in variables local to the rule. If the rule succeeds an -associative array of mapped values is returned. The mapped values are -taken from the local variables set during the rule execution. The -definition of the rules and mapped results are expressed in JSON -notation. - -A rule is somewhat akin to a function in a programming language. It -starts execution with a set of predefined local variables. It executes -statements which are grouped together in blocks. Execution continues -until an `exit`_ statement returning a success/fail result is -executed or until the last statement is reached which implies -success. The remaining statements in a block may be skipped via a -`continue`_ statement which tests a condition, this is equivalent to -an "if" control flow of logic in a programming language. - -Rule execution continues until a rule returns success. Each rule has a -`mapping`_ associative array bound to it which is a template for the -transformed result. Upon success the `mapping`_ template for the -rule is loaded and the local variables from the successful rule are -used to populate the values in the `mapping`_ template yielding the -final mapped result. - -If no rules returns success authentication fails. - - -Pseudo Code Illustrating Operational Model ------------------------------------------- - -:: - - mapped = null - foreach rule in rules { - result = null - initialize rule.variables with pre-defined values - - foreach block in rule.statement_blocks { - for statement in block.statements { - if statement.verb is exit { - result = exit.status - break - } - elif statement.verb is continue { - break - } - } - if result { - break - } - if result == null { - result = success - } - if result == success { - mapped = rule.mapping(rule.variables) - } - return mapped - - - -Structure Of Rule Definitions -============================= - -Rules are loaded by the rule processor via a JSON document called a -rule definition. A definition has an *optional* set of mapping -templates and a list of rules. Each rule has specifies a mapping -template and has a list of statement blocks. Each statement block has -a list of statements. - -In pseudo-JSON (JSON does not have comments, the ... ellipsis is a -place holder): - -:: - - { - "mappings": { - "template1": "{...}", - "template2": "{...}" - }, - "rules": [ - { # Rule 0. A rule has a mapping or a mapping name - # and a list of statement blocks - - "mapping": {...}, - # -OR- - "mapping_name": "template1", - - "statement_blocks": [ - [ # Block 0 - [statement 0] - [statement 1] - ], - [ # Block 1 - [statement 0] - [statement 1] - ], - - ] - }, - { # Rule 1 ... - } - ] - - } - -Mapping -------- - -A mapping template is used to produce the final associative array of -name/value pairs. The template is a JSON Object. The value in a -name/value pair can be a constant or a variable. If the template value -is a variable the value of the variable is retrieved from the set of -local variables bound to the rule thereby replacing it in the final -result. - -For example given this mapping template and rule variables in JSON: - -template: - -:: - - { - "organization": "BigCorp.com", - "user: "$subject", - "roles": "$roles" - } - -local variables: - -:: - - { - "subject": "Sally", - "roles": ["user", "admin"] - } - -The final mapped results would be: - -:: - - { - "organization": "BigCorp.com", - "user: "Sally", - "roles": ["user", "admin"] - } - - -Each rule must bind a mapping template to the rule. The mapping -template may either be defined directly in the rule via the -``mapping`` key or referenced by name via the ``mapping_name`` key. - -If the ``mapping_name`` is specified the mapping is looked up in a -table of mapping templates bound to the Rule Processor. Using the name -of a mapping template is useful when many rules generate the exact -same template values. - -If both ``mapping`` and ``mapping_name`` are defined the locally bound -``mapping`` takes precedence. - -Syntax ------- - -The logic for a rule consists of a sequence of statements grouped in -blocks. A statement is similar to a function call in a programming -language. - -A statement is a list of values the first of which is a verb which -defines the operation the statement will perform. Think of the -`verbs`_ as function names or operators. Following the verb are -parameters which may be constants or variables. If the statement -assigns a value to a variable left hand side of the assignment (lhs) -is always the first parameter following the verb in the list of -statement values. - -For example this statement in JSON: - -:: - - ["split", "$groups", "$assertion[Groups]", ":"] - -will assign an array to the variable ``$groups``. It looks up the -string named ``Groups`` in the assertion which is a colon (:) -separated list of group names splitting that string on the colon -character. - -Statements **must** be grouped together in blocks. Therefore a rule is -a sequence of blocks and block is a sequence of statements. The -purpose of blocks is allow for crude flow of control logic. For -example this JSON rule has 4 blocks. - -:: - - [ - [ - ["set", $user, ""], - ["set", $roles, []] - ], - [ - ["in", "UserName", "$assertion"], - ["continue", "if_not_success"], - ["set", "$user", "$assertion[UserName"], - ], - [ - ["in", "subject", "$assertion"], - ["continue", "if_not_success"], - ["set", "$user", "$assertion[subject]"], - ], - [ - ["length", "$temp", "$user"], - ["compare", "$temp", ">", 0], - ["exit", "rule_fails", "if_not_success"] - ["append" "$roles", "unprivileged"] - ] - ] - -The rule will succeed if either ``UserName`` or ``subject`` is defined -in the assertion and if so the local variable ``$user`` will be set to -the value found in the assertion and the "unprivileged" role will be -appended to the roles array. - -The first block performs initialization. The second block tests to see -if the assertion has the key ``UserName`` if not execution continues -at the next block otherwise the value of UserName in the assertion is -copied into the variable ``$user``. The third block performs a similar -operation looking for a ``subject`` in the assertion. The fourth block -checks to see if the ``$user`` variable is empty, if it is empty the -rule fails because it didn't find either a ``UserName`` nor a -``subject`` in the assertion. If ``$user`` is not empty the -"unprivileged" role is appended and the rule succeeds. - -Data Types ----------- - -There are 7 supported types which equate to the types available in -JSON. At the time of this writing there are 2 implementations of this -Mapping specification, one in Python and one in Java. This table -illustrates how each data type is represented. The first two columns -are definitions from an abstract specification. The JSON column -enumerates the data type JSON supports. The Mapping column lists the -7 enumeration names used by the Mapping implemenation in each -language. The following columns list the concrete data type used in -that language. - -+-----------+------------+--------------------+---------------------+ -| JSON | Mapping | Python | Java | -+===========+============+====================+=====================+ -| object | MAP | dict | Map<String, Object> | -+-----------+------------+--------------------+---------------------+ -| array | ARRAY | list | List<Object> | -+-----------+------------+--------------------+---------------------+ -| string | STRING | unicode (Python 2) | String | -| | +--------------------+ | -| | | str (Python 3) | | -+-----------+------------+--------------------+---------------------+ -| | INTEGER | int | Long | -| number +------------+--------------------+---------------------+ -| | REAL | float | Double | -+-----------+------------+--------------------+---------------------+ -| true | | | | -+-----------+ BOOLEAN | bool | Boolean | -| false | | | | -+-----------+------------+--------------------+---------------------+ -| null | NULL | None | null | -+-----------+------------+--------------------+---------------------+ - - -Rule Debugging and Documentation --------------------------------- - -If the rule processor reports an error or if you're debugging your -rules by enabling DEBUG log tracing then you must be able to correlate -the reported statement to where it appears in your rule JSON source. A -message will always identify a statement by the rule number, block -number within that rule and the statement number within that -block. However once your rules become moderately complex it will -become increasingly difficult to identify a statement by counting -rules, blocks and statements. - -A better approach is to tag rules and blocks with a name or other -identifying string. You can set the `Reserved Variables`_ -``rule_name`` and ``block_name`` to a string of your choice. These -strings will be reported in all messages along with the rule, block -and statement numbers. - -JSON does not permit comments, as such you cannot include explanatory -comments next to your rules, blocks and statements in the JSON -source. The ``rule_name`` and ``block_name`` can serve a similar -purpose. By putting assignments to these variables as the first -statement in a block you'll both document your rules and be able to -identify specific statements in log messages. - -During rule execution the ``rule_name`` and ``block_name`` are -initialized to the empty string at the beginning of each rule and -block respectively. - -The above example is augmented to include this information. The rule -name is set in the first statement in the first block. - -:: - - [ - [ - ["set", "$rule_name", "Must have UserName or subject"], - ["set", "block_name", "Initialization"], - ["set", $user, ""], - ["set", $roles, []] - ], - [ - ["set", "block_name", "Test for UserName, set $user"], - ["in", "UserName", "$assertion"], - ["continue", "if_not_success"], - ["set", "$user", "$assertion[UserName"], - ], - [ - ["set", "block_name", "Test for subject, set $user"], - ["in", "subject", "$assertion"], - ["continue", "if_not_success"], - ["set", "$user", "$assertion[subject]"], - ], - [ - ["set", "block_name", "If not $user fail, else append unprivileged to roles"], - ["length", "$temp", "$user"], - ["compare", "$temp", ">", 0], - ["exit", "rule_fails", "if_not_success"] - ["append" "$roles", "unprivileged"] - ] - ] - - - - -Variables ---------- - - -Variables always begin with a dollar sign ($) and are followed by an -identifier which is any alpha character followed by zero or more -alphanumeric or underscore characters. The variable may optionally be -delimited with braces ({}) to separate the variable from surrounding -text. Three types of variables are supported: - -* scalar -* array (indexed by zero based integer) -* associative array (indexed by string) - -Both arrays and associative arrays use square brackets ([]) to specify -a member of the array. Examples of variable usage: - -:: - - $name - ${name} - $groups[0] - ${groups[0]} - $properties[key] - ${properties[key]} - -An array or an associative array may be referenced by it's base name -(omitting the indexing brackets). For example the associative array -array named "properties" is referenced using it's base name -``$properties`` but if you want to access a member of the "properties" -associative array named "duration" you would do this ``$properties[duration]`` - -This is not a general purpose language with full expression -syntax. Only one level of variable lookup is supported. Therefore -compound references like this - -:: - - $properties[$groups[2]] - -will not work. - - -Escaping -^^^^^^^^ - -If you need to include a dollar sign in a string (where it is -immediately followed by either an identifier or a brace and identifier) -and do not want to have it be interpreted as representing a variable -you must escape the dollar sign with a backslash, for example -"$amount" is interpreted as the variable ``amount`` but "\\$amount" -is interpreted as the string "$amount" . - - -Reserved Variables ------------------- - -A rule has the following reserved variables: - -assertion - The current assertion values from the federated IdP. It is a - dictionary of key/value pairs. - -regexp_array - The regular expression groups from the last successful regexp match - indexed by number. Group 0 is the entire match. Groups 1..n are - the corresponding parenthesized group counting from the left. For - example regexp_array[1] is the first group. - -regexp_map - The regular expression groups from the last successful regexp match - indexed by group name. - -rule_number - The zero based index of the currently executing rule. - -rule_name - The name of the currently executing rule. If the rule name has not - been set it will be the empty string. - -block_number - The zero based index of the currently executing block within the - currently executing rule. - -block_name - The name of the currently executing block. If the block name has not - been set it will be the empty string. - - -statement_number - The zero based index of the currently executing statement within the - currently executing block. - - -Examples -======== - -Split a fully qualified username into user and realm components ---------------------------------------------------------------- - -It's common for some IdP's to return a fully qualified username -(e.g. principal or subject). The fully qualified username is the -concatenation of the user name, separator and realm name. A common -separator is the @ character. In this example lets say the fully -qualified username is ``bob@example.com`` and you want to return the -user and realm as independent values in your mapped result. The -username appears in the assertion as the value ``Principal``. - -Our strategy will be to use a regular expression identify the user and -realm components and then assign them to local variables which will -then populate the mapped result. - -The mapping in JSON is: - -:: - - { - "user": "$username", - "realm": "$domain" - } - -The assertion in JSON is: - -:: - - { - "Principal": "bob@example.com" - } - -Our rule is: - -:: - - [ - [ - ["in", "Principal", "assertion"], - ["exit", "rule_fails", "if_not_success"], - ["regexp", "$assertion[Principal]", (?P<username>\\w+)@(?P<domain>.+)"], - ["set", "$username", "$regexp_map[username]"], - ["set", "$domain", "$regexp_map[domain]"], - ["exit, "rule_succeeds", "always"] - ] - ] - -Rule explanation: - -Block 0: - -0. Test if the assertion contains a Principal value. -1. Abort the rule if the assertion does not contain a Principal - value. -2. Apply a regular expression the the Principal value. Use named - groupings for the username and domain components for clarity. -3. Assign the regexp group username to the $username local variable. -4. Assign the regexp group domain to the $domain local variable. -5. Exit the rule, apply the mapping, return the mapped values. Note, an - explicit `exit`_ is not required if there are no further statements - in the rule, as is the case here. - -The mapped result in JSON is: - -:: - - { - "user": "bob", - "realm": "example.com" - } - -Build a set of roles based on group membership ----------------------------------------------- - -Often one wants to grant roles to a user based on their membership in -certain groups. In this example let's say the assertion contains a -``Groups`` value which is a colon separated list of group names. Our -strategy is to split the ``Groups`` assertion value into an array of -group names. Then we'll test if a specific group is in the groups -array, if it is we'll add a role. Finally if no roles have been mapped -we fail. Users in the group "student" will get the role "unprivileged" -and users in the group "helpdesk" will get the role "admin". - -The mapping in JSON is: - -:: - - { - "roles": "$roles", - } - -The assertion in JSON is: - -:: - - { - "Groups": "student:helpdesk" - } - -Our rule is: - -:: - - [ - [ - ["in", "Groups", "assertion"], - ["exit", "rule_fails", "if_not_success"], - ["set", "$roles", []], - ["split", "$groups", "$assertion[Groups]", ":"], - ], - [ - ["in", "student", "$groups"], - ["continue", "if_not_success"], - ["append", "$roles", "unprivileged"] - ], - [ - ["in", "helpdesk", "$groups"], - ["continue", "if_not_success"], - ["append", "$roles", "admin"] - ], - [ - ["unique", "$roles", "$roles"], - ["length", "$temp", "roles"], - ["compare", $temp", ">", 0], - ["exit", "rule_fails", "if_not_success"] - ] - - ] - -Rule explanation: - -Block 0 - -0. Test if the assertion contains a Groups value. -1. Abort the rule if the assertion does not contain a Groups - value. -2. Initialize the $roles variable to an empty array. -3. Split the colon separated list of group names into an array of - individual group names - -Block 1 - -0. Test if "student" is in the $groups array -1. Exit the block if it's not. -2. Append "unprivileged" to the $roles array - -Block 2 - -0. Test if "helpdesk" is in the $groups array -1. Exit the block if it's not. -2. Append "admin" to the $roles array - -Block 3 - -0. Strip any duplicate roles that might have been appended to the - $roles array to assure each role is unique. -1. Count how many members are in the $roles array, assign the - length to the $temp variable. -2. Test to see if the $roles array had any members. -3. Fail if no roles had been assigned. - -The mapped result in JSON is: - -:: - - { - "roles": ["unprivileged", "admin"] - } - -However, suppose whatever is receiving your mapped results is not -expecting an array of roles. Instead it expects a comma separated list -in a string. To accomplish this add the following statement as the -last one in the final block: - -:: - - ["join", "$roles", "$roles", ","] - -Then the mapped result will be: - -:: - - { - "roles": "unprivileged,admin"] - } - - - - -White list certain users and grant them specific roles ------------------------------------------------------- - -Suppose you have certain users you always want to unconditionally -accept and authorize with specific roles. For example if the user is -"head_of_IT" then assign her the "user" and "admin" roles. Otherwise -keep processing. The list of white listed users is hard-coded into the -rule. - -The mapping in JSON is: - -:: - - { - "user": $user, - "roles": "$roles", - } - -The assertion in JSON is: - -:: - - { - "UserName": "head_of_IT" - } - -Our rule in JSON is: - -:: - - [ - [ - ["in", "UserName", "assertion"], - ["exit", "rule_fails", "if_not_success"], - ["in", "$assertion[UserName]", ["head_of_IT", "head_of_Engineering"]], - ["continue", "if_not_success"], - ["set", "$user", "$assertion[UserName"] - ["set", "$roles", ["user", "admin"]], - ["exit", "rule_succeeds", "always"] - ], - [ - ... - ] - ] - -Rule explanation: - -Block 0 - -0. Test if the assertion contains a UserName value. -1. Abort the rule if the assertion does not contain a UserName - value. -2. Test if the user is in the hardcoded list of white listed users. -3. If the user isn't in the white listed array then exit the block and - continue execution at the next block. -4. Set the $user local variable to $assertion[UserName] -5. Set the $roles local variable to the hardcoded array containing - "user" and "admin" -6. We're done, unconditionally exit and return the mapped result. - -Block 1 - -0. Further processing - -The mapped result in JSON is: - -:: - - { - "user": "head_of_IT", - "roles": ["users", "admin"] - } - - -Black list certain users ------------------------- - -Suppose you have certain users you always want to unconditionally -deny access to by placing them in a black list. In this example the -user "BlackHat" will try to gain access. The black list includes the -users "BlackHat" and "Spook". - -The mapping in JSON is: - -:: - - { - "user": $user, - "roles": "$roles", - } - -The assertion in JSON is: - -:: - - { - "UserName": "BlackHat" - } - -Our rule in JSON is: - -:: - - [ - [ - ["in", "UserName", "assertion"], - ["exit", "rule_fails", "if_not_success"], - ["in", "$assertion[UserName]", ["BlackHat", "Spook"]], - ["exit", "rule_fails", "if_success"] - ], - [ - ... - ] - ] - -Rule explanation: - -Block 0 - -0. Test if the assertion contains a UserName value. -1. Abort the rule if the assertion does not contain a UserName - value. -2. Test if the user is in the hard-coded list of black listed users. -3. If the test succeeds then immediately abort and return failure. - -Block 1 - -0. Further processing - -The mapped result in JSON is: - -:: - - Null - -Format Strings and/or Concatenate Strings ------------------------------------------ - -You can replace variables in a format string using the `interpolate`_ -verb. String concatenation is trivially placing two variables adjacent -to one another in a format string. Suppose you want to form an email -address from the username and domain in an assertion. - -The mapping in JSON is: - -:: - - { - "email": $email, - } - -The assertion in JSON is: - -:: - - { - "UserName": "Bob", - "Domain": "example.com" - } - -Our rule in JSON is: - -:: - - [ - [ - ["interpolate", "$email", "$assertion[UserName]@$assertion[Domain]"], - ] - ] - -Rule explanation: - -Block 0 - -0. Replace the variable $assertion[UserName] with it's value and - replace the variable $assertion[Domain] with it's value. - -The mapped result in JSON is: - -:: - - { - "email": "Bob@example.com", - } - - -Note, sometimes it's necessary to utilize braces to separate variables -from surrounding text by using the brace notation. This can also make -the format string more readable. Using braces to delimit variables the -above would be: - -:: - - [ - [ - ["interpolate", "$email", "${assertion[UserName]}@${assertion[Domain]}"], - ] - ] - - - -Make associative array lookups case insensitive ------------------------------------------------ - -Many systems treat field names as case insensitive. By default -associative array indexing is case sensitive. The solution is to lower -case all the keys in an associative array and then only use lower case -indices. Suppose you want the assertion associative array to be case -insensitive. - -The mapping in JSON is: - -:: - - { - "user": $user, - } - -The assertion in JSON is: - -:: - - { - "UserName": "Bob" - } - -Our rule in JSON is: - -:: - - [ - [ - ["lower", "$assertion", "$assertion"], - ["in", "username", "assertion"], - ["exit", "rule_fails", "if_not_success"], - ["set", "$user", "$assertion[username"] - ] - ] - -Rule explanation: - -Block 0 - -0. Lower case all the keys in the assertion associative array. -1. Test if the assertion contains a username value. -2. Abort the rule if the assertion does not contain a username - value. -3. Assign the username value in the assertion to $user - -The mapped result in JSON is: - -:: - - { - "user": "Bob", - } - - -Verbs -===== - -The following verbs are supported: - -* `set`_ -* `length`_ -* `interpolate`_ -* `append`_ -* `unique`_ -* `regexp`_ -* `regexp_replace`_ -* `split`_ -* `join`_ -* `lower`_ -* `upper`_ -* `compare`_ -* `in`_ -* `not_in`_ -* `exit`_ -* `continue`_ - -Some verbs have a side effects. A verb may set a boolean success/fail -result which may then be tested with a subsequent verb. For example -the ``fail`` verb can be used to indicate the rule fails if a prior -result is either ``success`` or ``not_success``. The ``regexp`` verb -which performs a regular expression search on a string stores the -regular expression sub-matches as a side effect in the variables -``$regexp_array`` and ``$regexp_map``. - - -Verb Definitions -================ - -set ---- - -``set $variable value`` - -$variable - The variable being assigned (i.e. lhs) - -value - The value to assign to the variable (i.e. rhs). The value may be - another variable or a constant. - -**set** assigns a value to a variable, in other words it's an -assignment statement. - -Examples: -^^^^^^^^^ - -Initialize a variable to an empty array. - -:: - - ["set", "$groups", []] - -Initialize a variable to an empty associative array. - -:: - - ["set", "$groups", {}] - -Assign a string. - -:: - - ["set", "$version", "1.2.3"] - -Copy the ``UserName`` value from the assertion to a temporary variable. - -:: - - ["set", "$temp", "$assertion[UserName]"], - - -Get the 2nd item in an array (array indexing is zero based) - -:: - - ["set", "$group", "$groups[1]"] - - -Set the associative array entry "IdP" to "kdc.example.com". - -:: - - ["set", "$metadata[IdP]", "kdc.example.com""] - --------------------------------------------------------------------------------- - -length ------- - -``length $variable value`` - -$variable - The variable which receives the length value - -value - The value whose length is to be determined. May be one of array, - associative array, or string. - -**length** computes the number of items in the value. How this is done -depends upon the type of value: - -array - The length is the number of items in the array. - -associative array - The length is the number of key/value pairs in the associative - array. - -string - The length is the number of *characters* (not octets) in the - string. - -Examples: -^^^^^^^^^ - -Count how many items are in the ``$groups`` array and assign that -value to the ``$groups_length`` variable. - -:: - - ["length", "$groups_length", "$groups"] - -Count how many key/value pairs are in the ``$assertion`` associative -array and assign that value to the ``$num_assertion_values`` variable. - -:: - - ["length", "$num_assertion_values", "$assertion"] - -Count how many characters are in the assertion's UserName and assign -the value to ``$username_length``. - -:: - - ["length", "$user_name_length", "$assertion[UserName]"] - - --------------------------------------------------------------------------------- - -interpolate ------------ - -``interpolate $variable string`` - -$variable - This variable is assigned the result of the interpolation. - -string - A string containing references to variables which will be replaced - in the string. - -**interpolate** replaces each occurrence of a variable in a string with -it's value. The result is assigned to $variable. - -Examples: -^^^^^^^^^ - -Form an email address given the username and domain. If the username -is "jane" and the domain is "example.com" then $email will be -"jane@example.com" - -:: - - ["interpolate", "$email", "${username}@${domain}"] - - --------------------------------------------------------------------------------- - - -append ------- - -``append $variable value`` - -$variable - This variable **must** be an array. It is modified in place by - appending ``value`` to the end of the array. - -value - The value to append to the end of the array. - -**append** adds a value to end of an array. - -Examples: -^^^^^^^^^ - -Append the role "qa_test" to the roles list. - -:: - - ["append", "$roles", "qa_test"] - - --------------------------------------------------------------------------------- - - -unique ------- - -``unique $variable value`` - -$variable - This variable is assigned the unique values in the ``value`` - array. - -value - An array of values. **must** be an array. - -**unique** builds an array of unique values in ``value`` by stripping -out duplicates and assigns the array of unique values to -``$variable``. The order of items in the ``value`` array are -preserved. - -Examples: -^^^^^^^^^ - -$one_of_a_kind will be assigned ["a", "b"] - -:: - - ["unique", "$one_of_a_kind", ["a", "b", "a"]] - - --------------------------------------------------------------------------------- - -regexp ------- - -``regexp string pattern`` - -string - The string the regular expression pattern is applied to. - -pattern - The regular expression pattern. - -**regexp** performs a regular expression match against ``string``. The -regular expression pattern syntax is defined by the regular expression -implementation of the language this API is written in. - -Pattern groups are a convenient way to select sub-matches. Pattern -groups may accessed by either group number or group name. After a -successful regular expression match the groups are stored in the -special variables ``$regexp_array`` and -``$regexp_map``. - -``$regexp_array`` is used to access the groups by -numerical index. Groups are numbered by counting the left parenthesis -group delimiter starting at 1. Group 0 is the entire -match. ``$regexp_array`` is valid irregardless of whether you used -named groups or not. - -``$regexp_map`` is used to access the groups by -name. ``$regexp_map`` is only valid if you used named groups in the -pattern. - -Examples: -^^^^^^^^^ - -Many user names are of the form "user@domain", to split the username -from the domain and to be able to work with those values independently -use a regular expression and then assign the results to a variable. In -this example there are two regular expression groups, the first group -is the username and the second group is the domain. In the first -example we use named groups and then access the match information in -the special variable ``$regexp_map`` via the name of the group. - -:: - - ["regexp", "$assertion[UserName]", "(?P<username>\\w+)@(?P<domain>.+)"], - ["continue", "if_not_success"], - ["set", "$username", "$regexp_map[username]"], - ["set", "$domain", "$regexp_map[domain]"], - - -This is exactly equivalent but uses numbered groups instead of named -groups. In this instance the group matches are stored in the special -variable ``$regexp_array`` and accessed by numerical index. - -:: - - ["regexp", "$assertion[UserName]", "(\\w+)@(.+)"], - ["continue", "if_not_success"], - ["set", "$username", "$regexp_array[1]"], - ["set", "$domain", "$regexp_array[2]"], - - - --------------------------------------------------------------------------------- - -regexp_replace --------------- - -``regexp_replace $variable string pattern replacement`` - -$variable - The variable which receives result of the replacement. - -string - The string to perform the replacement on. - -pattern - The regular expression pattern. - -replacement - The replacement specification. - -**regexp_replace** replaces each occurrence of ``pattern`` in -``$string`` with ``replacement``. See `regexp`_ for details of using -regular expressions. - -Examples: -^^^^^^^^^ - -Convert hyphens in a name to underscores. - -:: - - ["regexp_replace", "$name", "$name", "-", "_"] - - --------------------------------------------------------------------------------- - -split ------ - -``split $variable string pattern`` - -$variable - This variable is assigned an array containing the split items. - -string - The string to split into separate items. - -pattern - The regular expression pattern used to split the string. - -**split** splits ``string`` into separate pieces and assigns the -result to ``$variable`` as an array of pieces. The split occurs -wherever the regular expression ``pattern`` occurs in ``string``. See -`regexp`_ for details of using regular expressions. - -Examples: -^^^^^^^^^ - -Split a list of groups separated by a colon (:) into an array of -individual group names. If $assertion[Groups] contained the string -"user:admin" then $group_list will set to ["user", "admin"]. - -:: - - ["split", "$group_list", "$assertion[Groups]", ":"] - - - --------------------------------------------------------------------------------- - -join ----- - -``join $variable array join_string`` - -$variable - This variable is assigned the string result of the join operation. - -array - An array of string items to be joined together with - ``$join_string``. - -join_string - The string inserted between each element in ``array``. - -**join** accepts an array of strings and produces a single string -where each element in the array is separated by ``join_string``. - -Examples: -^^^^^^^^^ - -Convert a list of group names into a single string where each group -name is separated by a colon (:). If the array ``$group_list`` is -["user", "admin"] and the ``join_string`` is ":" then the -``$group_string`` variable will be set to "user:admin". - -:: - - ["join", "$group_string", "$groups", ":"] - - --------------------------------------------------------------------------------- - -lower ------ - -``lower $variable value`` - -$variable - This variable is assigned the result of the lower operation. - -value - The value to lower case, may be either a string, array, or - associative array. - -**lower** lower cases the input value. The input value may be one of -the following types: - -string - The string is lower cased. - -array - Each member of the array must be a string, the result is an array - with the items replaced by their lower case value. - -associative array - Each key in the associative array is lower cased. The values - associated with the key are **not** modified. - -Examples: -^^^^^^^^^ - -Lookup ``UserName`` in the assertion and set the variable -``$username`` to it's lower case value. - -:: - - ["lower", "$username", "$assertion[UserName]"], - -Set each member of the ``$groups`` array to it's lower case value. If -``$groups`` was ["User", "Admin"] then ``$groups`` will become -["user", "admin"]. - -:: - - ["lower", "$groups", "$groups"], - -To enable case insensitive lookup's in an associative array lower case -each key in the associative array. If ``$assertion`` was {"UserName": -"JoeUser"} then ``$assertion`` will become {"username": "JoeUser"} - -:: - - ["lower", "$assertion", $assertion"] - --------------------------------------------------------------------------------- - -upper ------ - -``upper $variable value`` - -$variable - This variable is assigned the result of the upper operation. - -value - The value to upper case, may be either a string, array, or - associative array. - -**upper** is exactly analogous to `lower`_ except the values are upper -cased, see `lower`_ for details. - - --------------------------------------------------------------------------------- - -in --- - -``in member collection`` - -member - The value whose membership is being tested. - -collection - A collection of members. May be string, array or associative array. - -**in** tests to see if ``member`` is a member of ``collection``. The -membership test depends on the type of collection, the following are -supported: - -array - If any item in the array is equal to ``member`` then the result is - success. - -associative array - If the associative array contains a key equal to ``member`` then - the result is success. - -string - If the string contains a sub-string equal to ``member`` then the - result is success. - -Examples: -^^^^^^^^^ - -Test to see if the assertion contains a UserName value. - -:: - - ["in", "UserName", "$assertion"] - ["continue", "if_not_success"] - -Test to see if a group is one of "user" or "admin". - -:: - - ["in", "$group", ["user", "admin"]] - ["continue", "if_not_success"] - -Test to see if the sub-string "BigCorp" is in -the assertion's ``Provider`` value. - -:: - - ["in", "BigCorp", "$assertion[Provider]"] - ["continue", "if_not_success"] - - --------------------------------------------------------------------------------- - -not_in ------- - -``in member collection`` - -member - The value whose membership is being tested. - -collection - A collection of members. May be string, array or associative array. - -**not_in** is exactly analogous to `in`_ except the sense of the test -is reversed. See `in`_ for details. - --------------------------------------------------------------------------------- - -compare -------- - -``compare left operator right`` - -left - The left hand value of the binary operator. - -operator - The binary operator used for comparing left to right. - -right - The right hand value of the binary operator. - - -**compare** compares the left value to the right value according the -operator and sets success if the comparison evaluates to True. The -following relational operators are supported. - -+----------+-----------------------+ -| Operator | Description | -+==========+=======================+ -| == | equal | -+----------+-----------------------+ -| != | not equal | -+----------+-----------------------+ -| < | less than | -+----------+-----------------------+ -| <= | less than or equal | -+----------+-----------------------+ -| > | greater than | -+----------+-----------------------+ -| >= | greater than or equal | -+----------+-----------------------+ - - -The left and right hand sides of the comparison operator *must* be -the same type, no type conversions are performed. Not all combinations -of operator and type are supported. The table below illustrates the -supported combinations. Essentially you can test for equality or -inequality on any type. But only strings and numbers support the -magnitude relational operators. - - -+----------+--------+---------+------+---------+-----+------+------+ -| Operator | STRING | INTEGER | REAL | BOOLEAN | MAP | LIST | NULL | -+==========+========+=========+======+=========+=====+======+======+ -| == | X | X | X | X | X | X | X | -+----------+--------+---------+------+---------+-----+------+------+ -| != | X | X | X | X | X | X | X | -+----------+--------+---------+------+---------+-----+------+------+ -| < | X | X | X | | | | | -+----------+--------+---------+------+---------+-----+------+------+ -| <= | X | X | X | | | | | -+----------+--------+---------+------+---------+-----+------+------+ -| > | X | X | X | | | | | -+----------+--------+---------+------+---------+-----+------+------+ -| >= | X | X | X | | | | | -+----------+--------+---------+------+---------+-----+------+------+ - - -Examples: -^^^^^^^^^ - -Test to see if the ``$groups`` array has at least 2 members - -:: - - ["length", "$group_length", "$groups"], - ["compare", "$group_length", ">=", 2] - - --------------------------------------------------------------------------------- - -exit ----- - -``exit status criteria`` - -status - The result for the rule. - -criteria - The criteria upon which will cause the rule will be immediately - exited with a failed status. - -**exit** causes the rule being executed to immediately exit and a rule -result if the specified criteria is met. Statement verbs such as `in`_ -or `compare`_ set the result status which may be tested with the -``success`` and ``not_success`` criteria. - -The exit ``status`` may be one of: - -rule_fails - The rule has failed and no mapping will occur. - -rule_succeeds - The rule succeeded and the mapping will be applied. - -The ``criteria`` may be one of: - -if_success - If current result status is success then exit with ``status``. - -if_not_success - If current result status is not success then exit with ``status``. - -always - Unconditionally exit with ``status``. - -never - Effectively a no-op. Useful for debugging. - -Examples: -^^^^^^^^^ - -The rule requires ``UserName`` to be in the assertion. - -:: - - ["in", "UserName", "$assertion"] - ["exit", "rule_fails", "if_not_success"] - --------------------------------------------------------------------------------- - - -continue --------- - -``continue criteria`` - -criteria - The criteria which causes the remainder of the *block* to be - skipped. - -**continue** is used to control execution for statement blocks. It -mirrors in a crude way the `if` expression in a procedural -language. ``continue`` does *not* affect the success or failure of a -rule, rather it controls whether subsequent statements in a block are -executed or not. Control continues at the next statement block. - -Statement verbs such as `in`_ or `compare`_ set the result status -which may be tested with the ``success`` and ``not_success`` criteria. - -The criteria may be one of: - -if_success - If current result status is success then exit the statement - block and continue execution at the next statement block. - -if_not_success - If current result status is not success then exit the statement - block and continue execution at the next statement block. - -always - Immediately exit the statement block and continue execution at the - next statement block. - -never - Effectively a no-op. Useful for debugging. Execution continues at - the next statement. - -Examples: -^^^^^^^^^ - -The following pseudo code: - -:: - - roles = []; - if ("Groups" in assertion) { - groups = assertion["Groups"].split(":"); - if ("qa_test" in groups) { - roles.append("tester"); - } - } - -could be implemented this way: - -:: - - [ - ["set", "$roles", []], - ["in", "Groups", "$assertion"], - ["continue", "if_not_success"], - ["split" "$groups", $assertion[Groups]", ":"], - ["in", "qa_test", "$groups"], - ["continue", "if_not_success"], - ["append", "$roles", "tester"] - ] |