Skip to main content

Branch Permission Manager

The Branch Permission Manager is a service which keeps track of branch permissions:

  • Branches creation can be allowed for only a specific set of users.
  • Read and Edit permissions can be managed for each branch and user.
  • This applies to both MDX queries (read permissions) and Datastore REST API calls (create/read/write).

Branch permissions model

Only a specific set of user is allowed to create a branch, they are called branch creators.

Each branch has a set of owners and readers.

Owners can read and edit the content of a branch, update the permissions of the branch or even delete the branch. Readers can only read the content of a branch. To indicate that all the users are allowed in a specific role (reader, owner or creator), the constant IBranchPermissions.ALL_USERS_ALLOWED can be used. In the Datastore REST API the string __ALL_USERS__ can be used. This string is a reserved keyword and can therefore not be used for other purposes.

Additional default permissions must be defined when creating a Branch Permissions Manager. These defaults are used as a fallback when querying a branch that exists in the datastore, but which was not registered in the Branch Permissions Manager. This could happen if the branch is not created through the datastore service. These defaults are useful to not be stuck with a branch without permissions, but are not optimal as they are not branch specific. It is therefore highly recommended to only create branches through the datastore service, providing branch permissions at creation time.

Interaction with Datastore REST API

Each query sent to the Datastore REST API interacts with the Branch Permission Manager to determine the permissions of the current user.

Having the read permissions on the branch does not mean the user can read everything on said branch: it is still intersected with the stores and fields permissions. To read the data a user needs both the branch permission and the field permissions. The same thing happens for the write permissions: a user needs both to be owner of the branch and have the write permissions on the field to update anything.

Only branch creators are allowed to create a new branch. The creator can specify who are the owners and the readers of the new branch. If no permissions are specified, the current user roles and username will be set as both owner and reader.

Interaction with MDX queries

Each MDX query is filtered by the Branch Permission Manager to only allow content that is visible by the current user. This means that only the branches where the user has read permissions can be queried.

In the case of real time, if a query is registered on several branches, it is updated for each new branch created.

Configuration

Both cube configuration and database configuration require an IActivePivotBranchPermissionsManagerConfig. This configuration provides an IBranchPermissionsManager, which is required to create the Active Pivot Manager and build the Datastore.

The sandbox provides an example, where the branch permissions are retrieved from the Content Service (but with a cache that allows not to query the Content Service for every query). This is an example of how to build the service. It overrides the default permissions defined in the builder to benefit from the content service / cache behavior without allowing full access to all branches:

/**
* Sandbox configuration class creating the manager of branch permissions.
*
* @author ActiveViam
*/
@Configuration
@RequiredArgsConstructor
public class ActivePivotBranchPermissionsManagerConfig
implements IActivePivotBranchPermissionsManagerConfig {
private final IContentServiceConfig contentServiceConfig;
@Bean
@Override
public IBranchPermissionsManager branchPermissionsManager() {
final CachedBranchPermissionsManager manager =
new CachedBranchPermissionsManager(
ContentServiceBranchPermissionsManagerBuilder.create()
.contentService(this.contentServiceConfig.contentService())
.allowedBranchCreators(Set.of(ROLE_ADMIN, ROLE_USER))
.defaultBranchOwners(Set.of(ROLE_ADMIN))
.build());
manager.setBranchPermissions(
IEpoch.MASTER_BRANCH_NAME,
new BranchPermissions(
Collections.singleton(ROLE_ADMIN), IBranchPermissions.ALL_USERS_ALLOWED));
return manager;
}
}

BranchPermissionsManager is a simpler example that does not rely on any storage (permissions for each branch stored in a map). It is mostly used for tests when we don't want to build a full content service, and is as simple to use as:

final IBranchPermissionsManager bmp =
new BranchPermissionsManager(
Set.of(ROLE_ADMIN, ROLE_USER), // Branch creators
Set.of(ROLE_ADMIN), // Default branch owners
IBranchPermissions.ALL_USERS_ALLOWED); // Default branch readers
// The BranchPermissionsManager has a default security for the master branch (all users can read
// and edit),
// but it is highly recommended to redefine it :
bmp.setBranchPermissions(
IEpoch.MASTER_BRANCH_NAME,
new BranchPermissions(Set.of(ROLE_ADMIN), Collections.singleton(ROLE_USER)));