3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.cdm
.api
.service
;
12 import java
.util
.ArrayList
;
13 import java
.util
.List
;
14 import java
.util
.UUID
;
16 import org
.hibernate
.NonUniqueResultException
;
17 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
18 import org
.springframework
.dao
.DataAccessException
;
19 import org
.springframework
.dao
.IncorrectResultSizeDataAccessException
;
21 import org
.springframework
.security
.access
.AccessDeniedException
;
22 import org
.springframework
.security
.authentication
.AuthenticationManager
;
23 import org
.springframework
.security
.authentication
.UsernamePasswordAuthenticationToken
;
24 import org
.springframework
.security
.authentication
.dao
.ReflectionSaltSource
;
25 import org
.springframework
.security
.authentication
.dao
.SaltSource
;
26 import org
.springframework
.security
.authentication
.encoding
.Md5PasswordEncoder
;
27 import org
.springframework
.security
.authentication
.encoding
.PasswordEncoder
;
28 import org
.springframework
.security
.core
.Authentication
;
29 import org
.springframework
.security
.core
.GrantedAuthority
;
30 import org
.springframework
.security
.core
.context
.SecurityContextHolder
;
31 import org
.springframework
.security
.core
.userdetails
.UserCache
;
32 import org
.springframework
.security
.core
.userdetails
.UserDetails
;
33 import org
.springframework
.security
.core
.userdetails
.UsernameNotFoundException
;
34 import org
.springframework
.security
.core
.userdetails
.cache
.NullUserCache
;
35 import org
.springframework
.stereotype
.Service
;
36 import org
.springframework
.transaction
.annotation
.Propagation
;
37 import org
.springframework
.transaction
.annotation
.Transactional
;
38 import org
.springframework
.util
.Assert
;
40 import eu
.etaxonomy
.cdm
.model
.common
.GrantedAuthorityImpl
;
41 import eu
.etaxonomy
.cdm
.model
.common
.Group
;
42 import eu
.etaxonomy
.cdm
.model
.common
.User
;
43 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IGrantedAuthorityDao
;
44 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IGroupDao
;
45 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IUserDao
;
48 @Transactional(propagation
= Propagation
.SUPPORTS
, readOnly
= true)
49 public class UserService
extends ServiceBase
<User
,IUserDao
> implements IUserService
{
51 protected IGroupDao groupDao
;
53 protected IGrantedAuthorityDao grantedAuthorityDao
;
55 private SaltSource saltSource
= new ReflectionSaltSource();
57 private PasswordEncoder passwordEncoder
= new Md5PasswordEncoder();
59 private AuthenticationManager authenticationManager
;
61 private UserCache userCache
= new NullUserCache();
63 @Autowired(required
= false)
64 public void setUserCache(UserCache userCache
) {
65 Assert
.notNull(userCache
, "userCache cannot be null");
66 this.userCache
= userCache
;
69 @Autowired(required
= false)
70 public void setPasswordEncoder(PasswordEncoder passwordEncoder
) {
72 this.passwordEncoder
= passwordEncoder
;
75 @Autowired(required
= false)
76 public void setSaltSource(SaltSource saltSource
) {
77 this.saltSource
= saltSource
;
80 @Autowired(required
= false)
81 public void setAuthenticationManager(AuthenticationManager authenticationManager
) {
82 this.authenticationManager
= authenticationManager
;
87 protected void setDao(IUserDao dao
) {
92 public void setGroupDao(IGroupDao groupDao
) {
93 this.groupDao
= groupDao
;
97 public void setGrantedAuthorityDao(IGrantedAuthorityDao grantedAuthorityDao
) {
98 this.grantedAuthorityDao
= grantedAuthorityDao
;
101 @Transactional(readOnly
=false)
102 protected Authentication
createNewAuthentication(Authentication currentAuth
, String newPassword
) {
103 UserDetails user
= loadUserByUsername(currentAuth
.getName());
105 UsernamePasswordAuthenticationToken newAuthentication
= new UsernamePasswordAuthenticationToken(user
, user
.getPassword(), user
.getAuthorities());
106 newAuthentication
.setDetails(currentAuth
.getDetails());
108 return newAuthentication
;
111 @Transactional(readOnly
=false)
112 public void changePassword(String oldPassword
, String newPassword
) {
113 Assert
.hasText(oldPassword
);
114 Assert
.hasText(newPassword
);
115 Authentication authentication
= SecurityContextHolder
.getContext().getAuthentication();
116 if(authentication
!= null && authentication
.getPrincipal() != null && authentication
.getPrincipal() instanceof User
) {
117 User user
= (User
)authentication
.getPrincipal();
119 authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(user
.getUsername(), oldPassword
));
121 Object salt
= this.saltSource
.getSalt(user
);
123 String password
= passwordEncoder
.encodePassword(newPassword
, salt
);
124 ((User
)user
).setPassword(password
);
126 dao
.update((User
)user
);
127 SecurityContextHolder
.getContext().setAuthentication(createNewAuthentication(authentication
, newPassword
));
128 userCache
.removeUserFromCache(user
.getUsername());
130 throw new AccessDeniedException("Can't change password as no Authentication object found in context for current user.");
134 @Transactional(readOnly
=false)
135 public void changePasswordForUser(String username
, String newPassword
) {
136 Assert
.hasText(username
);
137 Assert
.hasText(newPassword
);
140 User user
= dao
.findUserByUsername(username
);
142 throw new UsernameNotFoundException(username
);
145 Object salt
= this.saltSource
.getSalt(user
);
147 String password
= passwordEncoder
.encodePassword(newPassword
, salt
);
148 ((User
)user
).setPassword(password
);
150 dao
.update((User
)user
);
151 userCache
.removeUserFromCache(user
.getUsername());
152 } catch(NonUniqueResultException nure
) {
153 throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username
+ "'", 1);
157 @Transactional(readOnly
=false)
158 public void createUser(UserDetails user
) {
159 Assert
.isInstanceOf(User
.class, user
);
161 String rawPassword
= user
.getPassword();
162 Object salt
= this.saltSource
.getSalt(user
);
164 String password
= passwordEncoder
.encodePassword(rawPassword
, salt
);
165 ((User
)user
).setPassword(password
);
167 dao
.save((User
)user
);
170 @Transactional(readOnly
=false)
171 public void deleteUser(String username
) {
172 Assert
.hasLength(username
);
174 User user
= dao
.findUserByUsername(username
);
176 dao
.delete((User
)user
);
179 userCache
.removeUserFromCache(username
);
182 @Transactional(readOnly
=false)
183 public void updateUser(UserDetails user
) {
184 Assert
.isInstanceOf(User
.class, user
);
186 dao
.update((User
)user
);
187 userCache
.removeUserFromCache(user
.getUsername());
190 public boolean userExists(String username
) {
191 Assert
.hasText(username
);
193 User user
= dao
.findUserByUsername(username
);
198 * DO NOT CALL THIS METHOD IN LONG RUNNING SESSIONS OR CONVERSATIONS
199 * A THROWN UsernameNotFoundException WILL RENDER THE CONVERSATION UNUSABLE
201 public UserDetails
loadUserByUsername(String username
)
202 throws UsernameNotFoundException
, DataAccessException
{
203 Assert
.hasText(username
);
205 User user
= dao
.findUserByUsername(username
);
207 throw new UsernameNotFoundException(username
);
210 } catch(NonUniqueResultException nure
) {
211 throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username
+ "'", 1);
215 @Transactional(readOnly
=false)
216 public void addGroupAuthority(String groupName
, GrantedAuthority authority
) {
217 Assert
.hasText(groupName
);
218 Assert
.notNull(authority
);
220 Group group
= groupDao
.findGroupByName(groupName
);
221 if(group
.getGrantedAuthorities().add(authority
)) {
222 groupDao
.update(group
);
226 @Transactional(readOnly
=false)
227 public void addUserToGroup(String username
, String groupName
) {
228 Assert
.hasText(username
);
229 Assert
.hasText(groupName
);
231 Group group
= groupDao
.findGroupByName(groupName
);
232 User user
= dao
.findUserByUsername(username
);
234 if(group
.addMember(user
)) {
235 groupDao
.update(group
);
236 userCache
.removeUserFromCache(user
.getUsername());
240 @Transactional(readOnly
=false)
241 public void createGroup(String groupName
, List
<GrantedAuthority
> authorities
) {
242 Assert
.hasText(groupName
);
243 Assert
.notNull(authorities
);
245 Group group
= new Group();
246 group
.setName(groupName
);
248 for(GrantedAuthority authority
: authorities
) {
249 group
.getGrantedAuthorities().add(authority
);
252 groupDao
.save(group
);
255 @Transactional(readOnly
=false)
256 public void deleteGroup(String groupName
) {
257 Assert
.hasText(groupName
);
259 Group group
= groupDao
.findGroupByName(groupName
);
260 groupDao
.delete(group
);
263 public List
<String
> findAllGroups() {
264 return groupDao
.listNames(null,null);
267 public List
<GrantedAuthority
> findGroupAuthorities(String groupName
) {
268 Assert
.hasText(groupName
);
269 Group group
= groupDao
.findGroupByName(groupName
);
271 return new ArrayList
<GrantedAuthority
>(group
.getGrantedAuthorities());
274 public List
<String
> findUsersInGroup(String groupName
) {
275 Assert
.hasText(groupName
);
276 Group group
= groupDao
.findGroupByName(groupName
);
278 List
<String
> users
= groupDao
.listMembers(group
, null, null);
283 @Transactional(readOnly
=false)
284 public void removeGroupAuthority(String groupName
, GrantedAuthority authority
) {
285 Assert
.hasText(groupName
);
286 Assert
.notNull(authority
);
288 Group group
= groupDao
.findGroupByName(groupName
);
290 if(group
.getGrantedAuthorities().remove(authority
)) {
291 groupDao
.update(group
);
295 @Transactional(readOnly
=false)
296 public void removeUserFromGroup(String username
, String groupName
) {
297 Assert
.hasText(username
);
298 Assert
.hasText(groupName
);
300 Group group
= groupDao
.findGroupByName(groupName
);
301 User user
= dao
.findUserByUsername(username
);
303 if(group
.removeMember(user
)) {
304 groupDao
.update(group
);
305 userCache
.removeUserFromCache(user
.getUsername());
309 @Transactional(readOnly
=false)
310 public void renameGroup(String oldName
, String newName
) {
311 Assert
.hasText(oldName
);
312 Assert
.hasText(newName
);
314 Group group
= groupDao
.findGroupByName(oldName
);
316 group
.setName(newName
);
317 groupDao
.update(group
);
320 @Transactional(readOnly
=false)
321 public UUID
save(User user
) {
322 if(user
.getId() == 0 || dao
.load(user
.getUuid()) == null){
327 return user
.getUuid();
331 public UUID
update(User user
) {
333 return user
.getUuid();
336 @Transactional(readOnly
=false)
337 public UUID
saveGrantedAuthority(GrantedAuthority grantedAuthority
) {
338 return grantedAuthorityDao
.save((GrantedAuthorityImpl
)grantedAuthority
);
341 @Transactional(readOnly
=false)
342 public UUID
saveGroup(Group group
) {
343 return groupDao
.save(group
);