fixed a bug that occurred when executing operations on taxon nodes on root level
[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.List;
13 import java.util.UUID;
14
15 import org.hibernate.NonUniqueResultException;
16 import org.springframework.beans.factory.annotation.Autowired;
17 import org.springframework.dao.DataAccessException;
18 import org.springframework.dao.IncorrectResultSizeDataAccessException;
19 import org.springframework.security.AccessDeniedException;
20 import org.springframework.security.Authentication;
21 import org.springframework.security.AuthenticationManager;
22 import org.springframework.security.GrantedAuthority;
23 import org.springframework.security.context.SecurityContextHolder;
24 import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
25 import org.springframework.security.providers.dao.SaltSource;
26 import org.springframework.security.providers.dao.UserCache;
27 import org.springframework.security.providers.dao.cache.NullUserCache;
28 import org.springframework.security.providers.dao.salt.ReflectionSaltSource;
29 import org.springframework.security.providers.encoding.Md5PasswordEncoder;
30 import org.springframework.security.providers.encoding.PasswordEncoder;
31 import org.springframework.security.userdetails.UserDetails;
32 import org.springframework.security.userdetails.UsernameNotFoundException;
33 import org.springframework.stereotype.Service;
34 import org.springframework.transaction.annotation.Transactional;
35 import org.springframework.util.Assert;
36
37 import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl;
38 import eu.etaxonomy.cdm.model.common.Group;
39 import eu.etaxonomy.cdm.model.common.User;
40 import eu.etaxonomy.cdm.persistence.dao.common.IGrantedAuthorityDao;
41 import eu.etaxonomy.cdm.persistence.dao.common.IGroupDao;
42 import eu.etaxonomy.cdm.persistence.dao.common.IUserDao;
43
44 @Service
45 @Transactional(readOnly=true)
46 public class UserService extends ServiceBase<User,IUserDao> implements IUserService {
47
48 protected IGroupDao groupDao;
49
50 protected IGrantedAuthorityDao grantedAuthorityDao;
51
52 private SaltSource saltSource = new ReflectionSaltSource();
53
54 private PasswordEncoder passwordEncoder = new Md5PasswordEncoder();
55
56 private AuthenticationManager authenticationManager;
57
58 private UserCache userCache = new NullUserCache();
59
60 @Autowired(required = false)
61 public void setUserCache(UserCache userCache) {
62 Assert.notNull(userCache, "userCache cannot be null");
63 this.userCache = userCache;
64 }
65
66 @Autowired(required = false)
67 public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
68
69 this.passwordEncoder = passwordEncoder;
70 }
71
72 @Autowired(required = false)
73 public void setSaltSource(SaltSource saltSource) {
74 this.saltSource = saltSource;
75 }
76
77 @Autowired(required= false)
78 public void setAuthenticationManager(AuthenticationManager authenticationManager) {
79 this.authenticationManager = authenticationManager;
80 }
81
82 @Override
83 @Autowired
84 protected void setDao(IUserDao dao) {
85 this.dao = dao;
86 }
87
88 @Autowired
89 public void setGroupDao(IGroupDao groupDao) {
90 this.groupDao = groupDao;
91 }
92
93 @Autowired
94 public void setGrantedAuthorityDao(IGrantedAuthorityDao grantedAuthorityDao) {
95 this.grantedAuthorityDao = grantedAuthorityDao;
96 }
97
98 @Transactional(readOnly=false)
99 protected Authentication createNewAuthentication(Authentication currentAuth, String newPassword) {
100 UserDetails user = loadUserByUsername(currentAuth.getName());
101
102 UsernamePasswordAuthenticationToken newAuthentication = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
103 newAuthentication.setDetails(currentAuth.getDetails());
104
105 return newAuthentication;
106 }
107
108 @Transactional(readOnly=false)
109 public void changePassword(String oldPassword, String newPassword) {
110 Assert.hasText(oldPassword);
111 Assert.hasText(newPassword);
112 Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
113 if(authentication != null && authentication.getPrincipal() != null && authentication.getPrincipal() instanceof User) {
114 User user = (User)authentication.getPrincipal();
115
116 authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), oldPassword));
117
118 Object salt = this.saltSource.getSalt(user);
119
120 String password = passwordEncoder.encodePassword(newPassword, salt);
121 ((User)user).setPassword(password);
122
123 dao.update((User)user);
124 SecurityContextHolder.getContext().setAuthentication(createNewAuthentication(authentication, newPassword));
125 userCache.removeUserFromCache(user.getUsername());
126 } else {
127 throw new AccessDeniedException("Can't change password as no Authentication object found in context for current user.");
128 }
129 }
130
131 @Transactional(readOnly=false)
132 public void changePasswordForUser(String username, String newPassword) {
133 Assert.hasText(username);
134 Assert.hasText(newPassword);
135
136 try {
137 User user = dao.findUserByUsername(username);
138 if(user == null) {
139 throw new UsernameNotFoundException(username);
140 }
141
142 Object salt = this.saltSource.getSalt(user);
143
144 String password = passwordEncoder.encodePassword(newPassword, salt);
145 ((User)user).setPassword(password);
146
147 dao.update((User)user);
148 userCache.removeUserFromCache(user.getUsername());
149 } catch(NonUniqueResultException nure) {
150 throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", 1);
151 }
152 }
153
154 @Transactional(readOnly=false)
155 public void createUser(UserDetails user) {
156 Assert.isInstanceOf(User.class, user);
157
158 String rawPassword = user.getPassword();
159 Object salt = this.saltSource.getSalt(user);
160
161 String password = passwordEncoder.encodePassword(rawPassword, salt);
162 ((User)user).setPassword(password);
163
164 dao.save((User)user);
165 }
166
167 @Transactional(readOnly=false)
168 public void deleteUser(String username) {
169 Assert.hasLength(username);
170
171 User user = dao.findUserByUsername(username);
172 if(user != null) {
173 dao.delete((User)user);
174 }
175
176 userCache.removeUserFromCache(username);
177 }
178
179 @Transactional(readOnly=false)
180 public void updateUser(UserDetails user) {
181 Assert.isInstanceOf(User.class, user);
182
183 dao.update((User)user);
184 userCache.removeUserFromCache(user.getUsername());
185 }
186
187 public boolean userExists(String username) {
188 Assert.hasText(username);
189
190 User user = dao.findUserByUsername(username);
191 return user != null;
192 }
193
194 public UserDetails loadUserByUsername(String username)
195 throws UsernameNotFoundException, DataAccessException {
196 Assert.hasText(username);
197 try {
198 User user = dao.findUserByUsername(username);
199 if(user == null) {
200 throw new UsernameNotFoundException(username);
201 }
202 return user;
203 } catch(NonUniqueResultException nure) {
204 throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", 1);
205 }
206 }
207
208 @Transactional(readOnly=false)
209 public void addGroupAuthority(String groupName, GrantedAuthority authority) {
210 Assert.hasText(groupName);
211 Assert.notNull(authority);
212
213 Group group = groupDao.findGroupByName(groupName);
214 if(group.getGrantedAuthorities().add(authority)) {
215 groupDao.update(group);
216 }
217 }
218
219 @Transactional(readOnly=false)
220 public void addUserToGroup(String username, String groupName) {
221 Assert.hasText(username);
222 Assert.hasText(groupName);
223
224 Group group = groupDao.findGroupByName(groupName);
225 User user = dao.findUserByUsername(username);
226
227 if(group.addMember(user)) {
228 groupDao.update(group);
229 userCache.removeUserFromCache(user.getUsername());
230 }
231 }
232
233 @Transactional(readOnly=false)
234 public void createGroup(String groupName, GrantedAuthority[] authorities) {
235 Assert.hasText(groupName);
236 Assert.notNull(authorities);
237
238 Group group = new Group();
239 group.setName(groupName);
240
241 for(GrantedAuthority authority : authorities) {
242 group.getGrantedAuthorities().add(authority);
243 }
244
245 groupDao.save(group);
246 }
247
248 @Transactional(readOnly=false)
249 public void deleteGroup(String groupName) {
250 Assert.hasText(groupName);
251
252 Group group = groupDao.findGroupByName(groupName);
253 groupDao.delete(group);
254 }
255
256 public String[] findAllGroups() {
257 List<String> names = groupDao.listNames(null,null);
258 return names.toArray(new String[names.size()]);
259 }
260
261 public GrantedAuthority[] findGroupAuthorities(String groupName) {
262 Assert.hasText(groupName);
263 Group group = groupDao.findGroupByName(groupName);
264
265 return group.getGrantedAuthorities().toArray(new GrantedAuthority[group.getGrantedAuthorities().size()]);
266 }
267
268 public String[] findUsersInGroup(String groupName) {
269 Assert.hasText(groupName);
270 Group group = groupDao.findGroupByName(groupName);
271
272 List<String> users = groupDao.listMembers(group, null, null);
273
274 return users.toArray(new String[users.size()]);
275 }
276
277 @Transactional(readOnly=false)
278 public void removeGroupAuthority(String groupName, GrantedAuthority authority) {
279 Assert.hasText(groupName);
280 Assert.notNull(authority);
281
282 Group group = groupDao.findGroupByName(groupName);
283
284 if(group.getGrantedAuthorities().remove(authority)) {
285 groupDao.update(group);
286 }
287 }
288
289 @Transactional(readOnly=false)
290 public void removeUserFromGroup(String username, String groupName) {
291 Assert.hasText(username);
292 Assert.hasText(groupName);
293
294 Group group = groupDao.findGroupByName(groupName);
295 User user = dao.findUserByUsername(username);
296
297 if(group.removeMember(user)) {
298 groupDao.update(group);
299 userCache.removeUserFromCache(user.getUsername());
300 }
301 }
302
303 @Transactional(readOnly=false)
304 public void renameGroup(String oldName, String newName) {
305 Assert.hasText(oldName);
306 Assert.hasText(newName);
307
308 Group group = groupDao.findGroupByName(oldName);
309
310 group.setName(newName);
311 groupDao.update(group);
312 }
313
314 @Transactional(readOnly=false)
315 public UUID save(User user) {
316 if(user.getId() == 0 || dao.load(user.getUuid()) == null){
317 createUser(user);
318 }
319 updateUser(user);
320
321 return user.getUuid();
322 // return dao.save(user);
323 }
324
325 @Override
326 public UUID update(User user) {
327 updateUser(user);
328 return user.getUuid();
329 }
330
331 @Transactional(readOnly=false)
332 public UUID saveGrantedAuthority(GrantedAuthority grantedAuthority) {
333 return grantedAuthorityDao.save((GrantedAuthorityImpl)grantedAuthority);
334 }
335
336 @Transactional(readOnly=false)
337 public UUID saveGroup(Group group) {
338 return groupDao.save(group);
339 }
340 }