Project

General

Profile

« Previous | Next » 

Revision 8bbd4f27

Added by Andreas Kohlbecker over 5 years ago

fix #7785 CdmUserHelper can use ICdmEntityUuidCacher to avoid loading entities from the db for permission checks:
- inner class CachingCdmUserHelper to be used when CdmUserHelper.withCache() is called
- ICdmEntityUuidCacher and CdmTransientEntityAndUuidCacher complements the CdmTransientEntityCacher by the ability to get CDM entities from the cache by the UUID

View differences:

cdmlib-cache/src/main/java/eu/etaxonomy/cdm/cache/CdmTransientEntityAndUuidCacher.java
1
/**
2
* Copyright (C) 2018 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.cache;
10

  
11
import java.util.HashMap;
12
import java.util.Map;
13
import java.util.UUID;
14

  
15
import eu.etaxonomy.cdm.model.ICdmEntityUuidCacher;
16
import eu.etaxonomy.cdm.model.common.CdmBase;
17

  
18
/**
19
 * Complements the CdmTransientEntityCacher by the ability to get CDM entities
20
 * from the cache by the UUID.
21
 * <p>
22
 * Internally a Map is used to store the entity UUID together with the CdmEntityCacheKey
23
 * of each entity being put into the cache.
24
 *
25
 * @author a.kohlbecker
26
 * @since Oct 14, 2018
27
 *
28
 */
29
public class CdmTransientEntityAndUuidCacher extends CdmTransientEntityCacher implements ICdmEntityUuidCacher {
30

  
31
    private Map<UUID, CdmEntityCacheKey<?>> uuidKeyMap = new HashMap<>();
32

  
33
    /**
34
     * @param cacheId
35
     */
36
    public CdmTransientEntityAndUuidCacher(String cacheId) {
37
        super(cacheId);
38
    }
39

  
40
    /**
41
     * @param sessionOwner
42
     */
43
    public CdmTransientEntityAndUuidCacher(Object sessionOwner) {
44
        super(sessionOwner);
45
    }
46

  
47
    @Override
48
    public CdmBase getFromCache(UUID uuid){
49
        return getFromCache(uuidKeyMap.get(uuid));
50
    }
51

  
52
    @Override
53
    protected void putToCache(CdmEntityCacheKey<?> key, CdmBase cdmEntityToCache) {
54
        super.putToCache(key, cdmEntityToCache);
55
        uuidKeyMap.put(cdmEntityToCache.getUuid(), key);
56
    }
57

  
58

  
59
    @Override
60
    public void dispose() {
61
        super.dispose();
62
        uuidKeyMap.clear();
63
    }
64

  
65

  
66
}
cdmlib-cache/src/main/java/eu/etaxonomy/cdm/cache/CdmTransientEntityCacher.java
266 266
                newEntity.setId(cdmEntity.getId());
267 267
                cdmEntityToCache = newEntity;
268 268
            }
269
            getCache().put(new Element(key, cdmEntityToCache));
269
            putToCache(key, cdmEntityToCache);
270 270
            cdmEntityToCache.initListener();
271 271
            newEntitiesMap.remove(cdmEntity.getUuid());
272 272
            if (logger.isDebugEnabled()){logger.debug(" - object of type " + cdmEntityToCache.getClass().getName() + " with id " + cdmEntityToCache.getId() + " put in cache");}
......
275 275
        logger.debug(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " already exists");
276 276
    }
277 277

  
278
    /**
279
     * @param key
280
     * @param cdmEntityToCache
281
     */
282
    protected void putToCache(CdmEntityCacheKey<?> key, CdmBase cdmEntityToCache) {
283
        getCache().put(new Element(key, cdmEntityToCache));
284
    }
285

  
278 286

  
279 287
    private Element getCacheElement(CdmEntityCacheKey<?> key) {
280 288
        return getCache().get(key);
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/ICdmEntityUuidCacher.java
1
/**
2
* Copyright (C) 2018 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.model;
10

  
11
import java.util.UUID;
12

  
13
import eu.etaxonomy.cdm.model.common.CdmBase;
14

  
15
/**
16
 * @author a.kohlbecker
17
 * @since Oct 14, 2018
18
 *
19
 */
20
public interface ICdmEntityUuidCacher extends ICdmCacher {
21

  
22
    CdmBase getFromCache(UUID uuid);
23

  
24
}
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/utility/CdmUserHelper.java
32 32
import eu.etaxonomy.cdm.api.application.CdmRepository;
33 33
import eu.etaxonomy.cdm.api.application.RunAsAuthenticator;
34 34
import eu.etaxonomy.cdm.database.PermissionDeniedException;
35
import eu.etaxonomy.cdm.model.ICdmEntityUuidCacher;
35 36
import eu.etaxonomy.cdm.model.common.CdmBase;
36 37
import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl;
37 38
import eu.etaxonomy.cdm.model.common.User;
......
59 60
    @Autowired
60 61
    @Lazy
61 62
    @Qualifier("cdmRepository")
62
    private CdmRepository repo;
63
    protected CdmRepository repo;
63 64

  
64 65
    AuthenticationProvider runAsAuthenticationProvider;
65 66

  
......
78 79
        super();
79 80
    }
80 81

  
82
    /**
83
     * @return
84
     */
85
    protected ICdmPermissionEvaluator permissionEvaluator() {
86
        return permissionEvaluator;
87
    }
88

  
89
    /**
90
     * @return
91
     */
92
    protected CdmRepository repo() {
93
        return repo;
94
    }
95

  
81 96
    @Override
82 97
    public boolean userIsAutheticated() {
83 98
        Authentication authentication = getAuthentication();
......
137 152
    public boolean userHasPermission(CdmBase entity, Object ... args){
138 153
        EnumSet<CRUD> crudSet = crudSetFromArgs(args);
139 154
        try {
140
            return permissionEvaluator.hasPermission(getAuthentication(), entity, crudSet);
155
            return permissionEvaluator().hasPermission(getAuthentication(), entity, crudSet);
141 156
        } catch (PermissionDeniedException e){
142 157
            //IGNORE
143 158
        }
144 159
        return false;
145 160
    }
146 161

  
162
    /**
163
     * @deprecated not performance optimized by using the cache,
164
     * use {@link #userHasPermission(Class, UUID, Object...)} instead
165
     */
147 166
    @Override
167
    @Deprecated
148 168
    public boolean userHasPermission(Class<? extends CdmBase> cdmType, Integer entitiyId, Object ... args){
149 169
        EnumSet<CRUD> crudSet = crudSetFromArgs(args);
150 170
        try {
151
            CdmBase entity = repo.getCommonService().find(cdmType, entitiyId);
152
            return permissionEvaluator.hasPermission(getAuthentication(), entity, crudSet);
171
            CdmBase entity = repo().getCommonService().find(cdmType, entitiyId);
172
            return permissionEvaluator().hasPermission(getAuthentication(), entity, crudSet);
153 173
        } catch (PermissionDeniedException e){
154 174
            //IGNORE
155 175
        }
......
160 180
    public boolean userHasPermission(Class<? extends CdmBase> cdmType, UUID entitiyUuid, Object ... args){
161 181
        EnumSet<CRUD> crudSet = crudSetFromArgs(args);
162 182
        try {
163
            CdmBase entity = repo.getCommonService().find(cdmType, entitiyUuid);
164
            return permissionEvaluator.hasPermission(getAuthentication(), entity, crudSet);
183
            CdmBase entity = entity(cdmType, entitiyUuid);
184
            return permissionEvaluator().hasPermission(getAuthentication(), entity, crudSet);
165 185
        } catch (PermissionDeniedException e){
166 186
            //IGNORE
167 187
        }
168 188
        return false;
169 189
    }
170 190

  
191
    /**
192
     * @param cdmType
193
     * @param entitiyUuid
194
     * @return
195
     */
196
    protected CdmBase entity(Class<? extends CdmBase> cdmType, UUID entitiyUuid) {
197
        CdmBase entity = entityFromCache(cdmType, entitiyUuid);
198
        if(entity == null){
199
            entity = repo().getCommonService().find(cdmType, entitiyUuid);
200
            if(getCache() != null && entity != null){
201
                getCache().put(entity);
202
            }
203
        }
204
        return entity;
205
    }
206

  
171 207
    @Override
172 208
    public boolean userHasPermission(Class<? extends CdmBase> cdmType, Object ... args){
173 209
        EnumSet<CRUD> crudSet = crudSetFromArgs(args);
174 210
        try {
175
            return permissionEvaluator.hasPermission(getAuthentication(), cdmType, crudSet);
211
            return permissionEvaluator().hasPermission(getAuthentication(), cdmType, crudSet);
176 212
        } catch (PermissionDeniedException e){
177 213
            //IGNORE
178 214
        }
......
222 258
    @Override
223 259
    public CdmAuthority createAuthorityFor(String username, CdmBase cdmEntity, EnumSet<CRUD> crud, String property) {
224 260

  
225
        TransactionStatus txStatus = repo.startTransaction();
226
        UserDetails userDetails = repo.getUserService().loadUserByUsername(username);
261
        TransactionStatus txStatus = repo().startTransaction();
262
        UserDetails userDetails = repo().getUserService().loadUserByUsername(username);
227 263
        boolean newAuthorityAdded = false;
228 264
        CdmAuthority authority = null;
229 265
        User user = (User)userDetails;
......
232 268
                getRunAsAutheticator().runAsAuthentication(Role.ROLE_USER_MANAGER);
233 269
                authority = new CdmAuthority(cdmEntity, property, crud);
234 270
                try {
235
                    GrantedAuthorityImpl grantedAuthority = repo.getGrantedAuthorityService().findAuthorityString(authority.toString());
271
                    GrantedAuthorityImpl grantedAuthority = repo().getGrantedAuthorityService().findAuthorityString(authority.toString());
236 272
                    if(grantedAuthority == null){
237 273
                        grantedAuthority = authority.asNewGrantedAuthority();
238 274
                    }
......
240 276
                } catch (CdmAuthorityParsingException e) {
241 277
                    throw new RuntimeException(e);
242 278
                }
243
                repo.getSession().flush();
279
                repo().getSession().flush();
244 280
            } finally {
245 281
                // in any case restore the previous authentication
246 282
                getRunAsAutheticator().restoreAuthentication();
......
250 286
            SecurityContextHolder.getContext().setAuthentication(authentication);
251 287
            logger.debug("security context refreshed with user " + username);
252 288
        }
253
        repo.commitTransaction(txStatus);
289
        repo().commitTransaction(txStatus);
254 290
        return newAuthorityAdded ? authority : null;
255 291

  
256 292
    }
......
261 297
     * @param entitiyId
262 298
     * @param crud
263 299
     * @return
300
     * @deprecated not performance optimized by using the cache,
301
     * use {@link #createAuthorityFor(String, Class, UUID, EnumSet, String)} instead
264 302
     */
265 303
    @Override
304
    @Deprecated
266 305
    public CdmAuthority createAuthorityFor(String username, Class<? extends CdmBase> cdmType, Integer entitiyId, EnumSet<CRUD> crud, String property) {
267 306

  
268
        CdmBase cdmEntity = repo.getCommonService().find(cdmType, entitiyId);
307
        CdmBase cdmEntity = repo().getCommonService().find(cdmType, entitiyId);
269 308
        return createAuthorityFor(username, cdmEntity, crud, property);
270 309
    }
271 310

  
......
279 318
    @Override
280 319
    public CdmAuthority createAuthorityFor(String username, Class<? extends CdmBase> cdmType, UUID entitiyUuid, EnumSet<CRUD> crud, String property) {
281 320

  
282
        CdmBase cdmEntity = repo.getCommonService().find(cdmType, entitiyUuid);
321
        CdmBase cdmEntity = entity(cdmType, entitiyUuid);
283 322
        return createAuthorityFor(username, cdmEntity, crud, property);
284 323
    }
285 324

  
......
329 368
    @Override
330 369
    public void removeAuthorityForCurrentUser(String username, CdmAuthority cdmAuthority) {
331 370

  
332
        UserDetails userDetails = repo.getUserService().loadUserByUsername(username);
371
        UserDetails userDetails = repo().getUserService().loadUserByUsername(username);
333 372
        if(userDetails != null){
334 373
            getRunAsAutheticator().runAsAuthentication(Role.ROLE_USER_MANAGER);
335 374
            User user = (User)userDetails;
336 375
            user.getGrantedAuthorities().remove(cdmAuthority);
337
            repo.getSession().flush();
376
            repo().getSession().flush();
338 377
            getRunAsAutheticator().restoreAuthentication();
339 378
            Authentication authentication = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
340 379
            SecurityContextHolder.getContext().setAuthentication(authentication);
......
388 427
        return runAsAutheticator;
389 428
    }
390 429

  
430
    /**
431
     * @return the cache
432
     */
433
    public ICdmEntityUuidCacher getCache() {
434
        return null;
435
    }
436

  
437
    /**
438
     * @param cdmType
439
     * @param entitiyUuid
440
     * @return
441
     */
442
    private CdmBase entityFromCache(Class<? extends CdmBase> cdmType, UUID entitiyUuid) {
443
        CdmBase entity = null;
444
        if(getCache() != null){
445
           entity = getCache().getFromCache(entitiyUuid);
446
           if(entity != null && !cdmType.isAssignableFrom(entity.getClass())){
447
               logger.error("Entity with " +  entitiyUuid + " does not match the required type");
448
               entity = null;
449
           }
450
        }
451
        return entity;
452
    }
453

  
454
    @Override
455
    public CdmUserHelper withCache(ICdmEntityUuidCacher cache){
456

  
457
        return new CachingCdmUserHelper(cache);
458
    }
459

  
460
    class CachingCdmUserHelper extends CdmUserHelper{
461

  
462

  
463
        private static final long serialVersionUID = -5010082174809972831L;
464

  
465
        private ICdmEntityUuidCacher cache;
466

  
467
        public CachingCdmUserHelper(ICdmEntityUuidCacher cache){
468
            this.cache = cache;
469
        }
470

  
471
        /**
472
         * @return the cache
473
         */
474
        @Override
475
        public ICdmEntityUuidCacher getCache() {
476
            return cache;
477
        }
478

  
479
        @Override
480
        protected CdmRepository repo() {
481
            return CdmUserHelper.this.repo;
482
        }
483

  
484
        @Override
485
        protected ICdmPermissionEvaluator permissionEvaluator() {
486
            return CdmUserHelper.this.permissionEvaluator;
487
        }
488

  
489
    }
490

  
391 491
}
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/utility/UserHelper.java
14 14

  
15 15
import org.springframework.security.core.Authentication;
16 16

  
17
import eu.etaxonomy.cdm.model.ICdmEntityUuidCacher;
17 18
import eu.etaxonomy.cdm.model.common.CdmBase;
18 19
import eu.etaxonomy.cdm.model.common.User;
19 20
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
......
28 29
 */
29 30
public interface UserHelper {
30 31

  
32
    @Deprecated
31 33
    boolean userHasPermission(Class<? extends CdmBase> cdmType, Integer entitiyId, Object ... args);
32 34

  
33 35
    boolean userHasPermission(Class<? extends CdmBase> cdmType, UUID entitiyUUID, Object ... args);
......
144 146
     */
145 147
    public Authentication getAuthentication();
146 148

  
149
    public CdmUserHelper withCache(ICdmEntityUuidCacher iCdmCacher);
150

  
147 151

  
148 152
}

Also available in: Unified diff