summaryrefslogtreecommitdiffstats
path: root/doc/mapping.rst
diff options
context:
space:
mode:
Diffstat (limited to 'doc/mapping.rst')
-rw-r--r--doc/mapping.rst344
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
===============