Project

General

Profile

Download (13.4 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2017 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.service;
10

    
11
import java.io.Serializable;
12
import java.util.Collection;
13
import java.util.EnumSet;
14
import java.util.HashSet;
15
import java.util.Set;
16
import java.util.UUID;
17

    
18
import org.apache.log4j.Logger;
19
import org.springframework.beans.factory.annotation.Autowired;
20
import org.springframework.beans.factory.annotation.Qualifier;
21
import org.springframework.security.authentication.AnonymousAuthenticationToken;
22
import org.springframework.security.authentication.AuthenticationProvider;
23
import org.springframework.security.core.Authentication;
24
import org.springframework.security.core.GrantedAuthority;
25
import org.springframework.security.core.context.SecurityContext;
26
import org.springframework.security.core.context.SecurityContextHolder;
27
import org.springframework.security.core.userdetails.UserDetails;
28
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
29
import org.springframework.transaction.TransactionStatus;
30

    
31
import com.vaadin.spring.annotation.SpringComponent;
32
import com.vaadin.spring.annotation.UIScope;
33

    
34
import eu.etaxonomy.cdm.api.application.CdmRepository;
35
import eu.etaxonomy.cdm.api.application.RunAsAuthenticator;
36
import eu.etaxonomy.cdm.database.PermissionDeniedException;
37
import eu.etaxonomy.cdm.model.common.CdmBase;
38
import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl;
39
import eu.etaxonomy.cdm.model.common.User;
40
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
41
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthority;
42
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthorityParsingException;
43
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionClass;
44
import eu.etaxonomy.cdm.persistence.hibernate.permission.ICdmPermissionEvaluator;
45
import eu.etaxonomy.cdm.persistence.hibernate.permission.Role;
46
import eu.etaxonomy.cdm.vaadin.permission.RolesAndPermissions;
47
import eu.etaxonomy.cdm.vaadin.permission.VaadinUserHelper;
48

    
49
/**
50
 * @author a.kohlbecker
51
 * @since May 19, 2017
52
 *
53
 */
54
@SpringComponent
55
@UIScope
56
public class CdmUserHelper extends VaadinUserHelper implements Serializable {
57

    
58
    private static final long serialVersionUID = -2521474709047255979L;
59

    
60
    public static final Logger logger = Logger.getLogger(CdmUserHelper.class);
61

    
62
    @Autowired
63
    private ICdmPermissionEvaluator permissionEvaluator;
64

    
65
    @Autowired
66
    @Qualifier("cdmRepository")
67
    private CdmRepository repo;
68

    
69
    AuthenticationProvider runAsAuthenticationProvider;
70

    
71
    @Autowired
72
    @Qualifier("runAsAuthenticationProvider")
73
    public void setRunAsAuthenticationProvider(AuthenticationProvider runAsAuthenticationProvider){
74
        this.runAsAuthenticationProvider = runAsAuthenticationProvider;
75
        runAsAutheticator.setRunAsAuthenticationProvider(runAsAuthenticationProvider);
76
    }
77

    
78
    RunAsAuthenticator runAsAutheticator = new RunAsAuthenticator();
79

    
80
    public CdmUserHelper(){
81
        super();
82
    }
83

    
84
    @Override
85
    public boolean userIsAutheticated() {
86
        Authentication authentication = getAuthentication();
87
        if(authentication != null){
88
            return authentication.isAuthenticated();
89
        }
90
        return false;
91
    }
92

    
93

    
94
    @Override
95
    public boolean userIsAnnonymous() {
96
        Authentication authentication = getAuthentication();
97
        return authentication != null
98
                && authentication.isAuthenticated()
99
                && authentication instanceof AnonymousAuthenticationToken;
100
    }
101

    
102
    @Override
103
    public User user() {
104
        Authentication authentication = getAuthentication();
105
        if(authentication != null && authentication.getPrincipal() != null) {
106
            return (User) authentication.getPrincipal();
107
        }
108
        return null;
109
    }
110

    
111
    @Override
112
    public String userName() {
113
        Authentication authentication = getAuthentication();
114
        if(authentication != null) {
115
            return authentication.getName();
116
        }
117
        return null;
118
    }
119

    
120
    @Override
121
    public boolean userIsAdmin() {
122
        Authentication authentication = getAuthentication();
123
        if(authentication != null) {
124
            return authentication.getAuthorities().stream().anyMatch(a -> {
125
                return a.getAuthority().equals(Role.ROLE_ADMIN.getAuthority());
126
            });
127
        }
128
        return false;
129
    }
130

    
131
    @Override
132
    public boolean userIsRegistrationCurator() {
133
        Authentication authentication = getAuthentication();
134
        if(authentication != null) {
135
            return authentication.getAuthorities().stream().anyMatch(a -> {
136
                return a.equals(RolesAndPermissions.ROLE_CURATION)
137
                        // doing faster regex check here instreas of using CdmAuthoritiy.fromString()
138
                        || a.getAuthority().matches("^Registration\\.\\[.*UPDATE");
139
            });
140
        }
141
        return false;
142
    }
143

    
144
    @Override
145
    public boolean userHasPermission(CdmBase entity, Object ... args){
146
        EnumSet<CRUD> crudSet = crudSetFromArgs(args);
147
        try {
148
            return permissionEvaluator.hasPermission(getAuthentication(), entity, crudSet);
149
        } catch (PermissionDeniedException e){
150
            //IGNORE
151
        }
152
        return false;
153
    }
154

    
155
    @Override
156
    public boolean userHasPermission(Class<? extends CdmBase> cdmType, Integer entitiyId, Object ... args){
157
        EnumSet<CRUD> crudSet = crudSetFromArgs(args);
158
        try {
159
            CdmBase entity = repo.getCommonService().find(cdmType, entitiyId);
160
            return permissionEvaluator.hasPermission(getAuthentication(), entity, crudSet);
161
        } catch (PermissionDeniedException e){
162
            //IGNORE
163
        }
164
        return false;
165
    }
166

    
167
    @Override
168
    public boolean userHasPermission(Class<? extends CdmBase> cdmType, UUID entitiyUuid, Object ... args){
169
        EnumSet<CRUD> crudSet = crudSetFromArgs(args);
170
        try {
171
            CdmBase entity = repo.getCommonService().find(cdmType, entitiyUuid);
172
            return permissionEvaluator.hasPermission(getAuthentication(), entity, crudSet);
173
        } catch (PermissionDeniedException e){
174
            //IGNORE
175
        }
176
        return false;
177
    }
178

    
179
    @Override
180
    public boolean userHasPermission(Class<? extends CdmBase> cdmType, Object ... args){
181
        EnumSet<CRUD> crudSet = crudSetFromArgs(args);
182
        try {
183
            return permissionEvaluator.hasPermission(getAuthentication(), cdmType, crudSet);
184
        } catch (PermissionDeniedException e){
185
            //IGNORE
186
        }
187
        return false;
188
    }
189

    
190
    public void logout() {
191
        SecurityContext context = SecurityContextHolder.getContext();
192
        context.setAuthentication(null);
193
        SecurityContextHolder.clearContext();
194
    }
195

    
196

    
197
    private EnumSet<CRUD> crudSetFromArgs(Object[] args) {
198
        EnumSet<CRUD> crudSet = EnumSet.noneOf(CRUD.class);
199
        for(int i = 0; i < args.length; i++){
200
            try {
201
                crudSet.add(CRUD.valueOf(args[i].toString()));
202
            } catch (Exception e){
203
                throw new IllegalArgumentException("could not add " + args[i], e);
204
            }
205
        }
206
        return crudSet;
207
    }
208

    
209

    
210
    /**
211
     * @return
212
     *
213
     * FIXME is it ok to use the SecurityContextHolder or do we need to hold the context in the vaadin session?
214
     */
215
    private SecurityContext currentSecurityContext() {
216
        return SecurityContextHolder.getContext();
217
    }
218

    
219
    /**
220
     * @return
221
     */
222
    private Authentication getAuthentication() {
223
        return currentSecurityContext().getAuthentication();
224
    }
225

    
226
    /**
227
     * {@inheritDoc}
228
     *
229
     */
230
    @Override
231
    public CdmAuthority createAuthorityFor(String username, CdmBase cdmEntity, EnumSet<CRUD> crud, String property) {
232

    
233
        TransactionStatus txStatus = repo.startTransaction();
234
        UserDetails userDetails = repo.getUserService().loadUserByUsername(username);
235
        boolean newAuthorityAdded = false;
236
        CdmAuthority authority = null;
237
        User user = (User)userDetails;
238
        if(userDetails != null){
239
            try{
240
                runAsAutheticator.runAsAuthentication(Role.ROLE_USER_MANAGER);
241
                authority = new CdmAuthority(cdmEntity, property, crud);
242
                try {
243
                    GrantedAuthorityImpl grantedAuthority = repo.getGrantedAuthorityService().findAuthorityString(authority.toString());
244
                    if(grantedAuthority == null){
245
                        grantedAuthority = authority.asNewGrantedAuthority();
246
                    }
247
                    newAuthorityAdded = user.getGrantedAuthorities().add(grantedAuthority);
248
                } catch (CdmAuthorityParsingException e) {
249
                    throw new RuntimeException(e);
250
                }
251
                repo.getSession().flush();
252
            } finally {
253
                // in any case restore the previous authentication
254
                runAsAutheticator.restoreAuthentication();
255
            }
256
            logger.debug("new authority for " + username + ": " + authority.toString());
257
            Authentication authentication = new PreAuthenticatedAuthenticationToken(user, user.getPassword(), user.getAuthorities());
258
            SecurityContextHolder.getContext().setAuthentication(authentication);
259
            logger.debug("security context refreshed with user " + username);
260
        }
261
        repo.commitTransaction(txStatus);
262
        return newAuthorityAdded ? authority : null;
263

    
264
    }
265

    
266
    /**
267
     * @param username
268
     * @param cdmType
269
     * @param entitiyId
270
     * @param crud
271
     * @return
272
     */
273
    @Override
274
    public CdmAuthority createAuthorityFor(String username, Class<? extends CdmBase> cdmType, Integer entitiyId, EnumSet<CRUD> crud, String property) {
275

    
276
        CdmBase cdmEntity = repo.getCommonService().find(cdmType, entitiyId);
277
        return createAuthorityFor(username, cdmEntity, crud, property);
278
    }
279

    
280
    /**
281
     * @param username
282
     * @param cdmType
283
     * @param entitiyUuid
284
     * @param crud
285
     * @return
286
     */
287
    @Override
288
    public CdmAuthority createAuthorityFor(String username, Class<? extends CdmBase> cdmType, UUID entitiyUuid, EnumSet<CRUD> crud, String property) {
289

    
290
        CdmBase cdmEntity = repo.getCommonService().find(cdmType, entitiyUuid);
291
        return createAuthorityFor(username, cdmEntity, crud, property);
292
    }
293

    
294
    /**
295
     * {@inheritDoc}
296
     */
297
    @Override
298
    public CdmAuthority createAuthorityForCurrentUser(CdmBase cdmEntity, EnumSet<CRUD> crud, String property) {
299
        return createAuthorityFor(userName(), cdmEntity, crud, property);
300

    
301
    }
302

    
303
    /**
304
     * @param cdmType
305
     * @param entitiyId
306
     * @param crud
307
     * @return
308
     */
309
    @Override
310
    public CdmAuthority createAuthorityForCurrentUser(Class<? extends CdmBase> cdmType, Integer entitiyId, EnumSet<CRUD> crud, String property) {
311
        return createAuthorityFor(userName(), cdmType, entitiyId, crud, property);
312
    }
313

    
314
    /**
315
     * @param cdmType
316
     * @param entitiyUuid
317
     * @param crud
318
     * @return
319
     */
320
    @Override
321
    public CdmAuthority createAuthorityForCurrentUser(Class<? extends CdmBase> cdmType, UUID entitiyUuid, EnumSet<CRUD> crud, String property) {
322
        return createAuthorityFor(userName(), cdmType, entitiyUuid, crud, property);
323
    }
324

    
325
    /**
326
     * {@inheritDoc}
327
     */
328
    @Override
329
    public void removeAuthorityForCurrentUser(CdmAuthority cdmAuthority) {
330
        removeAuthorityForCurrentUser(userName(), cdmAuthority);
331

    
332
    }
333

    
334
    /**
335
     * {@inheritDoc}
336
     */
337
    @Override
338
    public void removeAuthorityForCurrentUser(String username, CdmAuthority cdmAuthority) {
339

    
340
        UserDetails userDetails = repo.getUserService().loadUserByUsername(username);
341
        if(userDetails != null){
342
            runAsAutheticator.runAsAuthentication(Role.ROLE_USER_MANAGER);
343
            User user = (User)userDetails;
344
            user.getGrantedAuthorities().remove(cdmAuthority);
345
            repo.getSession().flush();
346
            runAsAutheticator.restoreAuthentication();
347
            Authentication authentication = new PreAuthenticatedAuthenticationToken(user, user.getPassword(), user.getAuthorities());
348
            SecurityContextHolder.getContext().setAuthentication(authentication);
349
            logger.debug("security context refreshed with user " + username);
350
        }
351

    
352
    }
353

    
354
    /**
355
     * {@inheritDoc}
356
     */
357
    @Override
358
    public Collection<CdmAuthority> findUserPermissions(CdmBase cdmEntity, EnumSet<CRUD> crud) {
359
        Set<CdmAuthority> matches = new HashSet<>();
360
        CdmPermissionClass permissionClass = CdmPermissionClass.getValueOf(cdmEntity);
361
        Collection<? extends GrantedAuthority> authorities = getAuthentication().getAuthorities();
362
        for(GrantedAuthority ga : authorities){
363
            try {
364
                CdmAuthority cdmAuthority = CdmAuthority.fromGrantedAuthority(ga);
365
                if(cdmAuthority.getPermissionClass().equals(permissionClass)){
366
                    if(cdmAuthority.getOperation().containsAll(crud)){
367
                        if(cdmAuthority.hasTargetUuid() && cdmAuthority.getTargetUUID().equals(cdmEntity.getUuid())){
368
                            matches.add(cdmAuthority);
369
                        } else {
370
                            matches.add(cdmAuthority);
371
                        }
372
                    }
373
                }
374
            } catch (CdmAuthorityParsingException e) {
375
                continue;
376
            }
377
        }
378
        return matches;
379
    }
380

    
381
}
(4-4/9)