Skip to content

Commit

Permalink
Added code to handle test context reloads.
Browse files Browse the repository at this point in the history
Fixed permission tests.
  • Loading branch information
chrisknoll committed Sep 27, 2024
1 parent 37aaef8 commit 0a77f67
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 90 deletions.
6 changes: 4 additions & 2 deletions src/main/java/org/ohdsi/webapi/cache/CacheService.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.StreamSupport;
import javax.cache.Cache;
import javax.cache.CacheManager;
Expand Down Expand Up @@ -54,6 +53,10 @@ public CacheService(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}

public CacheService() {
}


@GET
@Path("/")
@Produces(MediaType.APPLICATION_JSON)
Expand Down Expand Up @@ -88,5 +91,4 @@ public ClearCacheResult clearAll() {
}
return result;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,12 @@ public static class CachingSetup implements JCacheManagerCustomizer {
@Override
public void customize(CacheManager cacheManager) {
// Evict when a cohort definition is created or updated, or permissions, or tags
cacheManager.createCache(COHORT_DEFINITION_LIST_CACHE, new MutableConfiguration<String, List<CohortMetadataDTO>>()
.setTypes(String.class, (Class<List<CohortMetadataDTO>>) (Class<?>) List.class)
.setStoreByValue(false)
.setStatisticsEnabled(true));
if (!CacheHelper.getCacheNames(cacheManager).contains(COHORT_DEFINITION_LIST_CACHE)) {
cacheManager.createCache(COHORT_DEFINITION_LIST_CACHE, new MutableConfiguration<String, List<CohortMetadataDTO>>()
.setTypes(String.class, (Class<List<CohortMetadataDTO>>) (Class<?>) List.class)
.setStoreByValue(false)
.setStatisticsEnabled(true));
}
}
}

Expand Down
16 changes: 11 additions & 5 deletions src/main/java/org/ohdsi/webapi/service/ConceptSetService.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.ohdsi.webapi.conceptset.dto.ConceptSetVersionFullDTO;
import org.ohdsi.webapi.exception.ConceptNotExistException;
import org.ohdsi.webapi.security.PermissionService;
import static org.ohdsi.webapi.service.CohortDefinitionService.CachingSetup.COHORT_DEFINITION_LIST_CACHE;
import org.ohdsi.webapi.service.dto.ConceptSetDTO;
import org.ohdsi.webapi.shiro.Entities.UserEntity;
import org.ohdsi.webapi.shiro.Entities.UserRepository;
Expand All @@ -51,6 +52,7 @@
import org.ohdsi.webapi.source.SourceService;
import org.ohdsi.webapi.tag.domain.HasTags;
import org.ohdsi.webapi.tag.dto.TagNameListRequestDTO;
import org.ohdsi.webapi.util.CacheHelper;
import org.ohdsi.webapi.util.ExportUtil;
import org.ohdsi.webapi.util.NameUtils;
import org.ohdsi.webapi.util.ExceptionUtils;
Expand Down Expand Up @@ -88,14 +90,18 @@ public static class CachingSetup implements JCacheManagerCustomizer {

@Override
public void customize(CacheManager cacheManager) {
// due to unit tests causing application contexts to reload cache manager caches, we
// have to check for the existance of a cache before creating it
Set<String> cacheNames = CacheHelper.getCacheNames(cacheManager);
// Evict when a cohort definition is created or updated, or permissions, or tags
cacheManager.createCache(CONCEPT_SET_LIST_CACHE, new MutableConfiguration<String, Collection<ConceptSetDTO>>()
.setTypes(String.class, (Class<Collection<ConceptSetDTO>>) (Class<?>) List.class)
.setStoreByValue(false)
.setStatisticsEnabled(true));
if (!cacheNames.contains(CONCEPT_SET_LIST_CACHE)) {
cacheManager.createCache(CONCEPT_SET_LIST_CACHE, new MutableConfiguration<String, Collection<ConceptSetDTO>>()
.setTypes(String.class, (Class<Collection<ConceptSetDTO>>) (Class<?>) List.class)
.setStoreByValue(false)
.setStatisticsEnabled(true));
}
}
}

@Autowired
private ConceptSetGenerationInfoRepository conceptSetGenerationInfoRepository;

Expand Down
34 changes: 22 additions & 12 deletions src/main/java/org/ohdsi/webapi/service/VocabularyService.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import org.ohdsi.webapi.source.SourceService;
import org.ohdsi.webapi.source.SourceDaimon;
import org.ohdsi.webapi.source.SourceInfo;
import org.ohdsi.webapi.util.CacheHelper;
import org.ohdsi.webapi.util.PreparedSqlRender;
import org.ohdsi.webapi.util.PreparedStatementRenderer;
import org.ohdsi.webapi.vocabulary.ConceptRecommendedNotInstalledException;
Expand Down Expand Up @@ -98,19 +99,28 @@ public static class CachingSetup implements JCacheManagerCustomizer {

@Override
public void customize(CacheManager cacheManager) {
// due to unit tests causing application contexts to reload cache manager caches, we
// have to check for the existance of a cache before creating it
Set<String> cacheNames = CacheHelper.getCacheNames(cacheManager);
// Evict when a cohort definition is created or updated, or permissions, or tags
cacheManager.createCache(CONCEPT_DETAIL_CACHE, new MutableConfiguration<String, Concept>()
.setTypes(String.class, Concept.class)
.setStoreByValue(false)
.setStatisticsEnabled(true));
cacheManager.createCache(CONCEPT_RELATED_CACHE, new MutableConfiguration<String, Collection<RelatedConcept>>()
.setTypes(String.class, (Class<Collection<RelatedConcept>>) (Class<?>) Collection.class)
.setStoreByValue(false)
.setStatisticsEnabled(true));
cacheManager.createCache(CONCEPT_HIERARCHY_CACHE, new MutableConfiguration<String, Collection<RelatedConcept>>()
.setTypes(String.class, (Class<Collection<RelatedConcept>>) (Class<?>) Collection.class)
.setStoreByValue(false)
.setStatisticsEnabled(true));
if (!cacheNames.contains(CONCEPT_DETAIL_CACHE)) {
cacheManager.createCache(CONCEPT_DETAIL_CACHE, new MutableConfiguration<String, Concept>()
.setTypes(String.class, Concept.class)
.setStoreByValue(false)
.setStatisticsEnabled(true));
}
if (!cacheNames.contains(CONCEPT_RELATED_CACHE)) {
cacheManager.createCache(CONCEPT_RELATED_CACHE, new MutableConfiguration<String, Collection<RelatedConcept>>()
.setTypes(String.class, (Class<Collection<RelatedConcept>>) (Class<?>) Collection.class)
.setStoreByValue(false)
.setStatisticsEnabled(true));
}
if (!cacheNames.contains(CONCEPT_HIERARCHY_CACHE)) {
cacheManager.createCache(CONCEPT_HIERARCHY_CACHE, new MutableConfiguration<String, Collection<RelatedConcept>>()
.setTypes(String.class, (Class<Collection<RelatedConcept>>) (Class<?>) Collection.class)
.setStoreByValue(false)
.setStatisticsEnabled(true));
}
}
}

Expand Down
80 changes: 45 additions & 35 deletions src/main/java/org/ohdsi/webapi/shiro/PermissionManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.apache.shiro.authz.Permission;
import org.apache.shiro.authz.permission.WildcardPermission;
import org.ohdsi.circe.helper.ResourceHelper;
import org.ohdsi.webapi.util.CacheHelper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer;
import org.springframework.cache.annotation.CacheEvict;
Expand All @@ -62,14 +63,18 @@ public static class CachingSetup implements JCacheManagerCustomizer {

@Override
public void customize(CacheManager cacheManager) {
// due to unit tests causing application contexts to reload cache manager caches, we
// have to check for the existance of a cache before creating it
Set<String> cacheNames = CacheHelper.getCacheNames(cacheManager);
// Evict when a user, role or permission is modified/deleted.
cacheManager.createCache(AUTH_INFO_CACHE, new MutableConfiguration<String, UserSimpleAuthorizationInfo>()
.setTypes(String.class, UserSimpleAuthorizationInfo.class)
.setStoreByValue(false)
.setStatisticsEnabled(true));
if (!cacheNames.contains(AUTH_INFO_CACHE)) {
cacheManager.createCache(AUTH_INFO_CACHE, new MutableConfiguration<String, UserSimpleAuthorizationInfo>()
.setTypes(String.class, UserSimpleAuthorizationInfo.class)
.setStoreByValue(false)
.setStatisticsEnabled(true));
}
}
}


@Value("${datasource.ohdsi.schema}")
private String ohdsiSchema;
Expand All @@ -95,6 +100,8 @@ public void customize(CacheManager cacheManager) {
@Autowired
private JdbcTemplate jdbcTemplate;

private ThreadLocal<ConcurrentHashMap<String, UserSimpleAuthorizationInfo>> authorizationInfoCache = ThreadLocal.withInitial(ConcurrentHashMap::new);

public static class PermissionsDTO {

public Map<String, List<String>> permissions = null;
Expand Down Expand Up @@ -163,39 +170,42 @@ public Iterable<RoleEntity> getRoles(boolean includePersonalRoles) {
@Cacheable(cacheNames = CachingSetup.AUTH_INFO_CACHE)
public UserSimpleAuthorizationInfo getAuthorizationInfo(final String login) {

final UserSimpleAuthorizationInfo info = new UserSimpleAuthorizationInfo();

final UserEntity userEntity = userRepository.findByLogin(login);
if(userEntity == null) {
throw new UnknownAccountException("Account does not exist");
}

info.setUserId(userEntity.getId());
info.setLogin(userEntity.getLogin());

for (UserRoleEntity userRole: userEntity.getUserRoles()) {
info.addRole(userRole.getRole().getName());
}

// convert permission index from queryUserPermissions() into a map of WildcardPermissions
Map<String, List<String>> permsIdx = this.queryUserPermissions(login).permissions;
Map permissionMap = new HashMap<String, List<Permission>>();
Set<String> permissionNames = new HashSet<>();

for(String permIdxKey : permsIdx.keySet()) {
List<String> perms = permsIdx.get(permIdxKey);
permissionNames.addAll(perms);
// convert raw string permission into Wildcard perm for each element in this key's array.
permissionMap.put(permIdxKey, perms.stream().map(perm -> new WildcardPermission(perm)).collect(Collectors.toList()));
}

info.setStringPermissions(permissionNames);
info.setPermissionIdx(permissionMap);
return info;
}
return authorizationInfoCache.get().computeIfAbsent(login, newLogin -> {
final UserSimpleAuthorizationInfo info = new UserSimpleAuthorizationInfo();

final UserEntity userEntity = userRepository.findByLogin(login);
if(userEntity == null) {
throw new UnknownAccountException("Account does not exist");
}

info.setUserId(userEntity.getId());
info.setLogin(userEntity.getLogin());

for (UserRoleEntity userRole: userEntity.getUserRoles()) {
info.addRole(userRole.getRole().getName());
}

// convert permission index from queryUserPermissions() into a map of WildcardPermissions
Map<String, List<String>> permsIdx = this.queryUserPermissions(login).permissions;
Map permissionMap = new HashMap<String, List<Permission>>();
Set<String> permissionNames = new HashSet<>();

for(String permIdxKey : permsIdx.keySet()) {
List<String> perms = permsIdx.get(permIdxKey);
permissionNames.addAll(perms);
// convert raw string permission into Wildcard perm for each element in this key's array.
permissionMap.put(permIdxKey, perms.stream().map(perm -> new WildcardPermission(perm)).collect(Collectors.toList()));
}

info.setStringPermissions(permissionNames);
info.setPermissionIdx(permissionMap);
return info;
});
}

@CacheEvict(cacheNames = CachingSetup.AUTH_INFO_CACHE, allEntries = true)
public void clearAuthorizationInfoCache() {
authorizationInfoCache.remove();
}

@Transactional
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/org/ohdsi/webapi/util/CacheHelper.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package org.ohdsi.webapi.util;

import java.lang.management.ManagementFactory;
import java.util.HashSet;
import java.util.Set;
import javax.cache.CacheManager;
import javax.cache.configuration.MutableConfiguration;
import javax.cache.management.CacheStatisticsMXBean;
import javax.management.MBeanServer;
import javax.management.MBeanServerInvocationHandler;
Expand Down Expand Up @@ -33,4 +35,10 @@ public static CacheStatisticsMXBean getCacheStats(CacheManager cacheManager, Str
throw new RuntimeException(e);
}
}

public static Set<String> getCacheNames(CacheManager cacheManager) {
Set<String> cacheNames = new HashSet<>();
cacheManager.getCacheNames().forEach((name) -> cacheNames.add(name));
return cacheNames;
}
}
4 changes: 2 additions & 2 deletions src/test/java/org/ohdsi/webapi/security/PermissionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public void setup() {
ThreadContext.bind(subject);
}

@Ignore
// @Ignore
@Test
public void permsTest() throws Exception {
// need to clear authorization cache before each test
Expand All @@ -88,7 +88,7 @@ public void permsTest() throws Exception {

}

@Ignore
// @Ignore
@Test
public void wildcardTest() throws Exception {
// need to clear authorization cache before each test
Expand Down
42 changes: 21 additions & 21 deletions src/test/resources/permission/permsTest_PREP.json
Original file line number Diff line number Diff line change
@@ -1,64 +1,64 @@
{
"public.sec_user": [
{
"id":1001,
"id":100001,
"login":"permsTest",
"name":"Perms Test User",
"origin":"SYSTEM"
}
],
"public.sec_role": [
{
"id": 1001,
"id": 100001,
"name":"permsTest",
"system_role":false
}
],
"public.sec_permission" : [
{
"id": 1001,
"id": 100001,
"value":"printer:manage:printer1"
},
{
"id": 1002,
"id": 100002,
"value":"printer:manage:printer2"
},
{
"id": 1003,
"id": 100003,
"value":"printer:query:*"
},
{
"id": 1004,
"id": 100004,
"value":"printer:print"
}
],
"public.sec_role_permission" : [
{
"id":1001,
"role_id":1001,
"permission_id":1001
"id":100001,
"role_id":100001,
"permission_id":100001
},
{
"id":1002,
"role_id":1001,
"permission_id":1002
"id":100002,
"role_id":100001,
"permission_id":100002
},
{
"id":1003,
"role_id":1001,
"permission_id":1003
"id":103,
"role_id":100001,
"permission_id":100003
},
{
"id":1004,
"role_id":1001,
"permission_id":1004
"id":100004,
"role_id":100001,
"permission_id":100004
}
],
"public.sec_user_role": [
{
"id": 1001,
"user_id":1001,
"role_id":1001,
"id": 100001,
"user_id":100001,
"role_id":100001,
"origin":"SYSTEM"
}
]
Expand Down
Loading

0 comments on commit 0a77f67

Please sign in to comment.