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/24 21:20:46 UTC

svn commit: r328138 - in /directory: apacheds/trunk/main/src/test/org/apache/ldap/server/ protocol-providers/ldap/trunk/src/main/java/org/apache/ldap/server/protocol/ protocol-providers/ldap/trunk/src/main/java/org/apache/ldap/server/protocol/support/

Author: akarasulu
Date: Mon Oct 24 12:20:33 2005
New Revision: 328138

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

 o fixes DIREVE-283
 o made search handler use a special getLdapContext method when the search
   operation is on the root DSE with (objectClass=*), scope = base, and 
   base = ""
 o allowed bind operation as anonymous even when anonymous binds are disabled
   in the configuration ... delayed checks for anonymous user operations until
   other operations are performed.
 o added test case to make sure anonymous access is still disabled for binds
   to anything other than root dse


Modified:
    directory/apacheds/trunk/main/src/test/org/apache/ldap/server/MiscTest.java
    directory/protocol-providers/ldap/trunk/src/main/java/org/apache/ldap/server/protocol/SessionRegistry.java
    directory/protocol-providers/ldap/trunk/src/main/java/org/apache/ldap/server/protocol/support/BindHandler.java
    directory/protocol-providers/ldap/trunk/src/main/java/org/apache/ldap/server/protocol/support/SearchHandler.java

Modified: directory/apacheds/trunk/main/src/test/org/apache/ldap/server/MiscTest.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/trunk/main/src/test/org/apache/ldap/server/MiscTest.java?rev=328138&r1=328137&r2=328138&view=diff
==============================================================================
--- directory/apacheds/trunk/main/src/test/org/apache/ldap/server/MiscTest.java (original)
+++ directory/apacheds/trunk/main/src/test/org/apache/ldap/server/MiscTest.java Mon Oct 24 12:20:33 2005
@@ -53,6 +53,10 @@
         {
             configuration.setAllowAnonymousAccess( false );
         }
+        else if ( this.getName().equals( "testEnableAnonymousBindsOnRootDSE" ) )
+        {
+            configuration.setAllowAnonymousAccess( false );
+        }
         super.setUp();
     }
 
@@ -73,14 +77,62 @@
         env.put( Context.SECURITY_AUTHENTICATION, "none" );
         env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
 
+        InitialDirContext ic = new InitialDirContext( env );
         try
         {
-            new InitialContext( env );
+            ic.search( "", "(objectClass=*)", new SearchControls() );
             fail( "If anonymous binds are disabled we should never get here!" );
         }
         catch ( NoPermissionException e )
         {
         }
+
+        Attributes attrs = new BasicAttributes( true );
+        Attribute oc = new BasicAttribute( "objectClass" );
+        attrs.put( oc );
+        oc.add( "top" );
+        oc.add( "organizationalUnit" );
+
+        try
+        {
+            ic.createSubcontext( "ou=blah", attrs );
+        }
+        catch( NoPermissionException e )
+        {
+        }
+    }
+
+
+    /**
+     * Test to make sure anonymous binds are allowed on the RootDSE even when disabled
+     * in general when going through the wire protocol.
+     *
+     * @throws Exception if anything goes wrong
+     */
+    public void testEnableAnonymousBindsOnRootDSE() throws Exception
+    {
+        // Use the SUN JNDI provider to hit server port and bind as anonymous
+
+        final Hashtable env = new Hashtable();
+
+        env.put( Context.PROVIDER_URL, "ldap://localhost:" + port + "/" );
+        env.put( Context.SECURITY_AUTHENTICATION, "none" );
+        env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
+
+        InitialDirContext ctx = new InitialDirContext( env );
+        SearchControls cons = new SearchControls();
+        cons.setSearchScope( SearchControls.OBJECT_SCOPE );
+        NamingEnumeration list = ctx.search( "", "(objectClass=*)", cons );
+        SearchResult result = null;
+        if ( list.hasMore() )
+        {
+            result = ( SearchResult ) list.next();
+        }
+        assertFalse( list.hasMore() );
+        list.close();
+
+        assertNotNull( result );
+        assertEquals( "", result.getName().trim() );
     }
 
 

Modified: directory/protocol-providers/ldap/trunk/src/main/java/org/apache/ldap/server/protocol/SessionRegistry.java
URL: http://svn.apache.org/viewcvs/directory/protocol-providers/ldap/trunk/src/main/java/org/apache/ldap/server/protocol/SessionRegistry.java?rev=328138&r1=328137&r2=328138&view=diff
==============================================================================
--- directory/protocol-providers/ldap/trunk/src/main/java/org/apache/ldap/server/protocol/SessionRegistry.java (original)
+++ directory/protocol-providers/ldap/trunk/src/main/java/org/apache/ldap/server/protocol/SessionRegistry.java Mon Oct 24 12:20:33 2005
@@ -29,6 +29,7 @@
 import javax.naming.spi.InitialContextFactory;
 
 import org.apache.ldap.common.exception.LdapNoPermissionException;
+import org.apache.ldap.server.jndi.ServerLdapContext;
 import org.apache.mina.protocol.ProtocolSession;
 
 
@@ -118,6 +119,10 @@
      * client.  If the context is not present then there was no bind operation
      * that set it.  Hence this operation requesting the IC is anonymous.
      *
+     * @todo this allowAnonymous parameter is a bit confusing - figure out
+     * something better to call it.  I think only bind requests a context
+     * that is not anonymous.  Have to refactor the heck out of this lousy code.
+     * 
      * @param session the client's key
      * @param connCtls connection controls if any to use if creating anon context
      * @param allowAnonymous true if anonymous requests will create anonymous
@@ -134,13 +139,83 @@
             ctx = ( LdapContext ) contexts.get( session );
         }
 
+        // there is no context so its an implicit bind, no bind operation is being performed
         if ( ctx == null && allowAnonymous )
         {
+            // if configuration says disable anonymous binds we throw exection
             if ( env.containsKey( "server.disable.anonymous" ) )
             {
                 throw new LdapNoPermissionException( "Anonymous binds have been disabled!" );
             }
 
+            if ( env.containsKey( "server.use.factory.instance" ) )
+            {
+                InitialContextFactory factory = ( InitialContextFactory ) env.get( "server.use.factory.instance" );
+
+                if ( factory == null )
+                {
+                    throw new NullPointerException( "server.use.factory.instance was set in env but was null" );
+                }
+
+                ctx = ( LdapContext ) factory.getInitialContext( env );
+            }
+            else
+            {
+                Hashtable cloned = ( Hashtable ) env.clone();
+                cloned.put( Context.SECURITY_AUTHENTICATION, "none" );
+                cloned.remove( Context.SECURITY_PRINCIPAL );
+                cloned.remove( Context.SECURITY_CREDENTIALS );
+                ctx = new InitialLdapContext( cloned, connCtls );
+            }
+        }
+        // the context came up non null so we binded explicitly and op now is not bind
+        else if ( ctx != null && allowAnonymous )
+        {
+            ServerLdapContext slc = null;
+            if ( ! ( ctx instanceof ServerLdapContext ) )
+            {
+                slc = ( ServerLdapContext ) ctx.lookup( "" );
+            }
+            else
+            {
+                slc = ( ServerLdapContext ) ctx;
+            }
+            boolean isAnonymousUser = slc.getPrincipal().getName().trim().equals( "" );
+            boolean cfgAllowsAnonymous = env.containsKey( "server.disable.anonymous" );
+
+            // if the user principal is anonymous and the configuration does not allow anonymous binds we
+            // prevent the operation by blowing a NoPermissionsException
+            if ( isAnonymousUser && !cfgAllowsAnonymous )
+            {
+                throw new LdapNoPermissionException( "Anonymous binds have been disabled!" );
+            }
+        }
+
+        return ctx;
+    }
+
+
+    /**
+     * Gets the InitialContext to the root of the system that was gotten for
+     * client ONLY to be used for RootDSE Search operations.  This bypasses
+     * checks to only allow anonymous binds for this special case.
+     *
+     * @param session the client's key
+     * @param connCtls connection controls if any to use if creating anon context
+     * @return the InitialContext or null
+     */
+    public LdapContext getLdapContextOnRootDSEAccess( ProtocolSession session, Control[] connCtls )
+            throws NamingException
+    {
+        LdapContext ctx = null;
+
+        synchronized( contexts )
+        {
+            ctx = ( LdapContext ) contexts.get( session );
+        }
+
+        if ( ctx == null )
+        {
             if ( env.containsKey( "server.use.factory.instance" ) )
             {
                 InitialContextFactory factory = ( InitialContextFactory ) env.get( "server.use.factory.instance" );

Modified: directory/protocol-providers/ldap/trunk/src/main/java/org/apache/ldap/server/protocol/support/BindHandler.java
URL: http://svn.apache.org/viewcvs/directory/protocol-providers/ldap/trunk/src/main/java/org/apache/ldap/server/protocol/support/BindHandler.java?rev=328138&r1=328137&r2=328138&view=diff
==============================================================================
--- directory/protocol-providers/ldap/trunk/src/main/java/org/apache/ldap/server/protocol/support/BindHandler.java (original)
+++ directory/protocol-providers/ldap/trunk/src/main/java/org/apache/ldap/server/protocol/support/BindHandler.java Mon Oct 24 12:20:33 2005
@@ -66,7 +66,7 @@
 
         Hashtable env = SessionRegistry.getSingleton().getEnvironment();
         StartupConfiguration cfg = ( StartupConfiguration ) Configuration.toConfiguration( env );
-        // if the bind request is not simple then we freak: no strong auth yet
+        // if the bind request is not simple then we freak: no sasl based auth yet
         if ( ! req.isSimple() )
         {
             result.setResultCode( ResultCodeEnum.AUTHMETHODNOTSUPPORTED );
@@ -75,18 +75,18 @@
             return;
         }
 
-        boolean allowAnonymousBinds = cfg.isAllowAnonymousAccess();
-        boolean emptyCredentials = req.getCredentials() == null || req.getCredentials().length == 0;
-        boolean emptyDn = req.getName() == null || req.getName().length() == 0;
-
-        if ( emptyCredentials && emptyDn && ! allowAnonymousBinds )
-        {
-            result.setResultCode( ResultCodeEnum.INSUFFICIENTACCESSRIGHTS );
-            String msg = "Bind failure: Anonymous binds have been disabled!";
-            result.setErrorMessage( msg );
-            session.write( resp );
-            return;
-        }
+//        boolean allowAnonymousBinds = cfg.isAllowAnonymousAccess();
+//        boolean emptyCredentials = req.getCredentials() == null || req.getCredentials().length == 0;
+//        boolean emptyDn = req.getName() == null || req.getName().length() == 0;
+//
+//        if ( emptyCredentials && emptyDn && ! allowAnonymousBinds )
+//        {
+//            result.setResultCode( ResultCodeEnum.INSUFFICIENTACCESSRIGHTS );
+//            String msg = "Bind failure: Anonymous binds have been disabled!";
+//            result.setErrorMessage( msg );
+//            session.write( resp );
+//            return;
+//        }
 
         // clone the environment first then add the required security settings
 

Modified: directory/protocol-providers/ldap/trunk/src/main/java/org/apache/ldap/server/protocol/support/SearchHandler.java
URL: http://svn.apache.org/viewcvs/directory/protocol-providers/ldap/trunk/src/main/java/org/apache/ldap/server/protocol/support/SearchHandler.java?rev=328138&r1=328137&r2=328138&view=diff
==============================================================================
--- directory/protocol-providers/ldap/trunk/src/main/java/org/apache/ldap/server/protocol/support/SearchHandler.java (original)
+++ directory/protocol-providers/ldap/trunk/src/main/java/org/apache/ldap/server/protocol/support/SearchHandler.java Mon Oct 24 12:20:33 2005
@@ -24,26 +24,21 @@
 
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
+import javax.naming.ldap.LdapContext;
 import javax.naming.directory.Attribute;
 import javax.naming.directory.SearchControls;
 import javax.naming.directory.SearchResult;
 
 import org.apache.ldap.common.exception.LdapException;
-import org.apache.ldap.common.message.LdapResultImpl;
-import org.apache.ldap.common.message.ReferralImpl;
-import org.apache.ldap.common.message.ResultCodeEnum;
-import org.apache.ldap.common.message.SearchRequest;
-import org.apache.ldap.common.message.SearchResponseDone;
-import org.apache.ldap.common.message.SearchResponseDoneImpl;
-import org.apache.ldap.common.message.SearchResponseEntry;
-import org.apache.ldap.common.message.SearchResponseEntryImpl;
-import org.apache.ldap.common.message.SearchResponseReference;
-import org.apache.ldap.common.message.SearchResponseReferenceImpl;
+import org.apache.ldap.common.message.*;
 import org.apache.ldap.common.name.LdapName;
 import org.apache.ldap.common.util.ArrayUtils;
 import org.apache.ldap.common.util.ExceptionUtils;
+import org.apache.ldap.common.filter.PresenceNode;
 import org.apache.ldap.server.jndi.ServerLdapContext;
 import org.apache.ldap.server.protocol.SessionRegistry;
+import org.apache.ldap.server.configuration.StartupConfiguration;
+import org.apache.ldap.server.configuration.Configuration;
 import org.apache.mina.protocol.ProtocolSession;
 import org.apache.mina.protocol.handler.MessageHandler;
 import org.slf4j.Logger;
@@ -63,7 +58,7 @@
 
     public void messageReceived( ProtocolSession session, Object request )
     {
-        ServerLdapContext ctx;
+        LdapContext ctx;
         SearchRequest req = ( SearchRequest ) request;
         NamingEnumeration list = null;
 
@@ -93,9 +88,49 @@
 
         try
         {
-            ctx = ( ServerLdapContext ) SessionRegistry.getSingleton().getLdapContext( session, null, true ).lookup( "" );
+            boolean isBaseIsRoot = req.getBase().trim().equals( "" );
+            boolean isBaseScope = req.getScope() == ScopeEnum.BASEOBJECT;
+            boolean isRootDSEFilter = false;
+            if ( req.getFilter() instanceof PresenceNode )
+            {
+                isRootDSEFilter = ( ( PresenceNode ) req.getFilter() ).getAttribute().equalsIgnoreCase( "objectClass" );
+            }
+            boolean isRootDSESearch = isBaseIsRoot && isBaseScope && isRootDSEFilter;
+
+            // bypass checks to disallow anonymous binds for search on RootDSE with base obj scope
+            if ( isRootDSESearch )
+            {
+                ctx = SessionRegistry.getSingleton().getLdapContextOnRootDSEAccess( session, null );
+            }
+            // all those search operations are subject to anonymous bind checks when anonymous binda are disallowed
+            else
+            {
+                ctx = ( LdapContext ) SessionRegistry.getSingleton().getLdapContext( session, null, true ).lookup( "" );
+            }
+
+            if ( ! ( ctx instanceof ServerLdapContext ) )
+            {
+                ctx = ( ServerLdapContext ) ctx.lookup( "" );
+            }
+
+            StartupConfiguration cfg = ( StartupConfiguration ) Configuration.toConfiguration( ctx.getEnvironment() );
+            boolean allowAnonymousBinds = cfg.isAllowAnonymousAccess();
+            boolean isAnonymousUser = ( ( ServerLdapContext ) ctx ).getPrincipal().getName().trim().equals( "" );
+
+            if ( isAnonymousUser && ! allowAnonymousBinds && ! isRootDSESearch )
+            {
+                SearchResponseDone resp = new SearchResponseDoneImpl( req.getMessageId() );
+                LdapResultImpl result = new LdapResultImpl( resp );
+                resp.setLdapResult( result );
+                result.setResultCode( ResultCodeEnum.INSUFFICIENTACCESSRIGHTS );
+                String msg = "Bind failure: Anonymous binds have been disabled!";
+                result.setErrorMessage( msg );
+                session.write( resp );
+                return;
+            }
+
             ctx.addToEnvironment( DEREFALIASES_KEY, req.getDerefAliases().getName() );
-            list = ctx.search( new LdapName( req.getBase() ), req.getFilter(), controls );
+            list = ( ( ServerLdapContext ) ctx ).search( new LdapName( req.getBase() ), req.getFilter(), controls );
 
             if( list.hasMore() )
             {