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 2004/10/31 06:10:29 UTC

svn commit: rev 56121 - in incubator/directory/eve/trunk/backend/core: . src/java/org/apache/eve src/java/org/apache/eve/auth src/java/org/apache/eve/exception src/java/org/apache/eve/jndi src/java/org/apache/eve/jndi/exception src/java/org/apache/eve/jndi/ibs src/java/org/apache/eve/schema src/java/org/apache/eve/schema/bootstrap src/test/org/apache/eve/jndi

Author: akarasulu
Date: Sat Oct 30 22:10:29 2004
New Revision: 56121

Added:
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/auth/
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/auth/LdapPrincipal.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/exception/EveNoPermissionException.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/AuthenticationService.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/exception/EveAuthenticationException.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/exception/EveAuthenticationNotSupportedException.java
   incubator/directory/eve/trunk/backend/core/src/test/org/apache/eve/jndi/SimpleAuthenticationTest.java
Modified:
   incubator/directory/eve/trunk/backend/core/project.properties
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/SystemPartition.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveContext.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveContextFactory.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveDirContext.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveJndiProvider.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveLdapContext.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/ibs/OperationalAttributeService.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/ibs/SchemaService.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/schema/GlobalRegistries.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/schema/bootstrap/BootstrapRegistries.java
   incubator/directory/eve/trunk/backend/core/src/test/org/apache/eve/jndi/AbstractJndiTest.java
   incubator/directory/eve/trunk/backend/core/src/test/org/apache/eve/jndi/EveContextFactoryTest.java
Log:
Changes ...

 o introduced authentication service interceptor
 o added new field for the authenticated Principal to EveContext
 o authentication service removes creds from env after successful auth
 o implemented several test cases for authentication handling policies
 o added new bootstrap property for enabling anonymous use
 o enabled automatic creation of the admin account on db building 
   first time bootstrap attempts
 o heavily cleaned up context implementations
 o context constructors now just take a Name instead of LdapName arg
 o a special context constructor also takes the principal for propagating
   the principal across JNDI contexts created by the same user
 o new LdapPrincipal - was using X500Principal but this had some serious
   issues: basically it capitalized all attribute names but we need a 
   fully normalized name
 o corrected misspelling of isHumanReadible()
 o added some extra aspectj properties to play
 o added authentication service to the before pipeline

Notes ...

 o phew lots of major changes here 
 o test cases working but we need more to confirm correct operation
 o we really need to document all this once done - it's a must



Modified: incubator/directory/eve/trunk/backend/core/project.properties
==============================================================================
--- incubator/directory/eve/trunk/backend/core/project.properties	(original)
+++ incubator/directory/eve/trunk/backend/core/project.properties	Sat Oct 30 22:10:29 2004
@@ -1,18 +1,15 @@
 maven.junit.fork=yes
 
-maven.javadoc.private=true
+#maven.javadoc.private=true
 maven.javadoc.overview=src/java/org/apache/eve/schema/overview.html
-maven.javadoc.customtags=tag1 tag2
 
-tag1.name=todo
-tag1.description=To Do:
-tag1.enabled=true
-tag1.scope=all
+# AspectJ Properties
+# =======================
+
+#maven.aspectj.verbose=true
+#maven.aspectj.incremental=true
+maven.aspectj.time=true
 
-tag2.name=task
-tag2.description=Task:
-tag2.enabled=false
-tag2.scope=all
 
 # schema class generation
 # =======================

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/SystemPartition.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/SystemPartition.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/SystemPartition.java	Sat Oct 30 22:10:29 2004
@@ -42,7 +42,8 @@
 public final class SystemPartition extends AbstractContextPartition
 {
     /** the default user principal or DN */
-    public final static String DEFAULT_PRINCIPAL = "uid=admin,ou=system";
+    public final static String ADMIN_PRINCIPAL = "uid=admin,ou=system";
+    public final static String ADMIN_UID = "admin";
 
     /**
      * System backend suffix constant.  Should be kept down to a single Dn name 
@@ -98,7 +99,7 @@
             attributes = new LockableAttributesImpl() ;
             attributes.put( "objectClass", "top" ) ;
             attributes.put( "objectClass", "organizationalUnit" ) ;
-            attributes.put( "creatorsName", DEFAULT_PRINCIPAL ) ;
+            attributes.put( "creatorsName", ADMIN_PRINCIPAL ) ;
             attributes.put( "createTimestamp", DateUtils.getGeneralizedTime() ) ;
             attributes.put( NamespaceTools.getRdnAttribute( SUFFIX ),
                 NamespaceTools.getRdnValue( SUFFIX ) ) ;

Added: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/auth/LdapPrincipal.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/auth/LdapPrincipal.java	Sat Oct 30 22:10:29 2004
@@ -0,0 +1,86 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.eve.auth;
+
+
+import javax.naming.Name;
+import java.security.Principal;
+
+import org.apache.ldap.common.name.LdapName;
+
+
+/**
+ * An alternative X500 user implementation that has access to the distinguished
+ * name of the principal as well as the String representation.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class LdapPrincipal implements Principal
+{
+    /** the normalized distinguished name of the principal */
+    private final Name name;
+    /** the no name anonymous user whose DN is the empty String */
+    public static final Principal ANONYMOUS = new LdapPrincipal();
+
+
+    /**
+     * Creates a new LDAP/X500 principal.
+     *
+     * @param name the normalized distinguished name of the principal
+     */
+    public LdapPrincipal( Name name )
+    {
+        this.name = name;
+    }
+
+
+    /**
+     * Creates a principal for the no name anonymous user whose DN is the empty
+     * String.
+     */
+    private LdapPrincipal()
+    {
+        this.name = new LdapName();
+    }
+
+
+
+    /**
+     * Gets a cloned copy of the normalized distinguished name of this
+     * principal as a JNDI Name.  It must be cloned to protect this Principal
+     * from alteration.
+     *
+     * @return the normalized distinguished name of the principal as a JNDI Name
+     */
+    public Name getDn()
+    {
+        return ( Name ) name.clone();
+    }
+
+
+    /**
+     * Gets the normalized distinguished name of the principal as a String.
+     *
+     * @see Principal#getName()
+     * @return
+     */
+    public String getName()
+    {
+        return name.toString();
+    }
+}

Added: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/exception/EveNoPermissionException.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/exception/EveNoPermissionException.java	Sat Oct 30 22:10:29 2004
@@ -0,0 +1,64 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.eve.exception;
+
+
+import javax.naming.NoPermissionException;
+
+import org.apache.ldap.common.message.ResultCodeEnum;
+
+
+/**
+ * A NoPermissionException which associates a resultCode namely the
+ * {@link ResultCodeEnum#INSUFFICIENTACCESSRIGHTS} resultCode with the exception.
+ *
+ * @see EveException
+ * @see NoPermissionException
+ * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class EveNoPermissionException extends NoPermissionException
+        implements EveException
+{
+    /**
+     * @see NoPermissionException#NoPermissionException()
+     */
+    public EveNoPermissionException()
+    {
+        super();
+    }
+
+
+    /**
+     * @see NoPermissionException#NoPermissionException(String)
+     */
+    public EveNoPermissionException( String explanation )
+    {
+        super( explanation );
+    }
+
+
+    /**
+     * Always returns {@link ResultCodeEnum#INSUFFICIENTACCESSRIGHTS}
+     *
+     * @see EveException#getResultCode()
+     */
+    public ResultCodeEnum getResultCode()
+    {
+        return ResultCodeEnum.INSUFFICIENTACCESSRIGHTS;
+    }
+}

Added: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/AuthenticationService.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/AuthenticationService.java	Sat Oct 30 22:10:29 2004
@@ -0,0 +1,242 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.eve.jndi;
+
+
+import java.util.Hashtable;
+import java.io.IOException;
+import javax.naming.NamingException;
+import javax.naming.Context;
+import javax.naming.ConfigurationException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.Attribute;
+
+import org.apache.eve.RootNexus;
+import org.apache.eve.SystemPartition;
+import org.apache.eve.auth.LdapPrincipal;
+import org.apache.eve.exception.EveNoPermissionException;
+import org.apache.eve.exception.EveNamingException;
+import org.apache.eve.jndi.exception.EveAuthenticationNotSupportedException;
+import org.apache.eve.jndi.exception.EveNameNotFoundException;
+import org.apache.eve.jndi.exception.EveAuthenticationException;
+import org.apache.ldap.common.message.ResultCodeEnum;
+import org.apache.ldap.common.util.ArrayUtils;
+import org.apache.ldap.common.name.LdapName;
+import org.apache.ldap.common.name.NameComponentNormalizer;
+import org.apache.ldap.common.name.DnParser;
+
+
+/**
+ * A service used to for authenticating users.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class AuthenticationService implements Interceptor
+{
+
+    private static final String TYPE = Context.SECURITY_AUTHENTICATION;
+    private static final String PRINCIPAL = Context.SECURITY_PRINCIPAL;
+    private static final String ADMIN = SystemPartition.ADMIN_PRINCIPAL;
+
+    /** the root nexus to all database partitions */
+    private final RootNexus nexus;
+    /** whether or not to allow anonymous users */
+    private boolean allowAnonymous = false;
+    /** the normalizing DnParser to use while parsing names */
+    private final DnParser parser;
+
+
+    /**
+     * Creates an authentication service interceptor.
+     *
+     * @param nexus the root nexus to access all database partitions
+     */
+    public AuthenticationService( RootNexus nexus, NameComponentNormalizer normalizer,
+                                  boolean allowAnonymous ) throws EveNamingException
+    {
+        this.nexus = nexus;
+        this.allowAnonymous = allowAnonymous;
+        try
+        {
+            this.parser = new DnParser( normalizer );
+        }
+        catch ( IOException e )
+        {
+            EveNamingException ene = new EveNamingException( ResultCodeEnum.OTHER );
+            ene.setRootCause( e );
+            throw ene;
+        }
+    }
+
+
+    public void invoke( Invocation invocation ) throws NamingException
+    {
+        if ( invocation.getState() != InvocationStateEnum.PREINVOCATION )
+        {
+            return;
+        }
+
+        EveContext ctx = ( EveLdapContext ) invocation.getContextStack().peek();
+        if ( ctx.getPrincipal() != null )
+        {
+            if ( ctx.getEnvironment().containsKey( Context.SECURITY_CREDENTIALS ) )
+            {
+                ctx.removeFromEnvironment( Context.SECURITY_CREDENTIALS );
+            }
+
+            return;
+        }
+
+        String principal = getPrincipal( ctx.getEnvironment() );
+
+        if ( principal.length() == 0 )
+        {
+            if ( allowAnonymous )
+            {
+                ctx.setPrincipal( LdapPrincipal.ANONYMOUS );
+                return;
+            }
+            else
+            {
+                throw new EveNoPermissionException( "" );
+            }
+        }
+
+        Object creds = ctx.getEnvironment().get( Context.SECURITY_CREDENTIALS );
+        if ( creds == null )
+        {
+            creds = ArrayUtils.EMPTY_BYTE_ARRAY;
+        }
+        else if ( creds instanceof String )
+        {
+            creds = ( ( String ) creds ).getBytes();
+        }
+
+        LdapName principalDn = new LdapName( principal );
+        Attributes userEntry = nexus.lookup( principalDn );
+        if ( userEntry == null )
+        {
+            throw new EveNameNotFoundException();
+        }
+
+        Object userPassword;
+        Attribute userPasswordAttr = userEntry.get( "userPassword" );
+        if ( userPasswordAttr == null )
+        {
+            userPassword = ArrayUtils.EMPTY_BYTE_ARRAY;
+        }
+        else
+        {
+            userPassword = userPasswordAttr.get();
+            if ( userPassword instanceof String )
+            {
+                userPassword = ( ( String ) userPassword ).getBytes();
+            }
+        }
+
+        if ( ! ArrayUtils.isEquals( creds, userPassword ) )
+        {
+            throw new EveAuthenticationException();
+        }
+
+        synchronized( parser )
+        {
+            ctx.setPrincipal( new LdapPrincipal( parser.parse( principal ) ) );
+        }
+
+        // remove creds so there is no security risk
+        ctx.removeFromEnvironment( Context.SECURITY_CREDENTIALS );
+    }
+
+
+    /**
+     * Gets the effective principal associated with a JNDI context's environment.
+     *
+     * @param env the JNDI Context environment
+     * @return the effective principal
+     * @throws NamingException if certain properties are not present or present
+     * in wrong values or present in the wrong combinations
+     */
+    private String getPrincipal( Hashtable env ) throws NamingException
+    {
+        if ( "strong".equalsIgnoreCase( ( String ) env.get( TYPE ) ) )
+        {
+            throw new EveAuthenticationNotSupportedException( ResultCodeEnum.AUTHMETHODNOTSUPPORTED );
+        }
+
+        // --------------------------------------------------------------------
+        // if both the authtype and principal keys not defined then the
+        // princial is set to the admin user for the system
+        // --------------------------------------------------------------------
+        if ( ! env.containsKey( TYPE ) && ! env.containsKey( PRINCIPAL ) )
+        {
+            return SystemPartition.ADMIN_PRINCIPAL;
+        }
+
+        // the authtype is set but the principal is not
+        if ( env.containsKey( TYPE ) && ! env.containsKey( PRINCIPAL ) )
+        {
+            Object val = env.get( TYPE );
+
+            // princial is set to the anonymous user if authType is "none"
+            if ( "none".equalsIgnoreCase( ( String ) val ) )
+            {
+                return "";
+            }
+            // princial is set to the admin user if authType is "simple"
+            else if ( "simple".equalsIgnoreCase( ( String ) val ) )
+            {
+                return ADMIN;
+            }
+
+            // blow chuncks if we see any other authtype values
+            throw new ConfigurationException( "Unknown value for property " + TYPE + ": " + val );
+        }
+
+        // both are set
+        if ( env.containsKey( TYPE ) && env.containsKey( PRINCIPAL ) )
+        {
+            Object val = env.get( TYPE );
+
+            // princial is set to the anonymous user if authType is "none"
+            if ( "none".equalsIgnoreCase( ( String ) val ) )
+            {
+                String msg = "Ambiguous configuration: " + TYPE;
+                msg += " is set to none and the security principal";
+                msg += " is set using " + PRINCIPAL + " as well";
+                throw new ConfigurationException( msg );
+            }
+            // princial is set to the admin user if authType is "simple"
+            else if ( "simple".equalsIgnoreCase( ( String ) val ) )
+            {
+                return ( String ) env.get( PRINCIPAL );
+            }
+
+            // blow chuncks if we see any other authtype values
+            throw new ConfigurationException( "Unknown value for property " + TYPE + ": " + val );
+        }
+
+        // we have the principal key so we set that as the value
+        if ( env.containsKey( PRINCIPAL ) )
+        {
+            return ( String ) env.get( PRINCIPAL );
+        }
+
+        return ADMIN;
+    }
+}

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveContext.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveContext.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveContext.java	Sat Oct 30 22:10:29 2004
@@ -17,22 +17,18 @@
 package org.apache.eve.jndi;
 
 
-import java.util.Hashtable ;
+import java.util.Hashtable;
+import java.security.Principal;
 
-import javax.naming.Name ;
-import javax.naming.Context ;
-import javax.naming.NameParser ;
-import javax.naming.ldap.Control ;
-import javax.naming.NamingException ;
-import javax.naming.NamingEnumeration ;
-import javax.naming.directory.Attributes ;
-import javax.naming.InvalidNameException ;
-import javax.naming.directory.SearchControls ;
-
-import org.apache.ldap.common.name.LdapName ;
-import org.apache.ldap.common.filter.PresenceNode ;
-import org.apache.ldap.common.util.NamespaceTools ;
-import org.apache.ldap.common.message.LockableAttributesImpl ;
+import javax.naming.*;
+import javax.naming.ldap.Control;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.SearchControls;
+
+import org.apache.ldap.common.name.LdapName;
+import org.apache.ldap.common.filter.PresenceNode;
+import org.apache.ldap.common.util.NamespaceTools;
+import org.apache.ldap.common.message.LockableAttributesImpl;
 
 import org.apache.eve.PartitionNexus;
 
@@ -46,15 +42,17 @@
 public abstract class EveContext implements Context
 {
     /** */
-    public static final String DELETE_OLD_RDN_PROP = "java.naming.ldap.deleteRDN" ;
+    public static final String DELETE_OLD_RDN_PROP = "java.naming.ldap.deleteRDN";
 
     /** The interceptor proxy to the backend nexus */
-    private final PartitionNexus nexusProxy ;
+    private final PartitionNexus nexusProxy;
     /** The cloned environment used by this Context */
-    private final Hashtable env ;
+    private final Hashtable env;
     /** The distinguished name of this Context */
-    private final LdapName dn ;
-    
+    private final LdapName dn;
+    /** The Principal associated with this context */
+    private Principal principal;
+
 
     // ------------------------------------------------------------------------
     // Constructors
@@ -63,7 +61,12 @@
 
     /**
      * Must be called by all subclasses to initialize the nexus proxy and the
-     * environment settings to be used by this Context implementation.
+     * environment settings to be used by this Context implementation.  This
+     * specific contstructor relies on the presence of the {@link
+     * Context#PROVIDER_URL} key and value to determine the distinguished name
+     * of the newly created context.  It also checks to make sure the
+     * referenced name actually exists within the system.  This constructor
+     * is used for all InitialContext requests.
      * 
      * @param nexusProxy the intercepting proxy to the nexus.
      * @param env the environment properties used by this context.
@@ -72,40 +75,82 @@
      */
     protected EveContext( PartitionNexus nexusProxy, Hashtable env ) throws NamingException
     {
-        this.nexusProxy = nexusProxy ;
-        this.env = ( Hashtable ) env.clone() ;
-        
-        if ( null == env.get( PROVIDER_URL ) )
+        String url;
+
+        // set references to cloned env and the proxy
+        this.nexusProxy = nexusProxy;
+        this.env = ( Hashtable ) env.clone();
+
+        /* --------------------------------------------------------------------
+         * 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 ) )
         {
-            throw new NamingException( PROVIDER_URL + " property not found in environment." ) ;
+            throw new ConfigurationException( "Expected property "
+                    + Context.PROVIDER_URL + " but could not find it in env!" );
         }
-        
 
-        /*
-         * TODO Make sure we can handle URLs here as well as simple DNs
-         * The PROVIDER_URL is interpreted as just a entry Dn since we are 
-         * within the server.  However this may change in the future if we 
-         * want to convey the listener from which the protocol originating
-         * requests are comming from.
-         */
-        dn = new LdapName( ( String ) env.get( PROVIDER_URL ) ) ;
+        url = ( String ) env.get( Context.PROVIDER_URL );
+        if ( url == null )
+        {
+            throw new ConfigurationException( "Expected value for property "
+                    + Context.PROVIDER_URL + " but it was set to null in env!" );
+        }
+
+        dn = new LdapName( url );
+        if ( ! nexusProxy.hasEntry( dn ) )
+        {
+            throw new NameNotFoundException( dn + " does not exist" );
+        }
     }
 
 
     /**
      * Must be called by all subclasses to initialize the nexus proxy and the
-     * environment settings to be used by this Context implementation.
-     * 
+     * environment settings to be used by this Context implementation.  This
+     * constructor is used to propagate new contexts from existing contexts.
+     *
+     * @param principal the directory user principal that is propagated
      * @param nexusProxy the intercepting proxy to the nexus
      * @param env the environment properties used by this context
      * @param dn the distinguished name of this context
      */
-    protected EveContext( PartitionNexus nexusProxy, Hashtable env, LdapName dn )
+    protected EveContext( Principal principal, PartitionNexus nexusProxy,
+                          Hashtable env, Name dn )
+    {
+        this.dn = ( LdapName ) dn.clone();
+        this.env = ( Hashtable ) env.clone();
+        this.env.put( PROVIDER_URL, dn.toString() );
+        this.nexusProxy = nexusProxy;
+        this.principal = principal;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // New Impl Specific Public Methods
+    // ------------------------------------------------------------------------
+
+
+    /**
+     * Gets the principal of the authenticated user which also happens to own
+     * @return
+     */
+    public Principal getPrincipal()
+    {
+        return principal;
+    }
+
+
+    /**
+     * Package friendly setter to alter the principal.  It is very important
+     * for security's sake to keep this package friendly and not public.
+     *
+     * @param principal the directory user principal
+     */
+    void setPrincipal( Principal principal )
     {
-        this.dn = ( LdapName ) dn.clone() ;
-        this.env = ( Hashtable ) env.clone() ;
-        this.env.put( PROVIDER_URL, dn.toString() ) ;
-        this.nexusProxy = nexusProxy ;
+        this.principal = principal;
     }
 
 
@@ -121,7 +166,7 @@
      */
     protected PartitionNexus getNexusProxy()
     {
-       return nexusProxy  ;
+       return nexusProxy ;
     }
     
     
@@ -132,7 +177,7 @@
      */
     protected Name getDn()
     {
-        return dn ;
+        return dn;
     }
 
 
@@ -155,16 +200,16 @@
      */
     public String getNameInNamespace() throws NamingException
     {
-        return dn.toString() ;
+        return dn.toString();
     }
 
 
     /**
      * @see javax.naming.Context#getEnvironment()
      */
-    public Hashtable getEnvironment() throws NamingException
+    public Hashtable getEnvironment()
     {
-        return env ;
+        return env;
     }
 
 
@@ -174,7 +219,7 @@
      */
     public Object addToEnvironment( String propName, Object propVal ) throws NamingException
     {
-        return env.put( propName, propVal ) ;
+        return env.put( propName, propVal );
     }
 
 
@@ -183,7 +228,7 @@
      */
     public Object removeFromEnvironment( String propName ) throws NamingException
     {
-        return env.remove( propName ) ;
+        return env.remove( propName );
     }
 
 
@@ -192,7 +237,7 @@
      */
     public Context createSubcontext( String name ) throws NamingException
     {
-        return createSubcontext( new LdapName( name ) ) ;
+        return createSubcontext( new LdapName( name ) );
     }
 
 
@@ -211,11 +256,11 @@
          * 
          * TODO Add multivalued RDN handling code 
          */
-        Attributes attributes = new LockableAttributesImpl() ;
-        LdapName target = buildTarget( name ) ;
-        String rdn = name.get( name.size() - 1 ) ;
-        String rdnAttribute = NamespaceTools.getRdnAttribute( rdn ) ;
-        String rdnValue = NamespaceTools.getRdnValue( rdn ) ;
+        Attributes attributes = new LockableAttributesImpl();
+        LdapName target = buildTarget( name );
+        String rdn = name.get( name.size() - 1 );
+        String rdnAttribute = NamespaceTools.getRdnAttribute( rdn );
+        String rdnValue = NamespaceTools.getRdnValue( rdn );
 
         /* 
          * TODO Add code within the interceptor service managing operational
@@ -223,11 +268,11 @@
          * attributes before normalization.  The result should have ths same
          * affect as the following line within the interceptor.
          * 
-         * attributes.put( BootstrapSchema.DN_ATTR, target.toString() ) ;
+         * attributes.put( BootstrapSchema.DN_ATTR, target.toString() );
          */
-        attributes.put( rdnAttribute, rdnValue ) ;
-        attributes.put( JavaLdapSupport.OBJECTCLASS_ATTR, JavaLdapSupport.JCONTAINER_ATTR ) ;
-        attributes.put( JavaLdapSupport.OBJECTCLASS_ATTR, JavaLdapSupport.TOP_ATTR ) ;
+        attributes.put( rdnAttribute, rdnValue );
+        attributes.put( JavaLdapSupport.OBJECTCLASS_ATTR, JavaLdapSupport.JCONTAINER_ATTR );
+        attributes.put( JavaLdapSupport.OBJECTCLASS_ATTR, JavaLdapSupport.TOP_ATTR );
         
         /*
          * Add the new context to the server which as a side effect adds 
@@ -236,12 +281,12 @@
          * we need to copy over the controls as well to propagate the complete 
          * environment besides whats in the hashtable for env.
          */
-        nexusProxy.add( target.toString(), target, attributes ) ;
+        nexusProxy.add( target.toString(), target, attributes );
         
-        EveLdapContext ctx = new EveLdapContext( nexusProxy, env, target ) ;
-        Control [] controls = ( Control [] ) ( ( EveLdapContext ) this ).getRequestControls().clone() ;
-        ctx.setRequestControls( controls ) ;
-        return ctx ;
+        EveLdapContext ctx = new EveLdapContext( principal, nexusProxy, env, target );
+        Control [] controls = ( Control [] ) ( ( EveLdapContext ) this ).getRequestControls().clone();
+        ctx.setRequestControls( controls );
+        return ctx;
     }
 
 
@@ -250,7 +295,7 @@
      */
     public void destroySubcontext( String name ) throws NamingException
     {
-        destroySubcontext( new LdapName( name ) ) ;
+        destroySubcontext( new LdapName( name ) );
     }
 
 
@@ -259,8 +304,8 @@
      */
     public void destroySubcontext( Name name ) throws NamingException
     {
-        Name target = buildTarget( name ) ;
-        nexusProxy.delete( target ) ;
+        Name target = buildTarget( name );
+        nexusProxy.delete( target );
     }
 
 
@@ -269,7 +314,7 @@
      */
     public void bind( String name, Object obj ) throws NamingException
     {
-        bind( new LdapName( name ), obj ) ;
+        bind( new LdapName( name ), obj );
     }
     
 
@@ -280,7 +325,7 @@
     {
         if ( obj instanceof EveLdapContext )
         {
-            throw new IllegalArgumentException( "Cannot bind a directory context object!" ) ;
+            throw new IllegalArgumentException( "Cannot bind a directory context object!" );
         }
 
         /* 
@@ -293,12 +338,12 @@
          * 
          * TODO Add multivalued RDN handling code 
          */
-        Attributes attributes = new LockableAttributesImpl() ;
-        Name target = buildTarget( name ) ;
+        Attributes attributes = new LockableAttributesImpl();
+        Name target = buildTarget( name );
 
         // Serialize object into entry attributes and add it.
-        JavaLdapSupport.serialize( attributes, obj ) ;
-        nexusProxy.add( target.toString(), target, attributes ) ;
+        JavaLdapSupport.serialize( attributes, obj );
+        nexusProxy.add( target.toString(), target, attributes );
     }
 
 
@@ -308,7 +353,7 @@
     public void rename( String oldName, String newName )
         throws NamingException
     {
-        rename( new LdapName( oldName ), new LdapName( newName ) ) ;
+        rename( new LdapName( oldName ), new LdapName( newName ) );
     }
 
 
@@ -317,15 +362,15 @@
      */
     public void rename( Name oldName, Name newName ) throws NamingException
     {
-        Name oldDn = buildTarget( oldName ) ;
-        Name newDn = buildTarget( newName ) ;
-        Name oldBase = oldName.getSuffix( 1 ) ;
-        Name newBase = newName.getSuffix( 1 ) ;
+        Name oldDn = buildTarget( oldName );
+        Name newDn = buildTarget( newName );
+        Name oldBase = oldName.getSuffix( 1 );
+        Name newBase = newName.getSuffix( 1 );
 
-        String newRdn = newName.get( newName.size() - 1 ) ;
-        String oldRdn = oldName.get( oldName.size() - 1 ) ;
+        String newRdn = newName.get( newName.size() - 1 );
+        String oldRdn = oldName.get( oldName.size() - 1 );
                 
-        boolean delOldRdn = true ;
+        boolean delOldRdn = true;
             
         /*
          * Attempt to use the java.naming.ldap.deleteRDN environment property
@@ -333,10 +378,10 @@
          */
         if ( null != env.get( DELETE_OLD_RDN_PROP ) )
         {
-            String delOldRdnStr = ( String ) env.get( DELETE_OLD_RDN_PROP ) ;
+            String delOldRdnStr = ( String ) env.get( DELETE_OLD_RDN_PROP );
             delOldRdn = ! ( delOldRdnStr.equals( "false" ) ||
                 delOldRdnStr.equals( "no" ) ||
-                delOldRdnStr.equals( "0" ) ) ;
+                delOldRdnStr.equals( "0" ) );
         }
 
         /*
@@ -349,19 +394,19 @@
          */
         if ( oldName.size() == newName.size() && oldBase.equals( newBase ) )
         {
-            nexusProxy.modifyRn( oldDn, newRdn, delOldRdn ) ;
+            nexusProxy.modifyRn( oldDn, newRdn, delOldRdn );
         }
         else
         {
-            Name parent = newDn.getSuffix( 1 ) ;
+            Name parent = newDn.getSuffix( 1 );
             
             if ( newRdn.equalsIgnoreCase( oldRdn ) )
             {
-                nexusProxy.move( oldDn, parent ) ;
+                nexusProxy.move( oldDn, parent );
             }
             else
             {
-                nexusProxy.move( oldDn, parent, newRdn, delOldRdn ) ;
+                nexusProxy.move( oldDn, parent, newRdn, delOldRdn );
             }
         }
     }
@@ -372,7 +417,7 @@
      */
     public void rebind( String name, Object obj ) throws NamingException
     {
-        rebind( new LdapName( name ), obj ) ;
+        rebind( new LdapName( name ), obj );
     }
 
 
@@ -381,14 +426,14 @@
      */
     public void rebind( Name name, Object obj ) throws NamingException
     {
-        Name target = buildTarget( name ) ;
+        Name target = buildTarget( name );
 
         if ( nexusProxy.hasEntry( target ) )
         {
-            nexusProxy.delete( target ) ;
+            nexusProxy.delete( target );
         }
 
-        bind( name, obj ) ;
+        bind( name, obj );
     }
 
 
@@ -397,7 +442,7 @@
      */
     public void unbind( String name ) throws NamingException
     {
-        unbind( new LdapName( name ) ) ;
+        unbind( new LdapName( name ) );
     }
 
 
@@ -406,7 +451,7 @@
      */
     public void unbind( Name name ) throws NamingException
     {
-        nexusProxy.delete( buildTarget( name ) ) ;
+        nexusProxy.delete( buildTarget( name ) );
     }
 
 
@@ -415,7 +460,7 @@
      */
     public Object lookup( String name ) throws NamingException
     {
-        return lookup( new LdapName( name ) ) ;
+        return lookup( new LdapName( name ) );
     }
 
 
@@ -424,27 +469,27 @@
      */
     public Object lookup( Name name ) throws NamingException
     {
-        LdapName target = buildTarget( name ) ;
-        Attributes attributes = nexusProxy.lookup( target ) ;
+        LdapName target = buildTarget( name );
+        Attributes attributes = nexusProxy.lookup( target );
         
         // First lets test and see if the entry is a serialized java object
         if ( attributes.get( JavaLdapSupport.JCLASSNAME_ATTR ) != null )
         {
             // Give back serialized object and not a context
-            return JavaLdapSupport.deserialize( attributes ) ;
+            return JavaLdapSupport.deserialize( attributes );
         }
         
         // Initialize and return a context since the entry is not a java object
-        EveLdapContext ctx = new EveLdapContext( nexusProxy, env, target ) ;
+        EveLdapContext ctx = new EveLdapContext( principal, nexusProxy, env, target );
             
         // Need to add controls to propagate extended ldap operational env
-        Control [] controls = ( ( EveLdapContext ) this ).getRequestControls() ;
+        Control [] controls = ( ( EveLdapContext ) this ).getRequestControls();
         if ( null != controls )
         {    
-            ctx.setRequestControls( ( Control [] ) controls.clone() ) ;
+            ctx.setRequestControls( ( Control [] ) controls.clone() );
         }
         
-        return ctx ;
+        return ctx;
     }
 
 
@@ -453,7 +498,7 @@
      */
     public Object lookupLink( String name ) throws NamingException
     {
-        throw new UnsupportedOperationException() ;
+        throw new UnsupportedOperationException();
     }
 
 
@@ -462,7 +507,7 @@
      */
     public Object lookupLink( Name name ) throws NamingException
     {
-        throw new UnsupportedOperationException() ;
+        throw new UnsupportedOperationException();
     }
 
 
@@ -476,7 +521,7 @@
      */
     public NameParser getNameParser( String name ) throws NamingException
     {
-        return LdapName.getNameParser() ;
+        return LdapName.getNameParser();
     }
 
 
@@ -490,7 +535,7 @@
      */
     public NameParser getNameParser( Name name ) throws NamingException
     {
-        return LdapName.getNameParser() ;
+        return LdapName.getNameParser();
     }
 
 
@@ -499,7 +544,7 @@
      */
     public NamingEnumeration list( String name ) throws NamingException
     {
-        return list( new LdapName( name ) ) ;
+        return list( new LdapName( name ) );
     }
 
 
@@ -508,7 +553,7 @@
      */
     public NamingEnumeration list( Name name ) throws NamingException
     {
-        return nexusProxy.list( buildTarget( name ) ) ;
+        return nexusProxy.list( buildTarget( name ) );
     }
 
 
@@ -517,7 +562,7 @@
      */
     public NamingEnumeration listBindings( String name ) throws NamingException
     {
-        return listBindings( new LdapName( name ) ) ;
+        return listBindings( new LdapName( name ) );
     }
 
 
@@ -527,12 +572,12 @@
     public NamingEnumeration listBindings( Name name ) throws NamingException
     {
         // Conduct a special one level search at base for all objects
-        Name base = buildTarget( name ) ;
-        PresenceNode filter = new PresenceNode( "objectClass" ) ;
-        SearchControls ctls = new SearchControls() ;
-        ctls.setSearchScope( SearchControls.ONELEVEL_SCOPE ) ;
+        Name base = buildTarget( name );
+        PresenceNode filter = new PresenceNode( "objectClass" );
+        SearchControls ctls = new SearchControls();
+        ctls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
 
-        return nexusProxy.search( base , getEnvironment(), filter, ctls ) ;
+        return nexusProxy.search( base , getEnvironment(), filter, ctls );
     }
 
 
@@ -541,7 +586,7 @@
      */
     public String composeName( String name, String prefix ) throws NamingException
     {
-        return composeName( new LdapName( name ), new LdapName( prefix ) ).toString() ;
+        return composeName( new LdapName( name ), new LdapName( prefix ) ).toString();
     }
 
 
@@ -555,7 +600,7 @@
         // No prefix reduces to name, or the name relative to this context
         if ( prefix == null || prefix.size() == 0 )
         {
-            return name ;
+            return name;
         }
 
         /*
@@ -574,8 +619,8 @@
          */
          
         // 1). Find the Dn for name and walk it from the head to tail
-        Name fqn = buildTarget( name ) ;
-        String head = prefix.get( 0 ) ;
+        Name fqn = buildTarget( name );
+        String head = prefix.get( 0 );
         
         // 2). Walk the fqn trying to match for the head of the prefix
         while ( fqn.size() > 0 )
@@ -583,16 +628,16 @@
             // match found end loop
             if ( fqn.get( 0 ).equalsIgnoreCase( head ) )
             {
-                return fqn ;
+                return fqn;
             }
             else // 2). Remove name components from the Dn until a match 
             {
-                fqn.remove( 0 ) ;
+                fqn.remove( 0 );
             }
         }
         
         throw new NamingException( "The prefix '" + prefix
-                + "' is not an ancestor of this "  + "entry '" + dn + "'" ) ;
+                + "' is not an ancestor of this "  + "entry '" + dn + "'" );
     }
     
     
@@ -613,10 +658,10 @@
     LdapName buildTarget( Name relativeName ) throws InvalidNameException
     {
         // Clone our DN or absolute path
-        LdapName target = ( LdapName ) dn.clone() ;
+        LdapName target = ( LdapName ) dn.clone();
         
         // Add to left hand side of cloned DN the relative name arg
-        target.addAll( target.size(), relativeName ) ;
-        return target ;
+        target.addAll( target.size(), relativeName );
+        return target;
     }
 }

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveContextFactory.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveContextFactory.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveContextFactory.java	Sat Oct 30 22:10:29 2004
@@ -6,15 +6,19 @@
 import java.util.ArrayList;
 import java.io.File;
 
+import javax.naming.Name;
 import javax.naming.Context;
 import javax.naming.NamingException;
-import javax.naming.Name;
+import javax.naming.ConfigurationException;
 import javax.naming.directory.Attributes;
 import javax.naming.spi.InitialContextFactory;
 
 import org.apache.ldap.common.name.LdapName;
 import org.apache.ldap.common.schema.AttributeType;
 import org.apache.ldap.common.schema.Normalizer;
+import org.apache.ldap.common.message.LockableAttributesImpl;
+import org.apache.ldap.common.util.ArrayUtils;
+import org.apache.ldap.common.util.DateUtils;
 
 import org.apache.eve.RootNexus;
 import org.apache.eve.SystemPartition;
@@ -45,16 +49,25 @@
  */
 public class EveContextFactory implements InitialContextFactory
 {
+    // for convenience
+    private static final String TYPE = Context.SECURITY_AUTHENTICATION;
+    private static final String PRINCIPAL = Context.SECURITY_PRINCIPAL;
+    //private static final String ADMIN = SystemPartition.ADMIN_PRINCIPAL;
+
+    /** property used to shutdown the system */
     public static final String SHUTDOWN_OP_ENV = "eve.operation.shutdown";
+    /** property used to sync the system with disk */
     public static final String SYNC_OP_ENV = "eve.operation.sync";
     /** key base for a set of user indices provided as comma sep list of attribute names or oids */
     public static final String USER_INDICES_ENV_BASE = "eve.user.db.indices";
-    /** the path to eve's working directory - relative or absolute */
+    /** bootstrap prop: path to eve's working directory - relative or absolute */
     public static final String WKDIR_ENV = "eve.wkdir";
     /** default path to working directory if WKDIR_ENV property is not set */
     public static final String DEFAULT_WKDIR = "eve";
     /** a comma separated list of schema class files to load */
     public static final String SCHEMAS_ENV = "eve.schemas";
+    /** bootstrap prop: if key is present it enables anonymous users */
+    public static final String ANONYMOUS_ENV = "eve.enable.anonymous";
 
     // ------------------------------------------------------------------------
     //
@@ -85,7 +98,7 @@
     public static final String SUFFIX_BASE_ENV = "eve.db.partition.suffix.";
     /** the envprop key base to the space separated list of indices for a partition */
     public static final String INDICES_BASE_ENV = "eve.db.partition.indices.";
-    /** the envprop key base to the Attributes for the context root entry */
+    /** the envprop key base to the Attributes for the context nexus entry */
     public static final String ATTRIBUTES_BASE_ENV = "eve.db.partition.attributes.";
 
     // ------------------------------------------------------------------------
@@ -100,7 +113,7 @@
 
     private SystemPartition system;
     private GlobalRegistries globalRegistries;
-    private RootNexus root;
+    private RootNexus nexus;
 
 
     /**
@@ -148,10 +161,88 @@
         if ( null == provider )
         {
             this.initialEnv = env;
+
+            // check if we are trying to boostrap as another user
+            if ( initialEnv.containsKey( PRINCIPAL ) &&
+                 initialEnv.containsKey( TYPE ) &&
+                 initialEnv.get( TYPE ).equals( "none" ) )
+            {
+                String msg = "Ambiguous configuration: " + TYPE;
+                msg += " is set to none and the security principal";
+                msg += " is set using " + PRINCIPAL + " as well";
+                throw new ConfigurationException( msg );
+            }
+            else if ( ! initialEnv.containsKey( Context.SECURITY_PRINCIPAL ) &&
+                   initialEnv.containsKey( Context.SECURITY_AUTHENTICATION ) &&
+                   initialEnv.get( Context.SECURITY_AUTHENTICATION ).equals( "none" ) )
+            {
+                throw new ConfigurationException( "using authentication type none "
+                        + "for anonymous binds while trying to bootstrap Eve "
+                        + "- this is not allowed ONLY the admin can bootstrap" );
+            }
+            else if ( initialEnv.containsKey( Context.SECURITY_PRINCIPAL ) &&
+                      ! initialEnv.get( Context.SECURITY_PRINCIPAL ).equals( SystemPartition.ADMIN_PRINCIPAL ) )
+            {
+                throw new ConfigurationException( "user "
+                        + initialEnv.get( Context.SECURITY_PRINCIPAL )
+                        + " is not allowed to bootstrap the system. ONLY the "
+                        + "admin can bootstrap" );
+            }
+
             initialize();
+            createAdminAccount();
+        }
+
+        EveContext ctx = ( EveContext ) provider.getLdapContext( env );
+        return ctx;
+    }
+
+
+    /**
+     * Returns true if we had to create the admin account since this is the
+     * first time we started the server.  Otherwise if the account exists then
+     * we are not starting for the first time.
+     *
+     * @return
+     * @throws NamingException
+     */
+    private boolean createAdminAccount() throws NamingException
+    {
+        Name admin = new LdapName( SystemPartition.ADMIN_PRINCIPAL );
+
+        /*
+         * If the admin entry is there, then the database was already created
+         * before so we just need to lookup the userPassword field to see if
+         * the password matches.
+         */
+        if ( nexus.hasEntry( admin ) )
+        {
+            return false;
+        }
+
+        Attributes attributes = new LockableAttributesImpl();
+        attributes.put( "objectClass", "top" );
+        attributes.put( "objectClass", "person" );
+        attributes.put( "objectClass", "organizationalPerson" );
+        attributes.put( "objectClass", "inetOrgPerson" );
+        attributes.put( "uid", SystemPartition.ADMIN_UID );
+        attributes.put( "displayName", "Directory Superuser" );
+        attributes.put( "creatorsName", SystemPartition.ADMIN_PRINCIPAL );
+        attributes.put( "createTimestamp", DateUtils.getGeneralizedTime() );
+        attributes.put( "displayName", "Directory Superuser" );
+
+        if ( initialEnv.containsKey( Context.SECURITY_CREDENTIALS ) )
+        {
+            attributes.put( "userPassword", initialEnv.get(
+                    Context.SECURITY_CREDENTIALS ) );
         }
-        
-        return provider.getLdapContext( env );
+        else
+        {
+            attributes.put( "userPassword", ArrayUtils.EMPTY_BYTE_ARRAY );
+        }
+
+        nexus.add( SystemPartition.ADMIN_PRINCIPAL, admin, attributes );
+        return true;
     }
 
 
@@ -195,8 +286,7 @@
         {
             if ( ! wkdirFile.exists() )
             {
-                throw new NamingException( "working directory " +  wkdir
-                    + " does not exist" );
+                throw new NamingException( "working directory " +  wkdir + " does not exist" );
             }
         }
         else
@@ -234,8 +324,8 @@
 
         system = new SystemPartition( db, eng, attributes );
         globalRegistries = new GlobalRegistries( system, bootstrapRegistries );
-        root = new RootNexus( system );
-        provider = new EveJndiProvider( root );
+        nexus = new RootNexus( system );
+        provider = new EveJndiProvider( nexus );
 
 
         // --------------------------------------------------------------------
@@ -248,11 +338,18 @@
          * before and onError interceptor chains.
          */
         InvocationStateEnum[] state = new InvocationStateEnum[]{
-            InvocationStateEnum.POSTINVOCATION
+            InvocationStateEnum.PREINVOCATION
         };
-        Interceptor interceptor;
-        FilterService filterService =
-                new FilterServiceImpl();
+        boolean allowAnonymous = initialEnv.containsKey( ANONYMOUS_ENV );
+        Interceptor interceptor = new AuthenticationService( nexus, allowAnonymous );
+        provider.addInterceptor( interceptor, state );
+
+        /*
+         * Create and add the Eve Exception service interceptor to both the
+         * before and onError interceptor chains.
+         */
+        state = new InvocationStateEnum[]{ InvocationStateEnum.POSTINVOCATION };
+        FilterService filterService = new FilterServiceImpl();
         interceptor = ( Interceptor ) filterService;
         provider.addInterceptor( interceptor, state );
 
@@ -264,16 +361,14 @@
             InvocationStateEnum.PREINVOCATION,
             InvocationStateEnum.FAILUREHANDLING
         };
-        interceptor = new EveExceptionService( root );
+        interceptor = new EveExceptionService( nexus );
         provider.addInterceptor( interceptor, state );
 
         /*
          * Create and add the Eve schema service interceptor to before chain.
          */
-        state = new InvocationStateEnum[]{
-            InvocationStateEnum.PREINVOCATION
-        };
-        interceptor = new SchemaService( root, globalRegistries, filterService );
+        state = new InvocationStateEnum[]{ InvocationStateEnum.PREINVOCATION };
+        interceptor = new SchemaService( nexus, globalRegistries, filterService );
         provider.addInterceptor( interceptor, state );
 
         /*
@@ -284,10 +379,11 @@
             InvocationStateEnum.PREINVOCATION,
             InvocationStateEnum.POSTINVOCATION
         };
-        interceptor = new OperationalAttributeService( root, globalRegistries,
-                filterService );
+        interceptor = new OperationalAttributeService( nexus, globalRegistries, filterService );
         provider.addInterceptor( interceptor, state );
 
+
+        // fire up the app partitions now!
         if ( initialEnv.get( PARTITIONS_ENV ) != null )
         {
             initAppPartitions( wkdir );
@@ -315,7 +411,6 @@
             String wkdir = eveWkdir + File.separator + names[ii];
             mkdirs( eveWkdir, names[ii] );
 
-
             // ----------------------------------------------------------------
             // create the database/store
             // ----------------------------------------------------------------
@@ -371,10 +466,10 @@
                     .toArray( new AttributeType[attributeTypeList.size()] );
             ApplicationPartition partition = new ApplicationPartition( upSuffix,
                     normSuffix, db, eng, indexTypes );
-            root.register( partition );
+            nexus.register( partition );
 
             // ----------------------------------------------------------------
-            // add the root context entry
+            // add the nexus context entry
             // ----------------------------------------------------------------
 
             Attributes rootEntry = ( Attributes ) initialEnv.get(

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveDirContext.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveDirContext.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveDirContext.java	Sat Oct 30 22:10:29 2004
@@ -20,6 +20,7 @@
 import java.io.IOException;
 import java.util.Hashtable;
 import java.text.ParseException;
+import java.security.Principal;
 
 import javax.naming.Name;
 import javax.naming.ldap.Control;
@@ -75,14 +76,16 @@
     /**
      * Creates a new EveDirContext with a distinguished name which is used to
      * set the PROVIDER_URL to the distinguished name for this context.
-     * 
+     *
+     * @param principal the principal which is propagated
      * @param nexusProxy the intercepting proxy to the nexus
      * @param env the environment properties used by this context
      * @param dn the distinguished name of this context
      */
-    protected EveDirContext( PartitionNexus nexusProxy, Hashtable env, LdapName dn )
+    protected EveDirContext( Principal principal, PartitionNexus nexusProxy,
+                             Hashtable env, Name dn )
     {
-        super( nexusProxy, env, dn );
+        super( principal, nexusProxy, env, dn );
     }
 
 
@@ -291,7 +294,8 @@
         getNexusProxy().add( target.toString(), target, attributes );
 
         // Initialize the new context
-        EveLdapContext ctx = new EveLdapContext( getNexusProxy(), getEnvironment(), target );
+        EveLdapContext ctx = new EveLdapContext( getPrincipal(), getNexusProxy(),
+                getEnvironment(), target );
         
         Control [] controls = ( ( EveLdapContext ) this ).getRequestControls();
         if ( controls != null )

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveJndiProvider.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveJndiProvider.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveJndiProvider.java	Sat Oct 30 22:10:29 2004
@@ -113,14 +113,14 @@
     /**
      * @see org.apache.eve.EveBackendSubsystem#getLdapContext(Hashtable)
      */
-    public LdapContext getLdapContext( Hashtable aenv ) throws NamingException
+    public LdapContext getLdapContext( Hashtable env ) throws NamingException
     {
         if ( this.isShutdown )
         {
             throw new IllegalStateException( "Eve has been shutdown!" );
         }
 
-        return new EveLdapContext( proxy, aenv );
+        return new EveLdapContext( proxy, env );
     }
 
 

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveLdapContext.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveLdapContext.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/EveLdapContext.java	Sat Oct 30 22:10:29 2004
@@ -18,31 +18,40 @@
 
 
 import java.util.Hashtable;
+import java.security.Principal;
 
 import javax.naming.NamingException;
+import javax.naming.Name;
 import javax.naming.ldap.Control;
 import javax.naming.ldap.ExtendedRequest;
 import javax.naming.ldap.ExtendedResponse;
 import javax.naming.ldap.LdapContext;
 
-import org.apache.ldap.common.name.LdapName;
+import org.apache.ldap.common.NotImplementedException;
 
 import org.apache.eve.PartitionNexus;
 
 
 /**
+ * An Eve implementation of a JNDI LdapContext.
  *
  * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
  * @version $Rev$
  */
 public class EveLdapContext extends EveDirContext implements LdapContext
 {
+    private static final Control[] EMPTY_CONTROLS = new Control[0];
+    private Control[] requestControls = EMPTY_CONTROLS;
+    private Control[] responseControls = EMPTY_CONTROLS;
+    private Control[] connectControls = EMPTY_CONTROLS;
+
 
     /**
-     * TODO Document me!
+     * Creates an instance of an EveLdapContext.
      *
-     * @param nexusProxy TODO
-     * @param env TODO
+     * @param nexusProxy the proxy to a partition nexus
+     * @param env the JNDI environment parameters
+     * @throws NamingException the context cannot be created
      */
     public EveLdapContext( PartitionNexus nexusProxy, Hashtable env ) throws NamingException
     {
@@ -53,14 +62,15 @@
     /**
      * Creates a new EveDirContext with a distinguished name which is used to
      * set the PROVIDER_URL to the distinguished name for this context.
-     * 
+     *
+     * @param principal the directory user principal that is propagated
      * @param nexusProxy the intercepting proxy to the nexus
      * @param env the environment properties used by this context
      * @param dn the distinguished name of this context
      */
-    EveLdapContext( PartitionNexus nexusProxy, Hashtable env, LdapName dn )
+    EveLdapContext( Principal principal, PartitionNexus nexusProxy, Hashtable env, Name dn )
     {
-        super( nexusProxy, env, dn );
+        super( principal, nexusProxy, env, dn );
     }
 
 
@@ -70,8 +80,7 @@
      */
     public ExtendedResponse extendedOperation( ExtendedRequest request )
     {
-        // TODO Auto-generated method stub
-        return null;
+        throw new NotImplementedException();
     }
 
 
@@ -82,8 +91,10 @@
     public LdapContext newInstance( Control[] requestControls )
         throws NamingException
     {
-        // TODO Auto-generated method stub
-        return null;
+        EveLdapContext ctx = new EveLdapContext( getPrincipal(), getNexusProxy(),
+                getEnvironment(), getDn() );
+        ctx.setRequestControls( requestControls );
+        return ctx;
     }
 
 
@@ -92,56 +103,44 @@
      */
     public void reconnect( Control[] connCtls ) throws NamingException
     {
-        // TODO Auto-generated method stub
+        this.connectControls = connCtls;
     }
 
 
     /**
-     * TODO Document me! 
-     *
      * @see javax.naming.ldap.LdapContext#getConnectControls()
      */
     public Control[] getConnectControls() throws NamingException
     {
-        // TODO Auto-generated method stub
-        return null;
+        return this.connectControls;
     }
 
 
     /**
-     * TODO Document me! 
-     *
      * @see javax.naming.ldap.LdapContext#setRequestControls(
      * javax.naming.ldap.Control[])
      */
     public void setRequestControls( Control[] requestControls )
         throws NamingException
     {
-        // TODO Auto-generated method stub
+        this.requestControls = requestControls;
     }
 
 
     /**
-     * TODO Document me! 
-     *
      * @see javax.naming.ldap.LdapContext#getRequestControls()
      */
     public Control[] getRequestControls() throws NamingException
     {
-        // TODO Auto-generated method stub
-        return null;
+        return requestControls;
     }
 
 
     /**
-     * TODO Document me! 
-     *
      * @see javax.naming.ldap.LdapContext#getResponseControls()
      */
     public Control[] getResponseControls() throws NamingException
     {
-        // TODO Auto-generated method stub
-        return null;
+        return responseControls;
     }
-
 }

Added: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/exception/EveAuthenticationException.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/exception/EveAuthenticationException.java	Sat Oct 30 22:10:29 2004
@@ -0,0 +1,45 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.eve.jndi.exception;
+
+
+import javax.naming.AuthenticationException;
+
+import org.apache.eve.exception.EveException;
+import org.apache.ldap.common.message.ResultCodeEnum;
+
+
+/**
+ * The Eve version of an {@link AuthenticationException} which associates the
+ * {@link ResultCodeEnum.INVALIDCREDENTIALS} value with it.  
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class EveAuthenticationException extends AuthenticationException
+        implements EveException
+{
+    /**
+     * Gets ResultCodeEnum.INVALIDCREDENTIALS every time.
+     *
+     * @return ResultCodeEnum.INVALIDCREDENTIALS
+     */
+    public ResultCodeEnum getResultCode()
+    {
+        return ResultCodeEnum.INVALIDCREDENTIALS;
+    }
+}

Added: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/exception/EveAuthenticationNotSupportedException.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/exception/EveAuthenticationNotSupportedException.java	Sat Oct 30 22:10:29 2004
@@ -0,0 +1,121 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.eve.jndi.exception;
+
+
+import javax.naming.AuthenticationNotSupportedException;
+
+import org.apache.eve.exception.EveException;
+import org.apache.ldap.common.message.ResultCodeEnum;
+
+
+/**
+ * An Eve subclass of the {@link AuthenticationNotSupportedException} carrying
+ * along an unequivocal ResultCodeEnum value.
+ *
+ * @see <a href="http://java.sun.com/products/jndi/tutorial/ldap/models/exceptions.html">Exceptions</a>
+ * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class EveAuthenticationNotSupportedException
+        extends AuthenticationNotSupportedException implements EveException
+{
+    /** the result code type safe enumeration */
+    private final ResultCodeEnum resultCode;
+
+
+    // ------------------------------------------------------------------------
+    // C O N S T R U C T O R S
+    // ------------------------------------------------------------------------
+
+
+    /**
+     * Creates an EveException with the resultCode.
+     *
+     * @see AuthenticationNotSupportedException#AuthenticationNotSupportedException()
+     * @param resultCode the resultCode enumeration
+     * @throws IllegalArgumentException if the resultCode is not one of the
+     * codes corresponding to an AuthenticationNotSupportedException
+     */
+    public EveAuthenticationNotSupportedException( ResultCodeEnum resultCode )
+    {
+        super();
+        this.resultCode = resultCode;
+        checkResultCode();
+    }
+
+
+    /**
+     * Sets the resultCode associated with this EveException.
+     *
+     * @see AuthenticationNotSupportedException#AuthenticationNotSupportedException(String)
+     * @param resultCode the resultCode enumeration
+     * @throws IllegalArgumentException if the resultCode is not one of the
+     * codes corresponding to an AuthenticationNotSupportedException
+     */
+    public EveAuthenticationNotSupportedException( String explanation, ResultCodeEnum resultCode )
+    {
+        super( explanation );
+        this.resultCode = resultCode;
+        checkResultCode();
+    }
+
+
+    // ------------------------------------------------------------------------
+    // EveException methods
+    // ------------------------------------------------------------------------
+
+
+    /**
+     * @see org.apache.eve.exception.EveException#getResultCode()
+     */
+    public ResultCodeEnum getResultCode()
+    {
+        return resultCode;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // P R I V A T E   M E T H O D S
+    // ------------------------------------------------------------------------
+
+
+    /**
+     * Checks to make sure the resultCode value is right for this exception
+     * type.
+     *
+     * @throws IllegalArgumentException if the result code is not one of
+     * {@link ResultCodeEnum#INAPPROPRIATEAUTHENTICATION},
+     * {@link ResultCodeEnum#AUTHMETHODNOTSUPPORTED},
+     * {@link ResultCodeEnum#CONFIDENTIALITYREQUIRED}.
+     */
+    private void checkResultCode()
+    {
+        switch( resultCode.getValue() )
+        {
+            case( ResultCodeEnum.INAPPROPRIATEAUTHENTICATION_VAL ):
+                break;
+            case( ResultCodeEnum.CONFIDENTIALITYREQUIRED_VAL ):
+                break;
+            case( ResultCodeEnum.AUTHMETHODNOTSUPPORTED_VAL ):
+                break;
+            default:
+                throw new IllegalArgumentException( "Unexceptable result code "
+                        + "for this exception type: " + resultCode.getName() );
+        }
+    }
+}

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/ibs/OperationalAttributeService.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/ibs/OperationalAttributeService.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/ibs/OperationalAttributeService.java	Sat Oct 30 22:10:29 2004
@@ -289,6 +289,6 @@
         String principal;
         Context ctx = ( ( Context ) invocation.getContextStack().peek() );
         principal = ( String ) ctx.getEnvironment().get( Context.SECURITY_PRINCIPAL );
-        return principal == null ? SystemPartition.DEFAULT_PRINCIPAL : principal;
+        return principal == null ? SystemPartition.ADMIN_PRINCIPAL : principal;
     }
 }

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/ibs/SchemaService.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/ibs/SchemaService.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/jndi/ibs/SchemaService.java	Sat Oct 30 22:10:29 2004
@@ -147,7 +147,7 @@
             {
                 String id = ( String ) list.next();
                 AttributeType type = registry.lookup( id );
-                boolean isBinary = ! type.getSyntax().isHumanReadable();
+                boolean isBinary = ! type.getSyntax().isHumanReadible();
 
                 if ( isBinary || binaries.contains( type ) )
                 {

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/schema/GlobalRegistries.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/schema/GlobalRegistries.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/schema/GlobalRegistries.java	Sat Oct 30 22:10:29 2004
@@ -384,7 +384,7 @@
 //        try
 //        {
 //            String schema = attributeTypeRegistry.getSchemaName( at.getOid() );
-//            if ( ! hasMatchingRule && at.getSyntax().isHumanReadable() )
+//            if ( ! hasMatchingRule && at.getSyntax().isHumanReadible() )
 //            {
 //                errors.add( new NullPointerException( "attributeType "
 //                        + at.getName() + " in schema " + schema + " with OID "

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/schema/bootstrap/BootstrapRegistries.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/schema/bootstrap/BootstrapRegistries.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/schema/bootstrap/BootstrapRegistries.java	Sat Oct 30 22:10:29 2004
@@ -359,7 +359,7 @@
 //        try
 //        {
 //            String schema = attributeTypeRegistry.getSchemaName( at.getOid() );
-//            if ( ! hasMatchingRule && at.getSyntax().isHumanReadable() )
+//            if ( ! hasMatchingRule && at.getSyntax().isHumanReadible() )
 //            {
 //                errors.add( new NullPointerException( "attributeType "
 //                        + at.getName() + " in schema " + schema + " with OID "

Modified: incubator/directory/eve/trunk/backend/core/src/test/org/apache/eve/jndi/AbstractJndiTest.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/test/org/apache/eve/jndi/AbstractJndiTest.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/test/org/apache/eve/jndi/AbstractJndiTest.java	Sat Oct 30 22:10:29 2004
@@ -19,9 +19,11 @@
 
 import java.util.Hashtable;
 import java.io.File;
+import java.io.IOException;
 import javax.naming.ldap.LdapContext;
 import javax.naming.Context;
 import javax.naming.InitialContext;
+import javax.naming.NamingException;
 
 import junit.framework.TestCase;
 import org.apache.commons.io.FileUtils;
@@ -44,6 +46,9 @@
     /** extra environment parameters that can be added before setUp */
     protected Hashtable extras = new Hashtable();
 
+    /** extra environment parameters that can be added before setUp to override values */
+    protected Hashtable overrides = new Hashtable();
+
 
     /**
      * Get's the initial context factory for the provider's ou=system context
@@ -54,24 +59,67 @@
     protected void setUp() throws Exception
     {
         super.setUp();
+        doDelete( new File( "target" + File.separator + "eve" ) );
+        setSysRoot( "uid=admin,ou=system", "testing" );
+    }
 
-        if ( doDelete == true )
-        {
-            File file = new File( "target/eve" );
 
-            if ( file.exists() )
+    /**
+     * Deletes the Eve working directory.
+     *
+     * @throws IOException if there are failures while deleting.
+     */
+    protected void doDelete( File wkdir ) throws IOException
+    {
+        if ( doDelete )
+        {
+            if ( wkdir.exists() )
             {
-                FileUtils.deleteDirectory( file );
+                FileUtils.deleteDirectory( wkdir );
             }
         }
+    }
 
+
+    /**
+     * Sets and returns the system root.  Values of user and password used to
+     * set the respective JNDI properties.  These values can be overriden by the
+     * overrides properties.
+     *
+     * @param user the username for authenticating as this user
+     * @param passwd the password of the user
+     * @return the sysRoot context which is also set
+     * @throws NamingException if there is a failure of any kind
+     */
+    protected LdapContext setSysRoot( String user, String passwd ) throws NamingException
+    {
         Hashtable env = new Hashtable();
-        env.putAll( extras );
-        env.put( Context.PROVIDER_URL, "ou=system" );
-        env.put( Context.INITIAL_CONTEXT_FACTORY, "org.apache.eve.jndi.EveContextFactory" );
-        env.put( EveContextFactory.WKDIR_ENV, "target/eve" );
-        InitialContext initialContext = new InitialContext( env );
-        sysRoot = ( LdapContext ) initialContext.lookup( "" );
+        env.put( Context.SECURITY_PRINCIPAL, user );
+        env.put( Context.SECURITY_CREDENTIALS, passwd );
+        return setSysRoot( env );
+    }
+
+
+    /**
+     * Sets the system root taking into account the extras and overrides
+     * properties.  In between these it sets the properties for the working
+     * directory, the provider URL and the JNDI InitialContexFactory to use.
+     *
+     * @param env an environment to use while setting up the system root.
+     * @return the sysRoot context which is also set
+     * @throws NamingException if there is a failure of any kind
+     */
+    protected LdapContext setSysRoot( Hashtable env ) throws NamingException
+    {
+        Hashtable envFinal = new Hashtable();
+        envFinal.putAll( extras );
+        envFinal.putAll( env );
+        envFinal.put( Context.PROVIDER_URL, "ou=system" );
+        envFinal.put( EveContextFactory.WKDIR_ENV, "target" + File.separator + "eve" );
+        envFinal.put( Context.INITIAL_CONTEXT_FACTORY, "org.apache.eve.jndi.EveContextFactory" );
+        envFinal.putAll( overrides );
+        InitialContext initialContext = new InitialContext( envFinal );
+        return sysRoot = ( LdapContext ) initialContext.lookup( "" );
     }
 
 
@@ -87,6 +135,8 @@
         env.put( Context.PROVIDER_URL, "ou=system" );
         env.put( Context.INITIAL_CONTEXT_FACTORY, "org.apache.eve.jndi.EveContextFactory" );
         env.put( EveContextFactory.SHUTDOWN_OP_ENV, "" );
+        env.put( Context.SECURITY_PRINCIPAL, "uid=admin,ou=system" );
+        env.put( Context.SECURITY_CREDENTIALS, "testing" );
 
         try
         {
@@ -94,7 +144,6 @@
         }
         catch( Exception e )
         {
-
         }
 
         sysRoot = null;

Modified: incubator/directory/eve/trunk/backend/core/src/test/org/apache/eve/jndi/EveContextFactoryTest.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/test/org/apache/eve/jndi/EveContextFactoryTest.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/test/org/apache/eve/jndi/EveContextFactoryTest.java	Sat Oct 30 22:10:29 2004
@@ -108,6 +108,7 @@
     {
         Hashtable env = new Hashtable();
         env.put( Context.PROVIDER_URL, "dc=example" );
+        env.put( Context.SECURITY_CREDENTIALS, "testing" );
         env.put( Context.INITIAL_CONTEXT_FACTORY, "org.apache.eve.jndi.EveContextFactory" );
         InitialContext initialContext = new InitialContext( env );
         DirContext appRoot = ( DirContext ) initialContext.lookup( "" );
@@ -127,6 +128,7 @@
     {
         Hashtable env = new Hashtable();
         env.put( Context.PROVIDER_URL, "ou=testing" );
+        env.put( Context.SECURITY_CREDENTIALS, "testing" );
         env.put( Context.INITIAL_CONTEXT_FACTORY, "org.apache.eve.jndi.EveContextFactory" );
         InitialContext initialContext = new InitialContext( env );
         DirContext appRoot = ( DirContext ) initialContext.lookup( "" );

Added: incubator/directory/eve/trunk/backend/core/src/test/org/apache/eve/jndi/SimpleAuthenticationTest.java
==============================================================================
--- (empty file)
+++ incubator/directory/eve/trunk/backend/core/src/test/org/apache/eve/jndi/SimpleAuthenticationTest.java	Sat Oct 30 22:10:29 2004
@@ -0,0 +1,260 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.eve.jndi;
+
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Hashtable;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.Attributes;
+import javax.naming.NamingException;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.ConfigurationException;
+import javax.naming.ldap.LdapContext;
+
+import org.apache.ldap.common.util.ArrayUtils;
+
+
+/**
+ * A set of simple tests to make sure simple authentication is working as it
+ * should.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class SimpleAuthenticationTest extends AbstractJndiTest
+{
+    /**
+     * Cleans up old database files on creation.
+     *
+     * @throws IOException if we can't clean the files
+     */
+    public SimpleAuthenticationTest() throws IOException
+    {
+        doDelete( new File( "target" + File.separator + "eve" ) );
+    }
+
+
+    /**
+     * Customizes setup for each test case.
+     *
+     * <ul>
+     *   <li>sets doDelete to false for test1AdminAccountCreation</li>
+     *   <li>sets doDelete to false for test2AccountExistsOnRestart</li>
+     *   <li>sets doDelete to true for all other cases</li>
+     *   <li>bypasses normal setup for test3BuildDbNoNothing</li>
+     *   <li>bypasses normal setup for test5BuildDbNoPassWithPrincAuthNone</li>
+     *   <li>bypasses normal setup for test4BuildDbNoPassNoPrincAuthNone</li>
+     *   <li>bypasses normal setup for </li>
+     *   <li></li>
+     * </ul>
+     *
+     * @throws Exception
+     */
+    protected void setUp() throws Exception
+    {
+        if ( getName().equals( "test1AdminAccountCreation" ) ||
+             getName().equals( "test2AccountExistsOnRestart" ) )
+        {
+            super.doDelete = false;
+        }
+        else
+        {
+            super.doDelete = true;
+        }
+
+        if ( getName().equals( "test3BuildDbNoNothing" ) ||
+             getName().equals( "test5BuildDbNoPassWithPrincAuthNone" ) ||
+             getName().equals( "test4BuildDbNoPassNoPrincAuthNone" ) )
+        {
+            return;
+        }
+
+        super.setUp();
+    }
+
+
+    /**
+     * Checks all attributes of the admin account entry minus the userPassword
+     * attribute.
+     *
+     * @param attrs the entries attributes
+     */
+    protected void performAdminAccountChecks( Attributes attrs )
+    {
+        assertTrue( attrs.get( "objectClass" ).contains( "top" ) );
+        assertTrue( attrs.get( "objectClass" ).contains( "person" ) );
+        assertTrue( attrs.get( "objectClass" ).contains( "organizationalPerson" ) );
+        assertTrue( attrs.get( "objectClass" ).contains( "inetOrgPerson" ) );
+        assertTrue( attrs.get( "displayName" ).contains( "Directory Superuser" ) );
+    }
+
+
+    /**
+     * Check the creation of the admin account.
+     *
+     * @throws NamingException if there are failures
+     */
+    public void test1AdminAccountCreation() throws NamingException
+    {
+        DirContext ctx = ( DirContext ) sysRoot.lookup( "uid=admin" );
+        Attributes attrs = ctx.getAttributes( "" );
+        performAdminAccountChecks( attrs );
+        assertTrue( attrs.get( "userPassword" ).contains( "testing" ) );
+    }
+
+
+    /**
+     * Check the creation of the admin account even after a restart.
+     *
+     * @throws NamingException if there are failures
+     */
+    public void test2AccountExistsOnRestart() throws NamingException
+    {
+        DirContext ctx = ( DirContext ) sysRoot.lookup( "uid=admin" );
+        Attributes attrs = ctx.getAttributes( "" );
+
+        performAdminAccountChecks( attrs );
+        assertTrue( attrs.get( "userPassword" ).contains( "testing" ) );
+    }
+
+
+    /**
+     * Checks that we can give basically the minimal set of properties without
+     * any security information to build and bootstrap a new system.  The admin
+     * user is presumed and no password is used.
+     *
+     * @throws Exception if there are problems
+     */
+    public void test3BuildDbNoNothing() throws Exception
+    {
+        // clean out the database
+        doDelete( new File( "target" + File.separator + "eve" ) );
+        LdapContext ctx = setSysRoot( new Hashtable() );
+        Attributes attributes = ctx.getAttributes( "uid=admin" );
+        assertNotNull( attributes );
+
+        // Eve has started now so we access another context w/o the wkdir
+        Hashtable env = new Hashtable();
+        env.put( Context.PROVIDER_URL, "ou=system" );
+        env.put( Context.INITIAL_CONTEXT_FACTORY, "org.apache.eve.jndi.EveContextFactory" );
+        InitialContext initial = new InitialContext( env );
+        ctx = ( LdapContext ) initial.lookup( "uid=admin" );
+        assertNotNull( ctx );
+        attributes = ctx.getAttributes( "" );
+        assertNotNull( attributes );
+
+        performAdminAccountChecks( attributes );
+        assertTrue( attributes.get( "userPassword" ).contains( ArrayUtils.EMPTY_BYTE_ARRAY ) );
+    }
+
+
+    /**
+     * Tests to make sure we throw an error when Context.SECURITY_AUTHENTICATION
+     * is set to "none" when trying to bootstrap the system.  Only the admin
+     * user is allowed to bootstrap.  Subsequent calls can 'bind' (authenticate
+     * in our case since there is no network connection) anonymously though.
+     *
+     * @throws Exception if anything goes wrong
+     */
+    public void test4BuildDbNoPassNoPrincAuthNone() throws Exception
+    {
+        // clean out the database
+        tearDown();
+        doDelete( new File( "target" + File.separator + "eve" ) );
+        Hashtable env = new Hashtable();
+        env.put( Context.SECURITY_AUTHENTICATION, "none" );
+
+        try
+        {
+            setSysRoot( env );
+            fail( "should not get here due to exception" );
+        }
+        catch( ConfigurationException e )
+        {
+        }
+
+        // ok this should start up the system now as admin
+        Hashtable anonymous = new Hashtable();
+        anonymous.put( EveContextFactory.ANONYMOUS_ENV, "true" );
+        EveLdapContext ctx = ( EveLdapContext ) setSysRoot( anonymous );
+        assertNotNull( ctx );
+
+        // now go in as anonymous user and we should be wh
+        env.put( Context.PROVIDER_URL, "ou=system" );
+        env.put( Context.INITIAL_CONTEXT_FACTORY, "org.apache.eve.jndi.EveContextFactory" );
+
+        InitialContext initial = new InitialContext( env );
+        ctx = ( EveLdapContext ) initial.lookup( "uid=admin" );
+        assertNotNull( ctx );
+        Attributes attributes = ctx.getAttributes( "" );
+        assertNotNull( attributes );
+
+        performAdminAccountChecks( attributes );
+        assertTrue( attributes.get( "userPassword" ).contains( ArrayUtils.EMPTY_BYTE_ARRAY ) );
+    }
+
+
+    public void test5BuildDbNoPassWithPrincAuthNone() throws Exception
+    {
+        // clean out the database
+        tearDown();
+        doDelete( new File( "target" + File.separator + "eve" ) );
+        Hashtable env = new Hashtable();
+        env.put( Context.SECURITY_AUTHENTICATION, "none" );
+        env.put( Context.SECURITY_PRINCIPAL, "uid=admin,ou=system" );
+
+        try
+        {
+            setSysRoot( env );
+            fail( "should not get here due to exception" );
+        }
+        catch( ConfigurationException e )
+        {
+        }
+
+//        // clean out the database
+//        doDelete( new File( "target" + File.separator + "eve" ) );
+//        Hashtable env = new Hashtable();
+//        env.put( Context.SECURITY_AUTHENTICATION, "none" );
+//        env.put( Context.SECURITY_PRINCIPAL, "uid=admin,ou=system" );
+//        EveLdapContext ctx = ( EveLdapContext ) setSysRoot( env );
+//        X500Principal principal = ctx.getPrincipal();
+//        assertTrue( principal.getName().equalsIgnoreCase( SystemPartition.ADMIN_PRINCIPAL ) );
+//        Attributes attributes = ctx.getAttributes( "uid=admin" );
+//        assertNotNull( attributes );
+//
+//        // Eve has started now so we access another context w/o the wkdir
+//        env = new Hashtable();
+//        env.put( Context.PROVIDER_URL, "ou=system" );
+//        env.put( Context.INITIAL_CONTEXT_FACTORY, "org.apache.eve.jndi.EveContextFactory" );
+//        InitialContext initial = new InitialContext( env );
+//        ctx = ( EveLdapContext ) initial.lookup( "uid=admin" );
+//        assertNotNull( ctx );
+//        attributes = ctx.getAttributes( "" );
+//        assertNotNull( attributes );
+//
+//        assertTrue( attributes.get( "objectClass" ).contains( "top" ) );
+//        assertTrue( attributes.get( "objectClass" ).contains( "person" ) );
+//        assertTrue( attributes.get( "objectClass" ).contains( "organizationalPerson" ) );
+//        assertTrue( attributes.get( "objectClass" ).contains( "inetOrgPerson" ) );
+//        assertTrue( attributes.get( "userPassword" ).contains( ArrayUtils.EMPTY_BYTE_ARRAY ) );
+//        assertTrue( attributes.get( "displayName" ).contains( "Directory Superuser" ) );
+    }
+}