/*==========================================================================*\
| $Id: LdapAuthenticator.java,v 1.2 2012/03/28 13:48:08 stedwar2 Exp $
|*-------------------------------------------------------------------------*|
| Copyright (C) 2006-2012 Virginia Tech
|
| This file is part of Web-CAT.
|
| Web-CAT is free software; you can redistribute it and/or modify
| it under the terms of the GNU Affero General Public License as published
| by the Free Software Foundation; either version 3 of the License, or
| (at your option) any later version.
|
| Web-CAT is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
|
| You should have received a copy of the GNU Affero General Public License
| along with Web-CAT; if not, see <http://www.gnu.org/licenses/>.
\*==========================================================================*/
package org.webcat.core;
import com.webobjects.eoaccess.*;
import edu.vt.middleware.ldap.*;
import org.webcat.core.AuthenticationDomain;
import org.webcat.core.LdapAuthenticator;
import org.webcat.core.User;
import org.webcat.core.UserAuthenticator;
import org.webcat.core.WCProperties;
import org.apache.log4j.Logger;
// --------------------------------------------------------------------------
/**
* A concrete implementation of <code>UserAuthenticator</code> that
* tests user ids/passwords using LDAP.
*
* @author Stephen Edwards
* @author Last changed by $Author: stedwar2 $
* @version $Revision: 1.2 $, $Date: 2012/03/28 13:48:08 $
*/
public class LdapAuthenticator
implements UserAuthenticator
{
//~ Constructors ..........................................................
// ----------------------------------------------------------
/**
* Create a new object.
*/
public LdapAuthenticator()
{
// Initialization happens in configure()
}
//~ Methods ...............................................................
// ----------------------------------------------------------
/**
* Initialize and configure the authenticator, reading subclass-specific
* settings from properties. The authenticator should read any
* instance-specific settings from properties named
* "baseName.<property>". This operation should only be called once,
* before any authenticate requests.
*
* @param baseName The base property name for this authenticator object
* @param properties The property collection from which the object
* should read its configuration settings
* @return true If configuration was successful and authenticator is
* ready for service
*/
public boolean configure( String baseName,
WCProperties properties )
{
boolean result = true;
String host = properties.getProperty( baseName + ".ldap.hostUrl" );
if ( host == null || host.equals("") )
{
log.error( "a required property is not set: "
+ baseName + ".ldap.hostUrl" );
result = false;
}
String base = properties.getProperty( baseName + ".ldap.context" );
if ( base == null || base.equals("") )
{
log.error( "a required property is not set: "
+ baseName + ".ldap.context" );
result = false;
}
if (!result) return result;
String userField =
properties.getProperty( baseName + ".ldap.userField" );
if ( userField == null || userField.equals("") )
{
userField = "cn";
}
log.debug(baseName + ": host = " + host + ", context = " + base
+ ", user field = " + userField);
AuthenticatorConfig config = new AuthenticatorConfig(host, base);
String bindDN = properties.getProperty( baseName + ".ldap.bindDN" );
String bindPassword =
properties.getProperty( baseName + ".ldap.bindPassword" );
if ("".equals(bindDN)) { bindDN = null; }
if ("".equals(bindPassword)) { bindPassword = null; }
if (bindDN == null && bindPassword != null)
{
log.error( baseName + ".ldap.bindPassword was set without"
+ "setting " + baseName + ".ldap.bindDN" );
result = false;
}
else if (bindPassword == null && bindDN != null)
{
log.error( baseName + ".ldap.bindDN was set without"
+ "setting " + baseName + ".ldap.bindPassword" );
result = false;
}
if (bindDN != null)
{
config.setServiceUser(bindDN);
log.debug(baseName + ": bindDN = " + bindDN);
}
if (bindPassword != null)
{
config.setServiceCredential(bindPassword);
log.debug(baseName + ": bindPassword = " + bindPassword);
}
config.setSubtreeSearch(
properties.booleanForKey( baseName + ".ldap.searchSubtrees" ) );
String authFilter =
properties.getProperty( baseName + ".ldap.authFilter" );
if (authFilter != null && !authFilter.equals(""))
{
config.setAuthorizationFilter(authFilter);
}
config.setUserField(new String[] {userField});
authenticator = new Authenticator(config);
if (properties.booleanForKey(baseName + ".useTLS"))
{
try
{
log.debug(baseName + ": turning TLS on");
authenticator.useTls(true);
}
catch (Exception e)
{
log.error("Cannot use TLS:", e);
}
}
return result;
}
// ----------------------------------------------------------
/**
* Validate the user `username' with the password `password'.
* Should not be called until the authenticator has been configured.
*
* @param username The user id to validate
* @param password The password to check
* @param domain The authentication domain associated with this check
* @param ec The editing context to use
* @return The current user object, or null if invalid login
*/
public User authenticate( String username,
String password,
AuthenticationDomain domain,
com.webobjects.eocontrol.EOEditingContext ec )
{
User user = null;
if ( authenticate( username, password ) )
{
log.debug( "user " + username + " validated" );
try
{
user = User.uniqueObjectMatchingQualifier(
ec,
User.userName.is(username).and(
User.authenticationDomain.is(domain)));
if (user == null)
{
user = User.createUser(
username,
null, // DO NOT MIRROR PASSWORD IN DATABASE
// for security reasons
domain,
User.STUDENT_PRIVILEGES,
ec
);
log.info( "new user '"
+ username
+ "' ("
+ domain.displayableName()
+ ") created"
);
}
else if ( user.authenticationDomain() != domain )
{
if ( user.authenticationDomain() == null )
{
user.setAuthenticationDomainRelationship( domain );
}
else
{
log.warn(
"user " + username
+ " successfully validated in '"
+ domain.displayableName()
+ "' but bound to '"
+ user.authenticationDomain().displayableName()
+ "'"
);
user = null;
}
}
}
catch ( EOUtilities.MoreThanOneException e )
{
log.error( "user '"
+ username
+ "' ("
+ domain.displayableName()
+ "):",
e
);
}
}
else
{
log.info( "user " + username + "(" + domain.displayableName()
+ "): login validation failed" );
}
return user;
}
private boolean authenticate( String username, String password )
{
boolean result = false;
try
{
result = authenticator.authenticate( username, password );
}
catch ( Exception e )
{
log.error( "authentication failure: ", e );
}
log.debug( "result = " + result );
return result;
}
// ----------------------------------------------------------
/**
* Check whether users validated with this authenticator can
* change their password. For authentication mechanisms using
* external databases or servers where no changes are allowed, the
* authenticator should return false.
*
* @return True if users associated with this authenticator can
* change their password
*/
public boolean canChangePassword()
{
return false;
}
// ----------------------------------------------------------
/**
* Change the user's password. For authentication mechanisms using
* external databases or servers where no changes are allowed, an
* authenticator may simply return false for all requests.
*
* @param user The user
* @param newPassword The password to change to
* @return True if the password change was successful
*/
public boolean changePassword( User user,
String newPassword )
{
return false;
}
// ----------------------------------------------------------
/**
* Change the user's password to a new random password, and e-mail's
* the user their new password. For authentication mechanisms using
* external databases or servers where no changes are allowed, an
* authenticator may simply return false for all requests.
*
* @param user The user
* @return True if the password change was successful
*/
public boolean newRandomPassword( User user )
{
return false;
}
//~ Instance/static variables .............................................
static Logger log = Logger.getLogger( LdapAuthenticator.class );
private Authenticator authenticator;
}