/*
* Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
*
* $Id$
*/
package org.eclipse.ecr.core.security;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.ecr.core.api.security.ACP;
import org.eclipse.ecr.core.api.security.Access;
import org.eclipse.ecr.core.model.Document;
import org.eclipse.ecr.core.query.sql.model.SQLQuery;
/**
* Security policy service implementation.
* <p>
* Iterates over ordered policies. First policy to give a known access (grant
* or deny) applies.
*
* @author Anahide Tchertchian
*/
public class SecurityPolicyServiceImpl implements SecurityPolicyService {
private static final long serialVersionUID = 482814921906794786L;
private static final Log log = LogFactory.getLog(SecurityPolicyServiceImpl.class);
private final Map<String, SecurityPolicyDescriptor> policyDescriptors;
private List<SecurityPolicy> policies;
public SecurityPolicyServiceImpl() {
policyDescriptors = new Hashtable<String, SecurityPolicyDescriptor>();
}
private void computePolicies() {
policies = new ArrayList<SecurityPolicy>();
List<SecurityPolicyDescriptor> orderedDescriptors = new ArrayList<SecurityPolicyDescriptor>();
for (SecurityPolicyDescriptor descriptor : policyDescriptors.values()) {
if (descriptor.isEnabled()) {
orderedDescriptors.add(descriptor);
}
}
Collections.sort(orderedDescriptors);
List<String> policyNames = new ArrayList<String>();
for (SecurityPolicyDescriptor descriptor : orderedDescriptors) {
if (descriptor.isEnabled()) {
try {
Object policy = descriptor.getPolicy().newInstance();
if (policy instanceof SecurityPolicy) {
policies.add((SecurityPolicy) policy);
policyNames.add(descriptor.getName());
} else {
log.error(String.format(
"Invalid contribution to security policy service %s:"
+ " must implement SecurityPolicy interface",
descriptor.getName()));
}
} catch (Exception e) {
log.error(e);
}
}
}
log.debug("Ordered security policies: " + policyNames.toString());
}
private List<SecurityPolicy> getPolicies() {
if (policies == null) {
computePolicies();
}
return policies;
}
private void resetPolicies() {
policies = null;
}
@Override
public boolean arePoliciesRestrictingPermission(String permission) {
for (SecurityPolicy policy : getPolicies()) {
if (policy.isRestrictingPermission(permission)) {
return true;
}
}
return false;
}
@Override
public boolean arePoliciesExpressibleInQuery(String repositoryName) {
for (SecurityPolicy policy : getPolicies()) {
if (!policy.isExpressibleInQuery(repositoryName)) {
return false;
}
}
return true;
}
@Override
public Collection<SQLQuery.Transformer> getPoliciesQueryTransformers(
String repositoryName) {
List<SQLQuery.Transformer> transformers = new LinkedList<SQLQuery.Transformer>();
for (SecurityPolicy policy : getPolicies()) {
if (policy.isExpressibleInQuery(repositoryName)) {
transformers.add(policy.getQueryTransformer(repositoryName));
}
}
return transformers;
}
@Override
public void registerDescriptor(SecurityPolicyDescriptor descriptor) {
String id = descriptor.getName();
if (policyDescriptors.containsKey(id)) {
log.info("Overriding security policy " + id);
}
policyDescriptors.put(id, descriptor);
resetPolicies();
}
@Override
public void unregisterDescriptor(SecurityPolicyDescriptor descriptor) {
String id = descriptor.getName();
if (policyDescriptors.containsKey(id)) {
policyDescriptors.remove(id);
resetPolicies();
}
}
@Override
public Access checkPermission(Document doc, ACP mergedAcp,
Principal principal, String permission,
String[] resolvedPermissions, String[] additionalPrincipals) {
Access access = Access.UNKNOWN;
List<SecurityPolicy> policies = getPolicies();
for (SecurityPolicy policy : policies) {
Access policyAccess = policy.checkPermission(doc, mergedAcp,
principal, permission, resolvedPermissions,
additionalPrincipals);
if (policyAccess != null && !Access.UNKNOWN.equals(policyAccess)) {
access = policyAccess;
break;
}
}
return access;
}
}