/* * 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.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.jcr.RepositoryException; import javax.jcr.Value; import javax.jcr.ValueFormatException; import javax.jcr.security.AccessControlException; import javax.jcr.security.Privilege; import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry; 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.QValueValue; import org.apache.jackrabbit.spi.commons.value.ValueFactoryQImpl; import org.apache.jackrabbit.value.ValueHelper; class AccessControlEntryImpl implements JackrabbitAccessControlEntry { /* * The principal this entry has been created for. */ private final Principal principal; /* * The privileges in this entry. */ private final Privilege[] privileges; /* * Whether this entry is allowed/denied */ private final boolean isAllow; /* * Restrictions that may apply with this entry. */ private final Map<Name, QValue> restrictions; private final Map<Name, Iterable<QValue>> mvRestrictions; private final NamePathResolver resolver; private final QValueFactory qvf; private int hashCode = -1; private int privsHashCode = -1; /** * * @param principal * @param privileges * @param isAllow * @param restrictions * @throws RepositoryException */ AccessControlEntryImpl(Principal principal, Privilege[] privileges, boolean isAllow, Map<Name, QValue> restrictions, Map<Name, Iterable<QValue>> mvRestrictions, NamePathResolver resolver, QValueFactory qvf) throws RepositoryException { if (principal == null || (privileges != null && privileges.length == 0)) { throw new AccessControlException("An Entry must not have a NULL principal or empty privileges"); } checkAbstract(privileges); this.principal = principal; this.privileges = privileges; this.isAllow = isAllow; this.resolver = resolver; this.qvf = qvf; if (restrictions == null) { this.restrictions = Collections.<Name, QValue>emptyMap(); } else { this.restrictions = restrictions; } if (mvRestrictions == null) { this.mvRestrictions = Collections.emptyMap(); } else { this.mvRestrictions = mvRestrictions; } } @Override public Principal getPrincipal() { return principal; } @Override public Privilege[] getPrivileges() { return privileges; } @Override public boolean isAllow() { return isAllow; } @Override public String[] getRestrictionNames() throws RepositoryException { List<String> restNames = new ArrayList<String>(restrictions.size()); for (Name restName : restrictions.keySet()) { restNames.add(resolver.getJCRName(restName)); } return restNames.toArray(new String[restNames.size()]); } @Override public Value getRestriction(String restrictionName) throws ValueFormatException, RepositoryException { try { Name restName = resolver.getQName(restrictionName); if (!restrictions.containsKey(restName)) { return null; } return createJcrValue(restrictions.get(restName)); } catch (IllegalStateException e) { throw new RepositoryException(e.getMessage()); } } /* * As of Jackrabbit 2.8, this extention has been added to the Jackrabbit API. * However, Jackrabbit (before) OAK doesn't support mv. restrictions. Thus simply * return an array containing the single restriction value. */ @Override public Value[] getRestrictions(String restrictionName) throws RepositoryException { return new Value[] {getRestriction(restrictionName)}; } //-------------------------------------------------------------< Object >--- @Override public int hashCode() { if (hashCode == -1) { hashCode = buildHashCode(); } return hashCode; } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof AccessControlEntryImpl) { AccessControlEntryImpl other = (AccessControlEntryImpl) obj; return principal.getName().equals(other.principal.getName()) && isAllow == other.isAllow && restrictions.equals(other.restrictions) && mvRestrictions.equals(other.mvRestrictions) && getPrivilegesHashCode() == other.getPrivilegesHashCode(); } return false; } //-------------------------------------------------------------< private >--- private int buildHashCode() { int h = 17; h = 37 * h + principal.getName().hashCode(); h = 37 * h + getPrivilegesHashCode(); h = 37 * h + Boolean.valueOf(isAllow).hashCode(); h = 37 * h + restrictions.hashCode(); h = 37 * h + mvRestrictions.hashCode(); return h; } private int getPrivilegesHashCode() { if (privsHashCode == -1) { Set<Privilege> prvs = new HashSet<Privilege>(Arrays.asList(privileges)); for (Privilege p : privileges) { if (p.isAggregate()) { prvs.addAll(Arrays.asList(p.getAggregatePrivileges())); } } privsHashCode = prvs.hashCode(); } return privsHashCode; } private void checkAbstract(Privilege[] privileges) throws AccessControlException { for (Privilege privilege : privileges) { if (privilege.isAbstract()) { throw new AccessControlException("An Entry cannot contain abstract privileges."); } } } /** * Creates a jcr Value from the given qvalue using the specified * factory. * @return the jcr value representing the qvalue. */ private Value createJcrValue(QValue qValue) throws RepositoryException { // build ValueFactory ValueFactoryQImpl valueFactory = new ValueFactoryQImpl(qvf, resolver); // build jcr value QValueValue jcrValue = new QValueValue(qValue, resolver); return ValueHelper.copy(jcrValue, valueFactory); } }