ACL computations

Yesterday my skypemate complained me about last Scott Roth’s post:

Is something changed in the Documentum platform or he is completely wrong, but he has may years of experience. I cannot believe that. I supposed that the 7.2 version changed the most permissive logic, the “standard” most permissive, it seems a post written by a Documentum newbie. I need to unsubscribe from his blog, there are not useful blogs about documentum.

The last point about useful blogs about documentum was insulting, so I think it is required to clarify how ACL computations work in Documentum.

Three years ago I got engaged in the investigation of the following performance problem:

Customer’s application associates every user with a group and grants privileges to associated group rather than certain user – this idea is very clear because when you need to grant “the same as certain user’s privileges” to specific user you just need to modify group memberships. Unfortunately, Documentum has a couple of performance issues related to such design, these issues are:

  • if ACL contains a lot of group entries, computation of effective privileges for specific user (i.e. “get,c,l,_permit,user_name”) becomes extremely slow (I saw some cases when IDfSysObject.getPermitEx(“username”) call took minutes) – if ACL entry contains a group Content Server tries to figure out whether user belongs to that group or not, i.e. Content Server performs one sql select per group entry
  • if ACL contains a lot entries, saving this ACL becomes extremely slow – when saving ACL Content Server tries to figure out whether ACL entry relates to user or group and validate the existence of corresponding user or group, in order to do that Content Server performs selects from database: one select if ACL entry relates to group and three selects if ACL entry relates to user – it’s more useful to put group entries in ACL, isn’t it?

The first issue seems to be resolved in recent releases of Content Server – now IDfSysObject.getPermitEx(“username”) call is backed up by the following single SQL query:

SELECT acl.r_accessor_name,
       acl.r_accessor_permit,
       acl.r_permit_type,
       acl.r_is_group
  FROM dm_acl_r acl, dm_group_r gr1, dm_group_r gr2
 WHERE     acl.r_object_id = :acl_id
       AND acl.r_is_group = 1
       AND gr1.users_names = :user_name
       AND gr1.r_object_id = gr2.r_object_id
       AND gr2.i_nondyn_supergroups_names IS NOT NULL
       AND gr2.i_nondyn_supergroups_names = acl.r_accessor_name
UNION
SELECT acl.r_accessor_name,
       acl.r_accessor_permit,
       acl.r_permit_type,
       acl.r_is_group
  FROM dm_acl_r acl
 WHERE     acl.r_object_id = :acl_id
       AND (   acl.r_accessor_name = :user_name
            OR acl.r_accessor_name = 'dm_world')

The second issue is still not resolved, moreover, there is no ETA for that, it’s very embarrassing because there is no need to perform a lot of SQL selects at all, let’s clarify. Content Server Performs following SQL selects:

-- determine whether ACL entry relates
-- to user or group
SELECT s.is_dynamic, s.group_class
  FROM dm_group_s s
 WHERE s.group_name = :p0;

-- query to get r_object_id or dm_user
SELECT r_object_id
  FROM dm_user_s
 WHERE user_name = :p0;

-- fetching user
  SELECT *
    FROM DM_USER_RV dm_dbalias_B, DM_USER_SV dm_dbalias_C
   WHERE (    dm_dbalias_C.R_OBJECT_ID = :dmb_handle
          AND dm_dbalias_C.R_OBJECT_ID = dm_dbalias_B.R_OBJECT_ID)
ORDER BY dm_dbalias_B.R_OBJECT_ID, dm_dbalias_B.I_POSITION;

last two queries are intended to check whether user exists or not, actually in order to perform the same it is enough to replace the first query by:

SELECT u.r_is_group
  FROM dm_user_s u
 WHERE u.user_name = :p0;

first query is intended to populate following attributes in dm_acl:

  • r_is_group – not required at all due to ACL computation algorithm, see explanation below
  • i_has_required_groups – required for MACL entries only
  • i_has_required_group_set – required for MACL entries only

Why r_is_group in dm_acl is not required at all? The explanation is very obvious: when Content Server tries to determine permissions of current user it retrieves information about all groups user belongs to from database, so it already has information about user’s groups and it is enough to check whether r_accessor_name in ACL entry exists in user’s group set or not, when Content Server tries to determine permissions of non-current user (see above SQL select) it is enough to use following SQL select:

SELECT acl.r_accessor_name,
       acl.r_accessor_permit,
       acl.r_permit_type,
       acl.r_is_group
  FROM dm_acl_r acl, dm_group_r gr1, dm_group_r gr2
 WHERE     acl.r_object_id = :acl_id
       -- AND acl.r_is_group = 1
       AND gr1.users_names = :user_name
       AND gr1.r_object_id = gr2.r_object_id
       AND gr2.i_nondyn_supergroups_names IS NOT NULL
       AND gr2.i_nondyn_supergroups_names = acl.r_accessor_name
UNION
SELECT acl.r_accessor_name,
       acl.r_accessor_permit,
       acl.r_permit_type,
       acl.r_is_group
  FROM dm_acl_r acl
 WHERE     acl.r_object_id = :acl_id
       AND (   acl.r_accessor_name = :user_name
            OR acl.r_accessor_name = 'dm_world')

Now about ACL computation logic.

The general logic is:

Sysobject’s owner:

+ implicit default permit (DM_PERMIT_READ)
+ permit granted to dm_owner
+ permits granted to the specific user
+ permits granted to any groups the user belongs to
- restrictions on specific user
- restrictions on any groups the user belongs to
- required group restrictions
- required group set restriction
_________________________________________________
RESULT: MAX(Calculated Permit, DM_PERMIT_BROWSE)

superuser:

+ implicit default permit (DM_PERMIT_READ)
+ permit granted to dm_owner
+ permits granted to the specific user
+ permits granted to any groups the user belongs to
_________________________________________________
RESULT: MAX(Calculated Permit, DM_PERMIT_READ)

regular user:

+ permits granted to the specific user
+ permits granted to any groups the user belongs to
- restrictions on specific user
- restrictions on any groups the user belongs to
- required group restrictions
- required group set restriction
_________________________________________________
RESULT: Calculated Permit

Non-common logic:

  • for regular users dm_escalated_* groups override restrictions on user/group but not required group/group set restrictions
  • dm_read_all, dm_browse_all group membership overrides all MACLs
  • minimum owner’s permissions actually is MAX(dm_docbase_config.minimum_owner_permit, DM_BROWSE_ALL)

What is wrong in last Scott Roth’s post? Implication “I’m getting weird results, so I think that product has certain behaviour” is wrong, the correct is “I’m getting weird results, here is my proof of concept”.

One thought on “ACL computations

  1. Pingback: Does Documentum Enforce Least Privilege? | dm_misc: Miscellaneous Documentum Information

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s