Transaction fails if SearchNarrowingInterceptor is registered and Partitioning Enabled - fix cross-tenant requests failure (#5408)
* Transaction with conditional update fails if SearchNarrowingInterceptor is registered and Enabled Partitioning - fix and tests added
This commit is contained in:
parent
97fc5ca0dc
commit
1c5fe61b38
|
@ -69,7 +69,7 @@ public class UrlBaseTenantIdentificationStrategy implements ITenantIdentificatio
|
||||||
tenantId = defaultIfBlank(theUrlPathTokenizer.peek(), null);
|
tenantId = defaultIfBlank(theUrlPathTokenizer.peek(), null);
|
||||||
|
|
||||||
// If it's "metadata" or starts with "$", use DEFAULT partition and don't consume this token:
|
// If it's "metadata" or starts with "$", use DEFAULT partition and don't consume this token:
|
||||||
if (tenantId != null && (tenantId.equals("metadata") || tenantId.startsWith("$"))) {
|
if (tenantId != null && (tenantId.equals("metadata") || isOperation(tenantId))) {
|
||||||
tenantId = "DEFAULT";
|
tenantId = "DEFAULT";
|
||||||
theRequestDetails.setTenantId(tenantId);
|
theRequestDetails.setTenantId(tenantId);
|
||||||
ourLog.trace("No tenant ID found for metadata or system request; using DEFAULT.");
|
ourLog.trace("No tenant ID found for metadata or system request; using DEFAULT.");
|
||||||
|
@ -94,6 +94,10 @@ public class UrlBaseTenantIdentificationStrategy implements ITenantIdentificatio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isOperation(String theToken) {
|
||||||
|
return theToken.startsWith("$");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String massageServerBaseUrl(String theFhirServerBase, RequestDetails theRequestDetails) {
|
public String massageServerBaseUrl(String theFhirServerBase, RequestDetails theRequestDetails) {
|
||||||
String result = theFhirServerBase;
|
String result = theFhirServerBase;
|
||||||
|
@ -105,9 +109,26 @@ public class UrlBaseTenantIdentificationStrategy implements ITenantIdentificatio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String resolveRelativeUrl(String theRelativeUrl, RequestDetails theRequestDetails) {
|
public String resolveRelativeUrl(String theRelativeUrl, RequestDetails theRequestDetails) {
|
||||||
if (theRequestDetails.getTenantId() != null && !theRelativeUrl.startsWith(theRequestDetails.getTenantId())) {
|
UrlPathTokenizer tokenizer = new UrlPathTokenizer(theRelativeUrl);
|
||||||
return theRequestDetails.getTenantId() + "/" + theRelativeUrl;
|
// there is no more tokens in the URL - skip url resolution
|
||||||
}
|
if (!tokenizer.hasMoreTokens() || tokenizer.peek() == null) {
|
||||||
return theRelativeUrl;
|
return theRelativeUrl;
|
||||||
}
|
}
|
||||||
|
String nextToken = tokenizer.peek();
|
||||||
|
// there is no tenant ID in parent request details or tenant ID is already present in URL - skip url resolution
|
||||||
|
if (theRequestDetails.getTenantId() == null || nextToken.equals(theRequestDetails.getTenantId())) {
|
||||||
|
return theRelativeUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// token is Resource type or operation - adding tenant ID from parent request details
|
||||||
|
if (isResourceType(nextToken, theRequestDetails) || isOperation(nextToken)) {
|
||||||
|
return theRequestDetails.getTenantId() + "/" + theRelativeUrl;
|
||||||
|
} else {
|
||||||
|
return theRelativeUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isResourceType(String token, RequestDetails theRequestDetails) {
|
||||||
|
return theRequestDetails.getFhirContext().getResourceTypes().stream().anyMatch(type -> type.equals(token));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,17 @@ import ca.uhn.fhir.util.UrlPathTokenizer;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.CsvSource;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.mockito.Mockito.lenient;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
@ -69,6 +74,27 @@ public class UrlBaseTenantIdentificationStrategyTest {
|
||||||
assertEquals(BASE_URL, actual);
|
assertEquals(BASE_URL, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CsvSource(value = {
|
||||||
|
" , , empty input url - empty URL should be returned",
|
||||||
|
"TENANT1/Patient/123 , TENANT1/Patient/123 , tenant ID already exists - input URL should be returned",
|
||||||
|
"TENANT1/Patient/$export, TENANT1/Patient/$export , tenant ID already exists - input URL should be returned",
|
||||||
|
"TENANT2/Patient/123 , TENANT2/Patient/123 , requestDetails contains different tenant ID - input URL should be returned",
|
||||||
|
"TENANT2/$export , TENANT2/$export , requestDetails contains different tenant ID - input URL should be returned",
|
||||||
|
"Patient/123 , TENANT1/Patient/123 , url starts with resource type - tenant ID should be added to URL",
|
||||||
|
"Patient/$export , TENANT1/Patient/$export , url starts with resource type - tenant ID should be added to URL",
|
||||||
|
"$export , TENANT1/$export , url starts with operation name - tenant ID should be added to URL",
|
||||||
|
})
|
||||||
|
@ParameterizedTest
|
||||||
|
void resolveRelativeUrl_returnsCorrectlyResolvedUrl(String theInputUrl, String theExpectedResolvedUrl, String theMessage) {
|
||||||
|
lenient().when(myRequestDetails.getTenantId()).thenReturn("TENANT1");
|
||||||
|
lenient().when(myFHIRContext.getResourceTypes()).thenReturn(Collections.singleton("Patient"));
|
||||||
|
lenient().when(myRequestDetails.getFhirContext()).thenReturn(myFHIRContext);
|
||||||
|
|
||||||
|
String actual = ourTenantStrategy.resolveRelativeUrl(theInputUrl, myRequestDetails);
|
||||||
|
|
||||||
|
assertEquals(theExpectedResolvedUrl, actual, theMessage);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void extractTenant_givenNormalRequestAndExplicitTenant_shouldUseTenant() {
|
void extractTenant_givenNormalRequestAndExplicitTenant_shouldUseTenant() {
|
||||||
//given a Patient request on MYTENANT
|
//given a Patient request on MYTENANT
|
||||||
|
|
Loading…
Reference in New Issue