Skip to content
2 changes: 1 addition & 1 deletion hapi-deployable-pom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<relativePath>../pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-android/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-base/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@
getterVisibility = JsonAutoDetect.Visibility.NONE,
isGetterVisibility = JsonAutoDetect.Visibility.NONE,
setterVisibility = JsonAutoDetect.Visibility.NONE)
public interface IModelJson {}
public interface IModelJson {
String SENSITIVE_DATA_FILTER_NAME = "sensitiveDataFilter";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*-
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2024 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.model.api.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Annotation to mark a field as sensitive, indicating that it should not
* be displayed or serialized by jackson. The only way to serialize an object annotated with this annotation is to use
* {@link ca.uhn.fhir.util.JsonUtil}, as it has a registered filter against this annotation.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SensitiveNoDisplay {}
67 changes: 67 additions & 0 deletions hapi-fhir-base/src/main/java/ca/uhn/fhir/util/JsonUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,23 @@

import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.model.api.IModelJson;
import ca.uhn.fhir.model.api.annotation.SensitiveNoDisplay;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.PropertyWriter;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import jakarta.annotation.Nonnull;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.Writer;
import java.util.List;
Expand All @@ -38,15 +46,30 @@ public class JsonUtil {

private static final ObjectMapper ourMapperPrettyPrint;
private static final ObjectMapper ourMapperNonPrettyPrint;
private static final ObjectMapper ourMapperIncludeSensitive;

public static final SimpleBeanPropertyFilter SIMPLE_BEAN_PROPERTY_FILTER = new SensitiveDataFilter();

public static final SimpleFilterProvider SENSITIVE_DATA_FILTER_PROVIDER =
new SimpleFilterProvider().addFilter(IModelJson.SENSITIVE_DATA_FILTER_NAME, SIMPLE_BEAN_PROPERTY_FILTER);
public static final SimpleFilterProvider SHOW_ALL_DATA_FILTER_PROVIDER = new SimpleFilterProvider()
.addFilter(IModelJson.SENSITIVE_DATA_FILTER_NAME, SimpleBeanPropertyFilter.serializeAll());

static {
ourMapperPrettyPrint = new ObjectMapper();
ourMapperPrettyPrint.setSerializationInclusion(JsonInclude.Include.NON_NULL);
ourMapperPrettyPrint.setFilterProvider(SENSITIVE_DATA_FILTER_PROVIDER);
ourMapperPrettyPrint.enable(SerializationFeature.INDENT_OUTPUT);

ourMapperNonPrettyPrint = new ObjectMapper();
ourMapperNonPrettyPrint.setSerializationInclusion(JsonInclude.Include.NON_NULL);
ourMapperNonPrettyPrint.setFilterProvider(SENSITIVE_DATA_FILTER_PROVIDER);
ourMapperNonPrettyPrint.disable(SerializationFeature.INDENT_OUTPUT);

ourMapperIncludeSensitive = new ObjectMapper();
ourMapperIncludeSensitive.setFilterProvider(SHOW_ALL_DATA_FILTER_PROVIDER);
ourMapperIncludeSensitive.setSerializationInclusion(JsonInclude.Include.NON_NULL);
ourMapperIncludeSensitive.disable(SerializationFeature.INDENT_OUTPUT);
}

/**
Expand All @@ -67,6 +90,24 @@ public static <T> T deserialize(@Nonnull String theInput, @Nonnull Class<T> theT
public static <T> List<T> deserializeList(@Nonnull String theInput, @Nonnull Class<T> theType) throws IOException {
return ourMapperPrettyPrint.readerForListOf(theType).readValue(theInput);
}
/**
* Parse JSON
*/
public static <T> T deserialize(@Nonnull InputStream theInput, @Nonnull Class<T> theType) throws IOException {
return ourMapperPrettyPrint.readerFor(theType).readValue(theInput);
}

/**
* Includes fields which are annotated with {@link SensitiveNoDisplay}. Currently only meant to be used for serialization
* for batch job parameters.
*/
public static String serializeWithSensitiveData(@Nonnull IModelJson theInput) {
try {
return ourMapperIncludeSensitive.writeValueAsString(theInput);
} catch (JsonProcessingException e) {
throw new InvalidRequestException(Msg.code(2487) + "Failed to encode " + theInput.getClass(), e);
}
}

/**
* Encode JSON
Expand All @@ -93,6 +134,10 @@ public static String serialize(@Nonnull Object theInput, boolean thePrettyPrint)
}
}

public FilterProvider getSensitiveDataFilterProvider() {
return SENSITIVE_DATA_FILTER_PROVIDER;
}

/**
* Encode JSON
*/
Expand All @@ -111,4 +156,26 @@ public static String serializeOrInvalidRequest(IModelJson theJson) {
throw new InvalidRequestException(Msg.code(1741) + "Failed to encode " + theJson.getClass(), e);
}
}

private static class SensitiveDataFilter extends SimpleBeanPropertyFilter {

@Override
protected boolean include(PropertyWriter writer) {
return true; // Default include all except explicitly checked and excluded
}

@Override
public void serializeAsField(Object pojo, JsonGenerator gen, SerializerProvider provider, PropertyWriter writer)
throws Exception {
if (include(writer)) {
if (!isFieldSensitive(writer)) {
super.serializeAsField(pojo, gen, provider, writer);
}
}
}

private boolean isFieldSensitive(PropertyWriter writer) {
return writer.getAnnotation(SensitiveNoDisplay.class) != null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ public enum VersionEnum {
V6_11_0,

V7_0_0,
V7_0_1,

V7_1_0,
V7_2_0;
Expand Down
54 changes: 54 additions & 0 deletions hapi-fhir-base/src/test/java/ca/uhn/fhir/util/JsonUtilTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package ca.uhn.fhir.util;

import ca.uhn.fhir.model.api.IModelJson;
import ca.uhn.fhir.model.api.annotation.SensitiveNoDisplay;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.junit.jupiter.api.Test;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;

class JsonUtilTest {

@JsonFilter(IModelJson.SENSITIVE_DATA_FILTER_NAME)
class TestObject implements IModelJson {
@JsonProperty("sensitiveField")
@SensitiveNoDisplay
private String mySensitiveField;

@JsonProperty(value = "publicField")
private String myPublicField;

public String getPrivateField() {
return mySensitiveField;
}

public void setSensitiveField(String thePrivateField) {
this.mySensitiveField = thePrivateField;
}

public String getPublicField() {
return myPublicField;
}

public void setPublicField(String thePublicField) {
this.myPublicField = thePublicField;
}
}

@Test
public void testSensitiveNoDisplayAnnotationIsHiddenFromBasicSerialization() {
TestObject object = new TestObject();
object.setPublicField("Public Value!");
object.setSensitiveField("Sensitive Value!");

String sensitiveExcluded = JsonUtil.serializeOrInvalidRequest(object);
assertThat(sensitiveExcluded, is(not(containsString("Sensitive Value!"))));

String sensitiveIncluded = JsonUtil.serializeWithSensitiveData(object);
assertThat(sensitiveIncluded, is(containsString("Sensitive Value!")));
}
}
4 changes: 2 additions & 2 deletions hapi-fhir-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
<modelVersion>4.0.0</modelVersion>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-bom</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<packaging>pom</packaging>
<name>HAPI FHIR BOM</name>

<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-checkstyle/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<relativePath>../pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-cli/hapi-fhir-cli-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-cli/hapi-fhir-cli-app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-cli</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<relativePath>../pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<relativePath>../pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-client-okhttp/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-converter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-dist/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<relativePath>../pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-docs/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
type: fix
jira: SMILE-7216
title: "Previously, the Bulk Import (`$import`) job was ignoring the `httpBasicCredentials` section of the incoming parameters
object, causing the job to fail with a 403 error. This has been corrected."
2 changes: 1 addition & 1 deletion hapi-fhir-jacoco/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-jaxrsserver-base/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-jpa/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
2 changes: 1 addition & 1 deletion hapi-fhir-jpaserver-base/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.0.1-SNAPSHOT</version>

<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
Expand Down
Loading