WindowsSSONAuthenticator.java

  1. /**
  2.  * Originally contributed by eMation (www.emation.pt)
  3.  */
  4. package org.itracker.services.authentication.adsson;

  5. import org.apache.log4j.Logger;
  6. import org.itracker.model.User;
  7. import org.itracker.UserException;
  8. import org.itracker.model.UserPreferences;
  9. import org.itracker.services.UserService;
  10. import org.itracker.services.authentication.DefaultAuthenticator;
  11. import org.itracker.services.exceptions.AuthenticatorException;
  12. import org.itracker.model.util.UserUtilities;

  13. import javax.servlet.http.HttpServletRequest;
  14. import java.rmi.RemoteException;
  15. import java.util.Date;


  16. /**
  17.  * Single Sign On class with Windows
  18.  * <p/>
  19.  * Gets an authentication from jcifs web filter, gets user information from
  20.  * active directory, creates or updates the user with that information if needed
  21.  *
  22.  * @author Ricardo Trindade (ricardo.trindade@emation.pt)
  23.  */
  24. public abstract class WindowsSSONAuthenticator extends DefaultAuthenticator {

  25.     private static final Logger logger = Logger.getLogger(WindowsSSONAuthenticator.class);

  26.     private static String TEMPLATE_USER = "TemplateUser";

  27.     /**
  28.      * @see org.itracker.ejb.authentication.AbstractPluggableAuthenticator#checkLogin(java.lang.String,
  29.      *      java.lang.Object, int, int)
  30.      */
  31.     public User checkLogin(String login, Object authentication, int authType, int reqSource)
  32.             throws AuthenticatorException {
  33.         User userModel;
  34.         try {
  35.             // this authenticator only handles authType=AUTH_TYPE_REQUEST
  36.             // (HttpServletRequest)
  37.             if (authType != AUTH_TYPE_REQUEST || !(authentication instanceof HttpServletRequest)) {
  38.                 logger.error("Only http request authentication supported by this single sign on class. Received "
  39.                         + authType);
  40.                 throw new AuthenticatorException(
  41.                         "Only http request authentication supported by this single sign on class",
  42.                         AuthenticatorException.INVALID_AUTHENTICATION_TYPE);
  43.             }
  44.             UserService userService = getUserService();
  45.             // validate we're really using jcifs, and we
  46.             // have a valid authentication object
  47.             // TODO: get user from jcifs
  48.             String theLogin = ((HttpServletRequest) authentication).getRemoteUser();

  49.             if (theLogin == null) {
  50.                 throw new AuthenticatorException("User obtained from jcifs is null. Check that jcifs is active",
  51.                         AuthenticatorException.CUSTOM_ERROR);
  52.             }

  53.             // sometimes jcifs sends the username in the form of DOMAIN\USER
  54.             if (theLogin.indexOf("\\") > 0) {
  55.                 theLogin = theLogin.substring(theLogin.indexOf("\\") + 1);
  56.             }
  57.             if (!theLogin.equals(login)) {
  58.                 // should an exception be thrown here?
  59.                 AuthenticatorException ex = new AuthenticatorException("User obtained from authenticator does not match, got " + theLogin + ", expected " + login + ".",
  60.                         AuthenticatorException.CUSTOM_ERROR);
  61.                 logger.warn("checkLogin: checking login for " + login + " but got " + theLogin + " in authentication " + authentication, ex);
  62.                 throw ex;
  63.             }

  64.             userModel = updateOrCreateUser(theLogin, userService);
  65.             return userModel;
  66.         } catch (RemoteException ex) {
  67.             logger.error("pt_PT", ex);
  68.             throw new AuthenticatorException(ex.getMessage(), AuthenticatorException.SYSTEM_ERROR, ex);
  69.         } catch (UserException ex) {
  70.             logger.error("pt_PT", ex);
  71.             throw new AuthenticatorException(ex.getMessage(), AuthenticatorException.SYSTEM_ERROR, ex);
  72.         } catch (AuthenticatorException ex) {
  73.             logger.error("pt_PT", ex);
  74.             throw new AuthenticatorException(ex.getMessage(), AuthenticatorException.SYSTEM_ERROR, ex);
  75.         }
  76.     }

  77.     /**
  78.      * Checks if the user needs creating or updating, and if so, do it
  79.      */
  80.     private User updateOrCreateUser(String login, UserService userService) throws RemoteException, UserException,
  81.             AuthenticatorException {
  82.         User userModel;
  83.         // check if the user already exists in ITracker
  84.         // if he already exists, and needs updating, update him
  85.         // if not, create him
  86.         userModel = userService.getUserByLogin(login);
  87.         if (null == userModel) {
  88.             userModel = createUser(login, userService);
  89.         } else {
  90.             // user exists, update if needed
  91.             // get user info from authentication source
  92.             if (needsUpdate(userModel, getExternalUserInfo(login))) {
  93.                 // update user here...
  94.                 // userService.updateUser();
  95.                 // get updated version
  96.                 userModel = userService.getUserByLogin(login);
  97.                 userModel = updateUser(userModel, getExternalUserInfo(login));
  98.                 userService.updateUser(userModel);
  99.             }
  100.         }
  101.         return userModel;
  102.     }

  103.     /**
  104.      * Updates parts of profile that are obtained from external source
  105.      */
  106.     private User updateUser(User oldUserModel, User newUserModel) {
  107.         oldUserModel.setEmail(newUserModel.getEmail());
  108.         oldUserModel.setFirstName(newUserModel.getFirstName());
  109.         oldUserModel.setLastName(newUserModel.getLastName());
  110.         oldUserModel.setLastModifiedDate(new Date());
  111.         oldUserModel.setSuperUser(newUserModel.isSuperUser());
  112.         return (oldUserModel);
  113.     }

  114.     /**
  115.      * Create a user in the ITracker database
  116.      */
  117.     private User createUser(String login, UserService userService) throws RemoteException, UserException,
  118.             AuthenticatorException {

  119.         // doesn't exist, create
  120.         User userModel = getExternalUserInfo(login);
  121.         userModel.setRegistrationType(UserUtilities.REGISTRATION_TYPE_ADMIN);
  122.         userModel.setStatus(UserUtilities.STATUS_ACTIVE);
  123.         userModel = userService.createUser(userModel);
  124.         // if this user is a super user, there is no need to set default
  125.         // permissions
  126.         // if not, set default permissions
  127.         if (!userModel.isSuperUser()) {
  128.             setDefaultPermissions(userModel, userService);
  129.         }

  130.         return userModel;
  131.     }

  132.     /**
  133.      * Set the default user permissions
  134.      * <p/>
  135.      * Default user permissions are the same as those of a user called
  136.      * "TemplateUser"
  137.      */
  138.     private void setDefaultPermissions(User userModel, UserService userService) throws RemoteException,
  139.             AuthenticatorException, UserException {

  140.         User templateUser = userService.getUserByLogin(TEMPLATE_USER);
  141.         if (templateUser == null) {
  142.             String errorMessage = "TemplateUser not found. Create a user called template user, new permissions are copied from him to new users";
  143.             logger.error(errorMessage);
  144.             throw new AuthenticatorException(errorMessage, AuthenticatorException.CUSTOM_ERROR);
  145.         }
  146.         // set permissions
  147.         userService.setUserPermissions(userModel.getId(), userService.getPermissionsByUserId(templateUser.getId()));
  148.         // set preferences
  149.         UserPreferences preferences = templateUser.getPreferences();
  150.         preferences.setUser(userModel);
  151.         userService.updateUserPreferences(preferences);
  152.     }

  153.     /**
  154.      * Checks if a given internal user needs updating, by comparing him with the
  155.      * external user data source
  156.      *
  157.      * @param localUser  The local User
  158.      * @param remoteUser The remote User
  159.      * @return true if the user needs updating, false otherwise
  160.      */
  161.     private boolean needsUpdate(User localUser, User remoteUser) {
  162.         if (!(localUser.getEmail().equals(remoteUser.getEmail())))
  163.             return true;
  164.         if (!(localUser.getFirstName().equals(remoteUser.getFirstName())))
  165.             return true;
  166.         if (!(localUser.getLastName().equals(remoteUser.getLastName())))
  167.             return true;
  168.         if (localUser.isSuperUser() != remoteUser.isSuperUser())
  169.             return true;
  170.         return (false);
  171.     }

  172.     protected abstract User getExternalUserInfo(String login) throws AuthenticatorException;

  173.     /*
  174.      * (non-Javadoc)
  175.      *
  176.      * @see org.itracker.ejb.authentication.AbstractPluggableAuthenticator#allowProfileUpdates(org.itracker.model.deprecatedmodels.User,
  177.      *      java.lang.Object, int, int)
  178.      */
  179.     public boolean allowProfileUpdates(User user, Object authentication, int authType, int reqSource)
  180.             throws AuthenticatorException {
  181.         return true;
  182.     }

  183.     /*
  184.      * (non-Javadoc)
  185.      *
  186.      * @see org.itracker.ejb.authentication.AbstractPluggableAuthenticator#allowPasswordUpdates(org.itracker.model.deprecatedmodels.User,
  187.      *      java.lang.Object, int, int)
  188.      */
  189.     public boolean allowPasswordUpdates(User user, Object authentication, int authType, int reqSource)
  190.             throws AuthenticatorException {
  191.         return false;
  192.     }

  193. }