diff --git a/hapi-deployable-pom/pom.xml b/hapi-deployable-pom/pom.xml index 1cb6dade030..eb73eeb0634 100644 --- a/hapi-deployable-pom/pom.xml +++ b/hapi-deployable-pom/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-android/pom.xml b/hapi-fhir-android/pom.xml index 0efd9f8ca41..9a573147707 100644 --- a/hapi-fhir-android/pom.xml +++ b/hapi-fhir-android/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-base/pom.xml b/hapi-fhir-base/pom.xml index 28cb9278b5b..8435cda5b19 100644 --- a/hapi-fhir-base/pom.xml +++ b/hapi-fhir-base/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-bom/pom.xml b/hapi-fhir-bom/pom.xml index 50e8712adcd..287c3b97c23 100644 --- a/hapi-fhir-bom/pom.xml +++ b/hapi-fhir-bom/pom.xml @@ -4,7 +4,7 @@ 4.0.0 ca.uhn.hapi.fhir hapi-fhir-bom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT pom HAPI FHIR BOM @@ -12,7 +12,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-checkstyle/pom.xml b/hapi-fhir-checkstyle/pom.xml index 22f5f082e30..f4c45ad7593 100644 --- a/hapi-fhir-checkstyle/pom.xml +++ b/hapi-fhir-checkstyle/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml index 19bf9659f3d..2b8cd4af8ce 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml index 81eee9f6772..90b1c320e9b 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-fhir-cli - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-cli/pom.xml b/hapi-fhir-cli/pom.xml index da5d153d45c..3dafefe914e 100644 --- a/hapi-fhir-cli/pom.xml +++ b/hapi-fhir-cli/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-client-okhttp/pom.xml b/hapi-fhir-client-okhttp/pom.xml index 763719d6bd7..d9bc621c40a 100644 --- a/hapi-fhir-client-okhttp/pom.xml +++ b/hapi-fhir-client-okhttp/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-client/pom.xml b/hapi-fhir-client/pom.xml index 755417b00fb..aa8ec1f4e0b 100644 --- a/hapi-fhir-client/pom.xml +++ b/hapi-fhir-client/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-converter/pom.xml b/hapi-fhir-converter/pom.xml index 62f1628c37f..14d2432b584 100644 --- a/hapi-fhir-converter/pom.xml +++ b/hapi-fhir-converter/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-dist/pom.xml b/hapi-fhir-dist/pom.xml index d9d7469beca..4b4037ff3d4 100644 --- a/hapi-fhir-dist/pom.xml +++ b/hapi-fhir-dist/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-docs/pom.xml b/hapi-fhir-docs/pom.xml index 9cc90e735dc..ead123ac73c 100644 --- a/hapi-fhir-docs/pom.xml +++ b/hapi-fhir-docs/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/interceptor/HeaderBasedBinarySecurityContextInterceptor.java b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/interceptor/HeaderBasedBinarySecurityContextInterceptor.java new file mode 100644 index 00000000000..8ad829c3370 --- /dev/null +++ b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/interceptor/HeaderBasedBinarySecurityContextInterceptor.java @@ -0,0 +1,68 @@ +/*- + * #%L + * HAPI FHIR - Docs + * %% + * Copyright (C) 2014 - 2023 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package ca.uhn.hapi.fhir.docs.interceptor; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.server.interceptor.binary.BinarySecurityContextInterceptor; +import org.hl7.fhir.instance.model.api.IBaseBinary; + +/** + * This class is mostly intended as an example implementation of the + * {@link BinarySecurityContextInterceptor} although it could be used if + * you wanted its specific rules. + */ +public class HeaderBasedBinarySecurityContextInterceptor extends BinarySecurityContextInterceptor { + + /** + * Header name + */ + public static final String X_SECURITY_CONTEXT_ALLOWED_IDENTIFIER = "X-SecurityContext-Allowed-Identifier"; + + /** + * Constructor + * + * @param theFhirContext The FHIR context + */ + public HeaderBasedBinarySecurityContextInterceptor(FhirContext theFhirContext) { + super(theFhirContext); + } + + /** + * This method should be overridden in order to determine whether the security + * context identifier is allowed for the user. + * + * @param theSecurityContextSystem The Binary.securityContext.identifier.system value + * @param theSecurityContextValue The Binary.securityContext.identifier.value value + * @param theRequestDetails The request details associated with this request + */ + @Override + protected boolean securityContextIdentifierAllowed(String theSecurityContextSystem, String theSecurityContextValue, RequestDetails theRequestDetails) { + + // In our simple example, we will use an incoming header called X-SecurityContext-Allowed-Identifier + // to determine whether the security context is allowed. This is typically not what you + // would want, since this is trusting the client to tell us what they are allowed + // to see. You would typically verify an access token or user session with something + // external, but this is a simple demonstration. + String actualHeaderValue = theRequestDetails.getHeader(X_SECURITY_CONTEXT_ALLOWED_IDENTIFIER); + String expectedHeaderValue = theSecurityContextSystem + "|" + theSecurityContextValue; + return expectedHeaderValue.equals(actualHeaderValue); + } +} diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_8_0/5052-add-binary-security-interceptor.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_8_0/5052-add-binary-security-interceptor.yaml new file mode 100644 index 00000000000..81afab3a90a --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_8_0/5052-add-binary-security-interceptor.yaml @@ -0,0 +1,6 @@ +--- +type: add +issue: 5052 +title: "A new interceptor called BinarySecurityInterceptor has been added. This interceptor can + be used to enforce access to Binary resources by using values in the Binary.securityContext + element." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/files.properties b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/files.properties index eaf9ae49b56..4a073716ef5 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/files.properties +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/files.properties @@ -109,6 +109,7 @@ page.security.consent_interceptor=Consent Interceptor page.security.search_narrowing_interceptor=Search Narrowing Interceptor page.security.cors=CORS page.security.balp_interceptor=Basic Audit Log Pattern (BALP) +page.security.binary_security_interceptor=Binary Resource Security Interceptor section.validation.title=Validation page.validation.introduction=Introduction diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md index 7064a8318e5..2d5b2a2f75a 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md @@ -182,6 +182,9 @@ HAPI FHIR provides an interceptor that can be used to automatically generate and HAPI FHIR provides an interceptor that can be used to implement user- and system-level authorization rules that are aware of FHIR semantics. See [Authorization](/docs/security/authorization_interceptor.html) for more information. +# Security: Binary Resources + +HAPI FHIR provides an interceptor that can be used to secure access to Binary resources by using the `Binary.securityContext` element. See [Binary Security Interceptor](/docs/security/binary_security_interceptor.html) for more information. # Security: Consent diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/binary_security_interceptor.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/binary_security_interceptor.md new file mode 100644 index 00000000000..2fea34f786b --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/binary_security_interceptor.md @@ -0,0 +1,17 @@ +# Binary Security Interceptor + +The Binary resource has an element called `Binary.securityContext` that can be used to declare a security context for a given resource instance. + +The **BinarySecurityContextInterceptor** can be used to verify whether a calling user/client should have access to a Binary resource they are trying to access. + +Note that this interceptor can currently only enforce identifier values found in `Binary.securityContext.identifier`. Reference values found in `Binary.securityContext.reference` are not examined by this interceptor at this time, although this may be added in the future. + +This interceptor is intended to be subclassed. A simple example is shown below: + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/interceptor/HeaderBasedBinarySecurityContextInterceptor.java}} +``` + +## Combining with Bulk Export + +The `setBinarySecurityContextIdentifierSystem(..)` and `setBinarySecurityContextIdentifierValue(..)` properties on the `BulkExportJobParameters` object can be used to automatically populate the security context on Binary resources created by Bulk Export jobs with values that can be verified by this interceptor. An interceptor on the `STORAGE_INITIATE_BULK_EXPORT` pointcut is the easiest way to set these properties when a new Bulk Export job is being kicked off. diff --git a/hapi-fhir-jacoco/pom.xml b/hapi-fhir-jacoco/pom.xml index 868f234c188..2744b189798 100644 --- a/hapi-fhir-jacoco/pom.xml +++ b/hapi-fhir-jacoco/pom.xml @@ -11,7 +11,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jaxrsserver-base/pom.xml b/hapi-fhir-jaxrsserver-base/pom.xml index 96ec64644b8..1e191c037d1 100644 --- a/hapi-fhir-jaxrsserver-base/pom.xml +++ b/hapi-fhir-jaxrsserver-base/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpa/pom.xml b/hapi-fhir-jpa/pom.xml index 28051fcafc3..de76c7a3e2c 100644 --- a/hapi-fhir-jpa/pom.xml +++ b/hapi-fhir-jpa/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-base/pom.xml b/hapi-fhir-jpaserver-base/pom.xml index 143d26279da..04ca2070362 100644 --- a/hapi-fhir-jpaserver-base/pom.xml +++ b/hapi-fhir-jpaserver-base/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml b/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml index ee8d97cdc6c..904fec429d9 100644 --- a/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml +++ b/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-ips/pom.xml b/hapi-fhir-jpaserver-ips/pom.xml index 192463f223a..26fd0773260 100644 --- a/hapi-fhir-jpaserver-ips/pom.xml +++ b/hapi-fhir-jpaserver-ips/pom.xml @@ -3,7 +3,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-mdm/pom.xml b/hapi-fhir-jpaserver-mdm/pom.xml index a7cd792d99b..d0100c5fa8e 100644 --- a/hapi-fhir-jpaserver-mdm/pom.xml +++ b/hapi-fhir-jpaserver-mdm/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-model/pom.xml b/hapi-fhir-jpaserver-model/pom.xml index 30d4bbc8535..6e27f95a364 100644 --- a/hapi-fhir-jpaserver-model/pom.xml +++ b/hapi-fhir-jpaserver-model/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-searchparam/pom.xml b/hapi-fhir-jpaserver-searchparam/pom.xml index afa60ddd40d..4ef43117ec4 100755 --- a/hapi-fhir-jpaserver-searchparam/pom.xml +++ b/hapi-fhir-jpaserver-searchparam/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-subscription/pom.xml b/hapi-fhir-jpaserver-subscription/pom.xml index 52278f93941..e57901df0d2 100644 --- a/hapi-fhir-jpaserver-subscription/pom.xml +++ b/hapi-fhir-jpaserver-subscription/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-dstu2/pom.xml b/hapi-fhir-jpaserver-test-dstu2/pom.xml index fa29b2e355c..750d5d3172c 100644 --- a/hapi-fhir-jpaserver-test-dstu2/pom.xml +++ b/hapi-fhir-jpaserver-test-dstu2/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-dstu3/pom.xml b/hapi-fhir-jpaserver-test-dstu3/pom.xml index d53356ec8ec..8749eba2dca 100644 --- a/hapi-fhir-jpaserver-test-dstu3/pom.xml +++ b/hapi-fhir-jpaserver-test-dstu3/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-r4/pom.xml b/hapi-fhir-jpaserver-test-r4/pom.xml index 93585a20b08..5a23b611562 100644 --- a/hapi-fhir-jpaserver-test-r4/pom.xml +++ b/hapi-fhir-jpaserver-test-r4/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportTest.java index fe6567acc3a..91ecc8b889e 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportTest.java @@ -11,6 +11,7 @@ import ca.uhn.fhir.jpa.api.model.BulkExportJobResults; import ca.uhn.fhir.jpa.batch.models.Batch2JobStartResponse; import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test; import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.rest.api.server.bulk.BulkExportJobParameters; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.util.Batch2JobDefinitionConstants; @@ -54,6 +55,7 @@ import javax.annotation.Nonnull; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashSet; @@ -61,6 +63,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import java.util.stream.Stream; import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TagsInlineTest.createSearchParameterForInlineSecurity; @@ -69,6 +72,7 @@ import static org.awaitility.Awaitility.await; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.matchesPattern; import static org.hamcrest.Matchers.not; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -86,6 +90,7 @@ public class BulkDataExportTest extends BaseResourceProviderR4Test { void afterEach() { myStorageSettings.setIndexMissingFields(JpaStorageSettings.IndexEnabledEnum.DISABLED); myStorageSettings.setTagStorageMode(new JpaStorageSettings().getTagStorageMode()); + myStorageSettings.setResourceClientIdStrategy(new JpaStorageSettings().getResourceClientIdStrategy()); } @BeforeEach @@ -732,6 +737,28 @@ public class BulkDataExportTest extends BaseResourceProviderR4Test { assertEquals(40, finalJobInstance.getCombinedRecordsProcessed()); } + @Test + public void testSystemBulkExport_ClientIdModeNone() { + myStorageSettings.setResourceClientIdStrategy(JpaStorageSettings.ClientIdStrategyEnum.NOT_ALLOWED); + + List expectedIds = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + expectedIds.add(createPatient(withActiveTrue()).getValue()); + expectedIds.add(createObservation(withStatus("final")).getValue()); + } + + final BulkExportJobParameters options = new BulkExportJobParameters(); + options.setResourceTypes(Set.of("Patient", "Observation")); + options.setFilters(Set.of("Patient?active=true", "Patient?active=false", "Observation?status=final")); + options.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); + options.setOutputFormat(Constants.CT_FHIR_NDJSON); + + JobInstance finalJobInstance = verifyBulkExportResults(options, expectedIds, List.of()); + assertEquals(40, finalJobInstance.getCombinedRecordsProcessed()); + } + + + @Test public void testSystemBulkExport_WithBulkExportInclusionInterceptor() { @@ -739,7 +766,7 @@ public class BulkDataExportTest extends BaseResourceProviderR4Test { @Hook(Pointcut.STORAGE_BULK_EXPORT_RESOURCE_INCLUSION) public boolean include(IBaseResource theResource) { - if (((Patient)theResource).getGender() == Enumerations.AdministrativeGender.FEMALE) { + if (((Patient) theResource).getGender() == Enumerations.AdministrativeGender.FEMALE) { return false; } return true; @@ -767,10 +794,38 @@ public class BulkDataExportTest extends BaseResourceProviderR4Test { assertEquals(10, finalJobInstance.getCombinedRecordsProcessed()); } finally { - myInterceptorRegistry.unregisterInterceptorsIf(t->t instanceof BoysOnlyInterceptor); + myInterceptorRegistry.unregisterInterceptorsIf(t -> t instanceof BoysOnlyInterceptor); } } + @Test + public void testSystemBulkExport_WithSecurityContext() { + List expectedIds = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + expectedIds.add(createPatient(withActiveTrue()).getValue()); + expectedIds.add(createObservation(withStatus("final")).getValue()); + } + + final BulkExportJobParameters options = new BulkExportJobParameters(); + options.setResourceTypes(Set.of("Patient", "Observation")); + options.setFilters(Set.of("Patient?active=true", "Patient?active=false", "Observation?status=final")); + options.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); + options.setOutputFormat(Constants.CT_FHIR_NDJSON); + options.setBinarySecurityContextIdentifierSystem("http://foo"); + options.setBinarySecurityContextIdentifierValue("bar"); + + JobInstance finalJobInstance = verifyBulkExportResults(options, expectedIds, List.of()); + BulkExportJobResults results = JsonUtil.deserialize(finalJobInstance.getReport(), BulkExportJobResults.class); + List binaryIds = results.getResourceTypeToBinaryIds().values().stream().flatMap(Collection::stream).toList(); + assertEquals(2, binaryIds.size()); + for (String next : binaryIds) { + Binary binary = myBinaryDao.read(new IdType(next), new SystemRequestDetails()); + assertEquals("http://foo", binary.getSecurityContext().getIdentifier().getSystem()); + assertEquals("bar", binary.getSecurityContext().getIdentifier().getValue()); + } + } + + private JobInstance verifyBulkExportResults(BulkExportJobParameters theOptions, List theContainedList, List theExcludedList) { Batch2JobStartResponse startResponse = startNewJob(theOptions); @@ -798,6 +853,9 @@ public class BulkDataExportTest extends BaseResourceProviderR4Test { List binaryIds = file.getValue(); for (var nextBinaryId : binaryIds) { + String nextBinaryIdPart = new IdType(nextBinaryId).getIdPart(); + assertThat(nextBinaryIdPart, matchesPattern("[a-zA-Z0-9]{32}")); + Binary binary = myBinaryDao.read(new IdType(nextBinaryId)); assertEquals(Constants.CT_FHIR_NDJSON, binary.getContentType()); diff --git a/hapi-fhir-jpaserver-test-r4b/pom.xml b/hapi-fhir-jpaserver-test-r4b/pom.xml index 677a9ca52d6..4dbc5053465 100644 --- a/hapi-fhir-jpaserver-test-r4b/pom.xml +++ b/hapi-fhir-jpaserver-test-r4b/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-r5/pom.xml b/hapi-fhir-jpaserver-test-r5/pom.xml index aca614fbbe7..85881800013 100644 --- a/hapi-fhir-jpaserver-test-r5/pom.xml +++ b/hapi-fhir-jpaserver-test-r5/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-utilities/pom.xml b/hapi-fhir-jpaserver-test-utilities/pom.xml index 09ab9e26270..2ca337b4257 100644 --- a/hapi-fhir-jpaserver-test-utilities/pom.xml +++ b/hapi-fhir-jpaserver-test-utilities/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml index 84a6d6dec11..afeee5071cf 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml +++ b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-server-mdm/pom.xml b/hapi-fhir-server-mdm/pom.xml index 4c49668e12e..80617f57860 100644 --- a/hapi-fhir-server-mdm/pom.xml +++ b/hapi-fhir-server-mdm/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server-openapi/pom.xml b/hapi-fhir-server-openapi/pom.xml index 0dcc05a3523..d2239b8c3d3 100644 --- a/hapi-fhir-server-openapi/pom.xml +++ b/hapi-fhir-server-openapi/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server/pom.xml b/hapi-fhir-server/pom.xml index be1b382cf47..9eebc8dcd8d 100644 --- a/hapi-fhir-server/pom.xml +++ b/hapi-fhir-server/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/api/server/bulk/BulkExportJobParameters.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/api/server/bulk/BulkExportJobParameters.java index 40740e05876..bde8e3b2efe 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/api/server/bulk/BulkExportJobParameters.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/api/server/bulk/BulkExportJobParameters.java @@ -110,6 +110,10 @@ public class BulkExportJobParameters implements IModelJson { */ @JsonProperty("partitionId") private RequestPartitionId myPartitionId; + @JsonProperty("binarySecurityContextIdentifierSystem") + private String myBinarySecurityContextIdentifierSystem; + @JsonProperty("binarySecurityContextIdentifierValue") + private String myBinarySecurityContextIdentifierValue; public String getExportIdentifier() { return myExportId; @@ -231,6 +235,38 @@ public class BulkExportJobParameters implements IModelJson { this.myPartitionId = thePartitionId; } + /** + * Sets a value to place in the generated Binary resource's + * Binary.securityContext.identifier + */ + public void setBinarySecurityContextIdentifierSystem(String theBinarySecurityContextIdentifierSystem) { + myBinarySecurityContextIdentifierSystem = theBinarySecurityContextIdentifierSystem; + } + + /** + * Sets a value to place in the generated Binary resource's + * Binary.securityContext.identifier + */ + public String getBinarySecurityContextIdentifierSystem() { + return myBinarySecurityContextIdentifierSystem; + } + + /** + * Sets a value to place in the generated Binary resource's + * Binary.securityContext.identifier + */ + public void setBinarySecurityContextIdentifierValue(String theBinarySecurityContextIdentifierValue) { + myBinarySecurityContextIdentifierValue = theBinarySecurityContextIdentifierValue; + } + + /** + * Sets a value to place in the generated Binary resource's + * Binary.securityContext.identifier + */ + public String getBinarySecurityContextIdentifierValue() { + return myBinarySecurityContextIdentifierValue; + } + public enum ExportStyle { PATIENT, GROUP, SYSTEM } diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/AuthorizationConstants.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/AuthorizationConstants.java index 3c2da3fc6c6..43426534786 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/AuthorizationConstants.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/AuthorizationConstants.java @@ -22,6 +22,7 @@ package ca.uhn.fhir.rest.server.interceptor.auth; public class AuthorizationConstants { public static final int ORDER_CONSENT_INTERCEPTOR = 100; + public static final int ORDER_BINARY_SECURITY_INTERCEPTOR = 150; public static final int ORDER_AUTH_INTERCEPTOR = 200; public static final int ORDER_CONVERTER_INTERCEPTOR = 300; diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/binary/BinarySecurityContextInterceptor.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/binary/BinarySecurityContextInterceptor.java new file mode 100644 index 00000000000..b5949976512 --- /dev/null +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/binary/BinarySecurityContextInterceptor.java @@ -0,0 +1,154 @@ +/*- + * #%L + * HAPI FHIR - Server Framework + * %% + * Copyright (C) 2014 - 2023 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package ca.uhn.fhir.rest.server.interceptor.binary; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.i18n.Msg; +import ca.uhn.fhir.interceptor.api.Hook; +import ca.uhn.fhir.interceptor.api.Interceptor; +import ca.uhn.fhir.interceptor.api.Pointcut; +import ca.uhn.fhir.rest.api.server.IPreResourceShowDetails; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.api.server.SystemRequestDetails; +import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException; +import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationConstants; +import ca.uhn.fhir.util.FhirTerser; +import org.apache.commons.lang3.Validate; +import org.hl7.fhir.instance.model.api.IBaseBinary; +import org.hl7.fhir.instance.model.api.IBaseResource; + +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +/** + * This security interceptor checks any Binary resources that are being exposed to + * a user and can forbid the user from accessing them based on the security context + * found in Binary.securityContext.identifier. + *

+ * This interceptor is intended to be subclassed. The default implementation if it + * is not subclassed will reject any access to a Binary resource unless the + * request is a system request (using {@link SystemRequestDetails} or the Binary + * resource has no value in Binary.securityContext.identifier. + *

+ *

+ * Override {@link #securityContextIdentifierAllowed(String, String, RequestDetails)} in order + * to allow the user to access specific context values. + *

+ * + * @since 6.8.0 + */ +@SuppressWarnings("unused") +@Interceptor(order = AuthorizationConstants.ORDER_BINARY_SECURITY_INTERCEPTOR) +public class BinarySecurityContextInterceptor { + + private final FhirContext myFhirContext; + + /** + * Constructor + * + * @param theFhirContext The FHIR context + */ + public BinarySecurityContextInterceptor(FhirContext theFhirContext) { + Validate.notNull(theFhirContext, "theFhirContext must not be null"); + myFhirContext = theFhirContext; + } + + /** + * Interceptor hook method. Do not call this method directly. + */ + @Hook(Pointcut.STORAGE_PRESHOW_RESOURCES) + public void preShowResources(IPreResourceShowDetails theShowDetails, RequestDetails theRequestDetails) { + for (IBaseResource nextResource : theShowDetails.getAllResources()) { + if (nextResource instanceof IBaseBinary) { + applyAccessControl((IBaseBinary) nextResource, theRequestDetails); + } + } + } + + /** + * Interceptor hook method. Do not call this method directly. + */ + @Hook(Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED) + public void preShowResources(IBaseResource theOldValue, IBaseResource theNewValue, RequestDetails theRequestDetails) { + if (theOldValue instanceof IBaseBinary) { + applyAccessControl((IBaseBinary) theOldValue, theRequestDetails); + } + } + + /** + * This method applies security to a given Binary resource. It is not typically + * overridden but you could override it if you wanted to completely replace the + * security logic in this interceptor. + * + * @param theBinary The Binary resource being checked + * @param theRequestDetails The request details associated with this request + */ + protected void applyAccessControl(IBaseBinary theBinary, RequestDetails theRequestDetails) { + FhirTerser terser = myFhirContext.newTerser(); + String securityContextSystem = terser.getSinglePrimitiveValueOrNull(theBinary, "securityContext.identifier.system"); + String securityContextValue = terser.getSinglePrimitiveValueOrNull(theBinary, "securityContext.identifier.value"); + + if (isNotBlank(securityContextSystem) || isNotBlank(securityContextValue)) { + applyAccessControl(theBinary, securityContextSystem, securityContextValue, theRequestDetails); + } + } + + /** + * This method applies access controls to a Binary resource containing the + * given identifier system and value in the Binary.securityContext element. + * + * @param theBinary The binary resource + * @param theSecurityContextSystem The identifier system + * @param theSecurityContextValue The identifier value + * @param theRequestDetails The request details + */ + protected void applyAccessControl(IBaseBinary theBinary, String theSecurityContextSystem, String theSecurityContextValue, RequestDetails theRequestDetails) { + if (theRequestDetails instanceof SystemRequestDetails) { + return; + } + if (securityContextIdentifierAllowed(theSecurityContextSystem, theSecurityContextValue, theRequestDetails)) { + return; + } + + handleForbidden(theBinary); + } + + /** + * Handles a non-permitted operation. This method throws a {@link ForbiddenOperationException} + * but you could override it to change that behaviour. + */ + protected void handleForbidden(IBaseBinary theBinary) { + throw new ForbiddenOperationException(Msg.code(2369) + "Security context not permitted"); + } + + /** + * Determines whether the current user has access to the given security + * context identifier. This method is intended to be overridden, the default + * implementation simply always returns false. + * + * @param theSecurityContextSystem The Binary.securityContext.identifier.system value + * @param theSecurityContextValue The Binary.securityContext.identifier.value value + * @param theRequestDetails The request details associated with this request + * @return Returns true if the request should be permitted, and false otherwise + */ + protected boolean securityContextIdentifierAllowed(String theSecurityContextSystem, String theSecurityContextValue, RequestDetails theRequestDetails) { + return false; + } + +} diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/OffsetCalculator.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/OffsetCalculator.java index 4c73a37ddd8..fa74b6a17f8 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/OffsetCalculator.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/OffsetCalculator.java @@ -1,3 +1,22 @@ +/*- + * #%L + * HAPI FHIR - Server Framework + * %% + * Copyright (C) 2014 - 2023 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ package ca.uhn.fhir.rest.server.method; import ca.uhn.fhir.rest.api.Constants; diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/RequestedPage.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/RequestedPage.java index 8aea1613e34..d182f13f327 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/RequestedPage.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/RequestedPage.java @@ -1,3 +1,22 @@ +/*- + * #%L + * HAPI FHIR - Server Framework + * %% + * Copyright (C) 2014 - 2023 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ package ca.uhn.fhir.rest.server.method; diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/ResponseBundleBuilder.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/ResponseBundleBuilder.java index 818d47bdf35..cb9b53bc89a 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/ResponseBundleBuilder.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/ResponseBundleBuilder.java @@ -1,3 +1,22 @@ +/*- + * #%L + * HAPI FHIR - Server Framework + * %% + * Copyright (C) 2014 - 2023 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ package ca.uhn.fhir.rest.server.method; import ca.uhn.fhir.i18n.Msg; diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/ResponseBundleRequest.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/ResponseBundleRequest.java index 9b7c1bcfb12..9deb8c41e50 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/ResponseBundleRequest.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/ResponseBundleRequest.java @@ -1,3 +1,22 @@ +/*- + * #%L + * HAPI FHIR - Server Framework + * %% + * Copyright (C) 2014 - 2023 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ package ca.uhn.fhir.rest.server.method; import ca.uhn.fhir.model.api.Include; diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/ResponsePage.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/ResponsePage.java index d36823c9cfd..b9c91944ba1 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/ResponsePage.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/ResponsePage.java @@ -1,3 +1,22 @@ +/*- + * #%L + * HAPI FHIR - Server Framework + * %% + * Copyright (C) 2014 - 2023 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ package ca.uhn.fhir.rest.server.method; import org.hl7.fhir.instance.model.api.IBaseResource; diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml index ce6320bf3cf..53389434d47 100644 --- a/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml +++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml @@ -7,7 +7,7 @@ hapi-fhir-serviceloaders ca.uhn.hapi.fhir - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml index e6b33f740a4..70d87d89be7 100644 --- a/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml +++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml @@ -7,7 +7,7 @@ hapi-fhir-serviceloaders ca.uhn.hapi.fhir - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../pom.xml @@ -21,7 +21,7 @@ ca.uhn.hapi.fhir hapi-fhir-caching-api - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml index 9335c0a9417..6029099b749 100644 --- a/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml +++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml @@ -7,7 +7,7 @@ hapi-fhir-serviceloaders ca.uhn.hapi.fhir - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml index b0a4b034bcb..e34a90f51e4 100644 --- a/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml +++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml @@ -7,7 +7,7 @@ hapi-fhir ca.uhn.hapi.fhir - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../../pom.xml diff --git a/hapi-fhir-serviceloaders/pom.xml b/hapi-fhir-serviceloaders/pom.xml index 030afbf06eb..9dde28f71f5 100644 --- a/hapi-fhir-serviceloaders/pom.xml +++ b/hapi-fhir-serviceloaders/pom.xml @@ -5,7 +5,7 @@ hapi-deployable-pom ca.uhn.hapi.fhir - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml index 90ce7c41cc1..7d55b61309f 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml index 7b2768e3b06..43296a0974a 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT hapi-fhir-spring-boot-sample-client-apache diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml index 2a1ad54b5a0..dbe4dd12825 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml index c7572bb43a5..869578e75b8 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml index 1ef53facc77..1726a6924b7 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml index fb0e7899832..6a9fe7b3373 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/pom.xml b/hapi-fhir-spring-boot/pom.xml index e91f6248bf1..25cca312042 100644 --- a/hapi-fhir-spring-boot/pom.xml +++ b/hapi-fhir-spring-boot/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-sql-migrate/pom.xml b/hapi-fhir-sql-migrate/pom.xml index 81fc6daba2c..db845a342e1 100644 --- a/hapi-fhir-sql-migrate/pom.xml +++ b/hapi-fhir-sql-migrate/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-batch2-jobs/pom.xml b/hapi-fhir-storage-batch2-jobs/pom.xml index 5a3fcc03db1..4744b8f78a7 100644 --- a/hapi-fhir-storage-batch2-jobs/pom.xml +++ b/hapi-fhir-storage-batch2-jobs/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/WriteBinaryStep.java b/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/WriteBinaryStep.java index fd06677bc9a..59071628dad 100644 --- a/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/WriteBinaryStep.java +++ b/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/WriteBinaryStep.java @@ -25,6 +25,8 @@ import ca.uhn.fhir.batch2.api.JobExecutionFailedException; import ca.uhn.fhir.batch2.api.RunOutcome; import ca.uhn.fhir.batch2.api.StepExecutionDetails; import ca.uhn.fhir.batch2.jobs.export.models.BulkExportBinaryFileId; +import ca.uhn.fhir.context.FhirVersionEnum; +import ca.uhn.fhir.jpa.util.RandomTextUtils; import ca.uhn.fhir.rest.api.server.bulk.BulkExportJobParameters; import ca.uhn.fhir.batch2.jobs.export.models.ExpandedResourcesList; import ca.uhn.fhir.context.FhirContext; @@ -36,8 +38,12 @@ import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.server.SystemRequestDetails; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.util.BinaryUtil; +import ca.uhn.fhir.util.FhirTerser; +import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; import org.hl7.fhir.instance.model.api.IBaseBinary; import org.hl7.fhir.instance.model.api.IBaseExtension; import org.hl7.fhir.instance.model.api.IBaseHasExtensions; @@ -50,6 +56,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; +import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.slf4j.LoggerFactory.getLogger; public class WriteBinaryStep implements IJobStepWorker { @@ -107,13 +114,45 @@ public class WriteBinaryStep implements IJobStepWorker binaryCaptor = ArgumentCaptor.forClass(IBaseBinary.class); ArgumentCaptor binaryDaoCreateRequestDetailsCaptor = ArgumentCaptor.forClass(SystemRequestDetails.class); verify(binaryDao) - .create(binaryCaptor.capture(), binaryDaoCreateRequestDetailsCaptor.capture()); + .update(binaryCaptor.capture(), binaryDaoCreateRequestDetailsCaptor.capture()); String outputString = new String(binaryCaptor.getValue().getContent()); // post-pending a \n (as this is what the binary does) String expected = String.join("\n", stringified) + "\n"; diff --git a/hapi-fhir-storage-batch2-test-utilities/pom.xml b/hapi-fhir-storage-batch2-test-utilities/pom.xml index 7dd205ad68d..b031de1491c 100644 --- a/hapi-fhir-storage-batch2-test-utilities/pom.xml +++ b/hapi-fhir-storage-batch2-test-utilities/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-batch2/pom.xml b/hapi-fhir-storage-batch2/pom.xml index 8ae1a897b88..386bff231ae 100644 --- a/hapi-fhir-storage-batch2/pom.xml +++ b/hapi-fhir-storage-batch2/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-cr/pom.xml b/hapi-fhir-storage-cr/pom.xml index 06af52b822d..82464aebd02 100644 --- a/hapi-fhir-storage-cr/pom.xml +++ b/hapi-fhir-storage-cr/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-mdm/pom.xml b/hapi-fhir-storage-mdm/pom.xml index 91e5fafe815..d43db7bba52 100644 --- a/hapi-fhir-storage-mdm/pom.xml +++ b/hapi-fhir-storage-mdm/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-test-utilities/pom.xml b/hapi-fhir-storage-test-utilities/pom.xml index 489a3b70706..a96661518bf 100644 --- a/hapi-fhir-storage-test-utilities/pom.xml +++ b/hapi-fhir-storage-test-utilities/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage/pom.xml b/hapi-fhir-storage/pom.xml index 321ccc0061a..7e0671ba447 100644 --- a/hapi-fhir-storage/pom.xml +++ b/hapi-fhir-storage/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/binary/svc/BaseBinaryStorageSvcImpl.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/binary/svc/BaseBinaryStorageSvcImpl.java index e69c7f38f51..6848f1bbdf8 100644 --- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/binary/svc/BaseBinaryStorageSvcImpl.java +++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/binary/svc/BaseBinaryStorageSvcImpl.java @@ -25,6 +25,7 @@ import ca.uhn.fhir.interceptor.api.HookParams; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.jpa.binary.api.IBinaryStorageSvc; +import ca.uhn.fhir.jpa.util.RandomTextUtils; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.PayloadTooLargeException; @@ -59,8 +60,6 @@ public abstract class BaseBinaryStorageSvcImpl implements IBinaryStorageSvc { public static long DEFAULT_MAXIMUM_BINARY_SIZE = Long.MAX_VALUE - 1; public static String BLOB_ID_PREFIX_APPLIED = "blob-id-prefix-applied"; - private final SecureRandom myRandom; - private final String CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; private final int ID_LENGTH = 100; private long myMaximumBinarySize = DEFAULT_MAXIMUM_BINARY_SIZE; private int myMinimumBinarySize; @@ -72,7 +71,7 @@ public abstract class BaseBinaryStorageSvcImpl implements IBinaryStorageSvc { public BaseBinaryStorageSvcImpl() { - myRandom = new SecureRandom(); + super(); } @Override @@ -98,12 +97,7 @@ public abstract class BaseBinaryStorageSvcImpl implements IBinaryStorageSvc { @Override public String newBlobId() { - StringBuilder b = new StringBuilder(); - for (int i = 0; i < ID_LENGTH; i++) { - int nextInt = Math.abs(myRandom.nextInt()); - b.append(CHARS.charAt(nextInt % CHARS.length())); - } - return b.toString(); + return RandomTextUtils.newSecureRandomAlphaNumericString(ID_LENGTH); } /** diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/util/RandomTextUtils.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/util/RandomTextUtils.java new file mode 100644 index 00000000000..adf7215f92c --- /dev/null +++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/util/RandomTextUtils.java @@ -0,0 +1,41 @@ +/*- + * #%L + * HAPI FHIR Storage api + * %% + * Copyright (C) 2014 - 2023 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package ca.uhn.fhir.jpa.util; + +import java.security.SecureRandom; + +public class RandomTextUtils { + + private static final SecureRandom ourRandom = new SecureRandom(); + private static final String ALPHANUMERIC_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + /** + * Creates a new string using randomly selected characters (using a secure random + * PRNG) containing letters (mixed case) and numbers. + */ + public static String newSecureRandomAlphaNumericString(int theLength) { + StringBuilder b = new StringBuilder(); + for (int i = 0; i < theLength; i++) { + int nextInt = Math.abs(ourRandom.nextInt()); + b.append(ALPHANUMERIC_CHARS.charAt(nextInt % ALPHANUMERIC_CHARS.length())); + } + return b.toString(); + } +} diff --git a/hapi-fhir-storage/src/test/java/ca/uhn/fhir/rest/server/interceptor/binary/BinarySecurityContextInterceptorTest.java b/hapi-fhir-storage/src/test/java/ca/uhn/fhir/rest/server/interceptor/binary/BinarySecurityContextInterceptorTest.java new file mode 100644 index 00000000000..ff3529bf8d8 --- /dev/null +++ b/hapi-fhir-storage/src/test/java/ca/uhn/fhir/rest/server/interceptor/binary/BinarySecurityContextInterceptorTest.java @@ -0,0 +1,211 @@ +package ca.uhn.fhir.rest.server.interceptor.binary; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.api.server.SystemRequestDetails; +import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException; +import ca.uhn.fhir.test.utilities.server.HashMapResourceProviderExtension; +import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; +import org.hl7.fhir.r4.model.Binary; +import org.hl7.fhir.r4.model.Patient; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +class BinarySecurityContextInterceptorTest { + + + private static final FhirContext ourCtx = FhirContext.forR4Cached(); + @RegisterExtension + @Order(0) + public static final RestfulServerExtension ourServer = new RestfulServerExtension(ourCtx) + .registerInterceptor(new HeaderBasedBinarySecurityContextInterceptor(ourCtx)); + @RegisterExtension + @Order(1) + public static final HashMapResourceProviderExtension ourBinaryProvider = new HashMapResourceProviderExtension<>(ourServer, Binary.class); + @RegisterExtension + @Order(1) + public static final HashMapResourceProviderExtension ourPatientProvider = new HashMapResourceProviderExtension<>(ourServer, Patient.class); + + @Test + void testRead_SecurityContextIdentifierPresent_RequestAllowedByInterceptor() { + storeBinaryWithSecurityContextIdentifier(); + + Binary actual = ourServer + .getFhirClient() + .read() + .resource(Binary.class) + .withId("A") + .withAdditionalHeader(HeaderBasedBinarySecurityContextInterceptor.X_SECURITY_CONTEXT_ALLOWED_IDENTIFIER, "http://foo|bar") + .execute(); + assertEquals("A", actual.getIdElement().getIdPart()); + assertEquals("http://foo", actual.getSecurityContext().getIdentifier().getSystem()); + } + + @Test + void testRead_SecurityContextIdentifierPresent_SystemRequestDetailsPermitted() { + storeBinaryWithSecurityContextIdentifier(); + + IBundleProvider results = ourBinaryProvider.searchAll(new SystemRequestDetails()); + assertEquals(1, results.sizeOrThrowNpe()); + } + + @Test + void testRead_SecurityContextIdentifierPresent_RequestBlockedByInterceptor() { + storeBinaryWithSecurityContextIdentifier(); + + try { + ourServer + .getFhirClient() + .read() + .resource(Binary.class) + .withId("A") + .execute(); + fail(); + } catch (ForbiddenOperationException e) { + assertEquals("HTTP 403 Forbidden: HAPI-2369: Security context not permitted", e.getMessage()); + } + } + + @Test + void testRead_SecurityContextIdentifierNotPresent() { + storeBinaryWithoutSecurityContext(); + + Binary actual = ourServer + .getFhirClient() + .read() + .resource(Binary.class) + .withId("A") + .execute(); + assertEquals("A", actual.getIdElement().getIdPart()); + assertNull(actual.getSecurityContext().getIdentifier().getSystem()); + } + + @Test + void testRead_NonBinaryResource() { + Patient patient = new Patient(); + patient.setId("Patient/A"); + patient.setActive(true); + ourPatientProvider.store(patient); + + Patient actual = ourServer + .getFhirClient() + .read() + .resource(Patient.class) + .withId("A") + .execute(); + assertEquals("A", actual.getIdElement().getIdPart()); + assertTrue(actual.getActive()); + } + + + + + + @Test + void testUpdate_SecurityContextIdentifierPresent_RequestAllowedByInterceptor() { + storeBinaryWithSecurityContextIdentifier(); + + Binary newBinary = new Binary(); + newBinary.setId("Binary/A"); + newBinary.setContentType("text/plain"); + + MethodOutcome outcome = ourServer + .getFhirClient() + .update() + .resource(newBinary) + .withAdditionalHeader(HeaderBasedBinarySecurityContextInterceptor.X_SECURITY_CONTEXT_ALLOWED_IDENTIFIER, "http://foo|bar") + .execute(); + assertEquals(2L, outcome.getId().getVersionIdPartAsLong()); + } + + @Test + void testUpdate_SecurityContextIdentifierPresent_RequestBlockedByInterceptor() { + storeBinaryWithSecurityContextIdentifier(); + + try { + Binary newBinary = new Binary(); + newBinary.setId("Binary/A"); + newBinary.setContentType("text/plain"); + + ourServer + .getFhirClient() + .update() + .resource(newBinary) + .execute(); + fail(); + } catch (ForbiddenOperationException e) { + assertEquals("HTTP 403 Forbidden: HAPI-2369: Security context not permitted", e.getMessage()); + } + } + + + private void storeBinaryWithoutSecurityContext() { + Binary binary = new Binary(); + binary.setId("Binary/A"); + binary.setContentType("text/plain"); + ourBinaryProvider.store(binary); + } + + /** + * This class also exists in hapi-fhir-docs - Make sure any changes here + * are reflected there too! + */ + private void storeBinaryWithSecurityContextIdentifier() { + Binary binary = new Binary(); + binary.setId("Binary/A"); + binary.getSecurityContext().getIdentifier().setSystem("http://foo"); + binary.getSecurityContext().getIdentifier().setValue("bar"); + ourBinaryProvider.store(binary); + } + + + /** + * This class also exists in hapi-fhir-docs - Update it there too if this changes! + */ + public static class HeaderBasedBinarySecurityContextInterceptor extends BinarySecurityContextInterceptor { + + /** + * Header name + */ + public static final String X_SECURITY_CONTEXT_ALLOWED_IDENTIFIER = "X-SecurityContext-Allowed-Identifier"; + + /** + * Constructor + * + * @param theFhirContext The FHIR context + */ + public HeaderBasedBinarySecurityContextInterceptor(FhirContext theFhirContext) { + super(theFhirContext); + } + + /** + * This method should be overridden in order to determine whether the security + * context identifier is allowed for the user. + * + * @param theSecurityContextSystem The Binary.securityContext.identifier.system value + * @param theSecurityContextValue The Binary.securityContext.identifier.value value + * @param theRequestDetails The request details associated with this request + */ + @Override + protected boolean securityContextIdentifierAllowed(String theSecurityContextSystem, String theSecurityContextValue, RequestDetails theRequestDetails) { + + // In our simple example, we will use an incoming header called X-SecurityContext-Allowed-Identifier + // to determine whether the security context is allowed. This is typically not what you + // would want, since this is trusting the client to tell us what they are allowed + // to see. You would typically verify an access token or user session with something + // external, but this is a simple demonstration. + String actualHeaderValue = theRequestDetails.getHeader(X_SECURITY_CONTEXT_ALLOWED_IDENTIFIER); + String expectedHeaderValue = theSecurityContextSystem + "|" + theSecurityContextValue; + return expectedHeaderValue.equals(actualHeaderValue); + } + } + +} diff --git a/hapi-fhir-structures-dstu2.1/pom.xml b/hapi-fhir-structures-dstu2.1/pom.xml index c2d0719bc90..33b3d164c26 100644 --- a/hapi-fhir-structures-dstu2.1/pom.xml +++ b/hapi-fhir-structures-dstu2.1/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu2/pom.xml b/hapi-fhir-structures-dstu2/pom.xml index 5f9dbded75d..222ae8ac461 100644 --- a/hapi-fhir-structures-dstu2/pom.xml +++ b/hapi-fhir-structures-dstu2/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu3/pom.xml b/hapi-fhir-structures-dstu3/pom.xml index 268c7d9a211..1135a07bde4 100644 --- a/hapi-fhir-structures-dstu3/pom.xml +++ b/hapi-fhir-structures-dstu3/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-hl7org-dstu2/pom.xml b/hapi-fhir-structures-hl7org-dstu2/pom.xml index b39917b48ec..24f0c9cff63 100644 --- a/hapi-fhir-structures-hl7org-dstu2/pom.xml +++ b/hapi-fhir-structures-hl7org-dstu2/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r4/pom.xml b/hapi-fhir-structures-r4/pom.xml index 654db47d7f2..aceafa7fabe 100644 --- a/hapi-fhir-structures-r4/pom.xml +++ b/hapi-fhir-structures-r4/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r4b/pom.xml b/hapi-fhir-structures-r4b/pom.xml index 3fcc2179bf1..f385d30beff 100644 --- a/hapi-fhir-structures-r4b/pom.xml +++ b/hapi-fhir-structures-r4b/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r5/pom.xml b/hapi-fhir-structures-r5/pom.xml index da17ed839de..99fec65d69a 100644 --- a/hapi-fhir-structures-r5/pom.xml +++ b/hapi-fhir-structures-r5/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-test-utilities/pom.xml b/hapi-fhir-test-utilities/pom.xml index 824c105079e..f92b5808e6f 100644 --- a/hapi-fhir-test-utilities/pom.xml +++ b/hapi-fhir-test-utilities/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-testpage-overlay/pom.xml b/hapi-fhir-testpage-overlay/pom.xml index 9a2018d38e6..66ede12e4d5 100644 --- a/hapi-fhir-testpage-overlay/pom.xml +++ b/hapi-fhir-testpage-overlay/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-validation-resources-dstu2.1/pom.xml b/hapi-fhir-validation-resources-dstu2.1/pom.xml index a61fa01a48b..1134b80d5c4 100644 --- a/hapi-fhir-validation-resources-dstu2.1/pom.xml +++ b/hapi-fhir-validation-resources-dstu2.1/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-dstu2/pom.xml b/hapi-fhir-validation-resources-dstu2/pom.xml index 57f4daf36cf..a0dc6aa9e62 100644 --- a/hapi-fhir-validation-resources-dstu2/pom.xml +++ b/hapi-fhir-validation-resources-dstu2/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-dstu3/pom.xml b/hapi-fhir-validation-resources-dstu3/pom.xml index 58ac108727c..b43d9b02d12 100644 --- a/hapi-fhir-validation-resources-dstu3/pom.xml +++ b/hapi-fhir-validation-resources-dstu3/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r4/pom.xml b/hapi-fhir-validation-resources-r4/pom.xml index a4a2988a161..bcda02cf979 100644 --- a/hapi-fhir-validation-resources-r4/pom.xml +++ b/hapi-fhir-validation-resources-r4/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r4b/pom.xml b/hapi-fhir-validation-resources-r4b/pom.xml index ffb780fa9d6..55dccb925a9 100644 --- a/hapi-fhir-validation-resources-r4b/pom.xml +++ b/hapi-fhir-validation-resources-r4b/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r5/pom.xml b/hapi-fhir-validation-resources-r5/pom.xml index 8a36a9652f4..dc3df50b4d1 100644 --- a/hapi-fhir-validation-resources-r5/pom.xml +++ b/hapi-fhir-validation-resources-r5/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation/pom.xml b/hapi-fhir-validation/pom.xml index 07f6ffcb351..ab536f6d8de 100644 --- a/hapi-fhir-validation/pom.xml +++ b/hapi-fhir-validation/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml index f0299d9fbb9..3be18c17a0a 100644 --- a/hapi-tinder-plugin/pom.xml +++ b/hapi-tinder-plugin/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../pom.xml diff --git a/hapi-tinder-test/pom.xml b/hapi-tinder-test/pom.xml index 9059b10857a..4eacff61eff 100644 --- a/hapi-tinder-test/pom.xml +++ b/hapi-tinder-test/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index 08ced3c838f..b9beb1a64d3 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-fhir pom - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT HAPI-FHIR An open-source implementation of the FHIR specification in Java. diff --git a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml index 6e03ace49e4..86e8fb17ff1 100644 --- a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml +++ b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../../pom.xml diff --git a/tests/hapi-fhir-base-test-mindeps-client/pom.xml b/tests/hapi-fhir-base-test-mindeps-client/pom.xml index aa4e15d0064..7f9e5b50e20 100644 --- a/tests/hapi-fhir-base-test-mindeps-client/pom.xml +++ b/tests/hapi-fhir-base-test-mindeps-client/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../../pom.xml diff --git a/tests/hapi-fhir-base-test-mindeps-server/pom.xml b/tests/hapi-fhir-base-test-mindeps-server/pom.xml index 6d3fc67bcdd..6910d86f677 100644 --- a/tests/hapi-fhir-base-test-mindeps-server/pom.xml +++ b/tests/hapi-fhir-base-test-mindeps-server/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.11-SNAPSHOT + 6.7.12-SNAPSHOT ../../pom.xml