Access to add and change pages is restricted. See: https://cwiki.apache.org/confluence/display/OFBIZ/Wiki+access

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 11 Next »

This page is intended to be used as a means of collaboration on the Apache OFBiz security refactor.

A new design is being proposed, but it is not finalized. Anyone who is interested is welcome to comment, critique, and add suggestions.

Security-Aware Artifacts

Introduction

The current OFBiz security implementation uses indirect security control - where permission services are used to control access to OFBiz artifacts. Permission services are small scripts that evaluate user permissions, determine if a user is related to a piece in data in some way, and other tasks. In the end, the script returns an access-granted or access-denied result (hasPermission) that is used to control access to the artifact(s) managed by the script.

As the number of artifacts in OFBiz grows, the number and complexity of permission services grows too. Some of this growth can be controlled by having common permission checking done in shared scripts.

Permission services use a coarse set of permissions - providing a basic set of create/update/delete (CRUD) flags that control broad ranges of artifacts. Fine-grained control is possible, but it requires complicated conditional processing.

A permission service can be extended by assigning a Service Event Condition Action (SECA) to it. If the primary permission service returns hasPermission=false, the SECA is triggered and an additional permission service is run. The result of the second permission service controls access to the artifact(s).

Disadvantages

Since the current OFBiz security implementation uses indirect security control, there is no direct connection of permission logic to the artifact that the logic is trying to control access to. Access to a particular artifact could be (and often is) controlled by a handful of different scripts. While this may appear to be an advantage (because it's flexible), it becomes a problem when something about the artifact changes that requires a change in access control. Permission scripts that control the artifact must be tracked down and updated.

The coarse grained permission logic fosters an "all or nothing" design mentality. Smaller artifacts - like menu items and data entry fields - can be controlled individually by permissions, but it requires cumbersome conditional code. Many times the developer will just give the user access to all of these smaller artifacts - regardless of whether or not the user has permission to use them.

The only way to get a list of all the user's permissions associated with an artifact is to perform a permission check for every one of the CRUD permissions and add each result to a list. That makes artifact access control cumbersome.

Any time a new artifact is created that needs access control, a new script needs to be written to control it.

A Different Approach

What if we took the job of artifact access control away from the permission services and gave it to the artifacts themselves? What if every artifact was security-aware?

Instead of an artifact's access being controlled in a handful of places, it is controlled in one place - within the artifact itself. There is no complicated intermediary code that must consider all possible interactions a user might have with a set of artifacts. Since all artifacts are security-aware, fine grained control is possible. There is no need for cumbersome conditional logic to control an artifact - the artifact controls itself.

Design Overview

There are three key players in the Security-Aware Artifact design:

  1. The user.
  2. The OFBiz artifact - an application, a service, an entity, or one of the screen widgets.
  3. An authorization manager (permissions management software).

The process is very simple:

  1. The user is about to interact with an artifact (through an event or a request).
  2. The artifact takes the UserLogin GenericValue and the artifact's identifier, and hands them to the authorization manager. The authorization manager returns a list of permissions granted to the user for that artifact.
  3. The artifact performs some type of default behavior based on the list of permissions returned.

Let's take a closer look at the process.

A user action triggers an interaction with an artifact - a service is invoked, or an entity is queried for data, or a screen widget is about to be rendered. In all cases, the security-aware artifacts (the service, the entity, or the screen) are responsible for their own security-related behavior.

Before the artifact begins its intended task, it asks the authorization manager for the permissions the user has for the artifact. In effect, the artifact says to the authorization manager, "Give me user X's permissions for artifact Y."

The authorization manager returns a list of permissions. For the sake of illustration, let's say the mere presence of a permission grants that permission. So, if "create" is in the permission list, then the user has create permission for the artifact.

What happens next depends upon the type of artifact - that is called the default behavior.

If the artifact is an entity, then the permissions control the user's ability to view, create, update, and delete records. If the artifact is a screen widget, then the permissions control if and how things are displayed. If the artifact is a service, then the permissions control if the service can be invoked.

Default behaviors for types of artifacts will be well documented, so the developer and OFBiz administrator will know exactly how permissions will affect each artifact.

Design Details

If each artifact has its own set of permissions, there could be potentially thousands of permissions - an administration nightmare! It would be helpful to have artifact permissions organized in a hierarchy - so that permissions defined higher up in the hierarchy are inherited by artifacts lower in the hierarchy. The hierarchy will reduce the number of permissions needed.

The components in OFBiz are organized in a hierarchy, and each component typically contains entities, services, and screen widgets. We can build on that structure to set up a hierarchy of security-aware artifacts:

  • OFBiz
    • applications
      • accounting
        • entity
          • Budget
          • BudgetAttribute
          • ...
          • PartyRate
        • service
          • createPartyAcctgPreference
          • updatePartyAcctgPreference
          • ...
          • payflowCCRefund
        • screen
          • FindAgreement
          • EditAgreement
          • ...
          • ViewGatewayResponse
    • ...

Permissions assigned at the OFBiz/applications/accounting level are inherited by all artifacts below that level. Permissions assigned at lower levels replace any inherited permissions. Permission inheritance is managed by the authorization manager.

In the design overview, it was mentioned that the security-aware artifact provides its identifier to the authorization manager when requesting permissions for itself. That identifier must be unique in order for the system to work. We can leverage the artifact hierarchy to construct a unique artifact identifier. The Budget entity's identifier would be OFBiz/applications/accounting/entity/Budget. The FindAgreement screen's identifier would be OFBiz/applications/accounting/screen/FindAgreement. The authorization manager should handle the identifier in a case-insensitive way.

The "OFBiz" portion of the identifier is considered the root of the hierarchy. The "applications" and "framework" portions of the identifiers could be left out of the design.

The permission list returned by the authorization manager is a set of flags - implemented as key/value pairs. The flag key indicates the type of permission - view, create, update, delete, etc. Valid flag values are "true" or "false." A value of "true" indicates access-granted, and a value of "false" or the absence of a key/value pair indicates access-denied. The permission list could consist of the standard view, create, update, and delete permissions. Artifacts are allowed to define additional permissions. For example, a web application or service artifact might need only one permission - access.

It is common for services to invoke other services, and for entities to be related to other entities. In those cases, the secondary or "child" artifacts inherit the permissions of the initial service or entity artifact. Permissions assigned to the child artifacts replace any inherited permissions.

Some of the existing permissions service scripts go beyond a simple check if a permission exists - they also check to see if the user is related to the data being accessed or changed. In other words, user access to data is constrained in some way depending upon the user. In those cases, we need more than a simple access-granted/access-denied permission - we need a service to perform those additional tests and we need a way for the authorization manager to specify the service.

When an artifact requires additional permissions checking beyond a simple list of permission flags, the additional permission checking logic will be put in a service, and the service will return an access-granted/access-denied result (just like the existing permission services). When that artifact requests permissions from the authorization manager, the authorization manager returns the normal list of permission key/value pairs plus a list of permission-checking service key/value pairs - where the key is "service" and the value is the service name. The permission service list is a set (no duplicates) and it represents an intersection - all services in the list must return an access-granted condition for access to be granted to the artifact.

When an artifact receives a list of permission services in addition to the list of permission flags, it will process the permission flags first, then the list of permission services.

A special case exists for entity lists. Sometimes it is desirable to filter a list of records based upon the user. Treating each record as an artifact and performing permission checks on them one at a time would be inefficient. We need a way to specify a filter.

The entity artifact could support permission "filters" - where a script is run to process a list of records. In those cases, the authorization manager would include the filters in the permission list - where the key is "filter" and the value is the script or service name. How the filter is implemented is outside the scope of this document.

The Authorization Manager

The Authorization Manager (AM) is a piece of software responsible for managing users and and their permissions.

The AM supports grouping users into User Groups, User Roles, and Policies. From the AM's perspective, all three group types are the same (they are just lists of users), but the different types of lists have meaning to the OFBiz administrator.

A user can be a member of a User Group, a User Role, or a Policy. In addition, the groups can be members of each other. For example, user X can be a member of User Group Y, and User Group Y can be a member of Policy Z. Users and groups can be members of more than one group.

There is no built-in significance to any group type - they are merely a convenience for the OFBiz administrator. The administrator will create Groups, Roles, and Policies appropriate for his/her organization, and then assign users as members of those groups.

The AM supports assigning artifact permissions to users, User Groups, User Roles, and Policies. Assigning artifact permissions to a user or group simply means a connection is made between the user or group and a set of artifact permissions. In other words, the user or group "points to" a set of artifact permissions.

When permissions are assigned to a group, all members of that group share those permissions. This gives the OFBiz administrator tremendous flexibility in assigning permissions. Permissions can be assigned directly to a user, or they can be assigned to a User Group - and then the user is made a member of that group.

When a user or group is a member of more than one group, the permissions from all groups are combined in a set.

Another way to view the AM user/user group design is by using properties:

Authorization Manager Artifact

Properties

User

IsUser, HasPermissions, IsMember

User Group

HasPermissions, IsMember, HasMembers

User Role

HasPermissions, IsMember, HasMembers

Policy

HasPermissions, IsMember, HasMembers

To simplify implementation, the AM could support just users and User Groups. OFBiz administrators could then implement User Roles and Policies using the User Groups.

The Authorization Manager must support the following operations:

  1. Create/delete users.
  2. Create/delete User Groups, User Roles, and Policies.
  3. Create/delete group memberships.
  4. Create/delete artifact permission assignments to users and groups.
  5. Return a list of permission flags and permission services for a given user/artifact pair.

Other operations could be included to support a security administration user interface.

The AM is a security-aware artifact. Users must have the appropriate permissions to perform any of the AM create/delete operations.

The AM's task of returning permission flags and permission services has been referred to throughout this document. Let's summarize that process from the AM's perspective.

An artifact provides a UserLogin GenericValue and an artifact identifier to the AM for a permissions request. The AM uses the UserLogin to look up the user's permissions in external storage. This would include all groups the user is a member of, and the groups that those groups are members of, etc. The AM compiles a list of the user's permissions, searches the list for the artifact's identifier, and then returns whatever permissions are found.

Although design implementation is beyond the scope of this document, for the sake of illustration let's say the AM builds an internal tree structure from all of the user's permissions. The tree structure would look just like the artifact hierarchy - but it only includes artifact identifiers the user has permissions for. Using the requesting artifact's identifier (and working from left to right), the AM "walks the tree" - looking for permission flags and permission services. While the AM walks the tree, it keeps a copy of the last permissions found. Every time new permissions are found, they replace the previous copy (that is how permission inheritance is achieved). Eventually, the AM will encounter the end of the tree or the end of the artifact identifier. When that happens, the AM returns the last permissions found.

The Super User

It is common to have a way to identify an administrator user, or super user. There are two ways that can be accomplished in this design:

  1. Have an admin permission.
  2. Have an admin User Role.

Although the term "admin" implies a user role, it would be more flexible to make it a permission. A user could be granted the admin permission to any artifact, which would make the user the admin of that artifact and all the artifacts below it. If an "Admin" User Role was desired, the admin permission could be assigned to a User Role called "Admin" - and all the members of that role would become admins.

A user could be made an admin of all of OFBiz by assigning the admin permission to the OFBiz (root) artifact for that user.

Artifacts must treat the admin permission as expected - it is the same as having all permissions. If the admin permission appears in a list of permission flags, it takes precedence - all other permission flags and permission services are ignored.

Artifact Reuse

Handling permissions with reused artifacts is greatly simplified with the Security-Aware Artifacts design. The problems associated with the existing intermediary design plus coarse-grained permissions are eliminated.

When a screen widget artifact is reused in another component, that artifact's identifier changes. For example, if I reuse the Example component's EditExample screen in my specialpurpose/NewApplication component (by including it in my own screen definition), the reused EditExample screen artifact identifier changes from OFBiz/framework/example/screen/EditExample to OFBiz/specialpurpose/NewApplication/screen/EditExample. Permissions assigned to the latter will not grant access to the former.

The form in the reused EditExample screen will generate an updateExample event which, in turn, invokes the updateExample service. I can give the users of NewApplication permission to access OFBiz/framework/example/service/updateExample without giving them access to any other Example component artifacts.

Not all artifact reuse will be this simple. But the more complicated scenarios can be accommodated by finding ways to "graft" the reused artifact into the new component's artifact hierarchy - which will provide a means to assign permissions to the reused artifact.

  • No labels