Index: openacs-4/packages/acs-core-docs/www/parties.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/parties.html,v diff -u -r1.42 -r1.43 --- openacs-4/packages/acs-core-docs/www/parties.html 17 Jul 2006 05:38:31 -0000 1.42 +++ openacs-4/packages/acs-core-docs/www/parties.html 5 Aug 2006 05:18:20 -0000 1.43 @@ -3,26 +3,28 @@ by OpenACS documentation staff.

Introduction

While many applications must deal with individuals and many applications must deal with groups, most applications must deal with individuals -or groups. It is often the case with such applications that in many -respects both individuals and groups are treated in an identical manner. It -is this latter class of application that makes it extremely useful to model -individuals and groups as specializations of one supertype. This concept is -so commonly used throughout human language and thought that we don't even -need to invent for it some bizarre and specialized terminology. This -supertype is called a "party".

A classic example use of the "party" supertype is evident -in a common address book. A typical person's address book might contain -the address of his doctor, and his cable company. So what do we label the -first field in an entry in his address book? It isn't a person, and it -isn't a company. It is a "party".

The Data Model

Most developers who do significant work with the OpenACS will become -intimately familiar with the parties data model, and probably extend it on -many occasions. For this reason the parties developer guide will begin with -an introduction to the data model.

Parties

The central table in the parties data model is the parties table itself. +or groups. It is often the case with such +applications that + both individuals and groups are treated identically. Modelling +individuals and groups as specializations of one supertype is a +practical way to manage both. This concept is +so mundane that there is +no need to invent special terminology. This +supertype is called a "party".

A classic example of the "party" supertype is evident +in address books. A typical address book might contain +the address of a doctor, grocery store, and friend. The +first field in an entry in the address book is not labeled a person or +company, but a "party". +

The Data Model

The parties developer guide begins with +an introduction to the parties data model, since OpenACS +community applications likely require using it in some way.

Parties

The central table in the parties data model is the parties table itself. Every party has exactly one row in this table. Every party has an optional unique email address and an optional url. A party is an acs object, so -permissions may granted and revoked on parties and auditing information is +permissions may be granted and revoked on parties and auditing information is stored in the acs objects table.

 
-create table parties (
+
+create table parties (
     party_id    not null
             constraint parties_party_id_fk references
             acs_objects (object_id)
@@ -33,17 +35,21 @@
 );
 
 
-

There are two tables that extend the parties table. One is the persons -table and one is the groups table. A row in the persons table represents the -most basic form of individual that is modeled by the parties data model. A -row in the groups table represents the most basic form of an aggregation of -individuals that is represented.

Persons

If a party is an individual then there will be a row in the persons table -containing first_names and last_name for that individual. Note that the -primary key of the persons table (person_id) references the primary key of -the parties table (party_id). This guarantees that if there is a row in the -persons table then there must be a corresponding row in the parties table. -Also note that an individual need not be known to the system as a user. A -user is in fact a further specialized form of an individual.

+

The persons and +groups tables extend the +parties table. A row in the persons table represents the +most generic form of individual modeled. An individual need not be known to the system as a user. A +user is a further specialized form of an individual (discussed later). A +row in the groups table represents the most generic form of group +modeled, where a group is an aggregation of zero or more +individuals.

Persons

If a party is an individual then there will be a row in the persons table +containing first_names and +last_name + for that individual. The +primary key of the persons table (person_id) references the primary key of +the parties table (party_id), so that there is a corresponding row in the +parties table when there is a row in the persons table. +

 
 create table persons (
     person_id   not null
@@ -55,21 +61,24 @@
 );
 
 
-

Users

The users table is an even more specialized form of an individual. A row -in the users table represents an individual that has login access to the -system. Note that the primary key of the users table references the primary -key of the persons table. Once again this guarantees that if there is a row -in the users table then there must be a row in the persons table and a row in -the parties table.

One of the interesting benefits of decomposing all the information +

Users

The users table is a more +specialized form of persons table. A row +in users table represents an individual that has login access to the +system. The primary key of the users table references the primary +key of the persons table. This guarantees that if there is a row +in users table then there must be a +corresponding row in persons +and parties tables.

Decomposing all the information associated with a user into the four tables (acs_objects, parties, persons, -users) is that it is now possible to "nuke" a user from a live -system by removing his entry from the users table, but leaving the rest of -his information present (i.e. turning him from a user into a person). This is -because wherever possible the OpenACS data model references the persons or -parties table, not the users table. If this feature is -desired when extending the system, then the developers should be careful to -only references the users table in situations where it is clear that the -references is to a user and not to an individual.

+users) has some immediate benefits.  For instance, it is possible to remove access to a user from a live
+system by removing his entry from the users table, while leaving the rest of
+his information present (i.e. turning him from a user into a
+person).

Wherever possible the OpenACS data model references the persons or +parties table, not the users table. +Developers should be careful to +only reference the users table in situations where it is clear that the +reference is to a user for all cases and not to any other individual +for any case.

 
 create table users (
     user_id         not null
@@ -99,11 +108,10 @@
 
 
 

Groups

The final piece of the parties data model is the groups data model. A -group is a specialization of a party that represents an aggregation of other +group is a specialization of a party that represents an aggregation of +zero or more other parties. The only extra information directly associated with a group (beyond -that in the parties table) is the name of the group. As you might guess there -is another piece to the groups data model that records relations between -parties and groups.

+that in the parties table) is the name of the group:

 
 create table groups (
     group_id    not null
@@ -114,32 +122,52 @@
 );
 
 
-

Group Relations

One surprise here is that there are actually two relations involved. One -is the normal membership relation between parties and groups. A party may be -a "member" of a group. The other relation is a composition -relation between two groups. To fully understand why two relations are -necessary, and the situations in which each is appropriate, let's -consider an example. Greenpeace is an organization that can have as members -both individuals and organizations. Hence the membership relation between -groups and parties. But just because you are a member of an -organization that is a member of Greenpeace, that doesn't make you a -member of Greenpeace, i.e., membership is not transitive with respect to -itself. Now let's consider a multinational corporation. This corporation -might have a U.S. division and a European division. A member of either the -U.S. or European division is automatically a member of the company. In this -situation the U.S. and European divisions are "components" of -the company, i.e., membership is transitive with respect to -composition. Having a membership relation between groups and parties, and -having a composition relation between groups and groups allows us to easily -model the full range of sophisticated group structures that exist in the real -world.

Group Membership

Group memberships can be created and manipulated using the membership_rel -package. Note that you can only create one membership object for a given -group, party pair. Because of composition, it is possible in some +

+There is another piece to the groups data model that records relations between +parties and groups. +

Group Relations

Two types of group relations are represented in the data model: +membership relations and composite relations. +The full range of sophisticated group structures that exist in the real +world can be modelled in OpenACS by these two relationship types.

Membership relations represent direct membership relation between parties and groups. A party may be +a "member" of a group. Direct membership relations are +common in administrative practices, and do not follow basic set +theory rules. If A is a member of B, and B is a member of C, A is +not a member of C. Membership relations are not transitive. +

Composition relation represents composite relation +between two groups. Composite relation is +transitive. That is, it works like +memberships in set theory. If A is a member of B, and B is a member of +C, then A is a member of C. +

+For example, consider the membership relations of Greenpeace, and +composite relations of a multinational corporation. Greenpeace, an +organization (ie. group), can have both individuals and organizations +(other groups) as members. Hence the membership relation between +groups and parties. However, someone is not +a member of Greenpeace just because they are a member of a +group that is a member of Greenpeace. Now, consider a multinational +corporation (MC) that has a U.S. division and a Eurasian division. A member of either the +U.S. or Eurasian division is automatically a member of the MC. In this +situation the U.S. and Eurasian divisions are "components" of +the MC, i.e., membership is transitive with respect to +composition. Furthermore, a member of a European (or other) office of the MC +is automatically a member of the MC. +

Group Membership

Group memberships can be created and manipulated using the membership_rel +package. Only one membership object can be created for a given +group, party pair. +

+It is possible in some circumstances to make someone a member of a group of which they are already a -member. This is because there is a distinction between direct membership and -indirect membership (membership via some component or sub component).

+member. That is because the model distinguishes between direct membership and
+indirect membership (membership via some composite relationship).
+For example, a person might be listed in a system as both an
+individual (direct membership) and a
+member of a household (indirect membership) at a video rental store.
+

 
-create or replace package membership_rel
+
+# sql code
+create or replace package membership_rel
 as
 
   function new (
@@ -183,13 +211,15 @@
 
 

Group Composition

Composition relations can be created or destroyed using the composition_rel package. The only restriction on compositions is that there -cannot be a cycle, i.e., a group cannot be a component of itself either -directly or indirectly. This constraint is maintained for you by the API, but -if you don't want users seeing some random PL/SQL error message, it is a -good idea to not give them the option to create a composition relation that -would result in a cycle.

+cannot be a reference loop, i.e., a group cannot be a component of itself either
+directly or indirectly. This constraint is maintained for you by the API. 
+So users do not see some random PL/SQL error message, 
+do not give them the option to create a composition relation that
+would result in a circular reference.

 
-create or replace package composition_rel
+
+# sql code
+create or replace package composition_rel
 as
 
   function new (
@@ -210,61 +240,64 @@
 show errors
 
 
-

Views

The data model described above does a reasonable job of representing many +

Views

The parties data model does a reasonable job of representing many of the situations one is likely to encounter when modeling organizational -structures, but we still need to be able to efficiently answer questions like +structures. We still need to be able to efficiently answer questions like "what members are in this group and all of its components?", and "of what groups is this party a member either directly or indirectly?". Composition relations allow you to describe an arbitrary Directed Acyclic Graph (DAG) between a group and its components. For these reasons the party system provides a bunch of views that take advantage of the internal representation of group relations to answer questions like these -very quickly.

This view returns all the subcomponents of a group including components of -sub components and so forth. The container_id column is the group_id of the -group in which component_id is directly contained. This allows you to easily +very quickly.

The group_component_map + view returns all the subcomponents of a group including components of +sub components and so forth. The container_id column is the group_id of the +group in which component_id is directly contained. This allows you to easily distinguish whether a component is a direct component or an indirect -component. (If a component is a direct component then group_id will be equal -to container_id.) You can think of this view as having a primary key of -group_id, component_id, and container_id. The rel_id column points to the row -in acs_rels that contains the relation object that relates component_id to -container_id. The rel_id might be useful for retrieving or updating standard +component. If a component is a direct component then group_id will be equal +to container_id. You can think of this view as having a primary key of +group_id, component_id, and container_id. The rel_id column points to the row +in acs_rels table that contains the relation object that relates component_id to +container_id. The rel_id might be useful for retrieving or updating standard auditing info for the relation.

 
 create or replace view group_component_map
 as select group_id, component_id, container_id, rel_id
 ...
 
 
-

This is similar to group_component_map except for membership relations. -Note that this view will return all membership relations regardless of -membership state.

+

The group_member_map view is similar to group_component_map except for membership relations. +This view returns all membership relations regardless of membership state.

 
 create or replace view group_member_map
 as select group_id, member_id, container_id, rel_id
 ...
 
 
-

The group_approved_member_map is the same as the group_member_map except +

The group_approved_member_map +view is the same as group_member_map except it only returns entries that relate to approved members.

 
 create or replace view group_approved_member_map
 as select group_id, member_id, container_id, rel_id
 ...
 
 
-

This view is useful if you don't care about the distinction between -direct membership and indirect membership. It simply returns all members of a -group including members of components. (It is the transitive closure.)

+

The group_distinct_member_map +view is a +useful view if you do not care about the distinction between +direct membership and indirect membership. It returns all members of a +group including members of components --the transitive closure.

 
 create or replace view group_distinct_member_map
 as select group_id, member_id
 ...
 
 
-

This view is the same as group_distinct_member_map, except it includes the -identity mapping. In other words it maps from a party to the fully expanded +

The party_member_map view is the same as group_distinct_member_map, except it includes the +identity mapping. It maps from a party to the fully expanded list of parties represented by that party including the party itself. So if a -party is an individual this view will have exactly one mapping that is from +party is an individual, this view will have exactly one mapping that is from that party to itself. If a view is a group containing three individuals, this view will have four rows for that party, one for each member, and one from the party to itself.

@@ -274,35 +307,35 @@
 ...
 
 
-

This view is the same as above except that when it expands groups, it only +

The party_approved_member_map view is the same as party_member_map except that when it expands groups, it only pays attention to approved members.

 
 create or replace view party_approved_member_map
 as select party_id, member_id
 ...
 
 
-

Extending The Parties Data Model

As is, the parties data model can represent some fairly sophisticated real -world situations, and a lot of work has been put into making this efficient, -but it is foolish to assume that this data model is sufficient for every -application. It therefore seems likely that developers will want to extend -the parties data model in a number of ways. This section will describe some -of the more common ways.

Specializing Users

It is conceivable that some applications will want to collect more -detailed information for people using the system. If it is the case that +

Extending The Parties Data Model

The parties data model can represent some fairly sophisticated real +world situations. Still, it would be foolish to assume that this data +model is sufficiently efficient for every +application. This section describes some +of the more common ways to extend the parties data model.

Specializing Users

Some applications will want to collect more +detailed information for people using the system. If there can be only one such piece of information per user, then it might make sense to create another type of individual that is a further specialization -of a user. For example a MENSA community web site might want to record IQs +of a user. For example a Chess Club community web site might want to record +the most recent score for each user. In a situation like this it would be appropriate to create a -subtype of users, say mensa_users. This child table of the users table would +subtype of users, say chess_club_users. This child table of the users table would have a primary key that references the users table, thereby guaranteeing that -each row in the mensa_users table has a corresponding row in each of the +each row in the chess_club_users table has a corresponding row in each of the users, persons, parties, and acs_objects tables. This child table could then -store any extra information relevant to the MENSA community.

Specializing Groups

If one were to build an intranet application on top of the party +store any extra information relevant to the Chess Club community.

Specializing Groups

If one were to build an intranet application on top of the party system, it is likely that one would want to take advantage of the systems efficient representation of sophisticated organizational structures, but there would be much more specialized information associated with each group. In this case it would make sense to specialize the group party type into a -company party type in the same manner as above.

Specializing Membership Relations

The final portion of the parties data model that is designed to be +company party type in the same manner as Specializing Users.

Specializing Membership Relations

The final portion of the parties data model that is designed to be extended is the membership relationship. Consider the intranet example again. It is likely that a membership in a company would have more information associated with it than a membership in an ordinary group. An obvious example 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.38 -r1.39 --- openacs-4/packages/acs-core-docs/www/permissions-tediously-explained.html 17 Jul 2006 05:38:31 -0000 1.38 +++ openacs-4/packages/acs-core-docs/www/permissions-tediously-explained.html 5 Aug 2006 05:18:20 -0000 1.39 @@ -1,19 +1,23 @@ 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 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 +

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

Permissions Overview

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

+ The general permissions system has a flexible (and relatively complex) data model in OpenACS. + Developers who have not had the time to learn the internals of the data model may end up writing seemingly correct code that crashes their system in weird ways. This writeup is the result of my running into such a piece of code and trying to understand exactly what went wrong. It is geared towards developers who understand the general permissions system to the extent that is described in the - OpenACS Permissions documentation, - but who haven't had the opportunity to take a long, careful look at the + Groups, Context, Permissions documentation, + but who have not had the opportunity to take a long, careful look at the system internals.

- In OpenACS 4.x, most of the interesting tables are expected to extend (subtype) + In OpenACS, 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. @@ -41,8 +45,8 @@ unique (context_id, object_id) disable );

- This means that any interesting entity (object) - in the system has an entry in the acs_objects. This + This means that items that want to use the features of the + OpenACS object system needs to have 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 @@ -81,7 +85,7 @@ 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 + The micromanaging approach to 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 who have the read privilege on all objects, then we would need to store 100,000,000 entries of the form: @@ -92,15 +96,15 @@ X has the read privilege on object A, she typically also has the read privilege on all objects attached under A.

- The general permission system, as implemented in OpenACS 4.x, takes advantage + The general permission system takes advantage of the hierarchical organization of objects to unburden developers of the 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

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

Table�11.2.�Context Hierarchy Example

+

Table�11.2.�Context Hierarchy Example

A

object_id=10 @@ -134,7 +138,7 @@ 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, @@ -158,7 +162,7 @@

1 + 2*2 + 3*4 + 4*8 + 5*16 + ... + (n+1)*2n = n*2n+1 + 1

Despite its potentially great storage costs, maintaining a - flattened representation of the context tree is exactly what OpenACS 4.x + flattened representation of the context tree is exactly what OpenACS does. The flattened context tree is stored in the acs_object_context_index table.

@@ -272,7 +276,11 @@
       admin privilege to which the first four
       privileges are tied. Privileges are structured as follows.
     

admin
createdeletereadwrite

- The parent-child relationship between privileges is represented in + Note that admin privileges are + greater than read, write, create and delete privileges combined. + Issuing someone read, write, create and delete privileges will + not result in the person getting + admin privileges.

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

   create table acs_privilege_hierarchy (
@@ -433,7 +441,11 @@
 	      Pranksters
 	    
Penelope -

+

Read acs_rels: right-side is a + subset of left-side, ie + object2 is a part of + object1. +

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 @@ -484,7 +496,7 @@ hierarchical queries, which are expensive in Oracle. As we saw in the Context Hierarchy section, one way of 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: + a table maintained by triggers. The OpenACS data model defines two such tables:

  create table group_component_index (
           group_id        not null
@@ -525,7 +537,7 @@
       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. 
-    

+

additional comments

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 @@ -587,7 +599,7 @@ table, unless doing so results in substantial performance gains.

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 + function in OpenACS. This is accessible from Tcl via the permission::permission_p procedure.

  
   create or replace package body acs_permission
@@ -612,17 +624,17 @@
     end;
 
   end acs_permission;
-    

- The function simply queries +

problem avoidance

+ The function queries acs_object_party_privilege_map, which is a humongous view that joins three flattened hierarchies: the context tree, the privilege hierarchy, - the party composition (and membership) hierarchy. As such, - it contains an extremely large number of rows. About + the party composition (and membership) hierarchy. + 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 function. Anything other than that would take forever to - finish or would ultimately result in an Oracle error. + finish or would ultimately result in a query error.

For example, do not try to do things like

Index: openacs-4/packages/acs-core-docs/www/permissions.html
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/permissions.html,v
diff -u -r1.42 -r1.43
--- openacs-4/packages/acs-core-docs/www/permissions.html	17 Jul 2006 05:38:31 -0000	1.42
+++ openacs-4/packages/acs-core-docs/www/permissions.html	5 Aug 2006 05:18:20 -0000	1.43
@@ -5,51 +5,23 @@
 The OpenACS 5.2.3rc1 Permissions system allows developers and administrators to
 set access control policies at the object level, that is, any
 application or system object represented by a row in the
-acs_objects table can be access-controlled via a simple
+acs_objects table can be access-controlled via a
 PL/SQL or Tcl interface. The permissions system manages a data model
-that then allows scripts to check permissions using another simple
-API call.
+that then allows scripts to check permissions using another API call.
 

-Although this may all sound easy and wonderful, no developer or -administrator would want to explicitly set access control +Although object level permissions seems appropriate, no developer or +administrator wants to explicitly set access control rights for every user and every object on a -site. Therefore, OpenACS 5.2.3rc1 has two auxiliary mechanisms for making this -easier: First, the Groups system allows users to be grouped together -in flexible ways. Second, the object model defines a notion of +site. Therefore, OpenACS has two auxiliary mechanisms for making this +easier:

  1. the Groups system allows users to be grouped together +in flexible ways.

  2. the object model defines a notion of object context, which allows applications to group objects -together into larger security domains. The rest of this document will -talk about each of these parts, and how they fit together with the +together into larger security domains. +

The rest of this document discusses each of these parts, and how they fit together with the permissions system.

Groups

-In OpenACS 3.x, the groups system allowed developers and administrators to -define simple groupings of users. Each group had a human readable name -and unique ID, and there was a single mapping table that mapped users -to groups. (The actual data model was more complicated because it -contained a meta-data system much like the OpenACS 5.2.3rc1 object type system, -but that's not relevant right now.) -

-The 3.x groups system, while very useful, was limited in few ways. The -main limitation: groups could not either contain or include other -groups. You could not express the fact that all the members of group A -should also be in group B - for example, to model a company with -multiple offices. The company should have a main group representing -all employees, and each office should have a group representing its -employees. Obviously, you'd want every member of an office employee -group to automatically be a member of the whole company employee -group. -

-In OpenACS 3.x, you also could not express the fact that group A should -itself be a member of group B, without also implying that all of its -members are also members of B. This type of relationship also comes up -in the real world, though not as often. A good example is an -organization like Greenpeace that can have as members both individuals -and organizations: although the Sierra Club may be an organization -member of Greenpeace, its members are not necessarily members of -Greenpeace. -

-OpenACS 5.2.3rc1 solves both of these modeling problems by introducing a new -abstraction called a party. Parties have a recursive -definition, and we can illustrate how it works with the following +OpenACS 5.2.3rc1 has an abstraction called a party. Parties have a recursive +definition. We can illustrate how it works with the following simplified data model. First, we define the parties table, where each party has an email address and a URL for contact information. @@ -79,55 +51,49 @@

The users table is also defined in this data model as a -subtype of person. It contains many of the basic columns -that the old OpenACS 3.x users table contained. +subtype of person.

Finally, we define two relations, one for group membership and -one for group composition. The composition relation allows us -to express the fact that every member of group A should also be a +one for group composition. +

The composition relation expresses that every member of group A should also be a member of group B. This relation allows us to define a hierarchy of -groups instead of the simple flat groups that 3.x allowed. +groups.

-The membership relation is much like the mapping we had in 3.x, except -that it maps groups to parties instead of groups to users. What -this means is that each member of a group is a party rather than just +The membership relation maps groups to parties. Each member of a group is a party rather than just a user. That is, groups consist of members that are either a person or an entire group. This allows us to say that group A should be a member of another group B.

-The groups data model is pleasantly recursive. The fact that parties -are modeled as being either a person or a group has a lot of power, -allowing us to model complex hierarchical groupings of persons and -groups that were hard or impossible to model in 3.x. +The groups data model is recursive. Modelling parties as either a +person or a group provides a way to model complex hierarchical groupings of persons and +groups.

The full details of the groups data model is beyond the scope of this -tutorial - I've just given you what you need to understand how -permissions work. For further detail, you can look at Parties in OpenACS 4 or OpenACS 4 Groups Design. +tutorial. See Parties in OpenACS or OpenACS 4 Groups Design for more details.

Permissions

NOTE: Much more detailed information about the permissions system and how to use it is available in the OpenACS Permissions Tediously Explained document.

-The permissions data model is actually pretty simple. The data model -is a mapping between privileges, parties and objects. We -already know what parties and objects are, but we don't know what -privileges are. +The permissions data model is a mapping between +privileges, parties and objects. Parties and +objects have already been discussed. Now we focus on privileges.

-In OpenACS 5.2.3rc1, a privilege models the right to perform some operation on -some object. They are the basic units out of which we build access -control policies. For example, in the Unix filesystem we typically -implement access control by granting users some combination of -read. write or execute privileges on files and directories. In OpenACS 5.2.3rc1, +In OpenACS, a privilege describes the right to perform some operation on +some object. Privileges are the basic units out of which we build access +control policies. For example in the Unix filesystem, access is controlled by granting users some combination of +read, write, or execute privileges on files and directories. In +OpenACS 5.2.3rc1, the table of privileges is organized hierarchically so that developers can define privileges that aggregate some set of privileges together. For example, if we have read, write, create and delete privileges, it might be convenient to combine them into a new privilege -called "admin". Then if we grant a user this privilege she is +called "admin". Then, when a user is granted "admin" privilege, she is automatically granted all the child privileges that the privilege -contains. The OpenACS 5.2.3rc1 kernel data model actually defines these -privileges as follows: +contains. The OpenACS 5.2.3rc1 kernel data model defines these +privileges:

-
+# 
 begin
  acs_privilege.create_privilege('read');
  acs_privilege.create_privilege('write');
@@ -144,12 +110,16 @@
 end;
 
 

+Note that a user does not gain admin privileges when granted +read, write, create and delete privileges, because some operations +explicitly require admin privileges. No substitutions. +

To give a user permission to perform a particular operation on a particular object you call acs_permission.grant_permission like this:

-
+# sql code
     acs_permission.grant_permission (
       object_id => some_object_id,
       grantee_id => some_party_id,
@@ -159,45 +129,47 @@
 

Using just these mechanisms is enough for developers and administrators to effectively define access control for every object -in a system. But it would be tedious to explicitly attach permissions -to every object individually: in many cases, we'd prefer controlling -permissions to large groups of objects in the site, all at once. We -use contexts to achieve this goal. +in a system. +

Explicitly defining permissions to every object individually +would become very tedious. +OpenACS provides a object contexts as a means for controlling permissions of a large group +of objects at the same time.

Object Context

-In OpenACS 5.2.3rc1, an object context is a generalization of the scoping -mechanism introduced in OpenACS 3.x. "Scoping" and "scope" are terms best +In OpenACS 5.2.3rc1, object context is a scoping +mechanism. "Scoping" and "scope" are terms best explained by example: consider some hypothetical rows in the address_book table:

...scopeuser_idgroup_id...
...user123 ...
...group 456...
...public ...

The first row represents an entry in User 123's personal address book, the second row represents an entry in User Group 456's shared address book, and the third row represents an entry in the site's public -address book. -

-In this way, the scoping columns identify the security context in +address book. In this way, the scoping columns identify the security context in which a given object belongs, where each context is either a person or a group of people or the general public (itself a group of people).

-In OpenACS 5.2.3rc1, rather than breaking the world into a limited set of scopes, -every object lives in a single context. A context is just an +Every object lives in a single context. A context is just an another object that represents the security domain to which the object -belongs. By convention, if an object A doesn't have any permissions +belongs. By convention, if an object A does not have any permissions explicitly attached to it, then the system will look at the context_id column in acs_objects and check the context object there for permissions. Two things control the scope -of this search: the structure of the context hierarchy itself, and the -value of the security_inherit_p flag in each object. If -this flag is set to 't', then the automatic search +of this search:

  1. the structure of the context hierarchy +itself, and +

  2. +the value of the security_inherit_p +flag in each object. +

If +security_inherit_p flag is set to 't', then the automatic search through the context happens, otherwise it does not. You might set this field to 'f' if you want to override the default permissions in a subtree of some context. -

A good example of how to use this hierarchy is in the forums +

For an example of how to use context hierarchy, consider the forums application. With only row-level permissions it is not obvious how to reasonably initialize the access control list when creating a message. At best, we have to explicitly grant various read and write -privileges whenever we create a message, which is tedious. In OpenACS 5.2.3rc1, -a reasonable thing to do is to create an object representing a forum, +privileges whenever we create a message, which is tedious. +A reasonable thing to do is to create an object representing a forum, and point the context_id field of a new message at the forum. Then, suppose we grant every user in the system read-access to this forum. By default, they will automatically have read-access to @@ -211,8 +183,8 @@ their application. The following picture shows a typical context hierarchy for a hypothetical site:

-A few things to note here. First, the top two contexts in the picture -are "magic" in some sense because they are created by default by OpenACS +The top two contexts in the diagram +are called "magic" numbers, because in some sense, they are created by default by OpenACS for a specific purpose. The object default_context represents the root of the context hierarchy for the entire site. All permission searches walk up the tree to this point and then stop. If @@ -222,135 +194,20 @@ security_context_root has a slightly different role. If some object has no permissions attached to it, and its value for security_inherit_p is 'f', or -context_id is null, then we use this context by default. -

Example

-At this point, you should either go and download the Notes example -code from the package repository, or check it out of the OpenACS CVS -repository and add it to your server. The package is called -"notes". To check it out from CVS, read the these instructions -on how to use anonymous checkouts and then -checkout the module notes: -

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

% export CVSROOT=:pserver:anonymous@cvs.openacs.org:/cvsroot
-% cvs login # just hit enter when prompted for a password
-% cvs co notes
-

-After you have downloaded the package, look at the -index.tcl page in the www directory. You can also -look at the code in your browser. The code should look something like this: -

-
-# main index page for notes.
-
-ad_page_contract {
-   @author you
-   @cvs-id $Id$
-} -properties {
-  notes:multirow
-  context_bar:onevalue
-  create_p:onevalue
-}
-
-set package_id [ad_conn package_id]
-set user_id [ad_conn user_id]
-
-set context_bar [ad_context_bar]
-set create_p [permission::permission_p \
-      -object_id $package_id \
-      -privilege create \
-      -party_id  $user_id]
-
-db_multirow notes notes {
-  select note_id, owner_id, title, body,
-         decode(acs_permission.permission_p(note_id,
-                                            :user_id,
-                                            'write'),
-                't', 1,
-                'f', 0) as write_p,
-         decode(acs_permission.permission_p(note_id,
-                                            :user_id,
-                                            'admin'),
-                't', 1,
-                'f', 0) as admin_p,
-         decode(acs_permission.permission_p(note_id,
-                                            :user_id,
-                                            'delete'),
-                't', 1,
-                'f', 0) as delete_p
-  from notes n, acs_objects o
-  where n.note_id = o.object_id
-  and o.context_id = :package_id
-  and acs_permission.permission_p(note_id, :user_id, 'read') = 't'
-  order by creation_date
-}
-
-ad_return_template
-
-

-This example shows both the Tcl and PL/SQL APIs for checking -permissions. The Tcl proc permission::permission_p and the PL/SQL -function acs_permission.permission_p both return a flag -indicating whether the current user has permission to perform the -given action. By default, the Tcl procedure extracts the user_id out -of the request environment, while the SQL procedure takes it as an -argument. -

-It also shows how we display more complicated items using the template -system. The code here creates a multirow data source, i.e. a -data source that represents a query returning multiple rows from the -database. For each row, we return the ID of the note, the ID of the -owner of the note, the title, the body and then three flags that -indicate whether the user has write, admin, and delete -privileges. Also, the WHERE clause of the query ensures that we only -see notes that we are allowed to see. -

-Next, look at the index.adp. It is pretty complicated. -The main part of this page uses a multiple template -tag. If you want to experiment, you can replace the main body of the -multiple tag with this: -

-
-<multiple name=notes>
-<td>@notes.title@</td><td>@notes.body</td>
-</multiple>
-
-

-This will just make a table with one note per row. -

-Now put the more complex code back. You'll notice a lot of stuff like this: -

-
-<if @notes.write_p@ eq 1>
-  <a href=add-edit?note_id=@notes.note_id@>@notes.title@</a>
-</if>
-<else>
-  @notes.title@
-</else>
-
-

-This displays the title of the note as either a link or plain text -depending on whether or not we have write privileges on the object. -The if tag is something that the OpenACS 5.2.3rc1 template system -defines for you to support conditional presentation. The templates developer guide provides more information about this. -

-If you study the rest of the system, you will also notice that the -notes application doesn't explicitly attach privileges to the objects -it creates. All privileges are inherited from the context of the object -which in this case is the package instance. The assumption is that the -administrator of the site would create one instance of notes for every -user that wants it, and set the permissions on this instance -appropriately. In a more advanced version of the application, we could -implement a user interface that allowed the user to explicitly attach -permissions to notes that she wanted to make public or whatever. But -that's beyond the scope of this example. +context_id is null, this context is used by default. +

See the package developer tutorials for examples on how to use +permissions code.

Summary

OpenACS 5.2.3rc1 defines three separate mechanisms for specifying access control -in applications. The Groups data model allows you to define -hierarchical organizations of users and groups of users. The Permissions -data model allows you to define a hierarchy of user rights. Finally, -the Context hierarchy allows you to define organize default -permissions in a hierarchical fashion. A simple PL/SQL or Tcl API is -then used to do access control checks in application pages. -

-In the next section, we'll look at a more complex page for adding and -editing notes, and discuss these issues further. +in applications.

  1. +The Groups data model allows you to define +hierarchical organizations of users and groups of users. +

  2. +The Permissions +data model allows you to define a hierarchy of user rights. +

  3. +The Context hierarchy allows you to define organize default +permissions in a hierarchical fashion. +

A PL/SQL or Tcl API is +then used to check permissions in application pages.

($Id$)
View comments on this page at openacs.org
Index: openacs-4/packages/acs-core-docs/www/xml/developers-guide/parties.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/xml/developers-guide/parties.xml,v diff -u -r1.7 -r1.8 --- openacs-4/packages/acs-core-docs/www/xml/developers-guide/parties.xml 17 Jul 2006 05:38:37 -0000 1.7 +++ openacs-4/packages/acs-core-docs/www/xml/developers-guide/parties.xml 5 Aug 2006 05:18:21 -0000 1.8 @@ -4,7 +4,7 @@ %myvars; ]> - + Parties in OpenACS @@ -18,46 +18,47 @@ While many applications must deal with individuals and many applications must deal with groups, most applications must deal with individuals -or groups. It is often the case with such applications that in many -respects both individuals and groups are treated in an identical manner. It -is this latter class of application that makes it extremely useful to model -individuals and groups as specializations of one supertype. This concept is -so commonly used throughout human language and thought that we don't even -need to invent for it some bizarre and specialized terminology. This +or groups. It is often the case with such +applications that + both individuals and groups are treated identically. Modelling +individuals and groups as specializations of one supertype is a +practical way to manage both. This concept is +so mundane that there is +no need to invent special terminology. This supertype is called a "party". -A classic example use of the "party" supertype is evident -in a common address book. A typical person's address book might contain -the address of his doctor, and his cable company. So what do we label the -first field in an entry in his address book? It isn't a person, and it -isn't a company. It is a "party". +A classic example of the "party" supertype is evident +in address books. A typical address book might contain +the address of a doctor, grocery store, and friend. The +first field in an entry in the address book is not labeled a person or +company, but a "party". + - The Data Model -Most developers who do significant work with the OpenACS will become -intimately familiar with the parties data model, and probably extend it on -many occasions. For this reason the parties developer guide will begin with -an introduction to the data model. +The parties developer guide begins with +an introduction to the parties data model, since OpenACS +community applications likely require using it in some way. Parties The central table in the parties data model is the parties table itself. Every party has exactly one row in this table. Every party has an optional unique email address and an optional url. A party is an acs object, so -permissions may granted and revoked on parties and auditing information is +permissions may be granted and revoked on parties and auditing information is stored in the acs objects table. -create table parties ( + +create table parties ( party_id not null constraint parties_party_id_fk references acs_objects (object_id) @@ -71,21 +72,25 @@ -There are two tables that extend the parties table. One is the persons -table and one is the groups table. A row in the persons table represents the -most basic form of individual that is modeled by the parties data model. A -row in the groups table represents the most basic form of an aggregation of -individuals that is represented. +The persons and +groups tables extend the +parties table. A row in the persons table represents the +most generic form of individual modeled. An individual need not be known to the system as a user. A +user is a further specialized form of an individual (discussed later). A +row in the groups table represents the most generic form of group +modeled, where a group is an aggregation of zero or more +individuals. Persons If a party is an individual then there will be a row in the persons table -containing first_names and last_name for that individual. Note that the -primary key of the persons table (person_id) references the primary key of -the parties table (party_id). This guarantees that if there is a row in the -persons table then there must be a corresponding row in the parties table. -Also note that an individual need not be known to the system as a user. A -user is in fact a further specialized form of an individual. +containing first_names and +last_name + for that individual. The +primary key of the persons table (person_id) references the primary key of +the parties table (party_id), so that there is a corresponding row in the +parties table when there is a row in the persons table. + @@ -106,25 +111,28 @@ Users -The users table is an even more specialized form of an individual. A row -in the users table represents an individual that has login access to the -system. Note that the primary key of the users table references the primary -key of the persons table. Once again this guarantees that if there is a row -in the users table then there must be a row in the persons table and a row in -the parties table. +The users table is a more +specialized form of persons table. A row +in users table represents an individual that has login access to the +system. The primary key of the users table references the primary +key of the persons table. This guarantees that if there is a row +in users table then there must be a +corresponding row in persons +and parties tables. -One of the interesting benefits of decomposing all the information +Decomposing all the information associated with a user into the four tables (acs_objects, parties, persons, -users) is that it is now possible to "nuke" a user from a live -system by removing his entry from the users table, but leaving the rest of -his information present (i.e. turning him from a user into a person). This is -because wherever possible the OpenACS data model references the persons or -parties table, not the users table. If this feature is -desired when extending the system, then the developers should be careful to -only references the users table in situations where it is clear that the -references is to a user and not to an individual. +users) has some immediate benefits. For instance, it is possible to remove access to a user from a live +system by removing his entry from the users table, while leaving the rest of +his information present (i.e. turning him from a user into a +person). +Wherever possible the OpenACS data model references the persons or +parties table, not the users table. +Developers should be careful to +only reference the users table in situations where it is clear that the +reference is to a user for all cases and not to any other individual +for any case. - @@ -161,11 +169,10 @@ Groups The final piece of the parties data model is the groups data model. A -group is a specialization of a party that represents an aggregation of other +group is a specialization of a party that represents an aggregation of +zero or more other parties. The only extra information directly associated with a group (beyond -that in the parties table) is the name of the group. As you might guess there -is another piece to the groups data model that records relations between -parties and groups. +that in the parties table) is the name of the group: @@ -181,44 +188,64 @@ + +There is another piece to the groups data model that records relations between +parties and groups. + - Group Relations -One surprise here is that there are actually two relations involved. One -is the normal membership relation between parties and groups. A party may be -a "member" of a group. The other relation is a composition -relation between two groups. To fully understand why two relations are -necessary, and the situations in which each is appropriate, let's -consider an example. Greenpeace is an organization that can have as members -both individuals and organizations. Hence the membership relation between -groups and parties. But just because you are a member of an -organization that is a member of Greenpeace, that doesn't make you a -member of Greenpeace, i.e., membership is not transitive with respect to -itself. Now let's consider a multinational corporation. This corporation -might have a U.S. division and a European division. A member of either the -U.S. or European division is automatically a member of the company. In this -situation the U.S. and European divisions are "components" of -the company, i.e., membership is transitive with respect to -composition. Having a membership relation between groups and parties, and -having a composition relation between groups and groups allows us to easily -model the full range of sophisticated group structures that exist in the real -world. +Two types of group relations are represented in the data model: +membership relations and composite relations. +The full range of sophisticated group structures that exist in the real +world can be modelled in OpenACS by these two relationship types. +Membership relations represent direct membership relation between parties and groups. A party may be +a "member" of a group. Direct membership relations are +common in administrative practices, and do not follow basic set +theory rules. If A is a member of B, and B is a member of C, A is +not a member of C. Membership relations are not transitive. +Composition relation represents composite relation +between two groups. Composite relation is +transitive. That is, it works like +memberships in set theory. If A is a member of B, and B is a member of +C, then A is a member of C. + +For example, consider the membership relations of Greenpeace, and +composite relations of a multinational corporation. Greenpeace, an +organization (ie. group), can have both individuals and organizations +(other groups) as members. Hence the membership relation between +groups and parties. However, someone is not +a member of Greenpeace just because they are a member of a +group that is a member of Greenpeace. Now, consider a multinational +corporation (MC) that has a U.S. division and a Eurasian division. A member of either the +U.S. or Eurasian division is automatically a member of the MC. In this +situation the U.S. and Eurasian divisions are "components" of +the MC, i.e., membership is transitive with respect to +composition. Furthermore, a member of a European (or other) office of the MC +is automatically a member of the MC. + Group Membership Group memberships can be created and manipulated using the membership_rel -package. Note that you can only create one membership object for a given -group, party pair. Because of composition, it is possible in some +package. Only one membership object can be created for a given +group, party pair. + +It is possible in some circumstances to make someone a member of a group of which they are already a -member. This is because there is a distinction between direct membership and -indirect membership (membership via some component or sub component). - +member. That is because the model distinguishes between direct membership and +indirect membership (membership via some composite relationship). +For example, a person might be listed in a system as both an +individual (direct membership) and a +member of a household (indirect membership) at a video rental store. + -create or replace package membership_rel + +# sql code +create or replace package membership_rel as function new ( @@ -267,17 +294,17 @@ Composition relations can be created or destroyed using the composition_rel package. The only restriction on compositions is that there -cannot be a cycle, i.e., a group cannot be a component of itself either -directly or indirectly. This constraint is maintained for you by the API, but -if you don't want users seeing some random PL/SQL error message, it is a -good idea to not give them the option to create a composition relation that -would result in a cycle. +cannot be a reference loop, i.e., a group cannot be a component of itself either +directly or indirectly. This constraint is maintained for you by the API. +So users do not see some random PL/SQL error message, +do not give them the option to create a composition relation that +would result in a circular reference. - - -create or replace package composition_rel + +# sql code +create or replace package composition_rel as function new ( @@ -309,9 +336,9 @@ -The data model described above does a reasonable job of representing many +The parties data model does a reasonable job of representing many of the situations one is likely to encounter when modeling organizational -structures, but we still need to be able to efficiently answer questions like +structures. We still need to be able to efficiently answer questions like "what members are in this group and all of its components?", and "of what groups is this party a member either directly or indirectly?". Composition relations allow you to describe an arbitrary @@ -320,15 +347,16 @@ internal representation of group relations to answer questions like these very quickly. -This view returns all the subcomponents of a group including components of -sub components and so forth. The container_id column is the group_id of the -group in which component_id is directly contained. This allows you to easily +The group_component_map + view returns all the subcomponents of a group including components of +sub components and so forth. The container_id column is the group_id of the +group in which component_id is directly contained. This allows you to easily distinguish whether a component is a direct component or an indirect -component. (If a component is a direct component then group_id will be equal -to container_id.) You can think of this view as having a primary key of -group_id, component_id, and container_id. The rel_id column points to the row -in acs_rels that contains the relation object that relates component_id to -container_id. The rel_id might be useful for retrieving or updating standard +component. If a component is a direct component then group_id will be equal +to container_id. You can think of this view as having a primary key of +group_id, component_id, and container_id. The rel_id column points to the row +in acs_rels table that contains the relation object that relates component_id to +container_id. The rel_id might be useful for retrieving or updating standard auditing info for the relation. @@ -343,9 +371,8 @@ -This is similar to group_component_map except for membership relations. -Note that this view will return all membership relations regardless of -membership state. +The group_member_map view is similar to group_component_map except for membership relations. +This view returns all membership relations regardless of membership state. @@ -359,7 +386,8 @@ -The group_approved_member_map is the same as the group_member_map except +The group_approved_member_map +view is the same as group_member_map except it only returns entries that relate to approved members. @@ -374,9 +402,11 @@ -This view is useful if you don't care about the distinction between -direct membership and indirect membership. It simply returns all members of a -group including members of components. (It is the transitive closure.) +The group_distinct_member_map +view is a +useful view if you do not care about the distinction between +direct membership and indirect membership. It returns all members of a +group including members of components --the transitive closure. @@ -390,10 +420,10 @@ -This view is the same as group_distinct_member_map, except it includes the -identity mapping. In other words it maps from a party to the fully expanded +The party_member_map view is the same as group_distinct_member_map, except it includes the +identity mapping. It maps from a party to the fully expanded list of parties represented by that party including the party itself. So if a -party is an individual this view will have exactly one mapping that is from +party is an individual, this view will have exactly one mapping that is from that party to itself. If a view is a group containing three individuals, this view will have four rows for that party, one for each member, and one from the party to itself. @@ -410,11 +440,9 @@ -This view is the same as above except that when it expands groups, it only +The party_approved_member_map view is the same as party_member_map except that when it expands groups, it only pays attention to approved members. - - create or replace view party_approved_member_map @@ -424,35 +452,31 @@ - - Extending The Parties Data Model +The parties data model can represent some fairly sophisticated real +world situations. Still, it would be foolish to assume that this data +model is sufficiently efficient for every +application. This section describes some +of the more common ways to extend the parties data model. - -As is, the parties data model can represent some fairly sophisticated real -world situations, and a lot of work has been put into making this efficient, -but it is foolish to assume that this data model is sufficient for every -application. It therefore seems likely that developers will want to extend -the parties data model in a number of ways. This section will describe some -of the more common ways. - Specializing Users -It is conceivable that some applications will want to collect more -detailed information for people using the system. If it is the case that +Some applications will want to collect more +detailed information for people using the system. If there can be only one such piece of information per user, then it might make sense to create another type of individual that is a further specialization -of a user. For example a MENSA community web site might want to record IQs +of a user. For example a Chess Club community web site might want to record +the most recent score for each user. In a situation like this it would be appropriate to create a -subtype of users, say mensa_users. This child table of the users table would +subtype of users, say chess_club_users. This child table of the users table would have a primary key that references the users table, thereby guaranteeing that -each row in the mensa_users table has a corresponding row in each of the +each row in the chess_club_users table has a corresponding row in each of the users, persons, parties, and acs_objects tables. This child table could then -store any extra information relevant to the MENSA community. +store any extra information relevant to the Chess Club community. Specializing Groups @@ -461,7 +485,7 @@ efficient representation of sophisticated organizational structures, but there would be much more specialized information associated with each group. In this case it would make sense to specialize the group party type into a -company party type in the same manner as above. +company party type in the same manner as Specializing Users. Specializing Membership Relations Index: openacs-4/packages/acs-core-docs/www/xml/developers-guide/permissions-tediously-explained.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/xml/developers-guide/permissions-tediously-explained.xml,v diff -u -r1.6 -r1.7 --- openacs-4/packages/acs-core-docs/www/xml/developers-guide/permissions-tediously-explained.xml 17 Jul 2006 05:38:37 -0000 1.6 +++ openacs-4/packages/acs-core-docs/www/xml/developers-guide/permissions-tediously-explained.xml 5 Aug 2006 05:18:21 -0000 1.7 @@ -14,23 +14,28 @@ - Overview + Permissions Overview + Who + (grantee_id) can do what + (privilege) on which object + (object_id). + - 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 + The general permissions system has a flexible (and relatively complex) data model in OpenACS. + Developers who have not had the time to learn the internals of the data model may end up writing seemingly correct code that crashes their system in weird ways. This writeup is the result of my running into such a piece of code and trying to understand exactly what went wrong. It is geared towards developers who understand the general permissions system to the extent that is described in the - OpenACS Permissions documentation, - but who haven't had the opportunity to take a long, careful look at the + Groups, Context, Permissions documentation, + but who have not had the opportunity to take a long, careful look at the system internals. - In OpenACS 4.x, most of the interesting tables are expected to extend (subtype) + In OpenACS, 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. @@ -62,8 +67,8 @@ - This means that any interesting entity (object) - in the system has an entry in the acs_objects. This + This means that items that want to use the features of the + OpenACS object system needs to have 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 @@ -115,7 +120,7 @@ - The naive approach to managing system security would be to require application developers + The micromanaging approach to 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 who have the read privilege on all objects, then we would need to store 100,000,000 entries of the form: @@ -206,7 +211,7 @@ also has the read privilege on all objects attached under A. - The general permission system, as implemented in OpenACS 4.x, takes advantage + The general permission system takes advantage of the hierarchical organization of objects to unburden developers of the necessity to explicitly maintain security information for every single object. There are three kinds of hierarchies involved. @@ -460,7 +465,7 @@ Despite its potentially great storage costs, maintaining a - flattened representation of the context tree is exactly what OpenACS 4.x + flattened representation of the context tree is exactly what OpenACS does. The flattened context tree is stored in the acs_object_context_index table. @@ -637,7 +642,12 @@ - The parent-child relationship between privileges is represented in + Note that admin privileges are + greater than read, write, create and delete privileges combined. + Issuing someone read, write, create and delete privileges will + not result in the person getting + admin privileges. + The parent-child relationship between privileges is represented in the acs_privilege_hierarchy table: @@ -884,7 +894,11 @@ - +Read acs_rels: right-side is a + subset of left-side, ie + object2 is a part of + object1. + Another way of building up groups is by adding subgroups. Suppose we define Merry Pranksters and Sad Pranksters as subgroups @@ -971,7 +985,7 @@ hierarchical queries, which are expensive in Oracle. As we saw in the Context Hierarchy section, one way of 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: + a table maintained by triggers. The OpenACS data model defines two such tables: @@ -1020,6 +1034,7 @@ and composition_rels tables through triggers. + additional comments 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 @@ -1097,7 +1112,7 @@ Security information is queried by calling the acs_permission.permission_p - function in OpenACS 4.x+. This is accessible from Tcl via the + function in OpenACS. This is accessible from Tcl via the permission::permission_p procedure. @@ -1125,18 +1140,18 @@ end acs_permission; - +problem avoidance - The function simply queries + The function queries , which is a humongous view that joins three flattened hierarchies: the context tree, the privilege hierarchy, - the party composition (and membership) hierarchy. As such, - it contains an extremely large number of rows. About + the party composition (and membership) hierarchy. + 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 function. Anything other than that would take forever to - finish or would ultimately result in an Oracle error. + finish or would ultimately result in a query error. Index: openacs-4/packages/acs-core-docs/www/xml/developers-guide/permissions.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/xml/developers-guide/permissions.xml,v diff -u -r1.15 -r1.16 --- openacs-4/packages/acs-core-docs/www/xml/developers-guide/permissions.xml 17 Jul 2006 05:38:37 -0000 1.15 +++ openacs-4/packages/acs-core-docs/www/xml/developers-guide/permissions.xml 5 Aug 2006 05:18:21 -0000 1.16 @@ -22,22 +22,26 @@ The OpenACS &version; Permissions system allows developers and administrators to set access control policies at the object level, that is, any application or system object represented by a row in the -acs_objects table can be access-controlled via a simple +acs_objects table can be access-controlled via a PL/SQL or Tcl interface. The permissions system manages a data model -that then allows scripts to check permissions using another simple -API call. +that then allows scripts to check permissions using another API call. -Although this may all sound easy and wonderful, no developer or -administrator would want to explicitly set access control +Although object level permissions seems appropriate, no developer or +administrator wants to explicitly set access control rights for every user and every object on a -site. Therefore, OpenACS &version; has two auxiliary mechanisms for making this -easier: First, the Groups system allows users to be grouped together -in flexible ways. Second, the object model defines a notion of +site. Therefore, OpenACS has two auxiliary mechanisms for making this +easier: + +the Groups system allows users to be grouped together +in flexible ways. +the object model defines a notion of object context, which allows applications to group objects -together into larger security domains. The rest of this document will -talk about each of these parts, and how they fit together with the +together into larger security domains. + + +The rest of this document discusses each of these parts, and how they fit together with the permissions system. @@ -48,42 +52,10 @@ Groups - -In OpenACS 3.x, the groups system allowed developers and administrators to -define simple groupings of users. Each group had a human readable name -and unique ID, and there was a single mapping table that mapped users -to groups. (The actual data model was more complicated because it -contained a meta-data system much like the OpenACS &version; object type system, -but that's not relevant right now.) - -The 3.x groups system, while very useful, was limited in few ways. The -main limitation: groups could not either contain or include other -groups. You could not express the fact that all the members of group A -should also be in group B - for example, to model a company with -multiple offices. The company should have a main group representing -all employees, and each office should have a group representing its -employees. Obviously, you'd want every member of an office employee -group to automatically be a member of the whole company employee -group. - - - -In OpenACS 3.x, you also could not express the fact that group A should -itself be a member of group B, without also implying that all of its -members are also members of B. This type of relationship also comes up -in the real world, though not as often. A good example is an -organization like Greenpeace that can have as members both individuals -and organizations: although the Sierra Club may be an organization -member of Greenpeace, its members are not necessarily members of -Greenpeace. - - - -OpenACS &version; solves both of these modeling problems by introducing a new -abstraction called a party. Parties have a recursive -definition, and we can illustrate how it works with the following +OpenACS &version; has an abstraction called a party. Parties have a recursive +definition. We can illustrate how it works with the following simplified data model. First, we define the parties table, where each party has an email address and a URL for contact information. @@ -127,38 +99,35 @@ The users table is also defined in this data model as a -subtype of person. It contains many of the basic columns -that the old OpenACS 3.x users table contained. +subtype of person. Finally, we define two relations, one for group membership and -one for group composition. The composition relation allows us -to express the fact that every member of group A should also be a +one for group composition. + +The composition relation expresses that every member of group A should also be a member of group B. This relation allows us to define a hierarchy of -groups instead of the simple flat groups that 3.x allowed. +groups. -The membership relation is much like the mapping we had in 3.x, except -that it maps groups to parties instead of groups to users. What -this means is that each member of a group is a party rather than just +The membership relation maps groups to parties. Each member of a group is a party rather than just a user. That is, groups consist of members that are either a person or an entire group. This allows us to say that group A should be a member of another group B. -The groups data model is pleasantly recursive. The fact that parties -are modeled as being either a person or a group has a lot of power, -allowing us to model complex hierarchical groupings of persons and -groups that were hard or impossible to model in 3.x. +The groups data model is recursive. Modelling parties as either a +person or a group provides a way to model complex hierarchical groupings of persons and +groups. The full details of the groups data model is beyond the scope of this -tutorial - I've just given you what you need to understand how -permissions work. For further detail, you can look at or . +tutorial. See or for more details. @@ -173,31 +142,30 @@ -The permissions data model is actually pretty simple. The data model -is a mapping between privileges, parties and objects. We -already know what parties and objects are, but we don't know what -privileges are. +The permissions data model is a mapping between +privileges, parties and objects. Parties and +objects have already been discussed. Now we focus on privileges. -In OpenACS &version;, a privilege models the right to perform some operation on -some object. They are the basic units out of which we build access -control policies. For example, in the Unix filesystem we typically -implement access control by granting users some combination of -read. write or execute privileges on files and directories. In OpenACS &version;, +In OpenACS, a privilege describes the right to perform some operation on +some object. Privileges are the basic units out of which we build access +control policies. For example in the Unix filesystem, access is controlled by granting users some combination of +read, write, or execute privileges on files and directories. In +OpenACS &version;, the table of privileges is organized hierarchically so that developers can define privileges that aggregate some set of privileges together. For example, if we have read, write, create and delete privileges, it might be convenient to combine them into a new privilege -called "admin". Then if we grant a user this privilege she is +called "admin". Then, when a user is granted "admin" privilege, she is automatically granted all the child privileges that the privilege -contains. The OpenACS &version; kernel data model actually defines these -privileges as follows: +contains. The OpenACS &version; kernel data model defines these +privileges: - +# begin acs_privilege.create_privilege('read'); acs_privilege.create_privilege('write'); @@ -214,8 +182,12 @@ end; + +Note that a user does not gain admin privileges when granted +read, write, create and delete privileges, because some operations +explicitly require admin privileges. No substitutions. + - To give a user permission to perform a particular operation on a particular object you call @@ -224,7 +196,7 @@ - +# sql code acs_permission.grant_permission ( object_id => some_object_id, grantee_id => some_party_id, @@ -237,11 +209,13 @@ Using just these mechanisms is enough for developers and administrators to effectively define access control for every object -in a system. But it would be tedious to explicitly attach permissions -to every object individually: in many cases, we'd prefer controlling -permissions to large groups of objects in the site, all at once. We -use contexts to achieve this goal. +in a system. +Explicitly defining permissions to every object individually +would become very tedious. +OpenACS provides a object contexts as a means for controlling permissions of a large group +of objects at the same time. + @@ -250,8 +224,8 @@ -In OpenACS &version;, an object context is a generalization of the scoping -mechanism introduced in OpenACS 3.x. "Scoping" and "scope" are terms best +In OpenACS &version;, object context is a scoping +mechanism. "Scoping" and "scope" are terms best explained by example: consider some hypothetical rows in the address_book table: @@ -299,38 +273,39 @@ The first row represents an entry in User 123's personal address book, the second row represents an entry in User Group 456's shared address book, and the third row represents an entry in the site's public -address book. - - - -In this way, the scoping columns identify the security context in +address book. In this way, the scoping columns identify the security context in which a given object belongs, where each context is either a person or a group of people or the general public (itself a group of people). -In OpenACS &version;, rather than breaking the world into a limited set of scopes, -every object lives in a single context. A context is just an +Every object lives in a single context. A context is just an another object that represents the security domain to which the object -belongs. By convention, if an object A doesn't have any permissions +belongs. By convention, if an object A does not have any permissions explicitly attached to it, then the system will look at the context_id column in acs_objects and check the context object there for permissions. Two things control the scope -of this search: the structure of the context hierarchy itself, and the -value of the security_inherit_p flag in each object. If -this flag is set to 't', then the automatic search +of this search: +the structure of the context hierarchy +itself, and + +the value of the security_inherit_p +flag in each object. + +If +security_inherit_p flag is set to 't', then the automatic search through the context happens, otherwise it does not. You might set this field to 'f' if you want to override the default permissions in a subtree of some context. - A good example of how to use this hierarchy is in the forums +For an example of how to use context hierarchy, consider the forums application. With only row-level permissions it is not obvious how to reasonably initialize the access control list when creating a message. At best, we have to explicitly grant various read and write -privileges whenever we create a message, which is tedious. In OpenACS &version;, -a reasonable thing to do is to create an object representing a forum, +privileges whenever we create a message, which is tedious. +A reasonable thing to do is to create an object representing a forum, and point the context_id field of a new message at the forum. Then, suppose we grant every user in the system read-access to this forum. By default, they will automatically have read-access to @@ -352,8 +327,8 @@ -A few things to note here. First, the top two contexts in the picture -are "magic" in some sense because they are created by default by OpenACS +The top two contexts in the diagram +are called "magic" numbers, because in some sense, they are created by default by OpenACS for a specific purpose. The object default_context represents the root of the context hierarchy for the entire site. All permission searches walk up the tree to this point and then stop. If @@ -363,197 +338,35 @@ security_context_root has a slightly different role. If some object has no permissions attached to it, and its value for security_inherit_p is 'f', or -context_id is null, then we use this context by default. +context_id is null, this context is used by default. - - - - -Example - - - -At this point, you should either go and download the Notes example -code from the package repository, or check it out of the OpenACS CVS -repository and add it to your server. The package is called -"notes". To check it out from CVS, read the these instructions -on how to use anonymous checkouts and then -checkout the module notes: +See the package developer tutorials for examples on how to use +permissions code. - - - The notes code has been modified since this document was written so it is now out of date. See this forum thread. - - -% export CVSROOT=:pserver:anonymous@cvs.openacs.org:/cvsroot -% cvs login # just hit enter when prompted for a password -% cvs co notes - - - - -After you have downloaded the package, look at the -index.tcl page in the www directory. You can also -look at the code in your browser. The code should look something like this: - - - - - - -# main index page for notes. - -ad_page_contract { - @author you - @cvs-id $Id$ -} -properties { - notes:multirow - context_bar:onevalue - create_p:onevalue -} - -set package_id [ad_conn package_id] -set user_id [ad_conn user_id] - -set context_bar [ad_context_bar] -set create_p [permission::permission_p \ - -object_id $package_id \ - -privilege create \ - -party_id $user_id] - -db_multirow notes notes { - select note_id, owner_id, title, body, - decode(acs_permission.permission_p(note_id, - :user_id, - 'write'), - 't', 1, - 'f', 0) as write_p, - decode(acs_permission.permission_p(note_id, - :user_id, - 'admin'), - 't', 1, - 'f', 0) as admin_p, - decode(acs_permission.permission_p(note_id, - :user_id, - 'delete'), - 't', 1, - 'f', 0) as delete_p - from notes n, acs_objects o - where n.note_id = o.object_id - and o.context_id = :package_id - and acs_permission.permission_p(note_id, :user_id, 'read') = 't' - order by creation_date -} - -ad_return_template - - - - - -This example shows both the Tcl and PL/SQL APIs for checking -permissions. The Tcl proc permission::permission_p and the PL/SQL -function acs_permission.permission_p both return a flag -indicating whether the current user has permission to perform the -given action. By default, the Tcl procedure extracts the user_id out -of the request environment, while the SQL procedure takes it as an -argument. - - - - -It also shows how we display more complicated items using the template -system. The code here creates a multirow data source, i.e. a -data source that represents a query returning multiple rows from the -database. For each row, we return the ID of the note, the ID of the -owner of the note, the title, the body and then three flags that -indicate whether the user has write, admin, and delete -privileges. Also, the WHERE clause of the query ensures that we only -see notes that we are allowed to see. - - - -Next, look at the index.adp. It is pretty complicated. -The main part of this page uses a multiple template -tag. If you want to experiment, you can replace the main body of the -multiple tag with this: - - - - - - -<multiple name=notes> -<td>@notes.title@</td><td>@notes.body</td> -</multiple> - - - - - -This will just make a table with one note per row. - - - -Now put the more complex code back. You'll notice a lot of stuff like this: - - - - - - -<if @notes.write_p@ eq 1> - <a href=add-edit?note_id=@notes.note_id@>@notes.title@</a> -</if> -<else> - @notes.title@ -</else> - - - - - -This displays the title of the note as either a link or plain text -depending on whether or not we have write privileges on the object. -The if tag is something that the OpenACS &version; template system -defines for you to support conditional presentation. The templates developer guide provides more information about this. - - - -If you study the rest of the system, you will also notice that the -notes application doesn't explicitly attach privileges to the objects -it creates. All privileges are inherited from the context of the object -which in this case is the package instance. The assumption is that the -administrator of the site would create one instance of notes for every -user that wants it, and set the permissions on this instance -appropriately. In a more advanced version of the application, we could -implement a user interface that allowed the user to explicitly attach -permissions to notes that she wanted to make public or whatever. But -that's beyond the scope of this example. - - - + Summary OpenACS &version; defines three separate mechanisms for specifying access control -in applications. The Groups data model allows you to define -hierarchical organizations of users and groups of users. The Permissions -data model allows you to define a hierarchy of user rights. Finally, -the Context hierarchy allows you to define organize default -permissions in a hierarchical fashion. A simple PL/SQL or Tcl API is -then used to do access control checks in application pages. +in applications. + +The Groups data model allows you to define +hierarchical organizations of users and groups of users. + +The Permissions +data model allows you to define a hierarchy of user rights. + +The Context hierarchy allows you to define organize default +permissions in a hierarchical fashion. + +A PL/SQL or Tcl API is +then used to check permissions in application pages. - -In the next section, we'll look at a more complex page for adding and -editing notes, and discuss these issues further. - - ($Id$)