diff options
Diffstat (limited to 'doc/mapping.rst')
-rw-r--r-- | doc/mapping.rst | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/doc/mapping.rst b/doc/mapping.rst index 3363550..2f76177 100644 --- a/doc/mapping.rst +++ b/doc/mapping.rst @@ -1,3 +1,347 @@ +Introduction +============ + +A need shared by many applications is the ability to authenticate a +user and then bind a set of permissions to the user which indicate +what actions the user is permitted to perform +(i.e. authorization). A LocalSystem may have implemented it's own +authentication and authorization and now wishes to utilize a federated +Identity Provider (IdP). Typically the IdP provides an assertion with +information describing the authenticated user. The goal is to +transform the IdP assertion into a LocalSystem token. In it's simplest +terms this is a data transformation which might include: + +* renaming of data items +* conversion to a different format +* deletion of data +* addition of data +* reorganization of data + +There are many ways such a transformation could be implemented: + +1. Custom site specific code +2. Scripts written in a scripting language +3. XSLT +4. Rule based transforms + +We also desire these goals for the transformation. + +1. Site administrator configurable +2. Secure +3. Simple +4. Extensible +5. Efficient + +Implementation choice 1, custom written code fails goals 1, 3 and 4, an +admin cannot adapt it, it's not simple, and it's likely to be +difficult to extend. + +Implementation choice 2, script based transformations have a lot of +appeal. Because one has at their disposal the full power of an actual +programming language there are virtually no limitations. If it's a +popular scripting language an administrator is likely to already know +the language and might be able to program a new transformation or at a +minimum tweak an existing script. Forking out to a script interpreter +is inefficient, but it's now possible to embed script interpreters in +the existing application. However sandboxing the execution of a +script such that it cannot perform malicious operations is +difficult. One could run a separate script process to provide +sandboxing but this introduces the vagaries of managing a subordinate +process and inter-process communication. Therefore scripts either fail +goals 1 or 5, secure or efficient (depending on whether the +interpreter is embedded or not). + +Implementation choice 3, XSLT fails goals 3 and 4, it is not simple, +it may not have the necessary features, and extending XSLT is +difficult. + +Implementation choice 4, rules based transformations offers the best +combination of features to meet the goals. Site administrators can +understand rules and edit them. There are no sandboxing concerns, rule +evaluation can be crafted to be secure. With careful design the rule +syntax can easily be extended. Rule execution should be efficient +because it's implemented in a native library loaded into the +application and does not depend on forking out to a separate process +or using inter-process communication. + +We describe a rule based system which offers much of the power and +flexibility of a scripting language but without it's downsides. The +rules are written much like a scripting language where you can call +functions (e.g. verbs) and perform simple branching logic based on the +result of a prior verb. Variables can be assigned and referenced. As +described in the `Variables`_ section a variable may be scalar, an +associative array (key/value), or an indexed array (ordered list). A +number of different data types are supported and are described in the +`Data Types`_ section. Because the rules are written in JSON it +should be easy for an administrator to understand and JSON provides +the ability load site specific hardcoded data the rules can +utilize. For example white lists, black lists, valid groups, invalid +groups, etc. are all easy to express in JSON. + +Implementation Status +--------------------- + +The Mapping Rule Processor described in this document currently has +implmentations in these languages: + +* Java +* Python + +An application simply needs to load the implementation and invoke it's +entry points. It is expected the rules will reside in site specific +configuration files. + +General Data Flow +----------------- + +`Figure 1.`_ illustrates the processing inside the application when it +needs to authenticate a user and provide a LocalSystem token +identifying the user, providing attributes bound to the user, and a +set of authorizations for the actions the user is permitted to perform +(e.g. roles). + + +.. figure:: figure-01.png + :align: center + + _`Figure 1.` + +:Step 1: + A federated Identity Provider (IdP) is asked to authenticate a user + and provide additional information (attributes) concerning the user. + +:Step 2: + Upon successful authentication the IdP provides an assertion for the + user which also contains extra information (attributes) bound to + the user (e.g. group membership, authorizations, etc.) + +:Step 3: + The mapper is invoked to transform the external IdP assertion into a + local representation. The transformation occurs according to the + rules and mapping templates loaded into the rule processor. + + The Mapping Rule Processor is designed to accept a JSON object (set + of key/value pairs) as input and emit a different JSON object as + output. Thus the Mappgin Rule Processor effectively operates as a + transformation engine on key/value pairs with the ability to add or + delete key/value pairs. + +:Step 3.1: + The input assertion is rewritten as a JSON object in the format + required by the Mapping Rule Processor. The JSON assertion is then + passed into the Mapping Rule Processor. + +:Step 3.2: + The Mapping Rule Processor identified as ``IdPMapper`` evaluates + the input JSON assertion in the context of the mapping rules defined + for the site deployment. If ``IdPMapper`` is able to successfully + transform the input it will return a JSON object which is called the + *mapped* result. If the input JSON assertion is not compatible with + the site specific rules loaded into the ``IdPMapper`` then NULL is + returned by the ``IdPMapper``. + +:Step 3.3: + If the mapping was successful the ``IdPMapper`` returns the + transformed assertion as a JSON object. + +:Step 4: + The mapped JSON object is converted for use in the local system. + +Example Assertion Transformation +-------------------------------- + +A federated IdP supplies metadata in a form unique to the IdP. This is +called an assertion. That assertion must be transformed into a format +and data understood by LocalSystem. More importantly that assertion +needs to yield *authorization roles specific to LocalSystem*. In +`Figure 1.`_ Step 3.2 the ``IdPMapper`` provides the transformation +from an external IdP assertion to a LocalSystem specific token. It +does this via a Mapping Rule Processor which reads a site specific set +of transformation rules. These mapping rules define how to transform +the external IdP assertion into a LocalSystem token. The mapping rules +also are responsible for validating the external IdP assertion to make +sure it is consistent with the site specific requirements. The +operation of the Mapping Rule Processor and the syntax of the mapping +rules are defined in `Structure Of Rule Definitions`_. + +Below is an example mapping rule which might be loaded into the +Mapping Rule Processor to support a fictional FOOBAR application. The +IdP provides assertions using the ``REMOTE_USER`` CGI style. It is +assumed there are two LocalSystem roles which may be assigned: + +``user`` + A role granting standard permissions for normal FOOBAR users. + +``admin`` + A special role granting full FOOBAR administrative permissions. + +In this example assigning the ``user`` and ``admin`` roles +will be based on group membership in the following groups: + +``foobar_users`` + Members of this group are normal FOOBAR users with restricted permissions. + +``foobar_admin`` + Members of this group are FOOBAR administrators with permission to + perform all operations. + +Granting of the ``user`` and/or ``admin`` roles based on +membership in the ``foobar_users`` and ``foobar_admin`` is illustrated in +the follow mapping rule example which also extracts the user principal +and domain information in the preferred format for the site +(e.g. usernames are lowercase without domain suffixes and the domain +is uppercase and supplied separately). + +_`Mapping Rule Example 1.` + +:: + + 1 [ + 2 {"mapping": {"ClientId": "$client_id", + 3 "UserId": "$user_id", + 4 "User": "$username", + 5 "Domain": "$domain", + 6 "roles": "$roles", + 7 }, + 8 "statement_blocks": [ + 9 [ + 10 ["set", "$groups", []], + 11 ["set", "$roles", []] + 12 ], + 13 [ + 14 ["in", "REMOTE_USER", "$assertion"], + 15 ["exit", "rule_fails", "if_not_success"], + 16 ["regexp", "$assertion[REMOTE_USER]", "(?<username>\\w+)@(?<domain>.+)"], + 17 ["exit", "rule_fails", "if_not_success"], + 18 ["lower", "$username", "$regexp_map[username]"], + 19 ["upper", "$domain", "$regexp_map[domain]"], + 20 ], + 21 [ + 22 ["in", "REMOTE_USER_GROUPS", "$assertion"], + 23 ["exit", "rule_fails", "if_not_success"], + 24 ["split", "$groups", "$assertion[REMOTE_USER_GROUPS]", ":"], + 25 ], + 26 [ + 27 ["in", "foobar_users", "$groups"], + 28 ["continue", "if_not_success"], + 29 ["append", "$roles", "user"], + 30 ], + 31 [ + 32 ["in", "foobar_admin", "$groups"], + 33 ["continue", "if_not_success"], + 34 ["append", "$roles", "admin"] + 35 ], + 36 [ + 37 ["unique", "$roles", "$roles"], + 38 ["length", "$n_roles", "$roles"], + 39 ["compare", "$n_roles", ">", 0], + 40 ["exit", "rule_fails", "if_not_success"], + 41 ], + 42 ] + 43 } + 44 ] + +:Line 1: + Starts a list of rules. In this example only 1 rule is defined. Each + rule is a JSON object containing a ``mapping`` and a required list + of ``statement_blocks``. The ``mapping`` may either be specified + inside a rule as it is here or may be referenced by name in a table + of mappings (this is easier to manage if you have a large number of + rules and small number of mappings). +:Lines 2-7: + Defines the JSON mapped result. Each key maps to LocalSystem token. + The value is a rule variable whose value will be substituted + if the rule succeeds. Thus for example the LocalSystem token value + ``User`` will be assigned the value from the ``$username`` rule + variable. +:Line 8: + Begins the list of statement blocks. A statement must be contained + inside a block. +:Lines 9-12: + The first block usually initializes variables that will be + referenced later. Here we initialize ``$groups`` and ``$roles`` to + empty arrays. These arrays may be appended to in later blocks and + may be referenced in the final ``mapping`` output. +:Lines 13-20: + This block sets the user and domain information based on + ``REMOTE_USER`` and exits the rule if ``REMOTE_USER`` is not defined. +:Lines 14-15: + This test is critical, it assures ``REMOTE_USER`` is defined in the + assertion, if not the rule is skipped because we depend on + ``REMOTE_USER``. +:Lines 16-17: + Performs a regular expression match against ``REMOTE_USER`` to split + the username from the domain. The regular expression uses named + groups, in this instance ``username`` and ``domain``. If the regular + expression does not match the rule is skipped. +:Lines 18-19: + These lines reference the previous result of the regular expression + match which are stored in the special variable ``$regexp_map``. The + username is converted to lower case and stored in ``$username`` and + the domain is converted to upper case and stored in ``$domain``. The + choice of case is purely by convention and site requirements. +:Lines 21-35: + These 3 blocks assign roles based on group membership. +:Lines 21-25: + Assures ``REMOTE_USER_GROUPS`` is defined in the assertion; if not, the + rule is skipped. ``REMOTE_USER_GROUPS`` is colon separated list of group + names. In order to operate on the individual group names appearing + in ``REMOTE_USER_GROUPS`` line 24 splits the string on the colon + separator and stores the result in the ``$groups`` array. +:Lines 27-30: + This block assigns the ``user`` role if the user is a member of the + ``foobar_users`` group. +:Lines 31-35: + This block assigns the ``admin`` role if the user is a + member of the ``foobar_admin`` group. +:Lines 36-41: + This block performs final clean up actions for the rule. First it + assures there are no duplicates in the ``$roles`` array by calling + the ``unique`` function. Then it gets a count of how many items are + in the ``$roles`` array and tests to see if it's empty. If there are + no roles assigned the rule is skipped. +:Line 43: + This is the end of the rule. If we reach the end of the rule it + succeeds. When a rule succeeds the mapping associated with the rule + is looked up. Any rule variable appearing in the mapping is + substituted with its value. + +Using the rules in `Mapping Rule Example 1.`_ and following example assertion +in JSON format: + +_`Assertion Example 1.` + +:: + + { + "REMOTE_USER": "TestUser@example.com", + "REMOTE_AUTH_TYPE": "Negotiate", + "REMOTE_USER_GROUPS": "foobar_users:foobar_admin", + "REMOTE_USER_EMAIL": "test.user@example.com", + "REMOTE_USER_FIRSTNAME": "Test", + "REMOTE_USER_LASTNAME": "User" + } + +Then the mapper will return the following mapped JSON document. This +is the ``mapping`` defined on line 2 of `Mapping Rule Example 1.`_ with the +variables substituted after the rule successfully executed. Note any +valid JSON data type can be returned, in this example the ``null`` +value is returned for ``ClientId`` and ``UserId``, normal strings for +``User`` and ``Domain`` and an array of strings for the ``roles`` value. + +_`Mapped Result Example 1.` + +:: + + { + "ClientId": null, + "UserId": null, + "User": "testuser", + "Domain": "EXAMPLE.COM", + "roles": ["user", "admin"] + } + + Operation Model =============== |