net.bytebuddy
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/config/ApplicationConfig.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/config/ApplicationConfig.java
index ea5e43fe1..ae72e1393 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/config/ApplicationConfig.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/config/ApplicationConfig.java
@@ -2,6 +2,8 @@
import edu.harvard.hms.dbmi.avillach.auth.service.impl.CustomUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
@@ -10,6 +12,7 @@
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
@Configuration
+@EnableCaching
public class ApplicationConfig {
private final CustomUserDetailService customUserDetailService;
@@ -30,4 +33,9 @@ public AuthenticationProvider authenticationProvider() {
provider.setUserDetailsService(customUserDetailService);
return provider;
}
+
+ @Bean("customKeyGenerator")
+ public KeyGenerator generator() {
+ return new CustomKeyGenerator();
+ }
}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/config/CustomKeyGenerator.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/config/CustomKeyGenerator.java
new file mode 100644
index 000000000..74d4adb8b
--- /dev/null
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/config/CustomKeyGenerator.java
@@ -0,0 +1,20 @@
+package edu.harvard.hms.dbmi.avillach.auth.config;
+
+import edu.harvard.hms.dbmi.avillach.auth.entity.User;
+import org.springframework.cache.interceptor.KeyGenerator;
+
+import java.lang.reflect.Method;
+
+public class CustomKeyGenerator implements KeyGenerator {
+
+ @Override
+ public Object generate(Object target, Method method, Object... params) {
+ for (Object param : params) {
+ if (param instanceof User user) {
+ return user.getEmail();
+ }
+ }
+
+ throw new IllegalArgumentException("No valid params found. Cannot generate cache key");
+ }
+}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/config/SecurityConfig.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/config/SecurityConfig.java
index 04e741cca..b880d5df1 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/config/SecurityConfig.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/config/SecurityConfig.java
@@ -35,7 +35,14 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
.sessionManagement((session) -> session.sessionCreationPolicy(STATELESS))
.authenticationProvider(authenticationProvider)
.authorizeHttpRequests((authorizeRequests) ->
- authorizeRequests.requestMatchers("/actuator/health", "/actuator/info", "/authentication/**", "/swagger.yaml", "/swagger.json","/authentication", "/okta/authentication", "/open/authentication").permitAll()
+ authorizeRequests.requestMatchers(
+ "/actuator/health",
+ "/actuator/info",
+ "/authentication",
+ "/authentication/**",
+ "/swagger.yaml",
+ "/swagger.json"
+ ).permitAll()
.anyRequest().authenticated()
)
.httpBasic(AbstractHttpConfigurer::disable)
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/AccessRuleController.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/AccessRuleController.java
index 2af131647..2b877ec52 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/AccessRuleController.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/AccessRuleController.java
@@ -2,7 +2,7 @@
import edu.harvard.hms.dbmi.avillach.auth.entity.AccessRule;
import edu.harvard.hms.dbmi.avillach.auth.model.response.PICSUREResponse;
-import edu.harvard.hms.dbmi.avillach.auth.service.impl.authorization.AccessRuleService;
+import edu.harvard.hms.dbmi.avillach.auth.service.impl.AccessRuleService;
import io.swagger.v3.oas.annotations.*;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.RolesAllowed;
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/AuthController.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/AuthController.java
deleted file mode 100644
index 5210d6e30..000000000
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/AuthController.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package edu.harvard.hms.dbmi.avillach.auth.rest;
-
-import edu.harvard.hms.dbmi.avillach.auth.model.response.PICSUREResponse;
-import edu.harvard.hms.dbmi.avillach.auth.service.impl.authentication.Auth0AuthenticationService;
-import edu.harvard.hms.dbmi.avillach.auth.service.impl.authorization.AuthorizationService;
-import edu.harvard.hms.dbmi.avillach.auth.service.impl.authentication.FENCEAuthenticationService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import jakarta.servlet.http.HttpServletRequest;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-
-/**
- * The authentication endpoint for PSAMA.
- */
-@Tag(name = "Authentication")
-@Controller
-@RequestMapping("/")
-public class AuthController {
-
- private final static Logger logger = LoggerFactory.getLogger(AuthController.class.getName());
-
- public final AuthorizationService authorizationService;
-
- public final Auth0AuthenticationService authenticationService;
- public final FENCEAuthenticationService fenceAuthenticationService;
-
- private final String idp_provider;
-
- @Autowired
- public AuthController(AuthorizationService authorizationService, Auth0AuthenticationService authenticationService, FENCEAuthenticationService fenceAuthenticationService, @Value("${application.idp.provider}") String idpProvider) {
- this.authorizationService = authorizationService;
- this.authenticationService = authenticationService;
- this.fenceAuthenticationService = fenceAuthenticationService;
- this.idp_provider = idpProvider;
- }
-
- @Operation(description = "The authentication endpoint for retrieving a valid user token")
- @PostMapping(path = "/authentication", consumes = "application/json", produces = "application/json")
- public ResponseEntity> authentication(
- @Parameter(required = true, description = "A json object that includes all Oauth authentication needs, for example, access_token and redirectURI")
- @RequestBody Map authRequest, HttpServletRequest request) throws IOException {
- logger.debug("authentication() starting...");
- String requestHost = request.getServerName();
- logger.debug("authentication() requestHost: {}", requestHost);
-
- if(authRequest == null) {
- logger.error("authentication() authRequest is null");
- return ResponseEntity.badRequest().body("authRequest is null");
- }
-
- if (this.idp_provider.equalsIgnoreCase("fence")) {
- logger.debug("authentication() FENCE authentication");
- HashMap fenceProfile = fenceAuthenticationService.getFENCEProfile("https://" + requestHost + "/psamaui/login/", authRequest);
- return PICSUREResponse.success(fenceProfile);
- } else {
- logger.debug("authentication() default authentication");
- HashMap token = authenticationService.getToken(authRequest);
- return PICSUREResponse.success(token);
- }
- }
-}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/AuthenticationController.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/AuthenticationController.java
new file mode 100644
index 000000000..f1e281684
--- /dev/null
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/AuthenticationController.java
@@ -0,0 +1,71 @@
+package edu.harvard.hms.dbmi.avillach.auth.rest;
+
+import edu.harvard.hms.dbmi.avillach.auth.model.response.PICSUREResponse;
+import edu.harvard.hms.dbmi.avillach.auth.service.AuthenticationService;
+import edu.harvard.hms.dbmi.avillach.auth.service.impl.authentication.AuthenticationServiceRegistry;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpServletRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * The authentication endpoint for PSAMA.
+ */
+@Tag(name = "Authentication")
+@Controller
+@RequestMapping("/")
+public class AuthenticationController {
+
+ private final static Logger logger = LoggerFactory.getLogger(AuthenticationController.class.getName());
+
+ private final AuthenticationServiceRegistry authenticationServiceRegistry;
+
+ @Autowired
+ public AuthenticationController(AuthenticationServiceRegistry authenticationServiceRegistry) {
+ this.authenticationServiceRegistry = authenticationServiceRegistry;
+ }
+
+ @Operation(description = "The authentication endpoint for retrieving a valid user token")
+ @PostMapping(path = "/authentication/{idpProvider}", consumes = "application/json", produces = "application/json")
+ public ResponseEntity> authentication(
+ @PathVariable("idpProvider") String idpProvider,
+ @Parameter(required = true, description = "A json object that includes all Oauth authentication needs, for example, access_token and redirectURI")
+ @RequestBody Map authRequest, HttpServletRequest request) throws IOException {
+ logger.debug("authentication() starting...");
+ logger.debug("authentication() requestHost: {}", request.getServerName());
+
+ if (authRequest == null) {
+ logger.error("authentication() authRequest is null");
+ return ResponseEntity.badRequest().body("authRequest is null");
+ }
+
+ AuthenticationService authenticationService = authenticationServiceRegistry.getAuthenticationService(idpProvider);
+ if (authenticationService == null) {
+ logger.error("authentication() authenticationService is null");
+ return ResponseEntity.badRequest().body("authenticationService is null");
+ }
+
+ HashMap authenticate = authenticationService.authenticate(authRequest, request.getServerName());
+ if (authenticate != null && !authenticate.isEmpty()) {
+ logger.info("authentication() User authenticated successfully.");
+ return PICSUREResponse.success(authenticate);
+ }
+
+ logger.error("authentication() User not authenticated.");
+ return PICSUREResponse.unauthorizedError("User not authenticated.");
+ }
+}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/OktaAuthenticationController.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/OktaAuthenticationController.java
deleted file mode 100644
index f8d591c58..000000000
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/OktaAuthenticationController.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package edu.harvard.hms.dbmi.avillach.auth.rest;
-
-import edu.harvard.hms.dbmi.avillach.auth.model.response.PICSUREResponse;
-import edu.harvard.hms.dbmi.avillach.auth.service.impl.authentication.OktaOAuthAuthenticationService;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import jakarta.servlet.http.HttpServletRequest;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-
-import java.util.HashMap;
-import java.util.Map;
-
-@Tag(name = "Okta Authentication Controller", description = "The authentication endpoint for Okta.")
-@Controller
-@RequestMapping("/okta")
-public class OktaAuthenticationController {
- private final Logger logger = LoggerFactory.getLogger(this.getClass());
-
- private final OktaOAuthAuthenticationService oktaOAuthAuthenticationService;
- private final String idp_provider;
-
- @Autowired
- public OktaAuthenticationController(OktaOAuthAuthenticationService oktaOAuthAuthenticationService,
- @Value("${application.idp.provider}") String idp_provider) {
- this.oktaOAuthAuthenticationService = oktaOAuthAuthenticationService;
- this.idp_provider = idp_provider;
- }
-
- @PostMapping("/authentication")
- public ResponseEntity> authenticate(@RequestBody Map authRequest, HttpServletRequest request) {
- logger.info("OKTA LOGIN ATTEMPT ___ {} ___", authRequest.get("code"));
- String host = request.getServerName();
-
- String idp_provider = this.idp_provider;
- if (idp_provider.equalsIgnoreCase("okta")) {
- HashMap authenticate = oktaOAuthAuthenticationService.authenticate(host, authRequest);
- if (authenticate != null) {
- return PICSUREResponse.success(authenticate);
- } else {
- return PICSUREResponse.unauthorizedError("User not authenticated.");
- }
- } else {
- return PICSUREResponse.error("IDP provider not configured correctly.x");
- }
- }
-
-}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/OpenAuthenticationController.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/OpenAuthenticationController.java
deleted file mode 100644
index 4a8ccbec5..000000000
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/rest/OpenAuthenticationController.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package edu.harvard.hms.dbmi.avillach.auth.rest;
-
-import edu.harvard.hms.dbmi.avillach.auth.model.response.PICSUREResponse;
-import edu.harvard.hms.dbmi.avillach.auth.service.impl.authentication.OpenAuthenticationService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-
-import java.util.Map;
-
-/**
- * The authentication endpoint for PSAMA.
- */
-@Tag(name = "Open Authentication")
-@RequestMapping("/open")
-@Controller
-public class OpenAuthenticationController {
-
- private final Logger logger = LoggerFactory.getLogger(this.getClass());
-
- private final OpenAuthenticationService openAuthenticationService;
- private final String idp_provider;
-
- @Autowired
- public OpenAuthenticationController(OpenAuthenticationService openAuthenticationService, @Value("${application.idp.provider}") String idp_provider) {
- this.openAuthenticationService = openAuthenticationService;
- this.idp_provider = idp_provider;
- }
-
- @Operation(summary = "Authenticate a user using the open endpoint")
- @PostMapping(value = "/authentication", consumes = "application/json", produces = "application/json")
- public ResponseEntity> authentication(@Parameter(required = true, description = "A json object that includes all Oauth authentication needs, for example, access_token and redirectURI") Map authRequest) {
- logger.debug("authentication() starting...");
- if (!this.idp_provider.equalsIgnoreCase("fence")) {
- Map authenticate = openAuthenticationService.authenticate(authRequest);
- return PICSUREResponse.success(authenticate);
- }
-
- return PICSUREResponse.unauthorizedError("Not authorized.");
- }
-
-}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/AuthenticationService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/AuthenticationService.java
new file mode 100644
index 000000000..ff0e10045
--- /dev/null
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/AuthenticationService.java
@@ -0,0 +1,15 @@
+package edu.harvard.hms.dbmi.avillach.auth.service;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public interface AuthenticationService {
+
+ HashMap authenticate(Map authRequest, String requestHost) throws IOException;
+
+ String getProvider();
+
+ boolean isEnabled();
+
+}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/AccessRuleService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/AccessRuleService.java
new file mode 100644
index 000000000..746b30b7b
--- /dev/null
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/AccessRuleService.java
@@ -0,0 +1,995 @@
+package edu.harvard.hms.dbmi.avillach.auth.service.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.jayway.jsonpath.JsonPath;
+import com.jayway.jsonpath.PathNotFoundException;
+import com.mysql.cj.xdevapi.JsonArray;
+import edu.harvard.hms.dbmi.avillach.auth.entity.AccessRule;
+import edu.harvard.hms.dbmi.avillach.auth.entity.Application;
+import edu.harvard.hms.dbmi.avillach.auth.entity.Privilege;
+import edu.harvard.hms.dbmi.avillach.auth.entity.User;
+import edu.harvard.hms.dbmi.avillach.auth.repository.AccessRuleRepository;
+import jakarta.annotation.PostConstruct;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Service
+public class AccessRuleService {
+
+ private final Logger logger = LoggerFactory.getLogger(AccessRuleService.class);
+
+ private final AccessRuleRepository accessRuleRepo;
+ private final ObjectMapper objectMapper = new ObjectMapper();
+
+ private final ConcurrentHashMap accessRuleCache = new ConcurrentHashMap<>();
+ private Set allowQueryTypeRules;
+
+ private static final String parentAccessionField = "\\\\_Parent Study Accession with Subject ID\\\\";
+ private static final String topmedAccessionField = "\\\\_Topmed Study Accession with Subject ID\\\\";
+ private final String fence_harmonized_consent_group_concept_path;
+ private final String fence_parent_consent_group_concept_path;
+ private final String fence_topmed_consent_group_concept_path;
+ private final String fence_standard_access_rules;
+ private final String fence_allowed_query_types;
+ private final String fence_harmonized_concept_path;
+
+ private String[] underscoreFields;
+
+ @Autowired
+ public AccessRuleService(AccessRuleRepository accessRuleRepo,
+ @Value("${fence.harmonized.consent.group.concept.path}") String fenceHarmonizedConsentGroupConceptPath,
+ @Value("${fence.parent.consent.group.concept.path}") String fenceParentConceptPath,
+ @Value("${fence.topmed.consent.group.concept.path}") String fenceTopmedConceptPath,
+ @Value("${fence.standard.access.rules}") String fenceStandardAccessRules,
+ @Value("${fence.allowed.query.types}") String fenceAllowedQueryTypes,
+ @Value("${fence.consent.group.concept.path}") String fenceHarmonizedConceptPath) {
+ this.accessRuleRepo = accessRuleRepo;
+ this.fence_harmonized_consent_group_concept_path = fenceHarmonizedConsentGroupConceptPath;
+ this.fence_parent_consent_group_concept_path = fenceParentConceptPath;
+ this.fence_topmed_consent_group_concept_path = fenceTopmedConceptPath;
+ this.fence_standard_access_rules = fenceStandardAccessRules;
+ this.fence_allowed_query_types = fenceAllowedQueryTypes;
+ this.fence_harmonized_concept_path = fenceHarmonizedConceptPath;
+ }
+
+ @PostConstruct
+ public void init() {
+ // We need to set the underscoreFields here so that we can use them in the access rules during PostConstruct
+ // If we don't set them here, we will get a NullPointerException when we try to use them in the access rules
+ underscoreFields = new String[]{
+ parentAccessionField,
+ topmedAccessionField,
+ fence_harmonized_consent_group_concept_path,
+ fence_parent_consent_group_concept_path,
+ fence_topmed_consent_group_concept_path,
+ "\\\\_VCF Sample Id\\\\",
+ "\\\\_studies\\\\",
+ "\\\\_studies_consents\\\\", //used to provide consent-level counts for open access
+ "\\\\_parent_consents\\\\", //parent consents not used for auth (use combined _consents)
+ "\\\\_Consents\\\\" ///old _Consents\Short Study... path no longer used, but still present in examples.
+ };
+
+ logger.info("fence_standard_access_rules: {}", fence_standard_access_rules);
+ logger.info("fence_allowed_query_types: {}", fence_allowed_query_types);
+ logger.info("fence_harmonized_consent_group_concept_path: {}", fence_harmonized_consent_group_concept_path);
+ logger.info("fence_parent_consent_group_concept_path: {}", fence_parent_consent_group_concept_path);
+ logger.info("fence_topmed_consent_group_concept_path: {}", fence_topmed_consent_group_concept_path);
+ logger.info("fence_harmonized_concept_path: {}", fence_harmonized_concept_path);
+ logger.info("underscoreFields: {}", Arrays.toString(underscoreFields));
+ }
+
+ public Optional getAccessRuleById(String accessRuleId) {
+ return accessRuleRepo.findById(UUID.fromString(accessRuleId));
+ }
+
+ public List getAllAccessRules() {
+ return accessRuleRepo.findAll();
+ }
+
+ public List addAccessRule(List accessRules) {
+ accessRules.forEach(accessRule -> {
+ if (accessRule.getEvaluateOnlyByGates() == null)
+ accessRule.setEvaluateOnlyByGates(false);
+
+ if (accessRule.getCheckMapKeyOnly() == null)
+ accessRule.setCheckMapKeyOnly(false);
+
+ if (accessRule.getCheckMapNode() == null)
+ accessRule.setCheckMapNode(false);
+
+ if (accessRule.getGateAnyRelation() == null)
+ accessRule.setGateAnyRelation(false);
+ });
+
+ return this.accessRuleRepo.saveAll(accessRules);
+ }
+
+ public List updateAccessRules(List accessRules) {
+ return this.accessRuleRepo.saveAll(accessRules);
+ }
+
+ @Transactional
+ public List removeAccessRuleById(String accessRuleId) {
+ this.accessRuleRepo.deleteById(UUID.fromString(accessRuleId));
+ return this.accessRuleRepo.findAll();
+ }
+
+ public AccessRule save(AccessRule accessRule) {
+ return this.accessRuleRepo.save(accessRule);
+ }
+
+ public AccessRule getAccessRuleByName(String arName) {
+ return this.accessRuleRepo.findByName(arName);
+ }
+
+ @Cacheable(value = "mergedRulesCache", keyGenerator = "customKeyGenerator")
+ public Set getAccessRulesForUserAndApp(User user, Application application) {
+ try {
+ Set privileges = user.getPrivilegesByApplication(application);
+ if (privileges == null || privileges.isEmpty()) {
+ return new HashSet<>();
+ }
+
+ Set detachedMergedRules = new HashSet<>();
+ for (AccessRule rule : preProcessAccessRules(privileges)) {
+ detachedMergedRules.add(objectMapper.readValue(objectMapper.writeValueAsString(rule), AccessRule.class));
+ }
+
+ return detachedMergedRules;
+ } catch (Exception e) {
+ logger.error("Error populating or retrieving data from cache: ", e);
+ }
+
+ return new HashSet<>();
+ }
+
+ /**
+ * Evicts the user from all AccessRule caches
+ * @param email the email to evict
+ */
+ public void evictFromCache(String email) {
+ logger.info("evictFromCache called for user.email: {}", email);
+ evictFromMergedAccessRuleCache(email);
+ evictFromPreProcessedAccessRules(email);
+ }
+
+ @CacheEvict(value = "mergedRulesCache")
+ public void evictFromMergedAccessRuleCache(String email) {
+ if (email == null || email.isEmpty()) {
+ logger.warn("evictFromMergedAccessRuleCache() was called with a null or empty email");
+ return;
+ }
+ logger.info("evictFromMergedAccessRuleCache() evicting cache for user: {}", email);
+ }
+
+ @Cacheable(value = "preProcessedAccessRules", keyGenerator = "customKeyGenerator")
+ public Set cachedPreProcessAccessRules(User user, Set privileges) {
+ Set accessRules = new HashSet<>();
+ for (Privilege privilege : privileges) {
+ accessRules.addAll(privilege.getAccessRules());
+ }
+
+ return preProcessARBySortedKeys(accessRules);
+ }
+
+ public Set preProcessAccessRules(Set privileges) {
+ Set accessRules = new HashSet<>();
+ for (Privilege privilege : privileges) {
+ accessRules.addAll(privilege.getAccessRules());
+ }
+
+ return preProcessARBySortedKeys(accessRules);
+ }
+
+ @CacheEvict(value = "preProcessedAccessRules", key = "#email", condition = "#email!=null")
+ public void evictFromPreProcessedAccessRules(String email) {
+ if (email == null || email.isEmpty()) {
+ logger.warn("evictFromPreProcessedAccessRules() was called with a null or empty email");
+ return;
+ }
+ logger.info("evictFromPreProcessedAccessRules() evicting cache for user: {}", email);
+ }
+
+ public Set preProcessARBySortedKeys(Set accessRules) {
+ Map> accessRuleMap = new HashMap<>();
+
+ for (AccessRule accessRule : accessRules) {
+
+ // 1st generate the key by grabbing all related string and put them together in order
+ // we use a treeSet here to put orderly combine Strings together
+ Set keys = new TreeSet<>();
+
+ // the current accessRule rule
+ keys.add(accessRule.getRule());
+
+ // all gates' UUID as strings
+ keys.add(accessRule.getType().toString());
+
+ if (accessRule.getGates() != null) {
+ for (AccessRule gate : accessRule.getGates()) {
+ keys.add(gate.getUuid().toString());
+ }
+ }
+
+ // all sub accessRule rules
+ if (accessRule.getSubAccessRule() != null) {
+ for (AccessRule subAccessRule : accessRule.getSubAccessRule()) {
+ keys.add(subAccessRule.getRule());
+ }
+ }
+ Boolean checkMapKeyOnly = accessRule.getCheckMapKeyOnly(),
+ checkMapNode = accessRule.getCheckMapNode(),
+ evaluateOnlyByGates = accessRule.getEvaluateOnlyByGates(),
+ gateAnyRelation = accessRule.getGateAnyRelation();
+
+ keys.add(checkMapKeyOnly == null ? "null" : Boolean.toString(checkMapKeyOnly));
+ keys.add(checkMapNode == null ? "null" : Boolean.toString(checkMapNode));
+ keys.add(evaluateOnlyByGates == null ? "null" : Boolean.toString(evaluateOnlyByGates));
+ keys.add(gateAnyRelation == null ? "null" : Boolean.toString(gateAnyRelation));
+
+ String key = String.join("", keys);
+ if (accessRuleMap.containsKey(key)) {
+ accessRuleMap.get(key).add(accessRule);
+ } else {
+ Set accessRuleSet = new HashSet<>();
+ accessRuleSet.add(accessRule);
+ accessRuleMap.put(key, accessRuleSet);
+ }
+ }
+
+ return mergeSameKeyAccessRules(accessRuleMap.values());
+ }
+
+ private Set mergeSameKeyAccessRules(Collection> accessRuleMap) {
+ Set accessRules = new HashSet<>();
+ for (Set accessRulesSet : accessRuleMap) {
+ AccessRule accessRule = null;
+ for (AccessRule innerAccessRule : accessRulesSet) {
+ accessRule = mergeAccessRules(accessRule, innerAccessRule);
+ }
+ if (accessRule != null) {
+ accessRules.add(accessRule);
+ }
+ }
+ return accessRules;
+ }
+
+ private AccessRule mergeAccessRules(AccessRule baseAccessRule, AccessRule accessRuleToBeMerged) {
+ if (baseAccessRule == null) {
+ accessRuleToBeMerged.getMergedValues().add(accessRuleToBeMerged.getValue());
+ return accessRuleToBeMerged;
+ }
+
+ if (baseAccessRule.getSubAccessRule() != null && accessRuleToBeMerged.getSubAccessRule() != null) {
+ baseAccessRule.getSubAccessRule().addAll(accessRuleToBeMerged.getSubAccessRule());
+ } else if (baseAccessRule.getSubAccessRule() == null && accessRuleToBeMerged.getSubAccessRule() != null) {
+ baseAccessRule.setSubAccessRule(accessRuleToBeMerged.getSubAccessRule());
+ }
+
+ baseAccessRule.getMergedValues().add(accessRuleToBeMerged.getValue());
+ if (baseAccessRule.getMergedName().startsWith("Merged|")) {
+ baseAccessRule.setMergedName(baseAccessRule.getMergedName() + "|" + accessRuleToBeMerged.getName());
+ } else {
+ baseAccessRule.setMergedName("Merged|" + baseAccessRule.getName() + "|" + accessRuleToBeMerged.getName());
+ }
+
+ return baseAccessRule;
+ }
+
+ public boolean evaluateAccessRule(Object parsedRequestBody, AccessRule accessRule) {
+ logger.debug("evaluateAccessRule() starting with: {}", parsedRequestBody);
+ logger.debug("evaluateAccessRule() access rule: {}", accessRule.getName());
+
+ Set gates = accessRule.getGates();
+ boolean gatesPassed = true;
+
+ // depends on the flag getGateAnyRelation is true or false,
+ // the logic of checking if apply gate will be changed
+ // the following cases are gate passed:
+ // 1. if gates are null or empty
+ // 2. if getGateAnyRelation is false, all gates passed
+ // 3. if getGateAnyRelation is true, one of the gate passed
+ if (gates != null && !gates.isEmpty()) {
+ if (accessRule.getGateAnyRelation() == null || !accessRule.getGateAnyRelation()) {
+ // All gates are AND relationship
+ // means one fails all fail
+ for (AccessRule gate : gates) {
+ if (!evaluateAccessRule(parsedRequestBody, gate)) {
+ logger.error("evaluateAccessRule() gate {} failed: {} ____ {}", gate.getName(), gate.getRule(), gate.getValue());
+ gatesPassed = false;
+ break;
+ }
+ }
+ } else {
+ // All gates are OR relationship
+ // means one passes all pass
+ gatesPassed = false;
+ for (AccessRule gate : gates) {
+ if (evaluateAccessRule(parsedRequestBody, gate)) {
+ logger.debug("evaluateAccessRule() gate {} passed ", gate.getName());
+ gatesPassed = true;
+ break;
+ }
+ }
+
+ if (!gatesPassed) {
+ logger.debug("all OR gates failed");
+ }
+ }
+ }
+
+ if (accessRule.getEvaluateOnlyByGates() != null && accessRule.getEvaluateOnlyByGates()) {
+ logger.debug("evaluateAccessRule() eval only by gates");
+ return gatesPassed;
+ }
+
+ if (gatesPassed) {
+ logger.debug("evaluateAccessRule() gates passed");
+ if (!extractAndCheckRule(accessRule, parsedRequestBody)) {
+ logger.debug("Query Rejected by rule(1) {} :: {} :: {}", accessRule.getRule(), accessRule.getType(), accessRule.getValue());
+ return false;
+ } else {
+ if (accessRule.getSubAccessRule() != null) {
+ for (AccessRule subAccessRule : accessRule.getSubAccessRule()) {
+ if (!extractAndCheckRule(subAccessRule, parsedRequestBody)) {
+ logger.debug("Query Rejected by rule(2) {} :: {} :: {}", subAccessRule.getRule(), subAccessRule.getType(), subAccessRule.getValue());
+ return false;
+ }
+ }
+ }
+ }
+ } else {
+ logger.debug("evaluateAccessRule() gates failed");
+ return false;
+ }
+
+ return true;
+ }
+
+ public boolean extractAndCheckRule(AccessRule accessRule, Object parsedRequestBody) {
+ logger.debug("extractAndCheckRule() starting");
+ String rule = accessRule.getRule();
+
+ if (rule == null || rule.isEmpty())
+ return true;
+
+ Object requestBodyValue;
+ int accessRuleType = accessRule.getType();
+
+ try {
+ requestBodyValue = JsonPath.parse(parsedRequestBody).read(rule);
+
+ // Json parse will always return a list even when we want a map (to check keys)
+ if (requestBodyValue instanceof JsonArray && ((JsonArray) requestBodyValue).size() == 1) {
+ requestBodyValue = ((JsonArray) requestBodyValue).get(0);
+ }
+
+ } catch (PathNotFoundException ex) {
+ if (accessRuleType == AccessRule.TypeNaming.IS_EMPTY) {
+ // We could return accessRuleType == AccessRule.TypeNaming.IS_EMPTY directly, but we want to log the reason
+ logger.debug("extractAndCheckRule() -> JsonPath.parse().read() PathNotFound; passing IS_EMPTY rule");
+ return true;
+ }
+ logger.debug("extractAndCheckRule() -> JsonPath.parse().read() throws exception with parsedRequestBody - {} : {} - {}", parsedRequestBody, ex.getClass().getSimpleName(), ex.getMessage());
+ return false;
+ }
+
+ if (accessRuleType == AccessRule.TypeNaming.IS_EMPTY
+ || accessRuleType == AccessRule.TypeNaming.IS_NOT_EMPTY) {
+ if (requestBodyValue == null
+ || (requestBodyValue instanceof String && ((String) requestBodyValue).isEmpty())
+ || (requestBodyValue instanceof Collection && ((Collection) requestBodyValue).isEmpty())
+ || (requestBodyValue instanceof Map && ((Map) requestBodyValue).isEmpty())) {
+ return accessRuleType == AccessRule.TypeNaming.IS_EMPTY;
+ } else {
+ return accessRuleType == AccessRule.TypeNaming.IS_NOT_EMPTY;
+ }
+ }
+
+ return evaluateNode(requestBodyValue, accessRule);
+ }
+
+ private boolean evaluateNode(Object requestBodyValue, AccessRule accessRule) {
+ logger.debug("evaluateNode() starting: {} :: {} :: {}", accessRule.getRule(), accessRule.getType(), accessRule.getMergedValues().isEmpty() ? accessRule.getValue() : ("Merged " + Arrays.deepToString(accessRule.getMergedValues().toArray())));
+ logger.trace("evaluateNode() requestBody {} {}", requestBodyValue.getClass().getName(), requestBodyValue instanceof Collection ?
+ Arrays.deepToString(((Collection) requestBodyValue).toArray()) :
+ requestBodyValue.toString());
+
+ return switch (requestBodyValue) {
+ case String s -> decisionMaker(accessRule, s);
+ case Collection collection -> evaluateCollection(collection, accessRule);
+ case Map map when accessRule.getCheckMapNode() != null && accessRule.getCheckMapNode() ->
+ evaluateMap(requestBodyValue, accessRule);
+ default -> true;
+ };
+ }
+
+ private boolean evaluateMap(Object requestBodyValue, AccessRule accessRule) {
+ switch (accessRule.getType()) {
+ case (AccessRule.TypeNaming.ANY_EQUALS):
+ case (AccessRule.TypeNaming.ANY_CONTAINS):
+ case (AccessRule.TypeNaming.ANY_REG_MATCH):
+ for (Map.Entry entry : ((Map) requestBodyValue).entrySet()) {
+ if (decisionMaker(accessRule, (String) entry.getKey()))
+ return true;
+
+ if ((accessRule.getCheckMapKeyOnly() == null || !accessRule.getCheckMapKeyOnly())
+ && evaluateNode(entry.getValue(), accessRule))
+ return true;
+ }
+ return false;
+ default:
+ if (((Map) requestBodyValue).isEmpty()) {
+ switch (accessRule.getType()) {
+ case (AccessRule.TypeNaming.ALL_EQUALS_IGNORE_CASE):
+ case (AccessRule.TypeNaming.ALL_EQUALS):
+ case (AccessRule.TypeNaming.ALL_CONTAINS):
+ case (AccessRule.TypeNaming.ALL_CONTAINS_IGNORE_CASE):
+ return false;
+ case (AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY):
+ case (AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY_IGNORE_CASE):
+ default:
+ return true;
+ }
+ }
+ for (Map.Entry entry : ((Map) requestBodyValue).entrySet()) {
+ if (!decisionMaker(accessRule, (String) entry.getKey()))
+ return false;
+
+ if ((accessRule.getCheckMapKeyOnly() == null || !accessRule.getCheckMapKeyOnly())
+ && !evaluateNode(entry.getValue(), accessRule))
+ return false;
+ }
+
+ }
+
+ return true;
+ }
+
+ private Boolean evaluateCollection(Collection requestBodyValue, AccessRule accessRule) {
+ switch (accessRule.getType()) {
+ case (AccessRule.TypeNaming.ANY_EQUALS):
+ case (AccessRule.TypeNaming.ANY_CONTAINS):
+ case (AccessRule.TypeNaming.ANY_REG_MATCH):
+ for (Object item : requestBodyValue) {
+ if (item instanceof String) {
+ if (decisionMaker(accessRule, (String) item)) {
+ return true;
+ }
+ } else {
+ if (evaluateNode(item, accessRule)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ default:
+ if (requestBodyValue.isEmpty()) {
+ switch (accessRule.getType()) {
+ case (AccessRule.TypeNaming.ALL_EQUALS_IGNORE_CASE):
+ case (AccessRule.TypeNaming.ALL_EQUALS):
+ case (AccessRule.TypeNaming.ALL_CONTAINS):
+ case (AccessRule.TypeNaming.ALL_CONTAINS_IGNORE_CASE):
+ return false;
+ case (AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY):
+ case (AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY_IGNORE_CASE):
+ default:
+ return true;
+ }
+ }
+
+ for (Object item : requestBodyValue) {
+ if (item instanceof String) {
+ if (!decisionMaker(accessRule, (String) item)) {
+ return false;
+ }
+ } else {
+ if (!evaluateNode(item, accessRule))
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public boolean decisionMaker(AccessRule accessRule, String requestBodyValue) {
+ if (accessRule.getMergedValues().isEmpty()) {
+ String value = accessRule.getValue();
+ if (value == null) {
+ return requestBodyValue == null;
+ }
+ return _decisionMaker(accessRule, requestBodyValue, value);
+ }
+
+ // recursively check the values
+ // until one of them is true
+ // if there is only one element in the merged value set
+ // the operation equals to _decisionMaker(accessRule, requestBodyValue, value)
+ boolean res = false;
+ for (String s : accessRule.getMergedValues()) {
+ // check the special case value is null
+ // if value is null, the check will stop here and
+ // not goes to _decisionMaker()
+ if (s == null) {
+ if (requestBodyValue == null) {
+ res = true;
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ // all the merged values are OR relationship
+ // means if you pass one of them, you pass the rule
+ if (_decisionMaker(accessRule, requestBodyValue, s)) {
+ res = true;
+ break;
+ }
+ }
+ return res;
+ }
+
+ private boolean _decisionMaker(AccessRule accessRule, String requestBodyValue, String value) {
+ logger.debug("_decisionMaker() starting");
+ logger.debug("_decisionMaker() access rule:{}", accessRule.getName());
+ logger.debug(requestBodyValue);
+ logger.debug(value);
+
+ return switch (accessRule.getType()) {
+ case AccessRule.TypeNaming.NOT_CONTAINS -> !requestBodyValue.contains(value);
+ case AccessRule.TypeNaming.NOT_CONTAINS_IGNORE_CASE -> !requestBodyValue.toLowerCase().contains(value.toLowerCase());
+ case (AccessRule.TypeNaming.NOT_EQUALS) -> !value.equals(requestBodyValue);
+ case (AccessRule.TypeNaming.ANY_EQUALS), (AccessRule.TypeNaming.ALL_EQUALS) -> value.equals(requestBodyValue);
+ case (AccessRule.TypeNaming.ALL_CONTAINS), (AccessRule.TypeNaming.ANY_CONTAINS), (AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY) -> requestBodyValue.contains(value);
+ case (AccessRule.TypeNaming.ALL_CONTAINS_IGNORE_CASE), (AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY_IGNORE_CASE) -> requestBodyValue.toLowerCase().contains(value.toLowerCase());
+ case (AccessRule.TypeNaming.NOT_EQUALS_IGNORE_CASE) -> !value.equalsIgnoreCase(requestBodyValue);
+ case (AccessRule.TypeNaming.ALL_EQUALS_IGNORE_CASE) -> value.equalsIgnoreCase(requestBodyValue);
+ case (AccessRule.TypeNaming.ALL_REG_MATCH), (AccessRule.TypeNaming.ANY_REG_MATCH) -> requestBodyValue.matches(value);
+ default -> {
+ logger.warn("evaluateAccessRule() incoming accessRule type is out of scope. Just return true.");
+ yield true;
+ }
+ };
+ }
+
+ /**
+ * Configures the AccessRule with gates and sub-rules.
+ *
+ * @param ar The AccessRule to configure.
+ * @param studyIdentifier The study identifier.
+ * @param consent_group The consent group.
+ * @param conceptPath The concept path.
+ * @param projectAlias The project alias.
+ * @param parent Whether to include parent gates.
+ * @param harmonized Whether to include harmonized gates.
+ * @param topmed Whether to include Topmed gates.
+ */
+ protected void configureAccessRule(AccessRule ar, String studyIdentifier, String consent_group, String conceptPath, String projectAlias, boolean parent, boolean harmonized, boolean topmed) {
+ if (ar.getGates() == null) {
+ ar.setGates(new HashSet<>());
+ ar.getGates().addAll(getGates(parent, harmonized, topmed));
+
+ if (ar.getSubAccessRule() == null) {
+ ar.setSubAccessRule(new HashSet<>());
+ }
+ ar.getSubAccessRule().addAll(getAllowedQueryTypeRules());
+ ar.getSubAccessRule().addAll(getPhenotypeSubRules(studyIdentifier, conceptPath, projectAlias));
+ ar.getSubAccessRule().addAll(getTopmedRestrictedSubRules());
+ this.save(ar);
+ }
+ }
+
+ /**
+ * Configures the harmonized AccessRule with gates and sub-rules.
+ *
+ * @param ar The AccessRule to configure.
+ * @param studyIdentifier The study identifier.
+ * @param consent_group The consent group.
+ * @param conceptPath The concept path.
+ * @param projectAlias The project alias.
+ */
+ protected void configureHarmonizedAccessRule(AccessRule ar, String studyIdentifier, String consent_group, String conceptPath, String projectAlias) {
+ if (ar.getGates() == null) {
+ ar.setGates(new HashSet<>());
+ ar.getGates().add(upsertConsentGate("HARMONIZED_CONSENT", "$.query.query.categoryFilters." + fence_harmonized_consent_group_concept_path + "[*]", true, "harmonized data"));
+
+ if (ar.getSubAccessRule() == null) {
+ ar.setSubAccessRule(new HashSet<>());
+ }
+ ar.getSubAccessRule().addAll(getAllowedQueryTypeRules());
+ ar.getSubAccessRule().addAll(getHarmonizedSubRules());
+ ar.getSubAccessRule().addAll(getPhenotypeSubRules(studyIdentifier, conceptPath, projectAlias));
+ this.save(ar);
+ }
+ }
+
+ private Set getAllowedQueryTypeRules() {
+ if (allowQueryTypeRules == null) {
+ allowQueryTypeRules = loadAllowedQueryTypeRules();
+ }
+
+ return allowQueryTypeRules;
+ }
+
+ /**
+ * Retrieves or creates AccessRules for allowed query types.
+ *
+ * @return A set of AccessRules for allowed query types.
+ */
+ private Set loadAllowedQueryTypeRules() {
+ // Initialize a set to hold the AccessRules
+ Set rules = new HashSet<>();
+ // Split the allowed query types from the configuration
+ String[] allowedTypes = this.fence_allowed_query_types.split(",");
+
+ // Iterate over each allowed query type
+ for (String queryType : allowedTypes) {
+ // Construct the AccessRule name
+ String ar_name = "AR_ALLOW_" + queryType;
+
+ // Log the creation of a new AccessRule
+ AccessRule ar = getOrCreateAccessRule(
+ ar_name,
+ "MANAGED SUB AR to allow " + queryType + " Queries",
+ "$.query.query.expectedResultType",
+ AccessRule.TypeNaming.ALL_EQUALS,
+ queryType,
+ false,
+ false,
+ false,
+ false
+ );
+
+ // Add the newly created rule to the set
+ rules.add(ar);
+ }
+ // Return the set of AccessRules
+ return rules;
+ }
+
+ private Collection extends AccessRule> getTopmedRestrictedSubRules() {
+ Set rules = new HashSet();
+ rules.add(upsertTopmedRestrictedSubRule("CATEGORICAL", "$.query.query.variantInfoFilters[*].categoryVariantInfoFilters.*"));
+ rules.add(upsertTopmedRestrictedSubRule("NUMERIC", "$.query.query.variantInfoFilters[*].numericVariantInfoFilters.*"));
+
+ return rules;
+ }
+
+ /**
+ * Creates and returns a restricted sub-rule AccessRule for Topmed.
+ * topmed restriction rules don't need much configuration. Just deny all access.
+ *
+ * @param type The type of the Topmed restriction.
+ * @param rule The rule expression.
+ * @return The created AccessRule.
+ */
+ private AccessRule upsertTopmedRestrictedSubRule(String type, String rule) {
+ // Construct the AccessRule name
+ String ar_name = "AR_TOPMED_RESTRICTED_" + type;
+ // Check if the AccessRule already exists
+ AccessRule ar = this.getAccessRuleByName(ar_name);
+ if (ar != null) {
+ // Log and return the existing rule
+ logger.debug("Found existing rule: {}", ar.getName());
+ return ar;
+ }
+
+ // Log the creation of a new AccessRule
+ // Create the AccessRule using the createAccessRule method
+ return getOrCreateAccessRule(
+ ar_name,
+ "MANAGED SUB AR for restricting " + type + " genomic concepts",
+ rule,
+ AccessRule.TypeNaming.IS_EMPTY,
+ null,
+ false,
+ false,
+ false,
+ false
+ );
+ }
+
+ protected Collection extends AccessRule> getPhenotypeSubRules(String studyIdentifier, String conceptPath, String alias) {
+
+ Set rules = new HashSet();
+ //categorical filters will always contain at least one entry (for the consent groups); it will never be empty
+ rules.add(createPhenotypeSubRule(fence_parent_consent_group_concept_path, "ALLOW_PARENT_CONSENT", "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "", true));
+
+ for (String underscorePath : underscoreFields) {
+ rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.fields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "FIELDS", false));
+ rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "CATEGORICAL", true));
+ rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.requiredFields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "REQ_FIELDS", false));
+ }
+
+ rules.add(createPhenotypeSubRule(conceptPath, alias + "_" + studyIdentifier, "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "CATEGORICAL", true));
+ rules.add(createPhenotypeSubRule(conceptPath, alias + "_" + studyIdentifier, "$.query.query.numericFilters", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "NUMERIC", true));
+ rules.add(createPhenotypeSubRule(conceptPath, alias + "_" + studyIdentifier, "$.query.query.fields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "FIELDS", false));
+ rules.add(createPhenotypeSubRule(conceptPath, alias + "_" + studyIdentifier, "$.query.query.requiredFields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "REQUIRED_FIELDS", false));
+
+ return rules;
+ }
+
+ /**
+ * Harmonized rules should allow the user to supply paretn and top med consent groups; this allows a single harmonized
+ * rules instead of splitting between a topmed+harmonized and parent+harmonized
+ *
+ * @return
+ */
+ private Collection extends AccessRule> getHarmonizedSubRules() {
+
+ Set rules = new HashSet();
+ //categorical filters will always contain at least one entry (for the consent groups); it will never be empty
+ rules.add(createPhenotypeSubRule(fence_parent_consent_group_concept_path, "ALLOW_PARENT_CONSENT", "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "", true));
+ rules.add(createPhenotypeSubRule(fence_harmonized_consent_group_concept_path, "ALLOW_HARMONIZED_CONSENT", "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "", true));
+ rules.add(createPhenotypeSubRule(fence_topmed_consent_group_concept_path, "ALLOW_TOPMED_CONSENT", "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "", true));
+
+ for (String underscorePath : underscoreFields) {
+ rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.fields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "FIELDS", false));
+ rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "CATEGORICAL", true));
+ rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.requiredFields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "REQ_FIELDS", false));
+ }
+
+ rules.add(createPhenotypeSubRule(fence_harmonized_concept_path, "HARMONIZED", "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "CATEGORICAL", true));
+ rules.add(createPhenotypeSubRule(fence_harmonized_concept_path, "HARMONIZED", "$.query.query.numericFilters", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "NUMERIC", true));
+ rules.add(createPhenotypeSubRule(fence_harmonized_concept_path, "HARMONIZED", "$.query.query.fields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "FIELDS", false));
+ rules.add(createPhenotypeSubRule(fence_harmonized_concept_path, "HARMONIZED", "$.query.query.requiredFields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "REQUIRED_FIELDS", false));
+
+ return rules;
+ }
+
+
+ /**
+ * generate and return a set of rules that disallow access to phenotype data (only genomic filters allowed)
+ *
+ * @return
+ */
+ protected Collection extends AccessRule> getPhenotypeRestrictedSubRules(String studyIdentifier, String consentCode, String alias) {
+ Set rules = new HashSet();
+ //categorical filters will always contain at least one entry (for the consent groups); it will never be empty
+ rules.add(createPhenotypeSubRule(fence_topmed_consent_group_concept_path, "ALLOW_TOPMED_CONSENT", "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "", true));
+
+ for (String underscorePath : underscoreFields) {
+ rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.fields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "FIELDS", false));
+ rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "CATEGORICAL", true));
+ rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.requiredFields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "REQ_FIELDS", false));
+ }
+
+ rules.add(createPhenotypeSubRule(null, alias + "_" + studyIdentifier + "_" + consentCode, "$.query.query.numericFilters.[*]", AccessRule.TypeNaming.IS_EMPTY, "DISALLOW_NUMERIC", false));
+ rules.add(createPhenotypeSubRule(null, alias + "_" + studyIdentifier + "_" + consentCode, "$.query.query.requiredFields.[*]", AccessRule.TypeNaming.IS_EMPTY, "DISALLOW_REQUIRED_FIELDS", false));
+
+ return rules;
+ }
+
+ /**
+ * Return a set of gates that identify which consent values have been provided. the boolean parameters indicate
+ * if a value in the specified consent location should allow this gate to pass.
+ *
+ * @param parent
+ * @param harmonized
+ * @param topmed
+ * @return
+ */
+ private Collection extends AccessRule> getGates(boolean parent, boolean harmonized, boolean topmed) {
+ Set gates = new HashSet();
+ gates.add(upsertConsentGate("PARENT_CONSENT", "$.query.query.categoryFilters." + fence_parent_consent_group_concept_path + "[*]", parent, "parent study data"));
+ gates.add(upsertConsentGate("HARMONIZED_CONSENT", "$.query.query.categoryFilters." + fence_harmonized_consent_group_concept_path + "[*]", harmonized, "harmonized data"));
+ gates.add(upsertConsentGate("TOPMED_CONSENT", "$.query.query.categoryFilters." + fence_topmed_consent_group_concept_path + "[*]", topmed, "Topmed data"));
+
+ return gates;
+ }
+
+ protected void populateAccessRule(AccessRule rule, boolean includeParent, boolean includeHarmonized, boolean includeTopmed) {
+ if (rule.getGates() == null) {
+ rule.setGates(new HashSet<>(getGates(includeParent, includeHarmonized, includeTopmed)));
+ }
+
+ if (rule.getSubAccessRule() == null) {
+ rule.setSubAccessRule(new HashSet<>(getAllowedQueryTypeRules()));
+ }
+
+ this.save(rule);
+ }
+
+ protected void populateHarmonizedAccessRule(AccessRule rule, String parentConceptPath, String studyIdentifier, String projectAlias) {
+ if (rule.getGates() == null) {
+ rule.setGates(new HashSet<>(Collections.singletonList(
+ upsertConsentGate("HARMONIZED_CONSENT", "$.query.query.categoryFilters." + fence_harmonized_consent_group_concept_path + "[*]", true, "harmonized data")
+ )));
+ }
+
+ if (rule.getSubAccessRule() == null) {
+ rule.setSubAccessRule(new HashSet<>(getAllowedQueryTypeRules()));
+ rule.getSubAccessRule().addAll(getHarmonizedSubRules());
+ rule.getSubAccessRule().addAll(getPhenotypeSubRules(studyIdentifier, parentConceptPath, projectAlias));
+ }
+
+ this.save(rule);
+ }
+
+ // A set of standard access rules that are added to all privileges
+ // to cache the standard access rules
+ private Set standardAccessRules;
+
+ protected void addStandardAccessRules(Set accessRules) {
+ if (standardAccessRules != null && !standardAccessRules.isEmpty()) {
+ accessRules.addAll(standardAccessRules);
+ } else {
+ standardAccessRules = new HashSet<>();
+ for (String arName : fence_standard_access_rules.split(",")) {
+ if (arName.startsWith("AR_")) {
+ logger.info("Adding AccessRule {} to privilege", arName);
+ AccessRule ar = this.getAccessRuleByName(arName);
+ if (ar != null) {
+ standardAccessRules.add(ar);
+ } else {
+ logger.warn("Unable to find an access rule with name {}", arName);
+ }
+ }
+ }
+
+ accessRules.addAll(standardAccessRules);
+ }
+ }
+
+
+ /**
+ * Creates and returns a consent access rule AccessRule.
+ * Generates Main rule only; gates & sub-rules attached after calling this
+ * prentRule should be null if this is the main rule, or the appropriate value if this is a sub-rule
+ *
+ * @param studyIdentifier The study identifier.
+ * @param consent_group The consent group.
+ * @param label The label for the rule.
+ * @param consent_path The consent path.
+ * @return The created AccessRule.
+ */
+ protected AccessRule createConsentAccessRule(String studyIdentifier, String consent_group, String label, String consent_path) {
+ String ar_name = (consent_group != null && !consent_group.isEmpty()) ? "AR_CONSENT_" + studyIdentifier + "_" + consent_group + "_" + label : "AR_CONSENT_" + studyIdentifier;
+ String description = (consent_group != null && !consent_group.isEmpty()) ? "MANAGED AR for " + studyIdentifier + "." + consent_group + " clinical concepts" : "MANAGED AR for " + studyIdentifier + " clinical concepts";
+ String ruleText = "$.query.query.categoryFilters." + consent_path + "[*]";
+ String arValue = (consent_group != null && !consent_group.isEmpty()) ? studyIdentifier + "." + consent_group : studyIdentifier;
+
+ return getOrCreateAccessRule(
+ ar_name,
+ description,
+ ruleText,
+ AccessRule.TypeNaming.ALL_CONTAINS,
+ arValue,
+ false,
+ false,
+ false,
+ false
+ );
+ }
+
+ /**
+ * Creates and returns a Topmed access rule AccessRule.
+ * Generates Main Rule only; gates & sub-rules attached by calling method
+ *
+ * @param project_name The name of the project.
+ * @param consent_group The consent group.
+ * @param label The label for the rule.
+ * @return The created AccessRule.
+ */
+ protected AccessRule upsertTopmedAccessRule(String project_name, String consent_group, String label) {
+ String ar_name = (consent_group != null && !consent_group.isEmpty()) ? "AR_TOPMED_" + project_name + "_" + consent_group + "_" + label : "AR_TOPMED_" + project_name + "_" + label;
+ String description = "MANAGED AR for " + project_name + "." + consent_group + " Topmed data";
+ String ruleText = "$.query.query.categoryFilters." + fence_topmed_consent_group_concept_path + "[*]";
+ String arValue = (consent_group != null && !consent_group.isEmpty()) ? project_name + "." + consent_group : project_name;
+
+ return getOrCreateAccessRule(
+ ar_name,
+ description,
+ ruleText,
+ AccessRule.TypeNaming.ALL_CONTAINS,
+ arValue,
+ false,
+ false,
+ false,
+ false
+ );
+ }
+
+ /**
+ * Creates and returns a harmonized access rule AccessRule for Topmed.
+ * Generates Main Rule only; gates & sub rules attached by calling method
+ *
+ * @param project_name The name of the project.
+ * @param consent_group The consent group.
+ * @param label The label for the rule.
+ * @return The created AccessRule.
+ */
+ protected AccessRule upsertHarmonizedAccessRule(String project_name, String consent_group, String label) {
+ String ar_name = "AR_TOPMED_" + project_name + "_" + consent_group + "_" + label;
+ logger.info("upsertHarmonizedAccessRule() Creating new access rule {}", ar_name);
+ String description = "MANAGED AR for " + project_name + "." + consent_group + " Topmed data";
+ String ruleText = "$.query.query.categoryFilters." + fence_harmonized_consent_group_concept_path + "[*]";
+ String arValue = project_name + "." + consent_group;
+
+ return getOrCreateAccessRule(
+ ar_name,
+ description,
+ ruleText,
+ AccessRule.TypeNaming.ALL_CONTAINS,
+ arValue,
+ false,
+ false,
+ false,
+ false
+ );
+ }
+
+ /**
+ * Creates and returns a consent gate AccessRule.
+ * Insert a new gate (if it doesn't exist yet) to identify if consent values are present in the query.
+ * return an existing gate named GATE_{gateName}_(PRESENT|MISSING) if it exists.
+ *
+ * @param gateName The name of the gate.
+ * @param rule The rule expression.
+ * @param is_present Whether the gate is for present or missing consent.
+ * @param description The description of the gate.
+ * @return The created AccessRule.
+ */
+ private AccessRule upsertConsentGate(String gateName, String rule, boolean is_present, String description) {
+ gateName = "GATE_" + gateName + "_" + (is_present ? "PRESENT" : "MISSING");
+ return getOrCreateAccessRule(
+ gateName,
+ "MANAGED GATE for " + description + " consent " + (is_present ? "present" : "missing"),
+ rule,
+ is_present ? AccessRule.TypeNaming.IS_NOT_EMPTY : AccessRule.TypeNaming.IS_EMPTY,
+ null,
+ false,
+ false,
+ false,
+ false
+ );
+ }
+
+ private AccessRule createPhenotypeSubRule(String conceptPath, String alias, String rule, int ruleType, String label, boolean useMapKey) {
+ String ar_name = "AR_PHENO_" + alias + "_" + label;
+ logger.info("createPhenotypeSubRule() Creating new access rule {}", ar_name);
+ return getOrCreateAccessRule(
+ ar_name,
+ "MANAGED SUB AR for " + alias + " " + label + " clinical concepts",
+ rule,
+ ruleType,
+ ruleType == AccessRule.TypeNaming.IS_NOT_EMPTY ? null : conceptPath,
+ useMapKey,
+ useMapKey,
+ false,
+ false
+ );
+ }
+
+ private AccessRule getOrCreateAccessRule(String name, String description, String rule, int type, String value, boolean checkMapKeyOnly, boolean checkMapNode, boolean evaluateOnlyByGates, boolean gateAnyRelation) {
+ return accessRuleCache.computeIfAbsent(name, key -> {
+ AccessRule ar = this.getAccessRuleByName(key);
+ if (ar == null) {
+ logger.info("Creating new access rule {}", key);
+ ar = new AccessRule();
+ ar.setName(name);
+ ar.setDescription(description);
+ ar.setRule(rule);
+ ar.setType(type);
+ ar.setValue(value);
+ ar.setCheckMapKeyOnly(checkMapKeyOnly);
+ ar.setCheckMapNode(checkMapNode);
+ ar.setEvaluateOnlyByGates(evaluateOnlyByGates);
+ ar.setGateAnyRelation(gateAnyRelation);
+ this.save(ar);
+ }
+
+ return ar;
+ });
+ }
+}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/PrivilegeService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/PrivilegeService.java
index 8befa75cc..8d6fae8df 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/PrivilegeService.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/PrivilegeService.java
@@ -1,18 +1,26 @@
package edu.harvard.hms.dbmi.avillach.auth.service.impl;
+import edu.harvard.hms.dbmi.avillach.auth.entity.AccessRule;
+import edu.harvard.hms.dbmi.avillach.auth.entity.Application;
import edu.harvard.hms.dbmi.avillach.auth.entity.Privilege;
+import edu.harvard.hms.dbmi.avillach.auth.entity.Role;
+import edu.harvard.hms.dbmi.avillach.auth.model.fenceMapping.StudyMetaData;
import edu.harvard.hms.dbmi.avillach.auth.repository.PrivilegeRepository;
+import edu.harvard.hms.dbmi.avillach.auth.utils.FenceMappingUtility;
+import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import java.util.List;
-import java.util.Optional;
-import java.util.UUID;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
import static edu.harvard.hms.dbmi.avillach.auth.utils.AuthNaming.AuthRoleNaming.ADMIN;
@@ -22,10 +30,42 @@ public class PrivilegeService {
private final static Logger logger = LoggerFactory.getLogger(PrivilegeService.class.getName());
private final PrivilegeRepository privilegeRepository;
+ private final ApplicationService applicationService;
+ private final AccessRuleService accessRuleService;
+ private final FenceMappingUtility fenceMappingUtility;
+
+ private Application picSureApp;
+ private final String variantAnnotationColumns;
+
+ private final String fence_harmonized_consent_group_concept_path;
+ private final String fence_parent_consent_group_concept_path;
+ private final String fence_topmed_consent_group_concept_path;
+
+ private String fence_harmonized_concept_path;
+ private static final String topmedAccessionField = "\\\\_Topmed Study Accession with Subject ID\\\\";
@Autowired
- protected PrivilegeService(PrivilegeRepository privilegeRepository) {
+ protected PrivilegeService(PrivilegeRepository privilegeRepository, ApplicationService applicationService, AccessRuleService accessRuleService, FenceMappingUtility fenceMappingUtility,
+ @Value("${fence.variant.annotation.columns}") String variantAnnotationColumns,
+ @Value("${fence.harmonized.consent.group.concept.path}") String fenceHarmonizedConsentGroupConceptPath,
+ @Value("${fence.parent.consent.group.concept.path}") String fenceParentConceptPath,
+ @Value("${fence.topmed.consent.group.concept.path}") String fenceTopmedConceptPath,
+ @Value("${fence.consent.group.concept.path}") String fenceHarmonizedConceptPath) {
this.privilegeRepository = privilegeRepository;
+ this.applicationService = applicationService;
+ this.accessRuleService = accessRuleService;
+ this.fenceMappingUtility = fenceMappingUtility;
+ this.variantAnnotationColumns = variantAnnotationColumns;
+ this.fence_harmonized_consent_group_concept_path = fenceHarmonizedConsentGroupConceptPath;
+ this.fence_parent_consent_group_concept_path = fenceParentConceptPath;
+ this.fence_topmed_consent_group_concept_path = fenceTopmedConceptPath;
+ this.fence_harmonized_concept_path = fenceHarmonizedConceptPath;
+ }
+
+ @PostConstruct
+ private void init() {
+ picSureApp = applicationService.getApplicationByName("PICSURE");
+ logger.info("variantAnnotationColumns: {}", variantAnnotationColumns);
}
@Transactional
@@ -37,7 +77,7 @@ public List deletePrivilegeByPrivilegeId(String privilegeId) {
// Get the principal name from the security context
String principalName = securityContext.getAuthentication().getName();
- if (ADMIN.equals(privilege.get().getName())) {
+ if (ADMIN.equals(privilege.get().getName())) {
logger.info("User: {}, is trying to remove the system admin privilege: " + ADMIN, principalName);
throw new RuntimeException("System Admin privilege cannot be removed - uuid: " + privilege.get().getUuid().toString()
+ ", name: " + privilege.get().getName());
@@ -71,4 +111,297 @@ public Privilege findByName(String privilegeName) {
public Privilege save(Privilege privilege) {
return this.privilegeRepository.save(privilege);
}
+
+ public Set addPrivileges(Role r) {
+ String roleName = r.getName();
+ logger.info("addFENCEPrivileges() starting, adding privilege(s) to role {}", roleName);
+
+ //each project can have up to three privileges: Parent | Harmonized | Topmed
+ //harmonized has 2 ARs for parent + harminized and harmonized only
+ //Topmed has up to three ARs for topmed / topmed + parent / topmed + harmonized
+ Set privs = r.getPrivileges();
+ if (privs == null) {
+ privs = new HashSet();
+ }
+
+ //e.g. FENCE_phs0000xx_c2 or FENCE_tutorial-biolinc_camp
+ String project_name = extractProject(roleName);
+ if (project_name.length() <= 0) {
+ logger.warn("addFENCEPrivileges() role name: {} returned an empty project name", roleName);
+ }
+ String consent_group = extractConsentGroup(roleName);
+ if (consent_group.length() <= 0) {
+ logger.warn("addFENCEPrivileges() role name: {} returned an empty consent group", roleName);
+ }
+ logger.info("addFENCEPrivileges() project name: {} consent group: {}", project_name, consent_group);
+
+ // Look up the metadata by consent group.
+ StudyMetaData projectMetadata = getFENCEMappingforProjectAndConsent(project_name, consent_group);
+
+ if (projectMetadata == null) {
+ //no privileges means no access to this project. just return existing set of privs.
+ logger.warn("No metadata available for project {}.{}", project_name, consent_group);
+ return privs;
+ }
+
+ logger.info("addPrivileges() This is a new privilege");
+
+ String dataType = projectMetadata.getDataType();
+ Boolean isHarmonized = projectMetadata.getIsHarmonized();
+ String concept_path = projectMetadata.getTopLevelPath();
+ String projectAlias = projectMetadata.getAbbreviatedName();
+
+ // we need to add escape sequence back in to the path for parsing later (also need to double escape the regex)
+ // we need to do this for the query Template and scopes, but should NOT do this for the rules.
+ if (concept_path != null) {
+ concept_path = concept_path.replaceAll("\\\\", "\\\\\\\\");
+ }
+
+ if (dataType != null && dataType.contains("G")) {
+ //insert genomic/topmed privs - this will also add rules for including harmonized & parent data if applicable
+ privs.add(upsertTopmedPrivilege(project_name, projectAlias, consent_group, concept_path, isHarmonized));
+ }
+
+ if (dataType != null && dataType.contains("P")) {
+ //insert clinical privs
+ logger.info("addPrivileges() project:{} consent_group:{} concept_path:{}", project_name, consent_group, concept_path);
+ privs.add(upsertClinicalPrivilege(project_name, projectAlias, consent_group, concept_path, false));
+
+ //if harmonized study, also create harmonized privileges
+ if (Boolean.TRUE.equals(isHarmonized)) {
+ privs.add(upsertClinicalPrivilege(project_name, projectAlias, consent_group, concept_path, true));
+ }
+ }
+
+ //projects without G or P in data_type are skipped
+ if (dataType == null || (!dataType.contains("P") && !dataType.contains("G"))) {
+ logger.warn("Missing study type for {} {}. Skipping.", project_name, consent_group);
+ }
+
+ logger.info("addPrivileges() Finished");
+ return privs;
+ }
+
+ /**
+ * Creates a privilege with a set of access rules that allow queries containing a consent group to pass if the query only contains valid entries that match conceptPath. If the study is harmonized,
+ * this also creates an access rule to allow access when using the harmonized consent concept path.
+ * Privileges created with this method will deny access if any genomic filters (topmed data) are included.
+ *
+ * @param studyIdentifier The study identifier
+ * @param consent_group The consent group
+ * @param conceptPath The concept path
+ * @param isHarmonized Whether the study is harmonized
+ * @return The created privilege
+ */
+ private Privilege upsertClinicalPrivilege(String studyIdentifier, String projectAlias, String consent_group, String conceptPath, boolean isHarmonized) {
+ // Construct the privilege name
+ String privilegeName = (consent_group != null && !consent_group.isEmpty()) ?
+ "PRIV_MANAGED_" + studyIdentifier + "_" + consent_group + (isHarmonized ? "_HARMONIZED" : "") :
+ "PRIV_MANAGED_" + studyIdentifier + (isHarmonized ? "_HARMONIZED" : "");
+
+ // Check if the Privilege already exists
+ Privilege priv = this.findByName(privilegeName);
+ if (priv != null) {
+ logger.info("{} already exists", privilegeName);
+ return priv;
+ }
+
+ priv = new Privilege();
+ try {
+ priv.setApplication(picSureApp);
+ priv.setName(privilegeName);
+
+ // Set consent concept path
+ String consent_concept_path = isHarmonized ? fence_harmonized_consent_group_concept_path : fence_parent_consent_group_concept_path;
+ if (!consent_concept_path.contains("\\\\")) {
+ consent_concept_path = consent_concept_path.replaceAll("\\\\", "\\\\\\\\");
+ logger.debug("Escaped consent concept path: {}", consent_concept_path);
+ }
+
+ if (fence_harmonized_concept_path != null && !fence_harmonized_concept_path.contains("\\\\")) {
+ //these have to be escaped again so that jaxson can convert it correctly
+ fence_harmonized_concept_path = fence_harmonized_concept_path.replaceAll("\\\\", "\\\\\\\\");
+ logger.debug("upsertTopmedPrivilege(): escaped harmonized consent path" + fence_harmonized_concept_path);
+ }
+
+
+ String studyIdentifierField = (consent_group != null && !consent_group.isEmpty()) ? studyIdentifier + "." + consent_group : studyIdentifier;
+ String queryTemplateText = String.format(
+ "{\"categoryFilters\": {\"%s\":[\"%s\"]},\"numericFilters\":{},\"requiredFields\":[],\"fields\":[],\"variantInfoFilters\":[{\"categoryVariantInfoFilters\":{},\"numericVariantInfoFilters\":{}}],\"expectedResultType\": \"COUNT\"}",
+ consent_concept_path, studyIdentifierField
+ );
+
+ priv.setQueryTemplate(queryTemplateText);
+ priv.setQueryScope(isHarmonized ? String.format("[\"%s\",\"_\",\"%s\"]", conceptPath, fence_harmonized_concept_path) : String.format("[\"%s\",\"_\"]", conceptPath));
+
+ // Initialize the set of AccessRules
+ Set accessrules = new HashSet<>();
+
+ // Create and add the parent consent access rule
+ AccessRule ar = this.accessRuleService.createConsentAccessRule(studyIdentifier, consent_group, "PARENT", fence_parent_consent_group_concept_path);
+ this.accessRuleService.configureAccessRule(ar, studyIdentifier, consent_group, conceptPath, projectAlias, true, false, false);
+ accessrules.add(ar);
+
+ // Create and add the Topmed+Parent access rule
+ ar = this.accessRuleService.upsertTopmedAccessRule(studyIdentifier, consent_group, "TOPMED+PARENT");
+ this.accessRuleService.configureAccessRule(ar, studyIdentifier, consent_group, conceptPath, projectAlias, true, false, true);
+ accessrules.add(ar);
+
+ // If harmonized, create and add the harmonized access rule
+ if (isHarmonized) {
+ ar = this.accessRuleService.createConsentAccessRule(studyIdentifier, consent_group, "HARMONIZED", fence_harmonized_consent_group_concept_path);
+ this.accessRuleService.configureHarmonizedAccessRule(ar, studyIdentifier, consent_group, conceptPath, projectAlias);
+ accessrules.add(ar);
+ }
+
+ // Add standard access rules
+ this.accessRuleService.addStandardAccessRules(accessrules);
+
+ priv.setAccessRules(accessrules);
+ logger.info("Added {} access_rules to privilege", accessrules.size());
+
+ this.save(priv);
+ logger.info("Added new privilege {} to DB", priv.getName());
+ } catch (Exception ex) {
+ logger.error("Could not save privilege", ex);
+ }
+ return priv;
+ }
+
+ /**
+ * Creates a privilege for Topmed access. This has (up to) three access rules:
+ * 1) topmed only 2) topmed + parent 3) topmed + harmonized.
+ *
+ * @param studyIdentifier
+ * @param projectAlias
+ * @param consentGroup
+ * @param parentConceptPath
+ * @param isHarmonized
+ * @return Privilege
+ */
+ private Privilege upsertTopmedPrivilege(String studyIdentifier, String projectAlias, String consentGroup, String parentConceptPath, boolean isHarmonized) {
+ String privilegeName = "PRIV_MANAGED_" + studyIdentifier + "_" + consentGroup + "_TOPMED";
+ Privilege priv = this.findByName(privilegeName);
+
+ if (priv != null) {
+ logger.info("upsertTopmedPrivilege() {} already exists", privilegeName);
+ return priv;
+ }
+
+ priv = new Privilege();
+
+ try {
+ buildPrivilegeObject(priv, privilegeName, studyIdentifier, consentGroup);
+
+ Set accessRules = new HashSet<>();
+ AccessRule topmedRule = this.accessRuleService.upsertTopmedAccessRule(studyIdentifier, consentGroup, "TOPMED");
+
+ this.accessRuleService.populateAccessRule(topmedRule, false, false, true);
+ topmedRule.getSubAccessRule().addAll(this.accessRuleService.getPhenotypeRestrictedSubRules(studyIdentifier, consentGroup, projectAlias));
+ accessRules.add(topmedRule);
+
+ if (parentConceptPath != null) {
+ AccessRule topmedParentRule = this.accessRuleService.upsertTopmedAccessRule(studyIdentifier, consentGroup, "TOPMED+PARENT");
+ this.accessRuleService.populateAccessRule(topmedParentRule, true, false, true);
+ topmedParentRule.getSubAccessRule().addAll(this.accessRuleService.getPhenotypeSubRules(studyIdentifier, parentConceptPath, projectAlias));
+ accessRules.add(topmedParentRule);
+
+ if (isHarmonized) {
+ AccessRule harmonizedRule = this.accessRuleService.upsertHarmonizedAccessRule(studyIdentifier, consentGroup, "HARMONIZED");
+ this.accessRuleService.populateHarmonizedAccessRule(harmonizedRule, parentConceptPath, studyIdentifier, projectAlias);
+ accessRules.add(harmonizedRule);
+ }
+ }
+
+ this.accessRuleService.addStandardAccessRules(accessRules);
+
+ priv.setAccessRules(accessRules);
+ logger.info("upsertTopmedPrivilege() Added {} access_rules to privilege", accessRules.size());
+
+ this.save(priv);
+ logger.info("upsertTopmedPrivilege() Added new privilege {} to DB", priv.getName());
+ } catch (Exception ex) {
+ logger.error("upsertTopmedPrivilege() could not save privilege", ex);
+ }
+
+ return priv;
+ }
+
+ private void buildPrivilegeObject(Privilege priv, String privilegeName, String studyIdentifier, String consentGroup) {
+ priv.setApplication(picSureApp);
+ priv.setName(privilegeName);
+ priv.setDescription("MANAGED privilege for Topmed " + studyIdentifier + "." + consentGroup);
+
+ String consentConceptPath = escapePath(fence_topmed_consent_group_concept_path);
+ fence_harmonized_concept_path = escapePath(fence_harmonized_concept_path);
+
+ String queryTemplateText = "{\"categoryFilters\": {\"" + consentConceptPath + "\":[\"" + studyIdentifier + "." + consentGroup + "\"]},"
+ + "\"numericFilters\":{},\"requiredFields\":[],"
+ + "\"fields\":[\"" + topmedAccessionField + "\"],"
+ + "\"variantInfoFilters\":[{\"categoryVariantInfoFilters\":{},\"numericVariantInfoFilters\":{}}],"
+ + "\"expectedResultType\": \"COUNT\""
+ + "}";
+
+ priv.setQueryTemplate(queryTemplateText);
+
+ priv.setQueryScope(buildQueryScope(this.variantAnnotationColumns));
+ }
+
+ private String escapePath(String path) {
+ if (path != null && !path.contains("\\\\")) {
+ return path.replaceAll("\\\\", "\\\\\\\\");
+ }
+ return path;
+ }
+
+ private String buildQueryScope(String variantColumns) {
+ if (variantColumns == null || variantColumns.isEmpty()) {
+ return "[\"_\"]";
+ }
+
+ return Arrays.stream(variantColumns.split(","))
+ .map(path -> "\"" + path + "\"")
+ .collect(Collectors.joining(",", "[", ",\"_\"]"));
+ }
+
+ private String extractProject(String roleName) {
+ String projectPattern = "MANAGED_(.*?)(?:_c\\d+)?$";
+ if (roleName.startsWith("MANUAL_")) {
+ projectPattern = "MANUAL_(.*?)(?:_c\\d+)?$";
+ }
+ Pattern projectRegex = Pattern.compile(projectPattern);
+ Matcher projectMatcher = projectRegex.matcher(roleName);
+ String project = "";
+ if (projectMatcher.find()) {
+ project = projectMatcher.group(1).trim();
+ } else {
+ logger.info("extractProject() Could not extract project from role name: {}", roleName);
+ String[] parts = roleName.split("_", 1);
+ if (parts.length > 0) {
+ project = parts[1];
+ }
+ }
+ return project;
+ }
+
+ private static String extractConsentGroup(String roleName) {
+ String consentPattern = "MANAGED_.*?_c(\\d+)$";
+ if (roleName.startsWith("MANUAL_")) {
+ consentPattern = "MANUAL_.*?_c(\\d+)$";
+ }
+ Pattern consentRegex = Pattern.compile(consentPattern);
+ Matcher consentMatcher = consentRegex.matcher(roleName);
+ String consentGroup = "";
+ if (consentMatcher.find()) {
+ consentGroup = "c" + consentMatcher.group(1).trim();
+ }
+ return consentGroup;
+ }
+
+ private StudyMetaData getFENCEMappingforProjectAndConsent(String projectId, String consent_group) {
+ String consentVal = (consent_group != null && !consent_group.isEmpty()) ? projectId + "." + consent_group : projectId;
+ logger.info("getFENCEMappingforProjectAndConsent() looking up {}", consentVal);
+
+ return this.fenceMappingUtility.getFENCEMapping().get(consentVal);
+ }
}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/RoleService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/RoleService.java
index 69d8d5453..8aced3c4f 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/RoleService.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/RoleService.java
@@ -2,10 +2,13 @@
import edu.harvard.hms.dbmi.avillach.auth.entity.Privilege;
import edu.harvard.hms.dbmi.avillach.auth.entity.Role;
+import edu.harvard.hms.dbmi.avillach.auth.entity.User;
import edu.harvard.hms.dbmi.avillach.auth.enums.SecurityRoles;
import edu.harvard.hms.dbmi.avillach.auth.model.CustomUserDetails;
import edu.harvard.hms.dbmi.avillach.auth.repository.PrivilegeRepository;
import edu.harvard.hms.dbmi.avillach.auth.repository.RoleRepository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
@@ -13,21 +16,22 @@
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
-import java.util.logging.Logger;
import java.util.stream.Collectors;
@Service
public class RoleService {
- private final static Logger logger = Logger.getLogger(RoleService.class.getName());
+ private final Logger logger = LoggerFactory.getLogger(RoleService.class);
private final RoleRepository roleRepository;
private final PrivilegeRepository privilegeRepo;
+ private final PrivilegeService privilegeService;
@Autowired
- protected RoleService(RoleRepository roleRepository, PrivilegeRepository privilegeRepo) {
+ protected RoleService(RoleRepository roleRepository, PrivilegeRepository privilegeRepo, PrivilegeService privilegeService) {
this.roleRepository = roleRepository;
this.privilegeRepo = privilegeRepo;
+ this.privilegeService = privilegeService;
}
public Optional getRoleById(String roleId) {
@@ -124,12 +128,85 @@ public List persistAll(List newRoles) {
return this.roleRepository.saveAll(newRoles);
}
- public void persistAll(Set newRoles) {
- this.roleRepository.saveAll(newRoles);
+ public List persistAll(Set newRoles) {
+ return this.roleRepository.saveAll(newRoles);
}
public Role findByName(String roleName) {
return this.roleRepository.findByName(roleName);
}
+
+ public Role createRole(String roleName, String roleDescription) {
+ if (roleName.isEmpty()) {
+ logger.info("createRole() roleName is empty");
+ return null;
+ }
+ logger.info("getFENCEProfile() New PSAMA role name:{}", roleName);
+ Role r;
+ // Create the Role in the repository, if it does not exist. Otherwise, add it.
+ Role existing_role = findByName(roleName);
+ if (existing_role != null) {
+ // Role already exists
+ logger.info("upsertRole() role already exists");
+ r = existing_role;
+ } else {
+ // This is a new Role
+ r = new Role();
+ r.setName(roleName);
+ r.setDescription(roleDescription);
+ // Since this is a new Role, we need to ensure that the
+ // corresponding Privilege (with gates) and AccessRule is added.
+ r.setPrivileges(privilegeService.addPrivileges(r));
+ logger.info("upsertRole() created new role");
+ }
+
+ return r;
+ }
+
+ /**
+ * Insert or Update the User object's list of Roles in the database.
+ *
+ * @param u The User object the generated Role will be added to
+ * @param roleName Name of the Role
+ * @param roleDescription Description of the Role
+ * @return boolean Whether the Role was successfully added to the User or not
+ */
+ public boolean upsertRole(User u, String roleName, String roleDescription) {
+ boolean status = false;
+
+ // Get the User's list of Roles. The first time, this will be an empty Set.
+ // This method is called for every Role, and the User's list of Roles will
+ // be updated for all subsequent calls.
+ try {
+ Role r = null;
+ // Create the Role in the Servicesitory, if it does not exist. Otherwise, add it.
+ Role existing_role = this.getRoleByName(roleName);
+ if (existing_role != null) {
+ // Role already exists
+ logger.info("upsertRole() role already exists");
+ r = existing_role;
+ } else {
+ // This is a new Role
+ r = new Role();
+ r.setName(roleName);
+ r.setDescription(roleDescription);
+ // Since this is a new Role, we need to ensure that the
+ // corresponding Privilege (with gates) and AccessRule is added.
+ r.setPrivileges(privilegeService.addPrivileges(r));
+ this.save(r);
+ logger.info("upsertRole() created new role");
+ }
+ if (u != null) {
+ u.getRoles().add(r);
+ }
+ status = true;
+ } catch (Exception ex) {
+ logger.error("upsertRole() Could not inser/update role {} to Service", roleName, ex);
+ }
+
+
+ logger.debug("upsertRole() finished");
+ return status;
+ }
}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/StudyAccessService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/StudyAccessService.java
index b0453820f..0c03bed7d 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/StudyAccessService.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/StudyAccessService.java
@@ -1,7 +1,6 @@
package edu.harvard.hms.dbmi.avillach.auth.service.impl;
import edu.harvard.hms.dbmi.avillach.auth.model.fenceMapping.StudyMetaData;
-import edu.harvard.hms.dbmi.avillach.auth.service.impl.authentication.FENCEAuthenticationService;
import edu.harvard.hms.dbmi.avillach.auth.utils.FenceMappingUtility;
import io.swagger.v3.oas.annotations.Parameter;
import org.apache.commons.lang3.StringUtils;
@@ -14,19 +13,17 @@
@Service
public class StudyAccessService {
+ private final Logger logger = LoggerFactory.getLogger(StudyAccessService.class);
+
private final FenceMappingUtility fenceMappingUtility;
- Logger logger = LoggerFactory.getLogger(StudyAccessService.class);
+ private final RoleService roleService;
public static final String MANUAL = "MANUAL_";
- public static final String STUDY_IDENTIFIER = "study_identifier";
- public static final String CONSENT_GROUP_CODE = "consent_group_code";
-
- private final FENCEAuthenticationService fenceAuthenticationService;
@Autowired
- public StudyAccessService(FENCEAuthenticationService fenceAuthenticationService, FenceMappingUtility fenceMappingUtility) {
- this.fenceAuthenticationService = fenceAuthenticationService;
+ public StudyAccessService(FenceMappingUtility fenceMappingUtility, RoleService roleService) {
this.fenceMappingUtility = fenceMappingUtility;
+ this.roleService = roleService;
}
public String addStudyAccess(@Parameter(description="The Study Identifier of the new study from the metadata.json")
@@ -58,7 +55,7 @@ public String addStudyAccess(@Parameter(description="The Study Identifier of the
String newRoleName = StringUtils.isNotBlank(consentCode) ? MANUAL+projectId+"_"+consentCode : MANUAL+projectId;
logger.debug("addStudyAccess - New manual PSAMA role name: {}", newRoleName);
- if (fenceAuthenticationService.upsertRole(null, newRoleName, MANUAL + " role "+newRoleName)) {
+ if (roleService.upsertRole(null, newRoleName, MANUAL + " role "+newRoleName)) {
logger.info("addStudyAccess - Updated user role. Now it includes `{}`", newRoleName);
return "Role '" + newRoleName + "' successfully created";
} else {
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/UserService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/UserService.java
index 25fdcc837..e8e9b504e 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/UserService.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/UserService.java
@@ -404,7 +404,7 @@ public Map getDefaultQueryTemplate() {
return Map.of("queryTemplate", mergedTemplate.orElse(null));
}
- @Cacheable(value = "mergedTemplateCache", key = "#user.getEmail()")
+ @Cacheable(value = "mergedTemplateCache", keyGenerator = "customKeyGenerator")
public String mergeTemplate(User user, Application application) {
String resultJSON;
Map mergedTemplateMap = null;
@@ -444,9 +444,13 @@ public String mergeTemplate(User user, Application application) {
return resultJSON;
}
- @CacheEvict(value = "mergedTemplateCache", key = "#user.getEmail()")
- public void evictFromCache(User user) {
- logger.info("evictMergedTemplate() evicting cache for user: {}", user.getUuid());
+ @CacheEvict(value = "mergedTemplateCache")
+ public void evictFromCache(String email) {
+ if (email == null || email.isEmpty()) {
+ logger.warn("evictFromCache() was called with a null or empty email");
+ return;
+ }
+ logger.info("evictFromCache() evicting cache for user: {}", email);
}
@Transactional
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/Auth0AuthenticationService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/Auth0AuthenticationService.java
index d6f56b745..0d7d2a330 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/Auth0AuthenticationService.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/Auth0AuthenticationService.java
@@ -7,6 +7,7 @@
import edu.harvard.hms.dbmi.avillach.auth.entity.Connection;
import edu.harvard.hms.dbmi.avillach.auth.exceptions.NotAuthorizedException;
import edu.harvard.hms.dbmi.avillach.auth.repository.ConnectionRepository;
+import edu.harvard.hms.dbmi.avillach.auth.service.AuthenticationService;
import edu.harvard.hms.dbmi.avillach.auth.service.impl.BasicMailService;
import edu.harvard.hms.dbmi.avillach.auth.service.impl.OauthUserMatchingService;
import edu.harvard.hms.dbmi.avillach.auth.service.impl.UserService;
@@ -36,20 +37,19 @@
*/
@Service
-public class Auth0AuthenticationService {
+public class Auth0AuthenticationService implements AuthenticationService {
private final Logger logger = LoggerFactory.getLogger(Auth0AuthenticationService.class);
private final OauthUserMatchingService matchingService;
-
private final UserRepository userRepository;
-
private final BasicMailService basicMailService;
-
private final UserService userService;
+
private static final int AUTH_RETRY_LIMIT = 3;
+ private final boolean isAuth0Enabled;
- private String deniedEmailEnabled;
+ private boolean deniedEmailEnabled;
private final String auth0host;
@@ -58,8 +58,16 @@ public class Auth0AuthenticationService {
private final RestClientUtil restClientUtil;
@Autowired
- public Auth0AuthenticationService(OauthUserMatchingService matchingService, UserRepository userRepository, BasicMailService basicMailService, UserService userService,
- @Value("${application.denied.email.enabled}") String deniedEmailEnabled, @Value("${application.auth0.host}") String auth0host, ConnectionRepository connectionRepository, RestClientUtil restClientUtil) {
+ public Auth0AuthenticationService(OauthUserMatchingService matchingService,
+ UserRepository userRepository,
+ BasicMailService basicMailService,
+ UserService userService,
+ ConnectionRepository connectionRepository,
+ RestClientUtil restClientUtil,
+ @Value("${auth0.idp.provider.is.enabled}") boolean isAuth0Enabled,
+ @Value("${auth0.denied.email.enabled}") boolean deniedEmailEnabled,
+ @Value("${auth0.host}") String auth0host
+ ) {
this.matchingService = matchingService;
this.userRepository = userRepository;
this.basicMailService = basicMailService;
@@ -68,9 +76,11 @@ public Auth0AuthenticationService(OauthUserMatchingService matchingService, User
this.auth0host = auth0host;
this.connectionRepository = connectionRepository;
this.restClientUtil = restClientUtil;
+ this.isAuth0Enabled = isAuth0Enabled;
}
- public HashMap getToken(Map authRequest) throws IOException {
+ @Override
+ public HashMap authenticate(Map authRequest, String requestHost) throws IOException {
String accessToken = authRequest.get("access_token");
String redirectURI = authRequest.get("redirectURI");
@@ -102,7 +112,7 @@ public HashMap getToken(Map authRequest) throws
//Try to match
user = matchingService.matchTokenToUser(userInfo);
if (user == null) {
- if (this.deniedEmailEnabled.startsWith("true")) {
+ if (this.deniedEmailEnabled) {
try {
basicMailService.sendDeniedAccessEmail(userInfo);
} catch (jakarta.mail.MessagingException e) {
@@ -123,6 +133,16 @@ public HashMap getToken(Map authRequest) throws
return responseMap;
}
+ @Override
+ public String getProvider() {
+ return "auth0";
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return this.isAuth0Enabled;
+ }
+
public JsonNode retrieveUserInfo(String accessToken) throws IOException {
String auth0UserInfoURI = this.auth0host + "/userinfo";
HttpHeaders headers = new HttpHeaders();
@@ -136,7 +156,7 @@ public JsonNode retrieveUserInfo(String accessToken) throws IOException {
ResponseEntity response = this.restClientUtil.retrieveGetResponseWithRequestConfiguration(
auth0UserInfoURI,
headers,
- this.createRequestConfigWithCustomTimeout(2000)
+ RestClientUtil.createRequestConfigWithCustomTimeout(2000)
);
auth0Response = objectMapper.readTree(response.getBody());
@@ -152,14 +172,7 @@ public JsonNode retrieveUserInfo(String accessToken) throws IOException {
return auth0Response;
}
- public ClientHttpRequestFactory createRequestConfigWithCustomTimeout(int timeoutMs) {
- SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
- requestFactory.setConnectTimeout(timeoutMs);
- requestFactory.setReadTimeout(timeoutMs);
- return requestFactory;
- }
-
- public void setDeniedEmailEnabled(String deniedEmailEnabled) {
+ public void setDeniedEmailEnabled(boolean deniedEmailEnabled) {
this.deniedEmailEnabled = deniedEmailEnabled;
}
}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/AuthenticationServiceRegistry.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/AuthenticationServiceRegistry.java
new file mode 100644
index 000000000..f744a5d07
--- /dev/null
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/AuthenticationServiceRegistry.java
@@ -0,0 +1,42 @@
+package edu.harvard.hms.dbmi.avillach.auth.service.impl.authentication;
+
+import edu.harvard.hms.dbmi.avillach.auth.service.AuthenticationService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Component
+public class AuthenticationServiceRegistry {
+
+ private final Logger logger = LoggerFactory.getLogger(AuthenticationServiceRegistry.class);
+
+ private final Map authenticationServices = new HashMap<>();
+
+ @Autowired
+ public AuthenticationServiceRegistry(List authenticationServices) {
+ authenticationServices.forEach(authenticationService -> {
+ logger.info("Registering authentication service: {}", authenticationService.getProvider());
+ if (authenticationService.isEnabled()) {
+ this.authenticationServices.put(authenticationService.getProvider(), authenticationService);
+ logger.info("Registered authentication service: {}", authenticationService.getProvider());
+ } else {
+ logger.info("Skipping registration of disabled authentication service: {}", authenticationService.getProvider());
+ }
+ });
+ }
+
+ public AuthenticationService getAuthenticationService(String provider) {
+ // Check if the provider is registered by the provider name
+ if (!authenticationServices.containsKey(provider)) {
+ throw new IllegalArgumentException("No authentication service found for provider: " + provider);
+ }
+
+ return authenticationServices.get(provider);
+ }
+
+}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/FENCEAuthenticationService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/FENCEAuthenticationService.java
index 0dffb59b9..690c51b85 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/FENCEAuthenticationService.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/FENCEAuthenticationService.java
@@ -4,16 +4,14 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
-import edu.harvard.hms.dbmi.avillach.auth.entity.AccessRule;
-import edu.harvard.hms.dbmi.avillach.auth.entity.Application;
import edu.harvard.hms.dbmi.avillach.auth.entity.Connection;
-import edu.harvard.hms.dbmi.avillach.auth.entity.Privilege;
import edu.harvard.hms.dbmi.avillach.auth.entity.Role;
import edu.harvard.hms.dbmi.avillach.auth.entity.User;
import edu.harvard.hms.dbmi.avillach.auth.exceptions.NotAuthorizedException;
import edu.harvard.hms.dbmi.avillach.auth.model.fenceMapping.StudyMetaData;
+import edu.harvard.hms.dbmi.avillach.auth.service.AuthenticationService;
import edu.harvard.hms.dbmi.avillach.auth.service.impl.*;
-import edu.harvard.hms.dbmi.avillach.auth.service.impl.authorization.AccessRuleService;
+import edu.harvard.hms.dbmi.avillach.auth.service.impl.AccessRuleService;
import edu.harvard.hms.dbmi.avillach.auth.utils.FenceMappingUtility;
import edu.harvard.hms.dbmi.avillach.auth.utils.RestClientUtil;
import org.apache.commons.lang3.StringUtils;
@@ -32,129 +30,65 @@
import org.springframework.util.MultiValueMap;
import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Service
-public class FENCEAuthenticationService {
+public class FENCEAuthenticationService implements AuthenticationService {
private final Logger logger = LoggerFactory.getLogger(FENCEAuthenticationService.class);
private final UserService userService;
private final RoleService roleService;
private final ConnectionWebService connectionService; // We will need to investigate if the ConnectionWebService will need to be versioned as well.
- private final ApplicationService applicationService;
- private final PrivilegeService privilegeService;
private final AccessRuleService accessRuleService;
private final FenceMappingUtility fenceMappingUtility;
- private Application picSureApp;
private Connection fenceConnection;
private final Set openAccessIdpValues = Set.of("fence", "ras");
+ private final boolean isFenceEnabled;
private final String idp_provider_uri;
private final String fence_client_id;
private final String fence_client_secret;
- private final String idp_provider;
- private final String fence_standard_access_rules;
- private final String fence_allowed_query_types;
- private final String variantAnnotationColumns;
- private final String templatePath;
- private final String fence_harmonized_consent_group_concept_path;
- private final String fence_parent_consent_group_concept_path;
- private final String fence_topmed_consent_group_concept_path;
- private String fence_harmonized_concept_path;
- private static final String parentAccessionField = "\\\\_Parent Study Accession with Subject ID\\\\";
- private static final String topmedAccessionField = "\\\\_Topmed Study Accession with Subject ID\\\\";
- public static final String fence_open_access_role_name = "FENCE_ROLE_OPEN_ACCESS";
-
- private String[] underscoreFields;
+ public static final String fence_open_access_role_name = "MANAGED_ROLE_OPEN_ACCESS";
private final RestClientUtil restClientUtil;
- private final ConcurrentHashMap accessRuleCache = new ConcurrentHashMap<>();
- private Set allowQueryTypeRules;
-
@Autowired
public FENCEAuthenticationService(UserService userService,
RoleService roleService,
ConnectionWebService connectionService,
- ApplicationService applicationService,
- PrivilegeService privilegeService,
RestClientUtil restClientUtil,
- @Value("${application.idp.provider.uri}") String idpProviderUri,
+ @Value("${fence.idp.provider.is.enabled}") boolean isFenceEnabled,
+ @Value("${fence.idp.provider.uri}") String idpProviderUri,
@Value("${fence.client.id}") String fenceClientId,
@Value("${fence.client.secret}") String fenceClientSecret,
- @Value("${application.idp.provider}") String idpProvider,
- @Value("${fence.standard.access.rules}") String fenceStandardAccessRules,
- @Value("${fence.allowed.query.types}") String fenceAllowedQueryTypes,
- @Value("${fence.variant.annotation.columns}") String variantAnnotationColumns,
- @Value("${application.template.path}") String templatePath,
- @Value("${fence.harmonized.consent.group.concept.path}") String fenceHarmonizedConsentGroupConceptPath,
- @Value("${fence.parent.consent.group.concept.path}") String fenceParentConceptPath,
- @Value("${fence.topmed.consent.group.concept.path}") String fenceTopmedConceptPath,
- @Value("${fence.consent.group.concept.path}") String fenceHarmonizedConceptPath,
- AccessRuleService accessRuleService, FenceMappingUtility fenceMappingUtility) {
+ AccessRuleService accessRuleService,
+ FenceMappingUtility fenceMappingUtility) {
this.userService = userService;
this.roleService = roleService;
this.connectionService = connectionService;
- this.applicationService = applicationService;
- this.privilegeService = privilegeService;
this.idp_provider_uri = idpProviderUri;
this.fence_client_id = fenceClientId;
this.fence_client_secret = fenceClientSecret;
- this.idp_provider = idpProvider;
- this.fence_standard_access_rules = fenceStandardAccessRules;
- this.fence_allowed_query_types = fenceAllowedQueryTypes;
- this.variantAnnotationColumns = variantAnnotationColumns;
- this.templatePath = templatePath;
this.restClientUtil = restClientUtil;
this.accessRuleService = accessRuleService;
- this.fence_parent_consent_group_concept_path = fenceParentConceptPath;
- this.fence_topmed_consent_group_concept_path = fenceTopmedConceptPath;
- this.fence_harmonized_concept_path = fenceHarmonizedConceptPath;
- this.fence_harmonized_consent_group_concept_path = fenceHarmonizedConsentGroupConceptPath;
this.fenceMappingUtility = fenceMappingUtility;
+ this.isFenceEnabled = isFenceEnabled;
}
@EventListener(ContextRefreshedEvent.class)
public void initializeFenceService() {
- picSureApp = applicationService.getApplicationByName("PICSURE");
fenceConnection = connectionService.getConnectionByLabel("FENCE");
- // We need to set the underscoreFields here so that we can use them in the access rules during PostConstruct
- // If we don't set them here, we will get a NullPointerException when we try to use them in the access rules
- underscoreFields = new String[]{
- parentAccessionField,
- topmedAccessionField,
- fence_harmonized_consent_group_concept_path,
- fence_parent_consent_group_concept_path,
- fence_topmed_consent_group_concept_path,
- "\\\\_VCF Sample Id\\\\",
- "\\\\_studies\\\\",
- "\\\\_studies_consents\\\\", //used to provide consent-level counts for open access
- "\\\\_parent_consents\\\\", //parent consents not used for auth (use combined _consents)
- "\\\\_Consents\\\\" ///old _Consents\Short Study... path no longer used, but still present in examples.
- };
-
// log all the properties
+ logger.info("isFenceEnabled: {}", isFenceEnabled);
logger.info("idp_provider_uri: {}", idp_provider_uri);
- logger.info("idp_provider: {}", idp_provider);
- logger.info("fence_standard_access_rules: {}", fence_standard_access_rules);
- logger.info("fence_allowed_query_types: {}", fence_allowed_query_types);
- logger.info("variantAnnotationColumns: {}", variantAnnotationColumns);
- logger.info("templatePath: {}", templatePath);
- logger.info("fence_harmonized_consent_group_concept_path: {}", fence_harmonized_consent_group_concept_path);
- logger.info("fence_parent_consent_group_concept_path: {}", fence_parent_consent_group_concept_path);
- logger.info("fence_topmed_consent_group_concept_path: {}", fence_topmed_consent_group_concept_path);
- logger.info("fence_harmonized_concept_path: {}", fence_harmonized_concept_path);
- logger.info("underscoreFields: {}", Arrays.toString(underscoreFields));
- if (!fenceMappingUtility.getFENCEMapping().isEmpty() && !fenceMappingUtility.getFenceMappingByAuthZ().isEmpty()) {
+ if (fenceMappingUtility.getFENCEMapping() != null && fenceMappingUtility.getFenceMappingByAuthZ() != null
+ && !fenceMappingUtility.getFENCEMapping().isEmpty() && !fenceMappingUtility.getFenceMappingByAuthZ().isEmpty()) {
// Create all potential access rules using the fence mapping
Set roles = fenceMappingUtility.getFenceMappingByAuthZ().values().parallelStream().map(projectMetadata -> {
if (projectMetadata == null) {
@@ -174,9 +108,9 @@ public void initializeFenceService() {
String projectId = projectMetadata.getStudyIdentifier();
String consentCode = projectMetadata.getConsentGroupCode();
- String newRoleName = StringUtils.isNotBlank(consentCode) ? "FENCE_" + projectId + "_" + consentCode : "FENCE_" + projectId;
+ String newRoleName = StringUtils.isNotBlank(consentCode) ? "MANAGED_" + projectId + "_" + consentCode : "MANAGED_" + projectId;
- return createRole(newRoleName, "FENCE role " + newRoleName);
+ return this.roleService.createRole(newRoleName, "MANAGED role " + newRoleName);
}).filter(Objects::nonNull).collect(Collectors.toSet());
roleService.persistAll(roles);
@@ -185,7 +119,10 @@ public void initializeFenceService() {
}
}
- public HashMap getFENCEProfile(String callback_url, Map authRequest) {
+ @Override
+ public HashMap authenticate(Map authRequest, String host) {
+ String callBackUrl = "https://" + host + "/psamaui/login/";
+
logger.debug("getFENCEProfile() starting...");
String fence_code = authRequest.get("code");
@@ -199,8 +136,8 @@ public HashMap getFENCEProfile(String callback_url, Map getFENCEProfile(String callback_url, Map getFENCEProfile(String callback_url, Map "PIC-SURE Top Admin".equals(userRole.getName()) || "Admin".equals(userRole.getName()) || userRole.getName().startsWith("MANUAL_")
Set rolesToRemove = current_user.getRoles().parallelStream()
@@ -266,7 +210,7 @@ public HashMap getFENCEProfile(String callback_url, Map newRoles = roleNames.parallelStream()
- .map(roleName -> createRole(roleName, "FENCE role " + roleName))
+ .map(roleName -> this.roleService.createRole(roleName, "MANAGED role " + roleName))
.filter(Objects::nonNull)
.collect(Collectors.toList());
@@ -303,31 +247,14 @@ public HashMap getFENCEProfile(String callback_url, Map fence_user_profile_response = this.restClientUtil.retrieveGetResponse(
+ ResponseEntity fence_user_profile_response = this.restClientUtil.retrieveGetResponseWithRequestConfiguration(
this.idp_provider_uri + "/user/user",
- headers
+ headers,
+ RestClientUtil.createRequestConfigWithCustomTimeout(10000)
);
// Map the response to a JsonNode object
@@ -428,774 +356,4 @@ private User createUserFromFENCEProfile(JsonNode node) {
return actual_user;
}
- /**
- * Insert or Update the User object's list of Roles in the database.
- *
- * @param u The User object the generated Role will be added to
- * @param roleName Name of the Role
- * @param roleDescription Description of the Role
- * @return boolean Whether the Role was successfully added to the User or not
- */
- public boolean upsertRole(User u, String roleName, String roleDescription) {
- boolean status = false;
-
- // Get the User's list of Roles. The first time, this will be an empty Set.
- // This method is called for every Role, and the User's list of Roles will
- // be updated for all subsequent calls.
- try {
- Role r = null;
- // Create the Role in the Servicesitory, if it does not exist. Otherwise, add it.
- Role existing_role = roleService.getRoleByName(roleName);
- if (existing_role != null) {
- // Role already exists
- logger.info("upsertRole() role already exists");
- r = existing_role;
- } else {
- // This is a new Role
- r = new Role();
- r.setName(roleName);
- r.setDescription(roleDescription);
- // Since this is a new Role, we need to ensure that the
- // corresponding Privilege (with gates) and AccessRule is added.
- r.setPrivileges(addFENCEPrivileges(r));
- roleService.save(r);
- logger.info("upsertRole() created new role");
- }
- if (u != null) {
- u.getRoles().add(r);
- }
- status = true;
- } catch (Exception ex) {
- logger.error("upsertRole() Could not inser/update role {} to Service", roleName, ex);
- }
-
-
- logger.debug("upsertRole() finished");
- return status;
- }
-
- private Set addFENCEPrivileges(Role r) {
- String roleName = r.getName();
- logger.info("addFENCEPrivileges() starting, adding privilege(s) to role {}", roleName);
-
- //each project can have up to three privileges: Parent | Harmonized | Topmed
- //harmonized has 2 ARs for parent + harminized and harmonized only
- //Topmed has up to three ARs for topmed / topmed + parent / topmed + harmonized
- Set privs = r.getPrivileges();
- if (privs == null) {
- privs = new HashSet();
- }
-
- //e.g. FENCE_phs0000xx_c2 or FENCE_tutorial-biolinc_camp
- String project_name = extractProject(roleName);
- if (project_name.length() <= 0) {
- logger.warn("addFENCEPrivileges() role name: {} returned an empty project name", roleName);
- }
- String consent_group = extractConsentGroup(roleName);
- if (consent_group.length() <= 0) {
- logger.warn("addFENCEPrivileges() role name: {} returned an empty consent group", roleName);
- }
- logger.info("addFENCEPrivileges() project name: {} consent group: {}", project_name, consent_group);
-
- // Look up the metadata by consent group.
- StudyMetaData projectMetadata = getFENCEMappingforProjectAndConsent(project_name, consent_group);
-
- if (projectMetadata == null) {
- //no privileges means no access to this project. just return existing set of privs.
- logger.warn("No metadata available for project {}.{}", project_name, consent_group);
- return privs;
- }
-
- logger.info("addPrivileges() This is a new privilege");
-
- String dataType = projectMetadata.getDataType();
- Boolean isHarmonized = projectMetadata.getIsHarmonized();
- String concept_path = projectMetadata.getTopLevelPath();
- String projectAlias = projectMetadata.getAbbreviatedName();
-
- // we need to add escape sequence back in to the path for parsing later (also need to double escape the regex)
- // we need to do this for the query Template and scopes, but should NOT do this for the rules.
- if (concept_path != null) {
- concept_path = concept_path.replaceAll("\\\\", "\\\\\\\\");
- }
-
- if (dataType != null && dataType.contains("G")) {
- //insert genomic/topmed privs - this will also add rules for including harmonized & parent data if applicable
- privs.add(upsertTopmedPrivilege(project_name, projectAlias, consent_group, concept_path, isHarmonized));
- }
-
- if (dataType != null && dataType.contains("P")) {
- //insert clinical privs
- logger.info("addPrivileges() project:{} consent_group:{} concept_path:{}", project_name, consent_group, concept_path);
- privs.add(upsertClinicalPrivilege(project_name, projectAlias, consent_group, concept_path, false));
-
- //if harmonized study, also create harmonized privileges
- if (Boolean.TRUE.equals(isHarmonized)) {
- privs.add(upsertClinicalPrivilege(project_name, projectAlias, consent_group, concept_path, true));
- }
- }
-
- //projects without G or P in data_type are skipped
- if (dataType == null || (!dataType.contains("P") && !dataType.contains("G"))) {
- logger.warn("Missing study type for {} {}. Skipping.", project_name, consent_group);
- }
-
- logger.info("addPrivileges() Finished");
- return privs;
- }
-
- /**
- * Creates a privilege with a set of access rules that allow queries containing a consent group to pass if the query only contains valid entries that match conceptPath. If the study is harmonized,
- * this also creates an access rule to allow access when using the harmonized consent concept path.
- * Privileges created with this method will deny access if any genomic filters (topmed data) are included.
- *
- * @param studyIdentifier The study identifier
- * @param consent_group The consent group
- * @param conceptPath The concept path
- * @param isHarmonized Whether the study is harmonized
- * @return The created privilege
- */
- private Privilege upsertClinicalPrivilege(String studyIdentifier, String projectAlias, String consent_group, String conceptPath, boolean isHarmonized) {
- // Construct the privilege name
- String privilegeName = (consent_group != null && !consent_group.isEmpty()) ?
- "PRIV_FENCE_" + studyIdentifier + "_" + consent_group + (isHarmonized ? "_HARMONIZED" : "") :
- "PRIV_FENCE_" + studyIdentifier + (isHarmonized ? "_HARMONIZED" : "");
-
- // Check if the Privilege already exists
- Privilege priv = privilegeService.findByName(privilegeName);
- if (priv != null) {
- logger.info("{} already exists", privilegeName);
- return priv;
- }
-
- priv = new Privilege();
- try {
- priv.setApplication(picSureApp);
- priv.setName(privilegeName);
-
- // Set consent concept path
- String consent_concept_path = isHarmonized ? fence_harmonized_consent_group_concept_path : fence_parent_consent_group_concept_path;
- if (!consent_concept_path.contains("\\\\")) {
- consent_concept_path = consent_concept_path.replaceAll("\\\\", "\\\\\\\\");
- logger.debug("Escaped consent concept path: {}", consent_concept_path);
- }
-
- if (fence_harmonized_concept_path != null && !fence_harmonized_concept_path.contains("\\\\")) {
- //these have to be escaped again so that jaxson can convert it correctly
- fence_harmonized_concept_path = fence_harmonized_concept_path.replaceAll("\\\\", "\\\\\\\\");
- logger.debug("upsertTopmedPrivilege(): escaped harmonized consent path" + fence_harmonized_concept_path);
- }
-
-
- String studyIdentifierField = (consent_group != null && !consent_group.isEmpty()) ? studyIdentifier + "." + consent_group : studyIdentifier;
- String queryTemplateText = String.format(
- "{\"categoryFilters\": {\"%s\":[\"%s\"]},\"numericFilters\":{},\"requiredFields\":[],\"fields\":[],\"variantInfoFilters\":[{\"categoryVariantInfoFilters\":{},\"numericVariantInfoFilters\":{}}],\"expectedResultType\": \"COUNT\"}",
- consent_concept_path, studyIdentifierField
- );
-
- priv.setQueryTemplate(queryTemplateText);
- priv.setQueryScope(isHarmonized ? String.format("[\"%s\",\"_\",\"%s\"]", conceptPath, fence_harmonized_concept_path) : String.format("[\"%s\",\"_\"]", conceptPath));
-
- // Initialize the set of AccessRules
- Set accessrules = new HashSet<>();
-
- // Create and add the parent consent access rule
- AccessRule ar = createConsentAccessRule(studyIdentifier, consent_group, "PARENT", fence_parent_consent_group_concept_path);
- configureAccessRule(ar, studyIdentifier, consent_group, conceptPath, projectAlias, true, false, false);
- accessrules.add(ar);
-
- // Create and add the Topmed+Parent access rule
- ar = upsertTopmedAccessRule(studyIdentifier, consent_group, "TOPMED+PARENT");
- configureAccessRule(ar, studyIdentifier, consent_group, conceptPath, projectAlias, true, false, true);
- accessrules.add(ar);
-
- // If harmonized, create and add the harmonized access rule
- if (isHarmonized) {
- ar = createConsentAccessRule(studyIdentifier, consent_group, "HARMONIZED", fence_harmonized_consent_group_concept_path);
- configureHarmonizedAccessRule(ar, studyIdentifier, consent_group, conceptPath, projectAlias);
- accessrules.add(ar);
- }
-
- // Add standard access rules
- addStandardAccessRules(accessrules);
-
- priv.setAccessRules(accessrules);
- logger.info("Added {} access_rules to privilege", accessrules.size());
-
- privilegeService.save(priv);
- logger.info("Added new privilege {} to DB", priv.getName());
- } catch (Exception ex) {
- logger.error("Could not save privilege", ex);
- }
- return priv;
- }
-
- /**
- * Configures the AccessRule with gates and sub-rules.
- *
- * @param ar The AccessRule to configure.
- * @param studyIdentifier The study identifier.
- * @param consent_group The consent group.
- * @param conceptPath The concept path.
- * @param projectAlias The project alias.
- * @param parent Whether to include parent gates.
- * @param harmonized Whether to include harmonized gates.
- * @param topmed Whether to include Topmed gates.
- */
- private void configureAccessRule(AccessRule ar, String studyIdentifier, String consent_group, String conceptPath, String projectAlias, boolean parent, boolean harmonized, boolean topmed) {
- if (ar.getGates() == null) {
- ar.setGates(new HashSet<>());
- ar.getGates().addAll(getGates(parent, harmonized, topmed));
-
- if (ar.getSubAccessRule() == null) {
- ar.setSubAccessRule(new HashSet<>());
- }
- ar.getSubAccessRule().addAll(getAllowedQueryTypeRules());
- ar.getSubAccessRule().addAll(getPhenotypeSubRules(studyIdentifier, conceptPath, projectAlias));
- ar.getSubAccessRule().addAll(getTopmedRestrictedSubRules());
- accessRuleService.save(ar);
- }
- }
-
- /**
- * Configures the harmonized AccessRule with gates and sub-rules.
- *
- * @param ar The AccessRule to configure.
- * @param studyIdentifier The study identifier.
- * @param consent_group The consent group.
- * @param conceptPath The concept path.
- * @param projectAlias The project alias.
- */
- private void configureHarmonizedAccessRule(AccessRule ar, String studyIdentifier, String consent_group, String conceptPath, String projectAlias) {
- if (ar.getGates() == null) {
- ar.setGates(new HashSet<>());
- ar.getGates().add(upsertConsentGate("HARMONIZED_CONSENT", "$.query.query.categoryFilters." + fence_harmonized_consent_group_concept_path + "[*]", true, "harmonized data"));
-
- if (ar.getSubAccessRule() == null) {
- ar.setSubAccessRule(new HashSet<>());
- }
- ar.getSubAccessRule().addAll(getAllowedQueryTypeRules());
- ar.getSubAccessRule().addAll(getHarmonizedSubRules());
- ar.getSubAccessRule().addAll(getPhenotypeSubRules(studyIdentifier, conceptPath, projectAlias));
- accessRuleService.save(ar);
- }
- }
-
- private Set getAllowedQueryTypeRules() {
- if (allowQueryTypeRules == null) {
- allowQueryTypeRules = loadAllowedQueryTypeRules();
- }
-
- return allowQueryTypeRules;
- }
-
- /**
- * Retrieves or creates AccessRules for allowed query types.
- *
- * @return A set of AccessRules for allowed query types.
- */
- private Set loadAllowedQueryTypeRules() {
- // Initialize a set to hold the AccessRules
- Set rules = new HashSet<>();
- // Split the allowed query types from the configuration
- String[] allowedTypes = this.fence_allowed_query_types.split(",");
-
- // Iterate over each allowed query type
- for (String queryType : allowedTypes) {
- // Construct the AccessRule name
- String ar_name = "AR_ALLOW_" + queryType;
-
- // Log the creation of a new AccessRule
- AccessRule ar = getOrCreateAccessRule(
- ar_name,
- "FENCE SUB AR to allow " + queryType + " Queries",
- "$.query.query.expectedResultType",
- AccessRule.TypeNaming.ALL_EQUALS,
- queryType,
- false,
- false,
- false,
- false
- );
-
- // Add the newly created rule to the set
- rules.add(ar);
- }
- // Return the set of AccessRules
- return rules;
- }
-
- private Collection extends AccessRule> getTopmedRestrictedSubRules() {
- Set rules = new HashSet();
- rules.add(upsertTopmedRestrictedSubRule("CATEGORICAL", "$.query.query.variantInfoFilters[*].categoryVariantInfoFilters.*"));
- rules.add(upsertTopmedRestrictedSubRule("NUMERIC", "$.query.query.variantInfoFilters[*].numericVariantInfoFilters.*"));
-
- return rules;
- }
-
- /**
- * Creates and returns a restricted sub-rule AccessRule for Topmed.
- * topmed restriction rules don't need much configuration. Just deny all access.
- *
- * @param type The type of the Topmed restriction.
- * @param rule The rule expression.
- * @return The created AccessRule.
- */
- private AccessRule upsertTopmedRestrictedSubRule(String type, String rule) {
- // Construct the AccessRule name
- String ar_name = "AR_TOPMED_RESTRICTED_" + type;
- // Check if the AccessRule already exists
- AccessRule ar = accessRuleService.getAccessRuleByName(ar_name);
- if (ar != null) {
- // Log and return the existing rule
- logger.debug("Found existing rule: {}", ar.getName());
- return ar;
- }
-
- // Log the creation of a new AccessRule
- // Create the AccessRule using the createAccessRule method
- return getOrCreateAccessRule(
- ar_name,
- "FENCE SUB AR for restricting " + type + " genomic concepts",
- rule,
- AccessRule.TypeNaming.IS_EMPTY,
- null,
- false,
- false,
- false,
- false
- );
- }
-
- private Collection extends AccessRule> getPhenotypeSubRules(String studyIdentifier, String conceptPath, String alias) {
-
- Set rules = new HashSet();
- //categorical filters will always contain at least one entry (for the consent groups); it will never be empty
- rules.add(createPhenotypeSubRule(fence_parent_consent_group_concept_path, "ALLOW_PARENT_CONSENT", "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "", true));
-
- for (String underscorePath : underscoreFields) {
- rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.fields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "FIELDS", false));
- rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "CATEGORICAL", true));
- rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.requiredFields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "REQ_FIELDS", false));
- }
-
- rules.add(createPhenotypeSubRule(conceptPath, alias + "_" + studyIdentifier, "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "CATEGORICAL", true));
- rules.add(createPhenotypeSubRule(conceptPath, alias + "_" + studyIdentifier, "$.query.query.numericFilters", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "NUMERIC", true));
- rules.add(createPhenotypeSubRule(conceptPath, alias + "_" + studyIdentifier, "$.query.query.fields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "FIELDS", false));
- rules.add(createPhenotypeSubRule(conceptPath, alias + "_" + studyIdentifier, "$.query.query.requiredFields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "REQUIRED_FIELDS", false));
-
- return rules;
- }
-
- /**
- * Harmonized rules should allow the user to supply paretn and top med consent groups; this allows a single harmonized
- * rules instead of splitting between a topmed+harmonized and parent+harmonized
- *
- * @return
- */
- private Collection extends AccessRule> getHarmonizedSubRules() {
-
- Set rules = new HashSet();
- //categorical filters will always contain at least one entry (for the consent groups); it will never be empty
- rules.add(createPhenotypeSubRule(fence_parent_consent_group_concept_path, "ALLOW_PARENT_CONSENT", "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "", true));
- rules.add(createPhenotypeSubRule(fence_harmonized_consent_group_concept_path, "ALLOW_HARMONIZED_CONSENT", "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "", true));
- rules.add(createPhenotypeSubRule(fence_topmed_consent_group_concept_path, "ALLOW_TOPMED_CONSENT", "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "", true));
-
- for (String underscorePath : underscoreFields) {
- rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.fields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "FIELDS", false));
- rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "CATEGORICAL", true));
- rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.requiredFields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "REQ_FIELDS", false));
- }
-
- rules.add(createPhenotypeSubRule(fence_harmonized_concept_path, "HARMONIZED", "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "CATEGORICAL", true));
- rules.add(createPhenotypeSubRule(fence_harmonized_concept_path, "HARMONIZED", "$.query.query.numericFilters", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "NUMERIC", true));
- rules.add(createPhenotypeSubRule(fence_harmonized_concept_path, "HARMONIZED", "$.query.query.fields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "FIELDS", false));
- rules.add(createPhenotypeSubRule(fence_harmonized_concept_path, "HARMONIZED", "$.query.query.requiredFields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "REQUIRED_FIELDS", false));
-
- return rules;
- }
-
-
- /**
- * generate and return a set of rules that disallow access to phenotype data (only genomic filters allowed)
- *
- * @return
- */
- private Collection extends AccessRule> getPhenotypeRestrictedSubRules(String studyIdentifier, String consentCode, String alias) {
- Set rules = new HashSet();
- //categorical filters will always contain at least one entry (for the consent groups); it will never be empty
- rules.add(createPhenotypeSubRule(fence_topmed_consent_group_concept_path, "ALLOW_TOPMED_CONSENT", "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "", true));
-
- for (String underscorePath : underscoreFields) {
- rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.fields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "FIELDS", false));
- rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.categoryFilters", AccessRule.TypeNaming.ALL_CONTAINS, "CATEGORICAL", true));
- rules.add(createPhenotypeSubRule(underscorePath, "ALLOW " + underscorePath, "$.query.query.requiredFields.[*]", AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY, "REQ_FIELDS", false));
- }
-
- rules.add(createPhenotypeSubRule(null, alias + "_" + studyIdentifier + "_" + consentCode, "$.query.query.numericFilters.[*]", AccessRule.TypeNaming.IS_EMPTY, "DISALLOW_NUMERIC", false));
- rules.add(createPhenotypeSubRule(null, alias + "_" + studyIdentifier + "_" + consentCode, "$.query.query.requiredFields.[*]", AccessRule.TypeNaming.IS_EMPTY, "DISALLOW_REQUIRED_FIELDS", false));
-
- return rules;
- }
-
- /**
- * Return a set of gates that identify which consent values have been provided. the boolean parameters indicate
- * if a value in the specified consent location should allow this gate to pass.
- *
- * @param parent
- * @param harmonized
- * @param topmed
- * @return
- */
- private Collection extends AccessRule> getGates(boolean parent, boolean harmonized, boolean topmed) {
- Set gates = new HashSet();
- gates.add(upsertConsentGate("PARENT_CONSENT", "$.query.query.categoryFilters." + fence_parent_consent_group_concept_path + "[*]", parent, "parent study data"));
- gates.add(upsertConsentGate("HARMONIZED_CONSENT", "$.query.query.categoryFilters." + fence_harmonized_consent_group_concept_path + "[*]", harmonized, "harmonized data"));
- gates.add(upsertConsentGate("TOPMED_CONSENT", "$.query.query.categoryFilters." + fence_topmed_consent_group_concept_path + "[*]", topmed, "Topmed data"));
-
- return gates;
- }
-
- /**
- * Creates a privilege for Topmed access. This has (up to) three access rules:
- * 1) topmed only 2) topmed + parent 3) topmed + harmonized.
- *
- * @param studyIdentifier
- * @param projectAlias
- * @param consentGroup
- * @param parentConceptPath
- * @param isHarmonized
- * @return Privilege
- */
- private Privilege upsertTopmedPrivilege(String studyIdentifier, String projectAlias, String consentGroup, String parentConceptPath, boolean isHarmonized) {
- String privilegeName = "PRIV_FENCE_" + studyIdentifier + "_" + consentGroup + "_TOPMED";
- Privilege priv = privilegeService.findByName(privilegeName);
-
- if (priv != null) {
- logger.info("upsertTopmedPrivilege() {} already exists", privilegeName);
- return priv;
- }
-
- priv = new Privilege();
-
- try {
- buildPrivilegeObject(priv, privilegeName, studyIdentifier, consentGroup);
-
- Set accessRules = new HashSet<>();
- AccessRule topmedRule = upsertTopmedAccessRule(studyIdentifier, consentGroup, "TOPMED");
-
- populateAccessRule(topmedRule, false, false, true);
- topmedRule.getSubAccessRule().addAll(getPhenotypeRestrictedSubRules(studyIdentifier, consentGroup, projectAlias));
- accessRules.add(topmedRule);
-
- if (parentConceptPath != null) {
- AccessRule topmedParentRule = upsertTopmedAccessRule(studyIdentifier, consentGroup, "TOPMED+PARENT");
- populateAccessRule(topmedParentRule, true, false, true);
- topmedParentRule.getSubAccessRule().addAll(getPhenotypeSubRules(studyIdentifier, parentConceptPath, projectAlias));
- accessRules.add(topmedParentRule);
-
- if (isHarmonized) {
- AccessRule harmonizedRule = upsertHarmonizedAccessRule(studyIdentifier, consentGroup, "HARMONIZED");
- populateHarmonizedAccessRule(harmonizedRule, parentConceptPath, studyIdentifier, projectAlias);
- accessRules.add(harmonizedRule);
- }
- }
-
- addStandardAccessRules(accessRules);
-
- priv.setAccessRules(accessRules);
- logger.info("upsertTopmedPrivilege() Added {} access_rules to privilege", accessRules.size());
-
- privilegeService.save(priv);
- logger.info("upsertTopmedPrivilege() Added new privilege {} to DB", priv.getName());
- } catch (Exception ex) {
- logger.error("upsertTopmedPrivilege() could not save privilege", ex);
- }
-
- return priv;
- }
-
- private void buildPrivilegeObject(Privilege priv, String privilegeName, String studyIdentifier, String consentGroup) {
- priv.setApplication(picSureApp);
- priv.setName(privilegeName);
- priv.setDescription("FENCE privilege for Topmed " + studyIdentifier + "." + consentGroup);
-
- String consentConceptPath = escapePath(fence_topmed_consent_group_concept_path);
- fence_harmonized_concept_path = escapePath(fence_harmonized_concept_path);
-
- String queryTemplateText = "{\"categoryFilters\": {\"" + consentConceptPath + "\":[\"" + studyIdentifier + "." + consentGroup + "\"]},"
- + "\"numericFilters\":{},\"requiredFields\":[],"
- + "\"fields\":[\"" + topmedAccessionField + "\"],"
- + "\"variantInfoFilters\":[{\"categoryVariantInfoFilters\":{},\"numericVariantInfoFilters\":{}}],"
- + "\"expectedResultType\": \"COUNT\""
- + "}";
-
- priv.setQueryTemplate(queryTemplateText);
-
- priv.setQueryScope(buildQueryScope(this.variantAnnotationColumns));
- }
-
- private String escapePath(String path) {
- if (path != null && !path.contains("\\\\")) {
- return path.replaceAll("\\\\", "\\\\\\\\");
- }
- return path;
- }
-
- private String buildQueryScope(String variantColumns) {
- if (variantColumns == null || variantColumns.isEmpty()) {
- return "[\"_\"]";
- }
-
- return Arrays.stream(variantColumns.split(","))
- .map(path -> "\"" + path + "\"")
- .collect(Collectors.joining(",", "[", ",\"_\"]"));
- }
-
- private void populateAccessRule(AccessRule rule, boolean includeParent, boolean includeHarmonized, boolean includeTopmed) {
- if (rule.getGates() == null) {
- rule.setGates(new HashSet<>(getGates(includeParent, includeHarmonized, includeTopmed)));
- }
-
- if (rule.getSubAccessRule() == null) {
- rule.setSubAccessRule(new HashSet<>(getAllowedQueryTypeRules()));
- }
-
- accessRuleService.save(rule);
- }
-
- private void populateHarmonizedAccessRule(AccessRule rule, String parentConceptPath, String studyIdentifier, String projectAlias) {
- if (rule.getGates() == null) {
- rule.setGates(new HashSet<>(Collections.singletonList(
- upsertConsentGate("HARMONIZED_CONSENT", "$.query.query.categoryFilters." + fence_harmonized_consent_group_concept_path + "[*]", true, "harmonized data")
- )));
- }
-
- if (rule.getSubAccessRule() == null) {
- rule.setSubAccessRule(new HashSet<>(getAllowedQueryTypeRules()));
- rule.getSubAccessRule().addAll(getHarmonizedSubRules());
- rule.getSubAccessRule().addAll(getPhenotypeSubRules(studyIdentifier, parentConceptPath, projectAlias));
- }
-
- accessRuleService.save(rule);
- }
-
- // A set of standard access rules that are added to all privileges
- // to cache the standard access rules
- private Set standardAccessRules;
-
- private void addStandardAccessRules(Set accessRules) {
- if (standardAccessRules != null && !standardAccessRules.isEmpty()) {
- accessRules.addAll(standardAccessRules);
- } else {
- standardAccessRules = new HashSet<>();
- for (String arName : fence_standard_access_rules.split(",")) {
- if (arName.startsWith("AR_")) {
- logger.info("Adding AccessRule {} to privilege", arName);
- AccessRule ar = accessRuleService.getAccessRuleByName(arName);
- if (ar != null) {
- standardAccessRules.add(ar);
- } else {
- logger.warn("Unable to find an access rule with name {}", arName);
- }
- }
- }
-
- accessRules.addAll(standardAccessRules);
- }
- }
-
-
- /**
- * Creates and returns a consent access rule AccessRule.
- * Generates Main rule only; gates & sub-rules attached after calling this
- * prentRule should be null if this is the main rule, or the appropriate value if this is a sub-rule
- *
- * @param studyIdentifier The study identifier.
- * @param consent_group The consent group.
- * @param label The label for the rule.
- * @param consent_path The consent path.
- * @return The created AccessRule.
- */
- private AccessRule createConsentAccessRule(String studyIdentifier, String consent_group, String label, String consent_path) {
- String ar_name = (consent_group != null && !consent_group.isEmpty()) ? "AR_CONSENT_" + studyIdentifier + "_" + consent_group + "_" + label : "AR_CONSENT_" + studyIdentifier;
- String description = (consent_group != null && !consent_group.isEmpty()) ? "FENCE AR for " + studyIdentifier + "." + consent_group + " clinical concepts" : "FENCE AR for " + studyIdentifier + " clinical concepts";
- String ruleText = "$.query.query.categoryFilters." + consent_path + "[*]";
- String arValue = (consent_group != null && !consent_group.isEmpty()) ? studyIdentifier + "." + consent_group : studyIdentifier;
-
- return getOrCreateAccessRule(
- ar_name,
- description,
- ruleText,
- AccessRule.TypeNaming.ALL_CONTAINS,
- arValue,
- false,
- false,
- false,
- false
- );
- }
-
- /**
- * Creates and returns a Topmed access rule AccessRule.
- * Generates Main Rule only; gates & sub-rules attached by calling method
- *
- * @param project_name The name of the project.
- * @param consent_group The consent group.
- * @param label The label for the rule.
- * @return The created AccessRule.
- */
- private AccessRule upsertTopmedAccessRule(String project_name, String consent_group, String label) {
- String ar_name = (consent_group != null && !consent_group.isEmpty()) ? "AR_TOPMED_" + project_name + "_" + consent_group + "_" + label : "AR_TOPMED_" + project_name + "_" + label;
- String description = "FENCE AR for " + project_name + "." + consent_group + " Topmed data";
- String ruleText = "$.query.query.categoryFilters." + fence_topmed_consent_group_concept_path + "[*]";
- String arValue = (consent_group != null && !consent_group.isEmpty()) ? project_name + "." + consent_group : project_name;
-
- return getOrCreateAccessRule(
- ar_name,
- description,
- ruleText,
- AccessRule.TypeNaming.ALL_CONTAINS,
- arValue,
- false,
- false,
- false,
- false
- );
- }
-
- /**
- * Creates and returns a harmonized access rule AccessRule for Topmed.
- * Generates Main Rule only; gates & sub rules attached by calling method
- *
- * @param project_name The name of the project.
- * @param consent_group The consent group.
- * @param label The label for the rule.
- * @return The created AccessRule.
- */
- private AccessRule upsertHarmonizedAccessRule(String project_name, String consent_group, String label) {
- String ar_name = "AR_TOPMED_" + project_name + "_" + consent_group + "_" + label;
- logger.info("upsertHarmonizedAccessRule() Creating new access rule {}", ar_name);
- String description = "FENCE AR for " + project_name + "." + consent_group + " Topmed data";
- String ruleText = "$.query.query.categoryFilters." + fence_harmonized_consent_group_concept_path + "[*]";
- String arValue = project_name + "." + consent_group;
-
- return getOrCreateAccessRule(
- ar_name,
- description,
- ruleText,
- AccessRule.TypeNaming.ALL_CONTAINS,
- arValue,
- false,
- false,
- false,
- false
- );
- }
-
- /**
- * Creates and returns a consent gate AccessRule.
- * Insert a new gate (if it doesn't exist yet) to identify if consent values are present in the query.
- * return an existing gate named GATE_{gateName}_(PRESENT|MISSING) if it exists.
- *
- * @param gateName The name of the gate.
- * @param rule The rule expression.
- * @param is_present Whether the gate is for present or missing consent.
- * @param description The description of the gate.
- * @return The created AccessRule.
- */
- private AccessRule upsertConsentGate(String gateName, String rule, boolean is_present, String description) {
- gateName = "GATE_" + gateName + "_" + (is_present ? "PRESENT" : "MISSING");
- return getOrCreateAccessRule(
- gateName,
- "FENCE GATE for " + description + " consent " + (is_present ? "present" : "missing"),
- rule,
- is_present ? AccessRule.TypeNaming.IS_NOT_EMPTY : AccessRule.TypeNaming.IS_EMPTY,
- null,
- false,
- false,
- false,
- false
- );
- }
-
- private AccessRule createPhenotypeSubRule(String conceptPath, String alias, String rule, int ruleType, String label, boolean useMapKey) {
- String ar_name = "AR_PHENO_" + alias + "_" + label;
- logger.info("createPhenotypeSubRule() Creating new access rule {}", ar_name);
- return getOrCreateAccessRule(
- ar_name,
- "FENCE SUB AR for " + alias + " " + label + " clinical concepts",
- rule,
- ruleType,
- ruleType == AccessRule.TypeNaming.IS_NOT_EMPTY ? null : conceptPath,
- useMapKey,
- useMapKey,
- false,
- false
- );
- }
-
- private AccessRule getOrCreateAccessRule(String name, String description, String rule, int type, String value, boolean checkMapKeyOnly, boolean checkMapNode, boolean evaluateOnlyByGates, boolean gateAnyRelation) {
- return accessRuleCache.computeIfAbsent(name, key -> {
- AccessRule ar = accessRuleService.getAccessRuleByName(key);
- if (ar == null) {
- logger.info("Creating new access rule {}", key);
- ar = new AccessRule();
- ar.setName(name);
- ar.setDescription(description);
- ar.setRule(rule);
- ar.setType(type);
- ar.setValue(value);
- ar.setCheckMapKeyOnly(checkMapKeyOnly);
- ar.setCheckMapNode(checkMapNode);
- ar.setEvaluateOnlyByGates(evaluateOnlyByGates);
- ar.setGateAnyRelation(gateAnyRelation);
- accessRuleService.save(ar);
- }
-
- return ar;
- });
- }
-
- private String extractProject(String roleName) {
- String projectPattern = "FENCE_(.*?)(?:_c\\d+)?$";
- if (roleName.startsWith("MANUAL_")) {
- projectPattern = "MANUAL_(.*?)(?:_c\\d+)?$";
- }
- Pattern projectRegex = Pattern.compile(projectPattern);
- Matcher projectMatcher = projectRegex.matcher(roleName);
- String project = "";
- if (projectMatcher.find()) {
- project = projectMatcher.group(1).trim();
- } else {
- logger.info("extractProject() Could not extract project from role name: {}", roleName);
- String[] parts = roleName.split("_", 1);
- if (parts.length > 0) {
- project = parts[1];
- }
- }
- return project;
- }
-
- private static String extractConsentGroup(String roleName) {
- String consentPattern = "FENCE_.*?_c(\\d+)$";
- if (roleName.startsWith("MANUAL_")) {
- consentPattern = "MANUAL_.*?_c(\\d+)$";
- }
- Pattern consentRegex = Pattern.compile(consentPattern);
- Matcher consentMatcher = consentRegex.matcher(roleName);
- String consentGroup = "";
- if (consentMatcher.find()) {
- consentGroup = "c" + consentMatcher.group(1).trim();
- }
- return consentGroup;
- }
-
- private StudyMetaData getFENCEMappingforProjectAndConsent(String projectId, String consent_group) {
- String consentVal = (consent_group != null && !consent_group.isEmpty()) ? projectId + "." + consent_group : projectId;
- logger.info("getFENCEMappingforProjectAndConsent() looking up {}", consentVal);
-
- return this.fenceMappingUtility.getFENCEMapping().get(consentVal);
- }
-
}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/OktaOAuthAuthenticationService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/OktaOAuthAuthenticationService.java
index cfc7482bb..29622abeb 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/OktaOAuthAuthenticationService.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/OktaOAuthAuthenticationService.java
@@ -5,9 +5,10 @@
import com.fasterxml.jackson.databind.node.ObjectNode;
import edu.harvard.hms.dbmi.avillach.auth.entity.Role;
import edu.harvard.hms.dbmi.avillach.auth.entity.User;
+import edu.harvard.hms.dbmi.avillach.auth.service.AuthenticationService;
import edu.harvard.hms.dbmi.avillach.auth.service.impl.RoleService;
import edu.harvard.hms.dbmi.avillach.auth.service.impl.UserService;
-import edu.harvard.hms.dbmi.avillach.auth.service.impl.authorization.AccessRuleService;
+import edu.harvard.hms.dbmi.avillach.auth.service.impl.AccessRuleService;
import edu.harvard.hms.dbmi.avillach.auth.utils.RestClientUtil;
import jakarta.persistence.NoResultException;
import org.apache.commons.lang3.StringUtils;
@@ -15,7 +16,6 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@@ -24,7 +24,7 @@
import java.util.*;
@Service
-public class OktaOAuthAuthenticationService {
+public class OktaOAuthAuthenticationService implements AuthenticationService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@@ -35,6 +35,7 @@ public class OktaOAuthAuthenticationService {
private final String connectionId;
private final String clientId;
private final String spClientSecret;
+ private final boolean isOktaEnabled;
private final AccessRuleService accessRuleService;
private final RestClientUtil restClientUtil;
@@ -48,23 +49,28 @@ public class OktaOAuthAuthenticationService {
* @param spClientSecret The client secret
*/
@Autowired
- public OktaOAuthAuthenticationService(UserService userService, RoleService roleService,
- @Value("${okta.idp.provider.uri}") String idp_provider_uri,
- @Value("${okta.connection.id}") String connectionId,
- @Value("${okta.client.id}") String clientId,
- @Value("${okta.client.secret}") String spClientSecret, AccessRuleService accessRuleService, RestClientUtil restClientUtil) {
+ public OktaOAuthAuthenticationService(UserService userService,
+ RoleService roleService,
+ AccessRuleService accessRuleService,
+ RestClientUtil restClientUtil,
+ @Value("${a4.okta.idp.provider.is.enabled}") boolean isOktaEnabled,
+ @Value("${a4.okta.idp.provider.uri}") String idp_provider_uri,
+ @Value("${a4.okta.connection.id}") String connectionId,
+ @Value("${a4.okta.client.id}") String clientId,
+ @Value("${a4.okta.client.secret}") String spClientSecret) {
this.userService = userService;
this.roleService = roleService;
this.idp_provider_uri = idp_provider_uri;
this.connectionId = connectionId;
this.clientId = clientId;
this.spClientSecret = spClientSecret;
+ this.isOktaEnabled = isOktaEnabled;
+ logger.info("OktaOAuthAuthenticationService is enabled: {}", isOktaEnabled);
logger.info("OktaOAuthAuthenticationService initialized");
logger.info("idp_provider_uri: {}", idp_provider_uri);
logger.info("connectionId: {}", connectionId);
- logger.info("clientId: {}", clientId);
- logger.info("spClientSecret: {}", spClientSecret);
+
this.accessRuleService = accessRuleService;
this.restClientUtil = restClientUtil;
}
@@ -78,7 +84,10 @@ public OktaOAuthAuthenticationService(UserService userService, RoleService roleS
* @param authRequest The request body
* @return The response from the authentication attempt
*/
- public HashMap authenticate(String host, Map authRequest) {
+ @Override
+ public HashMap authenticate(Map authRequest, String host) {
+ logger.info("OKTA LOGIN ATTEMPT ___ {} ___", authRequest.get("code"));
+
String code = authRequest.get("code");
if (StringUtils.isNotBlank(code)) {
JsonNode userToken = handleCodeTokenExchange(host, code);
@@ -99,6 +108,16 @@ public HashMap authenticate(String host, Map aut
return null;
}
+ @Override
+ public String getProvider() {
+ return "aimAheadOkta";
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return this.isOktaEnabled;
+ }
+
private User initializeUser(JsonNode introspectResponse) {
if (introspectResponse == null) {
logger.info("FAILED TO INTROSPECT TOKEN ___ ");
@@ -135,8 +154,8 @@ private HashMap createUserClaims(User user) {
}
private void clearCache(User user) {
- userService.evictFromCache(user);
- accessRuleService.evictFromCache(user);
+ userService.evictFromCache(user.getEmail());
+ accessRuleService.evictFromCache(user.getEmail());
}
/**
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/OpenAuthenticationService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/OpenAuthenticationService.java
index 2edd9b259..9c7d6b969 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/OpenAuthenticationService.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/OpenAuthenticationService.java
@@ -2,36 +2,41 @@
import edu.harvard.hms.dbmi.avillach.auth.entity.Role;
import edu.harvard.hms.dbmi.avillach.auth.entity.User;
+import edu.harvard.hms.dbmi.avillach.auth.service.AuthenticationService;
import edu.harvard.hms.dbmi.avillach.auth.service.impl.RoleService;
import edu.harvard.hms.dbmi.avillach.auth.service.impl.UserService;
-import edu.harvard.hms.dbmi.avillach.auth.service.impl.authorization.AccessRuleService;
+import edu.harvard.hms.dbmi.avillach.auth.service.impl.AccessRuleService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
-public class OpenAuthenticationService {
+public class OpenAuthenticationService implements AuthenticationService {
private final Logger logger = LoggerFactory.getLogger(OpenAuthenticationService.class);
private final UserService userService;
private final RoleService roleService;
private final AccessRuleService accessRuleService;
+ private final boolean isOpenEnabled;
@Autowired
- public OpenAuthenticationService(UserService userService, RoleService roleService, AccessRuleService accessRuleService) {
+ public OpenAuthenticationService(UserService userService, RoleService roleService, AccessRuleService accessRuleService,
+ @Value("${open.idp.provider.is.enabled}") boolean isOpenEnabled) {
this.userService = userService;
this.roleService = roleService;
this.accessRuleService = accessRuleService;
+ this.isOpenEnabled = isOpenEnabled;
}
-
- public Map authenticate(Map authRequest) {
+ @Override
+ public HashMap authenticate(Map authRequest, String host) {
String userUUID = authRequest.get("UUID");
User current_user = null;
@@ -51,8 +56,8 @@ public Map authenticate(Map authRequest) {
//clear some cache entries if we register a new login
// I don't see a clear need to caching here.
- accessRuleService.evictFromCache(current_user);
- userService.evictFromCache(current_user);
+ accessRuleService.evictFromCache(current_user.getEmail());
+ userService.evictFromCache(current_user.getEmail());
}
HashMap claims = new HashMap<>();
@@ -65,4 +70,14 @@ public Map authenticate(Map authRequest) {
return responseMap;
}
+
+ @Override
+ public String getProvider() {
+ return "open";
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return this.isOpenEnabled;
+ }
}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AccessRuleService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AccessRuleService.java
deleted file mode 100644
index 61ed3bf62..000000000
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AccessRuleService.java
+++ /dev/null
@@ -1,477 +0,0 @@
-package edu.harvard.hms.dbmi.avillach.auth.service.impl.authorization;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.jayway.jsonpath.InvalidPathException;
-import com.jayway.jsonpath.JsonPath;
-import com.jayway.jsonpath.PathNotFoundException;
-import com.mysql.cj.xdevapi.JsonArray;
-import edu.harvard.hms.dbmi.avillach.auth.entity.AccessRule;
-import edu.harvard.hms.dbmi.avillach.auth.entity.Application;
-import edu.harvard.hms.dbmi.avillach.auth.entity.Privilege;
-import edu.harvard.hms.dbmi.avillach.auth.entity.User;
-import edu.harvard.hms.dbmi.avillach.auth.repository.AccessRuleRepository;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.cache.annotation.CacheEvict;
-import org.springframework.cache.annotation.Cacheable;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.*;
-
-@Service
-public class AccessRuleService {
-
- private final AccessRuleRepository accessRuleRepo;
- private final Logger logger = LoggerFactory.getLogger(AccessRuleService.class);
- private final ObjectMapper objectMapper = new ObjectMapper();
-
- @Autowired
- public AccessRuleService(AccessRuleRepository accessRuleRepo) {
- this.accessRuleRepo = accessRuleRepo;
- }
-
- public Optional getAccessRuleById(String accessRuleId) {
- return accessRuleRepo.findById(UUID.fromString(accessRuleId));
- }
-
- public List getAllAccessRules() {
- return accessRuleRepo.findAll();
- }
-
- public List addAccessRule(List accessRules) {
- accessRules.forEach(accessRule -> {
- if (accessRule.getEvaluateOnlyByGates() == null)
- accessRule.setEvaluateOnlyByGates(false);
-
- if (accessRule.getCheckMapKeyOnly() == null)
- accessRule.setCheckMapKeyOnly(false);
-
- if (accessRule.getCheckMapNode() == null)
- accessRule.setCheckMapNode(false);
-
- if (accessRule.getGateAnyRelation() == null)
- accessRule.setGateAnyRelation(false);
- });
-
- return this.accessRuleRepo.saveAll(accessRules);
- }
-
- public List updateAccessRules(List accessRules) {
- return this.accessRuleRepo.saveAll(accessRules);
- }
-
- @Transactional
- public List removeAccessRuleById(String accessRuleId) {
- this.accessRuleRepo.deleteById(UUID.fromString(accessRuleId));
- return this.accessRuleRepo.findAll();
- }
-
- public AccessRule save(AccessRule accessRule) {
- return this.accessRuleRepo.save(accessRule);
- }
-
- public AccessRule getAccessRuleByName(String arName) {
- return this.accessRuleRepo.findByName(arName);
- }
-
- @Cacheable(value = "mergedRulesCache", key = "#user.getEmail()")
- public Set getAccessRulesForUserAndApp(User user, Application application) {
- try {
- Set privileges = user.getPrivilegesByApplication(application);
-
- if (privileges == null || privileges.isEmpty()) {
- return null;
- }
-
- Set detachedMergedRules = new HashSet<>();
- for (AccessRule rule : preProcessAccessRules(privileges)) {
- detachedMergedRules.add(objectMapper.readValue(objectMapper.writeValueAsString(rule), AccessRule.class));
- }
-
- return detachedMergedRules;
- } catch (Exception e) {
- logger.error("Error populating or retrieving data from cache: ", e);
- }
-
- return null;
- }
-
- @CacheEvict(value = "mergedRulesCache", key = "#user.getEmail()")
- public void evictFromCache(User user) {
- // This method is used to clear the cache for a user when their privileges are updated
- }
-
- public Set preProcessAccessRules(Set privileges) {
- Set accessRules = new HashSet<>();
- for (Privilege privilege : privileges) {
- accessRules.addAll(privilege.getAccessRules());
- }
-
- return preProcessARBySortedKeys(accessRules);
- }
-
- public Set preProcessARBySortedKeys(Set accessRules) {
- Map> accessRuleMap = new HashMap<>();
-
- for (AccessRule accessRule : accessRules) {
-
- // 1st generate the key by grabbing all related string and put them together in order
- // we use a treeSet here to put orderly combine Strings together
- Set keys = new TreeSet<>();
-
- // the current accessRule rule
- keys.add(accessRule.getRule());
-
- // all gates' UUID as strings
- keys.add(accessRule.getType().toString());
-
- if (accessRule.getGates() != null) {
- for (AccessRule gate : accessRule.getGates()) {
- keys.add(gate.getUuid().toString());
- }
- }
-
- // all sub accessRule rules
- if (accessRule.getSubAccessRule() != null) {
- for (AccessRule subAccessRule : accessRule.getSubAccessRule()) {
- keys.add(subAccessRule.getRule());
- }
- }
- Boolean checkMapKeyOnly = accessRule.getCheckMapKeyOnly(),
- checkMapNode = accessRule.getCheckMapNode(),
- evaluateOnlyByGates = accessRule.getEvaluateOnlyByGates(),
- gateAnyRelation = accessRule.getGateAnyRelation();
-
- keys.add(checkMapKeyOnly == null ? "null" : Boolean.toString(checkMapKeyOnly));
- keys.add(checkMapNode == null ? "null" : Boolean.toString(checkMapNode));
- keys.add(evaluateOnlyByGates == null ? "null" : Boolean.toString(evaluateOnlyByGates));
- keys.add(gateAnyRelation == null ? "null" : Boolean.toString(gateAnyRelation));
-
- String key = String.join("", keys);
- if (accessRuleMap.containsKey(key)) {
- accessRuleMap.get(key).add(accessRule);
- } else {
- Set accessRuleSet = new HashSet<>();
- accessRuleSet.add(accessRule);
- accessRuleMap.put(key, accessRuleSet);
- }
- }
-
- return mergeSameKeyAccessRules(accessRuleMap.values());
- }
-
- private Set mergeSameKeyAccessRules(Collection> accessRuleMap) {
- Set accessRules = new HashSet<>();
- for (Set accessRulesSet : accessRuleMap) {
- AccessRule accessRule = null;
- for (AccessRule innerAccessRule : accessRulesSet) {
- accessRule = mergeAccessRules(accessRule, innerAccessRule);
- }
- if (accessRule != null) {
- accessRules.add(accessRule);
- }
- }
- return accessRules;
- }
-
- private AccessRule mergeAccessRules(AccessRule baseAccessRule, AccessRule accessRuleToBeMerged) {
- if (baseAccessRule == null) {
- accessRuleToBeMerged.getMergedValues().add(accessRuleToBeMerged.getValue());
- return accessRuleToBeMerged;
- }
-
- if (baseAccessRule.getSubAccessRule() != null && accessRuleToBeMerged.getSubAccessRule() != null) {
- baseAccessRule.getSubAccessRule().addAll(accessRuleToBeMerged.getSubAccessRule());
- } else if (baseAccessRule.getSubAccessRule() == null && accessRuleToBeMerged.getSubAccessRule() != null) {
- baseAccessRule.setSubAccessRule(accessRuleToBeMerged.getSubAccessRule());
- }
-
- baseAccessRule.getMergedValues().add(accessRuleToBeMerged.getValue());
- if (baseAccessRule.getMergedName().startsWith("Merged|")) {
- baseAccessRule.setMergedName(baseAccessRule.getMergedName() + "|" + accessRuleToBeMerged.getName());
- } else {
- baseAccessRule.setMergedName("Merged|" + baseAccessRule.getName() + "|" + accessRuleToBeMerged.getName());
- }
-
- return baseAccessRule;
- }
-
- public boolean evaluateAccessRule(Object parsedRequestBody, AccessRule accessRule) {
- logger.debug("evaluateAccessRule() starting with: {}", parsedRequestBody);
- logger.debug("evaluateAccessRule() access rule: {}", accessRule.getName());
-
- Set gates = accessRule.getGates();
- boolean gatesPassed = true;
-
- // depends on the flag getGateAnyRelation is true or false,
- // the logic of checking if apply gate will be changed
- // the following cases are gate passed:
- // 1. if gates are null or empty
- // 2. if getGateAnyRelation is false, all gates passed
- // 3. if getGateAnyRelation is true, one of the gate passed
- if (gates != null && !gates.isEmpty()) {
- if (accessRule.getGateAnyRelation() == null || !accessRule.getGateAnyRelation()) {
- // All gates are AND relationship
- // means one fails all fail
- for (AccessRule gate : gates) {
- if (!evaluateAccessRule(parsedRequestBody, gate)) {
- logger.error("evaluateAccessRule() gate {} failed: {} ____ {}", gate.getName(), gate.getRule(), gate.getValue());
- gatesPassed = false;
- break;
- }
- }
- } else {
- // All gates are OR relationship
- // means one passes all pass
- gatesPassed = false;
- for (AccessRule gate : gates) {
- if (evaluateAccessRule(parsedRequestBody, gate)) {
- logger.debug("evaluateAccessRule() gate {} passed ", gate.getName());
- gatesPassed = true;
- break;
- }
- }
-
- if (!gatesPassed) {
- logger.debug("all OR gates failed");
- }
- }
- }
-
- if (accessRule.getEvaluateOnlyByGates() != null && accessRule.getEvaluateOnlyByGates()) {
- logger.debug("evaluateAccessRule() eval only by gates");
- return gatesPassed;
- }
-
- if (gatesPassed) {
- logger.debug("evaluateAccessRule() gates passed");
- if (!extractAndCheckRule(accessRule, parsedRequestBody)) {
- logger.debug("Query Rejected by rule(1) {} :: {} :: {}", accessRule.getRule(), accessRule.getType(), accessRule.getValue());
- return false;
- } else {
- if (accessRule.getSubAccessRule() != null) {
- for (AccessRule subAccessRule : accessRule.getSubAccessRule()) {
- if (!extractAndCheckRule(subAccessRule, parsedRequestBody)) {
- logger.debug("Query Rejected by rule(2) {} :: {} :: {}", subAccessRule.getRule(), subAccessRule.getType(), subAccessRule.getValue());
- return false;
- }
- }
- }
- }
- } else {
- logger.debug("evaluateAccessRule() gates failed");
- return false;
- }
-
- return true;
- }
-
- public boolean extractAndCheckRule(AccessRule accessRule, Object parsedRequestBody) {
- logger.debug("extractAndCheckRule() starting");
- String rule = accessRule.getRule();
-
- if (rule == null || rule.isEmpty())
- return true;
-
- Object requestBodyValue;
- int accessRuleType = accessRule.getType();
-
- try {
- requestBodyValue = JsonPath.parse(parsedRequestBody).read(rule);
-
- // Json parse will always return a list even when we want a map (to check keys)
- if (requestBodyValue instanceof JsonArray && ((JsonArray) requestBodyValue).size() == 1) {
- requestBodyValue = ((JsonArray) requestBodyValue).get(0);
- }
-
- } catch (PathNotFoundException ex) {
- if (accessRuleType == AccessRule.TypeNaming.IS_EMPTY) {
- // We could return accessRuleType == AccessRule.TypeNaming.IS_EMPTY directly, but we want to log the reason
- logger.debug("extractAndCheckRule() -> JsonPath.parse().read() PathNotFound; passing IS_EMPTY rule");
- return true;
- }
- logger.debug("extractAndCheckRule() -> JsonPath.parse().read() throws exception with parsedRequestBody - {} : {} - {}", parsedRequestBody, ex.getClass().getSimpleName(), ex.getMessage());
- return false;
- }
-
- if (accessRuleType == AccessRule.TypeNaming.IS_EMPTY
- || accessRuleType == AccessRule.TypeNaming.IS_NOT_EMPTY) {
- if (requestBodyValue == null
- || (requestBodyValue instanceof String && ((String) requestBodyValue).isEmpty())
- || (requestBodyValue instanceof Collection && ((Collection) requestBodyValue).isEmpty())
- || (requestBodyValue instanceof Map && ((Map) requestBodyValue).isEmpty())) {
- return accessRuleType == AccessRule.TypeNaming.IS_EMPTY;
- } else {
- return accessRuleType == AccessRule.TypeNaming.IS_NOT_EMPTY;
- }
- }
-
- return evaluateNode(requestBodyValue, accessRule);
- }
-
- private boolean evaluateNode(Object requestBodyValue, AccessRule accessRule) {
- logger.debug("evaluateNode() starting: {} :: {} :: {}", accessRule.getRule(), accessRule.getType(), accessRule.getMergedValues().isEmpty() ? accessRule.getValue() : ("Merged " + Arrays.deepToString(accessRule.getMergedValues().toArray())));
- logger.trace("evaluateNode() requestBody {} {}", requestBodyValue.getClass().getName(), requestBodyValue instanceof Collection ?
- Arrays.deepToString(((Collection) requestBodyValue).toArray()) :
- requestBodyValue.toString());
-
- return switch (requestBodyValue) {
- case String s -> decisionMaker(accessRule, s);
- case Collection collection -> evaluateCollection(collection, accessRule);
- case Map map when accessRule.getCheckMapNode() != null && accessRule.getCheckMapNode() ->
- evaluateMap(requestBodyValue, accessRule);
- default -> true;
- };
- }
-
- private boolean evaluateMap(Object requestBodyValue, AccessRule accessRule) {
- switch (accessRule.getType()) {
- case (AccessRule.TypeNaming.ANY_EQUALS):
- case (AccessRule.TypeNaming.ANY_CONTAINS):
- case (AccessRule.TypeNaming.ANY_REG_MATCH):
- for (Map.Entry entry : ((Map) requestBodyValue).entrySet()) {
- if (decisionMaker(accessRule, (String) entry.getKey()))
- return true;
-
- if ((accessRule.getCheckMapKeyOnly() == null || !accessRule.getCheckMapKeyOnly())
- && evaluateNode(entry.getValue(), accessRule))
- return true;
- }
- return false;
- default:
- if (((Map) requestBodyValue).isEmpty()) {
- switch (accessRule.getType()) {
- case (AccessRule.TypeNaming.ALL_EQUALS_IGNORE_CASE):
- case (AccessRule.TypeNaming.ALL_EQUALS):
- case (AccessRule.TypeNaming.ALL_CONTAINS):
- case (AccessRule.TypeNaming.ALL_CONTAINS_IGNORE_CASE):
- return false;
- case (AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY):
- case (AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY_IGNORE_CASE):
- default:
- return true;
- }
- }
- for (Map.Entry entry : ((Map) requestBodyValue).entrySet()) {
- if (!decisionMaker(accessRule, (String) entry.getKey()))
- return false;
-
- if ((accessRule.getCheckMapKeyOnly() == null || !accessRule.getCheckMapKeyOnly())
- && !evaluateNode(entry.getValue(), accessRule))
- return false;
- }
-
- }
-
- return true;
- }
-
- private Boolean evaluateCollection(Collection requestBodyValue, AccessRule accessRule) {
- switch (accessRule.getType()) {
- case (AccessRule.TypeNaming.ANY_EQUALS):
- case (AccessRule.TypeNaming.ANY_CONTAINS):
- case (AccessRule.TypeNaming.ANY_REG_MATCH):
- for (Object item : requestBodyValue) {
- if (item instanceof String) {
- if (decisionMaker(accessRule, (String) item)) {
- return true;
- }
- } else {
- if (evaluateNode(item, accessRule)) {
- return true;
- }
- }
- }
- return false;
- default:
- if (requestBodyValue.isEmpty()) {
- switch (accessRule.getType()) {
- case (AccessRule.TypeNaming.ALL_EQUALS_IGNORE_CASE):
- case (AccessRule.TypeNaming.ALL_EQUALS):
- case (AccessRule.TypeNaming.ALL_CONTAINS):
- case (AccessRule.TypeNaming.ALL_CONTAINS_IGNORE_CASE):
- return false;
- case (AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY):
- case (AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY_IGNORE_CASE):
- default:
- return true;
- }
- }
-
- for (Object item : requestBodyValue) {
- if (item instanceof String) {
- if (!decisionMaker(accessRule, (String) item)) {
- return false;
- }
- } else {
- if (!evaluateNode(item, accessRule))
- return false;
- }
- }
- }
-
- return true;
- }
-
- public boolean decisionMaker(AccessRule accessRule, String requestBodyValue) {
- if (accessRule.getMergedValues().isEmpty()) {
- String value = accessRule.getValue();
- if (value == null) {
- return requestBodyValue == null;
- }
- return _decisionMaker(accessRule, requestBodyValue, value);
- }
-
- // recursively check the values
- // until one of them is true
- // if there is only one element in the merged value set
- // the operation equals to _decisionMaker(accessRule, requestBodyValue, value)
- boolean res = false;
- for (String s : accessRule.getMergedValues()) {
- // check the special case value is null
- // if value is null, the check will stop here and
- // not goes to _decisionMaker()
- if (s == null) {
- if (requestBodyValue == null) {
- res = true;
- break;
- } else {
- continue;
- }
- }
-
- // all the merged values are OR relationship
- // means if you pass one of them, you pass the rule
- if (_decisionMaker(accessRule, requestBodyValue, s)) {
- res = true;
- break;
- }
- }
- return res;
- }
-
- private boolean _decisionMaker(AccessRule accessRule, String requestBodyValue, String value) {
- logger.debug("_decisionMaker() starting");
- logger.debug("_decisionMaker() access rule:{}", accessRule.getName());
- logger.debug(requestBodyValue);
- logger.debug(value);
-
- return switch (accessRule.getType()) {
- case AccessRule.TypeNaming.NOT_CONTAINS -> !requestBodyValue.contains(value);
- case AccessRule.TypeNaming.NOT_CONTAINS_IGNORE_CASE -> !requestBodyValue.toLowerCase().contains(value.toLowerCase());
- case (AccessRule.TypeNaming.NOT_EQUALS) -> !value.equals(requestBodyValue);
- case (AccessRule.TypeNaming.ANY_EQUALS), (AccessRule.TypeNaming.ALL_EQUALS) -> value.equals(requestBodyValue);
- case (AccessRule.TypeNaming.ALL_CONTAINS), (AccessRule.TypeNaming.ANY_CONTAINS), (AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY) -> requestBodyValue.contains(value);
- case (AccessRule.TypeNaming.ALL_CONTAINS_IGNORE_CASE), (AccessRule.TypeNaming.ALL_CONTAINS_OR_EMPTY_IGNORE_CASE) -> requestBodyValue.toLowerCase().contains(value.toLowerCase());
- case (AccessRule.TypeNaming.NOT_EQUALS_IGNORE_CASE) -> !value.equalsIgnoreCase(requestBodyValue);
- case (AccessRule.TypeNaming.ALL_EQUALS_IGNORE_CASE) -> value.equalsIgnoreCase(requestBodyValue);
- case (AccessRule.TypeNaming.ALL_REG_MATCH), (AccessRule.TypeNaming.ANY_REG_MATCH) -> requestBodyValue.matches(value);
- default -> {
- logger.warn("evaluateAccessRule() incoming accessRule type is out of scope. Just return true.");
- yield true;
- }
- };
- }
-}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AuthorizationService.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AuthorizationService.java
index b801dfe9f..940d622cc 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AuthorizationService.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AuthorizationService.java
@@ -7,6 +7,7 @@
import edu.harvard.hms.dbmi.avillach.auth.entity.Privilege;
import edu.harvard.hms.dbmi.avillach.auth.entity.User;
import edu.harvard.hms.dbmi.avillach.auth.rest.TokenController;
+import edu.harvard.hms.dbmi.avillach.auth.service.impl.AccessRuleService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -85,23 +86,26 @@ public AuthorizationService(AccessRuleService accessRuleService, @Value("${stric
* @see AccessRule
*/
public boolean isAuthorized(Application application, Object requestBody, User user) {
+ // create timer
+ long startTime = System.currentTimeMillis();
String applicationName = application.getName();
String resourceId = "null";
String targetService = "null";
//in some cases, we don't go through the evaluation
if (requestBody == null) {
- logger.info("ACCESS_LOG ___ {},{},{} ___ has been granted access to application ___ {} ___ NO REQUEST BODY FORWARDED BY APPLICATION", user.getUuid().toString(), user.getEmail(), user.getName(), applicationName);
+ logger.debug("ACCESS_LOG ___ {},{},{} ___ has been granted access to application ___ {} ___ NO REQUEST BODY FORWARDED BY APPLICATION", user.getUuid().toString(), user.getEmail(), user.getName(), applicationName);
return true;
}
+ long parseTimeFrame = System.currentTimeMillis();
try {
Map requestBodyMap = (Map) requestBody;
Map queryMap = (Map) requestBodyMap.get("query");
resourceId = (String) queryMap.get("resourceUUID");
targetService = (String) queryMap.get("Target Service");
} catch (RuntimeException e) {
- logger.info("Error parsing resource and target service from request body.");
+ logger.debug("Error parsing resource and target service from request body.");
}
String formattedQuery;
@@ -114,10 +118,11 @@ public boolean isAuthorized(Application application, Object requestBody, User us
}
} catch (ClassCastException | JsonProcessingException e1) {
- logger.info("ACCESS_LOG ___ {},{},{} ___ has been denied access to execute query ___ {} ___ in application ___ {} ___ UNABLE TO PARSE REQUEST", user.getUuid().toString(), user.getEmail(), user.getName(), requestBody, applicationName);
- logger.info("isAuthorized() Stack Trace: ", e1);
+ logger.debug("ACCESS_LOG ___ {},{},{} ___ has been denied access to execute query ___ {} ___ in application ___ {} ___ UNABLE TO PARSE REQUEST", user.getUuid().toString(), user.getEmail(), user.getName(), requestBody, applicationName);
+ logger.debug("isAuthorized() Stack Trace: ", e1);
return false;
}
+ logger.info("Parse timeframe {} ms", (System.currentTimeMillis() - parseTimeFrame));
Set accessRules;
String label = user.getConnection().getLabel();
@@ -128,12 +133,13 @@ public boolean isAuthorized(Application application, Object requestBody, User us
return false;
}
- accessRules = this.accessRuleService.preProcessAccessRules(privileges);
+ accessRules = this.accessRuleService.cachedPreProcessAccessRules(user, privileges);
if (accessRules == null || accessRules.isEmpty()) {
logger.info("ACCESS_LOG ___ {},{},{} ___ has been granted access to execute query ___ {} ___ in application ___ {} ___ NO ACCESS RULES EVALUATED", user.getUuid().toString(), user.getEmail(), user.getName(), formattedQuery, applicationName);
return true;
}
} else {
+ logger.info("User Email: {}", user.getEmail());
accessRules = this.accessRuleService.getAccessRulesForUserAndApp(user, application);
if (accessRules == null || accessRules.isEmpty()) {
logger.info("ACCESS_LOG ___ {},{},{} ___ has been denied access to execute query ___ {} ___ in application ___ {} ___ NO ACCESS RULES EVALUATED", user.getUuid().toString(), user.getEmail(), user.getName(), formattedQuery, applicationName);
@@ -168,6 +174,7 @@ public boolean isAuthorized(Application application, Object requestBody, User us
.map(ar -> (ar.getMergedName().isEmpty() ? ar.getName() : ar.getMergedName()))
.collect(Collectors.joining(", ")) + "]");
+ logger.info("Login time: {}ms", System.currentTimeMillis() - startTime);
return result;
}
diff --git a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/utils/RestClientUtil.java b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/utils/RestClientUtil.java
index 6c9dacaf6..e96dc76c1 100644
--- a/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/utils/RestClientUtil.java
+++ b/pic-sure-auth-services/src/main/java/edu/harvard/hms/dbmi/avillach/auth/utils/RestClientUtil.java
@@ -4,9 +4,11 @@
import org.slf4j.LoggerFactory;
import org.springframework.http.*;
import org.springframework.http.client.ClientHttpRequestFactory;
+import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
@Component
@@ -64,4 +66,11 @@ public ResponseEntity retrievePostResponse(String uri, HttpEntity();
authRequest.put("access_token", accessToken);
authRequest.put("redirectURI", redirectURI);
+
+ authenticationService = new Auth0AuthenticationService(matchingService, userRepository, basicMailService, userService, connectionRepository, restClientUtil, true, false, "localhost");
}
// Tests missing parameters in the authentication request
@Test(expected = IllegalArgumentException.class)
public void testGetToken_MissingParameters() throws IOException {
- authenticationService.getToken(new HashMap<>()); // Empty map should trigger the exception
+ authenticationService.authenticate(new HashMap<>(), "localhost"); // Empty map should trigger the exception
}
// Tests the failure in retrieving user information, expecting an IOException to be converted into a NotAuthorizedException
@@ -72,7 +72,7 @@ public void testGetToken_MissingParameters() throws IOException {
public void testGetToken_UserInfoRetrievalFails() throws IOException {
when(this.restClientUtil.retrieveGetResponseWithRequestConfiguration(anyString(), any(HttpHeaders.class), any(ClientHttpRequestFactory.class)))
.thenThrow(new NotAuthorizedException("Failed to retrieve user info"));
- authenticationService.getToken(authRequest);
+ authenticationService.authenticate(authRequest, "localhost");
}
// Tests the scenario where the user ID is not found in the user info retrieved
@@ -80,7 +80,7 @@ public void testGetToken_UserInfoRetrievalFails() throws IOException {
public void testGetToken_NoUserIdInUserInfo() throws IOException {
when(this.restClientUtil.retrieveGetResponseWithRequestConfiguration(anyString(), any(), any()))
.thenReturn(new ResponseEntity<>("{}", HttpStatus.OK));
- authenticationService.getToken(authRequest);
+ authenticationService.authenticate(authRequest, "localhost");
}
// Tests a successful token retrieval scenario
@@ -91,7 +91,7 @@ public void testGetToken_Successful() throws Exception {
// return null for matching user
when(matchingService.matchTokenToUser(any())).thenReturn(null);
- HashMap token = authenticationService.getToken(authRequest);
+ HashMap token = authenticationService.authenticate(authRequest, "localhost");
assertNotNull(token);
}
@@ -110,23 +110,23 @@ public void testRetrieveUserInfo_WithRetries() throws Exception {
@Test(expected = NotAuthorizedException.class)
public void testGetToken_NoUserMatchingAndCreationFails() throws Exception {
setupNoUserMatchScenario();
- authenticationService.getToken(authRequest);
+ authenticationService.authenticate(authRequest, "localhost");
}
// Test scenario where denied access email is triggered
@Test
public void testGetToken_SendDeniedAccessEmail() throws Exception {
setupDeniedEmailScenario();
- this.authenticationService.setDeniedEmailEnabled("true");
+ this.authenticationService.setDeniedEmailEnabled(true);
try {
- authenticationService.getToken(authRequest);
+ authenticationService.authenticate(authRequest, "localhost");
} catch (Exception e) {
verify(basicMailService).sendDeniedAccessEmail(any());
}
}
private void setupSuccessfulTokenRetrievalScenario() throws IOException {
- this.authenticationService.setDeniedEmailEnabled("false");
+ this.authenticationService.setDeniedEmailEnabled(false);
JsonNode mockUserInfo = mock(JsonNode.class);
when(mockUserInfo.get("user_id")).thenReturn(mock(JsonNode.class));
when(mockUserInfo.get("user_id").asText()).thenReturn(userId);
diff --git a/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/AuthorizationServiceTest.java b/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/AuthorizationServiceTest.java
index cedb3c30f..583f98899 100644
--- a/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/AuthorizationServiceTest.java
+++ b/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/AuthorizationServiceTest.java
@@ -4,12 +4,10 @@
import edu.harvard.hms.dbmi.avillach.auth.enums.SecurityRoles;
import edu.harvard.hms.dbmi.avillach.auth.model.CustomUserDetails;
import edu.harvard.hms.dbmi.avillach.auth.repository.AccessRuleRepository;
-import edu.harvard.hms.dbmi.avillach.auth.service.impl.authorization.AccessRuleService;
import edu.harvard.hms.dbmi.avillach.auth.service.impl.authorization.AuthorizationService;
import edu.harvard.hms.dbmi.avillach.auth.utils.AuthNaming;
import org.junit.Before;
import org.junit.Test;
-import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -37,7 +35,7 @@ public void setUp() {
MockitoAnnotations.initMocks(this);
SecurityContextHolder.setContext(securityContext);
- accessRuleService = new AccessRuleService(accessRuleRepository);
+ accessRuleService = new AccessRuleService(accessRuleRepository, "false", "false", "false", "false","false", "false");
authorizationService = new AuthorizationService(accessRuleService, "fence,okta,open");
}
diff --git a/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/StudyAccessServiceTest.java b/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/StudyAccessServiceTest.java
index 9317b2b0c..2c219c91a 100644
--- a/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/StudyAccessServiceTest.java
+++ b/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/StudyAccessServiceTest.java
@@ -20,7 +20,7 @@ public class StudyAccessServiceTest {
private StudyAccessService studyAccessService;
@Mock
- private FENCEAuthenticationService fenceAuthenticationService;
+ private RoleService roleService;
@Mock
private FenceMappingUtility fenceMappingUtility;
@@ -46,7 +46,7 @@ public void testAddStudyAccess() {
studyMetaData.setConsentGroupCode("");
when(fenceMappingUtility.getFENCEMapping()).thenReturn(Map.of(studyIdentifier, studyMetaData));
- when(fenceAuthenticationService.upsertRole(null, "MANUAL_testStudy", "MANUAL_ role MANUAL_testStudy")).thenReturn(true);
+ when(roleService.upsertRole(null, "MANUAL_testStudy", "MANUAL_ role MANUAL_testStudy")).thenReturn(true);
String status = studyAccessService.addStudyAccess(studyIdentifier);
assertEquals("Role 'MANUAL_testStudy' successfully created", status);
@@ -60,7 +60,7 @@ public void testAddStudyAccessWithConsent() {
studyMetaData.setConsentGroupCode("c2");
when(fenceMappingUtility.getFENCEMapping()).thenReturn(Map.of(studyIdentifier, studyMetaData));
- when(fenceAuthenticationService.upsertRole(null, "MANUAL_testStudy2_c2", "MANUAL_ role MANUAL_testStudy2_c2")).thenReturn(true);
+ when(roleService.upsertRole(null, "MANUAL_testStudy2_c2", "MANUAL_ role MANUAL_testStudy2_c2")).thenReturn(true);
String status = studyAccessService.addStudyAccess(studyIdentifier);
assertEquals("Role 'MANUAL_testStudy2_c2' successfully created", status);
diff --git a/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/AuthenticationServiceTest.java b/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/AuthenticationServiceTest.java
index 2b3204861..674b6eeaa 100644
--- a/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/AuthenticationServiceTest.java
+++ b/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/AuthenticationServiceTest.java
@@ -12,7 +12,6 @@
import edu.harvard.hms.dbmi.avillach.auth.utils.RestClientUtil;
import org.junit.Before;
import org.junit.Test;
-import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.HttpHeaders;
@@ -46,7 +45,6 @@ public class AuthenticationServiceTest {
@Mock
private RestClientUtil restClientUtil;
- @InjectMocks
private Auth0AuthenticationService authenticationService;
private final String accessToken = "dummyAccessToken";
@@ -61,12 +59,14 @@ public void setUp() {
authRequest = new HashMap<>();
authRequest.put("access_token", accessToken);
authRequest.put("redirectURI", redirectURI);
+
+ authenticationService = new Auth0AuthenticationService(matchingService, userRepository, basicMailService, userService, connectionRepository, restClientUtil, true, false, "localhost");
}
// Tests missing parameters in the authentication request
@Test(expected = IllegalArgumentException.class)
public void testGetToken_MissingParameters() throws IOException {
- authenticationService.getToken(new HashMap<>()); // Empty map should trigger the exception
+ authenticationService.authenticate(new HashMap<>(), "localhost"); // Empty map should trigger the exception
}
// Tests the failure in retrieving user information, expecting an IOException to be converted into a NotAuthorizedException
@@ -74,7 +74,7 @@ public void testGetToken_MissingParameters() throws IOException {
public void testGetToken_UserInfoRetrievalFails() throws IOException {
when(this.restClientUtil.retrieveGetResponseWithRequestConfiguration(anyString(), any(HttpHeaders.class), any(ClientHttpRequestFactory.class)))
.thenThrow(new NotAuthorizedException("Failed to retrieve user info"));
- authenticationService.getToken(authRequest);
+ authenticationService.authenticate(authRequest, "localhost");
}
// Tests the scenario where the user ID is not found in the user info retrieved
@@ -82,7 +82,7 @@ public void testGetToken_UserInfoRetrievalFails() throws IOException {
public void testGetToken_NoUserIdInUserInfo() throws IOException {
when(this.restClientUtil.retrieveGetResponseWithRequestConfiguration(anyString(), any(), any()))
.thenReturn(new ResponseEntity<>("{}", HttpStatus.OK));
- authenticationService.getToken(authRequest);
+ authenticationService.authenticate(authRequest, "localhost");
}
// Tests a successful token retrieval scenario
@@ -93,7 +93,7 @@ public void testGetToken_Successful() throws Exception {
// return null for matching user
when(matchingService.matchTokenToUser(any())).thenReturn(null);
- HashMap token = authenticationService.getToken(authRequest);
+ HashMap token = authenticationService.authenticate(authRequest, "localhost");
assertNotNull(token);
}
@@ -112,23 +112,23 @@ public void testRetrieveUserInfo_WithRetries() throws Exception {
@Test(expected = NotAuthorizedException.class)
public void testGetToken_NoUserMatchingAndCreationFails() throws Exception {
setupNoUserMatchScenario();
- authenticationService.getToken(authRequest);
+ authenticationService.authenticate(authRequest, "localhost");
}
// Test scenario where denied access email is triggered
@Test
public void testGetToken_SendDeniedAccessEmail() throws Exception {
setupDeniedEmailScenario();
- this.authenticationService.setDeniedEmailEnabled("true");
+ this.authenticationService.setDeniedEmailEnabled(true);
try {
- authenticationService.getToken(authRequest);
+ authenticationService.authenticate(authRequest, "localhost");
} catch (Exception e) {
verify(basicMailService).sendDeniedAccessEmail(any());
}
}
private void setupSuccessfulTokenRetrievalScenario() throws IOException {
- this.authenticationService.setDeniedEmailEnabled("false");
+ this.authenticationService.setDeniedEmailEnabled(false);
JsonNode mockUserInfo = mock(JsonNode.class);
when(mockUserInfo.get("user_id")).thenReturn(mock(JsonNode.class));
when(mockUserInfo.get("user_id").asText()).thenReturn(userId);
diff --git a/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/OpenAuthenticationServiceTest.java b/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/OpenAuthenticationServiceTest.java
index ca04f97ea..2183fb665 100644
--- a/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/OpenAuthenticationServiceTest.java
+++ b/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authentication/OpenAuthenticationServiceTest.java
@@ -4,10 +4,9 @@
import edu.harvard.hms.dbmi.avillach.auth.entity.User;
import edu.harvard.hms.dbmi.avillach.auth.service.impl.RoleService;
import edu.harvard.hms.dbmi.avillach.auth.service.impl.UserService;
-import edu.harvard.hms.dbmi.avillach.auth.service.impl.authorization.AccessRuleService;
+import edu.harvard.hms.dbmi.avillach.auth.service.impl.AccessRuleService;
import org.junit.Before;
import org.junit.Test;
-import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -29,12 +28,13 @@ public class OpenAuthenticationServiceTest {
@Mock
private AccessRuleService accessRuleService;
- @InjectMocks
private OpenAuthenticationService openAuthenticationService;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+
+ openAuthenticationService = new OpenAuthenticationService(userService, roleService, accessRuleService, true);
}
@Test
@@ -53,7 +53,7 @@ public void testAuthenticate_ValidUUID() {
when(userService.findUserByUUID(uuid.toString())).thenReturn(user);
when(userService.getUserProfileResponse(any(Map.class))).thenReturn(claims);
- Map authenticate = openAuthenticationService.authenticate(authRequest);
+ Map authenticate = openAuthenticationService.authenticate(authRequest, "localhost");
verify(userService, never()).createOpenAccessUser(any(Role.class));
verify(userService).findUserByUUID(uuid.toString());
verify(userService).getUserProfileResponse(any(Map.class));
@@ -75,7 +75,7 @@ public void testAuthenticate_InvalidUUID() {
when(userService.createOpenAccessUser(any(Role.class))).thenReturn(createUser(UUID.randomUUID()));
when(userService.getUserProfileResponse(any(Map.class))).thenReturn(new HashMap<>());
- Map authenticate = openAuthenticationService.authenticate(authRequest);
+ Map authenticate = openAuthenticationService.authenticate(authRequest, "localhost");
assertNotNull(authenticate);
assertEquals(0, authenticate.size());
}
@@ -88,7 +88,7 @@ public void testAuthenticate_NoUUID() {
when(userService.createOpenAccessUser(any())).thenReturn(createUser(UUID.randomUUID()));
when(userService.getUserProfileResponse(any(Map.class))).thenReturn(new HashMap<>());
- Map authenticate = openAuthenticationService.authenticate(authRequest);
+ Map authenticate = openAuthenticationService.authenticate(authRequest, "localhost");
assertNotNull(authenticate);
verify(userService).createOpenAccessUser(any(Role.class));
diff --git a/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AccessRuleServiceTest.java b/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AccessRuleServiceTest.java
index 7594ca4c5..5cd22f2b4 100644
--- a/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AccessRuleServiceTest.java
+++ b/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AccessRuleServiceTest.java
@@ -2,6 +2,7 @@
import edu.harvard.hms.dbmi.avillach.auth.entity.AccessRule;
import edu.harvard.hms.dbmi.avillach.auth.repository.AccessRuleRepository;
+import edu.harvard.hms.dbmi.avillach.auth.service.impl.AccessRuleService;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
diff --git a/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AuthorizationServiceTest.java b/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AuthorizationServiceTest.java
index 4410dc563..8a46e3954 100644
--- a/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AuthorizationServiceTest.java
+++ b/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AuthorizationServiceTest.java
@@ -5,6 +5,7 @@
import edu.harvard.hms.dbmi.avillach.auth.enums.SecurityRoles;
import edu.harvard.hms.dbmi.avillach.auth.model.CustomUserDetails;
import edu.harvard.hms.dbmi.avillach.auth.repository.AccessRuleRepository;
+import edu.harvard.hms.dbmi.avillach.auth.service.impl.AccessRuleService;
import edu.harvard.hms.dbmi.avillach.auth.utils.AuthNaming;
import org.junit.Assert;
import org.junit.Before;
@@ -311,7 +312,7 @@ public void setUp() {
MockitoAnnotations.initMocks(this);
SecurityContextHolder.setContext(securityContext);
- accessRuleService = new AccessRuleService(accessRuleRepository);
+ accessRuleService = new AccessRuleService(accessRuleRepository, "false", "false", "false", "false","false", "false");
authorizationService = new AuthorizationService(accessRuleService, "fence,okta");
}
diff --git a/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AuthorizationServiceTestByUseCases.java b/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AuthorizationServiceTestByUseCases.java
index 60af75dda..34931dd89 100644
--- a/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AuthorizationServiceTestByUseCases.java
+++ b/pic-sure-auth-services/src/test/java/edu/harvard/hms/dbmi/avillach/auth/service/impl/authorization/AuthorizationServiceTestByUseCases.java
@@ -3,6 +3,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.harvard.hms.dbmi.avillach.auth.entity.AccessRule;
import edu.harvard.hms.dbmi.avillach.auth.repository.AccessRuleRepository;
+import edu.harvard.hms.dbmi.avillach.auth.service.impl.AccessRuleService;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -418,7 +419,7 @@ public static void init() {
@Before
public void setUp() {
AccessRuleRepository accessRuleRepository = Mockito.mock(AccessRuleRepository.class);
- accessRuleService = new AccessRuleService(accessRuleRepository);
+ accessRuleService = new AccessRuleService(accessRuleRepository, "false", "false", "false", "false","false", "false");
}
@Test
diff --git a/scripts/build_images.sh b/scripts/build_images.sh
deleted file mode 100755
index 6419c5076..000000000
--- a/scripts/build_images.sh
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/bin/sh
-logger() {
- MSG=$*
- TIMESTAMP=`date +%c`
- echo "${TIMESTAMP} ${MSG}"
-}
-#
-# This script will build psama image to be pushed to the Docker hub, from the local depository.
-# This script will NOT push the generated images automatically.
-# This script will tag the generated images as:
-# "dbmi/pic-sure-auth-services:${GITHUB_BRANCH}_${GIT_COMMIT_HASH}"
-# for the PSAMA back-end image
-#
-# Currently, the script requires Java 11 (11.0.2-open) and Maven to be
-# installed on the machine that is executing the build process.
-
-# Check if Java is 11.0.2
-CURRENT_JAVA_VERSION=$(java --version | head -1 | cut -d " " -f 2)
-if [ "${CURRENT_JAVA_VERSION}" != "11.0.2" ];
-then
- logger "Incorrect Java version. It is ${CURRENT_JAVA_VERSION}, but it should be 11.0.2."
- logger "Cannot proceed with docker image build."
- exit 255
-else
- logger "Current Java version has been verified. Proceed with Maven build"
-fi
-
-# TODO: Could use a check on the docker version and wether it is running or not.
-
-# Do the build from the root directory of the repo
-cd ..
-# Just in case this is built on a Mac
-find ./ -name ".DS_Store" -exec rm -f {} \; 2>/dev/null
-
-mvn clean install
-MAVEN_COMPLETION_STATUS=$?
-
-# The maven build will generate the PSAMA back-end .war file
-if [ $MAVEN_COMPLETION_STATUS -eq 0 ];
-then
- logger "Building .war file was successful."
- find ./ -name "*.war" -ls
-else
- logger "Error building .war files."
-fi
-
-# Build the PSAMA back-end docker image.
-# sub-task 1., Get the current GitHub branch and commit hash
-GITHUB_BRANCH=$(git branch | grep "*" | cut -d " " -f 2)
-GITHUB_COMMIT_HASH=$(git log | head -1 | cut -d " " -f 2 | cut -c 1-12)
-cd pic-sure-auth-services
-docker build . --rm --tag "dbmi/pic-sure-auth-services:${GITHUB_BRANCH}.${GITHUB_COMMIT_HASH}"
-CMD_STATUS=$?
-if [ $CMD_STATUS -eq 0 ];
-then
- logger "Successfully built PSAMA back-end docker image dbmi/pic-sure-auth-services:${GITHUB_BRANCH}.${GITHUB_COMMIT_HASH} locally."
-else
- logger "Failed to build PSAMA back-end docker image locally."
- exit 255
-fi
-cd ..
-
-echo "Images:"
-echo "dbmi/pic-sure-auth-services:${GITHUB_BRANCH}.${GITHUB_COMMIT_HASH}"
-logger "Done."
diff --git a/scripts/docker-compose.yml b/scripts/docker-compose.yml
deleted file mode 100644
index 3108529db..000000000
--- a/scripts/docker-compose.yml
+++ /dev/null
@@ -1,53 +0,0 @@
-version: '3'
-services:
-
- picsureauth:
- build:
- context: pic-sure-auth-services
- dockerfile: Dockerfile
- command: --debug *:8787
- depends_on:
- - picsureauthdb
- environment:
- - AUTH_CLIENT_SECRET=${AUTH_CLIENT_SECRET:-secret}
- - AUTH_CLIENT_ID=${AUTH_CLIENT_ID:-client_id}
- - AUTH_USER_ID_CLAIM=sub
- - AUTH_MYSQLADDRESS=picsureauthdb
- - AUTH0TOKEN=${AUTH0TOKEN:-nothing}
- - AUTH0HOST=https://avillachlab.auth0.com
- - systemName=${systemName:-PICSURE}
- - EMAIL_TEMPLATE_PATH=${EMAIL_TEMPLATE_PATH:-/opt/jboss/wildfly/emailTemplates}/
- - DENIED_EMAIL_ENABLED=${DENIED_EMAIL_ENABLED:-false}
- - COMMA_SEPARATED_EMAILS=${COMMA_SEPARATED_EMAILS:-dummyemail}
- - accessGrantEmailSubject=Testing
- - MAIL_USERNAME=${MAIL_USERNAME:-emailuser@avillach.lab}
- - MAIL_PASSWORD=${MAIL_PASSWORD:-email_password}
- - TOS_ENABLED:false
- ports:
- - 8787:8787
- expose:
- - 8080
- volumes:
- - ./pic-sure-auth-services/src/main/resources/emailTemplates:${EMAIL_TEMPLATE_PATH:-/opt/jboss/wildfly/emailTemplates}
- networks:
- - public
- env_file:
- - .env
-
- picsureauthdb:
- build:
- context: pic-sure-auth-db
- dockerfile: Dockerfile
- environment:
- - MYSQL_ROOT_PASSWORD=${AUTH_MYSQL_ROOT_PASSWORD:-password}
- - MYSQL_DATABASE=auth
- restart: always
- expose:
- - 3306
- ports:
- - 3306:3306
- networks:
- - public
-
-networks:
- public:
diff --git a/scripts/fence-deployment/db/Dockerfile b/scripts/fence-deployment/db/Dockerfile
deleted file mode 100644
index 4b292e6d4..000000000
--- a/scripts/fence-deployment/db/Dockerfile
+++ /dev/null
@@ -1,8 +0,0 @@
-FROM mysql:5.7
-
-COPY fence_db_setup.sql /tmp/fence_db_setup.sql
-
-EXPOSE 3306
-
-ENTRYPOINT ["docker-entrypoint.sh"]
-CMD ["mysqld","--init-file","/tmp/fence_db_setup.sql"]
diff --git a/scripts/fence-deployment/db/fence_db_setup.sql b/scripts/fence-deployment/db/fence_db_setup.sql
deleted file mode 100644
index 9da53a517..000000000
--- a/scripts/fence-deployment/db/fence_db_setup.sql
+++ /dev/null
@@ -1,366 +0,0 @@
-GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password';
-
-DROP DATABASE IF EXISTS `auth`;
-CREATE DATABASE IF NOT EXISTS `auth` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_bin */;
-USE `auth`;
--- MySQL dump 10.13 Distrib 5.7.17, for macos10.12 (x86_64)
---
--- Host: 127.0.0.1 Database: auth
--- ------------------------------------------------------
--- Server version 5.7.20
-
-/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
-/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
-/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
-/*!40101 SET NAMES utf8 */;
-/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
-/*!40103 SET TIME_ZONE='+00:00' */;
-/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
-/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
-/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-
---
--- Table structure for table `privilege`
---
-
--- DROP TABLE IF EXISTS `privilege`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `privilege` (
- `uuid` binary(16) NOT NULL,
- `description` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- `name` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- `application_id` binary(16) DEFAULT NULL,
- `queryTemplate` varchar(8192) DEFAULT NULL,
- `queryScope` varchar(512) DEFAULT NULL,
- PRIMARY KEY (`uuid`),
- UNIQUE KEY `UK_h7iwbdg4ev8mgvmij76881tx8` (`name`),
- KEY `FK61h3jewffk70b5ni4tsi5rhoy` (`application_id`),
- CONSTRAINT `FK61h3jewffk70b5ni4tsi5rhoy` FOREIGN KEY (`application_id`) REFERENCES `application` (`uuid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `role`
---
-
--- DROP TABLE IF EXISTS `role`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `role` (
- `uuid` binary(16) NOT NULL,
- `name` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- `description` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- PRIMARY KEY (`uuid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `role_privilege`
---
-
--- DROP TABLE IF EXISTS `role_privilege`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `role_privilege` (
- `role_id` binary(16) NOT NULL,
- `privilege_id` binary(16) NOT NULL,
- PRIMARY KEY (`role_id`,`privilege_id`),
- KEY `FKdkwbrwb5r8h74m1v7dqmhp99c` (`privilege_id`),
- CONSTRAINT `FKdkwbrwb5r8h74m1v7dqmhp99c` FOREIGN KEY (`privilege_id`) REFERENCES `privilege` (`uuid`),
- CONSTRAINT `FKsykrtrdngu5iexmbti7lu9xa` FOREIGN KEY (`role_id`) REFERENCES `role` (`uuid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `user`
---
-
--- DROP TABLE IF EXISTS `user`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `user` (
- `uuid` binary(16) NOT NULL,
- `auth0_metadata` varchar(8000) COLLATE utf8_bin DEFAULT NULL,
- `general_metadata` varchar(9000) COLLATE utf8_bin DEFAULT NULL,
- `acceptedTOS` datetime COLLATE utf8_bin DEFAULT NULL,
- `connectionId` binary(16) DEFAULT NULL,
- `email` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- `matched` bit(1) NOT NULL DEFAULT FALSE,
- `subject` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- `is_active` bit(1) NOT NULL DEFAULT TRUE,
- `long_term_token` varchar(4000) COLLATE utf8_bin DEFAULT NULL,
- `isGateAnyRelation` bit(1) NOT NULL DEFAULT TRUE,
- PRIMARY KEY (`uuid`),
- UNIQUE KEY `UK_r8xpakluitn685ua7pt8xjy9r` (`subject`),
- KEY `FKn8bku0vydfcnuwbqwgnbgg8ry` (`connectionId`),
- CONSTRAINT `FKn8bku0vydfcnuwbqwgnbgg8ry` FOREIGN KEY (`connectionId`) REFERENCES `connection` (`uuid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `userMetadataMapping`
---
-
--- DROP TABLE IF EXISTS `userMetadataMapping`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `userMetadataMapping` (
- `uuid` binary(16) NOT NULL,
- `auth0MetadataJsonPath` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- `connectionId` binary(16) DEFAULT NULL,
- `generalMetadataJsonPath` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- PRIMARY KEY (`uuid`),
- KEY `FKayr8vrvvwpgsdhxdyryt6k590` (`connectionId`),
- CONSTRAINT `FKayr8vrvvwpgsdhxdyryt6k590` FOREIGN KEY (`connectionId`) REFERENCES `connection` (`uuid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `user_role`
---
-
--- DROP TABLE IF EXISTS `user_role`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `user_role` (
- `user_id` binary(16) NOT NULL,
- `role_id` binary(16) NOT NULL,
- PRIMARY KEY (`user_id`,`role_id`),
- KEY `FKa68196081fvovjhkek5m97n3y` (`role_id`),
- CONSTRAINT `FK859n2jvi8ivhui0rl0esws6o` FOREIGN KEY (`user_id`) REFERENCES `user` (`uuid`),
- CONSTRAINT `FKa68196081fvovjhkek5m97n3y` FOREIGN KEY (`role_id`) REFERENCES `role` (`uuid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-/*!40101 SET character_set_client = @saved_cs_client */;
-/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
-
-CREATE TABLE `termsOfService` (
- `uuid` binary(16) NOT NULL,
- `dateUpdated` timestamp,
- `content` varchar(9000) COLLATE utf8_bin DEFAULT NULL,
- PRIMARY KEY (`uuid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `connection` (
- `uuid` binary(16) NOT NULL,
- `label` varchar(255) COLLATE utf8_bin NOT NULL,
- `id` varchar(255) COLLATE utf8_bin NOT NULL,
- `subprefix` varchar(255) COLLATE utf8_bin NOT NULL,
- `requiredFields` varchar(9000) COLLATE utf8_bin NOT NULL,
- PRIMARY KEY (`uuid`),
- UNIQUE KEY `id` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
-CREATE TABLE `application` (
- `uuid` binary(16) NOT NULL,
- `description` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- `enable` bit(1) NOT NULL DEFAULT b'1',
- `name` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- `token` varchar(2000) COLLATE utf8_bin DEFAULT NULL,
- `url` varchar(500) COLLATE utf8_bin DEFAULT NULL,
- PRIMARY KEY (`uuid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-
-INSERT INTO `application` (`uuid`, `description`, `enable`, `name`, `token`, `url`)
-VALUES
- (
- X'8B5722C962FD48D6B0BF4F67E53EFB2B',
- X'5049432D53555245206D756C7469706C6520646174612061636365737320415049',
- 1,
- X'50494353555245',
- NULL,
- X'2F706963737572657569'
-);
-
-
-CREATE TABLE `access_rule` (
- `uuid` binary(16) NOT NULL,
- `name` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- `description` varchar(2000) COLLATE utf8_bin DEFAULT NULL,
- `rule` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- `type` int(11) DEFAULT NULL,
- `value` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- `checkMapKeyOnly` bit(1) NOT NULL,
- `checkMapNode` bit(1) NOT NULL,
- `subAccessRuleParent_uuid` binary(16) DEFAULT NULL,
- `isGateAnyRelation` bit(1) NOT NULL,
- `isEvaluateOnlyByGates` bit(1) NOT NULL,
- PRIMARY KEY (`uuid`),
- KEY `FK8rovvx363ui99ce21sksmg6uy` (`subAccessRuleParent_uuid`),
- CONSTRAINT `FK8rovvx363ui99ce21sksmg6uy` FOREIGN KEY (`subAccessRuleParent_uuid`) REFERENCES `access_rule` (`uuid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-
-CREATE TABLE `accessRule_privilege` (
- `privilege_id` binary(16) NOT NULL,
- `accessRule_id` binary(16) NOT NULL,
- PRIMARY KEY (`privilege_id`,`accessRule_id`),
- KEY `FK89rf30kbf9d246jty2dd7qk99` (`accessRule_id`),
- CONSTRAINT `FK7x47w81gpua380qd7lp9x94l1` FOREIGN KEY (`privilege_id`) REFERENCES `privilege` (`uuid`),
- CONSTRAINT `FK89rf30kbf9d246jty2dd7qk99` FOREIGN KEY (`accessRule_id`) REFERENCES `access_rule` (`uuid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-
-CREATE TABLE `accessRule_gate` (
- `accessRule_id` binary(16) NOT NULL,
- `gate_id` binary(16) NOT NULL,
- PRIMARY KEY (`accessRule_id`,`gate_id`),
- KEY `FK6re4kcq9tyl45jv9yg584doem` (`gate_id`),
- CONSTRAINT `FK6re4kcq9tyl45jv9yg584doem` FOREIGN KEY (`gate_id`) REFERENCES `access_rule` (`uuid`),
- CONSTRAINT `FKe6l5ee7f207958mm3anpsmqom` FOREIGN KEY (`accessRule_id`) REFERENCES `access_rule` (`uuid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-
-
-/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
-/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
-/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
-/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
-/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
-/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
-/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-
--- Add temporary config user
-
-SET @uuidUser = REPLACE(uuid(),'-','');
-
-INSERT INTO user (
- `uuid`,
- `general_metadata`,
- `subject`,
- `email`
-) VALUES (
- unhex(@uuidUser),
- '{"description":"Temporary user entry, for configuraiton"}',
- 'configurator|temporary_account',
- 'configurator@avillach.lab'
-);
-
-# Add the initial ADMIN role for the user.
-# Assuming, that all superuser privileges have been
-# assigned to this role, already, during creation
-# of the database.
-INSERT INTO user_role (
- `user_id`,
- `role_id`
-) VALUES (
- UNHEX(@uuidUser),
- (SELECT uuid FROM role WHERE name = 'PIC-SURE Top Admin')
-);
-
-
-DROP DATABASE IF EXISTS `picsure`;
-CREATE DATABASE IF NOT EXISTS `picsure` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_bin */;
-USE `picsure`;
--- MySQL dump 10.13 Distrib 5.7.17, for macos10.12 (x86_64)
---
--- Host: 127.0.0.1 Database: picsure
--- ------------------------------------------------------
--- Server version 5.7.20
-
-/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
-/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
-/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
-/*!40101 SET NAMES utf8 */;
-/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
-/*!40103 SET TIME_ZONE='+00:00' */;
-/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
-/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
-/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-
---
--- Table structure for table `query`
---
-
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `query` (
- `uuid` binary(16) NOT NULL,
- `query` longtext COLLATE utf8_bin,
- `readyTime` date DEFAULT NULL,
- `resourceResultId` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- `startTime` date DEFAULT NULL,
- `status` int(11) DEFAULT NULL,
- `resourceId` binary(16),
- `metadata` blob,
- PRIMARY KEY (`uuid`),
- KEY `FKhgiwd8kmi6pjw16txfhyqk2w0` (`resourceId`),
- CONSTRAINT `FKhgiwd8kmi6pjw16txfhyqk2w0` FOREIGN KEY (`resourceId`) REFERENCES `resource` (`uuid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `resource`
---
-
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `resource` (
- `uuid` binary(16) NOT NULL,
- `targetURL` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- `resourceRSPath` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- `description` varchar(8192) COLLATE utf8_bin DEFAULT NULL,
- `name` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- `token` varchar(8192) COLLATE utf8_bin DEFAULT NULL,
- PRIMARY KEY (`uuid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `user`
---
-
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `user` (
- `uuid` binary(16) NOT NULL,
- `roles` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- `subject` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- `userId` varchar(255) COLLATE utf8_bin DEFAULT NULL,
- PRIMARY KEY (`uuid`),
- UNIQUE KEY `subject_UNIQUE` (`subject`),
- UNIQUE KEY `userId_UNIQUE` (`userId`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-/*!40101 SET character_set_client = @saved_cs_client */;
-/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
-
-/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
-/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
-/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
-/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
-/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
-/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
-/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-
--- Dump completed on 2018-05-24 16:46:11
-
-START TRANSACTION;
-
-DELETE FROM `resource` WHERE `name` = 'hpds';
-
-SET @uuidResource = REPLACE('02e23f52-f354-4e8b-992c-d37c8b9ba140','-','');
-
-INSERT INTO `resource` (
- `uuid`,
- `targetURL`,
- `resourceRSPath`,
- `description`,
- `name`,
- `token`
-) VALUES (
- unhex(@uuidResource),
- NULL,
- 'http://localhost:8881/hpds',
- 'Basic HPDS resource',
- 'hpds',
- NULL
-);
-
-COMMIT;
-
-
-
-
-
diff --git a/scripts/fence-deployment/docker-compose.yml b/scripts/fence-deployment/docker-compose.yml
deleted file mode 100644
index ac7d78043..000000000
--- a/scripts/fence-deployment/docker-compose.yml
+++ /dev/null
@@ -1,159 +0,0 @@
-version: '3.3'
-services:
-
- httpd:
- build:
- context: ./httpd
- dockerfile: Dockerfile
- ports:
- - 80:80
- - 443:443
- depends_on:
- - psama
- - picsure
- volumes:
- - ./httpd/psamaui_settings.json:/usr/local/apache2/htdocs/psamaui/settings/settings.json
- - ./httpd/psamaui_settings.json:/usr/local/apache2/htdocs/picsureui/settings/settings.json
- networks:
- - public
-
- picsure:
- image: jboss/wildfly:17.0.0.Final
- environment:
- - JAVA_OPTS=-Xms1024m -Xmx2g -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true
- restart: always
- environment:
- - PICSURE_CLIENT_SECRET=nQWNixJHJ_jRWd6ZuFY9XJNdt9-gDvqBkpN9b80qHn7ySpCUfTdwIm0F85UZgbB4
- - PICSURE_USER_ID_CLAIM=sub
- - RESULT_FORMAT=JSON
- - IRCT_TARGET_URL=http://httpd/irct
- - PICSURE_DB_HOST=db
- - PICSURE_DB_USERNAME=root
- - PICSURE_DB_PASSWORD=password
- - PICSURE_DB_NAME=picsure
- - PICSURE_INTROSPECTION_URL=http://psama:8080/pic-sure-auth-services/auth/token/inspect
- - PICSURE_INTROSPECTION_TOKEN=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJQU0FNQV9BUFBMSUNBVElPTnxtaXNzaW5nUGljU3VyZUFwcFVVSUQiLCJ1c2VyX2lkIjoiUFNBTUFfQVBQTElDQVRJT058UElDU1VSRSIsImV4cCI6MTU3MTEyMDQxNywiaWF0IjoxNTcwMjIwNDE3fQ.8a6XEJBHsb6uAWBdU1MddM5NuAHPMMl_mhQ7h42gV0E
- expose:
- - 8080
- networks:
- - public
- entrypoint: /opt/jboss/wildfly/bin/standalone.sh -b 0.0.0.0 -bmanagement 0.0.0.0 --debug 0.0.0.0:8787
- user: root
- volumes:
- - ./picsure/standalone.xml:/opt/jboss/wildfly/standalone/configuration/standalone.xml
- - ./picsure/modules/system/layers/base/com/sql/:/opt/jboss/wildfly/modules/system/layers/base/com/sql/
- - ./picsure/deployments:/opt/jboss/wildfly/standalone/deployments
- depends_on:
- - db
- - copy-pic-sure-backend-war
- - copy-pic-sure-resource-war
-
- psama:
- image: jboss/wildfly:17.0.0.Final
- environment:
- - JAVA_OPTS=-Xms1024m -Xmx2g -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true
- restart: always
- environment:
- - SYSTEM_NAME=DataStageDev2
- - AUTH_CLIENT_ID=ywAq4Xu4Kl3uYNdm3m05Cc5ow0OibvXt
- - AUTH_CLIENT_SECRET=nQWNixJHJ_jRWd6ZuFY9XJNdt9-gDvqBkpN9b80qHn7ySpCUfTdwIm0F85UZgbB4
- - PSAMA_DB_HOST=db
- - PSAMA_DB_NAME=auth
- - PSAMA_DB_USERNAME=root
- - PSAMA_DB_PASSWORD=password
- - IDP_PROVIDER=fence
- - IDP_PROVIDER_URI=https://staging.datastage.io
- - FENCE_CLIENT_ID=3YkHUAoPSwaRWzSuNN0DyDbJeU1AxrMVkXBczDo6
- - FENCE_CLIENT_SECRET=W7JGecNQ91fMFRb0YVTRnqJ6fytPK4FIK2ZCsAbiQMbHaoTENHGzLFD
- - EMAIL_TEMPLATE_PATH=/tmp/config/emailTemplates/
- - MAIL_USERNAME=gkorodi@gmail.com
- - MAIL_PASSWORD=Trump!2020
- expose:
- - 8080
- - 8787
- ports:
- - 8787:8787
- - 8080:8080
- networks:
- - public
- entrypoint: /opt/jboss/wildfly/bin/standalone.sh -b 0.0.0.0 -bmanagement 0.0.0.0 --debug 0.0.0.0:8787
- user: root
- volumes:
- - ./psama/standalone.xml:/opt/jboss/wildfly/standalone/configuration/standalone.xml
- - ./psama/modules/system/layers/base/com/sql/:/opt/jboss/wildfly/modules/system/layers/base/com/sql/
- - ./psama/modules/system/layers/base/com/oracle/:/opt/jboss/wildfly/modules/system/layers/base/com/oracle/
- - ./psama/emailTemplates/:/tmp/config/emailTemplates/
- - ./psama/deployments:/opt/jboss/wildfly/standalone/deployments
- depends_on:
- - db
- - copy-pic-sure-auth-war
-
- copy-pic-sure-auth-war:
- image: dbmi/pic-sure-auth-services:fence-integration_72ef997e3346
- user: root
- volumes:
- - ./wildfly/deployments:/var/tmp
- entrypoint: cp /opt/jboss/wildfly/standalone/deployments/pic-sure-auth-services.war /var/tmp/pic-sure-auth-services.war
- networks:
- - public
-
- copy-pic-sure-backend-war:
- image: dbmi/picsure2:master.7a9b0c5
- user: root
- volumes:
- - ./picsure/deployments:/var/tmp
- entrypoint: cp /opt/jboss/wildfly/standalone/deployments/pic-sure-api-2.war /var/tmp/pic-sure-api-2.war
- networks:
- - public
-
- copy-pic-sure-resource-war:
- image: dbmi/pic-sure-irct-resource:picsure310.ef69613
- user: root
- volumes:
- - ./picsure/deployments:/var/tmp
- entrypoint: cp /opt/jboss/wildfly/standalone/deployments/pic-sure-irct-resource.war /var/tmp/pic-sure-irct-resource.war
- networks:
- - public
-
-# hpds:
-# image: dbmi/pic-sure-hpds:master_fbf04e7
-# entrypoint: java -Xdebug -Xrunjdwp:transport=dt_socket,address=0.0.0.0:8000,server=y,suspend=n -XX:+UseParallelGC -XX:SurvivorRatio=250 -Xms1g -Xmx2g -server -jar hpds.jar -httpPort 8080 -DCACHE_SIZE=10 -DSMALL_TASK_THREADS=1 -DLARGE_TASK_THREADS=1 -DSMALL_JOB_LIMIT=100 -DID_BATCH_SIZE=2000
-# environment:
-# - CACHESIZE=500
-# - HEAPSIZE=2048
-# - ID_BATCH_SIZE=50000
-# - LARGE_TASK_THREADS=1
-# - SMALL_JOB_LIMIT=100
-# - SMALL_TASK_THREADS=1
-# - SURVIVOR_RATIO=255
-# volumes:
-# - /scratch/hpds_symlink/:/opt/local/phenocube
-# - /scratch/hpds_symlink/:/opt/local/hpds
-# - /scratch/hpds_symlink/:/opt/local/hpds/variants
-# - /scratch/hpds_symlink/:/opt/local/hpds/all
-# restart: always
-# networks:
-# - public
-# expose:
-# - 8080
-# ports:
-# - 8080:8080
-
- db:
- build:
- context: db
- dockerfile: Dockerfile
- image: mysql
- environment:
- - MYSQL_ROOT_PASSWORD=${AUTH_MYSQL_ROOT_PASSWORD:-password}
- - MYSQL_DATABASE=auth
- restart: always
- expose:
- - 3306
- ports:
- - 3306:3306
- networks:
- - public
-
-networks:
- public:
diff --git a/scripts/fence-deployment/fence.sh b/scripts/fence-deployment/fence.sh
deleted file mode 100755
index 0e4a1ef9f..000000000
--- a/scripts/fence-deployment/fence.sh
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/sh
-
-export REF_REPO_DIR=/Users/gabor/pic-sure-i2b2-transmart
-
-config() {
- # Create directory for HPDS container
- mkdir -p /scratch/hpds_symlink/
-}
-
-build() {
- # Build HTTPD container, with settings and directory structure
- docker-compose build
-}
-
-up() {
- # Start up all containers
- docker-compose up -d
-}
-
-down() {
- docker-compose down
-}
-
-logs() {
- docker-compose logs $*
-}
-
-ps() {
- docker-compose ps
-}
-
-rebuild() {
- docker-compose down
- #docker system prune --force --all --volumes
- docker-compose pull
- docker-compose build
- docker-compose up -d
-}
-
-$*
diff --git a/scripts/fence-deployment/httpd/Dockerfile b/scripts/fence-deployment/httpd/Dockerfile
deleted file mode 100644
index 6c47bbc72..000000000
--- a/scripts/fence-deployment/httpd/Dockerfile
+++ /dev/null
@@ -1,34 +0,0 @@
-FROM dbmi/pic-sure-hpds-ui:master.0800720 AS picsureui
-FROM dbmi/pic-sure-auth-ui:fence-integration_72ef997e3346 AS psamaui
-FROM httpd:2.4.27-alpine
-
-RUN apk add --update openssl sed curl jq python3
-RUN pip3 install --upgrade pip && pip install PyJWT
-
-# Replace virtual host config file with ours
-COPY httpd-vhosts.conf ${HTTPD_PREFIX}/conf/extra/httpd-vhosts.conf
-
-# Enable virtual hosting config file
-RUN sed -i '/^#Include conf.extra.httpd-vhosts.conf/s/^#//' ${HTTPD_PREFIX}/conf/httpd.conf
-
-# Enable necessary proxy modules
-RUN sed -i '/^#LoadModule proxy_module/s/^#//' ${HTTPD_PREFIX}/conf/httpd.conf
-RUN sed -i '/^#LoadModule proxy_http_module/s/^#//' ${HTTPD_PREFIX}/conf/httpd.conf
-RUN sed -i '/^#LoadModule proxy_connect_module/s/^#//' ${HTTPD_PREFIX}/conf/httpd.conf
-
-#### SSL ####
-# enable ssl
-RUN sed -i '/^#LoadModule ssl_module modules\/mod_ssl.so/s/^#//' ${HTTPD_PREFIX}/conf/httpd.conf
-RUN sed -i '/^#LoadModule rewrite_module modules\/mod_rewrite.so/s/^#//' ${HTTPD_PREFIX}/conf/httpd.conf
-RUN sed -i '/^#LoadModule socache_shmcb_module modules\/mod_socache_shmcb.so/s/^#//' ${HTTPD_PREFIX}/conf/httpd.conf
-RUN mkdir /usr/local/apache2/logs/ssl_mutex
-
-COPY ./cert/server.key ${HTTPD_PREFIX}/cert/
-COPY ./cert/server.chain.crt ${HTTPD_PREFIX}/cert/
-COPY ./cert/server.crt ${HTTPD_PREFIX}/cert/
-COPY ./cert/server.chain ${HTTPD_PREFIX}/cert/
-
-COPY --from=psamaui /usr/local/apache2/htdocs ${HTTPD_PREFIX}/htdocs
-COPY --from=picsureui /usr/local/apache2/htdocs ${HTTPD_PREFIX}/htdocs
-
-COPY index.html ${HTTPD_PREFIX}/htdocs/
diff --git a/scripts/fence-deployment/httpd/cert/server.chain b/scripts/fence-deployment/httpd/cert/server.chain
deleted file mode 100644
index 0d9f49e20..000000000
--- a/scripts/fence-deployment/httpd/cert/server.chain
+++ /dev/null
@@ -1,17 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICpDCCAYwCCQCgfYbxmSm3hjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
-b2NhbGhvc3QwHhcNMTkwMzI5MTg1NDA0WhcNMjAwMzI4MTg1NDA0WjAUMRIwEAYD
-VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCw
-i3MoGmKL3EUk2en4bx1YSUR9ZfOmhB65r9schwdfSf1gugJb9YrGPWt2wwBltXQu
-JzZ75GtsgxtDPQZSwUrBxoUi0Aps0SU1yoErFRAT4ChYDDBpy0tMHNBpdCrH1Tk4
-oJV1BtTpW781BFvScx7TiAZucAnjxYNEdXToqtpiUP2IBATYc5eJMv9jrPSK2F8C
-AohbodPXsLcEX6JtiRYk7hDoKm+Xy7+zz3go+9Tynv2AjM8IBRsZ2enyXBXVIC/q
-k6dCzza4weMzikKQFgDXF+nDm9tFe8/rVXNPeAYek1osluTtjqzBYqffCAbLxR6N
-fI392T+C3nRG+oVTkPbLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFymuTGjusg
-aUiACo7cr/QvCQN8f5m7CtZUZ4NnAb8B8mq/gUFY/bzKO7tbyZipZIdndRtJfrxC
-1D3cV3ofVb3GrmFs1bbAYM1+qyaEnidZxly9Srbf8aoUgafnNXk6dRJGLRKIWN5V
-3upVbCWUDqRC409bSk6sdcr0LbWUMF8dP8GeySV0MeyhM1jd4SVZzOQ3IS0JXeiQ
-rn7C7TQmG4vcbHoaoTmgQh39iJRyxL9QyHqhAbfFLdN5bSyqOck7GaVhIFhhAl3y
-qmprQVjRSlxfnDHq1PCGY+SPLW8QpUFP4abzPY7kJ+V/lBWyrFm3bwyFQIqN01zD
-5Zg/Jyl24+Y=
------END CERTIFICATE-----
diff --git a/scripts/fence-deployment/httpd/cert/server.chain.crt b/scripts/fence-deployment/httpd/cert/server.chain.crt
deleted file mode 100644
index 6078724c0..000000000
--- a/scripts/fence-deployment/httpd/cert/server.chain.crt
+++ /dev/null
@@ -1 +0,0 @@
-PLACEHOLDER FILE, replace with real cert
\ No newline at end of file
diff --git a/scripts/fence-deployment/httpd/cert/server.crt b/scripts/fence-deployment/httpd/cert/server.crt
deleted file mode 100644
index 0d9f49e20..000000000
--- a/scripts/fence-deployment/httpd/cert/server.crt
+++ /dev/null
@@ -1,17 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICpDCCAYwCCQCgfYbxmSm3hjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
-b2NhbGhvc3QwHhcNMTkwMzI5MTg1NDA0WhcNMjAwMzI4MTg1NDA0WjAUMRIwEAYD
-VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCw
-i3MoGmKL3EUk2en4bx1YSUR9ZfOmhB65r9schwdfSf1gugJb9YrGPWt2wwBltXQu
-JzZ75GtsgxtDPQZSwUrBxoUi0Aps0SU1yoErFRAT4ChYDDBpy0tMHNBpdCrH1Tk4
-oJV1BtTpW781BFvScx7TiAZucAnjxYNEdXToqtpiUP2IBATYc5eJMv9jrPSK2F8C
-AohbodPXsLcEX6JtiRYk7hDoKm+Xy7+zz3go+9Tynv2AjM8IBRsZ2enyXBXVIC/q
-k6dCzza4weMzikKQFgDXF+nDm9tFe8/rVXNPeAYek1osluTtjqzBYqffCAbLxR6N
-fI392T+C3nRG+oVTkPbLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFymuTGjusg
-aUiACo7cr/QvCQN8f5m7CtZUZ4NnAb8B8mq/gUFY/bzKO7tbyZipZIdndRtJfrxC
-1D3cV3ofVb3GrmFs1bbAYM1+qyaEnidZxly9Srbf8aoUgafnNXk6dRJGLRKIWN5V
-3upVbCWUDqRC409bSk6sdcr0LbWUMF8dP8GeySV0MeyhM1jd4SVZzOQ3IS0JXeiQ
-rn7C7TQmG4vcbHoaoTmgQh39iJRyxL9QyHqhAbfFLdN5bSyqOck7GaVhIFhhAl3y
-qmprQVjRSlxfnDHq1PCGY+SPLW8QpUFP4abzPY7kJ+V/lBWyrFm3bwyFQIqN01zD
-5Zg/Jyl24+Y=
------END CERTIFICATE-----
diff --git a/scripts/fence-deployment/httpd/cert/server.key b/scripts/fence-deployment/httpd/cert/server.key
deleted file mode 100644
index eeedd0a8d..000000000
--- a/scripts/fence-deployment/httpd/cert/server.key
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCwi3MoGmKL3EUk
-2en4bx1YSUR9ZfOmhB65r9schwdfSf1gugJb9YrGPWt2wwBltXQuJzZ75GtsgxtD
-PQZSwUrBxoUi0Aps0SU1yoErFRAT4ChYDDBpy0tMHNBpdCrH1Tk4oJV1BtTpW781
-BFvScx7TiAZucAnjxYNEdXToqtpiUP2IBATYc5eJMv9jrPSK2F8CAohbodPXsLcE
-X6JtiRYk7hDoKm+Xy7+zz3go+9Tynv2AjM8IBRsZ2enyXBXVIC/qk6dCzza4weMz
-ikKQFgDXF+nDm9tFe8/rVXNPeAYek1osluTtjqzBYqffCAbLxR6NfI392T+C3nRG
-+oVTkPbLAgMBAAECggEAcsUlRuPoPr4i4TMdTJmHvTZcZR0bSZxIkTSGwEP0AfmK
-1A/4qqm03u1c6Gca4gQVlE9/twkm4PNWjN6mNrRcEh8pvBj9PgK1KwQL9uMJgbJO
-5/Z8nro/qCpvPq77hM/UFEEpCFw5m78+TYwY2XZniuK6M594fm+Px7iIGR3BPPoP
-WBquXLHb2dLRk6DmFzCKpnkgZDf8IbgS1I0094U5T9952YCUI1qwckIXA+hxzFf2
-Llf8opGJAvpvOl58lNFlbzLBSFtgIlJPcGx/X95RDa4TsDc0qwTixCPkjyxRMWom
-k8ajMMbnTu0nD1o64Xe2iCR9ENyOTLId1ShPGRsRmQKBgQDbtK8bcvHBD1daRyVm
-kn5UtqvIqMniT0K7ARM9YoVDSKt/vMVnifnIP3je6B8pSjNc1ng/lzsY3i/BjLSJ
-Z7ElCp08GXQ8imarlwvhc+fwCNPiQHQokRnaJOjHwWWAtPTG1Z/4FOQfZZoDalCK
-yGbb3Ti7BEr4N4tUPKUFTXO5ZQKBgQDNtX4ObolykMVl/lhT978+1Yo53XeFIEMH
-8slM1GUUzJKXpyvFVwfxns3ve+gVMhlOMwkGFbC+pnp3M8ELL1J2snazfMan7Ivp
-vYegvvBkmlT3Mm3VBl4p8sbR+uiMXDfPHtw0a1f5bP1nnW4J8733gj0AxVrG72nS
-ooVmWKYEbwKBgFcC6PKjBDGkhMDhOmO0Eso0CjaO+l1hbJkpJNiDwylRh3IwbbHC
-yCTRVmpZXbX5h/v1iGwO1b3UiO9LbViZs2NrH7hkkE9FtMGyMWdZgvriVB/fzOEg
-DjABvBsYcb2WbPauNguHIo14rJU7rqg4E9xxcX1HhvVk8g4rcmN2OCWtAoGABWyD
-pl3DwgGPMuFB8vTVVhLLUjtEq33uRodgR2ZSQ/og417FCK8CxpwpUecyd1yazjUK
-R97KijxZfksfC+xzgC20c4cWtdbG2aLlsJdYP07SbrIlszg3w2NjWqYC+7ByyENI
-CxnJeAonpFPCUwDaQWxtr1eEzToC0Er4uXoc5oECgYBz5wPLICW8rbVaONcXLmTK
-Z5s1qruKWzDwXz7vPPyT7IJIoEteInnTbjkbE9Bec/FBJ6xq1inh/g0mZVVZ/IAw
-bI6T0C+3HsEoxRFloNQhJcGnwNOqwZM0YTrHJPkWCiNt5oq97xwwjjPtXg3fGi8H
-WQ/t6CL85CL3Ck1tFPH0YQ==
------END PRIVATE KEY-----
diff --git a/scripts/fence-deployment/httpd/httpd-vhosts.conf b/scripts/fence-deployment/httpd/httpd-vhosts.conf
deleted file mode 100644
index 07309bd05..000000000
--- a/scripts/fence-deployment/httpd/httpd-vhosts.conf
+++ /dev/null
@@ -1,79 +0,0 @@
-Listen 443
-
-##
-## SSL Global Context
-##
-## All SSL configuration in this context applies both to
-## the main server and all SSL-enabled virtual hosts.
-##
-
-#
-# Some MIME-types for downloading Certificates and CRLs
-#
-AddType application/x-x509-ca-cert .crt
-AddType application/x-pkcs7-crl .crl
-
-SSLCipherSuite HIGH:MEDIUM:!MD5:!RC4:!3DES
-SSLProxyCipherSuite HIGH:MEDIUM:!MD5:!RC4:!3DES
-
-
-SSLHonorCipherOrder on
-
-SSLProtocol all -SSLv2 -SSLv3
-SSLProxyProtocol all -SSLv2 -SSLv3
-SSLPassPhraseDialog builtin
-
-SSLSessionCache "shmcb:${HTTPD_PREFIX}/logs/ssl_scache(512000)"
-SSLSessionCacheTimeout 300
-
-Mutex "file:${HTTPD_PREFIX}/logs/ssl_mutex"
-
-
- ServerName localhost
- RewriteEngine On
- ProxyPreserveHost On
- RewriteCond ${HTTPS} off [OR]
- RewriteCond %{HTTP_HOST} ^(?:)?(.+)$ [NC]
- RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=301]
-
-
-
- ServerName localhost
-
- SSLProxyEngine On
- SSLProxyCheckPeerCN off
-
- SSLCertificateFile "${HTTPD_PREFIX}/cert/server.crt"
- SSLCertificateKeyFile "${HTTPD_PREFIX}/cert/server.key"
- SSLCertificateChainFile "${HTTPD_PREFIX}/cert/server.chain"
-
- RewriteEngine On
- ProxyPreserveHost On
-
- RewriteRule ^/static/(.*)$ /static/$1 [L]
-
- RewriteRule ^/picsure/(.*)$ "http://picsure:8080/pic-sure-api-2/PICSURE/$1" [P]
- RewriteRule ^/picsure-irct/(.*)$ "http://picsure:8080/pic-sure-irct-resource/pic-sure/v1.4/$1" [P]
- RewriteRule ^/psama/(.*)$ "http://psama:8080/pic-sure-auth-services/auth/$1" [P]
-
- RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
- RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-d
-
- RewriteRule ^/psamaui/(.*)$ /psamaui/index.html [C]
- RewriteRule ^/picsureui/(.*)$ /picsureui/index.html [C]
-
- RewriteRule (.*) / [L]
- ErrorDocument 404 /index.html
-
- DocumentRoot "${HTTPD_PREFIX}/htdocs"
-
- ErrorLog "${HTTPD_PREFIX}/logs/error_log"
- TransferLog "${HTTPD_PREFIX}/logs/access_log"
- CustomLog "${HTTPD_PREFIX}/logs/ssl_request_log" \
- "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
-
- BrowserMatch "MSIE [2-5]" \
- nokeepalive ssl-unclean-shutdown \
- downgrade-1.0 force-response-1.0
-
-
diff --git a/scripts/fence-deployment/httpd/index.html b/scripts/fence-deployment/httpd/index.html
deleted file mode 100644
index 773013e5a..000000000
--- a/scripts/fence-deployment/httpd/index.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
- If you are note redirected automatically, please click the below link,
- to be redirected.
-
- PIC-SURE UI
-
-
-
-
diff --git a/scripts/fence-deployment/httpd/picsureui_settings.json b/scripts/fence-deployment/httpd/picsureui_settings.json
deleted file mode 100644
index 28a52b1e2..000000000
--- a/scripts/fence-deployment/httpd/picsureui_settings.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "resources": [
- {
- "id" : "datastage",
- "name" : "datastage",
- "basePath" : "/picsure",
- "findPath" : "/PIC-SURE/search"
- }
- ],
- "picSureResourceId":"02e23f52-f354-4e8b-992c-d37c8b9ba140",
- "applicationIdForBaseQuery":"8b5722c9-62fd-48d6-b0bf-4f67e53efb2b",
- "helpLink": "mailto:sample@email.com",
- "advancedSearchLink": "/transmart/login/callback_processor"
-}
diff --git a/scripts/fence-deployment/httpd/psamaui_settings.json b/scripts/fence-deployment/httpd/psamaui_settings.json
deleted file mode 100644
index b3f0d264b..000000000
--- a/scripts/fence-deployment/httpd/psamaui_settings.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "resources": [
- {
- "id" : "datastage",
- "name" : "datastage",
- "basePath" : "/picsure",
- "findPath" : "/PIC-SURE/search"
- }
- ],
- "picSureResourceId":"02e23f52-f354-4e8b-992c-d37c8b9ba140",
- "applicationIdForBaseQuery":"8b5722c9-62fd-48d6-b0bf-4f67e53efb2b",
- "helpLink": "mailto:sample@email.com",
- "client_id":"NA",
- "auth0domain":"__PSAMA_AUTH_DOMAIN__",
- "psamaServiceUrl":"/psama",
- "customizeAuth0Login": true,
- "basePath":"/psama",
- "idp_provider": "fence",
- "idp_provider_uri":"https://staging.datastage.io",
- "fence_client_id": "3YkHUAoPSwaRWzSuNN0DyDbJeU1AxrMVkXBczDo6",
- "fence_redirect_url": "https://datastage-i2b2-transmart-stage.aws.dbmi.hms.harvard.edu/psamaui/login/"
-}
diff --git a/scripts/fence-deployment/picsure/modules/system/layers/base/com/sql/mysql/main/module.xml b/scripts/fence-deployment/picsure/modules/system/layers/base/com/sql/mysql/main/module.xml
deleted file mode 100644
index e7362db95..000000000
--- a/scripts/fence-deployment/picsure/modules/system/layers/base/com/sql/mysql/main/module.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/scripts/fence-deployment/picsure/modules/system/layers/base/com/sql/mysql/main/mysql-connector-java-5.1.38.jar b/scripts/fence-deployment/picsure/modules/system/layers/base/com/sql/mysql/main/mysql-connector-java-5.1.38.jar
deleted file mode 100644
index be09493c0..000000000
Binary files a/scripts/fence-deployment/picsure/modules/system/layers/base/com/sql/mysql/main/mysql-connector-java-5.1.38.jar and /dev/null differ
diff --git a/scripts/fence-deployment/picsure/standalone.xml b/scripts/fence-deployment/picsure/standalone.xml
deleted file mode 100644
index b671a4555..000000000
--- a/scripts/fence-deployment/picsure/standalone.xml
+++ /dev/null
@@ -1,550 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
- h2
-
- sa
- sa
-
-
-
-
- jdbc:mysql://${env.PICSURE_DB_HOST}/picsure?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&autoReconnectForPools=true
- mysql
-
- 5
- 50
- true
-
-
- ${env.PICSURE_DB_USERNAME}
- ${env.PICSURE_DB_PASSWORD}
-
-
-
- SELECT 1
- true
- false
-
-
-
-
-
-
- com.mysql.jdbc.Driver
-
-
- org.h2.jdbcx.JdbcDataSource
-
-
-
-
-
-
-
-
-
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ${jboss.bind.address:127.0.0.1}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/scripts/fence-deployment/psama/emailTemplates/accessEmail.mustache b/scripts/fence-deployment/psama/emailTemplates/accessEmail.mustache
deleted file mode 100644
index 8b699bc69..000000000
--- a/scripts/fence-deployment/psama/emailTemplates/accessEmail.mustache
+++ /dev/null
@@ -1,17 +0,0 @@
-Access Changed:
-
-{{#rolesExists}}
-You have been granted access to {{systemName}} with the following roles:
-{{/rolesExists}}
-{{#roles}}
-{{name}} : {{#privileges}} {{description}} {{/privileges}}
-{{/roles}}
-{{^roles}}
-Currently NO roles have been granted for you to {{systemName}}.
-{{/roles}}
- {{#documentation}}
-You can find documentation at the following links:
- {{.}}
-{{/documentation}}
-
-Have a good day!
\ No newline at end of file
diff --git a/scripts/fence-deployment/psama/emailTemplates/deniedAccessEmail.mustache b/scripts/fence-deployment/psama/emailTemplates/deniedAccessEmail.mustache
deleted file mode 100644
index abab886ba..000000000
--- a/scripts/fence-deployment/psama/emailTemplates/deniedAccessEmail.mustache
+++ /dev/null
@@ -1,6 +0,0 @@
-The following user has been denied access to the {{systemName}} environment because their user has not been configured.
-
-First Name : {{given_name}}
-Last Name : {{family_name}}
-Email : {{email}}
-ID : {{nickname}}