diff --git a/plugins/src/main/java/com/google/fhir/proxy/plugin/AccessGrantedAndUpdateList.java b/plugins/src/main/java/com/google/fhir/proxy/plugin/AccessGrantedAndUpdateList.java index d21267ed..ed9d1f3f 100644 --- a/plugins/src/main/java/com/google/fhir/proxy/plugin/AccessGrantedAndUpdateList.java +++ b/plugins/src/main/java/com/google/fhir/proxy/plugin/AccessGrantedAndUpdateList.java @@ -148,7 +148,5 @@ public static AccessGrantedAndUpdateList forBundle( } @Override - public void preProcess(ServletRequestDetails servletRequestDetails) { - - } + public void preProcess(ServletRequestDetails servletRequestDetails) {} } diff --git a/plugins/src/main/java/com/google/fhir/proxy/plugin/OpenSRPSyncAccessDecision.java b/plugins/src/main/java/com/google/fhir/proxy/plugin/OpenSRPSyncAccessDecision.java index ce85376b..26e679a2 100644 --- a/plugins/src/main/java/com/google/fhir/proxy/plugin/OpenSRPSyncAccessDecision.java +++ b/plugins/src/main/java/com/google/fhir/proxy/plugin/OpenSRPSyncAccessDecision.java @@ -19,160 +19,174 @@ import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import com.google.fhir.proxy.ProxyConstants; import com.google.fhir.proxy.interfaces.AccessDecision; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.http.HttpResponse; -import org.apache.http.util.TextUtils; - import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.http.HttpResponse; +import org.apache.http.util.TextUtils; public class OpenSRPSyncAccessDecision implements AccessDecision { - private String applicationId; - - private final List syncStrategy; - - private boolean accessGranted; - - private List careTeamIds; - - private List locationIds; - - private List organizationIds; - - public OpenSRPSyncAccessDecision(String applicationId, boolean accessGranted, List locationIds, List careTeamIds, - List organizationIds, List syncStrategy) { - this.applicationId = applicationId; - this.accessGranted = accessGranted; - this.careTeamIds = careTeamIds; - this.locationIds = locationIds; - this.organizationIds = organizationIds; - this.syncStrategy = syncStrategy; - } - - @Override - public boolean canAccess() { - return accessGranted; - } - - @Override - public void preProcess(ServletRequestDetails servletRequestDetails) { - // TODO: Disable access for a user who adds tags to organisations, locations or care teams that they do not have access to - // This does not bar access to anyone who uses their own sync tags to circumvent - // the filter. The aim of this feature based on scoping was to pre-filter the data for the user - if (isSyncUrl(servletRequestDetails)) { - // This prevents access to a user who has no location/organisation/team assigned to them - if (locationIds.size() == 0 && careTeamIds.size() == 0 && organizationIds.size() == 0) { - locationIds.add( - "CR1bAeGgaYqIpsNkG0iidfE5WVb5BJV1yltmL4YFp3o6mxj3iJPhKh4k9ROhlyZveFC8298lYzft8SIy8yMNLl5GVWQXNRr1sSeBkP2McfFZjbMYyrxlNFOJgqvtccDKKYSwBiLHq2By5tRupHcmpIIghV7Hp39KgF4iBDNqIGMKhgOIieQwt5BRih5FgnwdHrdlK9ix"); - } - addSyncFilters(servletRequestDetails, getSyncTags(locationIds, careTeamIds, organizationIds)); - } - } - - /** - * Adds filters to the {@link ServletRequestDetails} for the _tag property to allow filtering by specific code-url-values that match specific locations, teams - * or organisations - * - * @param servletRequestDetails - * @param syncTags - */ - private void addSyncFilters(ServletRequestDetails servletRequestDetails, Pair> syncTags) { - List paramValues = new ArrayList<>(); - - for (Map.Entry codeUrlValuesMap : syncTags.getValue().entrySet()) { - String codeUrl = codeUrlValuesMap.getKey(); - for (String codeValue : codeUrlValuesMap.getValue()) { - StringBuilder paramValueSb = new StringBuilder(codeUrl.length() + codeValue.length() + 2); - paramValueSb.append(codeUrl); - paramValueSb.append(ProxyConstants.CODE_URL_VALUE_SEPARATOR); - paramValueSb.append(codeValue); - paramValues.add(paramValueSb.toString()); - } - } - - String[] prevTagFilters = servletRequestDetails.getParameters().get(ProxyConstants.SEARCH_PARAM_TAG); - if (prevTagFilters != null && prevTagFilters.length > 1) { - Collections.addAll(paramValues, prevTagFilters); - } - - servletRequestDetails.addParameter(ProxyConstants.SEARCH_PARAM_TAG, paramValues.toArray(new String[0])); - } - - @Override - public String postProcess(HttpResponse response) throws IOException { - return null; - } - - /** - * Generates a map of Code.url to multiple Code.Value which contains all the possible - * filters that will be used in syncing - * - * @param locationIds - * @param careTeamIds - * @param organizationIds - * @return Pair of URL to [Code.url, [Code.Value]] map. The URL is complete url - */ - private Pair> getSyncTags(List locationIds, List careTeamIds, - List organizationIds) { - StringBuilder sb = new StringBuilder(); - Map map = new HashMap<>(); - - sb.append(ProxyConstants.SEARCH_PARAM_TAG); - sb.append(ProxyConstants.Literals.EQUALS); - - addTags(ProxyConstants.LOCATION_TAG_URL, locationIds, map, sb); - addTags(ProxyConstants.ORGANISATION_TAG_URL, organizationIds, map, sb); - addTags(ProxyConstants.CARE_TEAM_TAG_URL, careTeamIds, map, sb); - - return new ImmutablePair<>(sb.toString(), map); - } - - private void addTags(String tagUrl, List values, Map map, StringBuilder urlStringBuilder) { - int len = values.size(); - if (len > 0) { - if (urlStringBuilder.length() != (ProxyConstants.SEARCH_PARAM_TAG + ProxyConstants.Literals.EQUALS).length()) { - urlStringBuilder.append(ProxyConstants.PARAM_VALUES_SEPARATOR); - } - - map.put(tagUrl, values.toArray(new String[0])); - - int i = 0; - for (String tagValue : values) { - urlStringBuilder.append(tagUrl); - urlStringBuilder.append(ProxyConstants.CODE_URL_VALUE_SEPARATOR); - urlStringBuilder.append(tagValue); - - if (i != len - 1) { - urlStringBuilder.append(ProxyConstants.PARAM_VALUES_SEPARATOR); - } - i++; - } - } - } - - private boolean isSyncUrl(ServletRequestDetails servletRequestDetails) { - if (servletRequestDetails.getRequestType() == RequestTypeEnum.GET && !TextUtils.isEmpty( - servletRequestDetails.getResourceName())) { - String requestPath = servletRequestDetails.getRequestPath(); - return isResourceTypeRequest(requestPath.replace(servletRequestDetails.getFhirServerBase(), "")); - } - - return false; - } - - private boolean isResourceTypeRequest(String requestPath) { - if (!TextUtils.isEmpty(requestPath)) { - String[] sections = requestPath.split("/"); - - return sections.length == 1 || (sections.length == 2 && TextUtils.isEmpty(sections[1])); - } - - return false; - } + private String applicationId; + + private final List syncStrategy; + + private boolean accessGranted; + + private List careTeamIds; + + private List locationIds; + + private List organizationIds; + + public OpenSRPSyncAccessDecision( + String applicationId, + boolean accessGranted, + List locationIds, + List careTeamIds, + List organizationIds, + List syncStrategy) { + this.applicationId = applicationId; + this.accessGranted = accessGranted; + this.careTeamIds = careTeamIds; + this.locationIds = locationIds; + this.organizationIds = organizationIds; + this.syncStrategy = syncStrategy; + } + + @Override + public boolean canAccess() { + return accessGranted; + } + + @Override + public void preProcess(ServletRequestDetails servletRequestDetails) { + // TODO: Disable access for a user who adds tags to organisations, locations or care teams that + // they do not have access to + // This does not bar access to anyone who uses their own sync tags to circumvent + // the filter. The aim of this feature based on scoping was to pre-filter the data for the user + if (isSyncUrl(servletRequestDetails)) { + // This prevents access to a user who has no location/organisation/team assigned to them + if (locationIds.size() == 0 && careTeamIds.size() == 0 && organizationIds.size() == 0) { + locationIds.add( + "CR1bAeGgaYqIpsNkG0iidfE5WVb5BJV1yltmL4YFp3o6mxj3iJPhKh4k9ROhlyZveFC8298lYzft8SIy8yMNLl5GVWQXNRr1sSeBkP2McfFZjbMYyrxlNFOJgqvtccDKKYSwBiLHq2By5tRupHcmpIIghV7Hp39KgF4iBDNqIGMKhgOIieQwt5BRih5FgnwdHrdlK9ix"); + } + addSyncFilters(servletRequestDetails, getSyncTags(locationIds, careTeamIds, organizationIds)); + } + } + + /** + * Adds filters to the {@link ServletRequestDetails} for the _tag property to allow filtering by + * specific code-url-values that match specific locations, teams or organisations + * + * @param servletRequestDetails + * @param syncTags + */ + private void addSyncFilters( + ServletRequestDetails servletRequestDetails, Pair> syncTags) { + List paramValues = new ArrayList<>(); + + for (Map.Entry codeUrlValuesMap : syncTags.getValue().entrySet()) { + String codeUrl = codeUrlValuesMap.getKey(); + for (String codeValue : codeUrlValuesMap.getValue()) { + StringBuilder paramValueSb = new StringBuilder(codeUrl.length() + codeValue.length() + 2); + paramValueSb.append(codeUrl); + paramValueSb.append(ProxyConstants.CODE_URL_VALUE_SEPARATOR); + paramValueSb.append(codeValue); + paramValues.add(paramValueSb.toString()); + } + } + + String[] prevTagFilters = + servletRequestDetails.getParameters().get(ProxyConstants.SEARCH_PARAM_TAG); + if (prevTagFilters != null && prevTagFilters.length > 1) { + Collections.addAll(paramValues, prevTagFilters); + } + + servletRequestDetails.addParameter( + ProxyConstants.SEARCH_PARAM_TAG, paramValues.toArray(new String[0])); + } + + @Override + public String postProcess(HttpResponse response) throws IOException { + return null; + } + + /** + * Generates a map of Code.url to multiple Code.Value which contains all the possible filters that + * will be used in syncing + * + * @param locationIds + * @param careTeamIds + * @param organizationIds + * @return Pair of URL to [Code.url, [Code.Value]] map. The URL is complete url + */ + private Pair> getSyncTags( + List locationIds, List careTeamIds, List organizationIds) { + StringBuilder sb = new StringBuilder(); + Map map = new HashMap<>(); + + sb.append(ProxyConstants.SEARCH_PARAM_TAG); + sb.append(ProxyConstants.Literals.EQUALS); + + addTags(ProxyConstants.LOCATION_TAG_URL, locationIds, map, sb); + addTags(ProxyConstants.ORGANISATION_TAG_URL, organizationIds, map, sb); + addTags(ProxyConstants.CARE_TEAM_TAG_URL, careTeamIds, map, sb); + + return new ImmutablePair<>(sb.toString(), map); + } + + private void addTags( + String tagUrl, + List values, + Map map, + StringBuilder urlStringBuilder) { + int len = values.size(); + if (len > 0) { + if (urlStringBuilder.length() + != (ProxyConstants.SEARCH_PARAM_TAG + ProxyConstants.Literals.EQUALS).length()) { + urlStringBuilder.append(ProxyConstants.PARAM_VALUES_SEPARATOR); + } + + map.put(tagUrl, values.toArray(new String[0])); + + int i = 0; + for (String tagValue : values) { + urlStringBuilder.append(tagUrl); + urlStringBuilder.append(ProxyConstants.CODE_URL_VALUE_SEPARATOR); + urlStringBuilder.append(tagValue); + + if (i != len - 1) { + urlStringBuilder.append(ProxyConstants.PARAM_VALUES_SEPARATOR); + } + i++; + } + } + } + + private boolean isSyncUrl(ServletRequestDetails servletRequestDetails) { + if (servletRequestDetails.getRequestType() == RequestTypeEnum.GET + && !TextUtils.isEmpty(servletRequestDetails.getResourceName())) { + String requestPath = servletRequestDetails.getRequestPath(); + return isResourceTypeRequest( + requestPath.replace(servletRequestDetails.getFhirServerBase(), "")); + } + + return false; + } + + private boolean isResourceTypeRequest(String requestPath) { + if (!TextUtils.isEmpty(requestPath)) { + String[] sections = requestPath.split("/"); + + return sections.length == 1 || (sections.length == 2 && TextUtils.isEmpty(sections[1])); + } + + return false; + } } diff --git a/plugins/src/main/java/com/google/fhir/proxy/plugin/PermissionAccessChecker.java b/plugins/src/main/java/com/google/fhir/proxy/plugin/PermissionAccessChecker.java index b397166f..74b06aad 100644 --- a/plugins/src/main/java/com/google/fhir/proxy/plugin/PermissionAccessChecker.java +++ b/plugins/src/main/java/com/google/fhir/proxy/plugin/PermissionAccessChecker.java @@ -15,6 +15,11 @@ */ package com.google.fhir.proxy.plugin; +import static com.google.fhir.proxy.ProxyConstants.SYNC_STRATEGY; +import static org.hl7.fhir.r4.model.Claim.CARE_TEAM; +import static org.smartregister.utils.Constants.LOCATION; +import static org.smartregister.utils.Constants.ORGANIZATION; + import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.rest.api.RequestTypeEnum; @@ -34,291 +39,359 @@ import com.google.fhir.proxy.interfaces.PatientFinder; import com.google.fhir.proxy.interfaces.RequestDetailsReader; import com.google.fhir.proxy.interfaces.ResourceFinder; - -import java.util.*; -import java.util.stream.Collectors; -import javax.inject.Named; - import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import java.util.*; +import java.util.stream.Collectors; +import javax.inject.Named; import org.hl7.fhir.r4.model.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.smartregister.model.practitioner.PractitionerDetails; -import static com.google.fhir.proxy.ProxyConstants.SYNC_STRATEGY; -import static org.hl7.fhir.r4.model.Claim.CARE_TEAM; -import static org.smartregister.utils.Constants.LOCATION; -import static org.smartregister.utils.Constants.ORGANIZATION; - public class PermissionAccessChecker implements AccessChecker { - private static final Logger logger = LoggerFactory.getLogger(PermissionAccessChecker.class); - private final ResourceFinder resourceFinder; - private final List userRoles; - private final String applicationId; - - private final List careTeamIds; - - private final List locationIds; - - private final List organizationIds; - - private final List syncStrategy; - - private PermissionAccessChecker(List userRoles, ResourceFinder resourceFinder, String applicationId, List careTeamIds, List locationIds, List organizationIds, List syncStrategy) { - Preconditions.checkNotNull(userRoles); - Preconditions.checkNotNull(resourceFinder); - Preconditions.checkNotNull(applicationId); - Preconditions.checkNotNull(careTeamIds); - Preconditions.checkNotNull(organizationIds); - Preconditions.checkNotNull(locationIds); - Preconditions.checkNotNull(syncStrategy); - this.resourceFinder = resourceFinder; - this.userRoles = userRoles; - this.applicationId = applicationId; - this.careTeamIds = careTeamIds; - this.organizationIds = organizationIds; - this.locationIds = locationIds; - this.syncStrategy = syncStrategy; + private static final Logger logger = LoggerFactory.getLogger(PermissionAccessChecker.class); + private final ResourceFinder resourceFinder; + private final List userRoles; + private final String applicationId; + + private final List careTeamIds; + + private final List locationIds; + + private final List organizationIds; + + private final List syncStrategy; + + private PermissionAccessChecker( + List userRoles, + ResourceFinder resourceFinder, + String applicationId, + List careTeamIds, + List locationIds, + List organizationIds, + List syncStrategy) { + Preconditions.checkNotNull(userRoles); + Preconditions.checkNotNull(resourceFinder); + Preconditions.checkNotNull(applicationId); + Preconditions.checkNotNull(careTeamIds); + Preconditions.checkNotNull(organizationIds); + Preconditions.checkNotNull(locationIds); + Preconditions.checkNotNull(syncStrategy); + this.resourceFinder = resourceFinder; + this.userRoles = userRoles; + this.applicationId = applicationId; + this.careTeamIds = careTeamIds; + this.organizationIds = organizationIds; + this.locationIds = locationIds; + this.syncStrategy = syncStrategy; + } + + @Override + public AccessDecision checkAccess(RequestDetailsReader requestDetails) { + // For a Bundle requestDetails.getResourceName() returns null + if (requestDetails.getRequestType() == RequestTypeEnum.POST + && requestDetails.getResourceName() == null) { + return processBundle(requestDetails); + + } else { + + boolean userHasRole = + checkUserHasRole( + requestDetails.getResourceName(), requestDetails.getRequestType().name()); + + RequestTypeEnum requestType = requestDetails.getRequestType(); + + switch (requestType) { + case GET: + return processGet(userHasRole); + case DELETE: + return processDelete(userHasRole); + case POST: + return processPost(userHasRole); + case PUT: + return processPut(userHasRole); + default: + // TODO handle other cases like PATCH + return NoOpAccessDecision.accessDenied(); + } } - - @Override - public AccessDecision checkAccess(RequestDetailsReader requestDetails) { - // For a Bundle requestDetails.getResourceName() returns null - if (requestDetails.getRequestType() == RequestTypeEnum.POST && requestDetails.getResourceName() == null) { - return processBundle(requestDetails); - + } + + private boolean checkUserHasRole(String resourceName, String requestType) { + return checkIfRoleExists(getAdminRoleName(resourceName), this.userRoles) + || checkIfRoleExists(getRelevantRoleName(resourceName, requestType), this.userRoles); + } + + private AccessDecision processGet(boolean userHasRole) { + return getAccessDecision(userHasRole); + } + + private AccessDecision processDelete(boolean userHasRole) { + return getAccessDecision(userHasRole); + } + + private AccessDecision getAccessDecision(boolean userHasRole) { + return userHasRole + ? new OpenSRPSyncAccessDecision( + applicationId, true, locationIds, careTeamIds, organizationIds, syncStrategy) + : NoOpAccessDecision.accessDenied(); + } + + private AccessDecision processPost(boolean userHasRole) { + return getAccessDecision(userHasRole); + } + + private AccessDecision processPut(boolean userHasRole) { + return getAccessDecision(userHasRole); + } + + private AccessDecision processBundle(RequestDetailsReader requestDetails) { + boolean hasMissingRole = false; + List resourcesInBundle = resourceFinder.findResourcesInBundle(requestDetails); + // Verify Authorization for individual requests in Bundle + for (BundleResources bundleResources : resourcesInBundle) { + if (!checkUserHasRole( + bundleResources.getResource().fhirType(), bundleResources.getRequestType().name())) { + + if (isDevMode()) { + hasMissingRole = true; + logger.info( + "Missing role " + + getRelevantRoleName( + bundleResources.getResource().fhirType(), + bundleResources.getRequestType().name())); } else { - - boolean userHasRole = checkUserHasRole(requestDetails.getResourceName(), requestDetails.getRequestType().name()); - - RequestTypeEnum requestType = requestDetails.getRequestType(); - - switch (requestType) { - case GET: - return processGet(userHasRole); - case DELETE: - return processDelete(userHasRole); - case POST: - return processPost(userHasRole); - case PUT: - return processPut(userHasRole); - default: - // TODO handle other cases like PATCH - return NoOpAccessDecision.accessDenied(); - } + return NoOpAccessDecision.accessDenied(); } + } } - private boolean checkUserHasRole(String resourceName, String requestType) { - return checkIfRoleExists(getAdminRoleName(resourceName), this.userRoles) || checkIfRoleExists(getRelevantRoleName(resourceName, requestType), this.userRoles); - } + return (isDevMode() && !hasMissingRole) || !isDevMode() + ? NoOpAccessDecision.accessGranted() + : NoOpAccessDecision.accessDenied(); + } - private AccessDecision processGet(boolean userHasRole) { - return getAccessDecision(userHasRole); - } + private String getRelevantRoleName(String resourceName, String methodType) { + return methodType + "_" + resourceName.toUpperCase(); + } - private AccessDecision processDelete(boolean userHasRole) { - return getAccessDecision(userHasRole); - } + private String getAdminRoleName(String resourceName) { + return "MANAGE_" + resourceName.toUpperCase(); + } - private AccessDecision getAccessDecision(boolean userHasRole) { - return userHasRole ? new OpenSRPSyncAccessDecision(applicationId, true, locationIds, careTeamIds, organizationIds, syncStrategy) : NoOpAccessDecision.accessDenied(); - } + @VisibleForTesting + protected boolean isDevMode() { + return FhirProxyServer.isDevMode(); + } - private AccessDecision processPost(boolean userHasRole) { - return getAccessDecision(userHasRole); - } + private boolean checkIfRoleExists(String roleName, List existingRoles) { + return existingRoles.contains(roleName); + } - private AccessDecision processPut(boolean userHasRole) { - return getAccessDecision(userHasRole); - } + @Named(value = "permission") + static class Factory implements AccessCheckerFactory { - private AccessDecision processBundle(RequestDetailsReader requestDetails) { - boolean hasMissingRole = false; - List resourcesInBundle = resourceFinder.findResourcesInBundle(requestDetails); - // Verify Authorization for individual requests in Bundle - for (BundleResources bundleResources : resourcesInBundle) { - if (!checkUserHasRole(bundleResources.getResource().fhirType(), bundleResources.getRequestType().name())) { - - if (isDevMode()) { - hasMissingRole = true; - logger.info("Missing role " + getRelevantRoleName(bundleResources.getResource().fhirType(), bundleResources.getRequestType().name())); - } else { - return NoOpAccessDecision.accessDenied(); - } - } - } + @VisibleForTesting static final String REALM_ACCESS_CLAIM = "realm_access"; + @VisibleForTesting static final String ROLES = "roles"; - return (isDevMode() && !hasMissingRole) || !isDevMode() ? NoOpAccessDecision.accessGranted() : NoOpAccessDecision.accessDenied(); - } + @VisibleForTesting static final String FHIR_CORE_APPLICATION_ID_CLAIM = "fhir_core_app_id"; - private String getRelevantRoleName(String resourceName, String methodType) { - return methodType + "_" + resourceName.toUpperCase(); - } + @VisibleForTesting static final String PROXY_TO_ENV = "PROXY_TO"; - private String getAdminRoleName(String resourceName) { - return "MANAGE_" + resourceName.toUpperCase(); + private List getUserRolesFromJWT(DecodedJWT jwt) { + Claim claim = jwt.getClaim(REALM_ACCESS_CLAIM); + Map roles = claim.asMap(); + List rolesList = (List) roles.get(ROLES); + return rolesList; } - @VisibleForTesting - protected boolean isDevMode() { - return FhirProxyServer.isDevMode(); + private String getApplicationIdFromJWT(DecodedJWT jwt) { + return JwtUtil.getClaimOrDie(jwt, FHIR_CORE_APPLICATION_ID_CLAIM); } - private boolean checkIfRoleExists(String roleName, List existingRoles) { - return existingRoles.contains(roleName); + private IGenericClient createFhirClientForR4() { + String fhirServer = System.getenv(PROXY_TO_ENV); + FhirContext ctx = FhirContext.forR4(); + IGenericClient client = ctx.newRestfulGenericClient(fhirServer); + return client; } - @Named(value = "permission") - static class Factory implements AccessCheckerFactory { - - @VisibleForTesting - static final String REALM_ACCESS_CLAIM = "realm_access"; - @VisibleForTesting - static final String ROLES = "roles"; - - @VisibleForTesting - static final String FHIR_CORE_APPLICATION_ID_CLAIM = "fhir_core_app_id"; - - @VisibleForTesting - static final String PROXY_TO_ENV = "PROXY_TO"; + private Composition readCompositionResource(String applicationId) { + IGenericClient client = createFhirClientForR4(); + Bundle compositionBundle = + client + .search() + .forResource(Composition.class) + .where(Composition.IDENTIFIER.exactly().identifier(applicationId)) + .returnBundle(Bundle.class) + .execute(); + List compositionEntries = + compositionBundle != null + ? compositionBundle.getEntry() + : Collections.singletonList(new Bundle.BundleEntryComponent()); + Bundle.BundleEntryComponent compositionEntry = + compositionEntries.size() > 0 ? compositionEntries.get(0) : null; + return compositionEntry != null ? (Composition) compositionEntry.getResource() : null; + } - private List getUserRolesFromJWT(DecodedJWT jwt) { - Claim claim = jwt.getClaim(REALM_ACCESS_CLAIM); - Map roles = claim.asMap(); - List rolesList = (List) roles.get(ROLES); - return rolesList; - } + private String getBinaryResourceReference(Composition composition) { + List indexes = new ArrayList<>(); + String id = ""; + if (composition != null && composition.getSection() != null) { + indexes = + composition.getSection().stream() + .filter(v -> v.getFocus().getIdentifier() != null) + .filter(v -> v.getFocus().getIdentifier().getValue() != null) + .filter(v -> v.getFocus().getIdentifier().getValue().equals("application")) + .map(v -> composition.getSection().indexOf(v)) + .collect(Collectors.toList()); + Composition.SectionComponent sectionComponent = composition.getSection().get(0); + Reference focus = sectionComponent != null ? sectionComponent.getFocus() : null; + id = focus != null ? focus.getReference() : null; + } + return id; + } - private String getApplicationIdFromJWT(DecodedJWT jwt) { - return JwtUtil.getClaimOrDie(jwt, FHIR_CORE_APPLICATION_ID_CLAIM); - } + private Binary findApplicationConfigBinaryResource(String binaryResourceId) { + IGenericClient client = createFhirClientForR4(); + Binary binary = null; + if (!binaryResourceId.isBlank()) { + binary = client.read().resource(Binary.class).withId(binaryResourceId).execute(); + } + return binary; + } - private IGenericClient createFhirClientForR4() { - String fhirServer = System.getenv(PROXY_TO_ENV); - FhirContext ctx = FhirContext.forR4(); - IGenericClient client = ctx.newRestfulGenericClient(fhirServer); - return client; + private List findSyncStrategy(Binary binary) { + byte[] bytes = + binary != null && binary.getDataElement() != null + ? Base64.getDecoder().decode(binary.getDataElement().getValueAsString()) + : null; + List syncStrategy = new ArrayList<>(); + if (bytes != null) { + String json = new String(bytes); + JsonObject jsonObject = new Gson().fromJson(json, JsonObject.class); + JsonArray jsonArray = jsonObject.getAsJsonArray(SYNC_STRATEGY); + if (jsonArray != null) { + for (JsonElement jsonElement : jsonArray) { + syncStrategy.add(jsonElement.getAsString()); + } } + } + return syncStrategy; + } - private Composition readCompositionResource(String applicationId) { - IGenericClient client = createFhirClientForR4(); - Bundle compositionBundle = client.search().forResource(Composition.class).where(Composition.IDENTIFIER.exactly().identifier(applicationId)).returnBundle(Bundle.class).execute(); - List compositionEntries = compositionBundle != null ? compositionBundle.getEntry() : Collections.singletonList(new Bundle.BundleEntryComponent()); - Bundle.BundleEntryComponent compositionEntry = compositionEntries.size() > 0 ? compositionEntries.get(0) : null; - return compositionEntry != null ? (Composition) compositionEntry.getResource() : null; - } + private PractitionerDetails readPractitionerDetails(String keycloakUUID) { + IGenericClient client = createFhirClientForR4(); + // Map<> + Bundle practitionerDetailsBundle = + client + .search() + .forResource(PractitionerDetails.class) + .where(getMapForWhere(keycloakUUID)) + .returnBundle(Bundle.class) + .execute(); + + List practitionerDetailsBundleEntry = + practitionerDetailsBundle.getEntry(); + Bundle.BundleEntryComponent practitionerDetailEntry = + practitionerDetailsBundleEntry != null && practitionerDetailsBundleEntry.size() > 0 + ? practitionerDetailsBundleEntry.get(0) + : null; + return practitionerDetailEntry != null + ? (PractitionerDetails) practitionerDetailEntry.getResource() + : null; + } - private String getBinaryResourceReference(Composition composition) { - List indexes = new ArrayList<>(); - String id = ""; - if (composition != null && composition.getSection() != null) { - indexes = composition.getSection().stream().filter(v -> v.getFocus().getIdentifier() != null).filter(v -> v.getFocus().getIdentifier().getValue() != null).filter(v -> v.getFocus().getIdentifier().getValue().equals("application")).map(v -> composition.getSection().indexOf(v)).collect(Collectors.toList()); - Composition.SectionComponent sectionComponent = composition.getSection().get(0); - Reference focus = sectionComponent != null ? sectionComponent.getFocus() : null; - id = focus != null ? focus.getReference() : null; - } - return id; - } + public Map> getMapForWhere(String keycloakUUID) { + Map> hmOut = new HashMap<>(); + // Adding keycloak-uuid + TokenParam tokenParam = new TokenParam("keycloak-uuid"); + tokenParam.setValue(keycloakUUID); + List lst = new ArrayList(); + lst.add(tokenParam); + hmOut.put(PractitionerDetails.SP_KEYCLOAK_UUID, lst); + + // Adding isAuthProvided + SpecialParam isAuthProvided = new SpecialParam(); + isAuthProvided.setValue("false"); + List l = new ArrayList(); + l.add(isAuthProvided); + hmOut.put(PractitionerDetails.SP_IS_AUTH_PROVIDED, l); + + return hmOut; + } - private Binary findApplicationConfigBinaryResource(String binaryResourceId) { - IGenericClient client = createFhirClientForR4(); - Binary binary = null; - if (!binaryResourceId.isBlank()) { - binary = client.read().resource(Binary.class).withId(binaryResourceId).execute(); + @Override + public AccessChecker create( + DecodedJWT jwt, + HttpFhirClient httpFhirClient, + FhirContext fhirContext, + PatientFinder patientFinder) + throws AuthenticationException { + List userRoles = getUserRolesFromJWT(jwt); + String applicationId = getApplicationIdFromJWT(jwt); + Composition composition = readCompositionResource(applicationId); + String binaryResourceReference = getBinaryResourceReference(composition); + Binary binary = findApplicationConfigBinaryResource(binaryResourceReference); + List syncStrategy = findSyncStrategy(binary); + PractitionerDetails practitionerDetails = readPractitionerDetails(jwt.getSubject()); + List careTeams; + List organizations; + List locations; + List careTeamIds = new ArrayList<>(); + List organizationIds = new ArrayList<>(); + List locationIds = new ArrayList<>(); + if (syncStrategy.size() > 0) { + if (syncStrategy.contains(CARE_TEAM)) { + careTeams = + practitionerDetails != null + && practitionerDetails.getFhirPractitionerDetails() != null + ? practitionerDetails.getFhirPractitionerDetails().getCareTeams() + : Collections.singletonList(new CareTeam()); + for (CareTeam careTeam : careTeams) { + if (careTeam.getIdElement() != null + && careTeam.getIdElement().getIdPartAsLong() != null) { + careTeamIds.add(careTeam.getIdElement().getIdPartAsLong().toString()); } - return binary; - } - - private List findSyncStrategy(Binary binary) { - byte[] bytes = binary != null && binary.getDataElement() != null ? Base64.getDecoder().decode(binary.getDataElement().getValueAsString()) : null; - List syncStrategy = new ArrayList<>(); - if (bytes != null) { - String json = new String(bytes); - JsonObject jsonObject = new Gson().fromJson(json, JsonObject.class); - JsonArray jsonArray = jsonObject.getAsJsonArray(SYNC_STRATEGY); - if (jsonArray != null) { - for (JsonElement jsonElement : jsonArray) { - syncStrategy.add(jsonElement.getAsString()); - } - } + careTeamIds.add(careTeam.getId()); + } + } else if (syncStrategy.contains(ORGANIZATION)) { + organizations = + practitionerDetails != null + && practitionerDetails.getFhirPractitionerDetails() != null + ? practitionerDetails.getFhirPractitionerDetails().getOrganizations() + : Collections.singletonList(new Organization()); + for (Organization organization : organizations) { + if (organization.getIdElement() != null + && organization.getIdElement().getIdPartAsLong() != null) { + organizationIds.add(organization.getIdElement().getIdPartAsLong().toString()); } - return syncStrategy; - } - - private PractitionerDetails readPractitionerDetails(String keycloakUUID) { - IGenericClient client = createFhirClientForR4(); - // Map<> - Bundle practitionerDetailsBundle = client.search().forResource(PractitionerDetails.class).where(getMapForWhere(keycloakUUID)).returnBundle(Bundle.class).execute(); - - List practitionerDetailsBundleEntry = practitionerDetailsBundle.getEntry(); - Bundle.BundleEntryComponent practitionerDetailEntry = practitionerDetailsBundleEntry != null && practitionerDetailsBundleEntry.size() > 0 ? practitionerDetailsBundleEntry.get(0) : null; - return practitionerDetailEntry != null ? (PractitionerDetails) practitionerDetailEntry.getResource() : null; - } - - public Map> getMapForWhere(String keycloakUUID) { - Map> hmOut = new HashMap<>(); - // Adding keycloak-uuid - TokenParam tokenParam = new TokenParam("keycloak-uuid"); - tokenParam.setValue(keycloakUUID); - List lst = new ArrayList(); - lst.add(tokenParam); - hmOut.put(PractitionerDetails.SP_KEYCLOAK_UUID, lst); - - // Adding isAuthProvided - SpecialParam isAuthProvided = new SpecialParam(); - isAuthProvided.setValue("false"); - List l = new ArrayList(); - l.add(isAuthProvided); - hmOut.put(PractitionerDetails.SP_IS_AUTH_PROVIDED, l); - - return hmOut; - } - - @Override - public AccessChecker create(DecodedJWT jwt, HttpFhirClient httpFhirClient, FhirContext fhirContext, PatientFinder patientFinder) throws AuthenticationException { - List userRoles = getUserRolesFromJWT(jwt); - String applicationId = getApplicationIdFromJWT(jwt); - Composition composition = readCompositionResource(applicationId); - String binaryResourceReference = getBinaryResourceReference(composition); - Binary binary = findApplicationConfigBinaryResource(binaryResourceReference); - List syncStrategy = findSyncStrategy(binary); - PractitionerDetails practitionerDetails = readPractitionerDetails(jwt.getSubject()); - List careTeams; - List organizations; - List locations; - List careTeamIds = new ArrayList<>(); - List organizationIds = new ArrayList<>(); - List locationIds = new ArrayList<>(); - if (syncStrategy.size() > 0) { - if (syncStrategy.contains(CARE_TEAM)) { - careTeams = practitionerDetails != null && practitionerDetails.getFhirPractitionerDetails() != null ? practitionerDetails.getFhirPractitionerDetails().getCareTeams() : Collections.singletonList(new CareTeam()); - for (CareTeam careTeam : careTeams) { - if (careTeam.getIdElement() != null && careTeam.getIdElement().getIdPartAsLong() != null) { - careTeamIds.add(careTeam.getIdElement().getIdPartAsLong().toString()); - } - careTeamIds.add(careTeam.getId()); - } - } else if (syncStrategy.contains(ORGANIZATION)) { - organizations = practitionerDetails != null && practitionerDetails.getFhirPractitionerDetails() != null ? practitionerDetails.getFhirPractitionerDetails().getOrganizations() : Collections.singletonList(new Organization()); - for (Organization organization : organizations) { - if (organization.getIdElement() != null && organization.getIdElement().getIdPartAsLong() != null) { - organizationIds.add(organization.getIdElement().getIdPartAsLong().toString()); - } - } - } else if (syncStrategy.contains(LOCATION)) { - locations = practitionerDetails != null && practitionerDetails.getFhirPractitionerDetails() != null ? practitionerDetails.getFhirPractitionerDetails().getLocations() : Collections.singletonList(new Location()); - for (Location location : locations) { - if (location.getIdElement() != null && location.getIdElement().getIdPartAsLong() != null) { - locationIds.add(location.getIdElement().getIdPartAsLong().toString()); - } - } - } + } + } else if (syncStrategy.contains(LOCATION)) { + locations = + practitionerDetails != null + && practitionerDetails.getFhirPractitionerDetails() != null + ? practitionerDetails.getFhirPractitionerDetails().getLocations() + : Collections.singletonList(new Location()); + for (Location location : locations) { + if (location.getIdElement() != null + && location.getIdElement().getIdPartAsLong() != null) { + locationIds.add(location.getIdElement().getIdPartAsLong().toString()); } - return new PermissionAccessChecker(userRoles, ResourceFinderImp.getInstance(fhirContext), applicationId, careTeamIds, locationIds, organizationIds, syncStrategy); + } } + } + return new PermissionAccessChecker( + userRoles, + ResourceFinderImp.getInstance(fhirContext), + applicationId, + careTeamIds, + locationIds, + organizationIds, + syncStrategy); } + } } diff --git a/plugins/src/test/java/com/google/fhir/proxy/plugin/OpenSRPSyncAccessDecisionTest.java b/plugins/src/test/java/com/google/fhir/proxy/plugin/OpenSRPSyncAccessDecisionTest.java index 1fbd2f15..75b5d612 100644 --- a/plugins/src/test/java/com/google/fhir/proxy/plugin/OpenSRPSyncAccessDecisionTest.java +++ b/plugins/src/test/java/com/google/fhir/proxy/plugin/OpenSRPSyncAccessDecisionTest.java @@ -19,159 +19,168 @@ import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import com.google.fhir.proxy.ProxyConstants; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; - import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) public class OpenSRPSyncAccessDecisionTest { - private List locationIds = new ArrayList<>(); - - private List careTeamIds = new ArrayList<>(); - - private List organisationIds = new ArrayList<>(); - - private OpenSRPSyncAccessDecision testInstance; - - @Test - public void preprocessShouldAddAllFiltersWhenIdsForLocationsOrganisationsAndCareTeamsAreProvided() throws IOException { - - testInstance = createOpenSRPSyncAccessDecisionTestInstance(); - - ServletRequestDetails requestDetails = new ServletRequestDetails(); - requestDetails.setRequestType(RequestTypeEnum.GET); - requestDetails.setRestOperationType(RestOperationTypeEnum.SEARCH_TYPE); - requestDetails.setResourceName("Patient"); - requestDetails.setFhirServerBase("https://smartregister.org/fhir"); - requestDetails.setCompleteUrl("https://smartregister.org/fhir/Patient"); - requestDetails.setRequestPath("Patient"); - - // Call the method under testing - testInstance.preProcess(requestDetails); - - List allIds = new ArrayList<>(); - allIds.addAll(locationIds); - allIds.addAll(organisationIds); - allIds.addAll(careTeamIds); - - for (String locationId : locationIds) { - Assert.assertFalse(requestDetails.getCompleteUrl().contains(locationId)); - Assert.assertFalse(requestDetails.getRequestPath().contains(locationId)); - Assert.assertTrue(Arrays.asList(requestDetails.getParameters().get("_tag")) - .contains(ProxyConstants.LOCATION_TAG_URL + "|" + locationId)); - } - - for (String careTeamId : careTeamIds) { - Assert.assertFalse(requestDetails.getCompleteUrl().contains(careTeamId)); - Assert.assertFalse(requestDetails.getRequestPath().contains(careTeamId)); - Assert.assertTrue(Arrays.asList(requestDetails.getParameters().get("_tag")) - .contains(ProxyConstants.CARE_TEAM_TAG_URL + "|" + careTeamId)); - } - - for (String organisationId : organisationIds) { - Assert.assertFalse(requestDetails.getCompleteUrl().contains(organisationId)); - Assert.assertFalse(requestDetails.getRequestPath().contains(organisationId)); - Assert.assertTrue(Arrays.asList(requestDetails.getParameters().get("_tag")) - .contains(ProxyConstants.ORGANISATION_TAG_URL + "|" + organisationId)); - } - } - - @Test - public void preProcessShouldAddLocationIdFiltersWhenUserIsAssignedToLocationsOnly() throws IOException { - locationIds.add("locationid12"); - locationIds.add("locationid2"); - testInstance = createOpenSRPSyncAccessDecisionTestInstance(); - - ServletRequestDetails requestDetails = new ServletRequestDetails(); - requestDetails.setRequestType(RequestTypeEnum.GET); - requestDetails.setRestOperationType(RestOperationTypeEnum.SEARCH_TYPE); - requestDetails.setResourceName("Patient"); - requestDetails.setFhirServerBase("https://smartregister.org/fhir"); - requestDetails.setCompleteUrl("https://smartregister.org/fhir/Patient"); - requestDetails.setRequestPath("Patient"); - - testInstance.preProcess(requestDetails); - - for (String locationId : locationIds) { - Assert.assertFalse(requestDetails.getCompleteUrl().contains(locationId)); - Assert.assertFalse(requestDetails.getRequestPath().contains(locationId)); - Assert.assertTrue(Arrays.asList(requestDetails.getParameters().get("_tag")) - .contains(ProxyConstants.LOCATION_TAG_URL + "|" + locationId)); - } - - for (String param : requestDetails.getParameters().get("_tag")) { - Assert.assertFalse(param.contains(ProxyConstants.CARE_TEAM_TAG_URL)); - Assert.assertFalse(param.contains(ProxyConstants.ORGANISATION_TAG_URL)); - } - } - - @Test - public void preProcessShouldAddCareTeamIdFiltersWhenUserIsAssignedToCareTeamsOnly() throws IOException { - careTeamIds.add("careteamid1"); - careTeamIds.add("careteamid2"); - testInstance = createOpenSRPSyncAccessDecisionTestInstance(); - - ServletRequestDetails requestDetails = new ServletRequestDetails(); - requestDetails.setRequestType(RequestTypeEnum.GET); - requestDetails.setRestOperationType(RestOperationTypeEnum.SEARCH_TYPE); - requestDetails.setResourceName("Patient"); - requestDetails.setFhirServerBase("https://smartregister.org/fhir"); - requestDetails.setCompleteUrl("https://smartregister.org/fhir/Patient"); - requestDetails.setRequestPath("Patient"); - - testInstance.preProcess(requestDetails); - - for (String locationId : careTeamIds) { - Assert.assertFalse(requestDetails.getCompleteUrl().contains(locationId)); - Assert.assertFalse(requestDetails.getRequestPath().contains(locationId)); - Assert.assertTrue(Arrays.asList(requestDetails.getParameters().get("_tag")) - .contains(ProxyConstants.CARE_TEAM_TAG_URL + "|" + locationId)); - } - - for (String param : requestDetails.getParameters().get("_tag")) { - Assert.assertFalse(param.contains(ProxyConstants.LOCATION_TAG_URL)); - Assert.assertFalse(param.contains(ProxyConstants.ORGANISATION_TAG_URL)); - } - } - - @Test - public void preProcessShouldAddOrganisationIdFiltersWhenUserIsAssignedToOrganisationsOnly() throws IOException { - organisationIds.add("organizationid1"); - organisationIds.add("organizationid2"); - testInstance = createOpenSRPSyncAccessDecisionTestInstance(); - - ServletRequestDetails requestDetails = new ServletRequestDetails(); - requestDetails.setRequestType(RequestTypeEnum.GET); - requestDetails.setRestOperationType(RestOperationTypeEnum.SEARCH_TYPE); - requestDetails.setResourceName("Patient"); - requestDetails.setFhirServerBase("https://smartregister.org/fhir"); - requestDetails.setCompleteUrl("https://smartregister.org/fhir/Patient"); - requestDetails.setRequestPath("Patient"); - - testInstance.preProcess(requestDetails); - - for (String locationId : careTeamIds) { - Assert.assertFalse(requestDetails.getCompleteUrl().contains(locationId)); - Assert.assertFalse(requestDetails.getRequestPath().contains(locationId)); - Assert.assertTrue(Arrays.asList(requestDetails.getParameters().get("_tag")) - .contains(ProxyConstants.ORGANISATION_TAG_URL + "|" + locationId)); - } - - for (String param : requestDetails.getParameters().get("_tag")) { - Assert.assertFalse(param.contains(ProxyConstants.LOCATION_TAG_URL)); - Assert.assertFalse(param.contains(ProxyConstants.CARE_TEAM_TAG_URL)); - } - } - - private OpenSRPSyncAccessDecision createOpenSRPSyncAccessDecisionTestInstance() { - return new OpenSRPSyncAccessDecision("sample-application-id", true, locationIds, careTeamIds, organisationIds, null); - } - + private List locationIds = new ArrayList<>(); + + private List careTeamIds = new ArrayList<>(); + + private List organisationIds = new ArrayList<>(); + + private OpenSRPSyncAccessDecision testInstance; + + @Test + public void preprocessShouldAddAllFiltersWhenIdsForLocationsOrganisationsAndCareTeamsAreProvided() + throws IOException { + + testInstance = createOpenSRPSyncAccessDecisionTestInstance(); + + ServletRequestDetails requestDetails = new ServletRequestDetails(); + requestDetails.setRequestType(RequestTypeEnum.GET); + requestDetails.setRestOperationType(RestOperationTypeEnum.SEARCH_TYPE); + requestDetails.setResourceName("Patient"); + requestDetails.setFhirServerBase("https://smartregister.org/fhir"); + requestDetails.setCompleteUrl("https://smartregister.org/fhir/Patient"); + requestDetails.setRequestPath("Patient"); + + // Call the method under testing + testInstance.preProcess(requestDetails); + + List allIds = new ArrayList<>(); + allIds.addAll(locationIds); + allIds.addAll(organisationIds); + allIds.addAll(careTeamIds); + + for (String locationId : locationIds) { + Assert.assertFalse(requestDetails.getCompleteUrl().contains(locationId)); + Assert.assertFalse(requestDetails.getRequestPath().contains(locationId)); + Assert.assertTrue( + Arrays.asList(requestDetails.getParameters().get("_tag")) + .contains(ProxyConstants.LOCATION_TAG_URL + "|" + locationId)); + } + + for (String careTeamId : careTeamIds) { + Assert.assertFalse(requestDetails.getCompleteUrl().contains(careTeamId)); + Assert.assertFalse(requestDetails.getRequestPath().contains(careTeamId)); + Assert.assertTrue( + Arrays.asList(requestDetails.getParameters().get("_tag")) + .contains(ProxyConstants.CARE_TEAM_TAG_URL + "|" + careTeamId)); + } + + for (String organisationId : organisationIds) { + Assert.assertFalse(requestDetails.getCompleteUrl().contains(organisationId)); + Assert.assertFalse(requestDetails.getRequestPath().contains(organisationId)); + Assert.assertTrue( + Arrays.asList(requestDetails.getParameters().get("_tag")) + .contains(ProxyConstants.ORGANISATION_TAG_URL + "|" + organisationId)); + } + } + + @Test + public void preProcessShouldAddLocationIdFiltersWhenUserIsAssignedToLocationsOnly() + throws IOException { + locationIds.add("locationid12"); + locationIds.add("locationid2"); + testInstance = createOpenSRPSyncAccessDecisionTestInstance(); + + ServletRequestDetails requestDetails = new ServletRequestDetails(); + requestDetails.setRequestType(RequestTypeEnum.GET); + requestDetails.setRestOperationType(RestOperationTypeEnum.SEARCH_TYPE); + requestDetails.setResourceName("Patient"); + requestDetails.setFhirServerBase("https://smartregister.org/fhir"); + requestDetails.setCompleteUrl("https://smartregister.org/fhir/Patient"); + requestDetails.setRequestPath("Patient"); + + testInstance.preProcess(requestDetails); + + for (String locationId : locationIds) { + Assert.assertFalse(requestDetails.getCompleteUrl().contains(locationId)); + Assert.assertFalse(requestDetails.getRequestPath().contains(locationId)); + Assert.assertTrue( + Arrays.asList(requestDetails.getParameters().get("_tag")) + .contains(ProxyConstants.LOCATION_TAG_URL + "|" + locationId)); + } + + for (String param : requestDetails.getParameters().get("_tag")) { + Assert.assertFalse(param.contains(ProxyConstants.CARE_TEAM_TAG_URL)); + Assert.assertFalse(param.contains(ProxyConstants.ORGANISATION_TAG_URL)); + } + } + + @Test + public void preProcessShouldAddCareTeamIdFiltersWhenUserIsAssignedToCareTeamsOnly() + throws IOException { + careTeamIds.add("careteamid1"); + careTeamIds.add("careteamid2"); + testInstance = createOpenSRPSyncAccessDecisionTestInstance(); + + ServletRequestDetails requestDetails = new ServletRequestDetails(); + requestDetails.setRequestType(RequestTypeEnum.GET); + requestDetails.setRestOperationType(RestOperationTypeEnum.SEARCH_TYPE); + requestDetails.setResourceName("Patient"); + requestDetails.setFhirServerBase("https://smartregister.org/fhir"); + requestDetails.setCompleteUrl("https://smartregister.org/fhir/Patient"); + requestDetails.setRequestPath("Patient"); + + testInstance.preProcess(requestDetails); + + for (String locationId : careTeamIds) { + Assert.assertFalse(requestDetails.getCompleteUrl().contains(locationId)); + Assert.assertFalse(requestDetails.getRequestPath().contains(locationId)); + Assert.assertTrue( + Arrays.asList(requestDetails.getParameters().get("_tag")) + .contains(ProxyConstants.CARE_TEAM_TAG_URL + "|" + locationId)); + } + + for (String param : requestDetails.getParameters().get("_tag")) { + Assert.assertFalse(param.contains(ProxyConstants.LOCATION_TAG_URL)); + Assert.assertFalse(param.contains(ProxyConstants.ORGANISATION_TAG_URL)); + } + } + + @Test + public void preProcessShouldAddOrganisationIdFiltersWhenUserIsAssignedToOrganisationsOnly() + throws IOException { + organisationIds.add("organizationid1"); + organisationIds.add("organizationid2"); + testInstance = createOpenSRPSyncAccessDecisionTestInstance(); + + ServletRequestDetails requestDetails = new ServletRequestDetails(); + requestDetails.setRequestType(RequestTypeEnum.GET); + requestDetails.setRestOperationType(RestOperationTypeEnum.SEARCH_TYPE); + requestDetails.setResourceName("Patient"); + requestDetails.setFhirServerBase("https://smartregister.org/fhir"); + requestDetails.setCompleteUrl("https://smartregister.org/fhir/Patient"); + requestDetails.setRequestPath("Patient"); + + testInstance.preProcess(requestDetails); + + for (String locationId : careTeamIds) { + Assert.assertFalse(requestDetails.getCompleteUrl().contains(locationId)); + Assert.assertFalse(requestDetails.getRequestPath().contains(locationId)); + Assert.assertTrue( + Arrays.asList(requestDetails.getParameters().get("_tag")) + .contains(ProxyConstants.ORGANISATION_TAG_URL + "|" + locationId)); + } + + for (String param : requestDetails.getParameters().get("_tag")) { + Assert.assertFalse(param.contains(ProxyConstants.LOCATION_TAG_URL)); + Assert.assertFalse(param.contains(ProxyConstants.CARE_TEAM_TAG_URL)); + } + } + + private OpenSRPSyncAccessDecision createOpenSRPSyncAccessDecisionTestInstance() { + return new OpenSRPSyncAccessDecision( + "sample-application-id", true, locationIds, careTeamIds, organisationIds, null); + } } diff --git a/plugins/src/test/java/com/google/fhir/proxy/plugin/PermissionAccessCheckerTest.java b/plugins/src/test/java/com/google/fhir/proxy/plugin/PermissionAccessCheckerTest.java index 12e22881..e5720e6c 100644 --- a/plugins/src/test/java/com/google/fhir/proxy/plugin/PermissionAccessCheckerTest.java +++ b/plugins/src/test/java/com/google/fhir/proxy/plugin/PermissionAccessCheckerTest.java @@ -15,7 +15,6 @@ */ package com.google.fhir.proxy.plugin; -import static com.google.fhir.proxy.plugin.PermissionAccessChecker.Factory.PROXY_TO_ENV; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.mockito.Mockito.when; @@ -34,7 +33,6 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; - import org.hl7.fhir.r4.model.Enumerations; import org.junit.Assert; import org.junit.Before; @@ -71,7 +69,8 @@ void setUpFhirBundle(String filename) throws IOException { public void setUp() throws IOException { when(jwtMock.getClaim(PermissionAccessChecker.Factory.REALM_ACCESS_CLAIM)) .thenReturn(claimMock); - when(jwtMock.getClaim(PermissionAccessChecker.Factory.FHIR_CORE_APPLICATION_ID_CLAIM)).thenReturn( claimMock); + when(jwtMock.getClaim(PermissionAccessChecker.Factory.FHIR_CORE_APPLICATION_ID_CLAIM)) + .thenReturn(claimMock); when(requestMock.getRequestType()).thenReturn(RequestTypeEnum.GET); } diff --git a/pom.xml b/pom.xml index 80b0a340..80d72ee6 100755 --- a/pom.xml +++ b/pom.xml @@ -31,30 +31,30 @@ server - - 6.0.1 - UTF-8 - 2.27.2 - ${project.basedir} - 11 - 11 - 2.6.6 - 4.1 - - nexus-releases https://oss.sonatype.org/service/local/staging/deploy/maven2 + false nexus-snapshots Nexus Snapshots Repository - false https://oss.sonatype.org/content/repositories/snapshots + + 6.0.1 + UTF-8 + 2.27.2 + ${project.basedir} + 11 + 11 + 2.6.6 + 4.1 + + @@ -144,92 +144,94 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + com.diffplug.spotless + spotless-maven-plugin + ${spotless.version} + + + + false + + + + + true + + + + + + + + **/*.sh + **/*.xml + .gitignore + + + + .idea/** + .settings/** + **/target/** + bin/** + tmp/** + docker/** + + + + + true + + + + + **/*.md + + + **/target/** + docker/** + + + + + always + + + + + + + + + + + java,javax,org,com,com.diffplug, + + + + + + + + 1.15.0 + + true + + + + + + + apply + + compile + + + org.apache.maven.plugins diff --git a/server/pom.xml b/server/pom.xml index bfd37b0f..208770c4 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -149,12 +149,6 @@ 1.18.24 - - org.smartregister - fhir-common-utils - 0.0.3-SNAPSHOT - - ca.uhn.hapi.fhir hapi-fhir-client diff --git a/server/src/main/java/com/google/fhir/proxy/CapabilityPostProcessor.java b/server/src/main/java/com/google/fhir/proxy/CapabilityPostProcessor.java index 9be4a683..0c24ec71 100644 --- a/server/src/main/java/com/google/fhir/proxy/CapabilityPostProcessor.java +++ b/server/src/main/java/com/google/fhir/proxy/CapabilityPostProcessor.java @@ -95,7 +95,5 @@ private void addCors(CapabilityStatementRestSecurityComponent security) { } @Override - public void preProcess(ServletRequestDetails servletRequestDetails) { - - } + public void preProcess(ServletRequestDetails servletRequestDetails) {} } diff --git a/server/src/main/java/com/google/fhir/proxy/ProxyConstants.java b/server/src/main/java/com/google/fhir/proxy/ProxyConstants.java index 7fb25a57..48b51a59 100644 --- a/server/src/main/java/com/google/fhir/proxy/ProxyConstants.java +++ b/server/src/main/java/com/google/fhir/proxy/ProxyConstants.java @@ -40,5 +40,4 @@ public class ProxyConstants { public interface Literals { String EQUALS = "="; } - } diff --git a/server/src/main/java/com/google/fhir/proxy/interfaces/AccessDecision.java b/server/src/main/java/com/google/fhir/proxy/interfaces/AccessDecision.java index ca3321c7..982438b5 100644 --- a/server/src/main/java/com/google/fhir/proxy/interfaces/AccessDecision.java +++ b/server/src/main/java/com/google/fhir/proxy/interfaces/AccessDecision.java @@ -15,9 +15,8 @@ */ package com.google.fhir.proxy.interfaces; -import java.io.IOException; - import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; +import java.io.IOException; import org.apache.http.HttpResponse; public interface AccessDecision { diff --git a/server/src/main/java/com/google/fhir/proxy/interfaces/NoOpAccessDecision.java b/server/src/main/java/com/google/fhir/proxy/interfaces/NoOpAccessDecision.java index a601f124..60ca70d9 100644 --- a/server/src/main/java/com/google/fhir/proxy/interfaces/NoOpAccessDecision.java +++ b/server/src/main/java/com/google/fhir/proxy/interfaces/NoOpAccessDecision.java @@ -37,8 +37,7 @@ public String postProcess(HttpResponse response) { } @Override - public void preProcess(ServletRequestDetails servletRequestDetails) { - } + public void preProcess(ServletRequestDetails servletRequestDetails) {} public static AccessDecision accessGranted() { return new NoOpAccessDecision(true);