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