View Javadoc

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