KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > outerj > daisy > repository > serverimpl > user > LocalUserManagementStrategy


1 /*
2  * Copyright 2004 Outerthought bvba and Schaubroeck nv
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.outerj.daisy.repository.serverimpl.user;
17
18 import java.sql.*;
19 import java.util.*;
20 import java.util.Date JavaDoc;
21 import java.security.MessageDigest JavaDoc;
22
23 import org.apache.avalon.framework.logger.Logger;
24 import org.apache.xmlbeans.XmlObject;
25 import org.apache.commons.collections.primitives.LongList;
26 import org.apache.commons.collections.primitives.ArrayLongList;
27 import org.outerj.daisy.repository.commonimpl.AuthenticatedUser;
28 import org.outerj.daisy.repository.commonimpl.user.RoleImpl;
29 import org.outerj.daisy.repository.commonimpl.user.RolesImpl;
30 import org.outerj.daisy.repository.commonimpl.user.RolesUtil;
31 import org.outerj.daisy.repository.commonimpl.user.UserImpl;
32 import org.outerj.daisy.repository.commonimpl.user.UserManagementStrategy;
33 import org.outerj.daisy.repository.commonimpl.user.UsersImpl;
34 import org.outerj.daisy.jdbcutil.JdbcHelper;
35 import org.outerj.daisy.repository.serverimpl.EventHelper;
36 import org.outerj.daisy.repository.serverimpl.LocalRepositoryManager.Context;
37 import org.outerj.daisy.repository.user.*;
38 import org.outerj.daisy.repository.RepositoryEventType;
39 import org.outerj.daisy.repository.RepositoryException;
40 import org.outerx.daisy.x10.*;
41
42 public class LocalUserManagementStrategy implements UserManagementStrategy {
43     private static final String JavaDoc SELECT_ALL_FROM_USERS = "select id, login, default_role, first_name, last_name, email, updateable_by_user, confirmed, confirmkey, auth_scheme, last_modified, last_modifier,updatecount from users";
44     private static final String JavaDoc SELECT_USER_WHERE_LOGIN = SELECT_ALL_FROM_USERS+" where login=?";
45     private static final String JavaDoc SELECT_USER_WHERE_ID = SELECT_ALL_FROM_USERS+" where id=?";
46     private static final String JavaDoc SELECT_USERS_WHERE_EMAIL = SELECT_ALL_FROM_USERS+" where email=?";
47     private static final String JavaDoc SELECT_ALL_FROM_ROLES = "select id, \"name\", description, last_modified, last_modifier, updatecount from roles";
48     private static final String JavaDoc SELECT_ROLE_WHERE_NAME = SELECT_ALL_FROM_ROLES+" where \"name\"=?";
49     private static final String JavaDoc SELECT_ROLE_WHERE_ID = SELECT_ALL_FROM_ROLES+" where id=?";
50     private static final String JavaDoc SELECT_ROLES_WHERE_USERID = "select role_id from user_roles where user_id=?";
51     private static final String JavaDoc INSERT_ROLES = "insert into user_roles(role_id, user_id) values (?,?)";
52     private static final String JavaDoc DELETE_ROLES = "delete from user_roles where user_id=?";
53     private Logger logger;
54     private Context context;
55     private JdbcHelper jdbcHelper;
56     private EventHelper eventHelper;
57
58     /**
59      * @param context
60      */

61     public LocalUserManagementStrategy(Context context, JdbcHelper jdbcHelper) {
62         this.context = context;
63         this.logger = context.getLogger();
64         this.jdbcHelper = jdbcHelper;
65         this.eventHelper = new EventHelper(context, jdbcHelper);
66     }
67     
68     public Users loadUsers(AuthenticatedUser requestingUser) throws UserManagementException {
69         if (!requestingUser.isInAdministratorRole())
70             throw new UserManagementException("Non-Administrator users cannot retrieve other users then themselve.");
71
72         Connection conn = null;
73         PreparedStatement stmt = null;
74         ArrayList users = new ArrayList();
75         
76         try {
77             conn = context.getDataSource().getConnection();
78
79             stmt = conn.prepareStatement(SELECT_ALL_FROM_USERS);
80             ResultSet rs = stmt.executeQuery();
81             
82             while (rs.next()) {
83                 UserImpl user = getUserFromResultSet(rs, requestingUser);
84                 users.add(user);
85             }
86         } catch (Exception JavaDoc e) {
87             throw new UserManagementException("Error while loading user list.", e);
88         } finally {
89             jdbcHelper.closeStatement(stmt);
90             jdbcHelper.closeConnection(conn);
91         }
92         
93         return new UsersImpl((User[])users.toArray(new User[users.size()]));
94     }
95
96     private UserImpl getUserFromResultSet(ResultSet rs, AuthenticatedUser requestingUser) throws SQLException, UserManagementException {
97         long id = rs.getLong(1);
98         String JavaDoc login = rs.getString(2);
99         long defaultRoleId = rs.getLong(3);
100         String JavaDoc firstName = rs.getString(4);
101         String JavaDoc lastName = rs.getString(5);
102         String JavaDoc email = rs.getString(6);
103         boolean updateableByUser = rs.getBoolean(7);
104         boolean confirmed = rs.getBoolean(8);
105         String JavaDoc confirmKey = rs.getString(9);
106         String JavaDoc authenticationScheme = rs.getString(10);
107         Date JavaDoc lastModified = rs.getTimestamp(11);
108         long lastModifier = rs.getLong(12);
109         long updateCount = rs.getLong(13);
110
111         UserImpl user = new UserImpl(this, login, requestingUser);
112         UserImpl.IntimateAccess userInt = user.getIntimateAccess(this);
113         // TODO using the saved() method here to set the object state is conceptually wrong,
114
// the purpose of that method is to update the object state after saving it
115
userInt.saved(id, firstName, lastName, email, lastModified, lastModifier, updateCount);
116         user.setUpdateableByUser(updateableByUser);
117         user.setConfirmed(confirmed);
118         user.setConfirmKey(confirmKey);
119         user.setAuthenticationScheme(authenticationScheme);
120
121         Role[] userRoles = getUserRoles(id, requestingUser);
122         for (int i = 0; i < userRoles.length; i++) {
123             Role role = userRoles[i];
124             userInt.addToRole(role);
125         }
126
127         if (defaultRoleId == -1) {
128             user.setDefaultRole(null);
129         } else {
130             Role defaultRole = RolesUtil.getRole(user.getAllRoles(), defaultRoleId);
131             user.setDefaultRole(defaultRole);
132         }
133
134         return user;
135     }
136
137     public long[] getUserIds(AuthenticatedUser requestingUser) throws UserManagementException {
138         Connection conn = null;
139         Statement stmt = null;
140         try {
141             conn = context.getDataSource().getConnection();
142             stmt = conn.createStatement();
143             ResultSet rs = stmt.executeQuery("select id from users");
144             LongList userIds = new ArrayLongList();
145             while (rs.next())
146                 userIds.add(rs.getLong(1));
147             return userIds.toArray();
148         } catch (Exception JavaDoc e) {
149             throw new UserManagementException("Error while loading user list.", e);
150         } finally {
151             jdbcHelper.closeStatement(stmt);
152             jdbcHelper.closeConnection(conn);
153         }
154     }
155
156     public Roles loadRoles(AuthenticatedUser requestingUser) throws UserManagementException {
157         Connection conn = null;
158         PreparedStatement stmt = null;
159         ArrayList roles = new ArrayList();
160         
161         try {
162             conn = context.getDataSource().getConnection();
163
164             stmt = conn.prepareStatement(SELECT_ALL_FROM_ROLES);
165             ResultSet rs = stmt.executeQuery();
166             
167             while (rs.next()) {
168                 long id = rs.getLong(1);
169                 String JavaDoc name = rs.getString(2);
170                 String JavaDoc description = rs.getString(3);
171                 Date JavaDoc lastModified = rs.getTimestamp(4);
172                 long lastModifier = rs.getLong(5);
173                 RoleImpl role = new RoleImpl(this, name, requestingUser);
174                 role.setDescription(description);
175                 RoleImpl.IntimateAccess roleInt = role.getIntimateAccess(this);
176                 roleInt.setId(id);
177                 roleInt.setLastModified(lastModified);
178                 roleInt.setLastModifier(lastModifier);
179                 roles.add(role);
180             }
181             
182             rs.close();
183         } catch (Exception JavaDoc e) {
184             throw new UserManagementException("Error while loading role list.", e);
185         } finally {
186             jdbcHelper.closeStatement(stmt);
187             jdbcHelper.closeConnection(conn);
188         }
189         
190         return new RolesImpl((Role[])roles.toArray(new Role[roles.size()]));
191     }
192     
193     public void deleteUser(long userId, AuthenticatedUser requestingUser) throws UserManagementException {
194         if (logger.isDebugEnabled())
195             logger.debug("start user deletion for user with login "+userId);
196
197         if (!requestingUser.isInAdministratorRole())
198             throw new UserManagementException("Only Administrators can delete users.");
199
200         if (userId == 1)
201             throw new UserManagementException("The system user (id 1) cannot be deleted.");
202         
203         Connection conn = null;
204         PreparedStatement stmt = null;
205         try {
206             conn = context.getDataSource().getConnection();
207             //yes...transaction necessary.
208
jdbcHelper.startTransaction(conn);
209
210             UserImpl user = getUser(userId, requestingUser);
211
212             logger.debug("first we need to remove child records from user_roles");
213
214             stmt = conn.prepareStatement("delete from user_roles where user_id=?");
215             stmt.setLong(1, userId);
216             
217             stmt.executeUpdate();
218             stmt.close();
219             logger.debug("user_roles should be clear for this user. User can be deleted now");
220
221             // Before deleting the user, set its last_modifier to 1 (system user ID), because
222
// it could be that the user last saved itself in which case deleting will
223
// fail because of the foreign key constraint that protects users from being
224
// deleted if they are still referenced as last_modifier of users.
225
stmt = conn.prepareStatement("update users set last_modifier = 1 where id = ?");
226             stmt.setLong(1, userId);
227             stmt.execute();
228             stmt.close();
229
230             stmt = conn.prepareStatement("delete from users where id=?");
231             stmt.setLong(1, userId);
232             
233             int modifiedRecords = stmt.executeUpdate();
234             if (modifiedRecords!=1) {
235                 throw new UserManagementException("Something went wrong " +
236                         "when trying to delete user with login "+userId+". " +
237                         "No records were affected.");
238             }
239
240             XmlObject eventDescription = createUserDeletedEvent(user, requestingUser.getId());
241             eventHelper.createEvent(eventDescription, "UserDeleted", conn);
242
243             conn.commit();
244         } catch (Throwable JavaDoc e) {
245             jdbcHelper.rollback(conn);
246             throw new UserManagementException("Error deleting the user with ID " + userId
247                     + ". This might be because the user is still in use (referenced by other objects such as documents), in which case it is impossible to delete the user.", e);
248         } finally {
249             jdbcHelper.closeStatement(stmt);
250             jdbcHelper.closeConnection(conn);
251             logger.debug("end user deletion");
252         }
253
254         // fire synchronous events
255
context.getCommonRepository().fireRepositoryEvent(RepositoryEventType.USER_DELETED, userId, -1);
256     }
257
258     private UserDeletedDocument createUserDeletedEvent(UserImpl user, long deleterId) {
259         UserDeletedDocument userDeletedDocument = UserDeletedDocument.Factory.newInstance();
260         UserDeletedDocument.UserDeleted userDeleted = userDeletedDocument.addNewUserDeleted();
261         userDeleted.setDeleterId(deleterId);
262         userDeleted.setDeletedTime(new GregorianCalendar());
263         UserDocument.User userXml = user.getXml().getUser();
264         if (userXml.isSetPassword())
265             userXml.unsetPassword();
266         userDeleted.addNewDeletedUser().setUser(userXml);
267         return userDeletedDocument;
268     }
269
270     public void deleteRole(long roleId, AuthenticatedUser requestingUser) throws UserManagementException {
271         if (!requestingUser.isInAdministratorRole())
272             throw new UserManagementException("Only Administrators can delete roles.");
273
274         if (roleId == 1)
275             throw new UserManagementException("The Administrator role (id 1) cannot be deleted.");
276
277         /* TRICKY SITUATION:
278          *
279          * suppose a role is deleted. Then we first remove all related records
280          * from the user_roles table. We then check all the users who have
281          * their default role pointing towards the role-to-be deleted.
282          *
283          * Suppose we find out that some users still have this role as their
284          * default role AND IT IS THEIR ONLY ROLE! This is tricky. What to do?
285          *
286          * Do we:
287          * 1) either: delete these users
288          * 2) or: throw an exception (preferred!) - we can provide an extra api call
289          * that enables an admin to switch a specified default role to another
290          * one. Also relieves us from the tedious task to switch default role
291          * for users who DO have other roles to another role. Which role to
292          * choose there? Therefore: just throw an exception in that case
293          * and let the role switching task be the responsability of an admin!
294          *
295          */

296         Connection conn = null;
297         PreparedStatement stmt = null;
298         
299         try {
300             conn = context.getDataSource().getConnection();
301
302             stmt = conn.prepareStatement("select count(*) from users where default_role=?");
303             stmt.setLong(1, roleId);
304             
305             ResultSet rs = stmt.executeQuery();
306             
307             rs.next();
308             // Let's see if the admin needs to do some work :)
309
long userCount = rs.getInt(1);
310             if (userCount>0) {
311                 throw new UserManagementException("Cannot delete the role with id "+roleId+" because " +
312                         "there are still "+userCount+" users who have this role as their default. " +
313                         "Change their default roles before deleting this role.");
314             }
315             
316         } catch (Exception JavaDoc e) {
317             throw new UserManagementException("Error while deleting role.", e);
318         } finally {
319             jdbcHelper.closeStatement(stmt);
320             jdbcHelper.closeConnection(conn);
321         }
322         
323         // no users exist with their default role the role-to-be-deleted. We can continue.
324

325         try {
326             conn = context.getDataSource().getConnection();
327             jdbcHelper.startTransaction(conn);
328
329             RoleImpl role = getRole(roleId, requestingUser);
330
331             stmt = conn.prepareStatement("delete from user_roles where role_id=?");
332             stmt.setLong(1, roleId);
333             
334             stmt.executeUpdate();
335             stmt.close();
336             //went ok? allright. Now we can delete role itself.
337

338             stmt = conn.prepareStatement("delete from roles where id=?");
339             stmt.setLong(1, roleId);
340                 
341             int modifiedRecords = stmt.executeUpdate();
342             if (modifiedRecords!=1) {
343                 throw new UserManagementException("Something went wrong " +
344                         "when trying to delete role with id "+roleId +". " +
345                         "Most likely the role didn't exist." +
346                         modifiedRecords +" records modified.");
347             }
348             stmt.close();
349
350             eventHelper.createEvent(createRoleDeletedEvent(role), "RoleDeleted", conn);
351
352             conn.commit();
353             
354         } catch (Throwable JavaDoc e) {
355             jdbcHelper.rollback(conn);
356             throw new UserManagementException("Error deleting the role with ID " + roleId + ".", e);
357         } finally {
358             jdbcHelper.closeStatement(stmt);
359             jdbcHelper.closeConnection(conn);
360         }
361         
362         // fire synchronous events
363
context.getCommonRepository().fireRepositoryEvent(RepositoryEventType.ROLE_DELETED, roleId, -1);
364     }
365
366     private RoleDeletedDocument createRoleDeletedEvent(RoleImpl role) {
367         RoleDeletedDocument roleDeletedDocument = RoleDeletedDocument.Factory.newInstance();
368         RoleDeletedDocument.RoleDeleted roleDeleted = roleDeletedDocument.addNewRoleDeleted();
369         roleDeleted.addNewDeletedRole().setRole(role.getXml().getRole());
370         roleDeleted.setDeletedTime(new GregorianCalendar());
371         roleDeleted.setDeleterId(role.getIntimateAccess(this).getCurrentUser().getId());
372         return roleDeletedDocument;
373     }
374
375     public UserImpl getUser(String JavaDoc userLogin, AuthenticatedUser requestingUser) throws UserManagementException {
376         Connection conn = null;
377         PreparedStatement stmt = null;
378         UserImpl user = null;
379
380         try {
381             conn = context.getDataSource().getConnection();
382             stmt = conn.prepareStatement(SELECT_USER_WHERE_LOGIN);
383             stmt.setString(1, userLogin);
384             ResultSet rs = stmt.executeQuery();
385             
386             if (rs.next()) {
387                 user = getUserFromResultSet(rs, requestingUser);
388
389                 if (user.getId() != requestingUser.getId() && !requestingUser.isInAdministratorRole())
390                     throw new UserManagementException("Non-Administrator users can only access their own user record.");
391
392             } else {
393                 throw new UserNotFoundException(userLogin);
394             }
395             
396             rs.close();
397         } catch (Exception JavaDoc e) {
398             if (e instanceof UserManagementException)
399                 throw (UserManagementException)e;
400             else
401                 throw new UserManagementException("Error while loading user with login "+userLogin+".", e);
402         } finally {
403             jdbcHelper.closeStatement(stmt);
404             jdbcHelper.closeConnection(conn);
405         }
406
407         return user;
408     }
409
410     /**
411      * returns array of Role objects to which the user with userid id belongs
412      */

413     private Role[] getUserRoles(long id, AuthenticatedUser requestingUser) throws UserManagementException {
414         if (logger.isDebugEnabled())
415             logger.debug("start loading roles for user with id "+id);
416         Connection conn = null;
417         PreparedStatement stmt = null;
418         ArrayList ids = new ArrayList();
419         Role[] roles=null;
420         
421         try {
422             conn = context.getDataSource().getConnection();
423             stmt = conn.prepareStatement(SELECT_ROLES_WHERE_USERID);
424             stmt.setLong(1, id);
425             ResultSet rs = stmt.executeQuery();
426             
427             while (rs.next()) {
428                 long roleId = rs.getLong(1);
429                 if (logger.isDebugEnabled())
430                     logger.debug("role found with id "+roleId);
431                 ids.add(new Long JavaDoc(roleId));
432             }
433             rs.close();
434         } catch (Exception JavaDoc e) {
435             throw new UserManagementException("Error while loading role list for user with id "+id+".", e);
436         } finally {
437             jdbcHelper.closeStatement(stmt);
438             jdbcHelper.closeConnection(conn);
439         }
440         
441         Iterator iter = ids.iterator();
442         roles = new Role[ids.size()];
443         for (int i=0; i<roles.length; i++) {
444             long roleId = ((Long JavaDoc)iter.next()).longValue();
445             roles[i] = getRoleWhereId(roleId, requestingUser);
446         }
447         
448         return roles;
449         
450     }
451
452     public RoleImpl getRole(String JavaDoc roleName, AuthenticatedUser requestingUser) throws UserManagementException{
453         Connection conn = null;
454         PreparedStatement stmt = null;
455         RoleImpl role = null;
456         
457         try {
458             conn = context.getDataSource().getConnection();
459             stmt = conn.prepareStatement(SELECT_ROLE_WHERE_NAME);
460             stmt.setString(1, roleName);
461             ResultSet rs = stmt.executeQuery();
462                         
463             if (rs.next()) {
464                 long id = rs.getLong(1);
465                 String JavaDoc name = rs.getString(2);
466                 String JavaDoc description = rs.getString(3);
467                 Date JavaDoc lastModified = rs.getTimestamp(4);
468                 long lastModifier = rs.getLong(5);
469                 long updateCount = rs.getLong(6);
470
471                 role = new RoleImpl(this, name, requestingUser);
472                 RoleImpl.IntimateAccess roleInt = role.getIntimateAccess(this);
473                 roleInt.saved(id, name, description, updateCount);
474                 roleInt.setLastModified(lastModified);
475                 roleInt.setLastModifier(lastModifier);
476                 
477             } else {
478                 throw new RoleNotFoundException(roleName);
479             }
480             rs.close();
481         } catch (Exception JavaDoc e) {
482             if (e instanceof UserManagementException)
483                 throw (UserManagementException)e;
484             else
485                 throw new UserManagementException("Error while loading role with name "+roleName+".", e);
486         } finally {
487             jdbcHelper.closeStatement(stmt);
488             jdbcHelper.closeConnection(conn);
489         }
490         
491         return role;
492     }
493
494     private Role getRoleWhereId(long roleId, AuthenticatedUser requestingUser) throws UserManagementException{
495         Connection conn = null;
496         PreparedStatement stmt = null;
497         RoleImpl role = null;
498         
499         try {
500             conn = context.getDataSource().getConnection();
501             stmt = conn.prepareStatement(SELECT_ROLE_WHERE_ID);
502             stmt.setLong(1, roleId);
503             ResultSet rs = stmt.executeQuery();
504             
505             if (rs.next()) {
506                 long id = rs.getLong(1);
507                 String JavaDoc name = rs.getString(2);
508                 String JavaDoc description = rs.getString(3);
509                 Date JavaDoc lastModified = rs.getTimestamp(4);
510                 long lastModifier = rs.getLong(5);
511                 long updateCount = rs.getLong(6);
512
513                 role = new RoleImpl(this, name, requestingUser);
514                 RoleImpl.IntimateAccess roleInt = role.getIntimateAccess(this);
515                 roleInt.saved(id, name, description, updateCount);
516                 roleInt.setLastModified(lastModified);
517                 roleInt.setLastModifier(lastModifier);
518                 
519             } else {
520                 throw new UserManagementException("No role found with id "+roleId);
521             }
522             rs.close();
523         } catch (Exception JavaDoc e) {
524             throw new UserManagementException("Error while loading role with id "+roleId+".", e);
525         } finally {
526             jdbcHelper.closeStatement(stmt);
527             jdbcHelper.closeConnection(conn);
528         }
529         
530         return role;
531     }
532     
533     public void store(UserImpl user) throws UserManagementException {
534         logger.debug("starting storage of user");
535
536         if (user.getId() == 1) {
537             throw new UserManagementException("User $system is read-only.");
538         }
539
540         UserImpl.IntimateAccess userInt = user.getIntimateAccess(this);
541
542         // New users can only be created by administrators, for restrictions on updating of users, see further on
543
if (user.getId() == -1 && !userInt.getCurrentUser().isInAdministratorRole())
544             throw new UserManagementException("Only Administrators can update user records.");
545
546
547         if (user.getId() == -1 && user.getAuthenticationScheme().equals("daisy") && userInt.getPassword() == null) {
548             throw new UserManagementException("Password is required if the authentication scheme is daisy.");
549         }
550
551         if (userInt.getPassword() != null && !UserImpl.isValidPassword(userInt.getPassword())) {
552             throw new UserManagementException("Password does not adhere to password rules.");
553         }
554
555         if (user.getDefaultRole() != null) {
556             if (!user.hasRole(user.getDefaultRole().getId())) {
557                 throw new UserManagementException("The user has a default role that does not belong to its assigned roles.");
558             }
559         }
560
561         if (user.getAllRoles().getArray().length < 1) {
562             throw new UserManagementException("A user must have at least one role.");
563         }
564
565         long id = user.getId();
566         boolean isNew = (id == -1);
567
568         Connection conn = null;
569         PreparedStatement stmt = null;
570         try {
571             conn = context.getDataSource().getConnection();
572             //we need transaction for this one...
573
jdbcHelper.startTransaction(conn);
574
575             String JavaDoc login = user.getLogin();
576             java.util.Date JavaDoc lastModified = new Date JavaDoc();
577             logger.debug("the last_modified date that will be stored is "+lastModified);
578
579             /* The (authenticated)user that requested the administrative user object is now persisting it,
580              * therefore he will be the last modifier
581              */

582             long lastModifier = userInt.getCurrentUser().getId();
583             XmlObject eventDescription;
584
585             if (id == -1) {
586                 // first test if the login already exists so that we can throw a nice exception in that case
587
stmt = conn.prepareStatement("select id from users where login = ?");
588                 stmt.setString(1, login);
589                 ResultSet rs = stmt.executeQuery();
590                 if (rs.next())
591                     throw new DuplicateLoginException(login);
592                 stmt.close();
593
594                 //a new user must be stored in the data store
595
stmt = conn.prepareStatement("insert into users(id, login, password, default_role, first_name, last_name, email, updateable_by_user, confirmed, confirmkey, auth_scheme, last_modified, last_modifier, updatecount) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
596                 id = context.getNextUserId();
597                 stmt.setLong(1, id);
598                 stmt.setString(2, login);
599                 stmt.setString(3, hashPassword(userInt.getPassword()));
600                 stmt.setLong(4, user.getDefaultRole() == null ? -1 : user.getDefaultRole().getId());
601                 stmt.setString(5, user.getFirstName());
602                 stmt.setString(6, user.getLastName());
603                 stmt.setString(7, user.getEmail());
604                 stmt.setBoolean(8, user.isUpdateableByUser());
605                 stmt.setBoolean(9, user.isConfirmed());
606                 stmt.setString(10, user.getConfirmKey());
607                 stmt.setString(11, user.getAuthenticationScheme());
608                 stmt.setTimestamp(12, new Timestamp(lastModified.getTime()));
609                 stmt.setLong(13, lastModifier);
610                 stmt.setLong(14, 1L);
611                 stmt.executeUpdate();
612
613                 storeRolesForUser(user, id, conn);
614
615                 eventDescription = createUserCreatedEvent(user, lastModified);
616             } else {
617                 //we have to update an existing user
618
UserImpl oldUser = getUser(user.getId(), userInt.getCurrentUser());
619
620                 if (!userInt.getCurrentUser().isInAdministratorRole()) {
621                     if (!oldUser.isUpdateableByUser() || (user.getId() != userInt.getCurrentUser().getId())) {
622                         throw new UserManagementException("Updating the user " + user.getId() + " is not allowed for user " + userInt.getCurrentUser().getId());
623                     }
624
625                     if (!oldUser.isConfirmed()) {
626                         throw new UserManagementException("A non-confimred user cannot by changed by a non-Administrator.");
627                     }
628
629                     if (userInt.hasRoleChanges() || (user.getDefaultRole() == null && oldUser.getDefaultRole() != null) || (user.getDefaultRole() != null && user.getDefaultRole().getId() != oldUser.getDefaultRole().getId())
630                         || !user.getLogin().equals(oldUser.getLogin())) {
631                         throw new UserManagementException("Changes to the roles or login of a user can only be done by an Administrator.");
632                     }
633                 }
634
635                 String JavaDoc oldPassword;
636                 // check if nobody else changed it in the meantime, and load previous password
637
stmt = conn.prepareStatement("select updatecount, password from users where id = ? " + jdbcHelper.getSharedLockClause());
638                 stmt.setLong(1, id);
639                 ResultSet rs = stmt.executeQuery();
640                 if (!rs.next()) {
641                     throw new UserManagementException("Unexpected error: the User with id " + id + " does not exist in the database.");
642                 } else {
643                     long dbUpdateCount = rs.getLong(1);
644                     if (dbUpdateCount != user.getUpdateCount()) {
645                         throw new UserManagementException("The User was concurrently changed.");
646                     }
647                     oldPassword = rs.getString(2);
648                 }
649                 stmt.close();
650
651                 if (!oldUser.getLogin().equals(user.getLogin())) {
652                     // login changed, test if there is already a user with the new login so that we can
653
// throw a nice exception in that case
654
stmt = conn.prepareStatement("select id from users where login = ?");
655                     stmt.setString(1, login);
656                     ResultSet rs2 = stmt.executeQuery();
657                     if (rs2.next() && rs2.getLong(1) != user.getId())
658                         throw new DuplicateLoginException(login);
659                     stmt.close();
660                 }
661
662                 //first see if there were role changes
663
if (userInt.hasRoleChanges()) {
664                     stmt = conn.prepareStatement("delete from user_roles where user_id=?");
665                     stmt.setLong(1, user.getId());
666                     
667                     stmt.executeUpdate();
668                     stmt.close();
669                 }
670
671                 long newUpdateCount = user.getUpdateCount() + 1;
672
673                 String JavaDoc password = null;
674                 if (user.getAuthenticationScheme().equals("daisy")) {
675                     password = userInt.getPassword() == null ? oldPassword: hashPassword(userInt.getPassword());
676                     if (password == null)
677                         throw new UserManagementException("If the authentication scheme is daisy, then the password is required.");
678                 }
679
680                 stmt = conn.prepareStatement("update users set login=?, password=?, default_role=?, first_name=?, last_name=?, email=?, updateable_by_user=?, confirmed=?, confirmkey=?, auth_scheme=?, last_modified=?, last_modifier=?, updatecount=? where id=?");
681                 stmt.setString(1, login);
682                 stmt.setString(2, password);
683                 stmt.setLong(3, user.getDefaultRole() == null ? -1 : user.getDefaultRole().getId());
684                 stmt.setString(4, user.getFirstName());
685                 stmt.setString(5, user.getLastName());
686                 stmt.setString(6, user.getEmail());
687                 stmt.setBoolean(7, user.isUpdateableByUser());
688                 stmt.setBoolean(8, user.isConfirmed());
689                 stmt.setString(9, user.getConfirmKey());
690                 stmt.setString(10, user.getAuthenticationScheme());
691                 stmt.setTimestamp(11, new Timestamp(lastModified.getTime()));
692                 stmt.setLong(12, lastModifier);
693                 stmt.setLong(13, newUpdateCount);
694                 stmt.setLong(14, user.getId());
695                 
696                 stmt.executeUpdate();
697                 storeRolesForUser(user, user.getId(), conn);
698
699                 eventDescription = createUserUpdatedEvent(oldUser, user, lastModified, newUpdateCount);
700             }
701
702             eventHelper.createEvent(eventDescription, isNew ? "UserCreated" : "UserUpdated", conn);
703
704             //everything went ok, so we can actively update the user OBJECT as well.
705
conn.commit();
706             userInt.saved(id, user.getFirstName(), user.getLastName(), user.getEmail(), lastModified, lastModifier, user.getUpdateCount() + 1);
707             
708         } catch (Throwable JavaDoc e) {
709             jdbcHelper.rollback(conn);
710             if (e instanceof DuplicateLoginException)
711                 throw (DuplicateLoginException)e;
712             else
713                 throw new UserManagementException("Error storing user.", e);
714         } finally {
715             jdbcHelper.closeStatement(stmt);
716             jdbcHelper.closeConnection(conn);
717         }
718
719         // fire synchronous events
720
if (isNew)
721             context.getCommonRepository().fireRepositoryEvent(RepositoryEventType.USER_CREATED, id, user.getUpdateCount());
722         else
723             context.getCommonRepository().fireRepositoryEvent(RepositoryEventType.USER_UPDATED, id, user.getUpdateCount());
724     }
725
726     public static String JavaDoc hashPassword(String JavaDoc password) {
727         if (password == null)
728             return null;
729         try {
730             byte[] data = password.getBytes("UTF-8");
731             MessageDigest JavaDoc digest = MessageDigest.getInstance("SHA-1");
732             digest.update(data);
733             byte[] result = digest.digest();
734             return toHexString(result);
735         } catch (Exception JavaDoc e) {
736             throw new RuntimeException JavaDoc("Problem calculating password hash.", e);
737         }
738     }
739
740     public static String JavaDoc toHexString(byte[] b) {
741         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(b.length * 2);
742         for (int i = 0; i < b.length; i++) {
743             sb.append(hexChar[(b[i] & 0xf0) >>> 4]);
744             sb.append(hexChar[b[i] & 0x0f]);
745         }
746         return sb.toString();
747     }
748
749     static char[] hexChar = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
750
751     private UserCreatedDocument createUserCreatedEvent(UserImpl user, Date JavaDoc lastModified) {
752         UserDocument.User userXml = user.getXml().getUser();
753         userXml.setLastModified(getCalendar(lastModified));
754         userXml.setLastModifier(user.getIntimateAccess(this).getCurrentUser().getId());
755         userXml.setUpdateCount(1);
756         if (userXml.isSetPassword())
757             userXml.unsetPassword();
758
759         UserCreatedDocument userCreatedDocument = UserCreatedDocument.Factory.newInstance();
760         userCreatedDocument.addNewUserCreated().addNewNewUser().setUser(userXml);
761
762         return userCreatedDocument;
763     }
764
765     private UserUpdatedDocument createUserUpdatedEvent(UserImpl oldUser, UserImpl newUser, Date JavaDoc lastModified, long newUpdateCount) {
766         UserUpdatedDocument userUpdatedDocument = UserUpdatedDocument.Factory.newInstance();
767         UserUpdatedDocument.UserUpdated userUpdated = userUpdatedDocument.addNewUserUpdated();
768
769         UserDocument.User oldUserXml = oldUser.getXml().getUser();
770         if (oldUserXml.isSetPassword())
771             oldUserXml.unsetPassword();
772         userUpdated.addNewOldUser().setUser(oldUserXml);
773
774         UserDocument.User newUserXml = newUser.getXml().getUser();
775         newUserXml.setLastModified(getCalendar(lastModified));
776         newUserXml.setLastModifier(newUser.getIntimateAccess(this).getCurrentUser().getId());
777         newUserXml.setUpdateCount(newUpdateCount);
778         if (newUserXml.isSetPassword())
779             newUserXml.unsetPassword();
780         userUpdated.addNewNewUser().setUser(newUserXml);
781
782         return userUpdatedDocument;
783     }
784
785     private Calendar getCalendar(Date JavaDoc date) {
786         GregorianCalendar calendar = new GregorianCalendar();
787         calendar.setTime(date);
788         return calendar;
789     }
790
791     /**
792      * @param user the user to store the roles for
793      * @param conn the connection to the data store containing users and roles
794      */

795     private void storeRolesForUser(UserImpl user, long userId, Connection conn) throws SQLException {
796         logger.debug("ARRAY SIZE: "+user.getAllRoles().getArray().length);
797         UserImpl.IntimateAccess userInt = user.getIntimateAccess(this);
798         
799         //can't do this because we haven't called the saved() method yet on the user!!!
800
//long userId = user.getId();
801

802         if (userInt.hasRoleChanges()) {
803             logger.debug("there are role changes");
804             PreparedStatement delRoles = null;
805             PreparedStatement insertRoles = null;
806             try {
807                 //first we need to delete the roles the user currently belongs to
808
delRoles = conn.prepareStatement(DELETE_ROLES);
809                 delRoles.setLong(1, userId);
810                 delRoles.executeUpdate();
811
812                 //roles deleted, now we can store the current state
813
insertRoles = conn.prepareStatement(INSERT_ROLES);
814                 Role[] userRoles = user.getAllRoles().getArray();
815                 for (int i = 0; i < userRoles.length; i++) {
816                     Role role = userRoles[i];
817                     insertRoles.setLong(1, role.getId());
818                     insertRoles.setLong(2, userId);
819                     insertRoles.executeUpdate();
820                 }
821             } finally {
822                 jdbcHelper.closeStatement(delRoles);
823                 jdbcHelper.closeStatement(insertRoles);
824             }
825         }
826     }
827
828     public void store(RoleImpl role) throws UserManagementException {
829         
830         RoleImpl.IntimateAccess roleInt = role.getIntimateAccess(this);
831
832         if (!roleInt.getCurrentUser().isInAdministratorRole())
833             throw new UserManagementException("Only Administrators can create or update roles.");
834
835         long id = role.getId();
836         boolean isNew = id == -1;
837
838         Connection conn = null;
839         PreparedStatement stmt = null;
840         try {
841             conn = context.getDataSource().getConnection();
842             jdbcHelper.startTransaction(conn);
843
844             String JavaDoc roleName = role.getName();
845             java.util.Date JavaDoc lastModified = new Date JavaDoc();
846
847             /* The user that requested the role is now persisting it,
848              * therefore he will be the last modifier
849              */

850             long lastModifier = roleInt.getCurrentUser().getId();
851             XmlObject eventDescription;
852
853             if (id == -1) {
854                 //a new role must be stored in the data store
855
stmt = conn.prepareStatement("insert into roles(id, \"name\", description, last_modified, last_modifier, updatecount) values (?,?,?,?,?,?)");
856                 id = context.getNextRoleId();
857                 stmt.setLong(1, id);
858                 stmt.setString(2, roleName);
859                 stmt.setString(3, role.getDescription());
860                 stmt.setTimestamp(4, new Timestamp(lastModified.getTime()));
861                 stmt.setLong(5, lastModifier);
862                 stmt.setLong(6, 1);
863                 stmt.executeUpdate();
864
865                 eventDescription = createRoleCreatedEvent(role, lastModified);
866             } else {
867                 //we have to update an existing role
868

869                 // check if nobody else changed it in the meantime
870
stmt = conn.prepareStatement("select updatecount from roles where id = ? " + jdbcHelper.getSharedLockClause());
871                 stmt.setLong(1, id);
872                 ResultSet rs = stmt.executeQuery();
873                 if (!rs.next()) {
874                     throw new UserManagementException("Unexpected error: the Role with id " + id + " does not exist in the database.");
875                 } else {
876                     long dbUpdateCount = rs.getLong(1);
877                     if (dbUpdateCount != role.getUpdateCount()) {
878                         throw new UserManagementException("The role was concurrently changed by someone else.");
879                     }
880                 }
881                 stmt.close();
882
883                 RoleImpl oldRole = getRole(role.getId(), roleInt.getCurrentUser());
884                 long newUpdateCount = role.getUpdateCount() + 1;
885
886                 stmt = conn.prepareStatement("update roles set \"name\"=?, description=?, last_modified=?, last_modifier=?, updatecount=? where id=?");
887                 stmt.setString(1, roleName);
888                 stmt.setString(2, role.getDescription());
889                 stmt.setTimestamp(3, new Timestamp(lastModified.getTime()));
890                 stmt.setLong(4, lastModifier);
891                 stmt.setLong(5, newUpdateCount);
892                 stmt.setLong(6, id);
893                 stmt.executeUpdate();
894
895                 eventDescription = createRoleUpdatedEvent(oldRole, role, lastModified, newUpdateCount);
896             }
897
898             eventHelper.createEvent(eventDescription, isNew ? "RoleCreated" : "RoleUpdated", conn);
899
900             conn.commit();
901
902             //everything went ok, so we can actively update the role OBJECT as well.
903
roleInt.saved(id, roleName, role.getDescription(), role.getUpdateCount() + 1);
904             roleInt.setLastModified(lastModified);
905             roleInt.setLastModifier(lastModifier);
906             
907         } catch (Throwable JavaDoc e) {
908             jdbcHelper.rollback(conn);
909             throw new UserManagementException("Error storing role.", e);
910         } finally {
911             jdbcHelper.closeStatement(stmt);
912             jdbcHelper.closeConnection(conn);
913         }
914
915         // fire synchronous events
916
if (isNew)
917             context.getCommonRepository().fireRepositoryEvent(RepositoryEventType.ROLE_CREATED, id, role.getUpdateCount());
918         else
919             context.getCommonRepository().fireRepositoryEvent(RepositoryEventType.ROLE_UPDATED, id, role.getUpdateCount());
920    }
921
922     private RoleCreatedDocument createRoleCreatedEvent(RoleImpl role, Date JavaDoc lastModified) {
923         RoleCreatedDocument roleCreatedDocument = RoleCreatedDocument.Factory.newInstance();
924
925         RoleDocument.Role roleXml = role.getXml().getRole();
926         roleXml.setLastModified(getCalendar(lastModified));
927         roleXml.setLastModifier(role.getIntimateAccess(this).getCurrentUser().getId());
928         roleXml.setUpdateCount(1);
929
930         roleCreatedDocument.addNewRoleCreated().addNewNewRole().setRole(roleXml);
931
932         return roleCreatedDocument;
933     }
934
935     private RoleUpdatedDocument createRoleUpdatedEvent(RoleImpl oldRole, RoleImpl newRole, Date JavaDoc lastModified, long newUpdateCount) {
936         RoleUpdatedDocument roleUpdatedDocument = RoleUpdatedDocument.Factory.newInstance();
937         RoleUpdatedDocument.RoleUpdated roleUpdated = roleUpdatedDocument.addNewRoleUpdated();
938         roleUpdated.addNewOldRole().setRole(oldRole.getXml().getRole());
939
940         RoleDocument.Role newRoleXml = newRole.getXml().getRole();
941         newRoleXml.setLastModified(getCalendar(lastModified));
942         newRoleXml.setLastModifier(newRole.getIntimateAccess(this).getCurrentUser().getId());
943         newRoleXml.setUpdateCount(newUpdateCount);
944
945         roleUpdated.addNewNewRole().setRole(newRoleXml);
946
947         return roleUpdatedDocument;
948     }
949
950     public UserImpl getUser(long userId, AuthenticatedUser requestingUser) throws UserManagementException {
951         if (userId != requestingUser.getId() && !requestingUser.isInAdministratorRole())
952             throw new UserManagementException("Non-Administrator users can only access their own user record.");
953
954         Connection conn = null;
955         PreparedStatement stmt = null;
956         UserImpl user = null;
957
958         try {
959             conn = context.getDataSource().getConnection();
960             stmt = conn.prepareStatement(SELECT_USER_WHERE_ID);
961             stmt.setLong(1, userId);
962             ResultSet rs = stmt.executeQuery();
963             
964             if (rs.next()) {
965                 user = getUserFromResultSet(rs, requestingUser);
966             } else {
967                 throw new UserNotFoundException(userId);
968             }
969             
970             rs.close();
971         } catch (Exception JavaDoc e) {
972             if (e instanceof UserManagementException)
973                 throw (UserManagementException)e;
974             else
975                 throw new UserManagementException("Error while loading user with id "+userId+".", e);
976         } finally {
977             jdbcHelper.closeStatement(stmt);
978             jdbcHelper.closeConnection(conn);
979         }
980         return user;
981     }
982
983     public RoleImpl getRole(long roleId, AuthenticatedUser requestingUser) throws UserManagementException {
984         Connection conn = null;
985         PreparedStatement stmt = null;
986         RoleImpl role = null;
987         
988         try {
989             conn = context.getDataSource().getConnection();
990             stmt = conn.prepareStatement(SELECT_ROLE_WHERE_ID);
991             stmt.setLong(1, roleId);
992             ResultSet rs = stmt.executeQuery();
993             
994             if (rs.next()) {
995                 long id = rs.getLong(1);
996                 String JavaDoc name = rs.getString(2);
997                 String JavaDoc description = rs.getString(3);
998                 Date JavaDoc lastModified = rs.getTimestamp(4);
999                 long lastModifier = rs.getLong(5);
1000                long updateCount = rs.getLong(6);
1001
1002                role = new RoleImpl(this, name, requestingUser);
1003                RoleImpl.IntimateAccess roleInt = role.getIntimateAccess(this);
1004                roleInt.saved(id, name, description, updateCount);
1005                roleInt.setLastModified(lastModified);
1006                roleInt.setLastModifier(lastModifier);
1007                
1008            } else {
1009                throw new RoleNotFoundException(roleId);
1010            }
1011            rs.close();
1012        } catch (Exception JavaDoc e) {
1013            if (e instanceof UserManagementException)
1014                throw (UserManagementException)e;
1015            else
1016                throw new UserManagementException("Error while loading role with id "+roleId+".", e);
1017        } finally {
1018            jdbcHelper.closeStatement(stmt);
1019            jdbcHelper.closeConnection(conn);
1020        }
1021        
1022        return role;
1023    }
1024
1025    public UsersImpl getUsersByEmail(String JavaDoc email, AuthenticatedUser requestingUser) throws RepositoryException {
1026        if (!requestingUser.isInAdministratorRole())
1027            throw new UserManagementException("Non-Administrator users cannot retrieve other users then themselve.");
1028
1029        Connection conn = null;
1030        PreparedStatement stmt = null;
1031        ArrayList users = new ArrayList();
1032
1033        try {
1034            conn = context.getDataSource().getConnection();
1035
1036            stmt = conn.prepareStatement(SELECT_USERS_WHERE_EMAIL);
1037            stmt.setString(1, email);
1038            ResultSet rs = stmt.executeQuery();
1039
1040            while (rs.next()) {
1041                UserImpl user = getUserFromResultSet(rs, requestingUser);
1042                users.add(user);
1043            }
1044        } catch (Exception JavaDoc e) {
1045            throw new UserManagementException("Error while loading list of users by email.", e);
1046        } finally {
1047            jdbcHelper.closeStatement(stmt);
1048            jdbcHelper.closeConnection(conn);
1049        }
1050
1051        return new UsersImpl((User[])users.toArray(new User[users.size()]));
1052    }
1053
1054    public AuthenticationSchemeInfos getAuthenticationSchemes(AuthenticatedUser requestingUser) {
1055        return context.getUserAuthenticator().getAuthenticationSchemes();
1056    }
1057}
1058
Popular Tags