Project

General

Profile

Download (12.3 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.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

    
22
import org.springframework.security.access.AccessDeniedException;
23
import org.springframework.security.access.prepost.PreAuthorize;
24
import org.springframework.security.authentication.AuthenticationManager;
25
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
26
import org.springframework.security.authentication.dao.ReflectionSaltSource;
27
import org.springframework.security.authentication.dao.SaltSource;
28
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
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.Propagation;
39
import org.springframework.transaction.annotation.Transactional;
40
import org.springframework.util.Assert;
41

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

    
51
/**
52
 * Note: All group related functionality has been refactored into a GroupService. The will be removed in a future version.
53
 */
54
@Service
55
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
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
	private UserCache userCache = new NullUserCache();
69
	
70
	@Autowired(required = false)
71
	public void setUserCache(UserCache userCache) {
72
		Assert.notNull(userCache, "userCache cannot be null");
73
		this.userCache = userCache;
74
	}
75
	
76
	@Autowired(required = false)
77
	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
78
		
79
		this.passwordEncoder = passwordEncoder;
80
	}
81

    
82
	@Autowired(required = false)
83
	public void setSaltSource(SaltSource saltSource) {
84
		this.saltSource = saltSource;
85
	}
86
	
87
	@Autowired(required= false)
88
	public void setAuthenticationManager(AuthenticationManager authenticationManager) {
89
		this.authenticationManager = authenticationManager;
90
	}
91
	
92
	@Override
93
	@Autowired
94
	protected void setDao(IUserDao dao) {
95
		this.dao = dao;
96
	}
97
	
98
	@Autowired
99
	public void setGroupDao(IGroupDao groupDao) {
100
		this.groupDao = groupDao;
101
	}
102
	
103
	@Autowired
104
	public void setGrantedAuthorityDao(IGrantedAuthorityDao grantedAuthorityDao) {
105
		this.grantedAuthorityDao = grantedAuthorityDao;
106
	}
107
	
108
	@Transactional(readOnly=false)
109
	protected Authentication createNewAuthentication(Authentication currentAuth, String newPassword) {
110
		UserDetails user = loadUserByUsername(currentAuth.getName());
111
			
112
		UsernamePasswordAuthenticationToken newAuthentication = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
113
		newAuthentication.setDetails(currentAuth.getDetails());
114
			
115
		return newAuthentication;
116
	}
117
	
118
	@Transactional(readOnly=false)
119
	public void changePassword(String oldPassword, String newPassword) {
120
		Assert.hasText(oldPassword);
121
		Assert.hasText(newPassword);
122
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
123
		if(authentication != null && authentication.getPrincipal() != null && authentication.getPrincipal() instanceof User) {
124
			User user = (User)authentication.getPrincipal();
125
			
126
			authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), oldPassword));
127
			
128
			Object salt = this.saltSource.getSalt(user);
129
			
130
			String password = passwordEncoder.encodePassword(newPassword, salt);
131
			((User)user).setPassword(password);
132
			
133
			dao.update((User)user);
134
			SecurityContextHolder.getContext().setAuthentication(createNewAuthentication(authentication, newPassword));
135
			userCache.removeUserFromCache(user.getUsername());
136
		} else {
137
			throw new AccessDeniedException("Can't change password as no Authentication object found in context for current user.");
138
		}		
139
	}
140
	
141
	@Transactional(readOnly=false)
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
	@Transactional(readOnly=false)
165
	@PreAuthorize("hasPermission(#user, 'CREATE')")
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
	@Transactional(readOnly=false)
179
	@PreAuthorize("hasPermission(#username, 'DELETE')")
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
	@Transactional(readOnly=false)
192
	@PreAuthorize("hasPermission(#user, 'EDIT')")
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
	public boolean userExists(String username) {
201
		Assert.hasText(username);
202
		
203
		User user = dao.findUserByUsername(username);
204
		return user != null;
205
	}
206

    
207
	/**
208
	 * DO NOT CALL THIS METHOD IN LONG RUNNING SESSIONS OR CONVERSATIONS
209
	 * A THROWN UsernameNotFoundException WILL RENDER THE CONVERSATION UNUSABLE
210
	 */
211
	public UserDetails loadUserByUsername(String username)
212
			throws UsernameNotFoundException, DataAccessException {
213
		Assert.hasText(username);
214
		try {
215
		    User user = dao.findUserByUsername(username);
216
		    if(user == null) {
217
				throw new UsernameNotFoundException(username);
218
			}
219
		    return user;
220
		} catch(NonUniqueResultException nure) {
221
			throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", 1);
222
		}
223
	}
224

    
225
	@Deprecated // use GroupService instead
226
	@Transactional(readOnly=false)
227
	public void addGroupAuthority(String groupName, GrantedAuthority authority) {
228
		Assert.hasText(groupName);
229
		Assert.notNull(authority);
230
		
231
		Group group = groupDao.findGroupByName(groupName);
232
		if(group.getGrantedAuthorities().add(authority)) {
233
			groupDao.update(group);
234
		}
235
	}
236

    
237
	@Deprecated // use GroupService instead
238
	@Transactional(readOnly=false)
239
	public void addUserToGroup(String username, String groupName) {
240
		Assert.hasText(username);
241
		Assert.hasText(groupName);
242
		
243
		Group group = groupDao.findGroupByName(groupName);
244
		User user = dao.findUserByUsername(username);
245
		
246
		if(group.addMember(user)) {
247
			groupDao.update(group);
248
			userCache.removeUserFromCache(user.getUsername());
249
		}		
250
	}
251

    
252
	@Deprecated // use GroupService instead
253
	@Transactional(readOnly=false)
254
	public void createGroup(String groupName, List<GrantedAuthority> authorities) {
255
		Assert.hasText(groupName);
256
		Assert.notNull(authorities);
257
		
258
		Group group = Group.NewInstance(groupName);
259
		
260
		for(GrantedAuthority authority : authorities) {
261
			group.getGrantedAuthorities().add(authority);
262
		}
263
		
264
		groupDao.save(group);
265
	}
266

    
267
	@Deprecated // use GroupService instead
268
	@Transactional(readOnly=false)
269
	public void deleteGroup(String groupName) {
270
		Assert.hasText(groupName);
271
		
272
		Group group = groupDao.findGroupByName(groupName);
273
		groupDao.delete(group);
274
	}
275

    
276
	@Deprecated // use GroupService instead
277
	public List<String> findAllGroups() {
278
		return groupDao.listNames(null,null);
279
	}
280

    
281
	@Deprecated // use GroupService instead
282
	public List<GrantedAuthority> findGroupAuthorities(String groupName) {
283
		Assert.hasText(groupName);
284
		Group group = groupDao.findGroupByName(groupName);
285
		
286
		return new ArrayList<GrantedAuthority>(group.getGrantedAuthorities());
287
	}
288

    
289
	@Deprecated // use GroupService instead
290
	public List<String> findUsersInGroup(String groupName) {
291
		Assert.hasText(groupName);
292
		Group group = groupDao.findGroupByName(groupName);
293
		
294
		List<String> users = groupDao.listMembers(group, null, null);
295
		
296
		return users;
297
	}
298

    
299
	@Deprecated // use GroupService instead
300
	@Transactional(readOnly=false)
301
	public void removeGroupAuthority(String groupName,	GrantedAuthority authority) {
302
		Assert.hasText(groupName);
303
		Assert.notNull(authority);
304
		
305
		Group group = groupDao.findGroupByName(groupName);
306
		
307
		if(group.getGrantedAuthorities().remove(authority)) {
308
			groupDao.update(group);
309
		}
310
	}
311

    
312
	@Deprecated // use GroupService instead
313
	@Transactional(readOnly=false)
314
	public void removeUserFromGroup(String username, String groupName) {
315
		Assert.hasText(username);
316
		Assert.hasText(groupName);
317
		
318
		Group group = groupDao.findGroupByName(groupName);
319
		User user = dao.findUserByUsername(username);
320
		
321
		if(group.removeMember(user)) {
322
			groupDao.update(group);
323
			userCache.removeUserFromCache(user.getUsername());
324
		}
325
	}
326

    
327
	@Transactional(readOnly=false)
328
	public void renameGroup(String oldName, String newName) {
329
		Assert.hasText(oldName);
330
		Assert.hasText(newName);
331
		
332
		Group group = groupDao.findGroupByName(oldName);
333
		
334
		group.setName(newName);
335
		groupDao.update(group);
336
	}
337
	
338
	@Transactional(readOnly=false)
339
	public UUID save(User user) {
340
		if(user.getId() == 0 || dao.load(user.getUuid()) == null){
341
			createUser(user);
342
		}else{
343
			updateUser(user);
344
		}
345
		return user.getUuid(); 
346
	}
347

    
348
	@Override
349
	public UUID update(User user) {
350
		updateUser(user);
351
		return user.getUuid(); 
352
	}
353

    
354
	@Transactional(readOnly=false)
355
	public UUID saveGrantedAuthority(GrantedAuthority grantedAuthority) {
356
		return grantedAuthorityDao.save((GrantedAuthorityImpl)grantedAuthority);
357
	}
358
	
359
	@Transactional(readOnly=false)
360
	public UUID saveGroup(Group group) {
361
		return groupDao.save(group);
362
	}
363
	
364
	@Transactional(readOnly = true)
365
	public List<User> listByUsername(String queryString,MatchMode matchmode, List<Criterion> criteria, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
366
		 Integer numberOfResults = dao.countByUsername(queryString, matchmode, criteria);
367
			
368
		 List<User> results = new ArrayList<User>();
369
		 if(numberOfResults > 0) { 
370
				results = dao.findByUsername(queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths); 
371
		 }
372
		 return results;
373
	}
374
	
375
} 
(76-76/79)