chap-users-groups-roles.xml revision 786c8a76edf4275c0c85b200563c8f318641b088
<?xml version="1.0" encoding="UTF-8"?>
<!--
! CCPL HEADER START
!
! This work is licensed under the Creative Commons
! Attribution-NonCommercial-NoDerivs 3.0 Unported License.
! To view a copy of this license, visit
! http://creativecommons.org/licenses/by-nc-nd/3.0/
! or send a letter to Creative Commons, 444 Castro Street,
! Suite 900, Mountain View, California, 94041, USA.
!
! You can also obtain a copy of the license at
! legal/CC-BY-NC-ND.txt.
! See the License for the specific language governing permissions
! and limitations under the License.
!
! If applicable, add the following below this CCPL HEADER, with the fields
! enclosed by brackets "[]" replaced with your own identifying information:
! Portions Copyright [yyyy] [name of copyright owner]
!
! CCPL HEADER END
!
! Copyright 2011-2014 ForgeRock AS
!
-->
<chapter xml:id='chap-users-groups-roles'
xmlns='http://docbook.org/ns/docbook'
version='5.0' xml:lang='en'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:schemaLocation='http://docbook.org/ns/docbook
http://docbook.org/xml/5.0/xsd/docbook.xsd'
xmlns:xlink='http://www.w3.org/1999/xlink'>
<title>Managing Users, Groups, and Roles</title>
<para>
OpenIDM does not control the structure of objects that are stored in its
repository. You can define any kind of managed object, but a definition for
users, groups and roles is provided by default.
</para>
<para>
This chapter describes how to work with these default managed objects. More
information about the OpenIDM object model is provided in the <link
xlink:show="new" xlink:href="integrators-guide#appendix-objects"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Data Models and
Objects Reference</citetitle></link>.
</para>
<section xml:id="working-with-managed-users">
<title>Working with Managed Users</title>
<para>
External users that are stored in OpenIDM's repository are referred to as
<firstterm>managed users</firstterm>. For a JDBC repository, OpenIDM stores
managed users in the <literal>managedobjects</literal> table. A second table,
<literal>managedobjectproperties</literal>, serves as the index table. For an
OrientDB repository, managed users are stored in the
<literal>managed_user</literal> table.
</para>
<para>
OpenIDM provides RESTful access to managed users, at the context path
<literal>/openidm/managed/user</literal>. For more information, see
<link xlink:show="new" xlink:href="install-guide#first-steps-with-rest"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>To Get Started
With the OpenIDM REST Interface</citetitle></link> in the
<citetitle>Installation Guide</citetitle>.
</para>
</section>
<section xml:id="working-with-groups">
<title>Working With Managed Groups</title>
<para>
OpenIDM provides support for a managed <literal>"group"</literal> object. For
a JDBC repository, OpenIDM stores managed groups with all other managed
objects, in the <literal>managedobjects</literal> table, and uses the
<literal>managedobjectproperties</literal> for indexing. For an OrientDB
repository, managed groups are stored in the <literal>managed_group</literal>
table.
</para>
<para>
The managed group object is not provided by default. To use managed groups,
add an object similar to the following to your
<filename>conf/managed.json</filename> file:
</para>
<programlisting>{
"name" : "group"
},
</programlisting>
<para>
With this addition, OpenIDM provides RESTful access to managed groups, at the
context path <literal>/openidm/managed/group</literal>.
</para>
<para>
For an example of a deployment that uses managed groups, see <link
xlink:show="new" xlink:href="install-guide#more-sample2d"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Sample 2d -
Synchronizing LDAP Groups</citetitle></link> in the <citetitle>Installation
Guide</citetitle>.
</para>
</section>
<section xml:id="configuring-custom-roles">
<title>Configuring Custom Roles</title>
<para>
The default managed object model includes a managed <literal>role</literal>
object that can be manipulated in the same way as any other managed object.
</para>
<para>
This section refers to two distinct types of roles - direct (static) and
indirect (dynamic) roles. Direct roles refer to roles that are specifically
added to the user's <literal>"roles"</literal> attribute by an administrator
operation. Indirect roles might be added to the user entry as a result of a
script or rule that assigns the role. For example, a user might acquire a
<literal>"sales-role"</literal> as a result of being in the
<literal>"sales"</literal> organization.
</para>
<para>
A managed user's <literal>"roles"</literal> attribute takes an array as a
value. Currently, only flat strings are supported in this array.
</para>
<para>
The <literal>"roles"</literal> attribute includes any specifically assigned
roles, and any roles assigned internally by OpenIDM. So, the
<literal>"roles"</literal> attribute of a particular user entry might
appear as follows:
</para>
<programlisting language="java">
"roles" : [
"name" : "managed/role/sample-role",
"name" : "openidm-authorized"
]
</programlisting>
<para>
A role value that includes a <literal>/</literal> character is considered to
be a URL that points to the role details on the router, for example,
<literal>managed/role/sample-role</literal>.
</para>
<para>
The following sections describe basic role manipulation - how roles are
defined, assigned to users, and deleted. The entitlements or assignments
supplied by roles are described in the subsequent section.
</para>
<section xml:id="roles-creating-assigning-deleting">
<title>Creating, Assigning, and Deleting Roles</title>
<para>
Role definitions are stored in the repository and are accessible at the
<literal>/openidm/managed/role</literal> context path. This section
describes how to manipulate roles over the REST interface.
</para>
<para>
The examples in this section assume that OpenIDM has been started with the
configuration of Sample 2b, and refers to the managed user objects created
in that sample. For more information, see <link xlink:show="new"
xlink:href="install-guide#more-sample2b"
xlink:role="http://docbook.org/xlink/role/olink"
><citetitle>Sample 2b - LDAP Two Way</citetitle></link> in the
<citetitle>Installation Guide</citetitle>.
</para>
<section xml:id="create-role-definition">
<title>To Create a Role Definition</title>
<para>
To create a managed role definition, use a PUT request on the
<literal>openidm/managed/role</literal> context path, specifying the role
ID in the URL. The following request creates a role definition named
<literal>newrole</literal>. The role effectively assigns the value
<literal>"CN=employees,O=corp"</literal> to the
<literal>ldapGroups</literal> attribute on the <literal>ldap</literal>
system.
</para>
<screen>$ <userinput>curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--header "If-None-Match: *" \
--request PUT \
--data '{
"properties": {
"description": "an example role"
},
"assignments": {
"ldap": {
"attributes": [
{
"name": "ldapGroups",
"assignmentOperation": "mergeWithTarget",
"unassignmentOperation": "removeFromTarget",
"value": [
"CN=employees,O=corp"
]
}
],
"onAssignment": {
"file": "roles\/onAssignment_ldap.js",
"type": "text\/javascript"
},
"onUnassignment": {
"file": "roles\/onUnassignment_ldap.js",
"type": "text\/javascript"
}
}
}
}' \
"https://localhost:8443/openidm/managed/role/newrole"</userinput>
<computeroutput>
{
"assignments": {
"ldap": {
"attributes": [
{
"name": "ldapGroups",
"unassignmentOperation": "removeFromTarget",
"assignmentOperation": "mergeWithTarget",
"value": [
"CN=employees,O=corp"
]
}
],
"onAssignment": {
"file": "roles/onAssignment_ldap.js",
"type": "text/javascript"
},
"onUnassignment": {
"file": "roles/onUnassignment_ldap.js",
"type": "text/javascript"
}
}
},
"_id": "newrole",
"properties": {
"description": "an example role"
},
"_rev": "1"
}</computeroutput>
</screen>
<para>
For information about each of the properties in the role definition, see
<xref linkend="sample-role-definition" />.
</para>
<para>
Most of the examples in this guide use PUT to create client-assigned IDs
for resources, as it makes the examples easier to read. Your deployment
might require you to use server-assigned UUIDs, in which case you should
use a POST request. For more information, see
<link xlink:role="http://docbook.org/xlink/role/olink" xlink:show="new"
xlink:href="integrators-guide#put-post-managed-objects">
<citetitle>Should You Use PUT or POST to Create A Managed Object?
</citetitle></link>
</para>
</section>
<section xml:id="listing-defined-roles">
<title>To List the Defined Roles</title>
<para>
To obtain a list of all defined managed roles, query the
<literal>/openidm/managed/role</literal> context path, as follows.
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/role/?_queryId=query-all-ids"</userinput>
<computeroutput>
{
"remainingPagedResults": -1,
"pagedResultsCookie": null,
"resultCount": 1,
"result": [
{
"_rev": "0",
"_id": "newrole"
}
]
} </computeroutput>
</screen>
</section>
<section xml:id="assign-role-to-user">
<title>To Assign a Role to a User</title>
<para>
To assign a direct role to a user, update the user's entry over REST,
adding <literal>managed/role/<replaceable>role ID</replaceable></literal>
to the user's <literal>"roles"</literal> attribute. The following example
adds the <literal>ldap</literal> role, created previously, to user
<literal>bjensen</literal>, whose <literal>_id</literal> is
<literal>2e78fd22-a7cb-4585-9570-5f649e8abd25</literal>.
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--header "If-Match: *" \
--request PATCH \
--data '[
{
"operation": "add",
"field": "/roles/-",
"value": "managed/role/newrole"
}
]' \
"https://localhost:8443/openidm/managed/user/2e78fd22-a7cb-4585-9570-5f649e8abd25"
</userinput>
<computeroutput>{
"displayName": "Barbara Jensen",
"stateProvince": "",
"userName": "bjensen",
"postalAddress": "",
"effectiveAssignments": {
"ldap": {
"attributes": [
{
"name": "ldapGroups",
"unassignmentOperation": "removeFromTarget",
"assignmentOperation": "mergeWithTarget",
"assignedThrough": "managed/role/newrole",
"value": [
"CN=employees,O=corp"
]
}
],
"onAssignment": {
"file": "roles/onAssignment_ldap.js",
"type": "text/javascript"
},
"onUnassignment": {
"file": "roles/onUnassignment_ldap.js",
"type": "text/javascript"
}
}
},
"roles": [
"openidm-authorized",
"managed/role/newrole"
],
"city": "",
"effectiveRoles": [
"openidm-authorized",
"managed/role/newrole"
],
"givenName": "Barbara",
"lastPasswordAttempt": "Tue Oct 21 2014 16:01:22 GMT+0200 (SAST)",
"address2": "",
"passwordAttempts": "0",
"sn": "Jensen",
"mail": "bjensen@example.com",
"country": "",
"_rev": "2",
"lastPasswordSet": "",
"postalCode": "",
"_id": "2e78fd22-a7cb-4585-9570-5f649e8abd25",
"description": "Created for OpenIDM",
"accountStatus": "active",
"telephoneNumber": "1-360-229-7105"
}</computeroutput>
</screen>
<para>
Note the dash (<literal>-</literal>) character that is appended to the
field name in the <literal>data</literal> that is being sent. This
character specifies that the role should be added to the existing roles for
that user. If you do not include the dash character, the request overwrites
all current values of the user's <literal>"roles"</literal> attribute.
</para>
</section>
<section xml:id="query-role-membership">
<title>To Query Role Membership</title>
<para>
To return a list of all users who have a specific directly assigned role,
use the <literal>get-users-of-direct-role</literal> query, specifying the
role ID. You cannot query role membership for indirect roles.
</para>
<para>
The following query returns all members of the <literal>"newrole"</literal>
role created previously. Currently that role has only one member,
<literal>bjensen</literal>, whose ID is
<literal>2e78fd22-a7cb-4585-9570-5f649e8abd25</literal>. The query returns
the complete user object.
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user?_queryId=get-users-of-direct-role&amp;role=managed/role/newrole"
</userinput>
<computeroutput>{
"remainingPagedResults": -1,
"pagedResultsCookie": null,
"resultCount": 1,
"result": [
{
"effectiveAssignments": {
"ldap": {
"attributes": [
{
"name": "ldapGroups",
...
"_id": "2e78fd22-a7cb-4585-9570-5f649e8abd25",
"_rev": "2",
"description": "Created for OpenIDM",
"accountStatus": "active"
}
]
}</computeroutput>
</screen>
</section>
<section xml:id="remove-role-assignment">
<title>To Remove a Role Assignment</title>
<para>
To remove a role assignment from a user, simply replace that user's
<literal>"roles"</literal> attribute with the array of roles that the user
should have. The following example removes the <literal>newrole</literal>
role from user <literal>bjensen</literal> by replacing the current value of
her <literal>"roles"</literal> attribute with its previous value
(<literal>"openidm-authorized"</literal>).
</para>
<screen>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--header "If-Match: *" \
--request PATCH \
--data '[
{
"operation": "replace",
"field": "/roles",
"value": [
"openidm-authorized"
]
}
]' \
"https://localhost:8443/openidm/managed/user/2e78fd22-a7cb-4585-9570-5f649e8abd25"</screen>
<para>
In the role definition, you can specify what should happen when an
assignment of that role is removed. For more information, see
<xref linkend="effective-roles-and-assignments" />.
</para>
</section>
<section xml:id="delete-role-definition">
<title>To Delete a Managed Role Definition</title>
<para>
To delete a role definition, send a DELETE request, specifying the role ID
in the URL. The following sample command deletes the
<literal>newrole</literal> role, created previously.
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request DELETE \
"https://localhost:8443/openidm/managed/role/newrole"</userinput>
<computeroutput>{
"properties": {
"description": "an example role"
},
"assignments": {
"ldap": {
"attributes": [
{
"name": "ldapGroups",
"unassignmentOperation": "removeFromTarget",
"assignmentOperation": "mergeWithTarget",
"value": [
"CN=employees,O=corp"
]
}
],
"onAssignment": {
"file": "roles/onAssignment_ldap.js",
"type": "text/javascript"
},
"onUnassignment": {
"file": "roles/onUnassignment_ldap.js",
"type": "text/javascript"
}
}
},
"_rev": "1",
"_id": "newrole"
}</computeroutput>
</screen>
<note>
<para>
You cannot delete a role definition if that role is currently assigned to
a user. Attempting to delete an assigned role results in the following
error:
</para>
<screen>{
"message": "Cannot delete a role that is currently assigned",
"reason": "Conflict",
"code": 409
}</screen>
</note>
</section>
</section>
<section xml:id="effective-roles-and-assignments">
<title>Understanding Effective Roles and Effective Assignments</title>
<para>
The primary purpose of roles is the management of user access to system
resources. User access is controlled by the
<firstterm>assignments</firstterm> or entitlements provided by the role.
</para>
<para>
The previous section described how to create a basic role definition and to
assign that role to a user. This section describes how the assignments that
are specified for that role are applied.
</para>
<section xml:id="sample-role-definition">
<title>A Sample Role Definition for Two Remote Systems</title>
<para>
The following sample role definition shows how assignments are configured
for two remote systems - an LDAP server (<literal>ldap</literal>), and an
Active Directory Server (<literal>ad</literal>).
</para>
<programlisting language="java">{
"name": "samplerole",
"_id": "samplerole",
"assignments": {
"ad": {
"attributes": [
{
"name": "adSystems",
"value": [
"CN=fileshare,O=corp",
"CN=desktop,O=corp",
"CN=terminal,O=corp",
"CN=intranet,O=corp"
],
"assignmentOperation": "mergeWithTarget",
"unassignmentOperation": "removeFromTarget"
}
]
},
"ldap": {
"attributes": [
{
"name": "ldapGroups",
"value": [
"CN=employees,O=corp"
],
"assignmentOperation": "mergeWithTarget",
"unassignmentOperation": "removeFromTarget"
},
{
"name": "employeeType",
"value": "employee"
}
],
"onAssignment": {
"file": "roles/onAssignment_ldap.js",
"type": "text/javascript"
},
"onUnassignment": {
"file": "roles/onUnassignment_ldap.js",
"type": "text/javascript"
}
}
}
}</programlisting>
<itemizedlist>
<para>
The role definition includes the following properties:
</para>
<listitem>
<para>
<literal>"name"</literal> is the name of the role, and should be unique.
Avoid using special characters in the role name.
</para>
</listitem>
<listitem>
<para>
<literal>"_id"</literal> is the object identifier of the role, by which
it is accessed over REST.
</para>
</listitem>
<listitem>
<para>
<literal>"assignments"</literal> specifies the list of assignments
(or entitlements) that this role will create on the remote systems.
</para>
<para>
Each assignment includes the name of the external system, such as
<literal>ad</literal> and <literal>ldap</literal>, the
attribute or attributes whose values will be generated, on the external
system, and the value or values that will be applied to each attribute.
</para>
<para>
OpenIDM uses the <literal>"assignments"</literal> property to keep
assigned roles up to date.
</para>
</listitem>
<listitem>
<para>
<literal>"assignmentOperation"</literal> and
<literal>"unassignmentOperation"</literal>
</para>
<para>
When you update a role definition by adding, updating, or removing an
attribute, the update triggers an <literal>"assignmentOperation"</literal>
or an <literal>"unassignmentOperation"</literal>.
</para>
<para>
When you assign or unassign a role to a user, that action also triggers
an <literal>"assignmentOperation"</literal> or an
<literal>"unassignmentOperation"</literal>.
</para>
<itemizedlist>
<listitem>
<para>
The <literal>"assignmentOperation"</literal> specifies the way in which
the attribute value is applied, and can be one of
<literal>"replaceTarget"</literal> (the default) or
<literal>"mergeWithTarget"</literal>.
</para>
<para>
The <literal>"replaceTarget"</literal> operation replaces the entire
target attribute value with whatever is specified in the role
definition. When this operation is specified, the value from the role
assignments becomes the only authoritative source for the attribute.
</para>
<para>
The <literal>"mergeWithTarget"</literal> operation first merges the
source value with the existing target value, then adds the value or
values from the role assignment. In the event that duplicate values are
found (for attributes that take a list as a value), each value is
included only once in the resulting target value.
</para>
</listitem>
<listitem>
<para>
The <literal>"unassignmentOperation"</literal> specifies the way in
which the attribute value is removed, and can only be set to
<literal>"removeFromTarget"</literal>.
</para>
</listitem>
</itemizedlist>
<para>
The <literal>"mergeWithTarget"</literal>, <literal>"replaceTarget"</literal>
and <literal>"removeFromTarget"</literal> operations are aliases, and are
defined in the file
<filename>openidm/bin/defaults/script/roles/defaultMapping.js</filename>.
</para>
</listitem>
<listitem>
<para>
<literal>"onAssignment"</literal> and <literal>"onUnassignment"</literal>
</para>
<para>
These properties refer to customizable scripts, that are specific to each
assignment.
</para>
<para>
By default, OpenIDM addresses any change in role assignments with the
assignment operations defined in the
<filename>defaultMapping.js</filename> file. You can modify this behavior
by writing custom <literal>onAssignment</literal> and
<literal>onUnassignment</literal> scripts. If these custom scripts are
specified, OpenIDM triggers the <literal>"onAssignment"</literal> or
<literal>"onUnassignment"</literal> script whenever you create, assign,
or delete a role from a user entry. In addition, every synchronization
operation triggers the <literal>"onAssignment"</literal> script. The
<literal>"onUnassignment"</literal> script is triggered when an
assignment is removed from a role, or when a role is unassigned from a
user.
</para>
<para>
If you create a custom <literal>"onAssignment"</literal> or
<literal>"onUnassignment"</literal> script, the script must return a
<literal>"targetObject"</literal>, otherwise, the script operation might
fail.
</para>
</listitem>
</itemizedlist>
<para>
OpenIDM logs any changes to a managed role definition in the audit log.
</para>
</section>
<section xml:id="roles-virtual-attributes">
<title>Virtual Role Attributes</title>
<para>
Based on the set of role definitions that are assigned to a specific user,
the roles mechanism generates two virtual attributes on the user entry -
<literal>effectiveRoles</literal> and
<literal>effectiveAssignments</literal>.
</para>
<para>
The logic that calculates the <literal>effectiveRoles</literal> and
<literal>effectiveAssignments</literal> attribute values is located in two
scripts:
<filename>openidm/bin/defaults/script/roles/effectiveRoles.js</filename>
and
<filename>openidm/bin/defaults/script/roles/effectiveAssignments.js</filename>.
Do not alter these scripts. If you need to modify how roles and assignments
are handled, create your own custom script and reference it in the
<filename>conf/managed.json</filename> file. For information about using
custom scripts, see the
<link xlink:href="integrators-guide#appendix-scripting"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>Scripting
Reference</citetitle></link>.
</para>
<para>
The <literal>effectiveRoles</literal> attribute lists the specific role
definitions that are applied to a user entry. By default, the effective
roles script supports direct role assignments only. Dynamic role assignment
is not provided out of the box, but can be added with a custom script that
overrides the default <filename>effectiveRoles.js</filename> script. For
more information, see <xref linkend="dynamic-role-assignments" />.
</para>
<para>
Based on the effective roles, the <literal>effectiveAssignments</literal>
attribute provides the calculated resource assignments, that is the
amalgamated set of entitlements for a specific user.
</para>
<para>
The value of the <literal>effectiveAssignments</literal> attribute provides
the information required for the provisioner to apply the effective
assignments, and provides a reference to the source of the assignment. In
reading this attribute, it is therefore possible to find and change the
root source of an assignment.
</para>
<para>
Effective assignments can merge attribute operations on the same system from
multiple roles. For example, role A might add group A to a user's group
membership list, and role B might add group B to the same group membership
property on the same assigned system.
</para>
<para>
The effective roles and effective assignments attributes are configured in
<filename>openidm/conf/managed.json</filename> as follows:
</para>
<programlisting language="java">
{
"name" : "effectiveRoles",
"type" : "virtual",
"onRetrieve" : {
"type" : "text/javascript",
"file" : "roles/effectiveRoles.js",
"rolesPropName" : "roles"
}
},
{
"name" : "effectiveAssignments",
"type" : "virtual",
"onRetrieve" : {
"type" : "text/javascript",
"file" : "roles/effectiveAssignments.js",
"effectiveRolesPropName" : "effectiveRoles"
}
}
</programlisting>
<para>
By default, the <filename>effectiveRoles.js</filename> script uses the
<literal>"roles"</literal> attribute of a user entry to determine the
direct roles assigned to the user. The
<filename>effectiveAssignments.js</filename> script uses the virtual
<literal>"effectiveRoles"</literal> attribute of the user entry to calculate
the user's effective assignments. If your deployment uses different
attributes to store this information, change the
<literal>"rolesPropName"</literal> and the
<literal>"effectiveRolesPropName"</literal> properties of the virtual
attribute definitions accordingly.
</para>
<para>
When a user entry is assigned a role, the <literal>effectiveRoles</literal>
and <literal>effectiveAssignments</literal> of that entry are calculated
according to the role definition. A managed user entry, whose roles have
been generated based on the role definition illustrated previously, might
appear as follows:
</para>
<programlisting language="javascript">
{
"_id":"i",
"_rev":"1",
"roles":[
"openidm-authorized",
"managed/role/sample-role"
],
"effectiveRoles":[
"openidm-authorized",
"managed/role/sample-role"
],
"effectiveAssignments":{
"ldap":{
"attributes":[
{
"value":[
"CN=employees,O=corp"
],
"operation":"replaceTarget",
"name":"ldapGroups",
"assignedThrough":"managed/role/sample-role"
},
{
"value":"employee",
"name":"employeeType",
"assignedThrough":"managed/role/sample-role"
}
]
},
"ad":{
"attributes":[
{
"value":[
"CN=fileshare,O=corp",
"CN=desktop,O=corp",
"CN=terminal,O=corp",
"CN=intranet,O=corp"
],
"operation":"replaceTarget",
"name":"adSystems",
"assignedThrough":"managed/role/sample-role"
}
]
}
}
}</programlisting>
<para>
Note that the value of the <literal>"assignedThrough"</literal> property
of the virtual <literal>"effectiveAssignments"</literal> attribute indicates
how each assignment has been generated.
</para>
<para>
After you have defined a role, and assigned it to a user, verify that the
expected effective roles and effective assignments have been generated for
that user. To apply the effective assignments to the target resource, add a
default mapping to your synchronization configuration, as described in the
following section.
</para>
</section>
</section>
<section xml:id="role-mapping">
<title>Setting up the Role Mapping</title>
<para>
After the role has been defined, and the effective assignments checked, you
must set up mapping for the role and, optionally, restrict provisioning
based on the effective assignments.
</para>
<para>
This section describes these two steps.
</para>
<section xml:id="roles-default-mapping">
<title>Creating a Mapping For Effective Assignments</title>
<para>
After the effective assignments have been calculated, OpenIDM applies these
assignments to the target resources.
</para>
<para>
The following sample extract of a <filename>sync.json</filename> file
applies the <literal>ldap</literal> assignment, illustrated in the previous
section, on the target resource (<literal>system/ldap/account</literal>) for
all entries that have <literal>"effectiveAssignments" : "ldap"</literal> in
the source.
</para>
<programlisting language="javascript">
{
"name" : "managedUser_systemLdapAccounts",
"source" : "managed/user",
"target" : "system/ldap/account",
"links" : "systemLdapAccounts_managedUser",
},
"assignmentsToMap": [
"ldap"
],
...
} </programlisting>
</section>
<section xml:id="conditional-mapping">
<title>Using Roles For Conditional Mapping</title>
<para>
The roles mechanism provides the ability to restrict provisioning based on
a user's effective assignments. For example, you might want to prevent users
from being provisioned to an Active Directory system, if they do not have
specific access to that system.
</para>
<para>
Based on the <literal>"effectiveAssignments"</literal> virtual attribute,
described in the previous section, you could configure a conditional mapping
for this example, as follows:
</para>
<orderedlist>
<listitem>
<para>
Create a role definition that gives the user the Active Directory
assignment, for example:
</para>
<programlisting language="javascript">
"_id": "ad-role",
"assignments": {
"ad": {
"attributes": [
{
"name": "adSystems",
"value": [
"CN=fileshare,O=corp",
"CN=desktop,O=corp",
"CN=terminal,O=corp",
"CN=intranet,O=corp"
],
"assignmentOperation": "replaceTarget"
}
]
}
</programlisting>
</listitem>
<listitem>
<para>Add the role directly as a value of the user's
<literal>"roles"</literal> attribute.</para>
<programlisting>
"roles" : [
"name" : "managed/role/ad-role",
"name" : "openidm-authorized"
]
</programlisting>
</listitem>
<listitem>
<para>
Add a condition in the mapping that restricts provisioning to users who
have the <literal>"ad"</literal> assignment as an effective assignment.
The effective assignments are calculated from the values in the user's
<literal>"roles"</literal> attribute.
</para>
<programlisting language="java">
{
"mappings": [
{
"name": "managedUser_systemAdAccounts",
"source": "managed/user",
"sourceCondition": {
"effectiveAssignments": "ad"
},
"target": "system/ad/account"
...
}
]
}
</programlisting>
</listitem>
</orderedlist>
</section>
</section>
<section xml:id="test-effective-roles">
<title>Testing the Roles Mechanism</title>
<procedure >
<para>
The following sample procedure creates a new role that includes an
assignment, adds that role to the user entry <literal>bjensen</literal> and
then shows how bjensen's effective assignments have been generated.
</para>
<step>
<para>
Create the role definition over REST.
</para>
<para>
This example uses a PUT request to create the role definition, so that we
can specify the role <literal>_id</literal>. The example adds a role
definition with the ID <literal>ldap-role</literal>. The role ID is used
to assign the role directly to the user entry.
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--header "If-None-Match: *" \
--request PUT \
--data '{
"assignments": {
"ldap": {
"attributes": [
{
"name": "ldapSystems",
"value": [
"cn=printers,ou=Groups,dc=example,dc=com",
"cn=intranet,ou=Groups,dc=example,dc=com"
],
"operation": "replaceTarget"
}
]
}
}
}' \
"https://localhost:8443/openidm/managed/role/ldap-role"</userinput>
<computeroutput>{
"assignments": {
"ldap": {
"attributes": [
{
"name": "ldapSystems",
"operation": "replaceTarget",
"value": [
"cn=printers,ou=Groups,dc=example,dc=com",
"cn=intranet,ou=Groups,dc=example,dc=com"
]
}
]
}
},
"_id": "ldap-role",
"_rev": "0"
}</computeroutput>
</screen>
</step>
<step>
<para>
The <literal>ldap-role</literal> includes one assignment, named
<literal>ldap</literal>. Add a mapping for the assignment, by adding the
following lines to your <literal>sync.json</literal> file:
</para>
<programlisting language="javascript">
"mappings":[
"assignmentsToMap":[
"ldap"
],
]</programlisting>
<para>
By default, OpenIDM addresses any change in role assignments with the
assignment operations defined in the
<filename>defaultMapping.js</filename> file. You can modify this behavior
by writing custom <literal>onAssignment</literal> and
<literal>onUnassignment</literal> scripts.
</para>
</step>
<step>
<para>
Assign the role to user <literal>bjensen</literal>, whose ID is
<literal>2e78fd22-a7cb-4585-9570-5f649e8abd25</literal>.
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--header "If-Match: *" \
--request PATCH \
--data '[
{
"operation": "replace",
"field": "/roles",
"value": [
"openidm-authorized",
"managed/role/ldap-role"
]
}
]' \
"https://localhost:8443/openidm/managed/user/2e78fd22-a7cb-4585-9570-5f649e8abd25"</userinput>
<computeroutput>{
"mail": "bjensen@example.com",
"sn": "Jensen",
"passwordAttempts": "0",
"address2": "",
"lastPasswordAttempt": "Thu October 23 2014 12:49:32 GMT+0200 (SAST)",
"givenName": "Barbara",
"city": "",
"country": "",
"_rev": "2",
"lastPasswordSet": "",
"postalCode": "",
"_id": "2e78fd22-a7cb-4585-9570-5f649e8abd25",
"accountStatus": "active",
"description": "Created for OpenIDM",
"roles": [
"openidm-authorized",
"managed/role/ldap-role"
],
"telephoneNumber": "1-360-229-7105",
"postalAddress": "",
"userName": "bjensen",
"stateProvince": "",
"displayName": "Barbara Jensen"
}</computeroutput>
</screen>
</step>
<step>
<para>
Query <literal>bjensen's</literal> user entry to verify that her
effective assignments have been updated.
</para>
<screen><userinput>$ curl \
--cacert self-signed.crt \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--request GET \
"https://localhost:8443/openidm/managed/user/2e78fd22-a7cb-4585-9570-5f649e8abd25"</userinput>
<computeroutput>...
{
"effectiveAssignments": {
"ldap": {
"attributes": [
{
"assignedThrough": "managed/role/ldap-role",
"name": "ldapSystems",
"operation": "replaceTarget",
"value": [
"cn=printers,ou=Groups,dc=example,dc=com",
"cn=intranet,ou=Groups,dc=example,dc=com"
]
}
]
}
},
...</computeroutput>
</screen>
<para>
Note that bjensen's effective assignments have been updated to include the
assignments provided by the <literal>ldap-role</literal> role.
</para>
</step>
</procedure>
</section>
<section xml:id="dynamic-role-assignments">
<title>Adding Support for Dynamic Assignments</title>
<para>
Although support for dynamic role assignments is not provided by default,
it can easily be added with a custom script, as follows.
</para>
<procedure>
<step>
<para>
Copy the default effective roles script to your project's
<literal>script/roles</literal> directory.
</para>
<screen>
$ cp /path/to/openidm/bin/defaults/script/roles/effectiveRoles.js \
<replaceable>project-dir</replaceable>/script/roles/
</screen>
<para>
The new script will override the default effective roles script.
</para>
</step>
<step>
<para>
Modify the effective roles script to include the dynamic role assignment
logic.
</para>
<para>
For example, to enable dynamic role assignment for the
<literal>example</literal> organization, you might add the following
extract after the section:
</para>
<programlisting language="java">
// This is the location to expand to dynamic roles,
// project role script return values can then be added via
// effectiveRoles = effectiveRoles.concat(dynamicRolesArray);
</programlisting>
<programlisting language="java">
if (object.org === 'example') {
effectiveRoles = effectiveRoles.concat(['dynamic-role1', 'dynamic-role2']);
}
</programlisting>
</step>
<step performance="optional">
<para>
To apply changes to the dynamic assignment rules to existing users, run a
reconciliation operation on those users.
</para>
</step>
</procedure>
<para>
Note that changes to dynamic role assignments for existing users require a
manual reconciliation of the affected group of users for those changes to
take effect. So, if a new dynamic role definition is created, if an
existing dynamic role definition is changed, or if changes are made to the
dynamic assignment rule, the group of users affected by that assignment
rule must be reconciled manually.
</para>
<para>
When a user entry is changed or synchronized, however, all dynamic role
assignments are reassessed automatically.
</para>
</section>
<section xml:id="managed-role-script-hooks">
<title>Managed Role Object Script Hooks</title>
<para>
In addition to the functionality provided by the assignments, a managed
role object has script hooks that enable you to configure role behavior.
The managed role object has the following structure in the managed objects
configuration file (<filename>managed.json</filename>):
</para>
<programlisting language="javascript">{
"name" : "role",
"postCreate" : {
"type" : "text/javascript",
"file" : "roles/update-users-of-role.js"
},
"postUpdate" : {
"type" : "text/javascript",
"file" : "roles/update-users-of-role.js"
},
"postDelete" : {
"type" : "text/javascript",
"file" : "roles/update-users-of-role.js"
}
}</programlisting>
<para>
The <literal>"postCreate"</literal>, <literal>"postUpdate"</literal>, and
<literal>"postDelete"</literal> properties enable you to specify what
should happen when a role definition is created, updated, or deleted. By
default, the <filename>update-users-of-role.js</filename> script runs in
each of these cases.
</para>
<para>
The <filename>update-users-of-role.js</filename> script includes a
<literal>triggerSyncCheck</literal> attribute, which reviews the
<literal>effectiveRoles</literal> and <literal>effectiveAssignments</literal>
virtual attributes, to determine whether OpenIDM should run a
synchronization operation on these attributes.
</para>
<para>
This script iterates over all managed users, locates the users who have
been assigned this role, and regenerates their effective assignments on the
target resource. So, for example, if the role <literal>"ldap"</literal>
gives a user an assignment on the resource "Active Directory", when that
role definition is changed, a reconciliation operation runs to update the
assignment for that user on the "Active Directory" resource.
</para>
</section>
</section>
</chapter>