chap-users-groups-roles.xml revision a4ac3d25336cfe35c700a2e98d08ad40bd52e86b
<?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>
The following REST call creates a relatively complex role:
</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":"cns",
"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": "cns",
"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 the definitions of each of these attributes, 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. Sometimes you may
prefer to use POST to create server-assigned UUIDs. 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, you can 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>.
</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/bjensen"
</userinput>
<computeroutput>
{
"mail": "bjensen@example.com",
"sn": "Jensen",
"passwordAttempts": "0",
"address2": "",
"lastPasswordAttempt": "Thu Apr 10 2014 12:49:32 GMT+0200 (SAST)",
"givenName": "Barbara",
"city": "",
"country": "",
"_rev": "2",
"lastPasswordSet": "",
"postalCode": "",
"_id": "bjensen",
"description": "Created for OpenIDM",
"accountStatus": "active",
"telephoneNumber": "1-360-229-7105",
"roles": [ "openidm-authorized", "managed/role/newrole" ],
"effectiveAssignments" : {
"ldap" : {
"onUnassignment" : {
"type" : "text/javascript",
"file" : "roles/onUnassignment_ldap.js"
},
"onAssignment" : {
"type" : "text/javascript",
"file" : "roles/onAssignment_ldap.js"
},
"attributes" : [ {
"value" : [ "CN=employees,O=corp" ],
"assignedThrough" : "managed/role/newrole",
"assignmentOperation" : "mergeWithTarget",
"unassignmentOperation" : "removeFromTarget",
"name" : "cns"
} ]
}
},
"postalAddress": "",
"userName": "bjensen",
"stateProvince": "",
"displayName": "Babara Jensen"
}</computeroutput>
</screen>
<para>
Note the dash (<literal>-</literal>) character appended to the field name,
within the <command>-data</command> option. This character specifies that
the command appends the role that you add to the existing roles for that
user. If you do not include the dash character, the request overwrites all
current values of the <literal>"roles"</literal> attribute.
</para>
<para>
If you see a message such as "Object bjensen not found in managed/user",
you may need to substitute the <literal>_id</literal>, as output from the
<literal>query-all-ids</literal> query described in the
<link xlink:show="new" xlink:role="http://docbook.org//xlink/role/olink"
xlink:href="install-guide#run-sample2b"><citetitle>Running the Sample
</citetitle></link> section associated with Sample 2b. Take care when
configuring that sample, as it assumes that you have set up a running
instance of OpenDJ with specific data.
</para>
</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>.
</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/bjensen"</screen>
<para>
In the role definition, you can specify what should happen when an
assignment of that role is removed.
</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,
specify the role ID in the query on the <literal>managed/user</literal>
context path. It is not currently possible to 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>.
</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": [
{
"_rev": "0",
"_id": "bjensen"
}
]
}</computeroutput>
</screen>
</section>
<section xml:id="delete-role-definition">
<title>To Delete a Managed Role Definition</title>
<para>
When a role definition is removed, an "unassignment" operation is triggered
for any attributes that have been assigned to a user indirectly through
that role.
</para>
<para>
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>
{
"_id" : "newrole",
"_rev" : "2",
"assignments" : {
"ldap" : {
"onUnassignment" : {
"type" : "text/javascript",
"file" : "roles/onUnassignment_ldap.js"
},
"onAssignment" : {
"type" : "text/javascript",
"file" : "roles/onAssignment_ldap.js"
},
"attributes" : [ {
"value" : [ "CN=employees,O=corp" ],
"assignmentOperation" : "mergeWithTarget",
"unassignmentOperation" : "removeFromTarget",
"name" : "cns"
} ]
}
},
"properties" : {
"description" : "an example role"
}
}
</computeroutput>
</screen>
</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. However, the main functionality of roles is
provided in the assignments that are specified for that role.
</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>
<para>
Do remember to include the <literal>assignments</literal> field name.
OpenIDM uses it to keep assigned roles up to date.
</para>
<programlisting language="java">{
"name": "samplerole",
"_id": "samplerole",
"assignments": {
"ad": {
"attributes": [
{
"name": "cns",
"value": [
"CN=fileshare,O=corp",
"CN=desktop,O=corp",
"CN=terminal,O=corp",
"CN=intranet,O=corp"
],
"assignmentOperation": "mergeWithTarget"
}
]
},
"ldap": {
"attributes": [
{
"name": "cns",
"value": [
"CN=employees,O=corp"
],
"assignmentOperation": "mergeWithTarget"
},
{
"name": "employeeType",
"value": "employee"
}
]
}
}
}</programlisting>
<itemizedlist>
<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. These examples use a client-assigned ID, for ease
of reference, however, in production, you may make a different choice.
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>
</listitem>
<listitem>
<para>
<literal>"assignments"</literal> provide the list of assignments
(or entitlements) that this role will create on the specified system.
</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>
</listitem>
<listitem>
<para>
When you update a role by adding, updating, or removing an attribute,
that action triggers either an <literal>"assignmentOperation"</literal>
or an <literal>"unassignmentOperation"</literal>.
</para>
<para>
If you assign or unassign a role to a user, that action will also trigger
either an <literal>"assignmentOperation"</literal> or an
<literal>"unassignmentOperation"</literal>.
</para>
<para>
The <literal>"assignmentOperation"</literal> specifies the way in which
the value is applied. You can set this option to
<literal>"mergeWithTarget"</literal> or to the default,
<literal>"replaceTarget"</literal>.
</para>
<para>
In contrast, the <literal>"unassignmentOperation"</literal> specifies the
way in which the value is removed. You can set this option to
<literal>"removeFromTarget"</literal>.
</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>
<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>, <literal>"replaceTarget"</literal>
and <literal>"removeFromTarget"</literal> operations are aliases, as
defined in the <filename>defaultMapping.js</filename> file.
</para>
</listitem>
<listitem>
<para>
The <literal>"onAssignment"</literal> and
<literal>"onUnassignment"</literal> scripts are assignment-specific.
Either option supports further customization.
</para>
<para>
When you create, assign, or delete a role from a specific user entry,
OpenIDM triggers either an <literal>"onAssignment"</literal> or an
<literal>"onUnassignment"</literal> script.
</para>
<para>
Every sync operation triggers an <literal>"onAssignment"</literal> script.
In contrast, an <literal>"onUnassignment"</literal> script is triggered
only when an assignment is removed from a role, or when a role is
unassigned from a user.
</para>
<para>
If you customize an <literal>"onAssignment"</literal> or an
<literal>"onUnassignment"</literal> script, make sure the script returns
a <literal>"targetObject"</literal>. Otherwise, the script operation may
fail.
</para>
</listitem>
</itemizedlist>
<para>
Once a role has been defined, and assigned to a user, check that the
expected effective roles and effective assignments have been generated for
that user.
</para>
<para>
Then add a default mapping to your synchronization configuration to apply
the effective assignments to the target resource.
</para>
<para>
OpenIDM logs any changes to a managed role definition in the audit log.
</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 allow you to determine what should happen
when a role is created, updated or deleted. 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, so see whether OpenIDM should run a sync operation on
them.
</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 deleted, a reconciliation operation runs to remove the
assignment for that user on the "Active Directory" resource.
</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>/path/to/openidm/bin/defaults/script/roles/effectiveRoles.js</filename>
and
<filename>/path/to/openidm/bin/defaults/script/roles/effectiveAssignments.js</filename>.
You should 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>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":"cns",
"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":"cns",
"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>
<procedure xml:id="test-effective-roles">
<title>To Test Effective Roles and Assignments</title>
<para>
The following sample procedure creates a new role (<literal>"ad"</literal>)
that includes assignments, 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 role <literal>_id</literal>. The <literal>_id</literal> will
be used to assign the role directly to user entries.
</para>
<para>
The example adds a role definition with the _id <literal>ldap</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-None-Match: *" \
--request PUT \
--data '{
"assignments": {
"ldap": {
"attributes": [
{
"name": "cns",
"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"</userinput>
<computeroutput>{
"assignments": {
"ldap": {
"attributes": [
{
"name": "cns",
"operation": "replaceTarget",
"value": [
"cn=printers,ou=Groups,dc=example,dc=com",
"cn=intranet,ou=Groups,dc=example,dc=com"
]
}
]
}
},
"_id": "ldap",
"_rev": "0"
}</computeroutput>
</screen>
</step>
<step>
<para>
Add a mapping for the role to assign to your <filename>sync.json</filename>
file. For this example, the following assignment add the following lines to
<literal>sync.json</literal>:
</para>
<programlisting language="javascript">
"mappings":[
"assignmentsToMap":[
"ldap"
],
]</programlisting>
<para>
OpenIDM addresses any change in role assignments with the
<literal>onAssignment</literal> and <literal>onUnassignment</literal>
attributes in the <filename>defaultMapping.js</filename> file.
</para>
</step>
<step>
<para>
Assign the role to user <literal>bjensen</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"
]
}
]' \
"https://localhost:8443/openidm/managed/user/bjensen"</userinput>
<computeroutput>{
"mail": "bjensen@example.com",
"sn": "Jensen",
"passwordAttempts": "0",
"address2": "",
"lastPasswordAttempt": "Thu Apr 10 2014 12:49:32 GMT+0200 (SAST)",
"givenName": "Barbara",
"city": "",
"country": "",
"_rev": "2",
"lastPasswordSet": "",
"postalCode": "",
"_id": "bjensen",
"accountStatus": "active",
"description": "Created for OpenIDM",
"roles": [
"openidm-authorized",
"managed/role/ldap"
],
"telephoneNumber": "1-360-229-7105",
"postalAddress": "",
"userName": "bjensen",
"stateProvince": "",
"displayName": "Babara Jensen"
}</computeroutput>
</screen>
</step>
<step>
<para>
Query <literal>bjensen's</literal> user entry again.
</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/bjensen"</userinput>
<computeroutput>...
{
"effectiveAssignments": {
"ldap": {
"attributes": [
{
"assignedThrough": "managed/role/ldap",
"name": "cns",
"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</literal> role.
</para>
</step>
</procedure>
<procedure xml:id="dynamic-role-assignments">
<title>To Add 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>
<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. and changes to the assigned roles.
</para>
<para>
When a user entry is changed or synchronized, however, all dynamic role
assignments are reassessed automatically.
</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": "cns",
"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-role"</literal> as an effective role. The effective
roles 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": {
"effectiveRoles": "managed/role/ad-role"
},
"target": "system/ad/account"
...
}
]
}
</programlisting>
</listitem>
</orderedlist>
</section>
</section>
</section>
</chapter>