Project

General

Profile

Download (13.1 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 * Copyright (C) 2007 EDIT
3
 * European Distributed Institute of Taxonomy
4
 * http://www.e-taxonomy.eu
5
 *
6
 * The contents of this file are subject to the Mozilla Public License Version 1.1
7
 * See LICENSE.TXT at the top of this package for the full license terms.
8
 */
9
package eu.etaxonomy.cdm.api.service;
10

    
11
import java.util.ArrayList;
12
import java.util.Collection;
13
import java.util.HashMap;
14
import java.util.List;
15
import java.util.Map;
16
import java.util.UUID;
17

    
18
import org.hibernate.NonUniqueResultException;
19
import org.hibernate.criterion.Criterion;
20
import org.springframework.beans.factory.annotation.Autowired;
21
import org.springframework.dao.DataAccessException;
22
import org.springframework.dao.IncorrectResultSizeDataAccessException;
23
import org.springframework.security.access.AccessDeniedException;
24
import org.springframework.security.access.prepost.PreAuthorize;
25
import org.springframework.security.authentication.AuthenticationManager;
26
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
27
import org.springframework.security.authentication.dao.SaltSource;
28
import org.springframework.security.authentication.encoding.PasswordEncoder;
29
import org.springframework.security.core.Authentication;
30
import org.springframework.security.core.GrantedAuthority;
31
import org.springframework.security.core.context.SecurityContextHolder;
32
import org.springframework.security.core.userdetails.UserCache;
33
import org.springframework.security.core.userdetails.UserDetails;
34
import org.springframework.security.core.userdetails.UsernameNotFoundException;
35
import org.springframework.security.core.userdetails.cache.NullUserCache;
36
import org.springframework.stereotype.Service;
37
import org.springframework.transaction.annotation.Transactional;
38
import org.springframework.util.Assert;
39

    
40
import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl;
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.
50
 * The will be removed in a future version.
51
 */
52
@Service
53
@Transactional(readOnly = true)
54
// NOTE: no type level @PreAuthorize annotation for this class!
55
public class UserService extends ServiceBase<User,IUserDao> implements IUserService {
56

    
57
    protected IGroupDao groupDao;
58

    
59
    protected IGrantedAuthorityDao grantedAuthorityDao;
60

    
61
    private SaltSource saltSource; // = new ReflectionSaltSource();
62

    
63
    private PasswordEncoder passwordEncoder; // = new Md5PasswordEncoder();
64

    
65
    private AuthenticationManager authenticationManager;
66

    
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

    
109
    /**
110
     * Changes the own password of in the database of the user which is
111
     * currently authenticated. Requires to supply the old password for security
112
     * reasons. Refreshes the authentication in the SecurityContext after the
113
     * password change by re-authenticating the user with the new password.
114
     *
115
     * @see org.springframework.security.provisioning.UserDetailsManager#changePassword(java.lang.String,
116
     *      java.lang.String)
117
     */
118
    @Override
119
    @Transactional(readOnly=false)
120
    @PreAuthorize("isAuthenticated()")
121
    public void changePassword(String oldPassword, String newPassword) {
122
        Assert.hasText(oldPassword);
123
        Assert.hasText(newPassword);
124
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
125
        if(authentication != null && authentication.getPrincipal() != null && authentication.getPrincipal() instanceof User) {
126

    
127
            // get current authentication and load it from the persistence layer,
128
            // to make sure we are modifying the instance which is
129
            // attached to the hibernate session
130
            User user = (User)authentication.getPrincipal();
131
            user = dao.load(user.getUuid());
132

    
133
            // check if old password is valid
134
            authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), oldPassword));
135

    
136
            // make new password and set it
137
            Object salt = this.saltSource.getSalt(user);
138
            String password = passwordEncoder.encodePassword(newPassword, salt);
139
            user.setPassword(password);
140
            dao.update(user);
141

    
142
            // authenticate the user again with the new password
143
            UsernamePasswordAuthenticationToken newAuthentication = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
144
            newAuthentication.setDetails(authentication.getDetails());
145
            SecurityContextHolder.getContext().setAuthentication(newAuthentication);
146
            userCache.removeUserFromCache(user.getUsername());
147

    
148
        } else {
149
            throw new AccessDeniedException("Can't change password as no Authentication object found in context for current user.");
150
        }
151
    }
152

    
153
    @Override
154
    @Transactional(readOnly=false)
155
    @PreAuthorize("#username == authentication.name or hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
156
    public void changePasswordForUser(String username, String newPassword) {
157
        Assert.hasText(username);
158
        Assert.hasText(newPassword);
159

    
160
        try {
161
            User user = dao.findUserByUsername(username);
162
            if(user == null) {
163
                throw new UsernameNotFoundException(username);
164
            }
165

    
166
            Object salt = this.saltSource.getSalt(user);
167

    
168
            String password = passwordEncoder.encodePassword(newPassword, salt);
169
            user.setPassword(password);
170

    
171
            dao.update(user);
172
            userCache.removeUserFromCache(user.getUsername());
173
        } catch(NonUniqueResultException nure) {
174
            throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", 1);
175
        }
176
    }
177

    
178
    @Override
179
    @Transactional(readOnly=false)
180
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
181
    public void createUser(UserDetails user) {
182
    	Assert.isInstanceOf(User.class, user);
183

    
184
        String rawPassword = user.getPassword();
185
        Object salt = this.saltSource.getSalt(user);
186

    
187
        String password = passwordEncoder.encodePassword(rawPassword, salt);
188
        ((User)user).setPassword(password);
189

    
190
        dao.save((User)user);
191
    }
192

    
193
    @Override
194
    @Transactional(readOnly=false)
195
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
196
    public void deleteUser(String username) {
197
        Assert.hasLength(username);
198

    
199
        User user = dao.findUserByUsername(username);
200
        if(user != null) {
201
            dao.delete(user);
202
        }
203

    
204
        userCache.removeUserFromCache(username);
205
    }
206

    
207
    /* (non-Javadoc)
208
     * @see org.springframework.security.provisioning.UserDetailsManager#updateUser(org.springframework.security.core.userdetails.UserDetails)
209
     */
210
    @Override
211
    @Transactional(readOnly=false)
212
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
213
    public void updateUser(UserDetails user) {
214
        Assert.isInstanceOf(User.class, user);
215

    
216
        dao.update((User)user);
217
        userCache.removeUserFromCache(user.getUsername());
218
    }
219

    
220
    /* (non-Javadoc)
221
     * @see org.springframework.security.provisioning.UserDetailsManager#userExists(java.lang.String)
222
     */
223
    @Override
224
    public boolean userExists(String username) {
225
        Assert.hasText(username);
226

    
227
        User user = dao.findUserByUsername(username);
228
        return user != null;
229
    }
230

    
231
    /**
232
     * <b>DO NOT CALL THIS METHOD IN LONG RUNNING SESSIONS OR CONVERSATIONS
233
     * A THROWN UsernameNotFoundException WILL RENDER THE CONVERSATION UNUSABLE</b>
234
     *
235
     * @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String)
236
     */
237
    // NOTE: this method must not be secured since it is being used during the
238
    //       authentication process
239
    @Override
240
    public UserDetails loadUserByUsername(String username)
241
            throws UsernameNotFoundException, DataAccessException {
242
        Assert.hasText(username);
243
        try {
244
            User user = dao.findUserByUsername(username);
245
            if(user == null) {
246
                throw new UsernameNotFoundException(username);
247
            }
248
            return user;
249
        } catch(NonUniqueResultException nure) {
250
            throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", 1);
251
        }
252
    }
253

    
254

    
255
    @Override
256
    @Transactional(readOnly=false)
257
   // @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_RUN_AS_ADMIN') or hasRole('ROLE_USER_MANAGER')")
258
    public User save(User user) {
259
        if(user.getId() == 0 || dao.load(user.getUuid()) == null){
260
            createUser(user);
261
        }else{
262
            updateUser(user);
263
        }
264
        return user;
265
    }
266

    
267
    @Override
268
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
269
    public UUID update(User user) {
270
        updateUser(user);
271
        return user.getUuid();
272
    }
273

    
274
    @Override
275
    @Transactional(readOnly=false)
276
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
277
    public UUID saveGrantedAuthority(GrantedAuthority grantedAuthority) {
278
        return grantedAuthorityDao.save((GrantedAuthorityImpl)grantedAuthority).getUuid();
279
    }
280

    
281

    
282

    
283
    @Override
284
    @Transactional(readOnly = true)
285
    public List<User> listByUsername(String queryString,MatchMode matchmode, List<Criterion> criteria, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
286
         long numberOfResults = dao.countByUsername(queryString, matchmode, criteria);
287

    
288
         List<User> results = new ArrayList<>();
289
         if(numberOfResults > 0) {
290
                results = dao.findByUsername(queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths);
291
         }
292
         return results;
293
    }
294

    
295
    /* ================================================
296
     *  overriding methods to secure them
297
     *  via the type level annotation @PreAuthorize
298
     * ================================================ */
299

    
300
    @Override
301
    @Transactional(readOnly=false)
302
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
303
    public DeleteResult delete(User persistentObject)  {
304
        return super.delete(persistentObject);
305
    }
306

    
307
    @Override
308
    @Transactional(readOnly=false)
309
    public DeleteResult delete(UUID userUuid)  {
310
        return delete(dao.load(userUuid));
311
    }
312

    
313
    @Override
314
    @Transactional(readOnly=false)
315
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
316
    public Map<UUID, User> save(Collection<User> newInstances) {
317
        Map<UUID, User> users = new HashMap<UUID, User>();
318
    	for (User user: newInstances){
319
        	createUser(user);
320
        	users.put(user.getUuid(), user);
321
        }
322
    	return users;
323
    }
324

    
325
    @Override
326
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
327
    public UUID saveOrUpdate(User transientObject) {
328
        return super.saveOrUpdate(transientObject);
329
    }
330

    
331
    @Override
332
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
333
    @Transactional(readOnly=false)
334
    public User merge(User detachedObject) {
335
        return super.merge(detachedObject);
336
    }
337

    
338
    @Override
339
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
340
    @Transactional(readOnly=false)
341
    public List<User> merge(List<User> detachedObjects) {
342
        return super.merge(detachedObjects);
343
    }
344

    
345
    @Override
346
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER_MANAGER')")
347
    public Map<UUID, User> saveOrUpdate(Collection<User> transientInstances) {
348
        return super.saveOrUpdate(transientInstances);
349
    }
350

    
351
}
(102-102/105)