Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

consolidate LDAP and LDAPHierarchical auth

Thanks to the previously merged DS-1180, the LDAPHierarchicalAuthentication
method gaind the capabilities of LDAPAuthentication. This commit renames
LDAPHierarchicalAuthentication to LDAPAuthentication and removes the
original LDAPAuthentication.
  • Loading branch information...
commit 3c45c1bc675479413e3bd8313893375b7c1b2ec4 1 parent 79c0142
@helix84 helix84 authored
View
592 dspace-api/src/main/java/org/dspace/authenticate/LDAPAuthentication.java
@@ -9,19 +9,16 @@
import java.sql.SQLException;
import java.util.Hashtable;
+import java.util.HashSet;
+import java.util.Set;
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.naming.directory.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.core.ConfigurationManager;
@@ -31,10 +28,16 @@
import org.dspace.eperson.Group;
/**
- * Authentication module to authenticate against a flat LDAP tree where
- * all users are in the same unit.
+ * This combined LDAP authentication method supersedes both the 'LDAPAuthentication'
+ * and the 'LDAPHierarchicalAuthentication' methods. It's capable of both:
+ * - authenticaton against a flat LDAP tree where all users are in the same unit
+ * (if search.user or search.password is not set)
+ * - authentication against structured hierarchical LDAP trees of users.
+ * An initial bind is required using a user name and password in order to
+ * search the tree and find the DN of the user. A second bind is then required to
+ * check the credentials of the user by binding directly to their DN.
*
- * @author Larry Stone, Stuart Lewis
+ * @author Stuart Lewis, Chris Yates, Alex Barbieri, Flavio Botelho, Reuben Pasquini, Samuel Ottenhoff, Ivan Masár
* @version $Revision$
*/
public class LDAPAuthentication
@@ -43,7 +46,7 @@
/** log4j category */
private static Logger log = Logger.getLogger(LDAPAuthentication.class);
- /**
+ /**
* Let a real auth method return true if it wants.
*/
public boolean canSelfRegister(Context context,
@@ -51,8 +54,7 @@ public boolean canSelfRegister(Context context,
String username)
throws SQLException
{
- // XXX might also want to check that username exists in LDAP.
-
+ // Looks to see if autoregister is set or not
return ConfigurationManager.getBooleanProperty("authentication-ldap", "autoregister");
}
@@ -89,7 +91,7 @@ public boolean isImplicit()
/*
* Add authenticated users to the group defined in dspace.cfg by
- * the ldap.login.specialgroup key.
+ * the login.specialgroup key.
*/
public int[] getSpecialGroups(Context context, HttpServletRequest request)
{
@@ -102,7 +104,7 @@ public boolean isImplicit()
String groupName = ConfigurationManager.getProperty("authentication-ldap", "login.specialgroup");
if ((groupName != null) && (!groupName.trim().equals("")))
{
- Group ldapGroup = Group.findByName(context, groupName);
+ Group ldapGroup = Group.findByName(context, groupName);
if (ldapGroup == null)
{
// Oops - the group isn't there.
@@ -122,12 +124,39 @@ public boolean isImplicit()
}
return new int[0];
}
-
- /*
- * MIT policy on certs and groups, so always short-circuit.
+
+ /*
+ * Authenticate the given credentials.
+ * This is the heart of the authentication method: test the
+ * credentials for authenticity, and if accepted, attempt to match
+ * (or optionally, create) an <code>EPerson</code>. If an <code>EPerson</code> is found it is
+ * set in the <code>Context</code> that was passed.
+ *
+ * @param context
+ * DSpace context, will be modified (ePerson set) upon success.
+ *
+ * @param username
+ * Username (or email address) when method is explicit. Use null for
+ * implicit method.
+ *
+ * @param password
+ * Password for explicit auth, or null for implicit method.
+ *
+ * @param realm
+ * Realm is an extra parameter used by some authentication methods, leave null if
+ * not applicable.
+ *
+ * @param request
+ * The HTTP request that started this operation, or null if not applicable.
*
* @return One of:
* SUCCESS, BAD_CREDENTIALS, CERT_REQUIRED, NO_SUCH_USER, BAD_ARGS
+ * <p>Meaning:
+ * <br>SUCCESS - authenticated OK.
+ * <br>BAD_CREDENTIALS - user exists, but credentials (e.g. passwd) don't match
+ * <br>CERT_REQUIRED - not allowed to login this way without X.509 cert.
+ * <br>NO_SUCH_USER - user not found using this method.
+ * <br>BAD_ARGS - user/pw not appropriate for this method
*/
public int authenticate(Context context,
String netid,
@@ -155,7 +184,32 @@ public int authenticate(Context context,
}
SpeakerToLDAP ldap = new SpeakerToLDAP(log);
- // if they entered a netid that matches an eperson
+ // Get the DN of the user
+ String adminUser = ConfigurationManager.getProperty("authentication-ldap", "search.user");
+ String adminPassword = ConfigurationManager.getProperty("authentication-ldap", "search.password");
+ String objectContext = ConfigurationManager.getProperty("authentication-ldap", "object_context");
+ String idField = ConfigurationManager.getProperty("authentication-ldap", "id_field");
+ String dn = "";
+
+ // If adminUser is blank, then we can't search so assume the DN
+ if (StringUtils.isBlank(adminUser) || StringUtils.isBlank(adminPassword))
+ {
+ dn = idField + "=" + netid + "," + objectContext;
+ }
+ else
+ {
+ dn = ldap.getDNOfUser(adminUser, adminPassword, context, netid);
+ }
+
+ // Check a DN was found
+ if ((dn == null) || (dn.trim().equals("")))
+ {
+ log.info(LogManager
+ .getHeader(context, "failed_login", "no DN found for user " + netid));
+ return BAD_CREDENTIALS;
+ }
+
+ // if they entered a netid that matches an eperson
if (eperson != null)
{
// e-mail address corresponds to active account
@@ -168,11 +222,15 @@ else if (!eperson.canLogIn())
return BAD_ARGS;
}
- if (ldap.ldapAuthenticate(netid, password, context))
+ if (ldap.ldapAuthenticate(dn, password, context))
{
- eperson = EPerson.findByNetid(context, netid.toLowerCase());
context.setCurrentUser(eperson);
- log.info(LogManager.getHeader(context, "authenticate", "type=ldap"));
+
+ // assign user to groups based on ldap dn
+ assignGroupsBasedOnLdapDn(dn, context);
+
+ log.info(LogManager
+ .getHeader(context, "authenticate", "type=ldap"));
return SUCCESS;
}
else
@@ -185,7 +243,7 @@ else if (!eperson.canLogIn())
// with ldap and create an eperson for them
else
{
- if (ldap.ldapAuthenticate(netid, password, context))
+ if (ldap.ldapAuthenticate(dn, password, context))
{
// Register the new user automatically
log.info(LogManager.getHeader(context,
@@ -201,85 +259,92 @@ else if (!eperson.canLogIn())
if ((email != null) && (!"".equals(email)))
{
- try
- {
- eperson = EPerson.findByEmail(context, email);
- if (eperson!=null)
- {
- log.info(LogManager.getHeader(context,
- "type=ldap-login", "type=ldap_but_already_email"));
- context.setIgnoreAuthorization(true);
- eperson.setNetid(netid.toLowerCase());
- 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 ((email != null) && (!"".equals(email)))
+ try
+ {
+ eperson = EPerson.findByEmail(context, email);
+ if (eperson!=null)
+ {
+ log.info(LogManager.getHeader(context,
+ "type=ldap-login", "type=ldap_but_already_email"));
+ context.setIgnoreAuthorization(true);
+ eperson.setNetid(netid.toLowerCase());
+ eperson.update();
+ context.commit();
+ context.setIgnoreAuthorization(false);
+ context.setCurrentUser(eperson);
+
+ // assign user to groups based on ldap dn
+ assignGroupsBasedOnLdapDn(dn, context);
+
+ return SUCCESS;
+ }
+ else
+ {
+ if (canSelfRegister(context, request, netid))
+ {
+ // TEMPORARILY turn off authorisation
+ try
+ {
+ context.setIgnoreAuthorization(true);
+ eperson = EPerson.create(context);
+ if ((email != null) && (!"".equals(email)))
{
eperson.setEmail(email);
}
- 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.toLowerCase());
- eperson.setCanLogIn(true);
- AuthenticationManager.initEPerson(context, request, eperson);
- eperson.update();
- context.commit();
+ 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.toLowerCase());
+ eperson.setCanLogIn(true);
+ AuthenticationManager.initEPerson(context, request, eperson);
+ eperson.update();
+ context.commit();
context.setCurrentUser(eperson);
+
+ // assign user to groups based on ldap dn
+ assignGroupsBasedOnLdapDn(dn, context);
}
- 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);
- }
- }
- }
+ 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);
+ }
+ }
+ }
}
return BAD_ARGS;
}
@@ -292,141 +357,219 @@ else if (!eperson.canLogIn())
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)
+ /** LDAP settings */
+ String ldap_provider_url = ConfigurationManager.getProperty("authentication-ldap", "provider_url");
+ String ldap_id_field = ConfigurationManager.getProperty("authentication-ldap", "id_field");
+ String ldap_search_context = ConfigurationManager.getProperty("authentication-ldap", "search_context");
+ String ldap_search_scope = ConfigurationManager.getProperty("authentication-ldap", "search_scope");
+
+ String ldap_email_field = ConfigurationManager.getProperty("authentication-ldap", "email_field");
+ String ldap_givenname_field = ConfigurationManager.getProperty("authentication-ldap", "givenname_field");
+ String ldap_surname_field = ConfigurationManager.getProperty("authentication-ldap", "surname_field");
+ String ldap_phone_field = ConfigurationManager.getProperty("authentication-ldap", "phone_field");
+
+ SpeakerToLDAP(Logger thelog)
{
log = thelog;
}
- /**
- * 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("authentication-ldap", "provider_url");
- String ldap_id_field = ConfigurationManager.getProperty("authentication-ldap", "id_field");
- String ldap_search_context = ConfigurationManager.getProperty("authentication-ldap", "search_context");
- String ldap_object_context = ConfigurationManager.getProperty("authentication-ldap", "object_context");
+ protected String getDNOfUser(String adminUser, String adminPassword, Context context, String netid)
+ {
+ // The resultant DN
+ String resultDN;
+
+ // The search scope to use (default to 0)
+ int ldap_search_scope_value = 0;
+ try
+ {
+ ldap_search_scope_value = Integer.parseInt(ldap_search_scope.trim());
+ }
+ catch (NumberFormatException e)
+ {
+ // Log the error if it has been set but is invalid
+ if (ldap_search_scope != null)
+ {
+ log.warn(LogManager.getHeader(context,
+ "ldap_authentication", "invalid search scope: " + ldap_search_scope));
+ }
+ }
- // 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);
+ // 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
+ if ((adminUser != null) && (!adminUser.trim().equals("")) &&
+ (adminPassword != null) && (!adminPassword.trim().equals("")))
+ {
+ // Use admin credencials for search// 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);
+ env.put(javax.naming.Context.SECURITY_PRINCIPAL, adminUser);
+ env.put(javax.naming.Context.SECURITY_CREDENTIALS, adminPassword);
+ }
+ else
+ {
+ // Use anonymous authentication
+ env.put(javax.naming.Context.SECURITY_AUTHENTICATION, "none");
+ }
- String ldap_email_field = ConfigurationManager.getProperty("authentication-ldap", "email_field");
- String ldap_givenname_field = ConfigurationManager.getProperty("authentication-ldap", "givenname_field");
- String ldap_surname_field = ConfigurationManager.getProperty("authentication-ldap", "surname_field");
- String ldap_phone_field = ConfigurationManager.getProperty("authentication-ldap", "phone_field");
+ DirContext ctx = null;
+ try
+ {
+ // Create initial context
+ ctx = new InitialDirContext(env);
- Attributes matchAttrs = new BasicAttributes(true);
- matchAttrs.put(new BasicAttribute(ldap_id_field, netid));
+ 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
+ {
+ SearchControls ctrls = new SearchControls();
+ ctrls.setSearchScope(ldap_search_scope_value);
+
+ NamingEnumeration<SearchResult> answer = ctx.search(
+ ldap_provider_url + ldap_search_context,
+ "(&({0}={1}))", new Object[] { ldap_id_field,
+ netid }, ctrls);
+
+ while (answer.hasMoreElements()) {
+ SearchResult sr = answer.next();
+ if (StringUtils.isEmpty(ldap_search_context)) {
+ resultDN = sr.getName();
+ } else {
+ resultDN = (sr.getName() + "," + ldap_search_context);
+ }
- // 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;
+ String attlist[] = {ldap_email_field, ldap_givenname_field,
+ ldap_surname_field, ldap_phone_field};
+ Attributes atts = sr.getAttributes();
+ Attribute att;
- if (attlist[0]!=null)
+ if (attlist[0] != null) {
+ att = atts.get(attlist[0]);
+ if (att != null)
{
- att = atts.get(attlist[0]);
- if (att != null)
- {
- ldapEmail = (String) att.get();
- }
+ ldapEmail = (String) att.get();
}
+ }
- if (attlist[1]!=null)
+ if (attlist[1] != null) {
+ att = atts.get(attlist[1]);
+ if (att != null)
{
- att = atts.get(attlist[1]);
- if (att != null)
- {
- ldapGivenName = (String) att.get();
- }
+ ldapGivenName = (String) att.get();
}
+ }
- if (attlist[2]!=null)
+ if (attlist[2] != null) {
+ att = atts.get(attlist[2]);
+ if (att != null)
{
- att = atts.get(attlist[2]);
- if (att != null)
- {
- ldapSurname = (String) att.get();
- }
+ ldapSurname = (String) att.get();
}
+ }
- if (attlist[3]!=null)
+ if (attlist[3] != null) {
+ att = atts.get(attlist[3]);
+ if (att != null)
{
- att = atts.get(attlist[3]);
- if (att != null)
- {
- ldapPhone = (String) att.get();
- }
+ ldapPhone = (String) att.get();
}
- }
- }
- catch (NamingException e)
+ }
+
+ if (answer.hasMoreElements()) {
+ // Oh dear - more than one match
+ // Ambiguous user, can't continue
+
+ } else {
+ log.debug(LogManager.getHeader(context, "got DN", resultDN));
+ return resultDN;
+ }
+ }
+ }
+ 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));
+ }
+ }
+ catch (NamingException e)
+ {
+ log.warn(LogManager.getHeader(context,
+ "ldap_authentication", "type=failed_auth " + e));
+ }
+ finally
+ {
+ // Close the context when we're done
+ try
+ {
+ if (ctx != null)
{
- // 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;
+ ctx.close();
}
- }
- 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)
+ }
+ catch (NamingException e)
+ {
+ }
+ }
+
+ // No DN match found
+ return null;
+ }
+
+ /**
+ * contact the ldap server and attempt to authenticate
+ */
+ protected boolean ldapAuthenticate(String netid, String password,
+ Context context) {
+ if (!password.equals("")) {
+ // Set up environment for creating initial context
+ Hashtable<String, String> env = new Hashtable<String, String>();
+ 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, netid);
+ env.put(javax.naming.Context.SECURITY_CREDENTIALS, password);
+ env.put(javax.naming.Context.AUTHORITATIVE, "true");
+ env.put(javax.naming.Context.REFERRAL, "follow");
+
+ DirContext ctx = null;
+ try {
+ // Try to bind
+ ctx = new InitialDirContext(env);
+ } 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();
}
- }
- catch (NamingException e)
- {
- }
- }
- }
- else
- {
- return false;
- }
+ } catch (NamingException e) {
+ }
+ }
+ } else {
+ return false;
+ }
- return true;
- }
- }
+ return true;
+ }
+ }
/*
* Returns URL to which to redirect to obtain credentials (either password
@@ -464,4 +607,57 @@ public String loginPageTitle(Context context)
{
return "org.dspace.eperson.LDAPAuthentication.title";
}
+
+
+ /*
+ * Add authenticated users to the group defined in dspace.cfg by
+ * the ldap.login.groupmap.* key.
+ */
+ private void assignGroupsBasedOnLdapDn(String dn, Context context)
+ {
+ if (StringUtils.isNotBlank(dn))
+ {
+ System.out.println("dn:" + dn);
+ int i = 1;
+ String groupMap = ConfigurationManager.getProperty("authentication-ldap", "login.groupmap." + i);
+ while (groupMap != null)
+ {
+ String t[] = groupMap.split(":");
+ String ldapSearchString = t[0];
+ String dspaceGroupName = t[1];
+
+ if (StringUtils.containsIgnoreCase(dn, ldapSearchString))
+ {
+ // assign user to this group
+ try
+ {
+ Group ldapGroup = Group.findByName(context, dspaceGroupName);
+ if (ldapGroup != null)
+ {
+ ldapGroup.addMember(context.getCurrentUser());
+ ldapGroup.update();
+ context.commit();
+ }
+ else
+ {
+ // The group does not exist
+ log.warn(LogManager.getHeader(context,
+ "ldap_assignGroupsBasedOnLdapDn",
+ "Group defined in ldap.login.groupmap." + i + " does not exist :: " + dspaceGroupName));
+ }
+ }
+ catch (AuthorizeException ae)
+ {
+ log.debug(LogManager.getHeader(context, "assignGroupsBasedOnLdapDn could not authorize addition to group", dspaceGroupName));
+ }
+ catch (SQLException e)
+ {
+ log.debug(LogManager.getHeader(context, "assignGroupsBasedOnLdapDn could not find group", dspaceGroupName));
+ }
+ }
+
+ groupMap = ConfigurationManager.getProperty("ldap.login.groupmap." + ++i);
+ }
+ }
+ }
}
View
660 dspace-api/src/main/java/org/dspace/authenticate/LDAPHierarchicalAuthentication.java
@@ -1,660 +0,0 @@
-/**
- * The contents of this file are subject to the license and copyright
- * detailed in the LICENSE and NOTICE files at the root of the source
- * tree and available online at
- *
- * http://www.dspace.org/license/
- */
-package org.dspace.authenticate;
-
-import java.sql.SQLException;
-import java.util.Hashtable;
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.*;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.log4j.Logger;
-import org.dspace.authorize.AuthorizeException;
-import org.dspace.core.ConfigurationManager;
-import org.dspace.core.Context;
-import org.dspace.core.LogManager;
-import org.dspace.eperson.EPerson;
-import org.dspace.eperson.Group;
-
-/**
- * This LDAP authentication method is more complex than the simple 'LDAPAuthentication'
- * in that it allows authentication against structured hierarchical LDAP trees of
- * users. An initial bind is required using a user name and password in order to
- * search the tree and find the DN of the user. A second bind is then required to
- * check the credentials of the user by binding directly to their DN.
- *
- * @author Stuart Lewis, Chris Yates, Alex Barbieri, Flavio Botelho, Reuben Pasquini
- * @version $Revision$
- */
-public class LDAPHierarchicalAuthentication
- implements AuthenticationMethod {
-
- /** log4j category */
- private static Logger log = Logger.getLogger(LDAPHierarchicalAuthentication.class);
-
- /**
- * Let a real auth method return true if it wants.
- */
- public boolean canSelfRegister(Context context,
- HttpServletRequest request,
- String username)
- throws SQLException
- {
- // Looks to see if autoregister is set or not
- return ConfigurationManager.getBooleanProperty("authentication-ldap", "autoregister");
- }
-
- /**
- * Nothing here, initialization is done when auto-registering.
- */
- public void initEPerson(Context context, HttpServletRequest request,
- EPerson eperson)
- throws SQLException
- {
- // XXX should we try to initialize netid based on email addr,
- // XXX for eperson created by some other method??
- }
-
- /**
- * Cannot change LDAP password through dspace, right?
- */
- public boolean allowSetPassword(Context context,
- HttpServletRequest request,
- String username)
- throws SQLException
- {
- // XXX is this right?
- return false;
- }
-
- /*
- * This is an explicit method.
- */
- public boolean isImplicit()
- {
- return false;
- }
-
- /*
- * Add authenticated users to the group defined in dspace.cfg by
- * the login.specialgroup key.
- */
- public int[] getSpecialGroups(Context context, HttpServletRequest request)
- {
- // Prevents anonymous users from being added to this group, and the second check
- // ensures they are LDAP users
- try
- {
- if (!context.getCurrentUser().getNetid().equals(""))
- {
- String groupName = ConfigurationManager.getProperty("authentication-ldap", "login.specialgroup");
- if ((groupName != null) && (!groupName.trim().equals("")))
- {
- Group ldapGroup = Group.findByName(context, groupName);
- if (ldapGroup == null)
- {
- // Oops - the group isn't there.
- log.warn(LogManager.getHeader(context,
- "ldap_specialgroup",
- "Group defined in login.specialgroup does not exist"));
- return new int[0];
- } else
- {
- return new int[] { ldapGroup.getID() };
- }
- }
- }
- }
- catch (Exception npe) {
- // The user is not an LDAP user, so we don't need to worry about them
- }
- return new int[0];
- }
-
- /*
- * Authenticate the given credentials.
- * This is the heart of the authentication method: test the
- * credentials for authenticity, and if accepted, attempt to match
- * (or optionally, create) an <code>EPerson</code>. If an <code>EPerson</code> is found it is
- * set in the <code>Context</code> that was passed.
- *
- * @param context
- * DSpace context, will be modified (ePerson set) upon success.
- *
- * @param username
- * Username (or email address) when method is explicit. Use null for
- * implicit method.
- *
- * @param password
- * Password for explicit auth, or null for implicit method.
- *
- * @param realm
- * Realm is an extra parameter used by some authentication methods, leave null if
- * not applicable.
- *
- * @param request
- * The HTTP request that started this operation, or null if not applicable.
- *
- * @return One of:
- * SUCCESS, BAD_CREDENTIALS, CERT_REQUIRED, NO_SUCH_USER, BAD_ARGS
- * <p>Meaning:
- * <br>SUCCESS - authenticated OK.
- * <br>BAD_CREDENTIALS - user exists, but credentials (e.g. passwd) don't match
- * <br>CERT_REQUIRED - not allowed to login this way without X.509 cert.
- * <br>NO_SUCH_USER - user not found using this method.
- * <br>BAD_ARGS - user/pw not appropriate for this method
- */
- public int authenticate(Context context,
- String netid,
- String password,
- String realm,
- HttpServletRequest request)
- throws SQLException
- {
- log.info(LogManager.getHeader(context, "auth", "attempting trivial auth of user="+netid));
-
- // Skip out when no netid or password is given.
- if (netid == null || password == null)
- {
- return BAD_ARGS;
- }
-
- // Locate the eperson
- EPerson eperson = null;
- try
- {
- eperson = EPerson.findByNetid(context, netid.toLowerCase());
- }
- catch (SQLException e)
- {
- }
- SpeakerToLDAP ldap = new SpeakerToLDAP(log);
-
- // Get the DN of the user
- String adminUser = ConfigurationManager.getProperty("authentication-ldap", "search.user");
- String adminPassword = ConfigurationManager.getProperty("authentication-ldap", "search.password");
- String objectContext = ConfigurationManager.getProperty("authentication-ldap", "object_context");
- String idField = ConfigurationManager.getProperty("authentication-ldap", "id_field");
- String dn = "";
-
- // If adminUser is blank, then we can't search so assume the DN
- if (StringUtils.isBlank(adminUser) || StringUtils.isBlank(adminPassword))
- {
- dn = idField + "=" + netid + "," + objectContext;
- }
- else
- {
- dn = ldap.getDNOfUser(adminUser, adminPassword, context, netid);
- }
-
- // Check a DN was found
- if ((dn == null) || (dn.trim().equals("")))
- {
- log.info(LogManager
- .getHeader(context, "failed_login", "no DN found for user " + netid));
- return BAD_CREDENTIALS;
- }
-
- // if they entered a netid that matches an eperson
- if (eperson != null)
- {
- // e-mail address corresponds to active account
- if (eperson.getRequireCertificate())
- {
- return CERT_REQUIRED;
- }
- else if (!eperson.canLogIn())
- {
- return BAD_ARGS;
- }
-
- if (ldap.ldapAuthenticate(dn, password, context))
- {
- context.setCurrentUser(eperson);
-
- // assign user to groups based on ldap dn
- assignGroupsBasedOnLdapDn(dn, context);
-
- log.info(LogManager
- .getHeader(context, "authenticate", "type=ldap"));
- return SUCCESS;
- }
- else
- {
- return BAD_CREDENTIALS;
- }
- }
-
- // the user does not already exist so try and authenticate them
- // with ldap and create an eperson for them
- else
- {
- if (ldap.ldapAuthenticate(dn, password, context))
- {
- // Register the new user automatically
- log.info(LogManager.getHeader(context,
- "autoregister", "netid=" + netid));
-
- // If there is no email and the email domain is set, add it to the netid
- String email = ldap.ldapEmail;
- if (((email == null) || ("".equals(email))) &&
- (!"".equals(ConfigurationManager.getProperty("authentication-ldap", "netid_email_domain"))))
- {
- email = netid + ConfigurationManager.getProperty("authentication-ldap", "netid_email_domain");
- }
-
- if ((email != null) && (!"".equals(email)))
- {
- try
- {
- eperson = EPerson.findByEmail(context, email);
- if (eperson!=null)
- {
- log.info(LogManager.getHeader(context,
- "type=ldap-login", "type=ldap_but_already_email"));
- context.setIgnoreAuthorization(true);
- eperson.setNetid(netid.toLowerCase());
- eperson.update();
- context.commit();
- context.setIgnoreAuthorization(false);
- context.setCurrentUser(eperson);
-
- // assign user to groups based on ldap dn
- assignGroupsBasedOnLdapDn(dn, context);
-
- return SUCCESS;
- }
- else
- {
- if (canSelfRegister(context, request, netid))
- {
- // TEMPORARILY turn off authorisation
- try
- {
- context.setIgnoreAuthorization(true);
- eperson = EPerson.create(context);
- if ((email != null) && (!"".equals(email)))
- {
- eperson.setEmail(email);
- }
- 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.toLowerCase());
- eperson.setCanLogIn(true);
- AuthenticationManager.initEPerson(context, request, eperson);
- eperson.update();
- context.commit();
- context.setCurrentUser(eperson);
-
- // assign user to groups based on ldap dn
- assignGroupsBasedOnLdapDn(dn, context);
- }
- 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);
- }
- }
- }
- }
- return BAD_ARGS;
- }
-
- /**
- * Internal class to manage LDAP query and results, mainly
- * because there are multiple values to return.
- */
- private static class SpeakerToLDAP {
-
- private Logger log = null;
-
- protected String ldapEmail = null;
- protected String ldapGivenName = null;
- protected String ldapSurname = null;
- protected String ldapPhone = null;
-
- /** LDAP settings */
- String ldap_provider_url = ConfigurationManager.getProperty("authentication-ldap", "provider_url");
- String ldap_id_field = ConfigurationManager.getProperty("authentication-ldap", "id_field");
- String ldap_search_context = ConfigurationManager.getProperty("authentication-ldap", "search_context");
- String ldap_search_scope = ConfigurationManager.getProperty("authentication-ldap", "search_scope");
-
- String ldap_email_field = ConfigurationManager.getProperty("authentication-ldap", "email_field");
- String ldap_givenname_field = ConfigurationManager.getProperty("authentication-ldap", "givenname_field");
- String ldap_surname_field = ConfigurationManager.getProperty("authentication-ldap", "surname_field");
- String ldap_phone_field = ConfigurationManager.getProperty("authentication-ldap", "phone_field");
-
- SpeakerToLDAP(Logger thelog)
- {
- log = thelog;
- }
-
- protected String getDNOfUser(String adminUser, String adminPassword, Context context, String netid)
- {
- // The resultant DN
- String resultDN;
-
- // The search scope to use (default to 0)
- int ldap_search_scope_value = 0;
- try
- {
- ldap_search_scope_value = Integer.parseInt(ldap_search_scope.trim());
- }
- catch (NumberFormatException e)
- {
- // Log the error if it has been set but is invalid
- if (ldap_search_scope != null)
- {
- log.warn(LogManager.getHeader(context,
- "ldap_authentication", "invalid search scope: " + ldap_search_scope));
- }
- }
-
- // 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);
-
- if ((adminUser != null) && (!adminUser.trim().equals("")) &&
- (adminPassword != null) && (!adminPassword.trim().equals("")))
- {
- // Use admin credencials for search// Authenticate
- env.put(javax.naming.Context.SECURITY_AUTHENTICATION, "simple");
- env.put(javax.naming.Context.SECURITY_PRINCIPAL, adminUser);
- env.put(javax.naming.Context.SECURITY_CREDENTIALS, adminPassword);
- }
- else
- {
- // Use anonymous authentication
- env.put(javax.naming.Context.SECURITY_AUTHENTICATION, "none");
- }
-
- DirContext ctx = null;
- try
- {
- // Create initial context
- ctx = new InitialDirContext(env);
-
- Attributes matchAttrs = new BasicAttributes(true);
- matchAttrs.put(new BasicAttribute(ldap_id_field, netid));
-
- // look up attributes
- try
- {
- SearchControls ctrls = new SearchControls();
- ctrls.setSearchScope(ldap_search_scope_value);
-
- NamingEnumeration<SearchResult> answer = ctx.search(
- ldap_provider_url + ldap_search_context,
- "(&({0}={1}))", new Object[] { ldap_id_field,
- netid }, ctrls);
-
- while (answer.hasMoreElements()) {
- SearchResult sr = answer.next();
- if (StringUtils.isEmpty(ldap_search_context)) {
- resultDN = sr.getName();
- } else {
- resultDN = (sr.getName() + "," + ldap_search_context);
- }
-
- String attlist[] = {ldap_email_field, ldap_givenname_field,
- ldap_surname_field, ldap_phone_field};
- 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();
- }
- }
-
- if (answer.hasMoreElements()) {
- // Oh dear - more than one match
- // Ambiguous user, can't continue
-
- } else {
- log.debug(LogManager.getHeader(context, "got DN", resultDN));
- return resultDN;
- }
- }
- }
- 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));
- }
- }
- catch (NamingException e)
- {
- log.warn(LogManager.getHeader(context,
- "ldap_authentication", "type=failed_auth " + e));
- }
- finally
- {
- // Close the context when we're done
- try
- {
- if (ctx != null)
- {
- ctx.close();
- }
- }
- catch (NamingException e)
- {
- }
- }
-
- // No DN match found
- return null;
- }
-
- /**
- * contact the ldap server and attempt to authenticate
- */
- protected boolean ldapAuthenticate(String netid, String password,
- Context context) {
- if (!password.equals("")) {
- // Set up environment for creating initial context
- Hashtable<String, String> env = new Hashtable<String, String>();
- 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, netid);
- env.put(javax.naming.Context.SECURITY_CREDENTIALS, password);
- env.put(javax.naming.Context.AUTHORITATIVE, "true");
- env.put(javax.naming.Context.REFERRAL, "follow");
-
- DirContext ctx = null;
- try {
- // Try to bind
- ctx = new InitialDirContext(env);
- } 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();
- }
- } catch (NamingException e) {
- }
- }
- } else {
- return false;
- }
-
- return true;
- }
- }
-
- /*
- * Returns URL to which to redirect to obtain credentials (either password
- * prompt or e.g. HTTPS port for client cert.); null means no redirect.
- *
- * @param context
- * DSpace context, will be modified (ePerson set) upon success.
- *
- * @param request
- * The HTTP request that started this operation, or null if not applicable.
- *
- * @param response
- * The HTTP response from the servlet method.
- *
- * @return fully-qualified URL
- */
- public String loginPageURL(Context context,
- HttpServletRequest request,
- HttpServletResponse response)
- {
- return response.encodeRedirectURL(request.getContextPath() +
- "/ldap-login");
- }
-
- /**
- * Returns message key for title of the "login" page, to use
- * in a menu showing the choice of multiple login methods.
- *
- * @param context
- * DSpace context, will be modified (ePerson set) upon success.
- *
- * @return Message key to look up in i18n message catalog.
- */
- public String loginPageTitle(Context context)
- {
- return "org.dspace.eperson.LDAPAuthentication.title";
- }
-
-
- /*
- * Add authenticated users to the group defined in dspace.cfg by
- * the ldap.login.groupmap.* key.
- */
- private void assignGroupsBasedOnLdapDn(String dn, Context context)
- {
- if (StringUtils.isNotBlank(dn))
- {
- System.out.println("dn:" + dn);
- int i = 1;
- String groupMap = ConfigurationManager.getProperty("authentication-ldap", "login.groupmap." + i);
- while (groupMap != null)
- {
- String t[] = groupMap.split(":");
- String ldapSearchString = t[0];
- String dspaceGroupName = t[1];
-
- if (StringUtils.containsIgnoreCase(dn, ldapSearchString))
- {
- // assign user to this group
- try
- {
- Group ldapGroup = Group.findByName(context, dspaceGroupName);
- if (ldapGroup != null)
- {
- ldapGroup.addMember(context.getCurrentUser());
- ldapGroup.update();
- context.commit();
- }
- else
- {
- // The group does not exist
- log.warn(LogManager.getHeader(context,
- "ldap_assignGroupsBasedOnLdapDn",
- "Group defined in ldap.login.groupmap." + i + " does not exist :: " + dspaceGroupName));
- }
- }
- catch (AuthorizeException ae)
- {
- log.debug(LogManager.getHeader(context, "assignGroupsBasedOnLdapDn could not authorize addition to group", dspaceGroupName));
- }
- catch (SQLException e)
- {
- log.debug(LogManager.getHeader(context, "assignGroupsBasedOnLdapDn could not find group", dspaceGroupName));
- }
- }
-
- groupMap = ConfigurationManager.getProperty("ldap.login.groupmap." + ++i);
- }
- }
- }
-}
View
12 dspace/config/modules/authentication-ldap.cfg
@@ -6,8 +6,7 @@
#---------------------------------------------------------------#
#
# In order to enable LDAP Authentication, you must first ensure the
-# 'org.dspace.authenticate.LDAPAuthentication' OR
-# 'org.dspace.authenticate.LDAPHierarchicalAuthentication'
+# 'org.dspace.authenticate.LDAPAuthentication'
# class is added to the list of enabled AuthenticationMethods in 'authenticate.cfg'.
# See 'authenticate.cfg' for more info.
#
@@ -112,10 +111,9 @@ autoregister = true
##### Hierarchical LDAP Settings #####
# If your users are spread out across a hierarchical tree on your
-# LDAP server, you will need to use the following stackable authentication
-# class:
-# plugin.sequence.org.dspace.authenticate.AuthenticationMethod = \
-# org.dspace.authenticate.LDAPHierarchicalAuthentication
+# LDAP server, you will need to specify the username and password of
+# a user who is allowed to search the tree to find the full DN of
+# the user who is logging in.
#
# You can optionally specify the search scope. If anonymous access is not
# enabled on your LDAP server, you will need to specify the full DN and
@@ -142,4 +140,4 @@ autoregister = true
# to the netid in order to make an email address. E.g. a netid of 'user' and
# netid_email_domain as '@example.com' would set the email of the user
# to be 'user@example.com
-#netid_email_domain = @example.com
+#netid_email_domain = @example.com
View
3  dspace/config/modules/authentication.cfg
@@ -17,7 +17,6 @@
# Configuration file: authentication-shibboleth.cfg
# * LDAP Authentication
# LDAP Plugin class: org.dspace.authenticate.LDAPAuthentication
-# Hierarchical LDAP Plugin class: org.dspace.authenticate.LDAPHierarchicalAuthentication
# Configuration file: authentication-ldap.cfg
# * IP Address Authentication
# Plugin class: org.dspace.authenticate.IPAuthentication
@@ -36,4 +35,4 @@
# org.dspace.authenticate.PasswordAuthentication
plugin.sequence.org.dspace.authenticate.AuthenticationMethod = \
- org.dspace.authenticate.PasswordAuthentication
+ org.dspace.authenticate.PasswordAuthentication
Please sign in to comment.
Something went wrong with that request. Please try again.