View Javadoc

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.util;
20  
21  import java.io.UnsupportedEncodingException;
22  import java.security.MessageDigest;
23  import java.security.NoSuchAlgorithmException;
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.Collections;
27  import java.util.HashMap;
28  import java.util.HashSet;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.Locale;
32  import java.util.Map;
33  import java.util.Random;
34  import java.util.Set;
35  
36  import org.itracker.core.resources.ITrackerResources;
37  import org.itracker.model.Issue;
38  import org.itracker.model.NameValuePair;
39  import org.itracker.model.Permission;
40  import org.itracker.model.PermissionType;
41  import org.itracker.model.Project;
42  import org.itracker.model.User;
43  import org.itracker.services.UserService;
44  import org.itracker.services.exceptions.PasswordException;
45  
46  //import sun.misc.BASE64Encoder;
47  
48  public class UserUtilities implements AuthenticationConstants {
49      protected static final char[] alphabet = new char[] {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
50      
51      public static final int STATUS_DELETED = -1;
52      public static final int STATUS_ACTIVE = 1;
53      public static final int STATUS_LOCKED = 2;
54  
55      // TODO: Could use an enumeration
56  
57      /** User Admin Permission.  Currently this is equivalent to super user, since the permission can't be granted, and is only available to an admin. */
58      public static final int PERMISSION_USER_ADMIN = -1;
59      /** Product Admin Permission */
60      public static final int PERMISSION_PRODUCT_ADMIN = 1;
61      /** Issue Create Permission */
62      public static final int PERMISSION_CREATE = 2;
63      /** Issue Edit Permission.  Users with this permission can edit any issue in the project. */
64      public static final int PERMISSION_EDIT = 3;
65      /** Issue Close Permission.  Users with this permission can close issues in the project. */
66      public static final int PERMISSION_CLOSE = 4;
67      /** Issue Assign to Self Permission.  Users with this permission can assign issues to themselves. */
68      public static final int PERMISSION_ASSIGN_SELF = 5;
69      /** Issue Assign to Others Permissions.  Users with this permission can assign issues to anyone, given than those users have the ability to recieve the assignment. */
70      public static final int PERMISSION_ASSIGN_OTHERS = 6;
71      /** View All Issues Permission.  Users can view all issues in the project. */
72      public static final int PERMISSION_VIEW_ALL = 7;
73      /** View Users Issues Permission.  Users can view thier own issues.  This includes ones they are the creator or owner of. */
74      public static final int PERMISSION_VIEW_USERS = 8;
75      /** Edit Users Issues Permission.  Users with this permission can edit any issue they created or own.
76       * They are limited to editing the description, adding history entries, and adding attachments. */
77      public static final int PERMISSION_EDIT_USERS = 9;
78      /** Issue Unassign Self Permission.  Users with this permission can unassign issues they own. */
79      public static final int PERMISSION_UNASSIGN_SELF = 10;
80      /** Issue Assignable.  Users with this permission can be assigned any issue in the system.  To determine if a user can
81       * be assigned an issue, it will be a combination of users with EDIT_ALL, users with EDIT_USERS if they are the creator,
82       * and users with this permission and EDIT_USERS. */
83      public static final int PERMISSION_ASSIGNABLE = 11;
84      /** Create for Others.  Users with this permission are allowed to create issues on behalf of other users.  The system
85       * will treat the issue as if the other user had created it.  The actual creator will be logged in the audit log. */
86      public static final int PERMISSION_CREATE_OTHERS = 12;
87      /** Full edit permission.  This defines what levelof editing a user has for an issue.  Without this permission, users will
88       * be limited to editing only the description, attachments, custom fields, and history of an issue. */
89      public static final int PERMISSION_EDIT_FULL = 13;
90      
91      
92      private static final Integer[] ALL_PERMISSIONS = new Integer[] {
93  		    PERMISSION_PRODUCT_ADMIN,
94  		    PERMISSION_CREATE,
95  		    PERMISSION_EDIT,
96  		    PERMISSION_CLOSE,
97  		    PERMISSION_ASSIGN_SELF,
98  		    PERMISSION_ASSIGN_OTHERS,
99  		    PERMISSION_VIEW_ALL,
100 		    PERMISSION_VIEW_USERS,
101 		    PERMISSION_EDIT_USERS,
102 		    PERMISSION_UNASSIGN_SELF,
103 		    PERMISSION_ASSIGNABLE,
104 		    PERMISSION_CREATE_OTHERS,
105 		    PERMISSION_EDIT_FULL,
106 	
107 	};
108     public static final Set<Integer> ALL_PERMISSIONS_SET = Collections.unmodifiableSet(getAllPermissionsSet());
109     
110     private static final Set<Integer> getAllPermissionsSet() {
111     	return new HashSet<Integer>(Arrays.asList(ALL_PERMISSIONS));
112     }
113     public static final int REGISTRATION_TYPE_ADMIN = 1;
114     public static final int REGISTRATION_TYPE_SELF = 2;
115     public static final int REGISTRATION_TYPE_IMPORT = 3;
116     
117     public static final int PREF_HIDE_ASSIGNED = 1;
118     public static final int PREF_HIDE_UNASSIGNED = 2;
119     public static final int PREF_HIDE_CREATED = 4;
120     public static final int PREF_HIDE_WATCHED = 8;
121     
122     public UserUtilities() {
123     }
124     
125     public static String getStatusName(int value) {
126         return getStatusName(value, ITrackerResources.getLocale());
127     }
128     
129     public static String getStatusName(int value, Locale locale) {
130         return ITrackerResources.getString(ITrackerResources.KEY_BASE_USER_STATUS + value, locale);
131     }
132     
133     public static HashMap<String, String> getStatusNames() {
134         return getStatusNames(ITrackerResources.getLocale());
135     }
136     
137     public static HashMap<String, String> getStatusNames(Locale locale) {
138         HashMap<String,String> statuses = new HashMap<String,String>();
139         statuses.put(Integer.toString(STATUS_DELETED), getStatusName(STATUS_DELETED, locale));
140         statuses.put(Integer.toString(STATUS_ACTIVE), getStatusName(STATUS_ACTIVE, locale));
141         statuses.put(Integer.toString(STATUS_LOCKED), getStatusName(STATUS_LOCKED, locale));
142         return statuses;
143     }
144     
145     public static String getPermissionName(int value) {
146         return getPermissionName(value, ITrackerResources.getLocale());
147     }
148     
149     public static String getPermissionName(int value, Locale locale) {
150         return ITrackerResources.getString(ITrackerResources.KEY_BASE_PERMISSION + value, locale);
151     }
152     
153     public static List<NameValuePair> getPermissionNames() {
154         return getPermissionNames(ITrackerResources.getLocale());
155     }
156     
157     public static List<NameValuePair> getPermissionNames(Locale locale) {
158         List<NameValuePair> permissions = new ArrayList<NameValuePair>();
159         permissions.add(0,new NameValuePair(getPermissionName(PERMISSION_CREATE, locale), Integer.toString(PERMISSION_CREATE)));
160         permissions.add(1,new NameValuePair(getPermissionName(PERMISSION_CREATE_OTHERS, locale), Integer.toString(PERMISSION_CREATE_OTHERS)));
161         permissions.add(2,new NameValuePair(getPermissionName(PERMISSION_EDIT, locale), Integer.toString(PERMISSION_EDIT)));
162         permissions.add(3,new NameValuePair(getPermissionName(PERMISSION_EDIT_USERS, locale), Integer.toString(PERMISSION_EDIT_USERS)));
163         permissions.add(4,new NameValuePair(getPermissionName(PERMISSION_EDIT_FULL, locale), Integer.toString(PERMISSION_EDIT_FULL)));
164         permissions.add(5,new NameValuePair(getPermissionName(PERMISSION_CLOSE, locale), Integer.toString(PERMISSION_CLOSE)));
165         permissions.add(6,new NameValuePair(getPermissionName(PERMISSION_ASSIGNABLE, locale), Integer.toString(PERMISSION_ASSIGNABLE)));
166         permissions.add(7,new NameValuePair(getPermissionName(PERMISSION_ASSIGN_SELF, locale), Integer.toString(PERMISSION_ASSIGN_SELF)));
167         permissions.add(8,new NameValuePair(getPermissionName(PERMISSION_UNASSIGN_SELF, locale), Integer.toString(PERMISSION_UNASSIGN_SELF)));
168         permissions.add(9,new NameValuePair(getPermissionName(PERMISSION_ASSIGN_OTHERS, locale), Integer.toString(PERMISSION_ASSIGN_OTHERS)));
169         permissions.add(10,new NameValuePair(getPermissionName(PERMISSION_VIEW_ALL, locale), Integer.toString(PERMISSION_VIEW_ALL)));
170         permissions.add(11,new NameValuePair(getPermissionName(PERMISSION_VIEW_USERS, locale), Integer.toString(PERMISSION_VIEW_USERS)));
171         permissions.add(12,new NameValuePair(getPermissionName(PERMISSION_PRODUCT_ADMIN, locale), Integer.toString(PERMISSION_PRODUCT_ADMIN)));
172         return permissions;
173     }
174     
175     /**
176      * Genrates a new random password.  The password that is returned is in plain text.
177      * @return a new ramdon plaintext password
178      */
179     public static String generatePassword() throws PasswordException {
180         StringBuffer buf = new StringBuffer();
181         Random rand = new Random();
182         for(int i = 0; i < 8; i++) {
183             buf.append((rand.nextInt(2) == 0 ? Character.toUpperCase(alphabet[rand.nextInt(34)]) : alphabet[rand.nextInt(34)]));
184         }
185         return buf.toString();
186     }
187     
188     /**
189      * Returns an encrypted (digest) password from a plain text password.
190      * @param password the plain text password to encrypt.
191      * @return the encrypted password
192      */
193     public static String encryptPassword(String password) throws PasswordException {
194         String hash = null;
195         if(password != null && ! password.equals("")) {
196             try {
197                 MessageDigest md = MessageDigest.getInstance("SHA");
198                 md.update(password.getBytes("UTF-8"));
199                 byte raw[] = md.digest();
200                 // TODO: must we really use this BASE64Encoder()? it seems to be not support by jrockit rt.jar 
201 //                hash = Base64.encodeBytes(raw);
202                 hash = String.valueOf(Base64Coder.encode(raw));
203 //                hash = (new BASE64Encoder()).encode(raw);
204             } catch(NoSuchAlgorithmException nsae) {
205                 throw new PasswordException(PasswordException.SYSTEM_ERROR);
206             } catch(UnsupportedEncodingException uee) {
207                 throw new PasswordException(PasswordException.SYSTEM_ERROR);
208             }
209         }
210         return hash;
211     }
212     
213     /**
214      * Checks to see if the user is a super user.
215      * @param permissions map of user permissions by project Id
216      * @return true is the user is a super user
217      */
218     public static boolean isSuperUser(Map<Integer, Set<PermissionType>> permissionsMap) {
219         if(permissionsMap == null) {
220             return false;
221         }
222         
223         // Super user has access to all projects, which is indicated by null. 
224         final Set<PermissionType> permissionTypes = permissionsMap.get(null);
225         
226         return (permissionTypes != null) && permissionTypes.contains(PermissionType.USER_ADMIN);
227     }
228     
229     /**
230      * Returns true if the user has the required permission in any project.
231      * @param permissions a Map of the user's permissions by project ID
232      * @param permissionNeeded the permission to check for
233      */
234     public static boolean hasPermission(Map<Integer, Set<PermissionType>> permissionsMap, int permissionNeeded) {
235         if(permissionsMap == null) {
236             return false;
237         }
238         
239         if (isSuperUser(permissionsMap)) {
240             return true;
241         }
242         
243         // Set of project Ids for which the user has permissions. 
244         Set<Integer> keySet = permissionsMap.keySet();
245                 
246         for(Iterator<Integer> iterator = keySet.iterator(); iterator.hasNext(); ) {
247             Integer projectId = iterator.next();
248             if (hasPermission(permissionsMap, projectId, permissionNeeded)) {
249                 return true;
250             }
251         }
252         return false;
253     }
254     
255     /**
256      * Returns true if the user has any of required permissions in any project.
257      * @param permissions a HashMap of the user's permissions
258      * @param permissionsNeeded a list of permissions that can fulfill the permission check
259      */
260     public static boolean hasPermission(Map<Integer, Set<PermissionType>> permissionsMap, int[] permissionsNeeded) {
261         if(permissionsMap == null) {
262             return false;
263         }
264         
265         if (isSuperUser(permissionsMap)) {
266             return true;
267         }
268         
269         Set<Integer> keySet = permissionsMap.keySet();
270         
271         for (Iterator<Integer> iterator = keySet.iterator(); iterator.hasNext(); ) {
272             Integer projectId = iterator.next();
273             
274             if (hasPermission(permissionsMap, projectId, permissionsNeeded)) {
275                 return true;
276             }
277         }
278         return false;
279     }
280     
281     /**
282      * Returns true if the user has the required permission for the given project.
283      * @param permissions a HashMap of the user's permissions
284      * @param projectId the project that the permission is required for
285      * @param permissionNeeded the permission to check for
286      */
287     public static boolean hasPermission(Map<Integer, Set<PermissionType>> permissionsMap, Integer projectId, int permissionNeeded) {
288         if(permissionsMap == null) {
289             return false;
290         }
291         
292         if (isSuperUser(permissionsMap)) {
293             return true;
294         }
295         
296         final Set<PermissionType> permissionTypes = permissionsMap.get(projectId);
297         
298         if ((permissionTypes != null) && permissionTypes.contains(PermissionType.fromCode(permissionNeeded))){
299         	return true;
300         } else {
301         	return false;
302         }
303     }
304     
305     /**
306      * Returns true if the user has any of required permissions for the given project.
307      * @param permissions a HashMap of the user's permissions
308      * @param projectId the project that the permission is required for
309      * @param permissionsNeeded a list of permissions that can fulfill the permission check
310      */
311     public static boolean hasPermission(Map<Integer, Set<PermissionType>> permissionsMap, Integer projectId, int[] permissionsNeeded) {
312         if(permissionsMap == null) {
313             return false;
314         }
315         
316         if (isSuperUser(permissionsMap)) {
317             return true;
318         }
319         
320         final Set<PermissionType> permissionTypes = permissionsMap.get(projectId);
321         
322         if (permissionTypes != null) {
323             for(int i = 0; i < permissionsNeeded.length; i++) {
324                 if(permissionTypes.contains(PermissionType.fromCode(permissionsNeeded[i]))) {
325                     return true;
326                 }
327             }
328         }
329         return false;
330     }
331     
332     public static String getInitial(String name) {
333         return (name != null && name.length() > 0 ? name.substring(0,1).toUpperCase() + "." : "");
334     }
335     
336     public static Permission[] createPermissionArray(User user, Project project, int[] permissions) {
337         Permission[] permissionsArray = new Permission[0];
338         
339         List<Permission> permissionsList = new ArrayList<Permission>();
340         
341         if (user.isSuperUser()) {
342             permissionsList.add(new Permission(-1, user, (Project) null));
343         }
344         
345         for (int i = 0; i < permissions.length; i++) {
346             permissionsList.add(new Permission(permissions[i], user, project));
347         }
348         permissionsArray = new Permission[permissionsList.size()];
349         permissionsArray = permissionsList.toArray(new Permission[]{});
350         
351         return permissionsArray;
352     }
353     
354     /**
355      * Maps sets of permission types by project ID. 
356      */
357     public static Map<Integer, Set<PermissionType>> mapPermissionTypesByProjectId(
358             List<Permission> permissionsList) {
359         
360         final Map<Integer, Set<PermissionType>> permissionsByProjectId = 
361                 new HashMap<Integer, Set<PermissionType>>();
362         
363         for (int i = 0; i < permissionsList.size(); i++) {
364             Permission permission = permissionsList.get(i);
365             
366             // Super user has access to all projects, which is indicated by the "null" project. 
367             final Integer projectId = (permission.getProject() == null) 
368                 ? null : permission.getProject().getId(); 
369                         
370             Set<PermissionType> projectPermissions = permissionsByProjectId.get(projectId); 
371 
372             if (projectPermissions == null) {
373                 // First permission for the project. 
374                 projectPermissions = new HashSet<PermissionType>();
375                 permissionsByProjectId.put(projectId, projectPermissions);
376             } //else { // Add the permission to the existing set of permissions for the project. }
377             
378             PermissionType permissionType = PermissionType.fromCode(permission.getPermissionType());
379             projectPermissions.add(permissionType);
380         }
381         return permissionsByProjectId;
382     }
383     
384     /**
385      * Returns whether the user is currently hiding a particular section on the myItracker page.
386      * @param section the section to check if it is hidden
387      * @param an integer of all sections the user is hiding
388      * @return true if the current section is hidden
389      */
390     public static boolean hideIndexSection(int section, int sections) {
391         return ((section & sections) == section);
392     }
393     
394     public static Integer[] getHiddenIndexSections(int sections) {
395         List<Integer> sectionsList = new ArrayList<Integer>();
396         if(hideIndexSection(PREF_HIDE_ASSIGNED, sections)) {
397             sectionsList.add(Integer.valueOf(PREF_HIDE_ASSIGNED));
398         }
399         if(hideIndexSection(PREF_HIDE_UNASSIGNED, sections)) {
400             sectionsList.add(Integer.valueOf(PREF_HIDE_UNASSIGNED));
401         }
402         if(hideIndexSection(PREF_HIDE_CREATED, sections)) {
403             sectionsList.add(Integer.valueOf(PREF_HIDE_CREATED));
404         }
405         if(hideIndexSection(PREF_HIDE_WATCHED, sections)) {
406             sectionsList.add(Integer.valueOf(PREF_HIDE_WATCHED));
407         }
408         Integer[] sectionsArray = new Integer[sectionsList.size()];
409         sectionsList.toArray(sectionsArray);
410         
411         return sectionsArray;
412     }
413     /**
414 	 * This method will obtain and build a list of possible owners for the
415 	 * webpages to display and the operator to choose from.
416 	 * 
417 	 * 
418 	 * @param issue
419 	 * @param project
420 	 * @param currUser
421 	 * @param locale
422 	 * @param userPermissions
423 	 * @return
424 	 */
425 	public static List<NameValuePair> getAssignableIssueOwnersList(Issue issue,
426 			Project project, User currUser, Locale locale,
427 			UserService userService,
428 			Map<Integer, Set<PermissionType>> userPermissions) {
429 
430 		List<NameValuePair> ownersList = new ArrayList<NameValuePair>();
431 
432 		if (UserUtilities.hasPermission(userPermissions, project.getId(),
433 				UserUtilities.PERMISSION_ASSIGN_OTHERS)) {
434 			if (issue.getOwner() == null) {
435 				ownersList.add(new NameValuePair(ITrackerResources.getString(
436 						"itracker.web.generic.unassigned", locale), "-1"));
437 			} else {
438 				ownersList.add(new NameValuePair(ITrackerResources.getString(
439 						"itracker.web.generic.unassign", locale), "-1"));
440 			}
441 			List<User> possibleOwners = userService.getPossibleOwners(issue,
442 					project.getId(), currUser.getId());
443 			Collections.sort(possibleOwners, User.NAME_COMPARATOR);
444 			List<NameValuePair> ownerNames = Convert
445 					.usersToNameValuePairs(possibleOwners);
446 			for (int i = 0; i < ownerNames.size(); i++) {
447 				ownersList.add(ownerNames.get(i));
448 			}
449 		} else if (UserUtilities.hasPermission(userPermissions,
450 				project.getId(), UserUtilities.PERMISSION_ASSIGN_SELF)) {
451 			if (issue.getOwner() != null) {
452 				if (IssueUtilities.canUnassignIssue(issue, currUser.getId(),
453 						userPermissions)) {
454 					ownersList.add(new NameValuePair(ITrackerResources
455 							.getString("itracker.web.generic.unassign",
456 									locale), "-1"));
457 				}
458 				if (!issue.getOwner().getId().equals(currUser.getId())) {
459 					ownersList.add(new NameValuePair(issue.getOwner()
460 							.getFirstName()
461 							+ " " + issue.getOwner().getLastName(), issue
462 							.getOwner().getId().toString()));
463 					ownersList.add(new NameValuePair(currUser.getFirstName()
464 							+ " " + currUser.getLastName(), currUser.getId()
465 							.toString()));
466 				} else {
467 					ownersList.add(new NameValuePair(currUser.getFirstName()
468 							+ " " + currUser.getLastName(), currUser.getId()
469 							.toString()));
470 				}
471 			}
472 		} else if (issue.getOwner() != null
473 				&& IssueUtilities.canUnassignIssue(issue, currUser.getId(),
474 						userPermissions)) {
475 			ownersList.add(new NameValuePair(ITrackerResources.getString(
476 					"itracker.web.generic.unassign", locale), "-1"));
477 			ownersList.add(new NameValuePair(issue.getOwner().getFirstName()
478 					+ " " + issue.getOwner().getLastName(), issue.getOwner()
479 					.getId().toString()));
480 		}
481 
482 		return ownersList;
483 	}
484 }