/* * 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.core.security.authorization; import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry; import org.apache.jackrabbit.spi.Name; import org.apache.jackrabbit.spi.commons.conversion.NameResolver; import org.apache.jackrabbit.value.ValueHelper; import javax.jcr.NamespaceException; import javax.jcr.RepositoryException; import javax.jcr.UnsupportedRepositoryOperationException; import javax.jcr.Value; import javax.jcr.ValueFactory; import javax.jcr.security.AccessControlException; import javax.jcr.security.Privilege; import java.security.Principal; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * Simple, immutable implementation of the * {@link javax.jcr.security.AccessControlEntry} * and the {@link JackrabbitAccessControlEntry} interfaces. */ public abstract class AccessControlEntryImpl implements JackrabbitAccessControlEntry { /** * All privileges contained in this entry. */ private Privilege[] privileges; /** * PrivilegeBits calculated from built-in privileges */ private final PrivilegeBits privilegeBits; /** * the Principal of this entry */ private final Principal principal; /** * Jackrabbit specific extension: if the actions contained are allowed or * denied. */ private final boolean allow; /** * Jackrabbit specific extension: the list of additional restrictions to be * included in the evaluation. */ private final Map<Name, Value> restrictions; /** * Hash code being calculated on demand. */ private int hashCode = -1; /** * Construct an access control entry for the given principal and privileges. * * @param principal Principal for this access control entry. * @param privileges Privileges for this access control entry. * @param isAllow <code>true</code> if this ACE grants the specified * privileges to the specified principal; <code>false</code> otherwise. * @param restrictions A map of restriction name (String) to restriction * (Value). See {@link org.apache.jackrabbit.api.security.JackrabbitAccessControlList#getRestrictionNames()} * and {@link org.apache.jackrabbit.api.security.JackrabbitAccessControlList#getRestrictionType(String)}. * @throws AccessControlException if either principal or privileges are invalid. * @throws RepositoryException if another error occurs. */ protected AccessControlEntryImpl(Principal principal, Privilege[] privileges, boolean isAllow, Map<String, Value> restrictions) throws AccessControlException, RepositoryException { if (principal == null || privileges == null) { throw new AccessControlException(); } // make sure no abstract privileges are passed. for (Privilege privilege : privileges) { if (privilege.isAbstract()) { throw new AccessControlException("Privilege " + privilege + " is abstract."); } } this.principal = principal; this.privileges = privileges; this.privilegeBits = getPrivilegeManager().getBits(privileges).unmodifiable(); this.allow = isAllow; if (restrictions == null) { this.restrictions = Collections.emptyMap(); } else { this.restrictions = new HashMap<Name, Value>(restrictions.size()); // validate the passed restrictions and fill the map for (String name : restrictions.keySet()) { Value value = ValueHelper.copy(restrictions.get(name), getValueFactory()); this.restrictions.put(getResolver().getQName(name), value); } } } /** * Construct an access control entry for the given principal and privileges. * * @param principal Principal for this access control entry. * @param privilegesBits Privileges for this access control entry. * @param isAllow <code>true</code> if this ACE grants the specified * privileges to the specified principal; <code>false</code> otherwise. * @param restrictions A map of restriction name (String) to restriction * (Value). See {@link org.apache.jackrabbit.api.security.JackrabbitAccessControlList#getRestrictionNames()} * and {@link org.apache.jackrabbit.api.security.JackrabbitAccessControlList#getRestrictionType(String)}. * @throws RepositoryException if another error occurs. */ protected AccessControlEntryImpl(Principal principal, PrivilegeBits privilegesBits, boolean isAllow, Map<String, Value> restrictions) throws RepositoryException { if (principal == null || privilegesBits == null) { throw new IllegalArgumentException(); } this.principal = principal; this.privilegeBits = privilegesBits.unmodifiable(); this.allow = isAllow; if (restrictions == null) { this.restrictions = Collections.emptyMap(); } else { this.restrictions = new HashMap<Name, Value>(restrictions.size()); // validate the passed restrictions and fill the map for (String name : restrictions.keySet()) { Value value = ValueHelper.copy(restrictions.get(name), getValueFactory()); this.restrictions.put(getResolver().getQName(name), value); } } } /** * * @param base * @param privilegeBits * @param isAllow * @throws AccessControlException */ protected AccessControlEntryImpl(AccessControlEntryImpl base, PrivilegeBits privilegeBits, boolean isAllow) throws AccessControlException, RepositoryException { this(base.principal, privilegeBits, isAllow, (base.restrictions.isEmpty()) ? null : Collections.<String, Value>emptyMap()); if (!base.restrictions.isEmpty()) { // validate the passed restrictions and fill the map for (Name name : base.restrictions.keySet()) { Value value = ValueHelper.copy(base.restrictions.get(name), getValueFactory()); this.restrictions.put(name, value); } } } /** * * @param base * @param privileges * @param isAllow * @throws AccessControlException */ protected AccessControlEntryImpl(AccessControlEntryImpl base, Privilege[] privileges, boolean isAllow) throws AccessControlException, RepositoryException { this(base.principal, privileges, isAllow, (base.restrictions.isEmpty()) ? null : Collections.<String, Value>emptyMap()); if (!base.restrictions.isEmpty()) { // validate the passed restrictions and fill the map for (Name name : base.restrictions.keySet()) { Value value = ValueHelper.copy(base.restrictions.get(name), getValueFactory()); this.restrictions.put(name, value); } } } /** * @return the permission bits that correspond to the privileges defined by this entry. */ public PrivilegeBits getPrivilegeBits() { return privilegeBits; } /** * Returns <code>true</code> if this ACE defines any restriction. * * @return <code>true</code> if this ACE defines any restriction; * <code>false</code> otherwise. */ public boolean hasRestrictions() { return !restrictions.isEmpty(); } /** * Returns the restrictions defined for this entry. * * @return the restrictions defined for this entry. */ public Map<Name,Value> getRestrictions() { return Collections.unmodifiableMap(restrictions); } /** * @param restrictionName * @return The restriction with the specified name or <code>null</code>. */ public Value getRestriction(Name restrictionName) { return ValueHelper.copy(restrictions.get(restrictionName), getValueFactory()); } /** * @return Returns the name resolver used to convert JCR names to Name and vice versa. */ protected abstract NameResolver getResolver(); /** * @return The value factory to be used. */ protected abstract ValueFactory getValueFactory(); /** * @return The privilege manager in use. */ protected abstract PrivilegeManagerImpl getPrivilegeManager(); /** * Build the hash code. * * @return the hash code. */ protected int buildHashCode() { int h = 17; h = 37 * h + principal.getName().hashCode(); h = 37 * h + privilegeBits.hashCode(); h = 37 * h + Boolean.valueOf(allow).hashCode(); h = 37 * h + restrictions.hashCode(); return h; } //-------------------------------------------------< AccessControlEntry >--- /** * @see javax.jcr.security.AccessControlEntry#getPrincipal() */ public Principal getPrincipal() { return principal; } /** * @see javax.jcr.security.AccessControlEntry#getPrivileges() */ public Privilege[] getPrivileges() { if (privileges == null) { Set<Privilege> ps = getPrivilegeManager().getPrivileges(privilegeBits); privileges = ps.toArray(new Privilege[ps.size()]); } return privileges; } //---------------------------------------< JackrabbitAccessControlEntry >--- /** * @see JackrabbitAccessControlEntry#isAllow() */ public boolean isAllow() { return allow; } /** * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry#getRestrictionNames() */ public String[] getRestrictionNames() throws NamespaceException { String[] restrNames = new String[restrictions.size()]; int i = 0; for (Name n : restrictions.keySet()) { restrNames[i] = getResolver().getJCRName(n); i++; } return restrNames; } /** * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry#getRestriction(String) */ public Value getRestriction(String restrictionName) throws RepositoryException { return getRestriction(getResolver().getQName(restrictionName)); } /** * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry#getRestrictions(String) */ public Value[] getRestrictions(String restrictionName) throws RepositoryException { return new Value[] {getRestriction(restrictionName)}; } //-------------------------------------------------------------< Object >--- /** * @see Object#hashCode() */ @Override public int hashCode() { if (hashCode == -1) { hashCode = buildHashCode(); } return hashCode; } /** * @see Object#equals(Object) */ @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()) && privilegeBits.equals(other.privilegeBits) && allow == other.allow && restrictions.equals(other.restrictions); } return false; } }