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 2006/02/03 13:13:10 UTC

svn commit: r374649 - in /directory/trunks/apacheds: core/src/main/java/org/apache/ldap/server/authn/ core/src/main/java/org/apache/ldap/server/interceptor/ core/src/main/java/org/apache/ldap/server/jndi/ core/src/main/java/org/apache/ldap/server/parti...

Author: akarasulu
Date: Fri Feb  3 04:12:53 2006
New Revision: 374649

URL: http://svn.apache.org/viewcvs?rev=374649&view=rev
Log:
(1) cleaned up authentication, (2) added bind, unbind intercepted methods (3) fixed DIREVE-314

Added:
    directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/jndi/LdapJndiProperties.java   (props changed)
      - copied unchanged from r374648, directory/sandbox/akarasulu/rc1refactor/apacheds/core/src/main/java/org/apache/ldap/server/jndi/LdapJndiProperties.java
    directory/trunks/apacheds/core/src/test/java/org/apache/ldap/server/jndi/LdapJndiPropertiesTest.java   (props changed)
      - copied unchanged from r374648, directory/sandbox/akarasulu/rc1refactor/apacheds/core/src/test/java/org/apache/ldap/server/jndi/LdapJndiPropertiesTest.java
Modified:
    directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/authn/AuthenticationService.java
    directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/BaseInterceptor.java
    directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/Interceptor.java
    directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/InterceptorChain.java
    directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/NextInterceptor.java
    directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/jndi/ServerContext.java
    directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/jndi/ServerDirContext.java
    directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/jndi/ServerLdapContext.java
    directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/DefaultDirectoryPartitionNexus.java
    directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/DirectoryPartition.java
    directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/DirectoryPartitionNexusProxy.java
    directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/impl/btree/jdbm/JdbmDirectoryPartition.java
    directory/trunks/apacheds/core/src/test/java/org/apache/ldap/server/interceptor/InterceptorChainTest.java
    directory/trunks/apacheds/protocols/ldap/src/main/java/org/apache/ldap/server/protocol/support/ExtendedHandler.java
    directory/trunks/apacheds/protocols/ldap/src/main/java/org/apache/ldap/server/protocol/support/UnbindHandler.java

Modified: directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/authn/AuthenticationService.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/authn/AuthenticationService.java?rev=374649&r1=374648&r2=374649&view=diff
==============================================================================
--- directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/authn/AuthenticationService.java (original)
+++ directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/authn/AuthenticationService.java Fri Feb  3 04:12:53 2006
@@ -21,6 +21,7 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 import javax.naming.Context;
@@ -32,11 +33,8 @@
 import javax.naming.directory.SearchControls;
 
 import org.apache.ldap.common.exception.LdapAuthenticationException;
-import org.apache.ldap.common.exception.LdapAuthenticationNotSupportedException;
 import org.apache.ldap.common.filter.ExprNode;
-import org.apache.ldap.common.message.ResultCodeEnum;
 import org.apache.ldap.common.util.AttributeUtils;
-import org.apache.ldap.common.util.StringTools;
 import org.apache.ldap.server.DirectoryServiceConfiguration;
 import org.apache.ldap.server.configuration.AuthenticatorConfiguration;
 import org.apache.ldap.server.configuration.InterceptorConfiguration;
@@ -44,6 +42,7 @@
 import org.apache.ldap.server.interceptor.Interceptor;
 import org.apache.ldap.server.interceptor.NextInterceptor;
 import org.apache.ldap.server.invocation.InvocationStack;
+import org.apache.ldap.server.jndi.LdapJndiProperties;
 import org.apache.ldap.server.jndi.ServerContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -184,7 +183,7 @@
     		log.debug( "Adding the entry " + AttributeUtils.toString( entry ) + " for DN = '"  + upName + "'" );
     	}
     	
-        authenticate();
+        checkAuthenticated();
         next.add( upName, normName, entry );
     }
 
@@ -196,7 +195,7 @@
     		log.debug( "Deleting name = '" + name.toString() + "'" );
     	}
     	
-        authenticate();
+        checkAuthenticated();
         next.delete( name );
     }
 
@@ -208,7 +207,7 @@
     		log.debug( "Matching name = '" + dn.toString() + "'" );
     	}
 
-    	authenticate();
+    	checkAuthenticated();
         return next.getMatchedName( dn, normalized );
     }
 
@@ -220,7 +219,7 @@
     		log.debug( "Getting root DSE" );
     	}
 
-        authenticate();
+        checkAuthenticated();
         return next.getRootDSE();
     }
 
@@ -232,7 +231,7 @@
     		log.debug( "Getting suffix for name = '" + dn.toString() + "'" );
     	}
 
-        authenticate();
+        checkAuthenticated();
         return next.getSuffix( dn, normalized );
     }
 
@@ -244,7 +243,7 @@
     		log.debug( "Testing if entry name = '" + name.toString() + "' exists");
     	}
 
-        authenticate();
+        checkAuthenticated();
         return next.hasEntry( name );
     }
 
@@ -256,7 +255,7 @@
     		log.debug( "Testing suffix for name = '" + name.toString() + "'" );
     	}
 
-        authenticate();
+        checkAuthenticated();
         return next.isSuffix( name );
     }
 
@@ -268,7 +267,7 @@
     		log.debug( "Listing base = '" + base.toString() + "'" );
     	}
 
-        authenticate();
+        checkAuthenticated();
         return next.list( base );
     }
 
@@ -280,7 +279,7 @@
     		log.debug( "Listing suffixes" );
     	}
 
-        authenticate();
+        checkAuthenticated();
         return next.listSuffixes( normalized );
     }
 
@@ -292,7 +291,7 @@
     		log.debug( "Lookup name = '" + dn.toString() + "', attributes = " + attrIds );
     	}
 
-        authenticate();
+        checkAuthenticated();
         return next.lookup( dn, attrIds );
     }
 
@@ -304,7 +303,7 @@
     		log.debug( "Lookup name = '" + name.toString() + "'" );
     	}
 
-        authenticate();
+        checkAuthenticated();
         return next.lookup( name );
     }
 
@@ -316,7 +315,7 @@
     		log.debug( "Modifying name = '" + name.toString() + "', modifs = " + AttributeUtils.toString( mods ) );
     	}
 
-        authenticate();
+        checkAuthenticated();
         next.modify( name, modOp, mods );
     }
 
@@ -328,7 +327,7 @@
     		log.debug( "Modifying name = '" + name.toString() + "'" );
     	}
 
-        authenticate();
+        checkAuthenticated();
         next.modify( name, mods );
     }
 
@@ -340,7 +339,7 @@
     		log.debug( "Modifying name = '" + name.toString() + "', new RDN = '" + newRn + "', oldRDN = '" + deleteOldRn + "'" );
     	}
 
-        authenticate();
+        checkAuthenticated();
         next.modifyRn( name, newRn, deleteOldRn );
     }
 
@@ -352,7 +351,7 @@
     		log.debug( "Moving name = '" + oriChildName.toString() + "' to name = '" + newParentName + "', new RDN = '" + newRn + "', oldRDN = '" + deleteOldRn + "'" );
     	}
 
-        authenticate();
+        checkAuthenticated();
         next.move( oriChildName, newParentName, newRn, deleteOldRn );
     }
 
@@ -364,7 +363,7 @@
     		log.debug( "Moving name = '" + oriChildName.toString() + " to name = '" + newParentName + "'" );
     	}
 
-        authenticate();
+        checkAuthenticated();
         next.move( oriChildName, newParentName );
     }
 
@@ -376,17 +375,14 @@
     		log.debug( "Search for base = '" + base.toString() + "'" );
     	}
 
-        authenticate();
+        checkAuthenticated();
         return next.search( base, env, filter, searchCtls );
     }
 
 
-    private void authenticate() throws NamingException
+    private void checkAuthenticated() throws NamingException
     {
-        // check if we are already authenticated and if so we return making
-        // sure first that the credentials are not exposed within context
-        ServerContext ctx =
-            ( ServerContext ) InvocationStack.getInstance().peek().getCaller();
+        ServerContext ctx = ( ServerContext ) InvocationStack.getInstance().peek().getCaller();
 
         if ( ctx.getPrincipal() != null )
         {
@@ -397,36 +393,32 @@
             return;
         }
 
-        String authList = ( String ) ctx.getEnvironment().get( Context.SECURITY_AUTHENTICATION );
+        throw new IllegalStateException( "Attempted operation by unauthenticated caller." );
+    }
+    
+    
+    public void bind( NextInterceptor next, Name bindDn, byte[] credentials, List mechanisms, String saslAuthId ) 
+        throws NamingException
+    {
+        // check if we are already authenticated and if so we return making
+        // sure first that the credentials are not exposed within context
+        ServerContext ctx =
+            ( ServerContext ) InvocationStack.getInstance().peek().getCaller();
 
-        if ( authList == null )
+        if ( ctx.getPrincipal() != null )
         {
             if ( ctx.getEnvironment().containsKey( Context.SECURITY_CREDENTIALS ) )
             {
-                // authentication type is simple here
-
-                authList = "simple";
-            }
-            else
-            {
-                // authentication type is anonymous
-
-                authList = "none";
+                ctx.removeFromEnvironment( Context.SECURITY_CREDENTIALS );
             }
-
+            return;
         }
 
-        authList = StringTools.deepTrim( authList );
-
-        String[] auth = authList.split( " " );
-
-        Collection authenticators = null;
-
         // pick the first matching authenticator type
-
-        for ( int i=0; i<auth.length; i++)
+        Collection authenticators = null;
+        for ( int ii = 0; ii < mechanisms.size(); ii++)
         {
-            authenticators = getAuthenticators( auth[i] );
+            authenticators = getAuthenticators( ( String ) mechanisms.get( ii ) );
 
             if ( authenticators != null )
             {
@@ -436,26 +428,28 @@
 
         if ( authenticators == null )
         {
-            ctx.getEnvironment(); // shut's up idea's yellow light
-
-            ResultCodeEnum rc = ResultCodeEnum.AUTHMETHODNOTSUPPORTED;
-
-            throw new LdapAuthenticationNotSupportedException( rc );
+            log.debug( "No authenticators found, delegating bind to the nexus." );
+            // as a last resort try binding via the nexus
+            next.bind( bindDn, credentials, mechanisms, saslAuthId );
+            log.debug( "Nexus succeeded on bind operation." );
+            // bind succeeded if we got this far 
+            ctx.setPrincipal( new TrustedPrincipalWrapper( 
+                new LdapPrincipal( bindDn, LdapJndiProperties.getAuthenticationLevel( ctx.getEnvironment() ) ) ) );
+            // remove creds so there is no security risk
+            ctx.removeFromEnvironment( Context.SECURITY_CREDENTIALS );
+            return;
         }
 
         // try each authenticators
         for ( Iterator i = authenticators.iterator(); i.hasNext(); )
         {
             Authenticator authenticator = ( Authenticator ) i.next();
-
             try
             {
                 // perform the authentication
                 LdapPrincipal authorizationId = authenticator.authenticate( ctx );
-
                 // authentication was successful
                 ctx.setPrincipal( new TrustedPrincipalWrapper( authorizationId ) );
-
                 // remove creds so there is no security risk
                 ctx.removeFromEnvironment( Context.SECURITY_CREDENTIALS );
                 return;
@@ -463,11 +457,18 @@
             catch( LdapAuthenticationException e )
             {
                 // authentication failed, try the next authenticator
+                if ( log.isInfoEnabled() )
+                {
+                    log.info( "Authenticator "+authenticator.getClass()+" failed to authenticate " + bindDn );
+                }
             }
             catch( Exception e )
             {
                 // Log other exceptions than LdapAuthenticationException
-                log.warn( "Unexpected exception from " + authenticator.getClass(), e );
+                if ( log.isWarnEnabled() )
+                {
+                    log.warn( "Unexpected exception from " + authenticator.getClass() + " for principal " + bindDn, e );
+                }
             }
         }
 

Modified: directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/BaseInterceptor.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/BaseInterceptor.java?rev=374649&r1=374648&r2=374649&view=diff
==============================================================================
--- directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/BaseInterceptor.java (original)
+++ directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/BaseInterceptor.java Fri Feb  3 04:12:53 2006
@@ -18,6 +18,7 @@
 
 
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 import javax.naming.Context;
@@ -208,5 +209,16 @@
     public boolean compare( NextInterceptor next, Name name, String oid, Object value ) throws NamingException
     {
         return next.compare( name, oid, value );
+    }
+    
+    public void bind( NextInterceptor next, Name bindDn, byte[] credentials, List mechanisms, String saslAuthId )
+        throws NamingException
+    {
+        next.bind( bindDn, credentials, mechanisms, saslAuthId );
+    }
+    
+    public void unbind( NextInterceptor next, Name bindDn ) throws NamingException
+    {
+        next.unbind( bindDn );
     }
 }

Modified: directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/Interceptor.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/Interceptor.java?rev=374649&r1=374648&r2=374649&view=diff
==============================================================================
--- directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/Interceptor.java (original)
+++ directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/Interceptor.java Fri Feb  3 04:12:53 2006
@@ -18,6 +18,7 @@
 
 
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 import javax.naming.Name;
@@ -212,4 +213,15 @@
      */
     void move( NextInterceptor next, Name oldName, Name newParentName, String newRn,
                boolean deleteOldRn ) throws NamingException;
+
+    /**
+     * Filters {@link DirectoryPartition#bind(Name, byte[], List, String)} call.
+     */
+    void bind( NextInterceptor next, Name bindDn, byte[] credentials, List mechanisms, String saslAuthId )
+        throws NamingException;
+
+    /**
+     * Filters {@link DirectoryPartition#unbind(Name)} call.
+     */
+    void unbind( NextInterceptor next, Name bindDn ) throws NamingException;
 }

Modified: directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/InterceptorChain.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/InterceptorChain.java?rev=374649&r1=374648&r2=374649&view=diff
==============================================================================
--- directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/InterceptorChain.java (original)
+++ directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/InterceptorChain.java Fri Feb  3 04:12:53 2006
@@ -184,6 +184,18 @@
         {
             nexus.removeContextPartition( suffix );
         }
+
+
+        public void bind( NextInterceptor next, Name bindDn, byte[] credentials, List mechanisms, String saslAuthId ) throws NamingException
+        {
+            nexus.bind( bindDn, credentials, mechanisms, saslAuthId );
+        }
+
+
+        public void unbind( NextInterceptor next, Name bindDn ) throws NamingException
+        {
+            nexus.unbind( bindDn );
+        }
     };
 
     private final Map name2entry = new HashMap();
@@ -681,6 +693,46 @@
     }
 
 
+    public void bind( Name bindDn, byte[] credentials, List mechanisms, String saslAuthId ) throws NamingException
+    {
+        Entry node = getStartingEntry();
+        Interceptor head = node.configuration.getInterceptor();
+        NextInterceptor next = node.nextInterceptor;
+        try
+        {
+            head.bind( next, bindDn, credentials, mechanisms, saslAuthId );
+        }
+        catch ( NamingException ne )
+        {
+            throw ne;
+        }
+        catch ( Throwable e )
+        {
+            throwInterceptorException( head, e );
+        }
+    }
+
+    
+    public void unbind( Name bindDn ) throws NamingException
+    {
+        Entry node = getStartingEntry();
+        Interceptor head = node.configuration.getInterceptor();
+        NextInterceptor next = node.nextInterceptor;
+        try
+        {
+            head.unbind( next, bindDn );
+        }
+        catch ( NamingException ne )
+        {
+            throw ne;
+        }
+        catch ( Throwable e )
+        {
+            throwInterceptorException( head, e );
+        }
+    }
+
+    
     public void modify( Name name, int modOp, Attributes mods ) throws NamingException
     {
         Entry entry = getStartingEntry();
@@ -1314,6 +1366,45 @@
                     try
                     {
                         interceptor.move( next.nextInterceptor, oriChildName, newParentName, newRn, deleteOldRn );
+                    }
+                    catch ( NamingException ne )
+                    {
+                        throw ne;
+                    }
+                    catch ( Throwable e )
+                    {
+                        throwInterceptorException( interceptor, e );
+                    }
+                }
+
+
+                public void bind( Name bindDn, byte[] credentials, List mechanisms, String saslAuthId ) throws NamingException
+                {
+                    Entry next = getNextEntry();
+                    Interceptor interceptor = next.configuration.getInterceptor();
+
+                    try
+                    {
+                        interceptor.bind( next.nextInterceptor, bindDn, credentials, mechanisms, saslAuthId );
+                    }
+                    catch ( NamingException ne )
+                    {
+                        throw ne;
+                    }
+                    catch ( Throwable e )
+                    {
+                        throwInterceptorException( interceptor, e );
+                    }
+                }
+
+                public void unbind( Name bindDn ) throws NamingException
+                {
+                    Entry next = getNextEntry();
+                    Interceptor interceptor = next.configuration.getInterceptor();
+
+                    try
+                    {
+                        interceptor.unbind( next.nextInterceptor, bindDn );
                     }
                     catch ( NamingException ne )
                     {

Modified: directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/NextInterceptor.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/NextInterceptor.java?rev=374649&r1=374648&r2=374649&view=diff
==============================================================================
--- directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/NextInterceptor.java (original)
+++ directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/interceptor/NextInterceptor.java Fri Feb  3 04:12:53 2006
@@ -18,6 +18,7 @@
 
 
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 import javax.naming.Name;
@@ -125,4 +126,12 @@
      */
     void move( Name oldName, Name newParentName, String newRn,
                boolean deleteOldRn ) throws NamingException;
+    /**
+     * Calls the next interceptor's {@link Interceptor#bind(NextInterceptor, Name, byte[], List, String)
+     */
+    void bind( Name bindDn, byte[] credentials, List mechanisms, String saslAuthId ) throws NamingException;
+    /**
+     * Calls the next interceptor's {@link Interceptor#unbind(NextInterceptor, Name)
+     */
+    void unbind( Name bindDn ) throws NamingException;
 }

Propchange: directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/jndi/LdapJndiProperties.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/jndi/ServerContext.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/jndi/ServerContext.java?rev=374649&r1=374648&r2=374649&view=diff
==============================================================================
--- directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/jndi/ServerContext.java (original)
+++ directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/jndi/ServerContext.java Fri Feb  3 04:12:53 2006
@@ -23,7 +23,6 @@
 import java.util.Iterator;
 import java.util.Set;
 
-import javax.naming.ConfigurationException;
 import javax.naming.Context;
 import javax.naming.InvalidNameException;
 import javax.naming.Name;
@@ -114,34 +113,16 @@
         this.nexusProxy = new DirectoryPartitionNexusProxy( this, service );
         
         DirectoryServiceConfiguration cfg = service.getConfiguration();
-        
         this.env = ( Hashtable ) cfg.getEnvironment().clone();
         this.env.putAll( env );
+        LdapJndiProperties props = LdapJndiProperties.getLdapJndiProperties( this.env );
+        dn = props.getProviderDn();
 
-        /* --------------------------------------------------------------------
-         * check for the provider URL property and make sure it exists
-         * as a valid value or else we need to throw a configuration error
-         * ------------------------------------------------------------------ */
-        if ( ! env.containsKey( Context.PROVIDER_URL ) )
-        {
-            String msg = "Expected property " + Context.PROVIDER_URL;
-            msg += " but could not find it in env!";
-
-            throw new ConfigurationException( msg );
-        }
-
-        String url = ( String ) env.get( Context.PROVIDER_URL );
-
-        if ( url == null )
-        {
-            String msg = "Expected value for property " + Context.PROVIDER_URL;
-            msg += " but it was set to null in env!";
-
-            throw new ConfigurationException( msg );
-        }
-
-        dn = new LdapName( url );
+        // need to issue a bind operation here
+        this.nexusProxy.bind( props.getBindDn(), props.getCredentials(), 
+            props.getAuthenticationMechanisms(), props.getSaslAuthId() );
 
+        if ( dn.size() == 0 ) return;
         if ( ! nexusProxy.hasEntry( dn ) )
         {
             throw new NameNotFoundException( dn + " does not exist" );
@@ -159,11 +140,12 @@
      * @param env the environment properties used by this context
      * @param dn the distinguished name of this context
      */
-    protected ServerContext( DirectoryService service, LdapPrincipal principal, Name dn )
+    protected ServerContext( DirectoryService service, LdapPrincipal principal, Name dn ) throws NamingException
     {
         this.service = service;
         this.dn = ( LdapName ) dn.clone();
-        this.env = ( Hashtable ) service.getConfiguration().getEnvironment();
+
+        this.env = ( Hashtable ) service.getConfiguration().getEnvironment().clone();
         this.env.put( PROVIDER_URL, dn.toString() );
         this.nexusProxy = new DirectoryPartitionNexusProxy( this, service );;
         this.principal = principal;

Modified: directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/jndi/ServerDirContext.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/jndi/ServerDirContext.java?rev=374649&r1=374648&r2=374649&view=diff
==============================================================================
--- directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/jndi/ServerDirContext.java (original)
+++ directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/jndi/ServerDirContext.java Fri Feb  3 04:12:53 2006
@@ -86,7 +86,7 @@
      * @param env the environment properties used by this context
      * @param dn the distinguished name of this context
      */
-    protected ServerDirContext( DirectoryService service, LdapPrincipal principal, Name dn )
+    protected ServerDirContext( DirectoryService service, LdapPrincipal principal, Name dn ) throws NamingException
     {
         super( service, principal, dn );
     }

Modified: directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/jndi/ServerLdapContext.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/jndi/ServerLdapContext.java?rev=374649&r1=374648&r2=374649&view=diff
==============================================================================
--- directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/jndi/ServerLdapContext.java (original)
+++ directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/jndi/ServerLdapContext.java Fri Feb  3 04:12:53 2006
@@ -19,6 +19,7 @@
 
 import java.util.Hashtable;
 
+import javax.naming.Context;
 import javax.naming.Name;
 import javax.naming.NamingException;
 import javax.naming.ldap.Control;
@@ -31,6 +32,8 @@
 import org.apache.ldap.server.authn.LdapPrincipal;
 import org.apache.ldap.server.referral.ReferralService;
 
+import com.sun.jndi.ldap.LdapName;
+
 
 /**
  * An implementation of a JNDI LdapContext.
@@ -68,7 +71,7 @@
      * @param env the environment properties used by this context
      * @param dn the distinguished name of this context
      */
-    ServerLdapContext( DirectoryService service, LdapPrincipal principal, Name dn )
+    ServerLdapContext( DirectoryService service, LdapPrincipal principal, Name dn ) throws NamingException
     {
         super( service, principal, dn );
     }
@@ -164,6 +167,21 @@
     public boolean compare( Name name, String oid, Object value ) throws NamingException
     {
        return super.getNexusProxy().compare( name, oid, value );
+    }
+    
+    
+    /**
+     * Calling this method tunnels an unbind call down into the partition holding 
+     * the bindDn.  The bind() counter part is not exposed because it is automatically
+     * called when you create a new initial context for a new connection (on wire) or 
+     * (programatic) caller.
+     * 
+     * @throws NamingException
+     */
+    public void ldapUnbind() throws NamingException
+    {
+        String bindDn = ( String ) getEnvironment().get( Context.SECURITY_PRINCIPAL );
+        super.getNexusProxy().unbind( new LdapName( bindDn ) );
     }
     
     

Modified: directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/DefaultDirectoryPartitionNexus.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/DefaultDirectoryPartitionNexus.java?rev=374649&r1=374648&r2=374649&view=diff
==============================================================================
--- directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/DefaultDirectoryPartitionNexus.java (original)
+++ directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/DefaultDirectoryPartitionNexus.java Fri Feb  3 04:12:53 2006
@@ -539,9 +539,23 @@
 
 
     // ------------------------------------------------------------------------
-    // Backend Interface Method Implementations
+    // DirectoryPartition Interface Method Implementations
     // ------------------------------------------------------------------------
     
+    
+    public void bind( Name bindDn, byte[] credentials, List mechanisms, String saslAuthId ) throws NamingException
+    {
+        DirectoryPartition partition = getBackend( bindDn );
+        partition.bind( bindDn, credentials, mechanisms, saslAuthId );
+    }
+
+
+    public void unbind( Name bindDn ) throws NamingException
+    {
+        DirectoryPartition partition = getBackend( bindDn );
+        partition.unbind( bindDn );
+    }
+
     
     /**
      * @see DirectoryPartition#delete(javax.naming.Name)

Modified: directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/DirectoryPartition.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/DirectoryPartition.java?rev=374649&r1=374648&r2=374649&view=diff
==============================================================================
--- directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/DirectoryPartition.java (original)
+++ directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/DirectoryPartition.java Fri Feb  3 04:12:53 2006
@@ -17,6 +17,7 @@
 package org.apache.ldap.server.partition;
 
 
+import java.util.List;
 import java.util.Map;
 
 import javax.naming.Context;
@@ -261,4 +262,28 @@
      */
     void move( Name oldName, Name newParentName, String newRn,
                boolean deleteOldRn ) throws NamingException;
+    
+    /**
+     * Represents a bind operation issued to authenticate a client.  Partitions
+     * need not support this operation.  This operation is here to enable those
+     * interested in implementing virtual directories with ApacheDS.
+     * 
+     * @param bindDn the normalized dn of the principal 
+     * @param credentials the credentials of the principal
+     * @param mechanisms the mechanisms requested by the JNDI caller or a single
+     * mechanism representing the SASL bind mechanism used by a networked client (Strings)
+     * @param saslAuthId the SASL authentication (may be null)
+     * @throws NamingException if something goes wrong
+     */
+    void bind( Name bindDn, byte[] credentials, List mechanisms, String saslAuthId ) throws NamingException;
+
+    /**
+     * Represents an unbind operation issued by an authenticated client.  Partitions
+     * need not support this operation.  This operation is here to enable those
+     * interested in implementing virtual directories with ApacheDS.
+     * 
+     * @param bindDn the normalized dn of the principal attempting to unbind
+     * @throws NamingException if something goes wrong
+     */
+    void unbind( Name bindDn ) throws NamingException;
 }

Modified: directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/DirectoryPartitionNexusProxy.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/DirectoryPartitionNexusProxy.java?rev=374649&r1=374648&r2=374649&view=diff
==============================================================================
--- directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/DirectoryPartitionNexusProxy.java (original)
+++ directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/DirectoryPartitionNexusProxy.java Fri Feb  3 04:12:53 2006
@@ -615,6 +615,53 @@
     }
 
 
+    public void bind( Name bindDn, byte[] credentials, List mechanisms, String saslAuthId, Collection bypass ) 
+        throws NamingException
+    {
+        ensureStarted();
+        InvocationStack stack = InvocationStack.getInstance();
+        Object[] args = new Object[] { bindDn, credentials, mechanisms, saslAuthId };
+        stack.push( new Invocation( this, caller, "bind", args, bypass ) );
+        try
+        {
+            this.configuration.getInterceptorChain().bind( bindDn, credentials, mechanisms, saslAuthId );
+        }
+        finally
+        {
+            stack.pop();
+        }
+    }
+
+
+    public void unbind( Name bindDn, Collection bypass ) throws NamingException
+    {
+        ensureStarted();
+        InvocationStack stack = InvocationStack.getInstance();
+        Object[] args = new Object[] { bindDn };
+        stack.push( new Invocation( this, caller, "unbind", args, bypass ) );
+        try
+        {
+            this.configuration.getInterceptorChain().unbind( bindDn );
+        }
+        finally
+        {
+            stack.pop();
+        }
+    }
+
+    
+    public void bind( Name bindDn, byte[] credentials, List mechanisms, String saslAuthId ) throws NamingException
+    {
+        bind( bindDn, credentials, mechanisms, saslAuthId, null );
+    }
+
+
+    public void unbind( Name bindDn ) throws NamingException
+    {
+        unbind( bindDn, null );
+    }
+
+    
     public Attributes getRootDSE() throws NamingException
     {
         return getRootDSE( null );

Modified: directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/impl/btree/jdbm/JdbmDirectoryPartition.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/impl/btree/jdbm/JdbmDirectoryPartition.java?rev=374649&r1=374648&r2=374649&view=diff
==============================================================================
--- directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/impl/btree/jdbm/JdbmDirectoryPartition.java (original)
+++ directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/partition/impl/btree/jdbm/JdbmDirectoryPartition.java Fri Feb  3 04:12:53 2006
@@ -23,6 +23,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 import javax.naming.Name;
@@ -38,6 +39,7 @@
 import jdbm.recman.BaseRecordManager;
 import jdbm.recman.CacheRecordManager;
 
+import org.apache.ldap.common.exception.LdapAuthenticationNotSupportedException;
 import org.apache.ldap.common.exception.LdapNameNotFoundException;
 import org.apache.ldap.common.exception.LdapSchemaViolationException;
 import org.apache.ldap.common.message.LockableAttributeImpl;
@@ -1566,6 +1568,22 @@
             
             subAliasIdx.drop( ancestorId, targetId );
         }    
+    }
+
+    
+    public void bind( Name bindDn, byte[] credentials, List mechanisms, String saslAuthId ) throws NamingException
+    {
+        // does nothing
+        throw new LdapAuthenticationNotSupportedException( 
+            "Bind requests only tunnel down into partitions if there are no authenticators to handle the mechanism.\n" +
+            "Check to see if you have correctly configured authenticators for the server.",
+            ResultCodeEnum.AUTHMETHODNOTSUPPORTED );
+    }
+
+    
+    public void unbind( Name bindDn ) throws NamingException
+    {
+        // does nothing
     }
 }
 

Modified: directory/trunks/apacheds/core/src/test/java/org/apache/ldap/server/interceptor/InterceptorChainTest.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core/src/test/java/org/apache/ldap/server/interceptor/InterceptorChainTest.java?rev=374649&r1=374648&r2=374649&view=diff
==============================================================================
--- directory/trunks/apacheds/core/src/test/java/org/apache/ldap/server/interceptor/InterceptorChainTest.java (original)
+++ directory/trunks/apacheds/core/src/test/java/org/apache/ldap/server/interceptor/InterceptorChainTest.java Fri Feb  3 04:12:53 2006
@@ -416,6 +416,20 @@
             interceptors.add( this );
             next.move( oldName, newParentName, newRn, deleteOldRn );
         }
+
+
+        public void bind( NextInterceptor next, Name bindDn, byte[] credentials, List mechanisms, String saslAuthId ) throws NamingException
+        {
+            interceptors.add( this );
+            next.bind( bindDn, credentials, mechanisms, saslAuthId );
+        }
+
+
+        public void unbind( NextInterceptor next, Name bindDn ) throws NamingException
+        {
+            interceptors.add( this );
+            next.unbind( bindDn );
+        }
     }
 
 

Propchange: directory/trunks/apacheds/core/src/test/java/org/apache/ldap/server/jndi/LdapJndiPropertiesTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: directory/trunks/apacheds/protocols/ldap/src/main/java/org/apache/ldap/server/protocol/support/ExtendedHandler.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/protocols/ldap/src/main/java/org/apache/ldap/server/protocol/support/ExtendedHandler.java?rev=374649&r1=374648&r2=374649&view=diff
==============================================================================
--- directory/trunks/apacheds/protocols/ldap/src/main/java/org/apache/ldap/server/protocol/support/ExtendedHandler.java (original)
+++ directory/trunks/apacheds/protocols/ldap/src/main/java/org/apache/ldap/server/protocol/support/ExtendedHandler.java Fri Feb  3 04:12:53 2006
@@ -15,7 +15,7 @@
  *
  */
 package org.apache.ldap.server.protocol.support;
-
+ 
 
 import java.util.Collections;
 import java.util.HashMap;

Modified: directory/trunks/apacheds/protocols/ldap/src/main/java/org/apache/ldap/server/protocol/support/UnbindHandler.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/protocols/ldap/src/main/java/org/apache/ldap/server/protocol/support/UnbindHandler.java?rev=374649&r1=374648&r2=374649&view=diff
==============================================================================
--- directory/trunks/apacheds/protocols/ldap/src/main/java/org/apache/ldap/server/protocol/support/UnbindHandler.java (original)
+++ directory/trunks/apacheds/protocols/ldap/src/main/java/org/apache/ldap/server/protocol/support/UnbindHandler.java Fri Feb  3 04:12:53 2006
@@ -20,6 +20,7 @@
 import javax.naming.NamingException;
 import javax.naming.ldap.LdapContext;
 
+import org.apache.ldap.server.jndi.ServerLdapContext;
 import org.apache.ldap.server.protocol.SessionRegistry;
 import org.apache.mina.common.IoSession;
 import org.apache.mina.handler.demux.MessageHandler;
@@ -46,9 +47,14 @@
 
         try
         {
-            LdapContext ctx = SessionRegistry.getSingleton().getLdapContext( session, null, false );
+            LdapContext ctx = ( LdapContext ) SessionRegistry.getSingleton().getLdapContext( session, null, false );
+            
             if ( ctx != null )
             {
+                if ( ctx instanceof ServerLdapContext && ( ( ServerLdapContext ) ctx ).getService().isStarted() )
+                {
+                    ( ( ServerLdapContext ) ctx ).ldapUnbind();
+                }
                 ctx.close();
             }
             registry.terminateSession( session );