Access Control Extension
1 Prerequisites
This is an extension of eXo JCR Access Control features. Please read
Access Control and
JCR Extensions topics before.
2 Overview
An extended Access Control system consists of:
- Specifically configured custom Extended Access Manager which is called by eXo JCR internals to check if some user's Session (user) has some privilege to perform some operation
- The Action which sets the thread local Invocation Context at runtime. This invocation context is used by the Extended Access Manager to make a decision about the current Session's permission
- Invocation Context is a collection of properties which reflect the state of a current Session. For the time being it contains: the type of the current operation on Session (event), current Item (javax.jcr.Item) on which this operation is performed and the current eXo Container
3 Access Context Action
SetAccessContextAction implements Action and may be called by
SessionActionInterceptor as a reaction of some event - usually before writing methods and after reading (
getNode(), getProperty() etc).
This
SetAccessContextAction calls the
AccessManager.setContext(InvocationContext context) method which sets the
ThreadLocal invocation context for the current call.
Action's Configuration may look like the following:
<value>
<object type="org.exoplatform.services.jcr.impl.ext.action.ActionConfiguration">
<field name="eventTypes"><string>addNode,read</string></field>
<field name="workspace"><string>production</string></field >
<field name="actionClassName"><string>org.exoplatform.services.jcr.ext.SetAccessContextAction</string></field>
</object>
</value>
4 The Invocation Context
The
InvocationContext contains the current Item, the current ExoContainer and the current EventType like below:
public interface InvocationContext extends ContextBase {
Item getCurrentItem();
int getEventType();
ExoContainer getContainer();
}
5 Custom Extended Access Manager
By default all Workspaces share an AccessManager instance, created by RepositoryService at the startup (
DefaultAccessManagerImpl) which supports default access control policy as described in the
Access Control chapter. Custom Access Control policy can be applied to certain Workspace configuring
access-manager element inside
workspace as follows:
<workspace name="ws">
...
<!-- after query-handler element -->
<access-manager class="org.exoplatform.services.jcr.CustomAccessManagerImpl">
<properties>
<property name="someProperty" value="value"/>
...
</properties>
</access-manager>
...
</workspace>
For each interested AccessManager implementation overwrite the
hasPermission() method so it will use the current invocation context at its discretion. For instance, it may get some current node's metadata and make a decision if the current User has appropriate permissions. Use Invocation Context's runtime properties to make a decision about current Session's privileges (see the Example below)
Simplified Sequence diagram for the Session.getNode() method (as an Example):
6 Example of a custom Access Manager
The sample CustomAccessManagerImpl below extends the default access manager and uses some DecisionMakingService in the overloaded hasPermission method to find out if a current user has permission to use current
item, event type, userID and some parameter of AccessManager. To make this Access manager work it is necessary to configure it in jcr configuration as mentioned in
Custom Extended Access Manager as well as SetAccessContextAction should be configured in the way mentioned in
Access Context Actio
public class CustomAccessManagerImpl extends AccessManager {
private String property;
private DecisionMakingService theService;
public CustomAccessManagerImpl (RepositoryEntry config, WorkspaceEntry wsConfig,
OrganizationService orgService, DecisionMakingService someService) throws RepositoryException {
super(config, wsConfig, orgService);
this.property = wsConfig.getAccessManager().getParameterValue("someParam");
this.theService = someService;
}
@Override
public boolean hasPermission(AccessControlList acl, String[] permission, String userId) {
// call the default permission check
if (super.hasPermission(acl, permission, userId)) {
Item curItem = context().getCurrentItem();
int eventType = context().getEventType();
ExoContainer container = context().getContainer();
// call some service's method
return theService.makeDecision(curItem, eventType, userId, property);
} else {
return false;
}
}
}