You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ak...@apache.org on 2005/10/08 09:07:58 UTC

svn commit: r307270 - in /directory/apacheds/trunk/core/src: main/java/org/apache/ldap/server/ main/java/org/apache/ldap/server/authz/ main/java/org/apache/ldap/server/exception/ test/org/apache/ldap/server/authz/

Author: akarasulu
Date: Sat Oct  8 00:07:47 2005
New Revision: 307270

URL: http://svn.apache.org/viewcvs?rev=307270&view=rev
Log:
changes ...

 o added a bunch of test cases for the ADD operation using different userClasses
 o added new rename methods for the Tuple and GroupCache to support modifyRn and
   move operations within the server
 o implemented interceptor methods for delete, compare, modify, modifyRn, & move
 o added better error reporting on LdapNameAlreadyBoundException
 o made sure the right normalized name for the Administrators group is used


Modified:
    directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/DefaultDirectoryService.java
    directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/authz/AuthorizationService.java
    directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/authz/GroupCache.java
    directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/authz/TupleCache.java
    directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/exception/ExceptionService.java
    directory/apacheds/trunk/core/src/test/org/apache/ldap/server/authz/AuthorizationServiceAsNonAdminTest.java

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/DefaultDirectoryService.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/DefaultDirectoryService.java?rev=307270&r1=307269&r2=307270&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/DefaultDirectoryService.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/DefaultDirectoryService.java Sat Oct  8 00:07:47 2005
@@ -460,7 +460,7 @@
         // -------------------------------------------------------------------
 
         String upName = "cn=Administrators,ou=groups,ou=system";
-        Name normName = new LdapName( upName );
+        Name normName = new LdapName( "cn=administrators,ou=groups,ou=system" );
         if ( !partitionNexus.hasEntry( normName ) )
         {
             firstStart = true;

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/authz/AuthorizationService.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/authz/AuthorizationService.java?rev=307270&r1=307269&r2=307270&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/authz/AuthorizationService.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/authz/AuthorizationService.java Sat Oct  8 00:07:47 2005
@@ -35,6 +35,7 @@
 import org.apache.ldap.common.aci.ACIItem;
 import org.apache.ldap.common.exception.LdapNamingException;
 import org.apache.ldap.common.message.ResultCodeEnum;
+import org.apache.ldap.common.util.NamespaceTools;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,10 +43,7 @@
 import javax.naming.Name;
 import javax.naming.NamingException;
 import javax.naming.NamingEnumeration;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.ModificationItem;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.Attribute;
+import javax.naming.directory.*;
 import java.util.*;
 import java.text.ParseException;
 
@@ -65,54 +63,6 @@
     private static final String SUBENTRYACI_ATTR = "subentryACI";
     private static final String AC_SUBENTRY_ATTR = "accessControlSubentries";
 
-    /** collection of MicroOperations for the add operation */
-    private static final Collection ADD_OPS;
-    /** collection of MicroOperations for the delete operation */
-    private static final Collection DELETE_OPS;
-    /** collection of MicroOperations for the compare operation */
-    private static final Collection COMPARE_OPS;
-    /** collection of MicroOperations for the search operation */
-    private static final Collection SEARCH_OPS;
-    /** collection of MicroOperations for the modify operation */
-    private static final Collection MODIFY_OPS;
-    /** collection of MicroOperations for the modifyRdn operation */
-    private static final Collection MODIFYRDN_OPS;
-    /** collection of MicroOperations for the browsing */
-    private static final Collection BROWSE_OPS;
-
-    static
-    {
-        Set ops = new HashSet();
-        ops.add( MicroOperation.ADD );
-        ADD_OPS = Collections.unmodifiableCollection( ops );
-
-        ops = new HashSet();
-        ops.add( MicroOperation.REMOVE );
-        DELETE_OPS = Collections.unmodifiableCollection( ops );
-
-        ops = new HashSet();
-        ops.add( MicroOperation.COMPARE );
-        COMPARE_OPS = Collections.unmodifiableCollection( ops );
-
-        ops = new HashSet();
-        ops.add( MicroOperation.RETURN_DN );
-        ops.add( MicroOperation.FILTER_MATCH );
-        ops.add( MicroOperation.READ );
-        SEARCH_OPS = Collections.unmodifiableCollection( ops );
-
-        ops = new HashSet();
-        ops.add( MicroOperation.MODIFY );
-        MODIFY_OPS = Collections.unmodifiableCollection( ops );
-
-        ops = new HashSet();
-        ops.add( MicroOperation.RENAME );
-        MODIFYRDN_OPS = Collections.unmodifiableCollection( ops );
-
-        ops = new HashSet();
-        ops.add( MicroOperation.BROWSE );
-        BROWSE_OPS = Collections.unmodifiableCollection( ops );
-    }
-
     /** the partition nexus */
     private DirectoryPartitionNexus nexus;
     /** a tupleCache that responds to add, delete, and modify attempts */
@@ -318,8 +268,19 @@
         // note that entryACI should not be considered in adds (it's a security breach)
         addPerscriptiveAciTuples( tuples, normName, subentryAttrs );
         addSubentryAciTuples( tuples, normName, subentryAttrs );
+        Collection perms = Collections.singleton( MicroOperation.ADD );
         engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(), normName, null,
-            null, ADD_OPS, tuples, subentryAttrs );
+            null, perms, tuples, subentryAttrs );
+        NamingEnumeration attributeList = entry.getAll();
+        while ( attributeList.hasMore() )
+        {
+            Attribute attr = ( Attribute ) attributeList.next();
+            for ( int ii = 0; ii < attr.size(); ii++ )
+            {
+                engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(), normName,
+                        attr.getID(), attr.get( ii ), perms, tuples, entry );
+            }
+        }
 
         // if we've gotten this far then access is granted
         next.add( upName, normName, entry );
@@ -330,17 +291,25 @@
 
     public void delete( NextInterceptor next, Name name ) throws NamingException
     {
+        // Access the principal requesting the operation, and bypass checks if it is the admin
         Attributes entry = nexus.lookup( name );
-//        ServerContext ctx = ( ServerContext ) InvocationStack.getInstance().peek().getCaller();
-//        LdapPrincipal user = ctx.getPrincipal();
-//        Set userGroups = groupCache.getGroups( user.getName() );
-//        Collection tuples = new HashSet();
-//        addPerscriptiveAciTuples( tuples, entry );
-//        addEntryAciTuples( tuples, entry );
-//        addSubentryAciTuples( tuples, entry );
-//
-//        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, null,
-//                null, DELETE_OPS, tuples );
+        LdapPrincipal user = ( ( ServerContext ) InvocationStack.getInstance().peek().getCaller() ).getPrincipal();
+        if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) || ! enabled )
+        {
+            next.delete( name );
+            tupleCache.subentryDeleted( name, entry );
+            groupCache.groupDeleted( name, entry );
+            return;
+        }
+
+        Set userGroups = groupCache.getGroups( user.getName() );
+        Collection tuples = new HashSet();
+        addPerscriptiveAciTuples( tuples, name, entry );
+        addEntryAciTuples( tuples, entry );
+        addSubentryAciTuples( tuples, name, entry );
+
+        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, null,
+                null, Collections.singleton( MicroOperation.REMOVE ), tuples, entry );
 
         next.delete( name );
         tupleCache.subentryDeleted( name, entry );
@@ -350,17 +319,52 @@
 
     public void modify( NextInterceptor next, Name name, int modOp, Attributes mods ) throws NamingException
     {
+        // Access the principal requesting the operation, and bypass checks if it is the admin
         Attributes entry = nexus.lookup( name );
-//        ServerContext ctx = ( ServerContext ) InvocationStack.getInstance().peek().getCaller();
-//        LdapPrincipal user = ctx.getPrincipal();
-//        Set userGroups = groupCache.getGroups( user.getName() );
-//        Collection tuples = new HashSet();
-//        addPerscriptiveAciTuples( tuples, entry );
-//        addEntryAciTuples( tuples, entry );
-//        addSubentryAciTuples( tuples, entry );
-//
-//        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, null,
-//                null, MODIFY_OPS, tuples );
+        LdapPrincipal user = ( ( ServerContext ) InvocationStack.getInstance().peek().getCaller() ).getPrincipal();
+        if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) || ! enabled )
+        {
+            next.modify( name, modOp, mods );
+            tupleCache.subentryModified( name, modOp, mods, entry );
+            groupCache.groupModified( name, modOp, mods, entry );
+            return;
+        }
+
+        Set userGroups = groupCache.getGroups( user.getName() );
+        Collection tuples = new HashSet();
+        addPerscriptiveAciTuples( tuples, name, entry );
+        addEntryAciTuples( tuples, entry );
+        addSubentryAciTuples( tuples, name, entry );
+
+        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, null,
+                null, Collections.singleton( MicroOperation.MODIFY ), tuples, entry );
+
+        NamingEnumeration attrList = mods.getAll();
+        Collection perms = null;
+        switch( modOp )
+        {
+            case( DirContext.ADD_ATTRIBUTE ):
+                perms = Collections.singleton( MicroOperation.ADD );
+                break;
+            case( DirContext.REMOVE_ATTRIBUTE ):
+                perms = Collections.singleton( MicroOperation.REMOVE );
+                break;
+            case( DirContext.REPLACE_ATTRIBUTE ):
+                perms = new HashSet();
+                perms.add( MicroOperation.ADD );
+                perms.add( MicroOperation.REMOVE );
+                break;
+        }
+
+        while( attrList.hasMore() )
+        {
+            Attribute attr = ( Attribute ) attrList.next();
+            for ( int ii = 0; ii < attr.size(); ii++ )
+            {
+                engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(),
+                        name, attr.getID(), attr.get( ii ), perms, tuples, entry );
+            }
+        }
 
         next.modify( name, modOp, mods );
         tupleCache.subentryModified( name, modOp, mods, entry );
@@ -370,39 +374,59 @@
 
     public void modify( NextInterceptor next, Name name, ModificationItem[] mods ) throws NamingException
     {
+        // Access the principal requesting the operation, and bypass checks if it is the admin
         Attributes entry = nexus.lookup( name );
-//        ServerContext ctx = ( ServerContext ) InvocationStack.getInstance().peek().getCaller();
-//        LdapPrincipal user = ctx.getPrincipal();
-//        Set userGroups = groupCache.getGroups( user.getName() );
-//        Collection tuples = new HashSet();
-//        addPerscriptiveAciTuples( tuples, entry );
-//        addEntryAciTuples( tuples, entry );
-//        addSubentryAciTuples( tuples, entry );
-//
-//        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, null,
-//                null, MODIFY_OPS, tuples );
+        LdapPrincipal user = ( ( ServerContext ) InvocationStack.getInstance().peek().getCaller() ).getPrincipal();
+        if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) || ! enabled )
+        {
+            next.modify( name, mods );
+            tupleCache.subentryModified( name, mods, entry );
+            groupCache.groupModified( name, mods, entry );
+            return;
+        }
 
-        next.modify( name, mods );
-        tupleCache.subentryModified( name, mods, entry );
-        groupCache.groupModified( name, mods, entry );
-    }
+        Set userGroups = groupCache.getGroups( user.getName() );
+        Collection tuples = new HashSet();
+        addPerscriptiveAciTuples( tuples, name, entry );
+        addEntryAciTuples( tuples, entry );
+        addSubentryAciTuples( tuples, name, entry );
+
+        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, null,
+                null, Collections.singleton( MicroOperation.MODIFY ), tuples, entry );
+
+        Collection perms = null;
+        Collection remove = Collections.singleton( MicroOperation.REMOVE );
+        Collection add = Collections.singleton( MicroOperation.ADD );
+        Collection replace = new HashSet();
+        replace.add( MicroOperation.ADD );
+        replace.add( MicroOperation.REMOVE );
 
+        for ( int ii = 0; ii < mods.length; ii++ )
+        {
+            switch( mods[ii].getModificationOp() )
+            {
+                case( DirContext.ADD_ATTRIBUTE ):
+                    perms = add;
+                    break;
+                case( DirContext.REMOVE_ATTRIBUTE ):
+                    perms = remove;
+                    break;
+                case( DirContext.REPLACE_ATTRIBUTE ):
+                    perms = replace;
+                    break;
+            }
 
-    public Attributes getRootDSE( NextInterceptor next ) throws NamingException
-    {
-        Attributes entry = super.getRootDSE( next );
-//        ServerContext ctx = ( ServerContext ) InvocationStack.getInstance().peek().getCaller();
-//        LdapPrincipal user = ctx.getPrincipal();
-//        Set userGroups = groupCache.getGroups( user.getName() );
-//        Collection tuples = new HashSet();
-//        addPerscriptiveAciTuples( tuples, entry );
-//        addEntryAciTuples( tuples, entry );
-//        addSubentryAciTuples( tuples, entry );
-//
-//        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(),
-//                new LdapName(), null, null, SEARCH_OPS, tuples );
+            Attribute attr = mods[ii].getAttribute();
+            for ( int jj = 0; jj < attr.size(); jj++ )
+            {
+                engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(),
+                        name, attr.getID(), attr.get( jj ), perms, tuples, entry );
+            }
+        }
 
-        return entry;
+        next.modify( name, mods );
+        tupleCache.subentryModified( name, mods, entry );
+        groupCache.groupModified( name, mods, entry );
     }
 
 
@@ -462,56 +486,164 @@
 
     public void modifyRn( NextInterceptor next, Name name, String newRn, boolean deleteOldRn ) throws NamingException
     {
-//        Attributes entry = nexus.lookup( name );
-//        ServerContext ctx = ( ServerContext ) InvocationStack.getInstance().peek().getCaller();
-//        LdapPrincipal user = ctx.getPrincipal();
-//        Set userGroups = groupCache.getGroups( user.getName() );
-//        Collection tuples = new HashSet();
-//        addPerscriptiveAciTuples( tuples, entry );
-//        addEntryAciTuples( tuples, entry );
-//        addSubentryAciTuples( tuples, entry );
-//
-//        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, null,
-//                null, MODIFYRDN_OPS, tuples );
+        // Access the principal requesting the operation, and bypass checks if it is the admin
+        Attributes entry = nexus.lookup( name );
+        LdapPrincipal user = ( ( ServerContext ) InvocationStack.getInstance().peek().getCaller() ).getPrincipal();
+        Name newName = ( Name ) name.clone();
+        newName.remove( name.size() - 1 );
+        newName.add( newRn );
+        if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) || ! enabled )
+        {
+            next.modifyRn( name, newRn, deleteOldRn );
+            tupleCache.subentryRenamed( name, newName );
+            groupCache.groupRenamed( name, newName );
+            return;
+        }
 
-        super.modifyRn( next, name, newRn, deleteOldRn );
+        Set userGroups = groupCache.getGroups( user.getName() );
+        Collection tuples = new HashSet();
+        addPerscriptiveAciTuples( tuples, name, entry );
+        addEntryAciTuples( tuples, entry );
+        addSubentryAciTuples( tuples, name, entry );
+
+        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, null,
+                null, Collections.singleton( MicroOperation.RENAME ), tuples, entry );
+
+        if ( deleteOldRn )
+        {
+            String oldRn = name.get( name.size() - 1 );
+            if ( NamespaceTools.hasCompositeComponents( oldRn ) )
+            {
+                String[] comps = NamespaceTools.getCompositeComponents( oldRn );
+                for ( int ii = 0; ii < comps.length; ii++ )
+                {
+                    String id = NamespaceTools.getRdnAttribute( comps[ii] );
+                    String value = NamespaceTools.getRdnValue( comps[ii] );
+                    engine.checkPermission( next, userGroups, user.getJndiName(),
+                            user.getAuthenticationLevel(), name, id,
+                            value, Collections.singleton( MicroOperation.REMOVE ),
+                            tuples, entry );
+                }
+            }
+            else
+            {
+                String id = NamespaceTools.getRdnAttribute( oldRn );
+                String value = NamespaceTools.getRdnValue( oldRn );
+                engine.checkPermission( next, userGroups, user.getJndiName(),
+                        user.getAuthenticationLevel(), name, id,
+                        value, Collections.singleton( MicroOperation.REMOVE ),
+                        tuples, entry );
+            }
+        }
+
+        next.modifyRn( name, newRn, deleteOldRn );
+        tupleCache.subentryRenamed( name, newName );
+        groupCache.groupRenamed( name, newName );
     }
 
 
     public void move( NextInterceptor next, Name oriChildName, Name newParentName, String newRn, boolean deleteOldRn )
             throws NamingException
     {
-//        Attributes entry = nexus.lookup( oriChildName );
-//        ServerContext ctx = ( ServerContext ) InvocationStack.getInstance().peek().getCaller();
-//        LdapPrincipal user = ctx.getPrincipal();
-//        Set userGroups = groupCache.getGroups( user.getName() );
-//        Collection tuples = new HashSet();
-//        addPerscriptiveAciTuples( tuples, entry );
-//        addEntryAciTuples( tuples, entry );
-//        addSubentryAciTuples( tuples, entry );
-//
-//        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(), oriChildName, null,
-//                null, MODIFYRDN_OPS, tuples );
+        // Access the principal requesting the operation, and bypass checks if it is the admin
+        Attributes entry = nexus.lookup( oriChildName );
+        LdapPrincipal user = ( ( ServerContext ) InvocationStack.getInstance().peek().getCaller() ).getPrincipal();
+        Name newName = ( Name ) newParentName.clone();
+        newName.add( newRn );
+        if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) || ! enabled )
+        {
+            next.move( oriChildName, newParentName, newRn, deleteOldRn );
+            tupleCache.subentryRenamed( oriChildName, newName );
+            groupCache.groupRenamed( oriChildName, newName );
+            return;
+        }
+
+        Set userGroups = groupCache.getGroups( user.getName() );
+        Collection tuples = new HashSet();
+        addPerscriptiveAciTuples( tuples, oriChildName, entry );
+        addEntryAciTuples( tuples, entry );
+        addSubentryAciTuples( tuples, oriChildName, entry );
+
+        Collection perms = new HashSet();
+        perms.add( MicroOperation.RENAME );
+        perms.add( MicroOperation.EXPORT );
+        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(),
+                oriChildName, null, null, perms, tuples, entry );
+
+        Collection destTuples = new HashSet();
+        addPerscriptiveAciTuples( destTuples, oriChildName, entry );
+        addEntryAciTuples( destTuples, entry );
+        addSubentryAciTuples( destTuples, oriChildName, entry );
+        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(),
+                oriChildName, null, null, Collections.singleton( MicroOperation.IMPORT ), tuples, entry );
 
-        super.move( next, oriChildName, newParentName, newRn, deleteOldRn );
+        if ( deleteOldRn )
+        {
+            String oldRn = oriChildName.get( oriChildName.size() - 1 );
+            if ( NamespaceTools.hasCompositeComponents( oldRn ) )
+            {
+                String[] comps = NamespaceTools.getCompositeComponents( oldRn );
+                for ( int ii = 0; ii < comps.length; ii++ )
+                {
+                    String id = NamespaceTools.getRdnAttribute( comps[ii] );
+                    String value = NamespaceTools.getRdnValue( comps[ii] );
+                    engine.checkPermission( next, userGroups, user.getJndiName(),
+                            user.getAuthenticationLevel(), oriChildName, id,
+                            value, Collections.singleton( MicroOperation.REMOVE ),
+                            tuples, entry );
+                }
+            }
+            else
+            {
+                String id = NamespaceTools.getRdnAttribute( oldRn );
+                String value = NamespaceTools.getRdnValue( oldRn );
+                engine.checkPermission( next, userGroups, user.getJndiName(),
+                        user.getAuthenticationLevel(), oriChildName, id,
+                        value, Collections.singleton( MicroOperation.REMOVE ),
+                        tuples, entry );
+            }
+        }
+
+        next.move( oriChildName, newParentName, newRn, deleteOldRn );
+        tupleCache.subentryRenamed( oriChildName, newName );
+        groupCache.groupRenamed( oriChildName, newName );
     }
 
 
     public void move( NextInterceptor next, Name oriChildName, Name newParentName ) throws NamingException
     {
-//        Attributes entry = nexus.lookup( oriChildName );
-//        ServerContext ctx = ( ServerContext ) InvocationStack.getInstance().peek().getCaller();
-//        LdapPrincipal user = ctx.getPrincipal();
-//        Set userGroups = groupCache.getGroups( user.getName() );
-//        Collection tuples = new HashSet();
-//        addPerscriptiveAciTuples( tuples, entry );
-//        addEntryAciTuples( tuples, entry );
-//        addSubentryAciTuples( tuples, entry );
-//
-//        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(), oriChildName, null,
-//                null, MODIFYRDN_OPS, tuples );
-//
-        super.move( next, oriChildName, newParentName );
+        // Access the principal requesting the operation, and bypass checks if it is the admin
+        Attributes entry = nexus.lookup( oriChildName );
+        LdapPrincipal user = ( ( ServerContext ) InvocationStack.getInstance().peek().getCaller() ).getPrincipal();
+        Name newName = ( Name ) newParentName.clone();
+        newName.add( oriChildName.get( oriChildName.size() - 1 ) );
+        if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) || ! enabled )
+        {
+            next.move( oriChildName, newParentName );
+            tupleCache.subentryRenamed( oriChildName, newName );
+            groupCache.groupRenamed( oriChildName, newName );
+            return;
+        }
+
+        Set userGroups = groupCache.getGroups( user.getName() );
+        Collection tuples = new HashSet();
+        addPerscriptiveAciTuples( tuples, oriChildName, entry );
+        addEntryAciTuples( tuples, entry );
+        addSubentryAciTuples( tuples, oriChildName, entry );
+
+        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(),
+                oriChildName, null, null, Collections.singleton( MicroOperation.EXPORT ), tuples, entry );
+
+        Collection destTuples = new HashSet();
+        addPerscriptiveAciTuples( destTuples, oriChildName, entry );
+        addEntryAciTuples( destTuples, entry );
+        addSubentryAciTuples( destTuples, oriChildName, entry );
+        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(),
+                oriChildName, null, null, Collections.singleton( MicroOperation.IMPORT ), tuples, entry );
+
+        next.move( oriChildName, newParentName );
+        tupleCache.subentryRenamed( oriChildName, newName );
+        groupCache.groupRenamed( oriChildName, newName );
     }
 
 
@@ -536,19 +668,27 @@
 
     public boolean compare( NextInterceptor next, Name name, String oid, Object value ) throws NamingException
     {
-//        Attributes entry = nexus.lookup( name );
-//        ServerContext ctx = ( ServerContext ) InvocationStack.getInstance().peek().getCaller();
-//        LdapPrincipal user = ctx.getPrincipal();
-//        Set userGroups = groupCache.getGroups( user.getName() );
-//        Collection tuples = new HashSet();
-//        addPerscriptiveAciTuples( tuples, entry );
-//        addEntryAciTuples( tuples, entry );
-//        addSubentryAciTuples( tuples, entry );
-//
-//        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, null,
-//                null, COMPARE_OPS, tuples );
 
-        return super.compare(next, name, oid, value);
+        // Access the principal requesting the operation, and bypass checks if it is the admin
+        Attributes entry = nexus.lookup( name );
+        LdapPrincipal user = ( ( ServerContext ) InvocationStack.getInstance().peek().getCaller() ).getPrincipal();
+        if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) || ! enabled )
+        {
+            return next.compare( name, oid, value );
+        }
+
+        Set userGroups = groupCache.getGroups( user.getName() );
+        Collection tuples = new HashSet();
+        addPerscriptiveAciTuples( tuples, name, entry );
+        addEntryAciTuples( tuples, entry );
+        addSubentryAciTuples( tuples, name, entry );
+
+        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, null,
+                null, Collections.singleton( MicroOperation.READ ), tuples, entry );
+        engine.checkPermission( next, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, oid,
+                value, Collections.singleton( MicroOperation.COMPARE ), tuples, entry );
+
+        return next.compare( name, oid, value );
     }
 
 

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/authz/GroupCache.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/authz/GroupCache.java?rev=307270&r1=307269&r2=307270&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/authz/GroupCache.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/authz/GroupCache.java Sat Oct  8 00:07:47 2005
@@ -371,4 +371,10 @@
 
         return memberGroups;
     }
+
+
+    public void groupRenamed( Name oldName, Name newName )
+    {
+        groups.put( newName.toString(), groups.remove( oldName.toString() ) );
+    }
 }

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/authz/TupleCache.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/authz/TupleCache.java?rev=307270&r1=307269&r2=307270&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/authz/TupleCache.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/authz/TupleCache.java Sat Oct  8 00:07:47 2005
@@ -226,4 +226,10 @@
         }
         return Collections.unmodifiableList( aciTuples );
     }
+
+
+    public void subentryRenamed( Name oldName, Name newName )
+    {
+        tuples.put( newName.toString(), tuples.remove( oldName.toString() ) );
+    }
 }

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/exception/ExceptionService.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/exception/ExceptionService.java?rev=307270&r1=307269&r2=307270&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/exception/ExceptionService.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/exception/ExceptionService.java Sat Oct  8 00:07:47 2005
@@ -77,7 +77,7 @@
         // check if the entry already exists
         if ( nextInterceptor.hasEntry( normName ) )
         {
-            NamingException ne = new LdapNameAlreadyBoundException();
+            NamingException ne = new LdapNameAlreadyBoundException( normName.toString() + " already exists!" );
             ne.setResolvedName( new LdapName( upName ) );
             throw ne;
         }

Modified: directory/apacheds/trunk/core/src/test/org/apache/ldap/server/authz/AuthorizationServiceAsNonAdminTest.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/trunk/core/src/test/org/apache/ldap/server/authz/AuthorizationServiceAsNonAdminTest.java?rev=307270&r1=307269&r2=307270&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/test/org/apache/ldap/server/authz/AuthorizationServiceAsNonAdminTest.java (original)
+++ directory/apacheds/trunk/core/src/test/org/apache/ldap/server/authz/AuthorizationServiceAsNonAdminTest.java Sat Oct  8 00:07:47 2005
@@ -22,10 +22,12 @@
 
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
+import javax.naming.Name;
 import javax.naming.directory.*;
 
 import org.apache.ldap.common.exception.LdapNoPermissionException;
 import org.apache.ldap.common.message.LockableAttributesImpl;
+import org.apache.ldap.common.name.LdapName;
 import org.apache.ldap.server.AbstractNonAdminTestCase;
 import org.apache.ldap.server.subtree.SubentryService;
 
@@ -176,7 +178,7 @@
                 "itemOrUserFirst userFirst: { " +
                 "userClasses { allUsers }, " +
                 "userPermissions { { " +
-                "protectedItems {entry}, " +
+                "protectedItems {entry, allUserAttributeTypesAndValues}, " +
                 "grantsAndDenials { grantAdd } } } } }" );
         adminCtx.createSubcontext( "cn=anybodyAdd", subentry );
 
@@ -187,5 +189,203 @@
         objectClass.add( "top" );
         objectClass.add( "organizationalUnit" );
         sysRoot.createSubcontext( "ou=testou", testEntry );
+    }
+
+
+    public Name createTestUser( String uid ) throws NamingException
+    {
+        DirContext adminCtx = getAdminContext();
+
+        Attributes testUser = new BasicAttributes( "uid", uid, true );
+        testUser.put( "userPassword", uid );
+        Attribute objectClass = new BasicAttribute( "objectClass" );
+        testUser.put( objectClass );
+        objectClass.add( "top" );
+        objectClass.add( "person" );
+        objectClass.add( "organizationalPerson" );
+        objectClass.add( "inetOrgPerson" );
+
+        adminCtx.createSubcontext( "uid="+uid+",ou=users", testUser );
+        return new LdapName( "uid="+uid+",ou=users,ou=system" );
+    }
+
+
+    public void addUserToGroup( String userUid, String groupCn ) throws NamingException
+    {
+        DirContext adminCtx = getAdminContext();
+        Attributes changes = new BasicAttributes( "uniqueMember", "uid="+userUid+",ou=users,ou=system", true );
+        adminCtx.modifyAttributes( "cn="+groupCn+",ou=groups", DirContext.ADD_ATTRIBUTE, changes );
+    }
+
+
+    public DirContext getUserContext( Name user, String password ) throws NamingException
+    {
+        Hashtable env = ( Hashtable ) ( ( Hashtable ) sysRoot.getEnvironment() ).clone();
+        env.put( DirContext.PROVIDER_URL, "ou=system" );
+        env.put( DirContext.SECURITY_AUTHENTICATION, "simple" );
+        env.put( DirContext.SECURITY_PRINCIPAL, user.toString() );
+        env.put( DirContext.SECURITY_CREDENTIALS, password );
+        return new InitialDirContext( env );
+    }
+
+
+    public void testGrantAddAdministrators() throws NamingException
+    {
+        DirContext adminCtx = getAdminContext();
+
+        // modify ou=system to be an AP for an A/C AA
+        Attributes changes = new BasicAttributes( "administrativeRole", SubentryService.AC_AREA, true );
+        adminCtx.modifyAttributes( "", DirContext.ADD_ATTRIBUTE, changes );
+
+        Name userName = createTestUser( "billyd" );
+
+        // try an add operation which should fail without any ACI
+        Attributes testEntry = new BasicAttributes( "ou", "testou", true );
+        Attribute objectClass = new BasicAttribute( "objectClass" );
+        testEntry.put( objectClass );
+        objectClass.add( "top" );
+        objectClass.add( "organizationalUnit" );
+
+        try
+        {
+            DirContext userContext = getUserContext( userName, "billyd" );
+            userContext.createSubcontext( "ou=testou", testEntry );
+            fail( "should never get here due to a permission exception" );
+        }
+        catch ( LdapNoPermissionException e ) {}
+
+        // now add a subentry that enables users in the admin group to add an entry below ou=system
+        Attributes subentry = new BasicAttributes( "cn", "administratorAdd", true );
+        objectClass = new BasicAttribute( "objectClass" );
+        subentry.put( objectClass );
+        objectClass.add( "top" );
+        objectClass.add( "subentry" );
+        objectClass.add( "accessControlSubentry" );
+        subentry.put( "subtreeSpecification", "{}" );
+        subentry.put( "prescriptiveACI", "{ " +
+                "identificationTag \"addAci\", " +
+                "precedence 14, " +
+                "authenticationLevel none, " +
+                "itemOrUserFirst userFirst: { " +
+                "userClasses { userGroup { \"cn=Administrators,ou=groups,ou=system\" } }, " +
+                "userPermissions { { " +
+                "protectedItems {entry, allUserAttributeTypesAndValues}, " +
+                "grantsAndDenials { grantAdd } } } } }" );
+        adminCtx.createSubcontext( "cn=administratorAdd", subentry );
+
+        // see if we can now add that test entry which we could not before
+        // add op should still fail since akarasulu is not in the admin group
+        try
+        {
+            DirContext userContext = getUserContext( userName, "billyd" );
+            userContext.createSubcontext( "ou=testou", testEntry );
+            fail( "should never get here due to a permission exception" );
+        }
+        catch ( LdapNoPermissionException e ) {}
+
+        // now add akarasulu to the Administrator group and try again
+        addUserToGroup( "billyd", "Administrators" );
+        DirContext userContext = getUserContext( userName, "billyd" );
+        userContext.createSubcontext( "ou=testou", testEntry );
+    }
+
+
+    public void testGrantAddByName() throws NamingException
+    {
+        DirContext adminCtx = getAdminContext();
+
+        // modify ou=system to be an AP for an A/C AA
+        Attributes changes = new BasicAttributes( "administrativeRole", SubentryService.AC_AREA, true );
+        adminCtx.modifyAttributes( "", DirContext.ADD_ATTRIBUTE, changes );
+
+        Name userName = createTestUser( "billyd" );
+
+        // try an add operation which should fail without any ACI
+        Attributes testEntry = new BasicAttributes( "ou", "testou", true );
+        Attribute objectClass = new BasicAttribute( "objectClass" );
+        testEntry.put( objectClass );
+        objectClass.add( "top" );
+        objectClass.add( "organizationalUnit" );
+
+        try
+        {
+            DirContext userContext = getUserContext( userName, "billyd" );
+            userContext.createSubcontext( "ou=testou", testEntry );
+            fail( "should never get here due to a permission exception" );
+        }
+        catch ( LdapNoPermissionException e ) {}
+
+        // now add a subentry that enables user billyd to add an entry below ou=system
+        Attributes subentry = new BasicAttributes( "cn", "billydAdd", true );
+        objectClass = new BasicAttribute( "objectClass" );
+        subentry.put( objectClass );
+        objectClass.add( "top" );
+        objectClass.add( "subentry" );
+        objectClass.add( "accessControlSubentry" );
+        subentry.put( "subtreeSpecification", "{}" );
+        subentry.put( "prescriptiveACI", "{ " +
+                "identificationTag \"addAci\", " +
+                "precedence 14, " +
+                "authenticationLevel none, " +
+                "itemOrUserFirst userFirst: { " +
+                "userClasses { name { \"uid=billyd,ou=users,ou=system\" } }, " +
+                "userPermissions { { " +
+                "protectedItems {entry, allUserAttributeTypesAndValues}, " +
+                "grantsAndDenials { grantAdd } } } } }" );
+        adminCtx.createSubcontext( "cn=billydAdd", subentry );
+
+        // should work now that billyd is authorized
+        DirContext userContext = getUserContext( userName, "billyd" );
+        userContext.createSubcontext( "ou=testou", testEntry );
+    }
+
+
+    public void testGrantAddBySubtree() throws NamingException
+    {
+        DirContext adminCtx = getAdminContext();
+
+        // modify ou=system to be an AP for an A/C AA
+        Attributes changes = new BasicAttributes( "administrativeRole", SubentryService.AC_AREA, true );
+        adminCtx.modifyAttributes( "", DirContext.ADD_ATTRIBUTE, changes );
+
+        Name userName = createTestUser( "billyd" );
+
+        // try an add operation which should fail without any ACI
+        Attributes testEntry = new BasicAttributes( "ou", "testou", true );
+        Attribute objectClass = new BasicAttribute( "objectClass" );
+        testEntry.put( objectClass );
+        objectClass.add( "top" );
+        objectClass.add( "organizationalUnit" );
+
+        try
+        {
+            DirContext userContext = getUserContext( userName, "billyd" );
+            userContext.createSubcontext( "ou=testou", testEntry );
+            fail( "should never get here due to a permission exception" );
+        }
+        catch ( LdapNoPermissionException e ) {}
+
+        // now add a subentry that enables user billyd to add an entry below ou=system
+        Attributes subentry = new BasicAttributes( "cn", "billydAdd", true );
+        objectClass = new BasicAttribute( "objectClass" );
+        subentry.put( objectClass );
+        objectClass.add( "top" );
+        objectClass.add( "subentry" );
+        objectClass.add( "accessControlSubentry" );
+        subentry.put( "subtreeSpecification", "{}" );
+        subentry.put( "prescriptiveACI", "{ " +
+                "identificationTag \"addAci\", " +
+                "precedence 14, " +
+                "authenticationLevel none, " +
+                "itemOrUserFirst userFirst: { " +
+                "userClasses { subtree { { base \"ou=users,ou=system\" } } }, " +
+                "userPermissions { { " +
+                "protectedItems {entry, allUserAttributeTypesAndValues}, " +
+                "grantsAndDenials { grantAdd } } } } }" );
+        adminCtx.createSubcontext( "cn=billydAdd", subentry );
+
+        // should work now that billyd is authorized
+        DirContext userContext = getUserContext( userName, "billyd" );
+        userContext.createSubcontext( "ou=testou", testEntry );
     }
 }