An extended Access Control system consists of:
Specifically configured custom ExtendedAccessManager
which is called by eXo
JCR internals to check if user's Session (user) has some privileges to
perform some operations or not.
The Action sets a thread local
InvocationContext
at runtime, the
InvocationContext instance is then used by the ExtendedAccessManager
in handling permissions of the current Session.
InvocationContext
is a
collection of properties which reflect the state of a current Session.
At present, 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.
SetAccessControlContextAction
implements Action and may be called by
SessionActionInterceptor
as a reaction of some events - usually before
writing methods and after reading (getNode(), getProperty()
, and more). This
SetAccessControlContextAction
calls the
AccessManager.setContext(InvocationContext context)
method which sets the
ThreadLocal invocation context for the current call.
Action's configuration may look like as 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.access.SetAccessControlContextAction</string></field>
</object>
</value>
The InvocationContext contains the
current Item, the previous Item, the current ExoContainer
and the current EventType
look like
below:
public class InvocationContext extends HashMap implements Context {
/**
* @return The related eXo container.
*/
public final ExoContainer getContainer()
/**
* @return The current item.
*/
public final Item getCurrentItem()
/**
* @return The previous item before the change.
*/
public final Item getPreviousItem()
/**
* @return The type of the event.
*/
public final int getEventType()
}
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 section. 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>
When implementing AccessManager
, the hasPermission()
method has to be
overridden so it uses the current invocation context at its discretion. For
instance, it may get the 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.
For example: The following is a simplified Sequence diagram for the Session.getNode()
method:
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, user and some
parameters of AccessManager
. To make this Access manager work, it is
necessary to configure it in the JCR configuration as mentioned in Extended Access Manager and
SetAccessControlContextAction
should be configured in the way mentioned in
Access Context Action.
public class CustomAccessManagerImpl extends AccessManager {
private String property;
private DecisionMakingService theService;
public CustomAccessManagerImpl (RepositoryEntry config, WorkspaceEntry wsConfig,
DecisionMakingService someService) throws RepositoryException, RepositoryConfigurationException {
super(config, wsConfig);
this.property = wsConfig.getAccessManager().getParameterValue("someParam");
this.theService = someService;
}
@Override
public boolean hasPermission(AccessControlList acl, String[] permission, Identity user) {
// call the default permission check
if (super.hasPermission(acl, permission, user)) {
Item curItem = context().getCurrentItem();
int eventType = context().getEventType();
ExoContainer container = context().getContainer();
// call some service's method
return theService.makeDecision(curItem, eventType, user, property);
} else {
return false;
}
}
}