Project

General

Profile

Download (19.8 KB) Statistics
| Branch: | Tag: | Revision:
1
// $Id$
2
/**
3
 * Copyright (C) 2007 EDIT
4
 * European Distributed Institute of Taxonomy
5
 * http://www.e-taxonomy.eu
6
 *
7
 * The contents of this file are subject to the Mozilla Public License Version 1.1
8
 * See LICENSE.TXT at the top of this package for the full license terms.
9
 */
10
package eu.etaxonomy.cdm.api.service;
11

    
12
import java.util.ArrayList;
13
import java.util.Collection;
14
import java.util.HashMap;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.UUID;
18

    
19
import org.hibernate.NonUniqueResultException;
20
import org.hibernate.criterion.Criterion;
21
import org.springframework.beans.factory.annotation.Autowired;
22
import org.springframework.dao.DataAccessException;
23
import org.springframework.dao.IncorrectResultSizeDataAccessException;
24
import org.springframework.security.access.AccessDeniedException;
25
import org.springframework.security.access.prepost.PreAuthorize;
26
import org.springframework.security.authentication.AuthenticationManager;
27
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
28
import org.springframework.security.authentication.dao.SaltSource;
29
import org.springframework.security.authentication.encoding.PasswordEncoder;
30
import org.springframework.security.core.Authentication;
31
import org.springframework.security.core.GrantedAuthority;
32
import org.springframework.security.core.context.SecurityContextHolder;
33
import org.springframework.security.core.userdetails.UserCache;
34
import org.springframework.security.core.userdetails.UserDetails;
35
import org.springframework.security.core.userdetails.UsernameNotFoundException;
36
import org.springframework.security.core.userdetails.cache.NullUserCache;
37
import org.springframework.stereotype.Service;
38
import org.springframework.transaction.annotation.Transactional;
39
import org.springframework.util.Assert;
40

    
41
import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl;
42
import eu.etaxonomy.cdm.model.common.Group;
43
import eu.etaxonomy.cdm.model.common.User;
44
import eu.etaxonomy.cdm.persistence.dao.common.IGrantedAuthorityDao;
45
import eu.etaxonomy.cdm.persistence.dao.common.IGroupDao;
46
import eu.etaxonomy.cdm.persistence.dao.common.IUserDao;
47
import eu.etaxonomy.cdm.persistence.query.MatchMode;
48
import eu.etaxonomy.cdm.persistence.query.OrderHint;
49

    
50
/**
51
 * Note: All group related functionality has been refactored into a GroupService. The will be removed in a future version.
52
 */
53
@Service
54
@Transactional(readOnly = true)
55
// NOTE: no type level @PreAuthorize annotation for this class!
56
public class UserService extends ServiceBase<User,IUserDao> implements IUserService {
57

    
58
    protected IGroupDao groupDao;
59

    
60
    protected IGrantedAuthorityDao grantedAuthorityDao;
61

    
62
    private SaltSource saltSource; // = new ReflectionSaltSource();
63

    
64
    private PasswordEncoder passwordEncoder; // = new Md5PasswordEncoder();
65

    
66
    private AuthenticationManager authenticationManager;
67

    
68

    
69
    private UserCache userCache = new NullUserCache();
70

    
71
    @Autowired(required = false)
72
    public void setUserCache(UserCache userCache) {
73
        Assert.notNull(userCache, "userCache cannot be null");
74
        this.userCache = userCache;
75
    }
76

    
77
    @Autowired(required = false)
78
    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
79

    
80
        this.passwordEncoder = passwordEncoder;
81
    }
82

    
83
    @Autowired(required = false)
84
    public void setSaltSource(SaltSource saltSource) {
85
        this.saltSource = saltSource;
86
    }
87

    
88
    @Autowired(required= false)
89
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
90
        this.authenticationManager = authenticationManager;
91
    }
92

    
93
    @Override
94
    @Autowired
95
    protected void setDao(IUserDao dao) {
96
        this.dao = dao;
97
    }
98

    
99
    @Autowired
100
    public void setGroupDao(IGroupDao groupDao) {
101
        this.groupDao = groupDao;
102
    }
103

    
104
    @Autowired
105
    public void setGrantedAuthorityDao(IGrantedAuthorityDao grantedAuthorityDao) {
106
        this.grantedAuthorityDao = grantedAuthorityDao;
107
    }
108

    
109

    
110
    /**
111
     * Changes the own password of in the database of the user which is
112
     * currently authenticated. Requires to supply the old password for security
113
     * reasons. Refreshes the authentication in the SecurityContext after the
114
     * password change by re-authenticating the user with the new password.
115
     *
116
     * @see org.springframework.security.provisioning.UserDetailsManager#changePassword(java.lang.String,
117
     *      java.lang.String)
118
     */
119
    @Override
120
    @Transactional(readOnly=false)
121
    @PreAuthorize("isAuthenticated()")
122
    public void changePassword(String oldPassword, String newPassword) {
123
        Assert.hasText(oldPassword);
124
        Assert.hasText(newPassword);
125
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
126
        if(authentication != null && authentication.getPrincipal() != null && authentication.getPrincipal() instanceof User) {
127

    
128
            // get current authentication and load it from the persistence layer,
129
            // to make sure we are modifying the instance which is
130
            // attached to the hibernate session
131
            User user = (User)authentication.getPrincipal();
132
            user = dao.load(user.getUuid());
133

    
134
            // check if old password is valid
135
            authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), oldPassword));
136

    
137
            // make new password and set it
138
            Object salt = this.saltSource.getSalt(user);
139
            String password = passwordEncoder.encodePassword(newPassword, salt);
140
            user.setPassword(password);
141
            dao.update(user);
142

    
143
            // authenticate the user again with the new password
144
            UsernamePasswordAuthenticationToken newAuthentication = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
145
            newAuthentication.setDetails(authentication.getDetails());
146
            SecurityContextHolder.getContext().setAuthentication(newAuthentication);
147
            userCache.removeUserFromCache(user.getUsername());
148

    
149
        } else {
150
            throw new AccessDeniedException("Can't change password as no Authentication object found in context for current user.");
151
        }
152
    }
153

    
154
    @Override
155
    @Transactional(readOnly=false)
156
    @PreAuthorize("#username == authentication.name or hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
157
    public void changePasswordForUser(String username, String newPassword) {
158
        Assert.hasText(username);
159
        Assert.hasText(newPassword);
160

    
161
        try {
162
            User user = dao.findUserByUsername(username);
163
            if(user == null) {
164
                throw new UsernameNotFoundException(username);
165
            }
166

    
167
            Object salt = this.saltSource.getSalt(user);
168

    
169
            String password = passwordEncoder.encodePassword(newPassword, salt);
170
            user.setPassword(password);
171

    
172
            dao.update(user);
173
            userCache.removeUserFromCache(user.getUsername());
174
        } catch(NonUniqueResultException nure) {
175
            throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", 1);
176
        }
177
    }
178

    
179
    @Override
180
    @Transactional(readOnly=false)
181
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
182
    public void createUser(UserDetails user) {
183
    	Assert.isInstanceOf(User.class, user);
184

    
185
        String rawPassword = user.getPassword();
186
        Object salt = this.saltSource.getSalt(user);
187

    
188
        String password = passwordEncoder.encodePassword(rawPassword, salt);
189
        ((User)user).setPassword(password);
190

    
191
        dao.save((User)user);
192
    }
193

    
194
    @Override
195
    @Transactional(readOnly=false)
196
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
197
    public void deleteUser(String username) {
198
        Assert.hasLength(username);
199

    
200
        User user = dao.findUserByUsername(username);
201
        if(user != null) {
202
            dao.delete(user);
203
        }
204

    
205
        userCache.removeUserFromCache(username);
206
    }
207

    
208
    /* (non-Javadoc)
209
     * @see org.springframework.security.provisioning.UserDetailsManager#updateUser(org.springframework.security.core.userdetails.UserDetails)
210
     */
211
    @Override
212
    @Transactional(readOnly=false)
213
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
214
    public void updateUser(UserDetails user) {
215
        Assert.isInstanceOf(User.class, user);
216

    
217
        dao.update((User)user);
218
        userCache.removeUserFromCache(user.getUsername());
219
    }
220

    
221
    /* (non-Javadoc)
222
     * @see org.springframework.security.provisioning.UserDetailsManager#userExists(java.lang.String)
223
     */
224
    @Override
225
    public boolean userExists(String username) {
226
        Assert.hasText(username);
227

    
228
        User user = dao.findUserByUsername(username);
229
        return user != null;
230
    }
231

    
232
    /**
233
     * <b>DO NOT CALL THIS METHOD IN LONG RUNNING SESSIONS OR CONVERSATIONS
234
     * A THROWN UsernameNotFoundException WILL RENDER THE CONVERSATION UNUSABLE</b>
235
     *
236
     * @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String)
237
     */
238
    // NOTE: this method must not be secured since it is being used during the
239
    //       authentication process
240
    @Override
241
    public UserDetails loadUserByUsername(String username)
242
            throws UsernameNotFoundException, DataAccessException {
243
        Assert.hasText(username);
244
        try {
245
            User user = dao.findUserByUsername(username);
246
            if(user == null) {
247
                throw new UsernameNotFoundException(username);
248
            }
249
            return user;
250
        } catch(NonUniqueResultException nure) {
251
            throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", 1);
252
        }
253
    }
254

    
255
    /* (non-Javadoc)
256
     * @see org.springframework.security.provisioning.GroupManager#addGroupAuthority(java.lang.String, org.springframework.security.core.GrantedAuthority)
257
     */
258
    @Override
259
    @Deprecated // use GroupService instead
260
    @Transactional(readOnly=false)
261
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
262
    public void addGroupAuthority(String groupName, GrantedAuthority authority) {
263
        Assert.hasText(groupName);
264
        Assert.notNull(authority);
265

    
266
        Group group = groupDao.findGroupByName(groupName);
267
        if(group.getGrantedAuthorities().add(authority)) {
268
            groupDao.update(group);
269
        }
270
    }
271

    
272
    /* (non-Javadoc)
273
     * @see org.springframework.security.provisioning.GroupManager#addUserToGroup(java.lang.String, java.lang.String)
274
     */
275
    @Override
276
    @Deprecated // use GroupService instead
277
    @Transactional(readOnly=false)
278
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
279
    public void addUserToGroup(String username, String groupName) {
280
        Assert.hasText(username);
281
        Assert.hasText(groupName);
282

    
283
        Group group = groupDao.findGroupByName(groupName);
284
        User user = dao.findUserByUsername(username);
285

    
286
        if(group.addMember(user)) {
287
            groupDao.update(group);
288
            userCache.removeUserFromCache(user.getUsername());
289
        }
290
    }
291

    
292
    /* (non-Javadoc)
293
     * @see org.springframework.security.provisioning.GroupManager#createGroup(java.lang.String, java.util.List)
294
     */
295
    @Override
296
    @Deprecated // use GroupService instead
297
    @Transactional(readOnly=false)
298
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
299
    public void createGroup(String groupName, List<GrantedAuthority> authorities) {
300
        Assert.hasText(groupName);
301
        Assert.notNull(authorities);
302

    
303
        Group group = Group.NewInstance(groupName);
304

    
305
        for(GrantedAuthority authority : authorities) {
306
            group.getGrantedAuthorities().add(authority);
307
        }
308

    
309
        groupDao.save(group);
310
    }
311

    
312
    /* (non-Javadoc)
313
     * @see org.springframework.security.provisioning.GroupManager#deleteGroup(java.lang.String)
314
     */
315
    @Override
316
    @Deprecated // use GroupService instead
317
    @Transactional(readOnly=false)
318
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
319
    public void deleteGroup(String groupName) {
320
        Assert.hasText(groupName);
321

    
322
        Group group = groupDao.findGroupByName(groupName);
323
        groupDao.delete(group);
324
    }
325

    
326
    /* (non-Javadoc)
327
     * @see org.springframework.security.provisioning.GroupManager#findAllGroups()
328
     */
329
    @Override
330
    @Deprecated // use GroupService instead
331
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
332
    public List<String> findAllGroups() {
333
        return groupDao.listNames(null,null);
334
    }
335

    
336
    /* (non-Javadoc)
337
     * @see org.springframework.security.provisioning.GroupManager#findGroupAuthorities(java.lang.String)
338
     */
339
    @Override
340
    @Deprecated // use GroupService instead
341
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
342
    public List<GrantedAuthority> findGroupAuthorities(String groupName) {
343
        Assert.hasText(groupName);
344
        Group group = groupDao.findGroupByName(groupName);
345

    
346
        return new ArrayList<GrantedAuthority>(group.getGrantedAuthorities());
347
    }
348

    
349
    /* (non-Javadoc)
350
     * @see org.springframework.security.provisioning.GroupManager#findUsersInGroup(java.lang.String)
351
     */
352
    @Override
353
    @Deprecated // use GroupService instead
354
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
355
    public List<String> findUsersInGroup(String groupName) {
356
        Assert.hasText(groupName);
357
        Group group = groupDao.findGroupByName(groupName);
358

    
359
        List<String> users = groupDao.listMembers(group, null, null);
360

    
361
        return users;
362
    }
363

    
364
    /* (non-Javadoc)
365
     * @see org.springframework.security.provisioning.GroupManager#removeGroupAuthority(java.lang.String, org.springframework.security.core.GrantedAuthority)
366
     */
367
    @Override
368
    @Deprecated // use GroupService instead
369
    @Transactional(readOnly=false)
370
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
371
    public void removeGroupAuthority(String groupName,	GrantedAuthority authority) {
372
        Assert.hasText(groupName);
373
        Assert.notNull(authority);
374

    
375
        Group group = groupDao.findGroupByName(groupName);
376

    
377
        if(group.getGrantedAuthorities().remove(authority)) {
378
            groupDao.update(group);
379
        }
380
    }
381

    
382
    /* (non-Javadoc)
383
     * @see org.springframework.security.provisioning.GroupManager#removeUserFromGroup(java.lang.String, java.lang.String)
384
     */
385
    @Override
386
    @Deprecated // use GroupService instead
387
    @Transactional(readOnly=false)
388
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
389
    public void removeUserFromGroup(String username, String groupName) {
390
        Assert.hasText(username);
391
        Assert.hasText(groupName);
392

    
393
        Group group = groupDao.findGroupByName(groupName);
394
        User user = dao.findUserByUsername(username);
395

    
396
        if(group.removeMember(user)) {
397
            groupDao.update(group);
398
            userCache.removeUserFromCache(user.getUsername());
399
        }
400
    }
401

    
402
    /* (non-Javadoc)
403
     * @see org.springframework.security.provisioning.GroupManager#renameGroup(java.lang.String, java.lang.String)
404
     */
405
    @Override
406
    @Deprecated // use GroupService instead
407
    @Transactional(readOnly=false)
408
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
409
    public void renameGroup(String oldName, String newName) {
410
        Assert.hasText(oldName);
411
        Assert.hasText(newName);
412

    
413
        Group group = groupDao.findGroupByName(oldName);
414

    
415
        group.setName(newName);
416
        groupDao.update(group);
417
    }
418

    
419
    /* (non-Javadoc)
420
     * @see eu.etaxonomy.cdm.api.service.ServiceBase#save(eu.etaxonomy.cdm.model.common.CdmBase)
421
     */
422
    @Override
423
    @Transactional(readOnly=false)
424
   // @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_RUN_AS_ADMIN') or hasRole('ROLE_USER_MANAGER')")
425
    public User save(User user) {
426
        if(user.getId() == 0 || dao.load(user.getUuid()) == null){
427
            createUser(user);
428
        }else{
429
            updateUser(user);
430
        }
431
        return user;
432
    }
433

    
434
    /* (non-Javadoc)
435
     * @see eu.etaxonomy.cdm.api.service.ServiceBase#update(eu.etaxonomy.cdm.model.common.CdmBase)
436
     */
437
    @Override
438
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
439
    public UUID update(User user) {
440
        updateUser(user);
441
        return user.getUuid();
442
    }
443

    
444
    /* (non-Javadoc)
445
     * @see eu.etaxonomy.cdm.api.service.IUserService#saveGrantedAuthority(org.springframework.security.core.GrantedAuthority)
446
     */
447
    @Override
448
    @Transactional(readOnly=false)
449
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
450
    public UUID saveGrantedAuthority(GrantedAuthority grantedAuthority) {
451
        return grantedAuthorityDao.save((GrantedAuthorityImpl)grantedAuthority).getUuid();
452
    }
453

    
454

    
455

    
456
    /* (non-Javadoc)
457
     * @see eu.etaxonomy.cdm.api.service.IUserService#listByUsername(java.lang.String, eu.etaxonomy.cdm.persistence.query.MatchMode, java.util.List, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
458
     */
459
    @Override
460
    @Transactional(readOnly = true)
461
    public List<User> listByUsername(String queryString,MatchMode matchmode, List<Criterion> criteria, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
462
         Integer numberOfResults = dao.countByUsername(queryString, matchmode, criteria);
463

    
464
         List<User> results = new ArrayList<User>();
465
         if(numberOfResults > 0) {
466
                results = dao.findByUsername(queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths);
467
         }
468
         return results;
469
    }
470

    
471
    /* ================================================
472
     *  overriding methods to secure them
473
     *  via the type level annotation @PreAuthorize
474
     * ================================================ */
475

    
476
    @Override
477
    @Transactional(readOnly=false)
478
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
479
    public DeleteResult delete(User persistentObject)  {
480
        return super.delete(persistentObject);
481
    }
482

    
483
    @Override
484
    @Transactional(readOnly=false)
485
    public DeleteResult delete(UUID userUuid)  {
486
        return delete(dao.load(userUuid));
487
    }
488

    
489
    @Override
490
    @Transactional(readOnly=false)
491
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
492
    public Map<UUID, User> save(Collection<User> newInstances) {
493
        Map<UUID, User> users = new HashMap<UUID, User>();
494
    	for (User user: newInstances){
495
        	createUser(user);
496
        	users.put(user.getUuid(), user);
497
        }
498
    	return users;
499
    }
500

    
501
    @Override
502
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
503
    public UUID saveOrUpdate(User transientObject) {
504
        return super.saveOrUpdate(transientObject);
505
    }
506

    
507
    @Override
508
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
509
    @Transactional(readOnly=false)
510
    public User merge(User detachedObject) {
511
        return super.merge(detachedObject);
512
    }
513

    
514
    @Override
515
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
516
    @Transactional(readOnly=false)
517
    public List<User> merge(List<User> detachedObjects) {
518
        return super.merge(detachedObjects);
519
    }
520

    
521
    @Override
522
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
523
    public Map<UUID, User> saveOrUpdate(Collection<User> transientInstances) {
524
        return super.saveOrUpdate(transientInstances);
525
    }
526

    
527
}
(94-94/97)