Class Useraccount

Description

Methods to access properties of the account of the logged in user

This deals mainly with retrieving information about the user that is currently logged in. There is one exception: a user that is NOT logged in can still have a $USER object, but there are no privileges in that case. The special user_id in that case is 0.

The constructor reads the important data from the database. This includes things like the full name of the user and the email address. This information is stored in the object and can be used, e.g. $USER->email. This information is basically copied from the table 'users'.

Furthermore, any properties for this user are retrieved from the table 'users_properties'. All properties are stored in an array. These can be used directly via $USER->properties['foobar'].

Access Control

Finally we deal with access control. This has become quite complex but still managable (I hope). There are six tables dealing with acl's:

  • acls: site-wide permissions for jobs, intranet, modules and nodes
  • acls_areas: permissions for intranet, modules and nodes at the area level
  • acls_nodes: permissions for modules and nodes a the node level
  • acls_modules: permissions for modules at the site level
  • acls_modules_areas: permissions for modules at the area level
  • acls_modules_nodes: permissions for modules at the node level
The user has at least one associated ACL: the acl_id field in the user record. Additional ACLs are associated with the user via group memberships. All ACLs are integer bitmasks where a '1' grants a permission for something and a '0' denies permission.

All bits '0' is a special case: this is the default (nothing allowed) and hence does not have to be stored: the mere non-existence of permissions implies no permissions.

All bits '1' is also a special case, dubbed 'ROLE_GURU'. If an ACL has this value, it means that all current (and future) permissions are granted. A user with ROLE_GURU can do anything.

Of the six tables, only the first one (acls) is read immediately in the constructor. The others are read on demand. This is done by initially setting the corresponding cache variable to NULL. If the table has been read, the variable will always be of type 'array', even though that array may be empty (indicating no permissions).

The permissions from the ACLs are combined between the user's acl and the optional group-acls. Only the combination of user and group permissions is cached in order to save space. This is done by OR'ing the permission bits. Note that the condition all bits '0' is not stored, also to save space.

There are some functions to test for individual permissions:

  • has_site_permissions()
  • has_area_permissions()
  • has_node_permissions()
  • has_module_site_permissions()
  • has_module_area_permissions()
  • has_module_node_permissions()
  • has_job_permissions()
  • has_intranet_permissions()
Example: in order to determine wheter a user has access to the intranet in area #2, the following could be used:

    $area_id = 2; if ($USER->has_intranet_permissions(ACL_ROLE_INTRANET_ACCESS,$area_id)) {     .... }

The effect of this call is as follows. First the routine checks the (already cached) intranet-permissions at the site level. If access is granted at the site level, there is no need to look any further because obviously this user has access to this intranet (private area) and all other current and future intranets. If not, the routine looks at intranet permissions at the area level. The first time this will trigger reading and caching the table for area-level permissions. In this case (intranet-access), the area-level permissions provide the definitive go/nogo for this user (there is no point in having intranet-access-permissions at the node level).

Note that the 'lower' ACL is only checked if the 'higher' does not provide answers. This saves unnecessary trips to the database.

Note that this works much the same for the other has_xxx_permissions(): first the site-level is tried, then the area-level and finally the node-level (when applicable).

ACLs for modules

Access to the CMS itself is fairly fine-grained. The permissions are stored in the fields 'permissions_nodes' in the tables 'acls' (site-level), acls_areas (area-level) and acls_nodes (node-level). These permissions basically deal with the page manager (the piece de resistance of the whole system).

However, there are modules that can be linked to nodes, e.g. a chat or a forum or an agenda which also require autorised users and permissions. These permissions are stored in three tables: acls_modules (site-level). acls_modules_areas (area-level) and acls_modules_nodes (node-level). This works pretty much the same as the permissions for the CMS itself, be it that there is an extra parameter, namely the module_id.

Once again, the permissions are only read when necessary. I.e., if the site-level already grants a permission, the area and node level are not read from the database. This saves time and space.

Roles and permissions

Permissions are indivial flags that allow or disallow a certain feature, e.g. 'adding a page to a section'. In order to keep these permissions manageable groups of permissions are combined yielding a limited number of 'roles'. A 'role' is a combination of 1 or more permission bits. Assigning permissions (in the user account manager) is done by assigning these 'roles' to a user, either sitewide, areawide or per node. These roles are dubbed sitemaster, areamaster, sectionmaster, pagemaster and contentmaster. The 'higher' roles incoporate the 'lower' roles: permissions of a sectionmaster include those of a pagemaster and a contentmaster.

Located in /program/lib/useraccount.class.php (line 254)


	
			
Variable Summary
 array $acls
 null|array $acls_areas
 null|array $acls_modules
 null|array $acls_modules_areas
 null|array $acls_modules_nodes
 null|array $acls_nodes
 int $acl_id
 string $editor
 string $email
 string $full_name
 string $language_key
 string $path
 array $properties
 string $skin
 string $username
 int $user_id
Method Summary
 void Useraccount ([int $user_id = 0])
 array fetch_acls_from_table (string $table)
 bool has_area_permissions (int $mask, int $area_id, [string $field = 'permissions_nodes'])
 bool has_intranet_permissions (int $mask, int $area_id)
 bool has_job_permissions (int $mask)
 bool has_module_area_permissions (int $mask, int $module_id, int $area_id)
 bool has_module_node_permissions (int $mask, int $module_id, int $area_id, int $node_id)
 bool has_module_site_permissions (int $mask, int $module_id)
 bool has_node_permissions (int $mask, int $area_id, int $node_id, [string $field = 'permissions_nodes'])
 bool has_site_permissions (int $mask, [string $field = 'permissions_nodes'])
 bool is_admin ()
 bool is_admin_pagemanager (int $area_id)
 string where_acl_id ([string $field = 'acl_id'])
Variables
array $acls = array('permissions_jobs' => ACL_ROLE_NONE,
'permissions_intranet' => ACL_ROLE_NONE,
'permissions_modules' => ACL_ROLE_NONE,
'permissions_nodes' => ACL_ROLE_NONE)
(line 280)
  • var: $acls caches site-level permissions, keyed by [$field]
null|array $acls_areas = NULL (line 286)
  • var: $acls_areas caches area-level permissions, keyed by [$area_id][$field]
null|array $acls_modules = NULL (line 292)
  • var: $acls_modules site-level modules permissions, keyed by [$module_id]
null|array $acls_modules_areas = NULL (line 295)
  • var: $acls_modules_areas area-level modules permissions, by [$module_id][$area_id]
null|array $acls_modules_nodes = NULL (line 298)
  • var: $acls_modules_nodes node-level modules permissions, by [$module_id][$node_id]
null|array $acls_nodes = NULL (line 289)
  • var: $acls_nodes caches node-level permissions, keyed by [$node_id][$field]
int $acl_id (line 274)
  • var: $acl_id identifies the main acl for this user
array|null $area_permissions_from_nodes = NULL (line 313)
  • var: cache for admin permissions based on node permissions
string $editor (line 304)
  • var: $editor the user's preferred editor (empty means system default from $CFG->editor)
string $email (line 265)
  • var: $email
string $full_name (line 262)
  • var: $full_name
bool $is_logged_in = FALSE (line 310)
  • var: $is_logged_in TRUE if user is logged in, FALSE otherwise
string $language_key (line 268)
  • var: $language_key
string $path (line 271)
  • var: $path directory holding personal data files relative to "{$CFG->datadir}/users/"
array $properties = array() (line 301)
  • var: $properties
array $related_acls = array() (line 277)
  • var: $related_acls holds acl_id -> groupname/capacity pairs related to this user
string $skin (line 307)
  • var: $skin the preferred skin for this user
string $username (line 259)
  • var: $username
int $user_id (line 256)
  • var: $user_id
Methods
Constructor Useraccount (line 330)

get pertinent user information in core

Note: We used to have a bool named 'high_visibility' in both the users table and this class. That changed with version 0.90.4 (April 2012) and we now have a field and variable 'skin' which is a varchar(20). The values were mapped as follows: high_availability=FALSE -> skin='base' and high_availability=TRUE -> skin='textonly'. The extra test for the existence of $record['skin'] was necessary for the case where the user wanted to upgrade from 0.90.3 to 0.90.4 where 'skin' replaced 'high_visibility'.

void Useraccount ([int $user_id = 0])
  • int $user_id: identifies data from which user to load, 0 means no user/a passerby
fetch_acls_from_table (line 678)

retrieve acl-data from table into a sparse array

  • return: zero or more elements with permissions
array fetch_acls_from_table (string $table)
  • string $table: name of the table which holds the acls
has_area_permissions (line 421)

determine user's permissions for an area

this looks at the area-level permissions for manipulating nodes and areas. However, we first look at the site-level permissions. If those already satisfy the request, we return immediately. If not, the permissions are fetched from the table acls_areas or from the cached data. We only fetch the data if it is really necessary.

  • return: TRUE if at least one permission in $mask is granted, FALSE otherwise
bool has_area_permissions (int $mask, int $area_id, [string $field = 'permissions_nodes'])
  • int $mask: bitmap of OR'ed permissions to test for
  • int $area_id: which area to test
  • string $field: name of permissions to check (default 'permissions_nodes')
has_intranet_permissions (line 587)

determine user's permissions for an intranet area

this looks at the area-level permissions for intranet areas.

  • return: TRUE if at least one permission in $mask is granted, FALSE otherwise
bool has_intranet_permissions (int $mask, int $area_id)
  • int $mask: bitmap of OR'ed permissions to test for
  • int $area_id: which area to test
has_job_permissions (line 571)

determine user's permissions for a job

  • return: TRUE if at least one permission in $mask is granted, FALSE otherwise
bool has_job_permissions (int $mask)
  • int $mask: bitmap of OR'ed permissions to test for
has_module_area_permissions (line 513)

determine user's permissions for a module at the area level

this looks at the area-level permissions for manipulating nodes and areas. However, we first look at the site-level permissions. If those already satisfy the request, we return immediately. If not, the permissions are fetched from the table acls_modules_areas or from the cached data. We only fetch the data if it is really necessary.

  • return: TRUE if at least one permission in $mask is granted, FALSE otherwise
bool has_module_area_permissions (int $mask, int $module_id, int $area_id)
  • int $mask: bitmap of OR'ed permissions to test for
  • int $area_id: which area to test
  • int $module_id: module_id identifies the module we are considering
has_module_node_permissions (line 544)

determine user's permissions for a module at the node level

  • return: TRUE if at least one permission in $mask is granted, FALSE otherwise
  • todo: FixMe: we need to take the parent nodes into account too!
bool has_module_node_permissions (int $mask, int $module_id, int $area_id, int $node_id)
  • int $mask: bitmap of OR'ed permissions to test for
  • int $area_id: which area to test
  • int $node_id: which node to test
  • int $module_id: module_id identifies the module we are considering
has_module_site_permissions (line 479)

determine user's permissions for a module at the site-level

this looks at the site-level permissions for manipulating mdules. The permissions are cached from the table acls_modules.

  • return: TRUE if at least one permission in $mask is granted, FALSE otherwise
bool has_module_site_permissions (int $mask, int $module_id)
  • int $mask: bitmap of OR'ed permissions to test for
  • int $module_id: identifies the module we are considering
has_node_permissions (line 450)

determine user's permissions for a node within an area

  • return: TRUE if at least one permission in $mask is granted, FALSE otherwise
  • todo: FixMe: we need to take the parent nodes into account too!
bool has_node_permissions (int $mask, int $area_id, int $node_id, [string $field = 'permissions_nodes'])
  • int $mask: bitmap of OR'ed permissions to test for
  • int $area_id: which area to test
  • int $node_id: which node to test
  • string $field: name of permissions to check (default 'permissions_nodes')
has_site_permissions (line 396)

determine user's permissions for the site-level

this looks at the site-level permissions for manipulating nodes and areas etc. The permissions are cached from the table acls.

  • return: TRUE if at least one permission in $mask is granted, FALSE otherwise
bool has_site_permissions (int $mask, [string $field = 'permissions_nodes'])
  • int $mask: bitmap of OR'ed permissions to test for
  • string $field: name of permissions to check (default 'permissions_nodes')
is_admin (line 604)

determine whether the user has administrator privilege

If this user has access to the admin startcenter, she is considered an administrator. Further access depends on the other bits in the job permissions, but at least she is allowed to enter the system via admin.php.

  • return: TRUE if user is considered an admin, FALSE otherwise
bool is_admin ()
is_admin_pagemanager (line 628)

determine whether the user has administrator privilege for pagemanager

This routine determines whether a user has any privileges at all for the page manager. This is true in the following cases:

  • the user has sitewide permissions that belong to one of the roles contentmaster, pagemaster, sectionmaster or areamaster, OR
  • the user has areawide permissions for one of those roles, OR
  • the user has permissions for one of those roles in at least one node in the requested area.
The calculations in the third case are cached for all areas.

  • return: TRUE if user is considered a pagemanager admin, FALSE otherwise
bool is_admin_pagemanager (int $area_id)
  • int $area_id: the area to examine
where_acl_id (line 760)

a convenient routine to construct a selection of acls

this constructs a where clause of the form '(acl_id = 1) OR (acl_id = 2) OR (acl_id = 3)'

  • return: ready-to-use where-clause without the word 'where'
string where_acl_id ([string $field = 'acl_id'])
  • string $field: identifies the fieldname to check

Documentation generated on Tue, 28 Jun 2016 19:12:29 +0200 by phpDocumentor 1.4.0