Index: openacs-4/packages/acs-core-docs/www/permissions-tediously-explained.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/permissions-tediously-explained.html,v diff -u -r1.36 -r1.36.2.1 --- openacs-4/packages/acs-core-docs/www/permissions-tediously-explained.html 16 Feb 2005 00:21:03 -0000 1.36 +++ openacs-4/packages/acs-core-docs/www/permissions-tediously-explained.html 26 Aug 2005 00:02:30 -0000 1.36.2.1 @@ -1,6 +1,6 @@ -OpenACS Permissions Tediously Explained

OpenACS Permissions Tediously Explained

+OpenACS Permissions Tediously Explained

OpenACS Permissions Tediously Explained

by Vadim Nasardinov. Modified and converted to Docbook XML by Roberto Mello -

The code has been modified since this document was written so it is now out of date. See this forum thread.

Overview

+

The code has been modified since this document was written so it is now out of date. See this forum thread.

Overview

The general permissions system has a relatively complex data model in OpenACS. Developers who haven't had the time to learn the internals of the data model may end up writing seemingly correct code that crashes their system in @@ -14,11 +14,11 @@ system internals.

In OpenACS 4.x, most of the interesting tables are expected to extend (subtype) - the acs_objects table, i.e. they are expected to have an integer - primary key column that references the object_id column of - acs_objects. + the acs_objects table, i.e. they are expected to have an integer + primary key column that references the object_id column of + acs_objects.

-create table acs_objects (
+create table acs_objects (
       object_id             integer
           not null
           constraint acs_objects_pk primary key,
@@ -42,23 +42,23 @@
 );
     

This means that any interesting entity (object) - in the system has an entry in the acs_objects. This + in the system has an entry in the acs_objects. This allows developers to define relationships between any two entities A and B by defining a relationship between their corresponding entries - in the acs_objects table. One of the applications of this + in the acs_objects table. One of the applications of this powerful capability is the general permissions system.

- At the heart of the permission system are two tables: acs_privileges - and acs_permissions. + At the heart of the permission system are two tables: acs_privileges + and acs_permissions.

-  create table acs_privileges (
+  create table acs_privileges (
       privilege           varchar2(100) not null
           constraint acs_privileges_pk primary key,
       pretty_name         varchar2(100),
       pretty_plural       varchar2(100)
   );
     
-  create table acs_permissions (
+  create table acs_permissions (
       object_id
           not null
           constraint acs_permissions_on_what_id_fk references acs_objects (object_id),
@@ -72,14 +72,14 @@
           primary key (object_id, grantee_id, privilege)
   );
     

- The acs_privileges table stores + The acs_privileges table stores named privileges like read, write, delete, create, and - admin. The acs_permissions + admin. The acs_permissions table stores assertions of the form:

- Who (grantee_id) can do what (privilege) - on which object (object_id). + Who (grantee_id) can do what (privilege) + on which object (object_id).

The naive approach to managing system security would be to require application developers to store permission information explicitly about every object, i.e. if the system has 100,000 and 1,000 users @@ -97,26 +97,44 @@ necessity to explicitly maintain security information for every single object. There are three kinds of hierarchies involved. These are discussed in the following sections. -

Context Hierarchy

+

Context Hierarchy

Suppose objects A, B, ..., and F form the following hierarchy. -

Table�11.2.�Context Hierarchy Example

A

- object_id=10 -

B

- object_id=20 -

C

- object_id=30 -

D

- object_id=40 -

E

- object_id=50 -

F

- object_id=60 -

+

Table�11.2.�Context Hierarchy Example

+ A +

+ object_id=10 +

+
+ B +

+ object_id=20 +

+
+ C +

+ object_id=30 +

+
+ D +

+ object_id=40 +

+
+ E +

+ object_id=50 +

+
+ F +

+ object_id=60 +

+

This can be represented in the acs_objects table by the following entries: -

Table�11.3.�acs_objects example data

object_idcontext_id
2010
3010
4020
5020
6030

+

Table�11.3.�acs_objects example data

object_idcontext_id
2010
3010
4020
5020
6030

The first entry tells us that object 20 is the descendant of object 10, and the third entry shows that object 40 is the descendant of object 20. By running a CONNECT BY query, @@ -142,9 +160,9 @@ Despite its potentially great storage costs, maintaining a flattened representation of the context tree is exactly what OpenACS 4.x does. The flattened context tree is stored in the - acs_object_context_index table. + acs_object_context_index table.

-  create table acs_object_context_index (
+  create table acs_object_context_index (
       object_id
           not null
           constraint acs_obj_context_idx_obj_id_fk references acs_objects (object_id),
@@ -162,12 +180,12 @@
       an index-organized
       table, which means it is substantially optimized for access by primary key.
       Number two, as the above computations suggest, the size of the table
-      grows polynomially
+      grows polynomially
       with respect to the average number of descendants that an object
-      has, and exponentially
+      has, and exponentially
       with respect to the depth of the context tree. 
     

- The acs_object_context_index is kept in sync with the + The acs_object_context_index is kept in sync with the acs_objects table by triggers like this:

@@ -200,34 +218,46 @@
 

One final note about acs_objects. By setting - an object's security_inherit_p column to 'f', you can stop permissions + an object's security_inherit_p column to 'f', you can stop permissions from cascading down the context tree. In the following example, Joe does not have the read permissions on C and F. -


-A
-object_id=10
+

+


+A
+object_id=10
readable�by�Joe
- ������


-B
-object_id=20
+ ������

+
+


+B
+object_id=20
readable�by�Joe
-��������������


-C
-object_id=30
+��������������

+
+


+C
+object_id=30
security_inherit_p�=�'f'
not�readable�by�Joe
- ������


-D
-object_id=40
- ������


-E
-object_id=50
- ������


-F
-object_id=60
+ ������

+
+


+D
+object_id=40
+ ������

+
+


+E
+object_id=50
+ ������

+
+


+F
+object_id=60
security_inherit_p�=�'f'
not�readable�by�Joe
- ������

Privilege Hierarchy

+ ������

+

Privilege Hierarchy

Privileges are also organized hierarchically. In addition to the five main system privileges defined in the ACS Kernel data model, application developers may define their own. Note, @@ -243,9 +273,9 @@ privileges are tied. Privileges are structured as follows.

admin
createdeletereadwrite

The parent-child relationship between privileges is represented in - the acs_privilege_hierarchy table: + the acs_privilege_hierarchy table:

-  create table acs_privilege_hierarchy (
+  create table acs_privilege_hierarchy (
       privilege
           not null
           constraint acs_priv_hier_priv_fk references acs_privileges (privilege),
@@ -259,7 +289,7 @@
       As in the case of the context hierarchy, it is convenient to have a flattened representation
       of this hierarchal structure.  This is accomplished by defining the following view. 
     

-  create or replace view acs_privilege_descendant_map
+  create or replace view acs_privilege_descendant_map
   as
   select
     p1.privilege,
@@ -284,11 +314,19 @@
       reasonably small, there is no pressing need to cache the flattened ansector-descendant
       view of the privilege hierarchy in a specially maintained table like
       it is done in the case of the context hierarchy.
-    

Party Hierarchy

+

Party Hierarchy

Now for the third hierarchy playing a promiment role in the permission system. The party data model is set up as follows. -

-  create table parties (
+    

+ parties +
+ persons + + groups +
+ users +
+  create table parties (
       party_id
           not null
           constraint parties_party_id_fk references acs_objects (object_id)
@@ -298,7 +336,7 @@
       url                 varchar2(200)
   );
     
-  create table persons (
+  create table persons (
       person_id
           not null
           constraint persons_person_id_fk references parties (party_id)
@@ -309,7 +347,7 @@
           not null
   );
     
-  create table users (
+  create table users (
       user_id
           not null
           constraint users_user_id_fk references persons (person_id)
@@ -318,17 +356,17 @@
       -- other attributes
   );
     
 
-  create table groups (
+  create table groups (
       group_id
           not null
           constraint groups_group_id_fk references parties (party_id)
           constraint groups_pk primary key,
       group_name           varchar2(100) not null
   );
     

- Recall that the grantee_id column of the + Recall that the grantee_id column of the acs_permissions table references - parties.party_id. + parties.party_id. This means that you can grant a privilege on an object to a party, person, user, or group. Groups represent aggregations of parties. The most common scenario that you are likely to encounter is a group that is a collection of users, although you could also @@ -339,9 +377,9 @@ a group named Pranksters, you can assign membership to Pete, Poly, and Penelope. The fact that these users are members of the Pranksters group will be recorded in the - membership_rels and acs_rels tables: + membership_rels and acs_rels tables:

-  create table acs_rels (
+  create table acs_rels (
       rel_id
           not null
           constraint acs_rels_rel_id_fk references acs_objects (object_id)
@@ -359,7 +397,7 @@
           unique (rel_type, object_id_one, object_id_two)
   );
     
-  create table membership_rels (
+  create table membership_rels (
       rel_id
           constraint membership_rel_rel_id_fk references acs_rels (rel_id)
           constraint membership_rel_rel_id_pk primary key,
@@ -371,7 +409,13 @@
     

The acs_rels table entries would look like so: -

rel_typeobject_oneobject_two
+

+ rel_type + + object_one + + object_two +
membership_rel Pranksters @@ -393,20 +437,26 @@ Another way of building up groups is by adding subgroups. Suppose we define Merry Pranksters and Sad Pranksters as subgroups of Pranksters. We say that the Pranksters group - is composed of + is composed of groups Merry Pranksters and Sad Pranksters. This information is stored in the acs_rels - and composition_rels tables. + and composition_rels tables.

-create table composition_rels (
+create table composition_rels (
     rel_id
         constraint composition_rel_rel_id_fk references acs_rels (rel_id)
         constraint composition_rel_rel_id_pk primary key
 );
     

The relevant entries in the acs_rels look like so. -

rel_typeobject_oneobject_two
+

+ rel_type + + object_one + + object_two +
composition_rel Pranksters @@ -436,7 +486,7 @@ reducing the performance hit incurred by hierarchical queries is to cache query results in a table maintained by triggers. The OpenACS 4.x data model defines two such tables:

- create table group_component_index (
+ create table group_component_index (
           group_id        not null
                           constraint group_comp_index_group_id_fk
                           references groups (group_id),
@@ -455,7 +505,7 @@
           primary key (group_id, component_id, rel_id)
   ) organization index;
     
-  create table group_member_index (
+  create table group_member_index (
       group_id
           not null
           constraint group_member_index_grp_id_fk references groups (group_id),
@@ -472,11 +522,11 @@
           primary key (member_id, group_id, rel_id)
   ) organization index;
     

- The group_component_index table stores a flattened representation of the + The group_component_index table stores a flattened representation of the group composition hierarchy that is maintained in sync with the acs_rels - and composition_rels tables through triggers. + and composition_rels tables through triggers.

- As far as the group_member_index table goes, I am not sure I understand its + As far as the group_member_index table goes, I am not sure I understand its purpose. It maintains group-member relationships that are resolved with respect to group composition. Note that information stored in group_member_index can be trivially derived by joining @@ -507,7 +557,7 @@ mr.rel_id = r.rel_id and r.object_id_one = gci.component_id;

- A heuristic way to verify that group_member_view is essentially identical + A heuristic way to verify that group_member_view is essentially identical to group_member_index is to compute the symmetric difference between the two:

@@ -535,16 +585,16 @@
       membership relationship resolution can be computed trivially with no hierarchical
       queries involved. There is no need to keep the view in a denormalized
       table, unless doing so results in substantial performance gains.
-    

Putting It All Together

- Security information is queried by calling the acs_permission.permission_p +

Putting It All Together

+ Security information is queried by calling the acs_permission.permission_p function in OpenACS 4.x+. This is accessible from Tcl via the - permission::permission_p procedure. + permission::permission_p procedure.

  
   create or replace package body acs_permission
   as
     -- some stuff removed for the sake of brevity
   
-    function permission_p (
+    function permission_p (
       object_id	 acs_objects.object_id%TYPE,
       party_id	 parties.party_id%TYPE,
       privilege	 acs_privileges.privilege%TYPE
@@ -570,7 +620,7 @@
       the party composition (and membership) hierarchy. As such,
       it contains an extremely large number of rows. About
       the only kind of query you can run against it is the one
-      performed by the acs_permission.permission_p
+      performed by the acs_permission.permission_p
       function.  Anything other than that would take forever to
       finish or would ultimately result in an Oracle error.
     

@@ -606,7 +656,7 @@ end; /

- The acs_permission.revoke_permission function merely runs a + The acs_permission.revoke_permission function merely runs a delete statement like so:

  
   delete from
@@ -616,9 +666,15 @@
      and grantee_id = revoke_permission.grantee_id
      and privilege = revoke_permission.privilege;
     

- Note that in the above example, acs_permissions had only + Note that in the above example, acs_permissions had only one entry that needed to be deleted: -

object_idgrantee_idprivilege
+

+ object_id + + grantee_id + + privilege +
default_context registered_users @@ -627,9 +683,9 @@

The above script would never get around to deleting this entry because it had to loop through a gazillion rows in the humongous - acs_object_party_privilege_map view. -

Appendix: Various View Definitions

-create or replace view acs_object_party_privilege_map
+      acs_object_party_privilege_map view. 
+    

Appendix: Various View Definitions

+create or replace view acs_object_party_privilege_map
 as
 select
   ogpm.object_id,
@@ -648,7 +704,7 @@
 from
   acs_object_grantee_priv_map;
     
-create or replace view acs_object_grantee_priv_map
+create or replace view acs_object_grantee_priv_map
 as
 select
   a.object_id,
@@ -660,7 +716,7 @@
 where
   a.privilege = m.privilege;
     
 
-create or replace view acs_permissions_all
+create or replace view acs_permissions_all
 as
 select
   op.object_id,
@@ -672,7 +728,7 @@
 where
   op.ancestor_id = p.object_id;
     
-create or replace view acs_object_paths
+create or replace view acs_object_paths
 as
 select
   object_id,
@@ -682,7 +738,7 @@
   acs_object_context_index;
     
 
 
-create or replace view group_member_map
+create or replace view group_member_map
 as
 select
   group_id,