org.picketlink.idm.permission.acl.spi.BaseAbstractPermissionHandler Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.picketlink.idm.permission.acl.spi;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.picketlink.idm.permission.annotations.AllowedOperation;
import org.picketlink.idm.permission.annotations.AllowedOperations;
/**
* Stored resource permissions can either be persisted as a comma-separated list of values, or as a
* bit-masked numerical value where each bit represents a specific permission for that class. This
* is a helper class that handles the conversion automatically and presents a unified API for
* dealing with these persistent actions.
*
* @author Shane Bryzak
*/
public abstract class BaseAbstractPermissionHandler implements PermissionHandler {
private Map, Boolean> usesMask = new HashMap, Boolean>();
private Map, Map> instanceOperations = new ConcurrentHashMap, Map>();
private Map, Map> classOperations = new ConcurrentHashMap, Map>();
private synchronized void initOperations(Class> cls) {
if (!instanceOperations.containsKey(cls)) {
Map instanceOps = new HashMap();
Map classOps = new HashMap();
boolean useMask = false;
AllowedOperations p = (AllowedOperations) cls.getAnnotation(AllowedOperations.class);
if (p != null) {
AllowedOperation[] operations = p.value();
if (operations != null) {
for (AllowedOperation operation : operations) {
if (operation.classOperation()) {
classOps.put(operation.value(), operation.mask());
} else {
instanceOps.put(operation.value(), operation.mask());
}
if (operation.mask() != 0) {
useMask = true;
}
}
}
}
// Validate that all actions have a proper mask
if (useMask) {
Set masks = new HashSet();
Set ops = new HashSet();
ops.addAll(instanceOps.keySet());
ops.addAll(classOps.keySet());
for (String op : ops) {
Long mask = instanceOps.containsKey(op) ? instanceOps.get(op) : classOps.get(op);
if (masks.contains(mask)) {
throw new IllegalArgumentException("Class " + cls.getName() +
" defines a duplicate mask for permission operation [" + op + "]");
}
if (mask == 0) {
throw new IllegalArgumentException("Class " + cls.getName() +
" must define a valid mask value for operation [" + op + "]");
}
if ((mask & (mask - 1)) != 0) {
throw new IllegalArgumentException("Class " + cls.getName() +
" must define a mask value that is a power of 2 for operation [" + op + "]");
}
masks.add(mask);
}
}
usesMask.put(cls, useMask);
instanceOperations.put(cls, instanceOps);
}
}
protected class PermissionSet {
private Set permissions = new HashSet();
private Class> resourceClass;
public PermissionSet(Class> resourceClass, String members) {
this.resourceClass = resourceClass;
addMembers(members);
}
public void addMembers(String members) {
if (members == null) {
return;
}
if (usesMask.get(resourceClass)) {
// bit mask-based actions
long vals = Long.valueOf(members);
Map permissions = instanceOperations.get(resourceClass);
for (String permission : permissions.keySet()) {
long mask = permissions.get(permission).longValue();
if ((vals & mask) != 0) {
this.permissions.add(permission);
}
}
}
else {
// comma-separated string based actions
String[] permissions = members.split(",");
for (String permission : permissions) {
this.permissions.add(permission);
}
}
}
public boolean contains(String action) {
return permissions.contains(action);
}
public PermissionSet add(String action) {
permissions.add(action);
return this;
}
public PermissionSet remove(String action) {
permissions.remove(action);
return this;
}
public Set getPermissions() {
return permissions;
}
public boolean isEmpty() {
return permissions.isEmpty();
}
@Override
public String toString() {
if (usesMask.get(resourceClass)) {
Map actions = instanceOperations.get(resourceClass);
long mask = 0;
for (String member : permissions) {
mask |= actions.get(member).longValue();
}
return "" + mask;
} else {
StringBuilder sb = new StringBuilder();
for (String member : permissions) {
if (sb.length() > 0) {
sb.append(',');
}
sb.append(member);
}
return sb.toString();
}
}
}
public PermissionSet createPermissionSet(Class> resourceClass, String members) {
if (!instanceOperations.containsKey(resourceClass)) {
initOperations(resourceClass);
}
return new PermissionSet(resourceClass, members);
}
@Override
public Set listClassOperations(Class> resourceClass) {
if (!classOperations.containsKey(resourceClass)) {
initOperations(resourceClass);
}
Set permissions = new HashSet();
for (String permission : classOperations.get(resourceClass).keySet()) {
permissions.add(permission);
}
return permissions;
}
@Override
public Set listInstanceOperations(Class> resourceClass) {
if (!instanceOperations.containsKey(resourceClass)) {
initOperations(resourceClass);
}
Set permissions = new HashSet();
for (String permission : instanceOperations.get(resourceClass).keySet()) {
permissions.add(permission);
}
return permissions;
}
}