Flavio, Yes, the problem isn't in coming up with a solution, its in coordinating with the commiters to shepherd through the change. Which has always been a total bottleneck in the community (as one can see by the long list of patches that go unapplied).
Part of this also has to do with the fact that everything done here by commiters is voluntary, and because of this there is a tendency to focus on projects that one would find advantageous to ones organizations own needs. The end result is that work done is that which the commiters want/need to do, not necessarily work that the community wishes/needs to get done. The flip side of this is that the commiters group is really the only technical body available that is capable of evaluating the patches to assure they meet the criteria needed to be accepted into the core code-base. IMO, the group needs to grow and the community needs to take a larger role in maintaining and improving the code-base. It is extremely important to note that the Commiters recognize this and have worked hard to introduce mechanisms to allow layers of plug- ability in the API. The AuthenticationManager is an example of such plug-ability. The goal being not to force a single specific "core implementation" of an LDAPAuthenticator onto the community, but instead allow the community to create their own Addons such as an LDAPAuthenticator plugin that will support the enhancements they want. Your code seems to do quite a bit of enhancement to the simple LDAPAuthenticator example provided in the code-base. I would recommend that rather than pushing for "inclusion" into the core code- base. We should be working to get your work available to the community as an Addon that can be added to anyones dspace build to support the level of LDAP Authentication your requiring. --------- Its been my personal agenda to try to resolve the above situation by actually breaking up the stranglehold on the code-base at Sourceforge. Rob Tansley recently started a svn repository at code.google.com and some of us in the community have been pushing that this be a much more open location to work on dspace addons and prototype that S.F. SVN. I (and certainly others in the commiters group) hope to see it be the case that significant chunks of code might move out of S.F. and be maintained in the sandbox by more of the community instead. Please read: http://wiki.dspace.org/index.php// DspaceResources#DSpace_Community_Sandbox --------- I've attempted to get folks to come into the dspace-sandbox and implement/test and push through changes in public transparent development groups. This is the only real way that I see around the bottleneck. Certainly, new authenticators would benefit from such community adoption. Your work could represent such an opportunity to prove this point by introducing a new home for the LDAPAuthenticator code and new blood to work on it. This will not only circumvent the above bottleneck, but it will also introduce a place where yourself and other interested in improving and working with this functionality can more freely work in the future. To prove the point, I've placed your code into the following project and I would recommend the following to anyone interested in working on the LDAPAuthentication support (or any other Authenticator support) in dspace: If you would like to work on this code-base, I highly recommend you get together and work on it as a group, working on it here until stable, after which we can introduce a dependency on it, drop the original LDAPAuthenticator and include yours in place of it as a dependency into dspace. http://dspace-sandbox.googlecode.com/svn/modules/dspace-ldap/trunk/ Lets us know if this is something you would entertain. Sincerely, Mark Diggory On Aug 28, 2008, at 9:18 AM, Flavio Botelho wrote: > Hello All, > > It's just me, or doesnt anybody else think there is a major problem > with effort coordination when a 4th person appears with yet another > LDAP patch for Dspace in a timespace of 2 years? > > I know for now Stuart is working on LDAP and getting it solved soon. > > But I don't think it's a problem specific to LDAP but much more how > 3rd party patches are handled by the main commiters. Years to have > feedback don't make people willing to commit time/resources for > anything outside trivial patches. > I have seen main commiters complaining about the lack of > time/resources, but if they don't provide a sane way for 3rd paties to > help then it won't happen much. > > Kudos, > Flavio Botelho > Programmer/Superior Court of Justice-Brazil > > > ---------- Forwarded message ---------- > From: Reuben Pasquini <[EMAIL PROTECTED]> > Date: Thu, Aug 28, 2008 at 12:14 PM > Subject: [Dspace-tech] LDAPAuthentication patch to consider > To: "[EMAIL PROTECTED]" <dspace- > [EMAIL PROTECTED]> > Cc: [EMAIL PROTECTED] > > > 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 > [EMAIL PROTECTED] > https://lists.sourceforge.net/lists/listinfo/dspace-tech > > ---------------------------------------------------------------------- > --- > 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-devel mailing list > [email protected] > https://lists.sourceforge.net/lists/listinfo/dspace-devel ------------------------------------------------------------------------- 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-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/dspace-devel
