Skip to content

Commit

Permalink
Issue #1961 - Optionally reject references without resource type
Browse files Browse the repository at this point in the history
Signed-off-by: Troy Biesterfeld <tbieste@us.ibm.com>
  • Loading branch information
tbieste committed Apr 9, 2021
1 parent dc4cf55 commit 9bd9b81
Show file tree
Hide file tree
Showing 14 changed files with 246 additions and 65 deletions.
4 changes: 2 additions & 2 deletions docs/src/pages/guides/FHIRServerUsersGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ layout: post
title: IBM FHIR Server User's Guide
description: IBM FHIR Server User's Guide
Copyright: years 2017, 2021
lastupdated: "2021-03-10"
lastupdated: "2021-04-09"
permalink: /FHIRServerUsersGuide/
---

Expand Down Expand Up @@ -2592,7 +2592,7 @@ For more information about topics related to configuring a FHIR server, see the

- <b id="f5">5</b>

An external reference is a reference to a resource which is meaningful outside a particular request bundle. The value typically includes the resource type and the resource identifier, and could be an absolute or relative URL. Examples: `https://fhirserver1:9443/fhir-server/api/v4/Patient/12345`, `Patient/12345`, etc. [](#a5)
An external reference is a reference to a resource which is meaningful outside a particular request bundle. The value must include the resource type and the resource identifier, and could be an absolute or relative URL. Examples: `https://fhirserver1:9443/fhir-server/api/v4/Patient/12345`, `Patient/12345`, etc. [](#a5)

- <b id="f6">6</b>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"reference": "Organization/1"
},
"request": {
"reference": "http://www.BenefitsInc.com/fhir/oralhealthclaim/15476332402"
"reference": "http://www.BenefitsInc.com/fhir/Claim/15476332402"
},
"outcome": "complete",
"disposition": "Claim settled as per contract.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
}
},
"request": {
"reference": "http://www.BenefitsInc.com/fhir/coverageeligibilityrequest/225476332405"
"reference": "http://www.BenefitsInc.com/fhir/CoverageEligibilityRequest/225476332405"
},
"outcome": "complete",
"disposition": "Policy is currently in-force.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
},
"created": "2014-08-16",
"request": {
"reference": "http://www.BenefitsInc.com/fhir/coverageeligibilityrequest/225476332402"
"reference": "http://www.BenefitsInc.com/fhir/CoverageEligibilityRequest/225476332402"
},
"outcome": "complete",
"disposition": "Policy is currently in-force.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
],
"status": "active",
"request": {
"reference": "http://www.BenefitsInc.com/fhir/eligibility/225476332402"
"reference": "http://www.BenefitsInc.com/fhir/EnrollmentRequest/225476332402"
},
"outcome": "complete",
"disposition": "Dependant added to policy.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"reference": "Organization/2"
},
"request": {
"reference": "http://www.BenefitsInc.com/fhir/eligibility/225476332402"
"reference": "http://www.BenefitsInc.com/fhir/Task/225476332402"
},
"requestor": {
"reference": "Organization/1"
Expand Down Expand Up @@ -89,7 +89,7 @@
]
},
"request": {
"reference": "http://www.BenefitsInc.com/fhir/oralhealthclaim/225476332699"
"reference": "http://www.BenefitsInc.com/fhir/Claim/225476332699"
},
"date": "2014-08-12",
"amount": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
</requestor>

<request>
<reference value="http://www.BenefitsInc.com/fhir/oralhealthclaim/15476332402"/>
<reference value="http://www.BenefitsInc.com/fhir/Claim/15476332402"/>
</request>

<outcome value="complete"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
</requestor>

<request>
<reference value="http://www.BenefitsInc.com/fhir/coverageeligibilityrequest/225476332405"/>
<reference value="http://www.BenefitsInc.com/fhir/CoverageEligibilityRequest/225476332405"/>
</request>

<outcome value="complete"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<created value="2014-08-16"/>

<request>
<reference value="http://www.BenefitsInc.com/fhir/coverageeligibilityrequest/225476332402"/>
<reference value="http://www.BenefitsInc.com/fhir/CoverageEligibilityRequest/225476332402"/>
</request>

<outcome value="complete"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<status value="active"/>

<request>
<reference value="http://www.BenefitsInc.com/fhir/eligibility/225476332402"/>
<reference value="http://www.BenefitsInc.com/fhir/EnrollmentRequest/225476332402"/>
</request>

<outcome value="complete"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
</paymentIssuer>

<request>
<reference value="http://www.BenefitsInc.com/fhir/eligibility/225476332402"/>
<reference value="http://www.BenefitsInc.com/fhir/Task/225476332402"/>
</request>

<requestor>
Expand Down Expand Up @@ -104,7 +104,7 @@
</coding>
</type>
<request>
<reference value="http://www.BenefitsInc.com/fhir/oralhealthclaim/225476332699"/>
<reference value="http://www.BenefitsInc.com/fhir/Claim/225476332699"/>
</request>
<date value="2014-08-12"/>
<amount>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* (C) Copyright IBM Corp. 2019, 2020
* (C) Copyright IBM Corp. 2019, 2021
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -55,6 +55,7 @@ public final class ValidationSupport {
private static final int RESOURCE_TYPE_GROUP = 4;
private static final int MIN_STRING_LENGTH = 1;
private static final int MAX_STRING_LENGTH = 1048576; // 1024 * 1024 = 1MB
private static final String LOCAL_REF_PREFIX = "urn:";
private static final String FHIR_XHTML_XSD = "fhir-xhtml.xsd";
private static final String FHIR_XML_XSD = "xml.xsd";
private static final String FHIR_XMLDSIG_CORE_SCHEMA_XSD = "xmldsig-core-schema.xsd";
Expand Down Expand Up @@ -672,54 +673,57 @@ public static void checkReferenceType(Element choiceElement, String elementName,
}

/**
* Checks that the reference contains valid resource type values.
* @param reference the reference
* @param elementName the element name
* @param referenceTypes the valid resource types for the reference
* @throws IllegalStateException if the resource type found in the reference value does not match the specified Reference.type value
* or is not one of the allowed reference types for that element
*/
public static void checkReferenceType(Reference reference, String elementName, String... referenceTypes) {
boolean checkReferenceTypes = FHIRModelConfig.getCheckReferenceTypes();
if (reference != null && checkReferenceTypes) {
String referenceType = getReferenceType(reference);
if (referenceType != null && !ModelSupport.isResourceType(referenceType)) {
throw new IllegalStateException(
String.format("Resource type found in Reference.type: '%s' for element: '%s' must be a valid resource type name",
referenceType, elementName));
}
List<String> referenceTypeList = Arrays.asList(referenceTypes);

// If there is an explicit Reference.type, ensure its an allowed type
if (referenceType != null && !referenceTypeList.contains(referenceType)) {
throw new IllegalStateException(
String.format("Resource type found in Reference.type: '%s' for element: '%s' must be one of: %s",
referenceType, elementName, referenceTypeList.toString()));
}

String referenceReference = getReferenceReference(reference);
String resourceType = null;

if (referenceReference != null && !referenceReference.startsWith("#")) {
Matcher matcher = REFERENCE_PATTERN.matcher(referenceReference);
if (matcher.matches()) {
resourceType = matcher.group(RESOURCE_TYPE_GROUP);
// If there is an explicit Reference.type, check that the resourceType pattern matches it
if (referenceType != null && !resourceType.equals(referenceType)) {
throw new IllegalStateException(
String.format("Resource type found in reference value: '%s' for element: '%s' does not match Reference.type: %s",
referenceReference, elementName, referenceType));
}
}
if (reference == null || !FHIRModelConfig.getCheckReferenceTypes()) {
return;
}

String resourceType = null;
String referenceReference = getReferenceReference(reference);
List<String> referenceTypeList = Arrays.asList(referenceTypes);

if (referenceReference != null && !referenceReference.startsWith("#") && !referenceReference.startsWith(LOCAL_REF_PREFIX)) {
Matcher matcher = REFERENCE_PATTERN.matcher(referenceReference);
if (matcher.matches()) {
resourceType = matcher.group(RESOURCE_TYPE_GROUP);
}

// resourceType is required in the reference value
if (resourceType == null) {
resourceType = referenceType;
throw new IllegalStateException(String.format("Resource type not found in reference value: '%s' for element: '%s'", referenceReference, elementName));
}

// If we've successfully inferred a type, check that its an allowed value
if (resourceType != null) {
if (!referenceTypeList.contains(resourceType)) {
throw new IllegalStateException(
String.format("Resource type found in reference value: '%s' for element: '%s' must be one of: %s",
referenceReference, elementName, referenceTypeList.toString()));
}
if (!ModelSupport.isResourceType(resourceType)) {
throw new IllegalStateException(String.format("Resource type found in reference value: '%s' for element: '%s' must be a valid resource type name", referenceReference, elementName));
}

// If there is a resourceType in the reference value, check that it's an allowed value
if (!referenceTypeList.contains(resourceType)) {
throw new IllegalStateException(String.format("Resource type found in reference value: '%s' for element: '%s' must be one of: %s", referenceReference, elementName, referenceTypeList.toString()));
}
}

String referenceType = getReferenceType(reference);
if (referenceType != null) {
if (!ModelSupport.isResourceType(referenceType)) {
throw new IllegalStateException(String.format("Resource type found in Reference.type: '%s' for element: '%s' must be a valid resource type name", referenceType, elementName));
}

// If there is an explicit Reference.type, ensure it's an allowed type
if (!referenceTypeList.contains(referenceType)) {
throw new IllegalStateException(String.format("Resource type found in Reference.type: '%s' for element: '%s' must be one of: %s", referenceType, elementName, referenceTypeList.toString()));
}

// If there is an explicit Reference.type, check that the resourceType pattern matches it
if (resourceType != null && !resourceType.equals(referenceType)) {
throw new IllegalStateException(String.format("Resource type found in reference value: '%s' for element: '%s' does not match Reference.type: %s", referenceReference, elementName, referenceType));
}
}
}
Expand Down
Loading

0 comments on commit 9bd9b81

Please sign in to comment.