implementing GrantedAuthorityService for #2990 (implement missing parts of Groups...
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / UserService.java
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.List;
14 import java.util.UUID;
15
16 import org.hibernate.NonUniqueResultException;
17 import org.hibernate.criterion.Criterion;
18 import org.springframework.beans.factory.annotation.Autowired;
19 import org.springframework.dao.DataAccessException;
20 import org.springframework.dao.IncorrectResultSizeDataAccessException;
21 import org.springframework.security.access.AccessDeniedException;
22 import org.springframework.security.access.prepost.PreAuthorize;
23 import org.springframework.security.authentication.AuthenticationManager;
24 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
25 import org.springframework.security.authentication.dao.SaltSource;
26 import org.springframework.security.authentication.encoding.PasswordEncoder;
27 import org.springframework.security.core.Authentication;
28 import org.springframework.security.core.GrantedAuthority;
29 import org.springframework.security.core.context.SecurityContextHolder;
30 import org.springframework.security.core.userdetails.UserCache;
31 import org.springframework.security.core.userdetails.UserDetails;
32 import org.springframework.security.core.userdetails.UsernameNotFoundException;
33 import org.springframework.security.core.userdetails.cache.NullUserCache;
34 import org.springframework.stereotype.Service;
35 import org.springframework.transaction.annotation.Propagation;
36 import org.springframework.transaction.annotation.Transactional;
37 import org.springframework.util.Assert;
38
39 import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl;
40 import eu.etaxonomy.cdm.model.common.Group;
41 import eu.etaxonomy.cdm.model.common.User;
42 import eu.etaxonomy.cdm.persistence.dao.common.IGrantedAuthorityDao;
43 import eu.etaxonomy.cdm.persistence.dao.common.IGroupDao;
44 import eu.etaxonomy.cdm.persistence.dao.common.IUserDao;
45 import eu.etaxonomy.cdm.persistence.query.MatchMode;
46 import eu.etaxonomy.cdm.persistence.query.OrderHint;
47
48 /**
49 * Note: All group related functionality has been refactored into a GroupService. The will be removed in a future version.
50 */
51 @Service
52 @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
53 public class UserService extends ServiceBase<User,IUserDao> implements IUserService {
54
55 protected IGroupDao groupDao;
56
57 protected IGrantedAuthorityDao grantedAuthorityDao;
58
59 private SaltSource saltSource; // = new ReflectionSaltSource();
60
61 private PasswordEncoder passwordEncoder; // = new Md5PasswordEncoder();
62
63 private AuthenticationManager authenticationManager;
64
65 private UserCache userCache = new NullUserCache();
66
67 @Autowired(required = false)
68 public void setUserCache(UserCache userCache) {
69 Assert.notNull(userCache, "userCache cannot be null");
70 this.userCache = userCache;
71 }
72
73 @Autowired(required = false)
74 public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
75
76 this.passwordEncoder = passwordEncoder;
77 }
78
79 @Autowired(required = false)
80 public void setSaltSource(SaltSource saltSource) {
81 this.saltSource = saltSource;
82 }
83
84 @Autowired(required= false)
85 public void setAuthenticationManager(AuthenticationManager authenticationManager) {
86 this.authenticationManager = authenticationManager;
87 }
88
89 @Override
90 @Autowired
91 protected void setDao(IUserDao dao) {
92 this.dao = dao;
93 }
94
95 @Autowired
96 public void setGroupDao(IGroupDao groupDao) {
97 this.groupDao = groupDao;
98 }
99
100 @Autowired
101 public void setGrantedAuthorityDao(IGrantedAuthorityDao grantedAuthorityDao) {
102 this.grantedAuthorityDao = grantedAuthorityDao;
103 }
104
105 @Transactional(readOnly=false)
106 protected Authentication createNewAuthentication(Authentication currentAuth, String newPassword) {
107 UserDetails user = loadUserByUsername(currentAuth.getName());
108
109 UsernamePasswordAuthenticationToken newAuthentication = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
110 newAuthentication.setDetails(currentAuth.getDetails());
111
112 return newAuthentication;
113 }
114
115 @Override
116 @Transactional(readOnly=false)
117 public void changePassword(String oldPassword, String newPassword) {
118 Assert.hasText(oldPassword);
119 Assert.hasText(newPassword);
120 Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
121 if(authentication != null && authentication.getPrincipal() != null && authentication.getPrincipal() instanceof User) {
122 User user = (User)authentication.getPrincipal();
123
124 authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), oldPassword));
125
126 Object salt = this.saltSource.getSalt(user);
127
128 String password = passwordEncoder.encodePassword(newPassword, salt);
129 ((User)user).setPassword(password);
130
131 dao.update((User)user);
132 SecurityContextHolder.getContext().setAuthentication(createNewAuthentication(authentication, newPassword));
133 userCache.removeUserFromCache(user.getUsername());
134 } else {
135 throw new AccessDeniedException("Can't change password as no Authentication object found in context for current user.");
136 }
137 }
138
139 @Override
140 @Transactional(readOnly=false)
141 @PreAuthorize("#username == authentication.name or hasRole('ROLE_ADMIN')")
142 public void changePasswordForUser(String username, String newPassword) {
143 Assert.hasText(username);
144 Assert.hasText(newPassword);
145
146 try {
147 User user = dao.findUserByUsername(username);
148 if(user == null) {
149 throw new UsernameNotFoundException(username);
150 }
151
152 Object salt = this.saltSource.getSalt(user);
153
154 String password = passwordEncoder.encodePassword(newPassword, salt);
155 ((User)user).setPassword(password);
156
157 dao.update((User)user);
158 userCache.removeUserFromCache(user.getUsername());
159 } catch(NonUniqueResultException nure) {
160 throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", 1);
161 }
162 }
163
164 @Override
165 @Transactional(readOnly=false)
166 public void createUser(UserDetails user) {
167 Assert.isInstanceOf(User.class, user);
168
169 String rawPassword = user.getPassword();
170 Object salt = this.saltSource.getSalt(user);
171
172 String password = passwordEncoder.encodePassword(rawPassword, salt);
173 ((User)user).setPassword(password);
174
175 dao.save((User)user);
176 }
177
178 @Override
179 @Transactional(readOnly=false)
180 public void deleteUser(String username) {
181 Assert.hasLength(username);
182
183 User user = dao.findUserByUsername(username);
184 if(user != null) {
185 dao.delete((User)user);
186 }
187
188 userCache.removeUserFromCache(username);
189 }
190
191 @Override
192 @Transactional(readOnly=false)
193 public void updateUser(UserDetails user) {
194 Assert.isInstanceOf(User.class, user);
195
196 dao.update((User)user);
197 userCache.removeUserFromCache(user.getUsername());
198 }
199
200 @Override
201 public boolean userExists(String username) {
202 Assert.hasText(username);
203
204 User user = dao.findUserByUsername(username);
205 return user != null;
206 }
207
208 /**
209 * DO NOT CALL THIS METHOD IN LONG RUNNING SESSIONS OR CONVERSATIONS
210 * A THROWN UsernameNotFoundException WILL RENDER THE CONVERSATION UNUSABLE
211 */
212 public UserDetails loadUserByUsername(String username)
213 throws UsernameNotFoundException, DataAccessException {
214 Assert.hasText(username);
215 try {
216 User user = dao.findUserByUsername(username);
217 if(user == null) {
218 throw new UsernameNotFoundException(username);
219 }
220 return user;
221 } catch(NonUniqueResultException nure) {
222 throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", 1);
223 }
224 }
225
226 @Deprecated // use GroupService instead
227 @Transactional(readOnly=false)
228 public void addGroupAuthority(String groupName, GrantedAuthority authority) {
229 Assert.hasText(groupName);
230 Assert.notNull(authority);
231
232 Group group = groupDao.findGroupByName(groupName);
233 if(group.getGrantedAuthorities().add(authority)) {
234 groupDao.update(group);
235 }
236 }
237
238 @Deprecated // use GroupService instead
239 @Transactional(readOnly=false)
240 public void addUserToGroup(String username, String groupName) {
241 Assert.hasText(username);
242 Assert.hasText(groupName);
243
244 Group group = groupDao.findGroupByName(groupName);
245 User user = dao.findUserByUsername(username);
246
247 if(group.addMember(user)) {
248 groupDao.update(group);
249 userCache.removeUserFromCache(user.getUsername());
250 }
251 }
252
253 @Deprecated // use GroupService instead
254 @Transactional(readOnly=false)
255 public void createGroup(String groupName, List<GrantedAuthority> authorities) {
256 Assert.hasText(groupName);
257 Assert.notNull(authorities);
258
259 Group group = Group.NewInstance(groupName);
260
261 for(GrantedAuthority authority : authorities) {
262 group.getGrantedAuthorities().add(authority);
263 }
264
265 groupDao.save(group);
266 }
267
268 @Deprecated // use GroupService instead
269 @Transactional(readOnly=false)
270 public void deleteGroup(String groupName) {
271 Assert.hasText(groupName);
272
273 Group group = groupDao.findGroupByName(groupName);
274 groupDao.delete(group);
275 }
276
277 @Deprecated // use GroupService instead
278 public List<String> findAllGroups() {
279 return groupDao.listNames(null,null);
280 }
281
282 @Deprecated // use GroupService instead
283 public List<GrantedAuthority> findGroupAuthorities(String groupName) {
284 Assert.hasText(groupName);
285 Group group = groupDao.findGroupByName(groupName);
286
287 return new ArrayList<GrantedAuthority>(group.getGrantedAuthorities());
288 }
289
290 @Deprecated // use GroupService instead
291 public List<String> findUsersInGroup(String groupName) {
292 Assert.hasText(groupName);
293 Group group = groupDao.findGroupByName(groupName);
294
295 List<String> users = groupDao.listMembers(group, null, null);
296
297 return users;
298 }
299
300 @Deprecated // use GroupService instead
301 @Transactional(readOnly=false)
302 public void removeGroupAuthority(String groupName, GrantedAuthority authority) {
303 Assert.hasText(groupName);
304 Assert.notNull(authority);
305
306 Group group = groupDao.findGroupByName(groupName);
307
308 if(group.getGrantedAuthorities().remove(authority)) {
309 groupDao.update(group);
310 }
311 }
312
313 @Deprecated // use GroupService instead
314 @Transactional(readOnly=false)
315 public void removeUserFromGroup(String username, String groupName) {
316 Assert.hasText(username);
317 Assert.hasText(groupName);
318
319 Group group = groupDao.findGroupByName(groupName);
320 User user = dao.findUserByUsername(username);
321
322 if(group.removeMember(user)) {
323 groupDao.update(group);
324 userCache.removeUserFromCache(user.getUsername());
325 }
326 }
327
328 @Deprecated // use GroupService instead
329 @Transactional(readOnly=false)
330 public void renameGroup(String oldName, String newName) {
331 Assert.hasText(oldName);
332 Assert.hasText(newName);
333
334 Group group = groupDao.findGroupByName(oldName);
335
336 group.setName(newName);
337 groupDao.update(group);
338 }
339
340 @Transactional(readOnly=false)
341 public UUID save(User user) {
342 if(user.getId() == 0 || dao.load(user.getUuid()) == null){
343 createUser(user);
344 }else{
345 updateUser(user);
346 }
347 return user.getUuid();
348 }
349
350 @Override
351 public UUID update(User user) {
352 updateUser(user);
353 return user.getUuid();
354 }
355
356 @Override
357 @Transactional(readOnly=false)
358 public UUID saveGrantedAuthority(GrantedAuthority grantedAuthority) {
359 return grantedAuthorityDao.save((GrantedAuthorityImpl)grantedAuthority);
360 }
361
362 @Deprecated // use GroupService instead
363 @Transactional(readOnly=false)
364 public UUID saveGroup(Group group) {
365 return groupDao.save(group);
366 }
367
368 @Override
369 @Transactional(readOnly = true)
370 public List<User> listByUsername(String queryString,MatchMode matchmode, List<Criterion> criteria, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
371 Integer numberOfResults = dao.countByUsername(queryString, matchmode, criteria);
372
373 List<User> results = new ArrayList<User>();
374 if(numberOfResults > 0) {
375 results = dao.findByUsername(queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths);
376 }
377 return results;
378 }
379
380
381
382
383 }