WindowsSSONAuthenticator.java
/**
* Originally contributed by eMation (www.emation.pt)
*/
package org.itracker.services.authentication.adsson;
import org.apache.log4j.Logger;
import org.itracker.model.User;
import org.itracker.UserException;
import org.itracker.model.UserPreferences;
import org.itracker.services.UserService;
import org.itracker.services.authentication.DefaultAuthenticator;
import org.itracker.services.exceptions.AuthenticatorException;
import org.itracker.model.util.UserUtilities;
import javax.servlet.http.HttpServletRequest;
import java.rmi.RemoteException;
import java.util.Date;
/**
* Single Sign On class with Windows
* <p/>
* Gets an authentication from jcifs web filter, gets user information from
* active directory, creates or updates the user with that information if needed
*
* @author Ricardo Trindade (ricardo.trindade@emation.pt)
*/
public abstract class WindowsSSONAuthenticator extends DefaultAuthenticator {
private static final Logger logger = Logger.getLogger(WindowsSSONAuthenticator.class);
private static String TEMPLATE_USER = "TemplateUser";
/**
* @see org.itracker.ejb.authentication.AbstractPluggableAuthenticator#checkLogin(java.lang.String,
* java.lang.Object, int, int)
*/
public User checkLogin(String login, Object authentication, int authType, int reqSource)
throws AuthenticatorException {
User userModel;
try {
// this authenticator only handles authType=AUTH_TYPE_REQUEST
// (HttpServletRequest)
if (authType != AUTH_TYPE_REQUEST || !(authentication instanceof HttpServletRequest)) {
logger.error("Only http request authentication supported by this single sign on class. Received "
+ authType);
throw new AuthenticatorException(
"Only http request authentication supported by this single sign on class",
AuthenticatorException.INVALID_AUTHENTICATION_TYPE);
}
UserService userService = getUserService();
// validate we're really using jcifs, and we
// have a valid authentication object
// TODO: get user from jcifs
String theLogin = ((HttpServletRequest) authentication).getRemoteUser();
if (theLogin == null) {
throw new AuthenticatorException("User obtained from jcifs is null. Check that jcifs is active",
AuthenticatorException.CUSTOM_ERROR);
}
// sometimes jcifs sends the username in the form of DOMAIN\USER
if (theLogin.indexOf("\\") > 0) {
theLogin = theLogin.substring(theLogin.indexOf("\\") + 1);
}
if (!theLogin.equals(login)) {
// should an exception be thrown here?
AuthenticatorException ex = new AuthenticatorException("User obtained from authenticator does not match, got " + theLogin + ", expected " + login + ".",
AuthenticatorException.CUSTOM_ERROR);
logger.warn("checkLogin: checking login for " + login + " but got " + theLogin + " in authentication " + authentication, ex);
throw ex;
}
userModel = updateOrCreateUser(theLogin, userService);
return userModel;
} catch (RemoteException ex) {
logger.error("pt_PT", ex);
throw new AuthenticatorException(ex.getMessage(), AuthenticatorException.SYSTEM_ERROR, ex);
} catch (UserException ex) {
logger.error("pt_PT", ex);
throw new AuthenticatorException(ex.getMessage(), AuthenticatorException.SYSTEM_ERROR, ex);
} catch (AuthenticatorException ex) {
logger.error("pt_PT", ex);
throw new AuthenticatorException(ex.getMessage(), AuthenticatorException.SYSTEM_ERROR, ex);
}
}
/**
* Checks if the user needs creating or updating, and if so, do it
*/
private User updateOrCreateUser(String login, UserService userService) throws RemoteException, UserException,
AuthenticatorException {
User userModel;
// check if the user already exists in ITracker
// if he already exists, and needs updating, update him
// if not, create him
userModel = userService.getUserByLogin(login);
if (null == userModel) {
userModel = createUser(login, userService);
} else {
// user exists, update if needed
// get user info from authentication source
if (needsUpdate(userModel, getExternalUserInfo(login))) {
// update user here...
// userService.updateUser();
// get updated version
userModel = userService.getUserByLogin(login);
userModel = updateUser(userModel, getExternalUserInfo(login));
userService.updateUser(userModel);
}
}
return userModel;
}
/**
* Updates parts of profile that are obtained from external source
*/
private User updateUser(User oldUserModel, User newUserModel) {
oldUserModel.setEmail(newUserModel.getEmail());
oldUserModel.setFirstName(newUserModel.getFirstName());
oldUserModel.setLastName(newUserModel.getLastName());
oldUserModel.setLastModifiedDate(new Date());
oldUserModel.setSuperUser(newUserModel.isSuperUser());
return (oldUserModel);
}
/**
* Create a user in the ITracker database
*/
private User createUser(String login, UserService userService) throws RemoteException, UserException,
AuthenticatorException {
// doesn't exist, create
User userModel = getExternalUserInfo(login);
userModel.setRegistrationType(UserUtilities.REGISTRATION_TYPE_ADMIN);
userModel.setStatus(UserUtilities.STATUS_ACTIVE);
userModel = userService.createUser(userModel);
// if this user is a super user, there is no need to set default
// permissions
// if not, set default permissions
if (!userModel.isSuperUser()) {
setDefaultPermissions(userModel, userService);
}
return userModel;
}
/**
* Set the default user permissions
* <p/>
* Default user permissions are the same as those of a user called
* "TemplateUser"
*/
private void setDefaultPermissions(User userModel, UserService userService) throws RemoteException,
AuthenticatorException, UserException {
User templateUser = userService.getUserByLogin(TEMPLATE_USER);
if (templateUser == null) {
String errorMessage = "TemplateUser not found. Create a user called template user, new permissions are copied from him to new users";
logger.error(errorMessage);
throw new AuthenticatorException(errorMessage, AuthenticatorException.CUSTOM_ERROR);
}
// set permissions
userService.setUserPermissions(userModel.getId(), userService.getPermissionsByUserId(templateUser.getId()));
// set preferences
UserPreferences preferences = templateUser.getPreferences();
preferences.setUser(userModel);
userService.updateUserPreferences(preferences);
}
/**
* Checks if a given internal user needs updating, by comparing him with the
* external user data source
*
* @param localUser The local User
* @param remoteUser The remote User
* @return true if the user needs updating, false otherwise
*/
private boolean needsUpdate(User localUser, User remoteUser) {
if (!(localUser.getEmail().equals(remoteUser.getEmail())))
return true;
if (!(localUser.getFirstName().equals(remoteUser.getFirstName())))
return true;
if (!(localUser.getLastName().equals(remoteUser.getLastName())))
return true;
if (localUser.isSuperUser() != remoteUser.isSuperUser())
return true;
return (false);
}
protected abstract User getExternalUserInfo(String login) throws AuthenticatorException;
/*
* (non-Javadoc)
*
* @see org.itracker.ejb.authentication.AbstractPluggableAuthenticator#allowProfileUpdates(org.itracker.model.deprecatedmodels.User,
* java.lang.Object, int, int)
*/
public boolean allowProfileUpdates(User user, Object authentication, int authType, int reqSource)
throws AuthenticatorException {
return true;
}
/*
* (non-Javadoc)
*
* @see org.itracker.ejb.authentication.AbstractPluggableAuthenticator#allowPasswordUpdates(org.itracker.model.deprecatedmodels.User,
* java.lang.Object, int, int)
*/
public boolean allowPasswordUpdates(User user, Object authentication, int authType, int reqSource)
throws AuthenticatorException {
return false;
}
}