package com.plexobject.rbac.security;
import java.util.Arrays;
import java.util.Collection;
import org.apache.commons.validator.GenericValidator;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.plexobject.rbac.Configuration;
import com.plexobject.rbac.domain.Permission;
import com.plexobject.rbac.domain.Role;
import com.plexobject.rbac.domain.SecurityError;
import com.plexobject.rbac.eval.PredicateEvaluator;
import com.plexobject.rbac.repository.RepositoryFactory;
import com.sun.jersey.spi.inject.Inject;
@Component("permissionManager")
public class PermissionManagerImpl implements InitializingBean,
PermissionManager {
enum EvaluationResult {
NONE, SUCCEEDED, FAILED
}
private static final Logger LOGGER = Logger
.getLogger(PermissionManagerImpl.class);
private static final boolean STORE_ERRORS_IN_DB = Configuration
.getInstance().getBoolean("store_errors_in_db", true);
@Autowired
@Inject
private RepositoryFactory repositoryFactory;
@Autowired
@Inject
private PredicateEvaluator evaluator;
PermissionManagerImpl() {
}
public PermissionManagerImpl(final RepositoryFactory repositoryFactory,
final PredicateEvaluator evaluator) {
if (repositoryFactory == null) {
throw new NullPointerException("null repositoryFactory");
}
if (evaluator == null) {
throw new NullPointerException("null evaluator");
}
this.repositoryFactory = repositoryFactory;
this.evaluator = evaluator;
}
/*
* (non-Javadoc)
*
* @see
* com.plexobject.rbac.security.PermissionManager#check(com.plexobject.rbac
* .security.PermissionRequest)
*/
public void check(PermissionRequest request) throws SecurityException {
Collection<Role> roles = null;
// by default subject gets anonymous role
if (GenericValidator.isBlankOrNull(request.getSubjectName())) {
roles = Arrays.asList(Role.ANONYMOUS);
} else {
roles = repositoryFactory.getRoleRepository(request.getDomain())
.getRolesForSubject(request.getSubjectName());
}
Collection<Permission> all = repositoryFactory.getPermissionRepository(
request.getDomain()).getPermissionsForRoles(roles);
boolean granted = false;
EvaluationResult evaluationResult = null;
Permission failedPermission = null;
for (Permission permission : all) {
if (permission.implies(request.getOperation(), request.getTarget())) {
if (GenericValidator.isBlankOrNull(permission.getExpression())) {
granted = true;
evaluationResult = EvaluationResult.NONE;
break;
} else {
if (evaluator.evaluate(permission.getExpression(), request
.getSubjectContext())) {
granted = true;
evaluationResult = EvaluationResult.SUCCEEDED;
break;
} else {
evaluationResult = EvaluationResult.FAILED;
failedPermission = permission;
}
}
}
}
if (granted) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(request.getSubjectName() + " granted access "
+ request.getOperation() + " for "
+ request.getTarget() + " using "
+ request.getSubjectContext() + ", permissions " + all);
}
return;
}
// access denied
try {
if (STORE_ERRORS_IN_DB) {
repositoryFactory.getSecurityErrorRepository(
request.getDomain()).save(
new SecurityError(request.getSubjectName(), request
.getOperation(), request.getTarget(), request
.getSubjectContext()));
} else {
LOGGER.warn("Permission failed for " + request);
}
} catch (Exception e) {
LOGGER.error("Failed to save securit error for subjectName "
+ request, e);
}
throw new SecurityException(request.getSubjectName()
+ " illegally accessing '" + request.getOperation() + "' on '"
+ request.getTarget() + "' evaluation result '"
+ evaluationResult + "', context "
+ request.getSubjectContext() + ", failed permission "
+ failedPermission + ", all permissions " + all);
}
public RepositoryFactory getRepositoryFactory() {
return repositoryFactory;
}
public void setRepositoryFactory(RepositoryFactory repositoryFactory) {
this.repositoryFactory = repositoryFactory;
}
public PredicateEvaluator getEvaluator() {
return evaluator;
}
public void setEvaluator(PredicateEvaluator evaluator) {
this.evaluator = evaluator;
}
@Override
public void afterPropertiesSet() throws Exception {
if (repositoryFactory == null) {
throw new IllegalStateException("repositoryFactory not set");
}
if (evaluator == null) {
throw new IllegalStateException("evaluator not set");
}
}
}