/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/providers/trunk/openldap/src/java/es/udl/asic/user/OpenLdapDirectoryProvider.java $ * $Id: OpenLdapDirectoryProvider.java 105079 2012-02-24 23:08:11Z ottenhoff@longsight.com $ *********************************************************************************** * * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008 The Sakai Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **********************************************************************************/ package es.udl.asic.user; import java.util.Collection; import java.util.Hashtable; import java.util.Iterator; import javax.naming.AuthenticationException; import javax.naming.Context; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.user.api.UserDirectoryProvider; import org.sakaiproject.user.api.UserEdit; /** * <p> * An implementation of a Sakai UserDirectoryProvider that authenticates/retrieves users from an OpenLDAP directory. * </p> * * @author ASIC - Udl */ public class OpenLdapDirectoryProvider implements UserDirectoryProvider { /** Our log (commons). */ private static Log M_log = LogFactory.getLog(OpenLdapDirectoryProvider.class); private String ldapHost = ""; // address of ldap server private int ldapPort = 389; // port to connect to ldap server on private String basePath = ""; private Hashtable env = new Hashtable(); public void init() { try { M_log.info("init()"); } catch (Throwable t) { M_log.warn("init(): ", t); } env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, getLdapHost() + ":" + getLdapPort()); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_CREDENTIALS, "secret"); } public void destroy() { M_log.info("destroy()"); } public boolean authenticateUser(String userLogin, UserEdit edit, String password) { Hashtable env = new Hashtable(); InitialDirContext ctx; String INIT_CTX = "com.sun.jndi.ldap.LdapCtxFactory"; String MY_HOST = getLdapHost() + ":" + getLdapPort(); String cn; boolean returnVal = false; if (!password.equals("")) { env.put(Context.INITIAL_CONTEXT_FACTORY, INIT_CTX); env.put(Context.PROVIDER_URL, MY_HOST); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_CREDENTIALS, "secret"); String[] returnAttribute = { "ou" }; SearchControls srchControls = new SearchControls(); srchControls.setReturningAttributes(returnAttribute); srchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); String searchFilter = "(&(objectclass=person)(uid=" + escapeSearchFilterTerm(userLogin) + "))"; try { ctx = new InitialDirContext(env); NamingEnumeration answer = ctx.search(getBasePath(), searchFilter, srchControls); String trobat = "false"; while (answer.hasMore() && trobat.equals("false")) { SearchResult sr = (SearchResult) answer.next(); String dn = sr.getName().toString() + "," + getBasePath(); // Second binding Hashtable authEnv = new Hashtable(); try { authEnv.put(Context.INITIAL_CONTEXT_FACTORY, INIT_CTX); authEnv.put(Context.PROVIDER_URL, MY_HOST); authEnv.put(Context.SECURITY_AUTHENTICATION, "simple"); authEnv.put(Context.SECURITY_PRINCIPAL, sr.getName() + "," + getBasePath()); authEnv.put(Context.SECURITY_CREDENTIALS, password); try { DirContext authContext = new InitialDirContext(authEnv); returnVal = true; trobat = "true"; authContext.close(); } catch (AuthenticationException ae) { M_log.info("Access forbidden"); } } catch (NamingException namEx) { M_log.info("User doesn't exist"); returnVal = false; namEx.printStackTrace(); } } if (trobat.equals("false")) returnVal = false; } catch (NamingException namEx) { namEx.printStackTrace(); returnVal = false; } } return returnVal; } public boolean findUserByEmail(UserEdit edit, String email) { env.put(Context.SECURITY_PRINCIPAL, ""); env.put(Context.SECURITY_CREDENTIALS, ""); String filter = "(&(objectclass=person)(mail=" + escapeSearchFilterTerm(email) + "))"; return getUserInf(edit, filter); } public boolean getUser(UserEdit edit) { if (!userExists(edit.getEid())) return false; env.put(Context.SECURITY_PRINCIPAL, ""); env.put(Context.SECURITY_CREDENTIALS, ""); String filter = "(&(objectclass=person)(uid=" + escapeSearchFilterTerm(edit.getEid()) + "))"; return getUserInf(edit, filter); } /** * Access a collection of UserEdit objects; if the user is found, update the information, otherwise remove the UserEdit object from the collection. * * @param users * The UserEdit objects (with id set) to fill in or remove. */ public void getUsers(Collection users) { for (Iterator i = users.iterator(); i.hasNext();) { UserEdit user = (UserEdit) i.next(); if (!getUser(user)) { i.remove(); } } } protected boolean userExists(String id) { env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_CREDENTIALS, "secret"); try { DirContext ctx = new InitialDirContext(env); /* * Setup subtree scope to tell LDAP to recursively descend directory structure during searches. */ SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); /* * Setup the directory entry attributes we want to search for. In this case it is the user's ID. */ String filter = "(&(objectclass=person)(uid=" + escapeSearchFilterTerm(id) + "))"; /* Execute the search, starting at the directory level of Users */ NamingEnumeration hits = ctx.search(getBasePath(), filter, searchControls); /* All we need to know is if there were any hits at all. */ if (hits.hasMore()) { hits.close(); ctx.close(); return true; } else { hits.close(); ctx.close(); return false; } } catch (Exception e) { e.printStackTrace(); return false; } } private boolean getUserInf(UserEdit edit, String filter) { String id = null; String firstName = null; String lastName = null; String employeenumber = null; String email = null; try { DirContext ctx = new InitialDirContext(env); // Setup subtree scope to tell LDAP to recursively descend directory structure // during searches. SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); // We want the user's id, first name and last name ... searchControls.setReturningAttributes(new String[] { "uid", "givenName", "sn" }); // Execute the search, starting at the directory level of Users NamingEnumeration results = ctx.search(getBasePath(), filter, searchControls); while (results.hasMore()) { SearchResult result = (SearchResult) results.next(); String dn = result.getName().toString() + "," + getBasePath(); Attributes attrs = ctx.getAttributes(dn); id = attrs.get("uid").get().toString(); String cn = attrs.get("cn").get().toString(); firstName = cn.substring(0, cn.indexOf(" ")); lastName = cn.substring(cn.indexOf(" ")); email = attrs.get("mail").get().toString(); } results.close(); ctx.close(); } catch (Exception ex) { ex.printStackTrace(); return false; } edit.setId(id); edit.setFirstName(firstName); edit.setLastName(lastName); edit.setEmail(email); return true; } /** * @return Returns the ldapHost. */ public String getLdapHost() { return ldapHost; } /** * @param ldapHost * The ldapHost to set. */ public void setLdapHost(String ldapHost) { this.ldapHost = ldapHost; } /** * @return Returns the ldapPort. */ public int getLdapPort() { return ldapPort; } /** * @param ldapPort * The ldapPort to set. */ public void setLdapPort(int ldapPort) { this.ldapPort = ldapPort; } /** * @return Returns the basePath. */ public String getBasePath() { return basePath; } /** * @param basePath * The basePath to set. */ public void setBasePath(String basePath) { this.basePath = basePath; } // helper class for storing user data in the hashtable cache /** * {@inheritDoc} */ public boolean authenticateWithProviderFirst(String id) { return false; } /** * {@inheritDoc} */ public boolean createUserRecord(String id) { return false; } /** * Borrowed from the jldap provider */ public String escapeSearchFilterTerm(String term) { if (term == null) return null; //From RFC 2254 String escapedStr = new String(term); escapedStr = escapedStr.replaceAll("\\\\","\\\\5c"); escapedStr = escapedStr.replaceAll("\\*","\\\\2a"); escapedStr = escapedStr.replaceAll("\\(","\\\\28"); escapedStr = escapedStr.replaceAll("\\)","\\\\29"); escapedStr = escapedStr.replaceAll("\\"+Character.toString('\u0000'), "\\\\00"); return escapedStr; } }