- 1 Business Requirements
- 1.1 What resources do we want to control access to?
- 1.2 Who needs access to these resources?
- 1.3 Permission Specification
- 1.4 What are some restrictions in our access model?
- 2 Technical Implementation
- 2.1 Policies as basic units of design
- 2.2 Policy Configuration and Enforcement
- 2.3 Role Based Access Control (RBAC)
- 2.4 Evaluation of the Authorization Framework Implementation
What resources do we want to control access to?
- Access to Features: These are logically grouped into "visual blocks" which form "pages" which are attributed to "workflow stages".
- Access to Application Objects
A workflow stage is defined as a number of editorial actions applied to one and the same "bundle of objects", all assigned to the same submission. This can be files, documents, reviews, etc. Files and other objects can be copied or promoted from one workflow stage to the next. Files and other objects can also be added to or removed from a given workflow stage.
A certain action (e.g. a review) can be applied to a sub-set of these objects (e.g. files selected for review) but objects that are not attributed to the given workflow stage are not accessible to any action within the workflow step.
All objects attributed to a submission must at the same time be attributed to a workflow stage.
Workflow stages in OMP are:
Workflow stages in OJS are:
Workflow stages in OCS are:
Workflow stages in the OHS are:
Pages present a number of logically grouped features to the end user. A new page is displayed when entering a URL or clicking a link (or more technically: making a full HTTP request). There might be several URLs pointing to different versions of the same basic page.
The smallest entity that we allow access to is a visual block on a page. This can be a grid with grid actions, it can be logically grouped read-only information or any other "bundle" of elements grouped together on a page and managed as a "whole" when it comes to access control. Visual blocks often display objects retrieved from the database like submissions, files, reviews, notes, etc. Each visual block defines the way these objects will be selected and filtered based on the user's permission that is currently looking at these data.
Visual blocks can be implemented as (AJAX) components which allows them to be updated, added to or deleted from the page without a full page reload.
A visual block usually presents or acts upon one or more application objects. A grid can contain several files or meta-data can be grouped and we can allow access only to certain groups of meta-data properties to a given user while other meta-data remains hidden.
Typical application objects that we want to allow access to are submissions, files, reviews, documents, etc.
You can roughly think of application objects as anything that can be added, deleted and edited in the database.
A less precise concept but one that is rather useful to distinguish between different features and categorize them is "access mode". Typical access modes are create, read, update and delete. Access modes are somehow the link between "features" and "application objects". Usually a given feature provides access to one or more application objects in a certain access mode.
A grid may for example have buttons to add, delete and edit objects that correspond to the add, delete and edit "features" of a grid.
To sum up we can say that the basic resource that we grant access to is: a visual block that allows inspection or manipulation of one or more application objects in a given access mode.
Who needs access to these resources?
PKP applications grant access to application users which represent (=identify) human actors accessing the application.
It is of course inefficient to define individual access levels for every user. We therefore have to find a way to group users so that they can be granted access in a more efficient way.
We have to make sure that we make the groups small enough to be able to define the level of differentiated access that we need to implement our specifications. At the same time, however, we want the groups to be as large (and as few) as possible to keep the administrative burden down.
The basic unit that can be used to group users with the same access levels is called a "user role" in PKP applications. A user role needs to unequivocally define all features and application objects available to its members. What we said in the previous paragraph means that we need to create roles in a way that within one role all users have the same homogeneous permissions but that no two roles are equal.
We therefore need a different role for all types of "bundles" of features and object access that are required in the application.
In our case we can create all roles from a combination of a few feature sets and basic object access logics.
Feature Access Definition
We can group features that can be accessed by a given role into feature sets. Typical feature sets that we can address as a single unit are:
- all features within the application
- all features within a worflow stage
- all features on a given page (e.g. review page for reviewers)
- one or more visual blocks on a page.
The most frequent feature set to be adressed in OJS, OHS and OCS is the page level with a few block-centered exceptions. In OMP the block level will be more important in many situations.
Feature sets also define for every block, page or workflow stage in which access mode it can be accessed. This may be addition, reading, updating and deletion of objects.
A typical feature set definition would therefore be: Members of the author role have read access on all features of the submission stage page with exception of file access where they can also add (=upload), delete and edit (=file metadata) objects.
Object Access Logic
While feature sets are fixed and can be "hard-coded" into the roles, we need to give our users quite some flexibility when it comes to defining object access. Not all publishers define object access in the same way and object access definitions need to be very granular sometimes.
A few examples:
- All reviewers basically need the same functionality to review a monograph or an article but not all reviewers need access to the same articles. They have access only to a small selection of articles, a single monograph or a single conference paper.
- Series editors (OMP) and section editors (OJS) have access to a sub-set of articles/monographs within a journal/press. The functionality, they have access to, is largely the same as that of a journal editor or press editor, though.
In some instances we have to define access on a per-object level. While we can say that authors see all submissions contributed by them we might have a situation in which a specific copyeditor has access to a completely arbitrary set of submissions which cannot be grouped by any pre-defined criteria.
Although we cannot "hard code" object access permissions themselves into our roles, we still can identify a few basic types of access logic that we can then attribute to roles and leave the actual permission administration to the end user.
Some possible access logics are:
- access to all objects of a kind throughout the application, e.g. site administrators' access to presses (OMP), journals (OJS), etc.
- access to all objects of a kind within one context (press, journal, conference, etc.), e.g. press editors' or journal managers' access to submissions within a press/journal
- access to all objects of a kind within a subset of a context (series, section, etc.), e.g. series editors' or section editors' access to all submissions within a series/section of a press/journal
- access to objects by ownership, e.g. authors' or reviewers' access to submissions/reviews they uploaded themselves
- access to objects via individual rights assignment based on pre-defined or custom user groups
While the first four access logics are obvious, the last one needs a bit more explanation. It actually means that we allow access to arbitrary application objects based on user group assignments. To explain this we need to introduce the user group concept.
PKP applications allow organizations to create and maintain subgroups within user roles that, from a technical viewpoint, provide the exact same level of access to the application. At first sight this doesn't seem to be efficient as it means maintaining duplicate groups with equal access rights which increases application administration cost. While this is true from a technical standpoint, there are reasons why organizations may want to keep groups apart even if they have the same access level.
In the case of OMP for example, authors and volume editors have the same access rights. Still it makes sense to name them differently as they are different from a publisher's point of view.
PKP applications contain a number of pre-defined user groups but organizations can freely add, rename or delete user groups per context (press, journal, etc.). A user group always has one of the application roles assigned which unequivocally defines the feature set and object access logic for that group.
Individual Rights Assignment
Based on user groups it is now possible to define highly flexible object access.
A user can be granted access to an object within one of the user groups she has been assigned to. This gives the user access to all the features defined for the role attached to the user group with respect to the assigned object.
- A press manager (which is a pre-defined user group which has the managerial access role assigned) creates a new user group called "translators" and assigns it to the author role.
- Then the press manager can assign users to that new user group which act as translators.
- Finally the press manager will now be able to assign a user as a translator to an arbitrary submission at a certain workflow stage, say the copyediting stage.
This will give this single user access to the features defined for the editorial role within the copyediting workflow stage but only for the selected submission. It won't give the user access to editorial features in other workflow steps, it won't give other users of the same group any additional access rights and it won't give the user any rights to any other submission.
Based on these concepts we've developed a detailed permission specification for OMP. Similar specifications will have to be developed for the other PKP applications. Specification stubs exist for the PKP library and OJS.
What are some restrictions in our access model?
Restrictions on Roles
Different user groups that are based on the same basic role cannot be granted different types of access. This includes access to either features or objects.
Example 1 - Different Feature Sets: If the proofreader group and the copyeditor group belong to the same basic role (e.g. "press role") then our current approach makes it impossible to give copyeditors access to different pages within the proofreading process than we allow proofreaders to look at. The implication is that if proofreaders need their own set of pages, then we have to introduce a separate role for them.
Example 2 - Different Object Access Logic: We also cannot manage object access based on a different logic for two different user groups that are based on the same role. If series editors see their objects (submissions) based on series and press manager see their objects based on the press they belong to, then these two user groups cannot be based on the same role model. The implication is that series editors and press editors need to be based on two distinct roles.
Conclusion: Proofreaders, series editors and press managers all have to be based on different basic application roles!
Restrictions on Feature Definitions
The smallest unit to define feature sets is a "visual block". Unique and definite access rights (access mode, feature set and object access logic) for a given role must be defined for every "visual block".
Restrictions on Object Access Definition
Individual object access can be attributed on a workflow stage or page (=handler operation) level only. This means that workflow stages/handler operations are the smallest unit to differentiate between individual user's access levels. Finer granularity can only be achieved by defining additional basic roles. For more efficient implementation we should try to group all handler operations with the same access levels into the same handlers. This is not always possible of course as handlers cannot be structured by access level only.
Policies as basic units of design
For our implementation we translated the above specification into authorization policies. Policies are the basic building blocks of our authorization framework design. Policies can be grouped together into policy sets.
Policy Configuration and Enforcement
The following functions must be implemented within any authorization framework to configure and actually enforce policy:
- a tool to administer policies
- a component determining authorization decisions based on policy
- actual authorization decision enforcement
- a policy information source
As we hard code most of our policies (namely assignement of roles to handler operations) we do not need to administer this kind of policy. Policies can be grouped into policy sets with a combining algorithm assigned (e.g. permit overrides or deny overrides) to form more complex combined policies.
We do have to administer the assignment of subjects (users) to user groups, the assignment of user groups to roles and the assignment of users to certain types of data objects (e.g. sections or articles in OJS or series in OMP):
- User-user group assignment is done on the user enrollment pages which shows all user groups and allows users with managerial access level to add/remove users to/from user groups.
- For the moment being user group-role assignment is only relevant to OMP as OJS/OCS do not yet implement the user group abstraction but directly assign users to roles. In OMP there will be a grid which is part of the press settings that allows members of managerial roles to add new user groups with a given role assigned or remove user groups from a role. NB: The same grid is used to assign workflow steps to user groups. This is, however, not a permission assignment! It simply determines which workflow stages will be linked by default to the user. The user always has the right to access all workflow stages and features assigned by permission policy to the assigned role. The role is the only instance that has permissions attached to.
See the section about our role based access model below for further information.
Assignment of users to data objects like series/monographs/workflow stages (OMP), sections/articles (OJS), tracks/papers (OCS), etc. is done at several places in the application. In the case of articles, papers, monographs, etc. we implement an "owner" concept. This means that the submitter of an article is automatically being assigned to it as its creator. Series, sections and tracks have to be assigned explicitly to a user.
Policy Information Sources
Policy information comes from several sources:
- The user-user group assignments as well as the user group-role assignments are held in database tables and will be queried there.
- Policies defined via descendants of the AuthorizationPolicy or PolicySet classes are defined in a handler's authorize() method.
- Role - handler operation assignments are done in the constructor of a handler via the handler's addRoleAssignment() method.
- Policies controlling access to data objects are defined...
- ... always in the handler's authorize() method if the data object is defined via a request parameter (e.g. access to a monograph in a monograph details page that passes in a monograph id via HTTP GET).
- ... sometimes also directly in the handler operation code if the data objects are not defined via a request parameter (e.g. all submissions of the currently logged in user). You should avoid this kind of policy definition if possible as it hinders re-use of policy code via AuthorizationPolicy implementations and makes it more difficult to find authorization code.
Data access policy definitions can be quite complex, e.g. in the case of subscription based access. They nearly always require inspection of the data objects or database access as well as inspection of the application environment (context, settings, etc.).
All policy-based authorization decisions are delegated to the AuthorizationDecisionManager. This class will be instantiated by the PKPHandler class in it's authorize() method. It recursively walks through all AuthorizationPolicy and PolicySet objects defined for the handler and delegates to these policy objects to take an authorization decision based on request attributes, environmental attributes (e.g. HTTPS vs. HTTP access) and attributes retrieved from the database.
When the authorization decision manager issues a favorable decision, it will make sure that authorized objects (e.g. a monograph or a user group) will be made available to the handler via the authorization context. Handler operations can retrieve authorized objects via the handler's getAuthorizedContextObject() method.
Authorization Decision Requests and Enforcement
Authorization decision requests will be issued by the router before a handler operation is actually being accessed. The router will call a handler's authorize() method to trigger the authorization process. The policies defined for the handler will then be evaluated by the authorization decision manager. The authorize() method will return a boolean value corresponding to the authorization decision. The router takes care of policy enforcement by blocking access to the router operation and issuing an error when the authorization was not successful.
Class Model: Authorization Policies and Policy Sets
Please see the actual class hierarchy of AuthorizationPolicy and search for instantiations of PolicySet to find policy types implemented in the various applications. Policies within the folder classes/security/authorization/internal are not meant for direct use within handlers!
Please only use policies that are...
- ... fully specified in the corresponding permission specification (i.e. Google Docs Spreadsheet)
- ... in the classes/security/authorization folder and not in the internal folder.
The PolicySet class is not usually subclassed. All high level policies to be used in handlers are actually policy sets that consist of a number of sub-policies which can either be AuthorizationPolicy sub-classes or other policy sets.
Policy sets are instantiated with a policy combining algorithm which defines how the policies within that set are being joined by the authorization decision manager to come to a final decision.
Two types of combining algorithms have been implemented so far:
- Permit overrides: If any of the sub-policies returns a "permit access" result then the policy set as a whole evaluates to "permit access". This is something like an "OR" condition with a few more complex rules when policies abstain from providing a decision (e.g. because the policy is not applicable to the current request environment).
- Deny overrides: If any of the sub-policies returns a "deny access" result then the policy set as a whole evaluates to "deny access". This is the default and implements something like an "AND" condition.
Policy sets can be nested into each other in an arbitrary depth. The authorization result returned by a policy set will be treated one level above as if returned from a single authorization policy.
Policy Specification for specific Applications
The permission specification for OMP shows how high level access policy requirements have been translated into specific policy definitions. Each spreadsheet tab within the document represent exactly one policy. The tab name corresponds to the policy's class name.
Similar policy classes will have to be specified and implemented for other PKP applications (OJS, OCS and OHS).
Role Based Access Control (RBAC)
The PKP authorization framework relies on several policy types. One very prominent policy type implements role-based access control (RBAC).
Elements of an RBAC system
The elements of a typical RBAC system are:
- Subjects (Agents, Users)
- Objects (Resources) to which access should be controlled
- Access Modes (e.g. "read", "write", "execute", etc.) - sometimes also called "operations" or "actions"
- Permissions that define a certain mode of access to a resource
Subjects and permissions are assigned to roles. Roles are thereby an efficient way to define which subject has access to which resource and through which access mode.
Refinements of this basic access control model are possible:
- Roles can be organized in a hierarchy whereby a subordinate role "inherits" permission assignments of its parent role.
- Subjects, objects, access modes and permissions can be organized in groups so that they can be assigned or otherwise handled in "bulk". Groups of permissions are calles "policies".
PKP's RBAC implementation
PKP does not require all elements of the generic RBAC model. We apply the model to our application in the following way:
- The subjects in PKP applications are called "users"
- The resources we control are handler operations and database objects (e.g. articles, files, papers, etc.).
- PKP applications currently use a hard coded, non-configurable role model (e.g. in OJS: "editor", "section editor", "author", "reviewer", "journal manager", "site administrator", etc.).
- PKP applications do not currently implement an explicit role hierarchy although in practice there are implicit role hierarchies:
- In OJS, the hierarchy goes from the site administrator over journal managers and editors down to section editors and subscription managers inherit a few permissions from the journal manager.
- Some roles (e.g. 'site administrator' and 'journal manager' in OJS) can "log in as" any other user, thereby temporarily inheriting all permissions of the impersonated user's role.
- Permission-role assignments are hard-coded into the application. Handler operations define which roles may access it. Currently authorization checks are part of the request "validation" procedure.
- Most of the time all operations within a handler may be accessed by the same roles. In these cases the handler constructor (for pages) or handler-wide validation method (for AJAX controllers) implement the permission-role assignments for all contained operations. In other words: We usually define a policy that contains permissions for all operations of a handler.
- HandlerValidatorRoles classes define the assignment of operations to roles
- Database object permissions are usually either hard coded into the validate() method or the handler operation itself
- There are a number of other permission-related checks (e.g. check for a given context, check for HTTPS protocol, etc.) which are also coded into the validate() method or the handler operation
- Usually operations only define one mode of access ("execute"). There are a few exception to this rule, where different roles may access the same operation in different ways, e.g. the differentiated access of "editors" and "section editors" to some of the operations in the editorial process in OJS. In these cases access modes are hard coded into the operation.
- Subject-role assignments are configurable via the role administration UI in PKP applications.
- We recently introduced configurable subject groups or in PKP terminology "user groups" that allow bulk assignment of several users to one (and only one) of PKP's hard coded roles. The names of user groups can be freely defined in the role administration UI. Applications that make use of user groups will no longer allow direct subject-role assignments. It must be stressed that user groups are not roles although end users do not necessarily need to understand this distinction. PKP developers should be very clear in their terminology, though, to avoid confusion and implementation errors. The term "flexible role" is deprecated in favor of "user group" and should no longer be used.
RBAC Database Model
Entities and Relationships
- RBAC subjects, objects, object groups, roles, permissions and permission assignments are all hard coded into PKP applications in handlers' constructors (see PKPHandler::addRoleAssignment()) and are therefore not mapped to any database entities!
- The interface of hard coded roles and the database is via PHP role constants (e.g. ROLE_ID_EDITOR).
- The "roles" table that has been present in earlier releases of PKP applications is not representing roles but user-role assignments. The name of this database entity is conceptually wrong and was replaced with the introduction of configurable user groups.
- Only configurable entities and relations are represented as entities in the database. These are "users", "user groups", "user - user group assignments" and "user group - role assignments". The corresponding database entities are "users", "users_user_groups" and "user_groups".
- As with all PKP entities, the user and user group entity tables will be accompanied by a corresponding settings table that allows for flexible meta-data (=attribute) assignment and internationalization.
- The "user_groups" table contains a foreign key to the non-database "role" entity. This means that the role column in "user_groups" contains references to the above mentioned role constants defined in the application code.
- one user can be assigned to several user groups, one user group can contain several users (0..n:0..m relation)
- one user group can be assigned to exactly one role, one role can have several user groups assigned (1..1:1..n relation)
- every role has a standard user group assigned which will never be deleted (which explains the 1.. relation).
Evaluation of the Authorization Framework Implementation
Our authorization framework is limited in several respects. This is not necessarily a bad thing as long as the framework is able to implement all specified requirements and is flexible enough to be extended within a reasonable range in the future:
- Hard coded policies: policies cannot be configured by the end user nor can we create "policy profiles" for different applications or use cases if such would become a requirement. This also implies that if we need to implement different permissions for different applications then we have to write application-specific sub-classes of the AuthorizationPolicy and PolicySet classes which means that policy definitions either have to follow the inheritance hierarchy or have to be duplicated in several places. Hard coding policies also means that requirements like subscription based access have to be hard coded into operations rather than providing central access profiles which could be changed in one single place.
- Hard coded roles: If we want to introduce a new role we'll have to introduce it in code which means that we cannot let the user introduce new roles with differentiated access levels from the application front-end.
- Authorization functions scattered: As can be seen from the previous sections authorization functions are spread over various locations in the code - database, router, handler constructor, handler's authorize() method, even the handler operation to some extend. This makes it sometimes difficult to find all policies relevant to a given handler operation or "visual block". On the other hand we define our policies close to the point at which they act (e.g. within the handler that they restrict) which is often less confusing than having to search for policies far from their "point of impact", e.g. in a central policy database.