Hello!

I've put together a set of patches to the LDAPAuthentication
code to get it working against Active Directory at Auburn
University, support implicit-group member-ids in dspace.cfg,
and add a JUnit regression test.
I think the changes are backward compatable and generic,
but I've only tested the code in my environment.

I hope that we can check this patch into the dspace repository.
An overview and svn diff follow, and a zip file with
the modified files is available here:
             http://erwg.lib.auburn.edu/dspace-ldap_20080828.zip
Please take a look, and let me know what you think.

Cheers,
Reuben

-----------------------------------

Changes under dspace-api org.dspace.authentication.

*. Moved the
              LDAPAuthentication.SpeakerToLDAP
    nested class out to its own non-nested interface
    with a DefaultSpeakerToLDAP implementation.

*. Refactored SpeakerToLDAP#ldapAuthenticate(...)
     to return a DataFromLDAP POJO data object 
     rather than set object member variables.

*. Implemented SpeakerToLDAPCase JUnit test-case
    and PackageTestSuite classes to support simple
    regression tests against SpeakerToLDAP implementations.
    Modified pom.xml so that 
        'mvn test'
    runs with a verbose log4j setting.

*. Modified the way SpeakToLDAP handles the
            ldap.object_context   
     dspace.cfg configuration property so that
     if the ldap.object_context matches
             'WINDOWS_DOMAIN:DOMAIN_NAME',
     then LDAP attempts to bind with
              'DOMAIN_NAME\NETID'
     rather than
              'cn=NETID,ldap.object_context'
     .  This change allows us to configure LDAP 
     to bind with Active Directory out of the box.

*. Modifed the LDAP search for user-info to take a SearchControls
     parameter that specifies a recursive tree-search under the
         ldap.search_context
      tree for a single user-object result.
      Once again - this allows LDAPAuthenticate to work
      with an Active Directory tree that has user objects
      organized into different folders under a tree.

*. Modified LDAPAuthentication.getSpecialGroups
    to access the
          ldap.dspace.autogroup
    dspace.cfg configuration property
    to get the group-ids that an LDAP-authenticated
    user should be an implicit member of.
    This makes it easy to configure a system where
    every user that can authenticate can also
    submit material to some collections.

*. Changed some of the if/else nesting in
        LDAPAuthentication.authenticate 
    so that instead of having something like
       if () {
            ...
             return bla;
        }  else { 
    we have
         if () {
               ...
               return bla;
         }
         ... // no else
      and instead of
         } else {
              if () {
                    return goo
              }
        }
      we just have
          } else if () {
       just to make the control flow a little
        easier to look at.

----------------------------------

$ svn diff pom.xml src/test src/main/java/org/dspace/authenticate >
/tmp/bla

Index: pom.xml
===================================================================
--- pom.xml     (revision 2942)
+++ pom.xml     (working copy)
@@ -61,6 +61,7 @@
      
<url>http://dspace.svn.sourceforge.net/viewvc/dspace/branches/dspace-1_5_x/dspace</url>
    </scm>
 
+
    <!-- 
       Runtime and Compile Time dependencies for DSpace.
    -->
@@ -188,6 +189,23 @@
          <groupId>com.ibm.icu</groupId>
          <artifactId>icu4j</artifactId>
       </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <scope>test</scope>
+    </dependency>
    </dependencies>
 
-</project>
\ No newline at end of file
+<build>
+    <testResources>
+      <testResource>
+        <directory>src/test/resources</directory>
+        <includes>
+          <include>log4j.properties</include>
+        </includes>
+      </testResource>
+    </testResources>
+  </build>
+
+</project>
Index: src/test/java/org/dspace/authenticate/SpeakerToLDAPCase.java
===================================================================
---
src/test/java/org/dspace/authenticate/SpeakerToLDAPCase.java    (revision
0)
+++
src/test/java/org/dspace/authenticate/SpeakerToLDAPCase.java    (revision
0)
@@ -0,0 +1,56 @@
+package org.dspace.authenticate;
+
+
+import junit.framework.TestCase;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Generic test runner for SpeakerToLDAP implementations.
+ */
+public class SpeakerToLDAPCase extends TestCase {
+    private static final Logger olog = Logger.getLogger(
SpeakerToLDAPCase.class );
+
+    private SpeakerToLDAP   oldap;
+    private String          os_netid;
+    private String          os_password;
+
+
+    /**
+     * Inject the test dependencies - initializes test properties
+     *
+     * @param s_name of test - pass to super
+     * @param ldap instance to authenticate agains
+     * @param s_netid user-id to authenticate as
+     * @param s_password for s_netid
+     */
+    public SpeakerToLDAPCase ( String s_name, SpeakerToLDAP ldap,
+                               String s_netid, String s_password
+                               ) {
+        super( s_name );
+        oldap = ldap;
+        os_netid = s_netid;
+        os_password = s_password;
+    }
+
+    /**
+     * Try to authenticate against the constructor-supplied
+     * (SpeakerToLDAP, s_netid, s_password)
+     */
+    public void testAuthenticate() {
+        try {
+            DataFromLDAP ldap_info = oldap.ldapAuthenticate( os_netid,
os_password );
+            assertTrue( "Test user logged in ok: " + os_netid,
+                        null != ldap_info
+                        );
+            // need e-mail to key into eperson database
+            olog.info( "Got e-mail for " + os_netid + ": " +
ldap_info.getEmail () );
+            assertTrue( "Got e-mail info for " + os_netid + " from
ldap",
+                        null != ldap_info.getEmail ()
+                        );
+        } catch ( Exception e ) {
+            olog.info( "Failed to authenticate user: " + os_netid, e
);
+            assertTrue( "Failed to authenticate user: " + os_netid +
", caught: " + e, false );
+        }
+    }
+}
Index: src/test/java/org/dspace/authenticate/PackageTest.java
===================================================================
---
src/test/java/org/dspace/authenticate/PackageTest.java  (revision
0)
+++
src/test/java/org/dspace/authenticate/PackageTest.java  (revision
0)
@@ -0,0 +1,40 @@
+package org.dspace.authenticate;
+
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Specialization of AbstactSpeakerToLDAPTest configured
+ * to run a DefaultSpeakerToLDAPTest through a test.
+ */
+public class PackageTest extends TestCase {
+    private static final Logger olog = Logger.getLogger(
PackageTest.class );
+
+
+    /**
+     * Build up the batch of tests to run for the
org.dspace.authenticate 
+     * package.  You'll have to modify the properties injected into
the
+     * test SpeakerToLDAP to work with your environment
+     */
+    public static TestSuite suite () {
+        TestSuite     suite = new TestSuite( PackageTest.class.getName
() );
+        SpeakerToLDAP ldap = new DefaultSpeakerToLDAP (
"ldap://ldaps.university.edu";,
+                                                        "cn",
+                                                       
"OU=People,OU=AUMain,DC=auburn,DC=edu",
+                                                       
"WINDOWS_DOMAIN:AUBURN",
+                                                        "mail",
+                                                        "givenName",
+                                                        "sn",
+                                                       
"telephoneNumber"
+                                                        );
+        suite.addTest ( new SpeakerToLDAPCase( "testAuthenticate",
ldap,
+                                               "USER", "PASSWORD"
+                                               )
+                        );
+        return suite;
+    }
+
+}
Index: src/test/resources/log4j.properties
===================================================================
--- src/test/resources/log4j.properties (revision 0)
+++ src/test/resources/log4j.properties (revision 0)
@@ -0,0 +1,9 @@
+# Set root logger level to DEBUG and its only appender to A1.
+log4j.rootLogger=DEBUG, A1
+
+# A1 is set to be a ConsoleAppender.
+log4j.appender.A1=org.apache.log4j.ConsoleAppender
+
+# A1 uses PatternLayout.
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x -
%m%n
Index: src/main/java/org/dspace/authenticate/LDAPAuthentication.java
===================================================================
---
src/main/java/org/dspace/authenticate/LDAPAuthentication.java   (revision
3054)
+++
src/main/java/org/dspace/authenticate/LDAPAuthentication.java   (working
copy)
@@ -40,17 +40,11 @@
 package org.dspace.authenticate;
 
 import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Hashtable;
 
-import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttribute;
-import javax.naming.directory.BasicAttributes;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.InitialDirContext;
-import javax.naming.directory.SearchResult;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -60,6 +54,7 @@
 import org.dspace.core.Context;
 import org.dspace.core.LogManager;
 import org.dspace.eperson.EPerson;
+import org.dspace.eperson.Group;
 
 /**
  * Authentication module to authenticate against a flat LDAP tree
where
@@ -72,9 +67,66 @@
     implements AuthenticationMethod {
 
     /** log4j category */
-    private static Logger log =
Logger.getLogger(LDAPAuthentication.class);
+    private static final Logger olog =
Logger.getLogger(LDAPAuthentication.class);
 
+    private final SpeakerToLDAP  oldap;
+
     /**
+     * Constructor injects SpeakerToLDAP dependency
+     *
+     * @param ldap SpeakerToLDAP knows how to authenticate
+     *                 against and query the LDAP directory
+     * @param b_autoregister set true to auto-register an eperson
+     *               for a new user that succesfully authenticates
+     *               with LDAP
+     * @param v_special_group ids of user groups that an
LDAP-authenticated
+     *          user should be considered an implicit member of
+     */
+    public LDAPAuthentication ( SpeakerToLDAP ldap,
+                                boolean b_autoregister,
+                                int[] v_special_group
+                                ) {
+        oldap = ldap;
+        ob_autoregister = b_autoregister;
+        ov_special_group = v_special_group;
+    }
+
+    /**
+     * Constructor invoked by dspace.cfg based configuration
+     * engine sets up DefaultSpeakerToLDAP,
+     * checks ldap.autoregister and ldap.dspace.autogroup
+     * configuration values to determine canSelfRegister
+     * and getSpecialGroups property values.
+     */
+    public LDAPAuthentication () {
+        String s_groups =
ConfigurationManager.getProperty("ldap.dspace.autogroup");
+
+        List<Integer> v_group_id = new ArrayList<Integer>();
+        if ( null != s_groups ) {
+            String[]     v_group_name = s_groups.trim ().split(
",\\s*" );
+            for ( int i=0; i < v_group_name.length; ++i ) {
+                String s_group = v_group_name[i].trim ();
+                if ( s_group.length () > 0 ) {
+                    try {
+                        v_group_id.add ( Integer.parseInt( s_group )
);
+                    } catch ( Exception e ) {
+                        olog.warn( "Exception parsing group " +
s_group, e );
+                    }
+                }
+            }
+        }
+        oldap = new DefaultSpeakerToLDAP ();
+        ob_autoregister =
ConfigurationManager.getBooleanProperty("webui.ldap.autoregister");
+        ov_special_group = new int[ v_group_id.size () ];
+        int i_count = 0;
+        for ( Integer i_group_id : v_group_id ) {
+            ov_special_group[ i_count ] = i_group_id;
+            ++i_count;
+        }
+    }
+
+    private final boolean ob_autoregister;
+    /**
      * Let a real auth method return true if it wants.
      */
     public boolean canSelfRegister(Context context,
@@ -83,8 +135,7 @@
         throws SQLException
     {
         // XXX might also want to check that username exists in LDAP.
-
-        return
ConfigurationManager.getBooleanProperty("webui.ldap.autoregister");
+        return ob_autoregister;
     }
 
     /**
@@ -118,12 +169,10 @@
         return false;
     }
 
-    /*
-     * Nothing here.
-     */
+    private final int[] ov_special_group;
     public int[] getSpecialGroups(Context context, HttpServletRequest
request)
     {
-        return new int[0];
+        return ov_special_group;
     }
 
     /*
@@ -139,261 +188,140 @@
                             HttpServletRequest request)
         throws SQLException
     {
-        log.info(LogManager.getHeader(context, "auth", "attempting
trivial auth of user="+netid));
+        olog.info(LogManager.getHeader(context, "auth", "attempting
auth of user="+netid));
 
         // Skip out when no netid or password is given.
-        if (netid == null || password == null)
-               return BAD_ARGS;
+        if (netid == null || password == null) {
+            return BAD_ARGS;
+        }
 
         // Locate the eperson
-        EPerson eperson = null;
+        EPerson      eperson = null;
         try
         {
-                       eperson = EPerson.findByNetid(context,
netid.toLowerCase());
+            eperson = EPerson.findByNetid(context,
netid.toLowerCase());
         }
         catch (SQLException e)
         {
         }
-        boolean loggedIn = false;
-        SpeakerToLDAP ldap = new SpeakerToLDAP(log);
 
+        olog.debug( "Found eperson for " + netid );
+
         // if they entered a netid that matches an eperson
         if (eperson != null)
         {
             // e-mail address corresponds to active account
-            if (eperson.getRequireCertificate())
+            if (eperson.getRequireCertificate()) {
                 return CERT_REQUIRED;
-            else if (!eperson.canLogIn())
+            } else if (!eperson.canLogIn()) {
                 return BAD_ARGS;
-            {
-                if (ldap.ldapAuthenticate(netid, password, context))
-                {
+            }
+            try {
+                // authenticate
+                olog.debug( "Attempting LDAP auth-1 for " + netid );
+                DataFromLDAP ldap_info = oldap.ldapAuthenticate(
netid, password );
+                if ( null != ldap_info ) {
                     context.setCurrentUser(eperson =
EPerson.findByNetid(context, netid.toLowerCase()));
-                    log.info(LogManager
-                        .getHeader(context, "authenticate",
"type=ldap"));
+                    olog.info(LogManager
+                             .getHeader(context, "authenticate",
"type=ldap"));
                     return SUCCESS;
-                }
-                else
-                   return BAD_CREDENTIALS;
+                } 
+            } catch ( NamingException e ) {
+                olog.warn( "Failed to authenticate user: " + netid, e
);
             }
+            //else {
+            return BAD_CREDENTIALS;
+        } 
+        // eperson == null
+        if ( null != eperson ) {
+            throw new AssertionError( "eperson should be null here!"
);
         }
-
-        // the user does not already exist so try and authenticate
them
-        // with ldap and create an eperson for them
-        else
-        {
-            if (ldap.ldapAuthenticate(netid, password, context))
-            {
-                // Register the new user automatically
-                log.info(LogManager.getHeader(context,
-                                "autoregister", "netid=" + netid));
-
-                if
((ldap.ldapEmail!=null)&&(!ldap.ldapEmail.equals("")))
-                {
-                    try
-                    {
-                        eperson = EPerson.findByEmail(context,
ldap.ldapEmail);
-                           if (eperson!=null)
-                           {
-                               log.info(LogManager.getHeader(context,
-                                       "type=ldap-login",
"type=ldap_but_already_email"));
-                               context.setIgnoreAuthorization(true);
-                               eperson.setNetid(netid);
-                               eperson.update();
-                               context.commit();
-                               context.setIgnoreAuthorization(false);
-                               context.setCurrentUser(eperson);
-                               return SUCCESS;
-                           }
-                           else
-                           {
-                               if (canSelfRegister(context, request,
netid))
-                               {
-                                   // TEMPORARILY turn off
authorisation
-                                   try
-                                   {
-                                      
context.setIgnoreAuthorization(true);
-                                       eperson =
EPerson.create(context);
-                                       if
((ldap.ldapEmail!=null)&&(!ldap.ldapEmail.equals("")))
eperson.setEmail(ldap.ldapEmail);
-                                       else eperson.setEmail(netid);
-                                       if
((ldap.ldapGivenName!=null)&&(!ldap.ldapGivenName.equals("")))
eperson.setFirstName(ldap.ldapGivenName);
-                                       if
((ldap.ldapSurname!=null)&&(!ldap.ldapSurname.equals("")))
eperson.setLastName(ldap.ldapSurname);
-                                       if
((ldap.ldapPhone!=null)&&(!ldap.ldapPhone.equals("")))
eperson.setMetadata("phone", ldap.ldapPhone);
-                                       eperson.setNetid(netid);
-                                       eperson.setCanLogIn(true);
-                                      
AuthenticationManager.initEPerson(context, request, eperson);
-                                       eperson.update();
-                                       context.commit();
-                                                                       
context.setCurrentUser(eperson);
-                                                               }
-                                   catch (AuthorizeException e)
-                                   {
-                                       return NO_SUCH_USER;
-                                   }
-                                   finally
-                                   {
-                                      
context.setIgnoreAuthorization(false);
-                                   }
-
-                                  
log.info(LogManager.getHeader(context, "authenticate",
-                                               "type=ldap-login,
created ePerson"));
-                                   return SUCCESS;
-                               }
-                               else
-                               {
-                                   // No auto-registration for valid
certs
-                                  
log.info(LogManager.getHeader(context,
-                                                   "failed_login",
"type=ldap_but_no_record"));
-                                   return NO_SUCH_USER;
-                               }
-                           }
-                    }
-                    catch (AuthorizeException e)
-                    {
-                        eperson = null;
-                    }
-                    finally
-                    {
-                        context.setIgnoreAuthorization(false);
-                    }
-                }
-            }
+        olog.debug( "Attempting LDAP auth-2 for " + netid );
+        DataFromLDAP ldap_info = null;
+        try {
+            ldap_info = oldap.ldapAuthenticate( netid, password );
+        } catch ( NamingException e ) {
+            olog.warn( "Failed to authenticate user: " + netid, e );
         }
-        return BAD_ARGS;
-    }
-
-    /**
-     * Internal class to manage LDAP query and results, mainly
-     * because there are multiple values to return.
-     */
-    public class SpeakerToLDAP {
-
-        private Logger log = null;
-
-        /** ldap email result */
-        protected String ldapEmail = null;
-
-        /** ldap name result */
-        protected String ldapGivenName = null;
-        protected String ldapSurname = null;
-        protected String ldapPhone = null;
-
-        SpeakerToLDAP(Logger thelog)
-        {
-            log = thelog;
+        if ( (null == ldap_info) 
+             || (ldap_info.getEmail()==null)
+             || ldap_info.getEmail().equals("")
+             ) {
+            return BAD_ARGS; // failed to authenticate or get e-mail
address
         }
 
-        /**
-         * contact the ldap server and attempt to authenticate
-         */
-        protected boolean ldapAuthenticate(String netid, String
password, Context context)
-        {
-            if (!password.equals(""))
-            {
-                String ldap_provider_url =
ConfigurationManager.getProperty("ldap.provider_url");
-                String ldap_id_field =
ConfigurationManager.getProperty("ldap.id_field");
-                String ldap_search_context =
ConfigurationManager.getProperty("ldap.search_context");
-                String ldap_object_context =
ConfigurationManager.getProperty("ldap.object_context");
-
-                // Set up environment for creating initial context
-                Hashtable env = new Hashtable(11);
-                env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
-                env.put(javax.naming.Context.PROVIDER_URL,
ldap_provider_url);
-
-                // Authenticate
-                env.put(javax.naming.Context.SECURITY_AUTHENTICATION,
"simple");
-                env.put(javax.naming.Context.SECURITY_PRINCIPAL,
ldap_id_field+"="+netid+","+ldap_object_context);
-                env.put(javax.naming.Context.SECURITY_CREDENTIALS,
password);
-
-                DirContext ctx = null;
-                try
-                {
-                    // Create initial context
-                    ctx = new InitialDirContext(env);
-
-                    String ldap_email_field =
ConfigurationManager.getProperty("ldap.email_field");
-                    String ldap_givenname_field =
ConfigurationManager.getProperty("ldap.givenname_field");
-                    String ldap_surname_field =
ConfigurationManager.getProperty("ldap.surname_field");
-                    String ldap_phone_field =
ConfigurationManager.getProperty("ldap.phone_field");
-
-                    Attributes matchAttrs = new
BasicAttributes(true);
-                    matchAttrs.put(new BasicAttribute(ldap_id_field,
netid));
-
-                    String attlist[] = {ldap_email_field,
ldap_givenname_field, ldap_surname_field, ldap_phone_field};
-
-                    // look up attributes
-                    try
-                    {
-                        NamingEnumeration answer =
ctx.search(ldap_search_context, matchAttrs, attlist);
-                        while(answer.hasMore()) {
-                            SearchResult sr =
(SearchResult)answer.next();
-                            Attributes atts = sr.getAttributes();
-                            Attribute att;
-
-                            if (attlist[0]!=null)
-                            {
-                                    att = atts.get(attlist[0]);
-                                    if (att != null) ldapEmail =
(String)att.get();
-                            }
-
-                            if (attlist[1]!=null)
-                            {
-                                    att = atts.get(attlist[1]);
-                                    if (att != null) ldapGivenName =
(String)att.get();
-                            }
-
-                            if (attlist[2]!=null)
-                            {
-                                    att = atts.get(attlist[2]);
-                                    if (att != null) ldapSurname =
(String)att.get();
-                            }
-
-                            if (attlist[3]!=null)
-                            {
-                                    att = atts.get(attlist[3]);
-                                    if (att != null) ldapPhone =
(String)att.get();
-                            }
-                        }
+        //
+        // autoregister the ldap-authenticated user
+        //
+        olog.info(LogManager.getHeader(context,
+                                      "autoregister", "netid=" +
netid)
+                 );
+        
+        try {
+            eperson = EPerson.findByEmail(context,
ldap_info.getEmail());
+            if (eperson!=null) {
+                // Just need to set the netid on the eperson record
+                olog.info(LogManager.getHeader(context,
+                                              "type=ldap-login",
"type=ldap_but_already_email"));
+                context.setIgnoreAuthorization(true);
+                eperson.setNetid(netid);
+                eperson.update();
+                context.commit();
+                context.setIgnoreAuthorization(false);
+                context.setCurrentUser(eperson);
+                return SUCCESS;
+            } else if (canSelfRegister(context, request, netid)) {
+                // TEMPORARILY turn off authorisation
+                try {
+                    context.setIgnoreAuthorization(true);
+                    eperson = EPerson.create(context);
+                    eperson.setEmail(ldap_info.getEmail());
+                    if ((ldap_info.getGivenName()!=null)
+                        &&(!ldap_info.getGivenName().equals(""))
+                        ) {
+                       
eperson.setFirstName(ldap_info.getGivenName());
                     }
-                    catch (NamingException e)
-                    {
-                        // if the lookup fails go ahead and create a
new record for them because the authentication
-                        // succeeded
-                        log.warn(LogManager.getHeader(context,
-                                        "ldap_attribute_lookup",
"type=failed_search "+e));
-                        return true;
+                    if ((ldap_info.getSurname()!=null)
+                        &&(!ldap_info.getSurname().equals(""))
+                        ) { 
+                        eperson.setLastName(ldap_info.getSurname());
                     }
-                }
-                catch (NamingException e)
-                {
-                    log.warn(LogManager.getHeader(context,
-                                        "ldap_authentication",
"type=failed_auth "+e));
-                    return false;
-                }
-                finally
-                {
-                    // Close the context when we're done
-                    try
-                    {
-                        if (ctx != null)
-                            ctx.close();
+                    if ((ldap_info.getPhone()!=null)
+                        &&(!ldap_info.getPhone().equals(""))
+                        ) { 
+                        eperson.setMetadata("phone",
ldap_info.getPhone());
                     }
-                    catch (NamingException e)
-                    {
-                    }
+                    eperson.setNetid(ldap_info.getNetId());
+                    eperson.setCanLogIn(true);
+                    AuthenticationManager.initEPerson(context,
request, eperson);
+                    eperson.update();
+                    context.commit();
+                    context.setCurrentUser(eperson);
+                } catch (AuthorizeException e) {
+                    return NO_SUCH_USER;
+                } finally {
+                    context.setIgnoreAuthorization(false);
                 }
+                olog.info(LogManager.getHeader(context,
"authenticate",
+                                              "type=ldap-login,
created ePerson"));
+                return SUCCESS;
+            } else {
+                // No auto-registration for valid certs
+                olog.info(LogManager.getHeader(context,
+                                              "failed_login",
"type=ldap_but_no_record"));
+                return NO_SUCH_USER;
             }
-            else
-            {
-                return false;
-            }
-
-            return true;
+        } catch (AuthorizeException e) {
+            eperson = null;
+            // authentication failed
+            return BAD_ARGS;
+        } finally {
+            context.setIgnoreAuthorization(false);
         }
-
-
+        // Unreachable!
     }
 
+
     /*
      * Returns URL to which to redirect to obtain credentials (either
password
      * prompt or e.g. HTTPS port for client cert.); null means no
redirect.
@@ -430,4 +358,4 @@
     {
         return "org.dspace.eperson.LDAPAuthentication.title";
     }
-}
\ No newline at end of file
+}
Index: src/main/java/org/dspace/authenticate/DefaultSpeakerToLDAP.java
===================================================================
---
src/main/java/org/dspace/authenticate/DefaultSpeakerToLDAP.java (revision
0)
+++
src/main/java/org/dspace/authenticate/DefaultSpeakerToLDAP.java (revision
0)
@@ -0,0 +1,183 @@
+package org.dspace.authenticate;
+
+import java.util.Hashtable;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+
+import org.apache.log4j.Logger;
+import org.dspace.core.ConfigurationManager;
+
+/**
+ * Internal class to manage LDAP query and results, mainly
+ * because there are multiple values to return.
+ */
+public class DefaultSpeakerToLDAP implements SpeakerToLDAP {
+    private static final Logger olog =
Logger.getLogger(DefaultSpeakerToLDAP.class);
+    private final String os_provider_url;
+    private final String os_id_field;
+    private final String os_search_context;
+    private final String os_object_context;
+    private final String os_email_field;
+    private final String os_givenname_field;
+    private final String os_surname_field;
+    private final String os_phone_field;
+            
+
+    /**
+     * Constructor allows injection of 
+     * configuration parameters.
+     *
+     * @param s_provider_url to the server - we assume simple
authentication
+     * @param s_id_field attribute of user object - usually cn
+     * @param s_search_context subtree under which to search for user
info,
+     *                          ex: ou=People,dc=myschool,dc=edu
+     * @param s_object_context of user bind-path - 
+     *         ex: ou=People,dc=myschool,dc=edu leads to bind attempt
+     *         againt cn=username,ou=People,dc=myschool,dc=edu
+     * @param s_email_field in user record
+     * @param s_givenname_field in user record
+     * @param s_surname_field in user record, usually sn
+     * @param s_phone_field in user record
+     */
+    public DefaultSpeakerToLDAP( String s_provider_url,
+                            String s_id_field,
+                            String s_search_context,
+                            String s_object_context,
+                            String s_email_field,
+                            String s_givenname_field,
+                            String s_surname_field,
+                            String s_phone_field
+                            ) 
+    {
+        os_provider_url = s_provider_url;
+        os_id_field = s_id_field;
+        os_search_context = s_search_context;
+        os_object_context = s_object_context;
+        os_email_field = s_email_field;
+        os_givenname_field = s_givenname_field;
+        os_surname_field = s_surname_field;
+        os_phone_field = s_phone_field;
+    }
+
+    /**
+     * Default constructor extracts LDAP-server parameters
+     * from ConfigurationManager (dspace.cfg):
+     *     ldap.provider_url, ldap_id_field,
+     *     ldap_search_contect, ldap_object_context
+     */
+    public DefaultSpeakerToLDAP() {
+        os_provider_url =
ConfigurationManager.getProperty("ldap.provider_url");
+        os_id_field =
ConfigurationManager.getProperty("ldap.id_field");
+        os_search_context =
ConfigurationManager.getProperty("ldap.search_context");
+        os_object_context =
ConfigurationManager.getProperty("ldap.object_context");
+        os_email_field =
ConfigurationManager.getProperty("ldap.email_field");
+        os_givenname_field =
ConfigurationManager.getProperty("ldap.givenname_field");
+        os_surname_field =
ConfigurationManager.getProperty("ldap.surname_field");
+        os_phone_field =
ConfigurationManager.getProperty("ldap.phone_field");
+    }
+
+    /**
+     * contact the ldap server and attempt to authenticate
+     */
+    public DataFromLDAP ldapAuthenticate(String s_netid, String
s_password ) throws NamingException
+    {
+        if (s_password.equals("")) 
+        {
+            return null;
+        }
+        // Set up environment for creating initial context
+        Hashtable env = new Hashtable(11);
+        env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
+        env.put(javax.naming.Context.PROVIDER_URL, os_provider_url);
+        
+        // Authenticate
+        env.put(javax.naming.Context.SECURITY_AUTHENTICATION,
"simple");
+        final String  s_ad_key = "WINDOWS_DOMAIN:";
+        if ( os_object_context.toUpperCase ().startsWith( s_ad_key ) )
{
+            // Active Directory bind
+            String s_principal = os_object_context.substring(
s_ad_key.length () ) + "\\" + s_netid;
+            olog.debug( "Binding principal to: " + s_principal );
+            env.put(javax.naming.Context.SECURITY_PRINCIPAL,
s_principal );
+        } else {
+            env.put(javax.naming.Context.SECURITY_PRINCIPAL,
os_id_field+"="+s_netid+","+os_object_context);
+        }
+        env.put(javax.naming.Context.SECURITY_CREDENTIALS,
s_password);
+        
+        DirContext ctx = new InitialDirContext(env);
+        try {
+            Attributes search_attributes = new BasicAttributes(true);
+            search_attributes.put(new BasicAttribute(os_id_field,
s_netid));
+            
+            String[] v_result_atts = {os_email_field,
os_givenname_field, os_surname_field, os_phone_field};
+            
+            olog.debug( "Searching LDAP for " + os_id_field + "=" +
s_netid 
+                        + " under " + os_search_context
+                        );
+
+            NamingEnumeration answer = ctx.search(os_search_context, 
+                                                  "(" + os_id_field +
"=" + s_netid + ")",
+                                                  new SearchControls(
SearchControls.SUBTREE_SCOPE,
+                                                                     
1, 20000,
+                                                                     
v_result_atts,
+                                                                     
false, false 
+                                                                     
)
+                                                  );
+            if( ! answer.hasMore()) {
+                olog.info( "Able to bind as " + s_netid + ", but
unable to find LDAP record" );
+                return null;
+            }
+            // look up attributes
+            String ldapEmail = null;
+            String ldapGivenName = null;
+            String ldapSurname = null;
+            String ldapPhone = null;
+            SearchResult sr = (SearchResult)answer.next();
+            Attributes atts = sr.getAttributes();
+            Attribute att;
+            
+            if (v_result_atts[0]!=null) {
+                att = atts.get(v_result_atts[0]);
+                if (att != null) ldapEmail = (String)att.get();
+            }
+            
+            if (v_result_atts[1]!=null) {
+                att = atts.get(v_result_atts[1]);
+                if (att != null) {
+                    ldapGivenName = (String)att.get();
+                }
+            }
+            
+            if (v_result_atts[2]!=null) {
+                att = atts.get(v_result_atts[2]);
+                if (att != null) {
+                    ldapSurname = (String)att.get();
+                }
+            }
+            
+            if (v_result_atts[3]!=null) {
+                att = atts.get(v_result_atts[3]);
+                if (att != null) {
+                    ldapPhone = (String)att.get();
+                }
+            }
+            return new SimpleDataFromLDAP( ldapEmail, ldapGivenName,
ldapSurname, ldapPhone, s_netid );
+        } finally {
+            // Close the context when we're done
+            try {
+                if (ctx != null) {
+                    ctx.close();
+                }
+            } catch (NamingException e) { }
+        }
+        // Unreachable
+    }
+}
Index: src/main/java/org/dspace/authenticate/SimpleDataFromLDAP.java
===================================================================
---
src/main/java/org/dspace/authenticate/SimpleDataFromLDAP.java   (revision
0)
+++
src/main/java/org/dspace/authenticate/SimpleDataFromLDAP.java   (revision
0)
@@ -0,0 +1,48 @@
+package org.dspace.authenticate;
+
+
+/**
+ * Simple implementation of DataFromLDAP
+ */
+public class SimpleDataFromLDAP implements DataFromLDAP {
+    /**
+     * Constructor injects all the property values
+     */
+    public SimpleDataFromLDAP ( String s_email,
+                          String s_given_name,
+                          String s_surname,
+                          String s_phone,
+                          String s_netid
+                          ) {
+        os_email = s_email;
+        os_given_name = s_given_name;
+        os_surname = s_surname;
+        os_phone = s_phone;
+        os_netid = s_netid;
+    }
+
+    private final String os_email;
+    public String getEmail () {
+        return os_email;
+    }
+
+    private final String os_given_name;
+    public String getGivenName () {
+        return os_given_name;
+    }
+
+    private final String os_surname;
+    public String getSurname() {
+        return os_surname;
+    }
+
+    private final String os_phone;
+    public String getPhone () {
+        return os_phone;
+    }
+
+    private final String os_netid;
+    public String getNetId () {
+        return os_netid;
+    }
+}
Index: src/main/java/org/dspace/authenticate/SpeakerToLDAP.java
===================================================================
---
src/main/java/org/dspace/authenticate/SpeakerToLDAP.java        (revision
0)
+++
src/main/java/org/dspace/authenticate/SpeakerToLDAP.java        (revision
0)
@@ -0,0 +1,20 @@
+package org.dspace.authenticate;
+
+import javax.naming.NamingException;
+
+/**
+ * Interface for LDAP interaction handler
+ */
+public interface SpeakerToLDAP {
+    /**
+     * Authenticate the given user with LDAP, 
+     * and get some data about him/her from the directory.
+     *
+     * @param s_netid cn of the user to authenticate
+     * @param s_password
+     * @return user info
+     */
+    public DataFromLDAP ldapAuthenticate( String s_netid, 
+                                          String s_password
+                                          ) throws NamingException;
+}
Index: src/main/java/org/dspace/authenticate/DataFromLDAP.java
===================================================================
---
src/main/java/org/dspace/authenticate/DataFromLDAP.java (revision
0)
+++
src/main/java/org/dspace/authenticate/DataFromLDAP.java (revision
0)
@@ -0,0 +1,15 @@
+package org.dspace.authenticate;
+
+
+/**
+ * POJO data bucket interface for user-data obtained during
+ * LDAP authentication
+ */
+public interface DataFromLDAP {
+    public String getEmail ();
+    public String getGivenName ();
+    public String getSurname();
+    public String getPhone ();
+    /** LDAP common name (cn) for the user */
+    public String getNetId ();
+}




-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
DSpace-tech mailing list
DSpace-tech@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dspace-tech

Reply via email to