[NEON] Fine grained access control [message #1750706] |
Mon, 26 December 2016 21:18 |
Marco Dörfliger Messages: 46 Registered: January 2015 |
Member |
|
|
I've recently been implementing a permission system in Neon. The BasicHierarchyPermission API has changed a bit since the Mars release, the documentation still uses the old API, and the javadoc, although helpful, is a bit thin I think. I'm posting my solution here in the hopes that a) someone closer to the 'source' can tell me if I understood it correctly, and b) to save others time in future, assuming point a) of course.
To cut a long story short, here's one permission implementation:
public class UpdateProjectPermission extends BasicHierarchyPermission {
private static final long serialVersionUID = 1L;
public static final int LEVEL_PROJECT = 10;
private long projectId;
public UpdateProjectPermission() {
super(UpdateProjectPermission.class.getSimpleName() + ".*", LEVEL_PROJECT);
}
public UpdateProjectPermission(long projectId) {
super(UpdateProjectPermission.class.getSimpleName() + "." + projectId, LEVEL_UNDEFINED);
this.projectId = projectId;
}
public long getProjectId() {
return projectId;
}
@Override
protected int execCalculateLevel(BasicHierarchyPermission other) {
int result = LEVEL_ALL;
if (other instanceof UpdateProjectPermission) {
long projectNr = ((UpdateProjectPermission) other).getProjectId();
Participation level = BEANS.get(IProjectService.class).getParticipationLevel(projectNr);
if (level != null && level.ordinal() >= Participation.MEMBER.ordinal()) {
result = LEVEL_PROJECT;
}
}
return result;
}
}
With this implementation, the following calls can be made:
- ACCESS.getLevel(new UpdateProjectPermission()) will indicate which level of access the user has with regards to all projects. If the granted permissions level is LEVEL_PROJECT, it means s/he can update projects to which he or she is a MEMBER of. And of course the defaults apply: LEVEL_ALL means all projects, and LEVEL_NONE means none.
- ACCESS.check(new UpdateProjectPermission(3)) will indicate whether the current user may update the project with id 3. It will trigger execCalculateLevel() which, after consulting the back-end service, will determine the required level the user needs to have on the global permission for access to be granted. If execCalculateLevel() returns LEVEL_PROJECT, and the user was assigned an UpdateProjectPermission level of at least LEVEL_PROJECT, the ACCESS.check() call will return true.
Notes:
- Participation is an enum with values NONE,VIEWER,MEMBER and MANAGER.
- I found that it was absolutely necessary to append ".*" to the permission name in the zero-argument constructor. Without it, project-specific permissions (i.e. those instantiated using the single-argument constructor) would not be considered as possible delegates during the background Permission.implies() operation, resulting in ACCESS.check() returning false without even consulting execCalculateLevel() on the permission.
- As documented, it is necessary to set the default permission level to LEVEL_UNKNOWN in the single-argument constructor.
- Only global (zero-arg) permissions are loaded on startup during ServerAccessControlService.execLoadPermissions(). The single-argument constructor is solely for checking against individual project IDs from within the application itself.
Does this look correct to you? Comments appreciated.
[Updated on: Tue, 27 December 2016 10:50] Report message to a moderator
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.02912 seconds