From commits-return-10005-apmail-jackrabbit-commits-archive=jackrabbit.apache.org@jackrabbit.apache.org Wed Jun 02 09:01:20 2010 Return-Path: Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: (qmail 59488 invoked from network); 2 Jun 2010 09:01:20 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 2 Jun 2010 09:01:20 -0000 Received: (qmail 46451 invoked by uid 500); 2 Jun 2010 09:01:20 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 46406 invoked by uid 500); 2 Jun 2010 09:01:20 -0000 Mailing-List: contact commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list commits@jackrabbit.apache.org Received: (qmail 46399 invoked by uid 99); 2 Jun 2010 09:01:20 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 02 Jun 2010 09:01:20 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 02 Jun 2010 09:01:11 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 9F58923889EB; Wed, 2 Jun 2010 09:00:47 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r950440 [1/3] - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/ main/java/org/apache/jackrabbit/core/observation/ main/java/org/apache/jackrabbit/core/query/lucene/ main/java/org/apache/jackrabbit/core/securi... Date: Wed, 02 Jun 2010 09:00:46 -0000 To: commits@jackrabbit.apache.org From: angela@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100602090047.9F58923889EB@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: angela Date: Wed Jun 2 09:00:44 2010 New Revision: 950440 URL: http://svn.apache.org/viewvc?rev=950440&view=rev Log: JCR-2573 - Performance of AC Evaluation [work in progress] Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlListener.java (with props) jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlModifications.java (with props) jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlObserver.java (with props) jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/CachingEntryCollector.java (with props) jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollector.java (with props) jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryFilter.java (with props) jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/EntryFilterImpl.java (with props) jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/EntriesCache.java (with props) jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/acl/EntryCollectorTest.java (with props) Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/UserPerWorkspaceSecurityManager.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventConsumer.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/AccessManager.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/DefaultAccessManager.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/SimpleJBossAccessManager.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplate.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractAccessControlProvider.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractCompiledPermissions.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/CompiledPermissions.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/UnmodifiableAccessControlList.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLEditor.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedProvider.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLProvider.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLTemplate.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/GlobPattern.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/simple/SimpleAccessManager.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/simple/SimpleLoginModule.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/AccessManagerTest.java jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/acl/EntryTest.java jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/acl/TestAll.java jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authorization/combined/WriteTest.java Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java Wed Jun 2 09:00:44 2010 @@ -1757,11 +1757,11 @@ public class BatchedItemOperations exten } // copy properties for (Name propName : srcState.getPropertyNames()) { - Path propPath = PathFactoryImpl.getInstance().create(srcPath, propName, true); - if (!srcAccessMgr.canRead(propPath)) { + Path propPath = PathFactoryImpl.getInstance().create(srcPath, propName, true); + PropertyId propId = new PropertyId(srcState.getNodeId(), propName); + if (!srcAccessMgr.canRead(propPath, propId)) { continue; } - PropertyId propId = new PropertyId(srcState.getNodeId(), propName); PropertyState srcChildState = (PropertyState) srcStateMgr.getItemState(propId); Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java Wed Jun 2 09:00:44 2010 @@ -39,7 +39,7 @@ import org.apache.jackrabbit.core.id.Pro import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry; import org.apache.jackrabbit.core.nodetype.EffectiveNodeType; import org.apache.jackrabbit.core.nodetype.NodeTypeConflictException; -import org.apache.jackrabbit.core.security.AccessManager; +import org.apache.jackrabbit.core.security.authorization.Permission; import org.apache.jackrabbit.core.state.ChildNodeEntry; import org.apache.jackrabbit.core.state.ItemState; import org.apache.jackrabbit.core.state.ItemStateException; @@ -51,6 +51,7 @@ import org.apache.jackrabbit.core.state. import org.apache.jackrabbit.core.util.Dumpable; import org.apache.jackrabbit.core.version.VersionHistoryImpl; import org.apache.jackrabbit.core.version.VersionImpl; +import org.apache.jackrabbit.core.security.AccessManager; import org.apache.jackrabbit.spi.Name; import org.apache.jackrabbit.spi.Path; import org.apache.jackrabbit.spi.QPropertyDefinition; @@ -437,26 +438,48 @@ public class ItemManager implements Dump if (state == null) { throw new InvalidItemStateException(data.getId() + ": the item does not exist anymore"); } - if (state.getStatus() == ItemState.STATUS_NEW && - !data.getDefinition().isProtected()) { - // NEW items can always be read as long they have been added - // through the API and NOT by the system (i.e. protected props). - return true; + if (state.getStatus() == ItemState.STATUS_NEW) { + if (!data.getDefinition().isProtected()) { + /* + NEW items can always be read as long they have been added through + the API and NOT by the system (i.e. protected items). + */ + return true; + } else { + /* + NEW protected (system) item: + need use the path to evaluate the effective permissions. + */ + return (path == null) ? + session.getAccessManager().isGranted(data.getId(), AccessManager.READ) : + session.getAccessManager().isGranted(path, Permission.READ); + } } else { - return (path == null) ? - canRead(data.getId()) : - session.getAccessManager().canRead(path); + /* item is not NEW -> save to call acMgr.canRead(Path,ItemId) */ + return session.getAccessManager().canRead(path, data.getId()); } } /** - * @param id - * @return true if the item with the given id can be read; + * @param parent The item data of the parent node. + * @param childId + * @return true if the item with the given childId can be read; * false otherwise. * @throws RepositoryException */ - private boolean canRead(ItemId id) throws RepositoryException { - return session.getAccessManager().isGranted(id, AccessManager.READ); + private boolean canRead(ItemData parent, ItemId childId) throws RepositoryException { + if (parent.getStatus() == ItemState.STATUS_EXISTING) { + /* + child item is for sure not NEW (because then the parent was modified). + safe to use AccessManager#canRead(Path, ItemId). + */ + return session.getAccessManager().canRead(null, childId); + } else { + /* + child could be NEW -> don't use AccessManager#canRead(Path, ItemId) + */ + return session.getAccessManager().isGranted(childId, AccessManager.READ); + } } //--------------------------------------------------< item access methods > @@ -697,7 +720,7 @@ public class ItemManager implements Dump NodeState state = (NodeState) data.getState(); for (ChildNodeEntry entry : state.getChildNodeEntries()) { // make sure any of the properties can be read. - if (canRead(entry.getId())) { + if (canRead(data, entry.getId())) { return true; } } @@ -758,7 +781,7 @@ public class ItemManager implements Dump while (iter.hasNext()) { Name propName = iter.next(); // make sure any of the properties can be read. - if (canRead(new PropertyId(parentId, propName))) { + if (canRead(data, new PropertyId(parentId, propName))) { return true; } } Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java Wed Jun 2 09:00:44 2010 @@ -3026,7 +3026,7 @@ public class NodeImpl extends ItemImpl i * * @return parent id */ - NodeId getParentId() { + public NodeId getParentId() { return data.getParentId(); } Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java Wed Jun 2 09:00:44 2010 @@ -48,10 +48,10 @@ class SystemSession extends SessionImpl /** * Package private factory method * - * @param rep - * @param wspConfig - * @return - * @throws RepositoryException + * @param repositoryContext The repository context + * @param wspConfig The workspace configuration + * @return A new instance of SystemSession + * @throws RepositoryException If an error occurs */ static SystemSession create( RepositoryContext repositoryContext, WorkspaceConfig wspConfig) @@ -69,7 +69,9 @@ class SystemSession extends SessionImpl * private constructor * * @param repositoryContext repository context - * @param wspConfig + * @param subject The subject + * @param wspConfig The workspace configuration + * @throws javax.jcr.RepositoryException If an error occurs. */ private SystemSession( RepositoryContext repositoryContext, Subject subject, @@ -193,10 +195,9 @@ class SystemSession extends SessionImpl /** * Always returns true. * - * @see AccessManager#canRead(Path) - * @param itemPath + * @see AccessManager#canRead(org.apache.jackrabbit.spi.Path,org.apache.jackrabbit.core.id.ItemId) */ - public boolean canRead(Path itemPath) throws RepositoryException { + public boolean canRead(Path itemPath, ItemId itemId) throws RepositoryException { return true; } Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/UserPerWorkspaceSecurityManager.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/UserPerWorkspaceSecurityManager.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/UserPerWorkspaceSecurityManager.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/UserPerWorkspaceSecurityManager.java Wed Jun 2 09:00:44 2010 @@ -63,6 +63,7 @@ import java.util.Set; public class UserPerWorkspaceSecurityManager extends DefaultSecurityManager { private final Map ppRegistries = new HashMap(); + private final Object monitor = new Object(); /** * List of workspace names for which {@link #createSystemUsers} has already @@ -72,25 +73,27 @@ public class UserPerWorkspaceSecurityMan private PrincipalProviderRegistry getPrincipalProviderRegistry(SessionImpl s) throws RepositoryException { String wspName = s.getWorkspace().getName(); - PrincipalProviderRegistry p = ppRegistries.get(wspName); - if (p == null) { - SystemSession systemSession; - if (s instanceof SystemSession) { - systemSession = (SystemSession) s; - } else { - RepositoryImpl repo = (RepositoryImpl) getRepository(); - systemSession = repo.getSystemSession(wspName); - // TODO: review again... this workaround is used in several places. - repo.onSessionCreated(systemSession); - } + synchronized (monitor) { + PrincipalProviderRegistry p = ppRegistries.get(wspName); + if (p == null) { + SystemSession systemSession; + if (s instanceof SystemSession) { + systemSession = (SystemSession) s; + } else { + RepositoryImpl repo = (RepositoryImpl) getRepository(); + systemSession = repo.getSystemSession(wspName); + // TODO: review again... this workaround is used in several places. + repo.onSessionCreated(systemSession); + } - PrincipalProvider defaultPP = new DefaultPrincipalProvider(systemSession, (UserManagerImpl) getUserManager(systemSession)); - defaultPP.init(new Properties()); - - p = new WorkspaceBasedPrincipalProviderRegistry(defaultPP); - ppRegistries.put(wspName, p); + PrincipalProvider defaultPP = new DefaultPrincipalProvider(systemSession, (UserManagerImpl) getUserManager(systemSession)); + defaultPP.init(new Properties()); + + p = new WorkspaceBasedPrincipalProviderRegistry(defaultPP); + ppRegistries.put(wspName, p); + } + return p; } - return p; } //------------------------------------------< JackrabbitSecurityManager >--- @@ -110,7 +113,7 @@ public class UserPerWorkspaceSecurityMan @Override public void dispose(String workspaceName) { super.dispose(workspaceName); - synchronized (ppRegistries) { + synchronized (monitor) { PrincipalProviderRegistry reg = ppRegistries.remove(workspaceName); if (reg != null) { reg.getDefault().close(); @@ -124,7 +127,7 @@ public class UserPerWorkspaceSecurityMan @Override public void close() { super.close(); - synchronized (ppRegistries) { + synchronized (monitor) { for (PrincipalProviderRegistry registry : ppRegistries.values()) { registry.getDefault().close(); } Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventConsumer.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventConsumer.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventConsumer.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventConsumer.java Wed Jun 2 09:00:44 2010 @@ -301,6 +301,6 @@ class EventConsumer { */ private boolean canRead(EventState eventState) throws RepositoryException { Path targetPath = pathFactory.create(eventState.getParentPath(), eventState.getChildRelPath().getName(), eventState.getChildRelPath().getNormalizedIndex(), true); - return session.getAccessManager().canRead(targetPath); + return session.getAccessManager().canRead(targetPath, null); } } Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java Wed Jun 2 09:00:44 2010 @@ -371,8 +371,7 @@ public abstract class QueryResultImpl im throws RepositoryException { for (ScoreNode node : nodes) { try { - // TODO: rather use AccessManager.canRead(Path) - if (node != null && !accessMgr.isGranted(node.getNodeId(), AccessManager.READ)) { + if (node != null && !accessMgr.canRead(null, node.getNodeId())) { return false; } } catch (ItemNotFoundException e) { Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/AccessManager.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/AccessManager.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/AccessManager.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/AccessManager.java Wed Jun 2 09:00:44 2010 @@ -171,13 +171,24 @@ public interface AccessManager { boolean isGranted(Path parentPath, Name childName, int permissions) throws RepositoryException; /** - * Determines whether the item at the specified absolute path can be read. + * Determines whether the item with the specified itemPath + * or itemId can be read. Either of the two parameters + * may be null.
+ * Note, that this method should only be called for persisted items as NEW + * items may not be visible to the permission evaluation. + * For new items {@link #isGranted(Path, int)} should be used instead.

+ * If this method is called with both Path and ItemId it is left to the + * evaluation, which parameter is used. * - * @param itemPath Path to the item to be tested.s + * @param itemPath The path to the item or null if itemId + * should be used to determine the READ permission. + * @param itemId Id of the item to be tested or null if the + * itemPath should be used to determine the permission. * @return true if the item can be read; otherwise false. - * @throws RepositoryException if an error occurs. + * @throws RepositoryException if the item is NEW and only an itemId is + * specified or if another error occurs. */ - boolean canRead(Path itemPath) throws RepositoryException; + boolean canRead(Path itemPath, ItemId itemId) throws RepositoryException; /** * Determines whether the subject of the current context is granted access Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/DefaultAccessManager.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/DefaultAccessManager.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/DefaultAccessManager.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/DefaultAccessManager.java Wed Jun 2 09:00:44 2010 @@ -215,6 +215,7 @@ public class DefaultAccessManager extend if ((actions & REMOVE) == REMOVE) { perm |= (id.denotesNode()) ? Permission.REMOVE_NODE : Permission.REMOVE_PROPERTY; } + Path path = hierMgr.getPath(id); return isGranted(path, perm); } @@ -240,13 +241,14 @@ public class DefaultAccessManager extend } /** - * @see AccessManager#canRead(Path) + * @see AccessManager#canRead(org.apache.jackrabbit.spi.Path,org.apache.jackrabbit.core.id.ItemId) */ - public boolean canRead(Path itemPath) throws RepositoryException { + public boolean canRead(Path itemPath, ItemId itemId) throws RepositoryException { + checkInitialized(); if (compiledPermissions.canReadAll()) { return true; } else { - return isGranted(itemPath, Permission.READ); + return compiledPermissions.canRead(itemPath, itemId); } } Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/SimpleJBossAccessManager.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/SimpleJBossAccessManager.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/SimpleJBossAccessManager.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/SimpleJBossAccessManager.java Wed Jun 2 09:00:44 2010 @@ -121,7 +121,7 @@ public class SimpleJBossAccessManager im return internalIsGranted(permissions); } - public boolean canRead(Path itemPath) throws RepositoryException { + public boolean canRead(Path itemPath, ItemId itemId) throws RepositoryException { return true; } Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplate.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplate.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplate.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplate.java Wed Jun 2 09:00:44 2010 @@ -76,12 +76,9 @@ public abstract class AbstractACLTemplat * Return the list of entries, if they are held in a orderable list. * * @return the list of entries. - * @throws UnsupportedRepositoryOperationException If the implementation - * does not held the entries in a list. - * @throws RepositoryException * @see #orderBefore(AccessControlEntry, AccessControlEntry) */ - protected abstract List getEntries() throws UnsupportedRepositoryOperationException, RepositoryException; + protected abstract List getEntries(); //--------------------------------------< JackrabbitAccessControlPolicy >--- /** @@ -101,6 +98,20 @@ public abstract class AbstractACLTemplat } /** + * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#size() + */ + public int size() { + return getEntries().size(); + } + + /** + * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#isEmpty() + */ + public boolean isEmpty() { + return getEntries().isEmpty(); + } + + /** * * @param srcEntry The access control entry to be moved within the list. * @param destEntry The entry before which the srcEntry will be moved. @@ -131,6 +142,14 @@ public abstract class AbstractACLTemplat //--------------------------------------------------< AccessControlList >--- /** + * @see javax.jcr.security.AccessControlList#getAccessControlEntries() + */ + public AccessControlEntry[] getAccessControlEntries() throws RepositoryException { + List l = getEntries(); + return l.toArray(new AccessControlEntry[l.size()]); + } + + /** * @see javax.jcr.security.AccessControlList#addAccessControlEntry(java.security.Principal , javax.jcr.security.Privilege[]) */ public boolean addAccessControlEntry(Principal principal, Privilege[] privileges) Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractAccessControlProvider.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractAccessControlProvider.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractAccessControlProvider.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractAccessControlProvider.java Wed Jun 2 09:00:44 2010 @@ -25,9 +25,14 @@ import javax.jcr.Session; import javax.jcr.observation.ObservationManager; import javax.jcr.security.Privilege; +import org.apache.jackrabbit.core.ItemImpl; +import org.apache.jackrabbit.core.NodeImpl; import org.apache.jackrabbit.core.SessionImpl; +import org.apache.jackrabbit.core.id.ItemId; +import org.apache.jackrabbit.core.nodetype.NodeTypeImpl; import org.apache.jackrabbit.core.security.SystemPrincipal; import org.apache.jackrabbit.core.security.principal.AdminPrincipal; +import org.apache.jackrabbit.spi.Name; import org.apache.jackrabbit.spi.Path; import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver; @@ -35,7 +40,7 @@ import org.apache.jackrabbit.spi.commons * AbstractAccessControlProvider... */ public abstract class AbstractAccessControlProvider implements AccessControlProvider, - AccessControlUtils { + AccessControlUtils, AccessControlConstants { /** * Constant for the name of the configuration option "omit-default-permission". @@ -98,6 +103,9 @@ public abstract class AbstractAccessCont public boolean canReadAll() { return true; } + public boolean canRead(Path itemPath, ItemId itemId) throws RepositoryException { + return true; + } }; } @@ -131,11 +139,48 @@ public abstract class AbstractAccessCont public boolean canReadAll() { return false; } + public boolean canRead(Path itemPath, ItemId itemId) throws RepositoryException { + if (itemPath != null) { + return !isAcItem(itemPath); + } else { + return !isAcItem(session.getItemManager().getItem(itemId)); + } + } }; } //-------------------------------------------------< AccessControlUtils >--- /** + * @see org.apache.jackrabbit.core.security.authorization.AccessControlUtils#isAcItem(Path) + */ + public boolean isAcItem(Path absPath) throws RepositoryException { + Path.Element[] elems = absPath.getElements(); + // start looking for a rep:policy name starting from the last element. + // NOTE: with the current content structure max. 3 levels must be looked + // at as the rep:policy node may only have ACE nodes with a properties. + if (elems.length > 1) { + for (int index = elems.length-1, j = 1; index >= 0 && j <= 3; index--, j++) { + if (N_POLICY.equals(elems[index].getName())) { + return true; + } + } + } + return false; + } + + /** + * Test if the given node is itself a rep:ACL or a rep:ACE node. + * @see org.apache.jackrabbit.core.security.authorization.AccessControlUtils#isAcItem(org.apache.jackrabbit.core.ItemImpl) + */ + public boolean isAcItem(ItemImpl item) throws RepositoryException { + NodeImpl n = ((item.isNode()) ? (NodeImpl) item : (NodeImpl) item.getParent()); + Name ntName = ((NodeTypeImpl) n.getPrimaryNodeType()).getQName(); + return ntName.equals(NT_REP_ACL) || + ntName.equals(NT_REP_GRANT_ACE) || + ntName.equals(NT_REP_DENY_ACE); + } + + /** * @see AccessControlUtils#isAdminOrSystem(Set) */ public boolean isAdminOrSystem(Set principals) { Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractCompiledPermissions.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractCompiledPermissions.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractCompiledPermissions.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractCompiledPermissions.java Wed Jun 2 09:00:44 2010 @@ -16,12 +16,11 @@ */ package org.apache.jackrabbit.core.security.authorization; -import java.util.Map; - import org.apache.commons.collections.map.LRUMap; import org.apache.jackrabbit.spi.Path; import javax.jcr.RepositoryException; +import java.util.Map; /** * AbstractCompiledPermissions... @@ -30,6 +29,7 @@ public abstract class AbstractCompiledPe // cache mapping a Path to a 'Result' containing permissions and privileges. private final Map cache; + private final Object monitor = new Object(); @SuppressWarnings("unchecked") protected AbstractCompiledPermissions() { @@ -44,7 +44,7 @@ public abstract class AbstractCompiledPe */ public Result getResult(Path absPath) throws RepositoryException { Result result; - synchronized (cache) { + synchronized (monitor) { result = cache.get(absPath); if (result == null) { result = buildResult(absPath); @@ -66,7 +66,7 @@ public abstract class AbstractCompiledPe * Removes all entries from the cache. */ protected void clearCache() { - synchronized (cache) { + synchronized (monitor) { cache.clear(); } } @@ -113,20 +113,13 @@ public abstract class AbstractCompiledPe private final int allowPrivileges; private final int denyPrivileges; - private final int hashCode; + private int hashCode = -1; public Result(int allows, int denies, int allowPrivileges, int denyPrivileges) { this.allows = allows; this.denies = denies; this.allowPrivileges = allowPrivileges; this.denyPrivileges = denyPrivileges; - - int h = 17; - h = 37 * h + allows; - h = 37 * h + denies; - h = 37 * h + allowPrivileges; - h = 37 * h + denyPrivileges; - hashCode = h; } public boolean grants(int permissions) { @@ -148,13 +141,23 @@ public abstract class AbstractCompiledPe /** * @see Object#hashCode() */ + @Override public int hashCode() { + if (hashCode == -1) { + int h = 17; + h = 37 * h + allows; + h = 37 * h + denies; + h = 37 * h + allowPrivileges; + h = 37 * h + denyPrivileges; + hashCode = h; + } return hashCode; } /** * @see Object#equals(Object) */ + @Override public boolean equals(Object object) { if (object == this) { return true; Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlListener.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlListener.java?rev=950440&view=auto ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlListener.java (added) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlListener.java Wed Jun 2 09:00:44 2010 @@ -0,0 +1,30 @@ +/* + * 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; + +/** + * + */ +public interface AccessControlListener { + + /** + * Informs this listener about changes made to access control content. + * + * @param modifications Information about access control modifications. + */ + void acModified(AccessControlModifications modifications); +} Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlListener.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlListener.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlModifications.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlModifications.java?rev=950440&view=auto ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlModifications.java (added) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlModifications.java Wed Jun 2 09:00:44 2010 @@ -0,0 +1,70 @@ +/* + * 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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +/** + * AccessControlModifications is an unmodifiable collection of + * modifications made to access control content allowing the + * {@link AccessControlListener modification listeners} to keep caches up to date. + */ +public class AccessControlModifications { + + /** + * logger instance + */ + private static final Logger log = LoggerFactory.getLogger(AccessControlModifications.class); + + private final Map modificationMap; + + /** + * @param modificationMap Map specifying the access control modifications. + * The keys allows to identify the Node that was modified by + * the policy modifications. The values specifies the modification type, + * which may be any of + *

    + *
  • {@link AccessControlObserver#POLICY_ADDED}
  • + *
  • {@link AccessControlObserver#POLICY_MODIFIED}
  • + *
  • {@link AccessControlObserver#POLICY_REMOVED}
  • + *
+ */ + public AccessControlModifications(Map modificationMap) { + this.modificationMap = Collections.unmodifiableMap(modificationMap); + } + + /** + * @return Set of Node identifiers or paths. + */ + public Set getNodeIdentifiers() { + return modificationMap.keySet(); + } + + /** + * @param identifier + * @return The modification type for the specified "identifier". Note that + * the object type of the identifier is independent specific. + */ + public Integer getType(K identifier) { + return modificationMap.get(identifier); + } +} \ No newline at end of file Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlModifications.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlModifications.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlObserver.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlObserver.java?rev=950440&view=auto ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlObserver.java (added) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlObserver.java Wed Jun 2 09:00:44 2010 @@ -0,0 +1,79 @@ +/* + * 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.core.observation.SynchronousEventListener; + +import java.util.HashSet; +import java.util.Set; + +/** + * AccessControlObserver... + */ +public abstract class AccessControlObserver implements SynchronousEventListener { + + public static final int POLICY_ADDED = 1; + public static final int POLICY_REMOVED = 2; + public static final int POLICY_MODIFIED = 4; + + private final Set listeners = new HashSet(); + private final Object listenerMonitor = new Object(); + + protected void close() { + synchronized (listenerMonitor) { + listeners.clear(); + } + } + + /** + * Add a listener that needs to be informed about changes made to access + * control. + * + * @param listener EntryListener to be added. + */ + public void addListener(AccessControlListener listener) { + synchronized (listenerMonitor) { + listeners.add(listener); + } + } + + /** + * Remove a listener added before. + * + * @param listener EntryListener to be removed. + */ + public void removeListener(AccessControlListener listener) { + synchronized (listenerMonitor) { + listeners.remove(listener); + } + } + + /** + * Notifies the listeners about AC modifications. + * + * @param modifications + */ + protected void notifyListeners(AccessControlModifications modifications) { + AccessControlListener[] lstnrs; + synchronized (listenerMonitor) { + lstnrs = listeners.toArray(new AccessControlListener[listeners.size()]); + } + for (AccessControlListener lstnr : lstnrs) { + lstnr.acModified(modifications); + } + } +} \ No newline at end of file Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlObserver.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlObserver.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/CompiledPermissions.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/CompiledPermissions.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/CompiledPermissions.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/CompiledPermissions.java Wed Jun 2 09:00:44 2010 @@ -17,6 +17,7 @@ package org.apache.jackrabbit.core.security.authorization; import org.apache.jackrabbit.spi.Path; +import org.apache.jackrabbit.core.id.ItemId; import javax.jcr.RepositoryException; @@ -74,6 +75,27 @@ public interface CompiledPermissions { boolean canReadAll() throws RepositoryException; /** + * Returns true if READ permission is granted for the + * existing item with the given Path and/or + * ItemId. + * This method acts as shortcut for {@link #grants(Path, int)} where + * permissions is {@link Permission#READ} and allows to shorten the + * evaluation time given the fact that a check for READ permissions is + * considered to be the most frequent test.
+ * If both Path and ItemId are not null it is left to the + * implementation which parameter to use.n + * + * @param itemPath The path to the item or null if the ID + * should be used to determine the READ permission. + * @param itemId The itemId or null if the path should be + * used to determine the READ permission. + * @return true if the READ permission is granted. + * @throws RepositoryException If no item exists with the specified path or + * itemId or if some other error occurs. + */ + boolean canRead(Path itemPath, ItemId itemId) throws RepositoryException; + + /** * Static implementation of a CompiledPermissions that doesn't * grant any permissions at all. */ @@ -91,5 +113,8 @@ public interface CompiledPermissions { public boolean canReadAll() { return false; } + public boolean canRead(Path itemPath, ItemId itemId) throws RepositoryException { + return false; + } }; } Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/UnmodifiableAccessControlList.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/UnmodifiableAccessControlList.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/UnmodifiableAccessControlList.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/UnmodifiableAccessControlList.java Wed Jun 2 09:00:44 2010 @@ -26,6 +26,7 @@ import javax.jcr.Value; import javax.jcr.PropertyType; import java.security.Principal; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Collections; @@ -48,6 +49,8 @@ public class UnmodifiableAccessControlLi private final String path; + private int hashCode = 0; + /** * Construct a new UnmodifiableAccessControlList * @@ -78,10 +81,21 @@ public class UnmodifiableAccessControlLi * * @param accessControlEntries A list of {@link AccessControlEntry access control entries}. */ - public UnmodifiableAccessControlList(List accessControlEntries) { + public UnmodifiableAccessControlList(List accessControlEntries) { + this(accessControlEntries, null, Collections.emptyMap()); + } + + /** + * Construct a new UnmodifiableAccessControlList + * + * @param accessControlEntries + * @param path + * @param restrictions + */ + public UnmodifiableAccessControlList(List accessControlEntries, String path, Maprestrictions) { this.accessControlEntries = accessControlEntries.toArray(new AccessControlEntry[accessControlEntries.size()]); - path = null; - restrictions = Collections.emptyMap(); + this.path = path; + this.restrictions = restrictions; } //--------------------------------------------------< AccessControlList >--- @@ -110,10 +124,17 @@ public class UnmodifiableAccessControlLi throw new AccessControlException("Unmodifiable ACL. Use AccessControlManager#getApplicablePolicies in order to obtain an modifiable ACL."); } + //----------------------------------------< JackrabbitAccessControlList >--- + /** + * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#getRestrictionNames() + */ public String[] getRestrictionNames() { return restrictions.keySet().toArray(new String[restrictions.size()]); } + /** + * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#getRestrictionType(String) + */ public int getRestrictionType(String restrictionName) { if (restrictions.containsKey(restrictionName)) { return restrictions.get(restrictionName); @@ -122,27 +143,83 @@ public class UnmodifiableAccessControlLi } } + /** + * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#isEmpty() + */ public boolean isEmpty() { return accessControlEntries.length == 0; } + /** + * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#size() + */ public int size() { return accessControlEntries.length; } + /** + * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#addEntry(Principal, Privilege[], boolean) + */ public boolean addEntry(Principal principal, Privilege[] privileges, boolean isAllow) throws AccessControlException { throw new AccessControlException("Unmodifiable ACL. Use AccessControlManager#getPolicy or #getApplicablePolicies in order to obtain an modifiable ACL."); } + /** + * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#addEntry(Principal, Privilege[], boolean, Map) + */ public boolean addEntry(Principal principal, Privilege[] privileges, boolean isAllow, Map restrictions) throws AccessControlException { throw new AccessControlException("Unmodifiable ACL. Use AccessControlManager#getPolicy or #getApplicablePolicies in order to obtain an modifiable ACL."); } + /** + * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#orderBefore(AccessControlEntry, AccessControlEntry) + */ public void orderBefore(AccessControlEntry srcEntry, AccessControlEntry destEntry) throws AccessControlException { throw new AccessControlException("Unmodifiable ACL. Use AccessControlManager#getPolicy or #getApplicablePolicy in order to obtain a modifiable ACL."); } + /** + * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#getPath() + */ public String getPath() { return path; } + + //-------------------------------------------------------------< Object >--- + /** + * @see Object#hashCode() + */ + @Override + public int hashCode() { + if (hashCode == 0) { + int result = 17; + result = 37 * result + (path != null ? path.hashCode() : 0); + for (AccessControlEntry entry : accessControlEntries) { + result = 37 * result + entry.hashCode(); + } + for (String restrictionName : restrictions.keySet()) { + result = 37 * (restrictionName + "." + restrictions.get(restrictionName)).hashCode(); + } + hashCode = result; + } + return hashCode; + } + + /** + * @see Object#equals(Object) + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (obj instanceof UnmodifiableAccessControlList) { + UnmodifiableAccessControlList acl = (UnmodifiableAccessControlList) obj; + return ((path == null) ? acl.path == null : path.equals(acl.path)) && + Arrays.equals(accessControlEntries, acl.accessControlEntries) && + restrictions.equals(acl.restrictions); + } + return false; + } } \ No newline at end of file Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLEditor.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLEditor.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLEditor.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLEditor.java Wed Jun 2 09:00:44 2010 @@ -44,7 +44,6 @@ import javax.jcr.ValueFormatException; import javax.jcr.NodeIterator; import javax.jcr.security.AccessControlEntry; import javax.jcr.security.AccessControlException; -import javax.jcr.security.AccessControlList; import javax.jcr.security.AccessControlPolicy; import javax.jcr.security.Privilege; import java.security.Principal; @@ -87,7 +86,7 @@ public class ACLEditor extends Protected * @return the control list * @throws RepositoryException if an error occurs */ - AccessControlList getACL(NodeImpl aclNode) throws RepositoryException { + ACLTemplate getACL(NodeImpl aclNode) throws RepositoryException { return new ACLTemplate(aclNode, privilegeRegistry); } Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java Wed Jun 2 09:00:44 2010 @@ -16,49 +16,48 @@ */ package org.apache.jackrabbit.core.security.authorization.acl; -import java.security.Principal; -import java.security.acl.Group; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Iterator; - -import javax.jcr.ItemNotFoundException; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.observation.Event; -import javax.jcr.observation.EventIterator; -import javax.jcr.security.AccessControlEntry; -import javax.jcr.security.AccessControlList; -import javax.jcr.security.AccessControlManager; -import javax.jcr.security.AccessControlPolicy; -import javax.jcr.security.Privilege; - +import org.apache.commons.collections.map.LRUMap; import org.apache.jackrabbit.api.security.principal.PrincipalManager; import org.apache.jackrabbit.core.ItemImpl; +import org.apache.jackrabbit.core.ItemManager; import org.apache.jackrabbit.core.NodeImpl; -import org.apache.jackrabbit.core.PropertyImpl; import org.apache.jackrabbit.core.SessionImpl; +import org.apache.jackrabbit.core.id.ItemId; import org.apache.jackrabbit.core.id.NodeId; -import org.apache.jackrabbit.core.observation.SynchronousEventListener; +import org.apache.jackrabbit.core.id.PropertyId; +import org.apache.jackrabbit.core.nodetype.NodeTypeImpl; import org.apache.jackrabbit.core.security.SecurityConstants; +import org.apache.jackrabbit.core.security.authorization.AccessControlListener; import org.apache.jackrabbit.core.security.authorization.AbstractAccessControlProvider; import org.apache.jackrabbit.core.security.authorization.AbstractCompiledPermissions; import org.apache.jackrabbit.core.security.authorization.AccessControlConstants; import org.apache.jackrabbit.core.security.authorization.AccessControlEditor; +import org.apache.jackrabbit.core.security.authorization.AccessControlModifications; import org.apache.jackrabbit.core.security.authorization.CompiledPermissions; import org.apache.jackrabbit.core.security.authorization.Permission; import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry; import org.apache.jackrabbit.core.security.authorization.UnmodifiableAccessControlList; +import org.apache.jackrabbit.spi.Name; import org.apache.jackrabbit.spi.Path; -import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl; -import org.apache.jackrabbit.util.Text; -import org.apache.commons.collections.iterators.IteratorChain; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.jcr.ItemNotFoundException; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.security.AccessControlEntry; +import javax.jcr.security.AccessControlList; +import javax.jcr.security.AccessControlManager; +import javax.jcr.security.AccessControlPolicy; +import javax.jcr.security.Privilege; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + /** * The ACLProvider generates access control policies out of the items stored * in the workspace applying the following rules: @@ -97,28 +96,12 @@ public class ACLProvider extends Abstrac */ private NodeId rootNodeId; - //-------------------------------------------------< AccessControlUtils >--- /** - * @see org.apache.jackrabbit.core.security.authorization.AccessControlUtils#isAcItem(Path) + * Cache to ease the retrieval of ACEs defined for a given node. This cache + * is used by the ACLPermissions created individually for each Session + * instance. */ - public boolean isAcItem(Path absPath) throws RepositoryException { - Path.Element[] elems = absPath.getElements(); - for (Path.Element elem : elems) { - if (N_POLICY.equals(elem.getName())) { - return true; - } - } - return false; - } - - /** - * Test if the given node is itself a rep:ACL or a rep:ACE node. - * @see org.apache.jackrabbit.core.security.authorization.AccessControlUtils#isAcItem(ItemImpl) - */ - public boolean isAcItem(ItemImpl item) throws RepositoryException { - NodeImpl n = ((item.isNode()) ? (NodeImpl) item : (NodeImpl) item.getParent()); - return n.isNodeType(NT_REP_ACL) || n.isNodeType(NT_REP_ACE); - } + private EntryCollector entryCollector; //----------------------------------------------< AccessControlProvider >--- /** @@ -133,11 +116,20 @@ public class ACLProvider extends Abstrac NodeImpl root = (NodeImpl) session.getRootNode(); rootNodeId = root.getNodeId(); systemEditor = new ACLEditor(systemSession, this); + // TODO: replace by configurable default policy (see JCR-2331) boolean initializedWithDefaults = !configuration.containsKey(PARAM_OMIT_DEFAULT_PERMISSIONS); if (initializedWithDefaults && !isAccessControlled(root)) { initRootACL(session, systemEditor); } + + entryCollector = createEntryCollector((SessionImpl) systemSession); + } + + @Override + public void close() { + super.close(); + entryCollector.close(); } /** @@ -148,7 +140,7 @@ public class ACLProvider extends Abstrac checkInitialized(); NodeImpl targetNode = (NodeImpl) session.getNode(session.getJCRPath(absPath)); - NodeImpl node = getNode(targetNode); + NodeImpl node = getNode(targetNode, isAcItem(targetNode)); List acls = new ArrayList(); // collect all ACLs effective at node @@ -194,22 +186,37 @@ public class ACLProvider extends Abstrac return true; } else { CompiledPermissions cp = new AclPermissions(principals, false); - return cp.grants(PathFactoryImpl.getInstance().getRootPath(), Permission.READ); + return cp.canRead(null, rootNodeId); } } //----------------------------------------------------------< protected >--- /** + * Create the EntryCollector instance that is used by this + * provider to gather the effective ACEs for a given list of principals at a + * given node during AC evaluation. + * + * @param systemSession The system session to create the entry collector for. + * @return A new instance of CachingEntryCollector. + * @throws RepositoryException If an error occurs. + * @see #retrieveResultEntries(NodeImpl, EntryFilter) + */ + protected EntryCollector createEntryCollector(SessionImpl systemSession) throws RepositoryException { + return new CachingEntryCollector(systemSession, systemEditor, rootNodeId); + } + + /** * Retrieve an iterator of AccessControlEntry to be evaluated * upon {@link AbstractCompiledPermissions#buildResult}. * * @param node Target node. - * @param principalNames List of principal names. + * @param filter The entry filter used to collect the access control entries. * @return an iterator of AccessControlEntry. * @throws RepositoryException If an error occurs. */ - protected Iterator retrieveResultEntries(NodeImpl node, List principalNames) throws RepositoryException { - return new Entries(node, principalNames).iterator(); + protected Iterator retrieveResultEntries(NodeImpl node, EntryFilter filter) throws RepositoryException { + Iterator itr = entryCollector.collectEntries(node, filter).iterator(); + return itr; } //------------------------------------------------------------< private >--- @@ -219,13 +226,17 @@ public class ACLProvider extends Abstrac * searched and returned. * * @param targetNode The node for which AC information needs to be retrieved. - * @return the node + * @param isAcItem true if the specified target node defines access control + * content; false otherwise. + * @return the given targetNode or the nearest non-ac-parent + * in case the targetNode itself defines access control content. * @throws RepositoryException if an error occurs */ - private NodeImpl getNode(NodeImpl targetNode) throws RepositoryException { + private NodeImpl getNode(NodeImpl targetNode, boolean isAcItem) throws RepositoryException { NodeImpl node; - if (isAcItem(targetNode)) { - if (targetNode.isNodeType(NT_REP_ACL)) { + if (isAcItem) { + Name ntName = ((NodeTypeImpl) targetNode.getPrimaryNodeType()).getQName(); + if (ntName.equals(NT_REP_ACL)) { node = (NodeImpl) targetNode.getParent(); } else { node = (NodeImpl) targetNode.getParent().getParent(); @@ -248,10 +259,8 @@ public class ACLProvider extends Abstrac // if the given node is access-controlled, construct a new ACL and add // it to the list if (isAccessControlled(node)) { - // build acl for the access controlled node - NodeImpl aclNode = node.getNode(N_POLICY); - AccessControlList acl = systemEditor.getACL(aclNode); - acls.add(new UnmodifiableAccessControlList(acl)); + // retrieve the entries for the access controlled node + acls.add(new UnmodifiableAccessControlList(entryCollector.getEntries(node), node.getPath(), Collections.emptyMap())); } // then, recursively look for access controlled parents up the hierarchy. if (!rootNodeId.equals(node.getId())) { @@ -316,22 +325,24 @@ public class ACLProvider extends Abstrac * and if it has a child node named * {@link AccessControlConstants#N_POLICY "rep:ACL"}. * - * @param node hte node - * @return true if the node is access controlled; - * false otherwise. + * @param node the node to be tested + * @return true if the node is access controlled and has a + * rep:policy child; false otherwise. * @throws RepositoryException if an error occurs */ static boolean isAccessControlled(NodeImpl node) throws RepositoryException { - return node.isNodeType(NT_REP_ACCESS_CONTROLLABLE) && node.hasNode(N_POLICY); + return node.hasNode(N_POLICY) && node.isNodeType(NT_REP_ACCESS_CONTROLLABLE); } //------------------------------------------------< CompiledPermissions >--- /** * */ - private class AclPermissions extends AbstractCompiledPermissions implements SynchronousEventListener { + private class AclPermissions extends AbstractCompiledPermissions implements AccessControlListener { private final List principalNames; + private final Map readCache = new LRUMap(1000); + private final Object monitor = new Object(); private AclPermissions(Set principals) throws RepositoryException { this(principals, true); @@ -346,58 +357,17 @@ public class ACLProvider extends Abstrac if (listenToEvents) { /* Make sure this AclPermission recalculates the permissions if - any ACL concerning it is modified. interesting events are: - - new ACE-entry for any of the principals (NODE_ADDED) - - changing ACE-entry for any of the principals (PROPERTY_CHANGED) - > new permissions granted/denied - > - - removed ACE-entry for any of the principals (NODE_REMOVED) - */ - int events = Event.PROPERTY_CHANGED | Event.NODE_ADDED | Event.NODE_REMOVED; - String[] ntNames = new String[] { - resolver.getJCRName(NT_REP_ACE), - resolver.getJCRName(NT_REP_ACL) - }; - observationMgr.addEventListener(this, events, session.getRootNode().getPath(), true, null, ntNames, true); + any ACL concerning it is modified. + */ + entryCollector.addListener(this); } } - //------------------------------------< AbstractCompiledPermissions >--- - /** - * @see AbstractCompiledPermissions#buildResult(Path) - */ - @Override - protected Result buildResult(Path absPath) throws RepositoryException { - boolean existingNode = false; - NodeImpl node = null; - String jcrPath = resolver.getJCRPath(absPath); - - if (session.nodeExists(jcrPath)) { - node = (NodeImpl) session.getNode(jcrPath); - existingNode = true; - } else { - // path points to existing prop or non-existing item (node or prop). - // -> find the nearest persisted node - String parentPath = Text.getRelativeParent(jcrPath, 1); - while (parentPath.length() > 0) { - if (session.nodeExists(parentPath)) { - node = (NodeImpl) session.getNode(parentPath); - break; - } - parentPath = Text.getRelativeParent(parentPath, 1); - } - } - - if (node == null) { - // should never get here - throw new ItemNotFoundException("Item out of hierarchy."); - } - - boolean isAcItem = isAcItem(absPath); - + private Result buildResult(NodeImpl node, boolean existingNode, boolean isAcItem, EntryFilter filter) throws RepositoryException { // retrieve all ACEs at path or at the direct ancestor of path that // apply for the principal names. - Iterator entries = retrieveResultEntries(getNode(node), principalNames); + Iterator entries = retrieveResultEntries(getNode(node, isAcItem), filter); + /* Calculate privileges and permissions: Since the ACEs only define privileges on a node and do not allow @@ -421,7 +391,7 @@ public class ACLProvider extends Abstrac defined locally must be treated different than inherited entries. */ int entryBits = ace.getPrivilegeBits(); - boolean isLocal = existingNode && ace.isLocal(jcrPath); + boolean isLocal = existingNode && ace.isLocal(node.getNodeId()); if (!isLocal) { if (ace.isAllow()) { parentAllows |= Permission.diff(entryBits, parentDenies); @@ -442,163 +412,115 @@ public class ACLProvider extends Abstrac return new Result(allows, denies, allowPrivileges, denyPrivileges); } - //--------------------------------------------< CompiledPermissions >--- + //------------------------------------< AbstractCompiledPermissions >--- /** - * @see CompiledPermissions#close() + * @see AbstractCompiledPermissions#buildResult(Path) */ @Override - public void close() { + protected Result buildResult(Path absPath) throws RepositoryException { + boolean existingNode = false; + NodeImpl node; + + ItemManager itemMgr = session.getItemManager(); try { - observationMgr.removeEventListener(this); + ItemImpl item = itemMgr.getItem(absPath); + if (item.isNode()) { + node = (NodeImpl) item; + existingNode = true; + } else { + node = (NodeImpl) item.getParent(); + } } catch (RepositoryException e) { - log.debug("Unable to unregister listener: ", e.getMessage()); + // path points to a non-persisted item. + // -> find the nearest persisted node starting from the root. + Path.Element[] elems = absPath.getElements(); + NodeImpl parent = (NodeImpl) session.getRootNode(); + for (int i = 1; i < elems.length - 1; i++) { + Name name = elems[i].getName(); + int index = elems[i].getIndex(); + if (!parent.hasNode(name, index)) { + // last persisted node reached + break; + } + parent = parent.getNode(name, index); + + } + node = parent; } - super.close(); + + if (node == null) { + // should never get here + throw new ItemNotFoundException("Item out of hierarchy."); + } + + boolean isAcItem = isAcItem(absPath); + return buildResult(node, existingNode, isAcItem, new EntryFilterImpl(principalNames)); } - //--------------------------------------------------< EventListener >--- /** - * @see javax.jcr.observation.EventListener#onEvent(EventIterator) + * @see AbstractCompiledPermissions#clearCache() */ - public synchronized void onEvent(EventIterator events) { - // only invalidate cache if any of the events affects the - // nodes defining permissions for principals compiled here. - boolean clearCache = false; - while (events.hasNext() && !clearCache) { - try { - Event ev = events.nextEvent(); - String path = ev.getPath(); - switch (ev.getType()) { - case Event.NODE_ADDED: - // test if the new node is an ACE node that affects - // the permission of any of the principals listed in - // principalNames. - NodeImpl n = (NodeImpl) session.getNode(path); - if (n.isNodeType(NT_REP_ACE) && - principalNames.contains(n.getProperty(P_PRINCIPAL_NAME).getString())) { - clearCache = true; - } - break; - case Event.PROPERTY_REMOVED: - case Event.NODE_REMOVED: - // can't find out if the removed ACL/ACE node was - // relevant for the principals - clearCache = true; - break; - case Event.PROPERTY_ADDED: - case Event.PROPERTY_CHANGED: - // test if the added/changed prop belongs to an ACe - // node and affects the permission of any of the - // principals listed in principalNames. - PropertyImpl p = (PropertyImpl) session.getProperty(path); - NodeImpl parent = (NodeImpl) p.getParent(); - if (parent.isNodeType(NT_REP_ACE)) { - String principalName = null; - if (P_PRIVILEGES.equals(p.getQName())) { - // test if principal-name sibling-prop matches - principalName = parent.getProperty(P_PRINCIPAL_NAME).getString(); - } else if (P_PRINCIPAL_NAME.equals(p.getQName())) { - // a new ace or an ace change its principal-name. - principalName = p.getString(); - } - if (principalName != null && - principalNames.contains(principalName)) { - clearCache = true; - } - } - break; - case Event.NODE_MOVED: - // protected ac nodes cannot be moved around - // -> nothing to do TODO check again - break; - default: - // illegal event-type: should never occur. ignore - } - } catch (RepositoryException e) { - // should not get here - log.warn("Internal error: ", e.getMessage()); - } - } - if (clearCache) { - clearCache(); + @Override + protected void clearCache() { + synchronized (monitor) { + readCache.clear(); } + super.clearCache(); } - } - - //-------------------------------------------------------------------------- - /** - * Inner class used to collect ACEs for a given set of principals throughout - * the node hierarchy. - */ - private class Entries { - private final Collection principalNames; - private final List userAces = new ArrayList(); - private final List groupAces = new ArrayList(); - - private Entries(NodeImpl node, Collection principalNames) throws RepositoryException { - this.principalNames = principalNames; - collectEntries(node); - } - - private void collectEntries(NodeImpl node) throws RepositoryException { - // if the given node is access-controlled, construct a new ACL and add - // it to the list - if (isAccessControlled(node)) { - // build acl for the access controlled node - NodeImpl aclNode = node.getNode(N_POLICY); - //collectEntries(aclNode, principalNamesToEntries); - collectEntriesFromAcl(aclNode); - } - // recursively look for access controlled parents up the hierarchy. - if (!rootNodeId.equals(node.getId())) { - NodeImpl parentNode = (NodeImpl) node.getParent(); - collectEntries(parentNode); - } + //--------------------------------------------< CompiledPermissions >--- + /** + * @see CompiledPermissions#close() + */ + @Override + public void close() { + entryCollector.removeListener(this); + super.close(); } /** - * Separately collect the entries defined for the user and group - * principals. - * - * @param aclNode acl node - * @throws RepositoryException if an error occurs + * @see CompiledPermissions#canRead(Path, ItemId) */ - private void collectEntriesFromAcl(NodeImpl aclNode) throws RepositoryException { - // first collect aces present on the given aclNode. - List gaces = new ArrayList(); - List uaces = new ArrayList(); - - ACLTemplate tmpl = (ACLTemplate) systemEditor.getACL(aclNode); - for (AccessControlEntry ace : tmpl.getAccessControlEntries()) { - Principal principal = ace.getPrincipal(); - // only process aceNode if 'principalName' is contained in the given set - if (principalNames.contains(principal.getName())) { - // add it to the proper list (e.g. separated by principals) - /** - * NOTE: access control entries must be collected in reverse - * order in order to assert proper evaluation. - */ - if (principal instanceof Group) { - gaces.add(0, ace); - } else { - uaces.add(0, ace); - } - } + public boolean canRead(Path path, ItemId itemId) throws RepositoryException { + ItemId id = (itemId == null) ? session.getHierarchyManager().resolvePath(path) : itemId; + /* currently READ access cannot be denied to individual properties. + if the parent node is readable the properties are as well. + this simplifies the canRead test as well as the caching. + */ + boolean existingNode = false; + NodeId nodeId; + if (id.denotesNode()) { + nodeId = (NodeId) id; + // since method may only be called for existing nodes the + // flag be set to true if the id identifies a node. + existingNode = true; + } else { + nodeId = ((PropertyId) id).getParentId(); } - // add the lists of aces to the overall lists that contain the entries - // throughout the hierarchy. - if (!gaces.isEmpty()) { - groupAces.addAll(gaces); - } - if (!uaces.isEmpty()) { - userAces.addAll(uaces); + boolean canRead; + synchronized (monitor) { + if (readCache.containsKey(nodeId)) { + canRead = readCache.get(nodeId); + } else { + ItemManager itemMgr = session.getItemManager(); + NodeImpl node = (NodeImpl) itemMgr.getItem(nodeId); + Result result = buildResult(node, existingNode, isAcItem(node), new EntryFilterImpl(principalNames)); + + canRead = result.grants(Permission.READ); + readCache.put(nodeId, canRead); + } } + return canRead; } - private Iterator iterator() { - return new IteratorChain(userAces.iterator(), groupAces.iterator()); + //----------------------------------------< ACLModificationListener >--- + /** + * @see org.apache.jackrabbit.core.security.authorization.AccessControlListener#acModified(AccessControlModifications) + */ + public void acModified(AccessControlModifications modifications) { + // ignore the details of the modifications and clear all caches. + clearCache(); } } } Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java?rev=950440&r1=950439&r2=950440&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java Wed Jun 2 09:00:44 2010 @@ -36,6 +36,8 @@ import org.apache.jackrabbit.api.securit import org.apache.jackrabbit.api.security.principal.PrincipalManager; import org.apache.jackrabbit.core.NodeImpl; import org.apache.jackrabbit.core.SessionImpl; +import org.apache.jackrabbit.core.id.NodeId; +import org.apache.jackrabbit.core.nodetype.NodeTypeImpl; import org.apache.jackrabbit.core.security.authorization.AbstractACLTemplate; import org.apache.jackrabbit.core.security.authorization.AccessControlConstants; import org.apache.jackrabbit.core.security.authorization.AccessControlEntryImpl; @@ -76,6 +78,14 @@ class ACLTemplate extends AbstractACLTem private final PrivilegeRegistry privilegeRegistry; /** + * The id of the access controlled node or null if this + * ACLTemplate isn't created for an existing access controlled node. + * Used for the Entry#isLocal(NodeId) call only in order to avoid calls + * to {@link javax.jcr.Node#getPath()}. + */ + private final NodeId id; + + /** * Construct a new empty {@link ACLTemplate}. * * @param path path @@ -88,6 +98,7 @@ class ACLTemplate extends AbstractACLTem super(path, valueFactory); this.principalMgr = principalMgr; this.privilegeRegistry = privilegeRegistry; + this.id = null; } /** @@ -100,13 +111,14 @@ class ACLTemplate extends AbstractACLTem */ ACLTemplate(NodeImpl aclNode, PrivilegeRegistry privilegeRegistry) throws RepositoryException { super((aclNode != null) ? aclNode.getParent().getPath() : null, (aclNode != null) ? aclNode.getSession().getValueFactory() : null); - if (aclNode == null || !aclNode.isNodeType(AccessControlConstants.NT_REP_ACL)) { + if (aclNode == null || !AccessControlConstants.NT_REP_ACL.equals(((NodeTypeImpl)aclNode.getPrimaryNodeType()).getQName())) { throw new IllegalArgumentException("Node must be of type 'rep:ACL'"); } SessionImpl sImpl = (SessionImpl) aclNode.getSession(); principalMgr = sImpl.getPrincipalManager(); - + this.privilegeRegistry = privilegeRegistry; + this.id = aclNode.getParentId(); // load the entries: AccessControlManager acMgr = sImpl.getAccessControlManager(); @@ -130,7 +142,7 @@ class ACLTemplate extends AbstractACLTem Entry ace = createEntry( princ, privs, - aceNode.isNodeType(AccessControlConstants.NT_REP_GRANT_ACE)); + AccessControlConstants.NT_REP_GRANT_ACE.equals(((NodeTypeImpl) aceNode.getPrimaryNodeType()).getQName())); // add the entry internalAdd(ace); } catch (RepositoryException e) { @@ -141,7 +153,7 @@ class ACLTemplate extends AbstractACLTem /** * Create a new entry omitting any validation checks. - * + * * @param principal * @param privileges * @param isAllow @@ -267,14 +279,6 @@ class ACLTemplate extends AbstractACLTem //--------------------------------------------------< AccessControlList >--- /** - * @see javax.jcr.security.AccessControlList#getAccessControlEntries() - */ - public AccessControlEntry[] getAccessControlEntries() throws RepositoryException { - List l = getEntries(); - return l.toArray(new AccessControlEntry[l.size()]); - } - - /** * @see javax.jcr.security.AccessControlList#removeAccessControlEntry(AccessControlEntry) */ public synchronized void removeAccessControlEntry(AccessControlEntry ace) @@ -310,20 +314,6 @@ class ACLTemplate extends AbstractACLTem } /** - * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#isEmpty() - */ - public boolean isEmpty() { - return entries.isEmpty(); - } - - /** - * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#size() - */ - public int size() { - return getEntries().size(); - } - - /** * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#addEntry(Principal, Privilege[], boolean, Map) */ public boolean addEntry(Principal principal, Privilege[] privileges, @@ -342,6 +332,7 @@ class ACLTemplate extends AbstractACLTem * @return always zero * @see Object#hashCode() */ + @Override public int hashCode() { return 0; } @@ -353,6 +344,7 @@ class ACLTemplate extends AbstractACLTem * @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; @@ -377,12 +369,12 @@ class ACLTemplate extends AbstractACLTem } /** - * @param nodePath + * @param nodeId * @return true if this entry is defined on the node - * at nodePath + * at nodeId */ - boolean isLocal(String nodePath) { - return path != null && path.equals(nodePath); + boolean isLocal(NodeId nodeId) { + return id != null && id.equals(nodeId); } } }