/*
* (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
*
* 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.
*
* Contributors:
* Nuxeo - initial API and implementation
*
* $Id$
*/
package org.nuxeo.ecm.core.api.security.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuxeo.ecm.core.api.security.ACE;
import org.nuxeo.ecm.core.api.security.ACL;
import org.nuxeo.ecm.core.api.security.AdministratorGroupsProvider;
import org.nuxeo.ecm.core.api.security.SecurityConstants;
import org.nuxeo.runtime.api.Framework;
import com.google.common.collect.Lists;
/**
* An ACL implementation.
*
* @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
*/
public class ACLImpl extends ArrayList<ACE>implements ACL {
private static final long serialVersionUID = 5332101749929771434L;
private static final Log log = LogFactory.getLog(ACLImpl.class);
private final String name;
private final boolean isReadOnly;
public ACLImpl(String name, boolean isReadOnly) {
this.name = name;
this.isReadOnly = isReadOnly;
}
public ACLImpl() {
this(LOCAL_ACL, false);
}
public ACLImpl(String name) {
this(name, false);
}
@Override
public String getName() {
return name;
}
@Override
public ACE[] getACEs() {
return toArray(new ACE[size()]);
}
@Override
public void setACEs(ACE[] aces) {
clear();
addAll(Arrays.asList(aces));
warnForDuplicateACEs(aces);
}
private void warnForDuplicateACEs(ACE[] aces) {
if (! log.isWarnEnabled() || ACL.INHERITED_ACL.equals(name)) {
return;
}
Set<ACE> aceSet = new HashSet<>(aces.length);
for (ACE ace : aces) {
if (!aceSet.add(ace)) {
Throwable throwable = null;
if (log.isTraceEnabled()) {
throwable = new Throwable();
}
log.warn("Setting an ACL with at least one duplicate entry: " + ace + ", ACL entries: " + Arrays.toString(aces),
throwable);
break;
}
}
}
public boolean isReadOnly() {
return isReadOnly;
}
@Override
public boolean blockInheritance(String username) {
boolean aclChanged = false;
List<ACE> aces = Lists.newArrayList(getACEs());
if (!aces.contains(ACE.BLOCK)) {
aces.add(ACE.builder(username, SecurityConstants.EVERYTHING).creator(username).build());
aces.addAll(getAdminEverythingACES());
aces.add(ACE.BLOCK);
aclChanged = true;
setACEs(aces.toArray(new ACE[aces.size()]));
}
return aclChanged;
}
@Override
public boolean unblockInheritance() {
boolean aclChanged = false;
List<ACE> aces = Lists.newArrayList(getACEs());
if (aces.contains(ACE.BLOCK)) {
aces.remove(ACE.BLOCK);
aclChanged = true;
setACEs(aces.toArray(new ACE[aces.size()]));
}
return aclChanged;
}
@Override
public boolean add(ACE ace) {
boolean aclChanged = false;
List<ACE> aces = Lists.newArrayList(getACEs());
if (!aces.contains(ace)) {
int pos = aces.indexOf(ACE.BLOCK);
if (pos >= 0) {
aces.add(pos, ace);
} else {
aces.add(ace);
}
aclChanged = true;
setACEs(aces.toArray(new ACE[aces.size()]));
}
return aclChanged;
}
protected List<ACE> getAdminEverythingACES() {
List<ACE> aces = new ArrayList<>();
AdministratorGroupsProvider provider = Framework.getLocalService(AdministratorGroupsProvider.class);
List<String> administratorsGroups = provider.getAdministratorsGroups();
for (String adminGroup : administratorsGroups) {
aces.add(new ACE(adminGroup, SecurityConstants.EVERYTHING, true));
}
return aces;
}
@Override
public boolean replace(ACE oldACE, ACE newACE) {
boolean aclChanged = false;
int index = indexOf(oldACE);
if (index != -1) {
remove(oldACE);
add(index, newACE);
aclChanged = true;
}
return aclChanged;
}
@Override
public boolean removeByUsername(String username) {
boolean aclChanged = false;
List<ACE> aces = Lists.newArrayList(getACEs());
for (Iterator<ACE> it = aces.iterator(); it.hasNext();) {
ACE ace = it.next();
if (ace.getUsername().equals(username)) {
it.remove();
aclChanged = true;
}
}
setACEs(aces.toArray(new ACE[aces.size()]));
return aclChanged;
}
@Override
public Object clone() {
ACLImpl copy = new ACLImpl(name, isReadOnly);
ACE[] aces = new ACE[size()];
for (int i = 0; i < size(); i++) {
aces[i] = (ACE) get(i).clone();
}
copy.setACEs(aces);
return copy;
}
}