/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.jackrabbit.jcr2spi.security.authorization.jackrabbit.acl; import java.security.Principal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.jcr.NamespaceException; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.UnsupportedRepositoryOperationException; import javax.jcr.Value; import javax.jcr.security.AccessControlEntry; import javax.jcr.security.AccessControlException; import javax.jcr.security.AccessControlManager; import javax.jcr.security.Privilege; import org.apache.jackrabbit.api.security.JackrabbitAccessControlList; import org.apache.jackrabbit.jcr2spi.hierarchy.NodeEntry; import org.apache.jackrabbit.jcr2spi.security.authorization.jackrabbit.AccessControlConstants; import org.apache.jackrabbit.jcr2spi.state.NodeState; import org.apache.jackrabbit.jcr2spi.state.PropertyState; import org.apache.jackrabbit.spi.Name; import org.apache.jackrabbit.spi.QValue; import org.apache.jackrabbit.spi.QValueFactory; import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver; import org.apache.jackrabbit.spi.commons.value.ValueFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; class AccessControlListImpl implements JackrabbitAccessControlList, AccessControlConstants { private static final Logger log = LoggerFactory.getLogger(AccessControlListImpl.class); private final String jcrPath; private final List<AccessControlEntry> entries; private final QValueFactory qValueFactory; private final NamePathResolver resolver; /** * Namespace sensitive name of the REP_GLOB property in standard JCR form. */ private final String jcrRepGlob; public AccessControlListImpl(String jcrPath, NamePathResolver resolver, QValueFactory qValueFactory) throws RepositoryException { this.jcrPath = jcrPath; this.entries = new ArrayList<AccessControlEntry>(); this.qValueFactory = qValueFactory; this.resolver = resolver; try { jcrRepGlob = resolver.getJCRName(P_GLOB); } catch (NamespaceException e) { throw new RepositoryException(e.getMessage()); } } AccessControlListImpl(NodeState aclNode, String aclPath, NamePathResolver resolver, QValueFactory factory, AccessControlManager acm) throws RepositoryException { this(aclPath, resolver, factory); NodeEntry entry = (NodeEntry) aclNode.getHierarchyEntry(); Iterator<NodeEntry> it = entry.getNodeEntries(); while(it.hasNext()) { NodeState aceNode = it.next().getNodeState(); try { PropertyState ps = aceNode.getPropertyState(N_REP_PRINCIPAL_NAME); // rep:principal property String principalName = ps.getValue().getString(); Principal principal = createPrincipal(principalName); // rep:privileges property ps = aceNode.getPropertyState(N_REP_PRIVILEGES); QValue[] values = ps.getValues(); Privilege[] privileges = new Privilege[values.length]; for (int i = 0; i < values.length; i++) { privileges[i] = acm.privilegeFromName(values[i].getString()); } // rep:glob property -> restrictions Map<Name, QValue> restrictions = null; if (aceNode.hasPropertyName(P_GLOB)) { ps = aceNode.getPropertyState(P_GLOB); restrictions = Collections.singletonMap(ps.getName(), ps.getValue()); } // the isAllow flag boolean isAllow = NT_REP_GRANT_ACE.equals(aceNode.getNodeTypeName()); // build the entry AccessControlEntry ace = new AccessControlEntryImpl(principal, privileges, isAllow, restrictions, Collections.EMPTY_MAP, resolver, qValueFactory); entries.add(ace); } catch (RepositoryException e) { log.debug("Fail to create Entry for "+ aceNode.getName().toString()); } } } //--------------------------------------------------< AccessControlList >--- @Override public AccessControlEntry[] getAccessControlEntries() throws RepositoryException { return entries.toArray(new AccessControlEntry[entries.size()]); } @Override public boolean addAccessControlEntry(Principal principal, Privilege[] privileges) throws AccessControlException, RepositoryException { return addEntry(principal, privileges, true, Collections.<String, Value>emptyMap()); } @Override public void removeAccessControlEntry(AccessControlEntry ace) throws AccessControlException, RepositoryException { if (entries.contains(ace)) { entries.remove(ace); } else { throw new AccessControlException("Entry not present in this list"); } } //----------------------------------------< JackrabbitAccessControlList >--- @Override public String getPath() { return jcrPath; } @Override public boolean isEmpty() { return entries.isEmpty(); } @Override public int size() { return entries.size(); } @Override public boolean addEntry(Principal principal, Privilege[] privileges, boolean isAllow) throws AccessControlException, RepositoryException { return addEntry(principal, privileges, isAllow, Collections.<String, Value>emptyMap()); } @Override public boolean addEntry(Principal principal, Privilege[] privileges, boolean isAllow, Map<String, Value> restrictions, Map<String, Value[]> mvRestrictions) throws AccessControlException, RepositoryException { // create entry to be added Map<Name, QValue> rs = createRestrictions(restrictions); Map<Name, Iterable<QValue>> mvRs = createMvRestrictions(mvRestrictions); AccessControlEntry entry = createEntry(principal, privileges, isAllow, rs, mvRs); return entries.add(entry); } @Override public boolean addEntry(Principal principal, Privilege[] privileges, boolean isAllow, Map<String, Value> restrictions) throws AccessControlException, RepositoryException { return addEntry(principal, privileges, isAllow, restrictions, Collections.EMPTY_MAP); } @Override public String[] getRestrictionNames() throws RepositoryException { return new String[] {jcrRepGlob}; } @Override public int getRestrictionType(String restrictionName) throws RepositoryException { if (!jcrRepGlob.equals(restrictionName)) { // JR2 feature return PropertyType.UNDEFINED; } return PropertyType.STRING; } @Override public void orderBefore(AccessControlEntry srcEntry, AccessControlEntry destEntry) throws AccessControlException, UnsupportedRepositoryOperationException, RepositoryException { // TODO throw new UnsupportedRepositoryOperationException("not yet implemented"); } //-------------------------------------------------------------< Object >--- /** * Returns zero to satisfy the Object equals/hashCode contract. * This class is mutable and not meant to be used as a hash key. * * @return always zero * @see Object#hashCode() */ @Override public int hashCode() { return 0; } /** * Returns true if the path and the entries are equal; false otherwise. * * @param obj Object to be tested. * @return true if the path and the entries are equal; false otherwise. * @see Object#equals(Object) */ @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof AccessControlListImpl) { AccessControlListImpl acl = (AccessControlListImpl) obj; return jcrPath.equals(acl.jcrPath) && entries.equals(acl.entries); } return false; } //------------------------------------------------------------< private >--- private AccessControlEntry createEntry(Principal principal, Privilege[] privileges, boolean isAllow, Map<Name, QValue> restrictions, Map<Name, Iterable<QValue>> mvRestrictions) throws RepositoryException { return new AccessControlEntryImpl(principal, privileges, isAllow, restrictions, mvRestrictions, resolver, qValueFactory); } private Map<Name, QValue> createRestrictions(Map<String, Value> restrictions) throws RepositoryException { Map<Name, QValue> rs = new HashMap<Name, QValue>(restrictions.size()); for (String restName : restrictions.keySet()) { Value v = restrictions.get(restName); rs.put(resolver.getQName(restName), ValueFormat.getQValue(v, resolver, qValueFactory)); } return rs; } private Map<Name, Iterable<QValue>> createMvRestrictions(Map<String, Value[]> restrictions) throws RepositoryException { Map<Name, Iterable<QValue>> rs = new HashMap<Name, Iterable<QValue>>(restrictions.size()); for (String restName : restrictions.keySet()) { QValue[] qvs = ValueFormat.getQValues(restrictions.get(restName), resolver, qValueFactory); rs.put(resolver.getQName(restName), Arrays.asList(qvs)); } return rs; } private static Principal createPrincipal(final String name) { return new Principal() { @Override public String getName() { return name; } }; } }