View Javadoc
1   /**
2    * Originally contributed by eMation (www.emation.pt)
3    */
4   package org.itracker.services.authentication.adsson;
5   
6   import org.apache.log4j.Logger;
7   import org.itracker.model.User;
8   import org.itracker.UserException;
9   import org.itracker.model.UserPreferences;
10  import org.itracker.services.UserService;
11  import org.itracker.services.authentication.DefaultAuthenticator;
12  import org.itracker.services.exceptions.AuthenticatorException;
13  import org.itracker.model.util.UserUtilities;
14  
15  import javax.servlet.http.HttpServletRequest;
16  import java.rmi.RemoteException;
17  import java.util.Date;
18  
19  
20  /**
21   * Single Sign On class with Windows
22   * <p/>
23   * Gets an authentication from jcifs web filter, gets user information from
24   * active directory, creates or updates the user with that information if needed
25   *
26   * @author Ricardo Trindade (ricardo.trindade@emation.pt)
27   */
28  public abstract class WindowsSSONAuthenticator extends DefaultAuthenticator {
29  
30      private static final Logger logger = Logger.getLogger(WindowsSSONAuthenticator.class);
31  
32      private static String TEMPLATE_USER = "TemplateUser";
33  
34      /**
35       * @see org.itracker.ejb.authentication.AbstractPluggableAuthenticator#checkLogin(java.lang.String,
36       *      java.lang.Object, int, int)
37       */
38      public User checkLogin(String login, Object authentication, int authType, int reqSource)
39              throws AuthenticatorException {
40          User userModel;
41          try {
42              // this authenticator only handles authType=AUTH_TYPE_REQUEST
43              // (HttpServletRequest)
44              if (authType != AUTH_TYPE_REQUEST || !(authentication instanceof HttpServletRequest)) {
45                  logger.error("Only http request authentication supported by this single sign on class. Received "
46                          + authType);
47                  throw new AuthenticatorException(
48                          "Only http request authentication supported by this single sign on class",
49                          AuthenticatorException.INVALID_AUTHENTICATION_TYPE);
50              }
51              UserService userService = getUserService();
52              // validate we're really using jcifs, and we
53              // have a valid authentication object
54              // TODO: get user from jcifs
55              String theLogin = ((HttpServletRequest) authentication).getRemoteUser();
56  
57              if (theLogin == null) {
58                  throw new AuthenticatorException("User obtained from jcifs is null. Check that jcifs is active",
59                          AuthenticatorException.CUSTOM_ERROR);
60              }
61  
62              // sometimes jcifs sends the username in the form of DOMAIN\USER
63              if (theLogin.indexOf("\\") > 0) {
64                  theLogin = theLogin.substring(theLogin.indexOf("\\") + 1);
65              }
66              if (!theLogin.equals(login)) {
67                  // should an exception be thrown here?
68                  AuthenticatorExceptionenticatorException.html#AuthenticatorException">AuthenticatorException ex = new AuthenticatorException("User obtained from authenticator does not match, got " + theLogin + ", expected " + login + ".",
69                          AuthenticatorException.CUSTOM_ERROR);
70                  logger.warn("checkLogin: checking login for " + login + " but got " + theLogin + " in authentication " + authentication, ex);
71                  throw ex;
72              }
73  
74              userModel = updateOrCreateUser(theLogin, userService);
75              return userModel;
76          } catch (RemoteException ex) {
77              logger.error("pt_PT", ex);
78              throw new AuthenticatorException(ex.getMessage(), AuthenticatorException.SYSTEM_ERROR, ex);
79          } catch (UserException ex) {
80              logger.error("pt_PT", ex);
81              throw new AuthenticatorException(ex.getMessage(), AuthenticatorException.SYSTEM_ERROR, ex);
82          } catch (AuthenticatorException ex) {
83              logger.error("pt_PT", ex);
84              throw new AuthenticatorException(ex.getMessage(), AuthenticatorException.SYSTEM_ERROR, ex);
85          }
86      }
87  
88      /**
89       * Checks if the user needs creating or updating, and if so, do it
90       */
91      private User updateOrCreateUser(String login, UserService userService) throws RemoteException, UserException,
92              AuthenticatorException {
93          User userModel;
94          // check if the user already exists in ITracker
95          // if he already exists, and needs updating, update him
96          // if not, create him
97          userModel = userService.getUserByLogin(login);
98          if (null == userModel) {
99              userModel = createUser(login, userService);
100         } else {
101             // user exists, update if needed
102             // get user info from authentication source
103             if (needsUpdate(userModel, getExternalUserInfo(login))) {
104                 // update user here...
105                 // userService.updateUser();
106                 // get updated version
107                 userModel = userService.getUserByLogin(login);
108                 userModel = updateUser(userModel, getExternalUserInfo(login));
109                 userService.updateUser(userModel);
110             }
111         }
112         return userModel;
113     }
114 
115     /**
116      * Updates parts of profile that are obtained from external source
117      */
118     private User updateUser(User oldUserModel, User newUserModel) {
119         oldUserModel.setEmail(newUserModel.getEmail());
120         oldUserModel.setFirstName(newUserModel.getFirstName());
121         oldUserModel.setLastName(newUserModel.getLastName());
122         oldUserModel.setLastModifiedDate(new Date());
123         oldUserModel.setSuperUser(newUserModel.isSuperUser());
124         return (oldUserModel);
125     }
126 
127     /**
128      * Create a user in the ITracker database
129      */
130     private User createUser(String login, UserService userService) throws RemoteException, UserException,
131             AuthenticatorException {
132 
133         // doesn't exist, create
134         User userModel = getExternalUserInfo(login);
135         userModel.setRegistrationType(UserUtilities.REGISTRATION_TYPE_ADMIN);
136         userModel.setStatus(UserUtilities.STATUS_ACTIVE);
137         userModel = userService.createUser(userModel);
138         // if this user is a super user, there is no need to set default
139         // permissions
140         // if not, set default permissions
141         if (!userModel.isSuperUser()) {
142             setDefaultPermissions(userModel, userService);
143         }
144 
145         return userModel;
146     }
147 
148     /**
149      * Set the default user permissions
150      * <p/>
151      * Default user permissions are the same as those of a user called
152      * "TemplateUser"
153      */
154     private void setDefaultPermissions(User userModel, UserService userService) throws RemoteException,
155             AuthenticatorException, UserException {
156 
157         User templateUser = userService.getUserByLogin(TEMPLATE_USER);
158         if (templateUser == null) {
159             String errorMessage = "TemplateUser not found. Create a user called template user, new permissions are copied from him to new users";
160             logger.error(errorMessage);
161             throw new AuthenticatorException(errorMessage, AuthenticatorException.CUSTOM_ERROR);
162         }
163         // set permissions
164         userService.setUserPermissions(userModel.getId(), userService.getPermissionsByUserId(templateUser.getId()));
165         // set preferences
166         UserPreferences preferences = templateUser.getPreferences();
167         preferences.setUser(userModel);
168         userService.updateUserPreferences(preferences);
169     }
170 
171     /**
172      * Checks if a given internal user needs updating, by comparing him with the
173      * external user data source
174      *
175      * @param localUser  The local User
176      * @param remoteUser The remote User
177      * @return true if the user needs updating, false otherwise
178      */
179     private boolean needsUpdate(User localUser, User remoteUser) {
180         if (!(localUser.getEmail().equals(remoteUser.getEmail())))
181             return true;
182         if (!(localUser.getFirstName().equals(remoteUser.getFirstName())))
183             return true;
184         if (!(localUser.getLastName().equals(remoteUser.getLastName())))
185             return true;
186         if (localUser.isSuperUser() != remoteUser.isSuperUser())
187             return true;
188         return (false);
189     }
190 
191     protected abstract User getExternalUserInfo(String login) throws AuthenticatorException;
192 
193     /*
194      * (non-Javadoc)
195      * 
196      * @see org.itracker.ejb.authentication.AbstractPluggableAuthenticator#allowProfileUpdates(org.itracker.model.deprecatedmodels.User,
197      *      java.lang.Object, int, int)
198      */
199     public boolean allowProfileUpdates(User user, Object authentication, int authType, int reqSource)
200             throws AuthenticatorException {
201         return true;
202     }
203 
204     /*
205      * (non-Javadoc)
206      * 
207      * @see org.itracker.ejb.authentication.AbstractPluggableAuthenticator#allowPasswordUpdates(org.itracker.model.deprecatedmodels.User,
208      *      java.lang.Object, int, int)
209      */
210     public boolean allowPasswordUpdates(User user, Object authentication, int authType, int reqSource)
211             throws AuthenticatorException {
212         return false;
213     }
214 
215 }