1 /*
2 * This software was designed and created by Jason Carroll.
3 * Copyright (c) 2002, 2003, 2004 Jason Carroll.
4 * The author can be reached at jcarroll@cowsultants.com
5 * ITracker website: http://www.cowsultants.com
6 * ITracker forums: http://www.cowsultants.com/phpBB/index.php
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it only under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19 package org.itracker.services.authentication;
20
21 import java.util.ArrayList;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25
26 import org.apache.log4j.Logger;
27 import org.itracker.model.Permission;
28 import org.itracker.model.User;
29 import org.itracker.services.exceptions.AuthenticatorException;
30 import org.itracker.services.exceptions.PasswordException;
31 import org.itracker.services.exceptions.UserException;
32 import org.itracker.services.util.UserUtilities;
33 import org.jfree.util.Log;
34 import org.springframework.dao.DataAccessException;
35
36
37 /**
38 * This class provides a default authentication scheme for ITracker. It uses passwords
39 * in the user table provided by ITracker to authenticate users. This authenticator
40 * allows any user to self register if self registration is available in the system.
41 */
42 public class DefaultAuthenticator extends AbstractPluggableAuthenticator {
43
44 private static final Logger logger = Logger.getLogger(DefaultAuthenticator.class);
45
46 /**
47 * Checks the login of a user against the user profile provided in ITracker. This is
48 * the default authentication scheme provided by ITracker.
49 *
50 * @param login the login the user/client provided
51 * @param authentication the user's authentication information, if known
52 * @param authType the type of authentication information being provided
53 * @param reqSource the source of the request (eg web, api)
54 * @return a User if the login is successful
55 * @throws AuthenticatorException an exception if the login is unsuccessful, or an error occurs
56 */
57 public User checkLogin(final String login, final Object authentication, final int authType, final int reqSource) throws AuthenticatorException {
58 if (logger.isDebugEnabled()) {
59 logger.debug("Checking login for " + login + " using DefaultAuthenticator");
60 }
61
62 if (login != null && authentication != null && !login.equals("")) {
63 User user;
64 try {
65 user = getUserService().getUserByLogin(login);
66 } catch (DataAccessException e) {
67 logger.error("checkLogin: failed to get user by login: " + login, e);
68 throw new AuthenticatorException(AuthenticatorException.UNKNOWN_USER, e.getMessage());
69 }
70
71 // if (user == null) {
72 // AuthenticatorException e = new AuthenticatorException(AuthenticatorException.UNKNOWN_USER);
73 // logger.error("checkLogin: failed to get user by login: " + login, e);
74 // throw e;
75 // }
76 if (user.getStatus() != UserUtilities.STATUS_ACTIVE) {
77 AuthenticatorException e = new AuthenticatorException(AuthenticatorException.INACTIVE_ACCOUNT);
78 logger.info("checkLogin: user is inactive, user: " + user, e);
79 throw e;
80 }
81
82 String userPassword;
83 try {
84 userPassword = getUserService().getUserPasswordByLogin(login);
85 } catch (DataAccessException e) {
86 AuthenticatorException ex = new AuthenticatorException(e.getMessage(), authType);
87 logger.info("checkLogin: user is inactive, user: " + user, ex);
88 throw e;
89 }
90 if (userPassword == null || userPassword.equals("")) {
91 AuthenticatorException e = new AuthenticatorException(AuthenticatorException.INVALID_PASSWORD);
92 logger.info("checkLogin: user has no password, user: " + user, e);
93 throw e;
94 }
95
96 try {
97 if (!userPassword.endsWith("=")) {
98 logger.info("checkLogin: User " + login + " has old style password. Converting to SHA1 hash.");
99 try {
100 user.setPassword(UserUtilities.encryptPassword(userPassword));
101 getUserService().updateUser(user);
102 } catch (UserException ue) {
103 logger.error("checkLogin: User password conversion failed for user " + user, ue);
104 throw new AuthenticatorException(AuthenticatorException.SYSTEM_ERROR);
105 }
106 }
107
108 if (authType == AUTH_TYPE_PASSWORD_PLAIN) {
109 if (!userPassword.equals(UserUtilities.encryptPassword((String) authentication))) {
110 throw new AuthenticatorException(AuthenticatorException.INVALID_PASSWORD);
111 }
112 } else if (authType == AUTH_TYPE_PASSWORD_ENC) {
113 if (!userPassword.equals(authentication)) {
114 throw new AuthenticatorException(AuthenticatorException.INVALID_PASSWORD);
115 }
116 } else {
117 logger.info("checkLogin: invalid authenticator type: " + authType);
118 throw new AuthenticatorException(AuthenticatorException.INVALID_AUTHENTICATION_TYPE);
119 }
120 } catch (ClassCastException cce) {
121 logger.error("checkLogin: Authenticator was of wrong type.", cce);
122 throw new AuthenticatorException(AuthenticatorException.SYSTEM_ERROR);
123 } catch (PasswordException pe) {
124 throw new AuthenticatorException(AuthenticatorException.SYSTEM_ERROR);
125 } catch (AuthenticatorException ae) {
126 if (logger.isDebugEnabled()) {
127 logger.debug("checkLogin: failed to authenticate " + login, ae);
128 }
129 throw ae;
130 }
131
132 return user;
133 }
134
135 Log.info("checkLogin: no login was supplied: " + login + ", type: " + authType + ", source: " + reqSource);
136 throw new AuthenticatorException(AuthenticatorException.INVALID_DATA);
137 }
138
139 /**
140 * The DefaultAuthenticator returns a list of user permissions from the database.
141 *
142 * @param user a User object that contains the user to retrieve permissions for
143 * @param reqSource the source of the request (eg web, api)
144 * @return an array of PermissionModels
145 * @throws AuthenticatorException an error occurs
146 */
147 public List<Permission> getUserPermissions(User user, int reqSource) throws AuthenticatorException {
148 if (user == null || user.getId() == null) {
149 throw new AuthenticatorException(AuthenticatorException.INVALID_DATA);
150 }
151
152 List<Permission> permissionList;
153 try {
154 permissionList = getUserService().getUserPermissionsLocal(user);
155 } catch (DataAccessException e) {
156 throw new AuthenticatorException(e.getMessage(), reqSource);
157 }
158
159 if (user.isSuperUser()) {
160 List<Permission> augmentedPermissions = new ArrayList<Permission>();
161
162 // Super user has access to all projects (represented by the "null" project).
163 Permission permission = new Permission(-1, user, null);
164 augmentedPermissions.add(permission);
165 augmentedPermissions.addAll(permissionList);
166 return augmentedPermissions;
167
168 } else {
169 return permissionList;
170 }
171
172 }
173
174 /**
175 * Returns the list of users for a given project. User permissions can be specified.
176 *
177 * @param projectId - The Project to search for users
178 * @param permissionTypes - User rights to filter
179 * @param requireAll - Require all permissions
180 * @param activeOnly - Filter users who are active (Possible user status: DELETED, ACTIVE, LOCKED)
181 * @param reqSource - not used. TODO: Tagged for removal
182 * @return List of users for the project with filters applied.
183 * @throws AuthenticatorException
184 */
185 public List<User> getUsersWithProjectPermission(Integer projectId,
186 int[] permissionTypes,
187 boolean requireAll,
188 boolean activeOnly,
189 int reqSource)
190 throws AuthenticatorException {
191
192 List<User> users;
193
194 try {
195 Map<Integer, User> userMap = new HashMap<Integer, User>();
196
197 if (requireAll) {
198
199 Integer[] types = new Integer[permissionTypes.length];
200 for (int i = 0; i < types.length; i++) {
201 types[i] = permissionTypes[i];
202 }
203
204 List<User> explicitUsers = getUserService().findUsersForProjectByPermissionTypeList(projectId, types);
205
206 for (User user : explicitUsers) {
207 userMap.put(user.getId(), user);
208 }
209 } else {
210
211 for (int i = 0; i < permissionTypes.length; i++) {
212 List<User> explicitUsers = getUserService().getUsersWithPermissionLocal(projectId, permissionTypes[i]);
213
214 for (User user : explicitUsers) {
215 userMap.put(user.getId(), user);
216 }
217
218 }
219
220 }
221
222 List<User> superUsers = getUserService().getSuperUsers();
223 for (User superUser : superUsers) {
224 userMap.put(superUser.getId(), superUser);
225 }
226
227 users = new ArrayList<User>();
228 for (User user : userMap.values()) {
229 if (activeOnly) {
230 if (user.getStatus() == UserUtilities.STATUS_ACTIVE) {
231 users.add(user);
232 }
233 } else {
234 users.add(user);
235 }
236 }
237
238 } catch (Exception e) {
239 logger.error("Error retreiving users with permissions.", e);
240 throw new AuthenticatorException();
241 }
242
243 return users;
244
245 }
246
247 /**
248 * The DefaultAuthenticator always allows self registered users.
249 *
250 * @param user a User object that contains the data the user submitted
251 * @param authentication the user's authentication information, if known
252 * @param authType the type of authentication information being provided
253 * @param reqSource the source of the request (eg web, api)
254 * @return true
255 */
256 public boolean allowRegistration(User user, Object authentication, int authType, int reqSource) throws AuthenticatorException {
257 return true;
258 }
259
260
261 /**
262 * The DefaultAuthenticator always allows new user profiles.
263 *
264 * @param user a User object that contains the data the user submitted
265 * @param authentication the user's authentication information, if known
266 * @param authType the type of authentication information being provided
267 * @return true
268 * @throws AuthenticatorException an exception if an error occurs
269 */
270 public boolean allowProfileCreation(User user, Object authentication, int authType, int reqSource) throws AuthenticatorException {
271 return true;
272 }
273
274 /**
275 * The DefaultAuthenticator always allows profile updates.
276 *
277 * @param user a User object that contains the data the user submitted
278 * @param authentication the user's authentication information, if known
279 * @param authType the type of authentication information being provided
280 * @param reqSource the source of the request (eg web, api)
281 * @return true
282 * @throws AuthenticatorException an exception if an error occurs
283 */
284 public boolean allowProfileUpdates(User user, Object authentication, int authType, int reqSource) throws AuthenticatorException {
285 return true;
286 }
287
288 /**
289 * The DefaultAuthenticator always allows password updates.
290 *
291 * @param user a User object that contains the data the user submitted
292 * @param authentication the user's authentication information, if known
293 * @param authType the type of authentication information being provided
294 * @param reqSource the source of the request (eg web, api)
295 * @return true
296 * @throws AuthenticatorException an exception if an error occurs
297 */
298 public boolean allowPasswordUpdates(User user, Object authentication, int authType, int reqSource) throws AuthenticatorException {
299 return true;
300 }
301
302 /**
303 * The DefaultAuthenticator always allows permission updates.
304 *
305 * @param user a User object that contains the data the user submitted
306 * @param authentication the user's authentication information, if known
307 * @param authType the type of authentication information being provided
308 * @param reqSource the source of the request (eg web, api)
309 * @return true
310 * @throws AuthenticatorException an exception if an error occurs
311 */
312 public boolean allowPermissionUpdates(User user, Object authentication, int authType, int reqSource) throws AuthenticatorException {
313 return true;
314 }
315
316 /**
317 * The DefaultAuthenticator always allows preferences updates.
318 *
319 * @param user a User object that contains the data the user submitted
320 * @param authentication the user's authentication information, if known
321 * @param authType the type of authentication information being provided
322 * @param reqSource the source of the request (eg web, api)
323 * @return true
324 * @throws AuthenticatorException an exception if an error occurs
325 */
326 public boolean allowPreferenceUpdates(User user, Object authentication, int authType, int reqSource) throws AuthenticatorException {
327 return true;
328 }
329
330 /**
331 * The DefaultAuthenticator does not make any changes to a newly created profile.
332 *
333 * @param user a User object that contains the newly created profile
334 * @param authentication the user's authentication information, if known
335 * @param authType the type of authentication information being provided
336 * @param reqSource the source of the request (eg web, api)
337 * @return boolean indicating whther changes to the user were made
338 * @throws AuthenticatorException an error occurs
339 */
340 public boolean createProfile(User user, Object authentication, int authType, int reqSource) throws AuthenticatorException {
341 return false;
342 }
343
344 /**
345 * The DefaultAuthenticator does not make any changes to an updated profile.
346 *
347 * @param user a User object that contains the updated profile
348 * @param updateType the type of information that is being updated
349 * @param authentication the user's authentication information, if known
350 * @param authType the type of authentication information being provided
351 * @param reqSource the source of the request (eg web, api)
352 * @return boolean indicating whther changes to the user were made
353 * @throws AuthenticatorException an exception if the login is unsuccessful, or an error occurs
354 */
355 public boolean updateProfile(User user, int updateType, Object authentication, int authType, int reqSource) throws AuthenticatorException {
356 return false;
357 }
358
359 }