Make sure that sub-request transaction searches and reads preserve HTTP
headers
This commit is contained in:
parent
b8f200f897
commit
aee7b2b882
|
@ -233,7 +233,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
Integer originalOrder = originalRequestOrder.get(nextReqEntry);
|
||||
Entry nextRespEntry = response.getEntry().get(originalOrder);
|
||||
|
||||
ServletSubRequestDetails requestDetails = new ServletSubRequestDetails();
|
||||
ServletSubRequestDetails requestDetails = new ServletSubRequestDetails(theRequestDetails);
|
||||
requestDetails.setServletRequest(theRequestDetails.getServletRequest());
|
||||
requestDetails.setRequestType(RequestTypeEnum.GET);
|
||||
requestDetails.setServer(theRequestDetails.getServer());
|
||||
|
|
|
@ -384,7 +384,7 @@ public class TransactionProcessor<BUNDLE extends IBaseBundle, BUNDLEENTRY> {
|
|||
Integer originalOrder = originalRequestOrder.get(nextReqEntry);
|
||||
BUNDLEENTRY nextRespEntry = myVersionAdapter.getEntries(response).get(originalOrder);
|
||||
|
||||
ServletSubRequestDetails requestDetails = new ServletSubRequestDetails();
|
||||
ServletSubRequestDetails requestDetails = new ServletSubRequestDetails(theRequestDetails);
|
||||
requestDetails.setServletRequest(theRequestDetails.getServletRequest());
|
||||
requestDetails.setRequestType(RequestTypeEnum.GET);
|
||||
requestDetails.setServer(theRequestDetails.getServer());
|
||||
|
|
|
@ -29,11 +29,25 @@ import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
|||
|
||||
public class ServletSubRequestDetails extends ServletRequestDetails {
|
||||
|
||||
private Map<String, ArrayList<String>> myHeaders = new HashMap<>();
|
||||
private Map<String, List<String>> myHeaders = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param theRequestDetails The parent request details
|
||||
*/
|
||||
public ServletSubRequestDetails(ServletRequestDetails theRequestDetails) {
|
||||
if (theRequestDetails != null) {
|
||||
Map<String, List<String>> headers = theRequestDetails.getHeaders();
|
||||
for (Map.Entry<String, List<String>> next : headers.entrySet()) {
|
||||
myHeaders.put(next.getKey().toLowerCase(), next.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addHeader(String theName, String theValue) {
|
||||
String lowerCase = theName.toLowerCase();
|
||||
ArrayList<String> list = myHeaders.get(lowerCase);
|
||||
List<String> list = myHeaders.get(lowerCase);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
myHeaders.put(lowerCase, list);
|
||||
|
@ -43,7 +57,7 @@ public class ServletSubRequestDetails extends ServletRequestDetails {
|
|||
|
||||
@Override
|
||||
public String getHeader(String theName) {
|
||||
ArrayList<String> list = myHeaders.get(theName.toLowerCase());
|
||||
List<String> list = myHeaders.get(theName.toLowerCase());
|
||||
if (list == null || list.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
@ -52,7 +66,7 @@ public class ServletSubRequestDetails extends ServletRequestDetails {
|
|||
|
||||
@Override
|
||||
public List<String> getHeaders(String theName) {
|
||||
ArrayList<String> list = myHeaders.get(theName.toLowerCase());
|
||||
List<String> list = myHeaders.get(theName.toLowerCase());
|
||||
if (list == null || list.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -42,10 +42,7 @@ public class DaoSubscriptionProvider implements ISubscriptionProvider {
|
|||
@Override
|
||||
public IBundleProvider search(SearchParameterMap theMap) {
|
||||
IFhirResourceDao subscriptionDao = myDaoRegistry.getSubscriptionDao();
|
||||
RequestDetails req = new ServletSubRequestDetails();
|
||||
req.setSubRequest(true);
|
||||
|
||||
return subscriptionDao.search(theMap, req);
|
||||
return subscriptionDao.search(theMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -72,12 +72,9 @@ public class DaoSubscriptionMatcher implements ISubscriptionMatcher {
|
|||
RuntimeResourceDefinition responseResourceDef = subscriptionDao.validateCriteriaAndReturnResourceDefinition(theCriteria);
|
||||
SearchParameterMap responseCriteriaUrl = myMatchUrlService.translateMatchUrl(theCriteria, responseResourceDef);
|
||||
|
||||
RequestDetails req = new ServletSubRequestDetails();
|
||||
req.setSubRequest(true);
|
||||
|
||||
IFhirResourceDao<? extends IBaseResource> responseDao = myDaoRegistry.getResourceDao(responseResourceDef.getImplementingClass());
|
||||
responseCriteriaUrl.setLoadSynchronousUpTo(1);
|
||||
|
||||
return responseDao.search(responseCriteriaUrl, req);
|
||||
return responseDao.search(responseCriteriaUrl);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import ca.uhn.fhir.model.primitive.IdDt;
|
|||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
|
||||
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
|
@ -28,6 +30,7 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.in;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
@ -148,6 +151,58 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadInTransaction() {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
||||
patient.addName().setFamily("Tester").addGiven("Raghad");
|
||||
IIdType id = ourClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||
@Override
|
||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||
String authHeader = theRequestDetails.getHeader("Authorization");
|
||||
if (!"Bearer AAA".equals(authHeader)) {
|
||||
throw new AuthenticationException("Invalid auth header: " + authHeader);
|
||||
}
|
||||
return new RuleBuilder()
|
||||
.allow().transaction().withAnyOperation().andApplyNormalRules().andThen()
|
||||
.allow().read().resourcesOfType(Patient.class).withAnyId()
|
||||
.build();
|
||||
}
|
||||
});
|
||||
|
||||
SimpleRequestHeaderInterceptor interceptor = new SimpleRequestHeaderInterceptor("Authorization", "Bearer AAA");
|
||||
try {
|
||||
ourClient.registerInterceptor(interceptor);
|
||||
|
||||
Bundle bundle;
|
||||
Bundle responseBundle;
|
||||
|
||||
// Read
|
||||
bundle = new Bundle();
|
||||
bundle.setType(Bundle.BundleType.TRANSACTION);
|
||||
bundle.addEntry().getRequest().setMethod(Bundle.HTTPVerb.GET).setUrl(id.getValue());
|
||||
responseBundle = ourClient.transaction().withBundle(bundle).execute();
|
||||
patient = (Patient) responseBundle.getEntry().get(0).getResource();
|
||||
assertEquals("Tester", patient.getNameFirstRep().getFamily());
|
||||
|
||||
// Search
|
||||
bundle = new Bundle();
|
||||
bundle.setType(Bundle.BundleType.TRANSACTION);
|
||||
bundle.addEntry().getRequest().setMethod(Bundle.HTTPVerb.GET).setUrl("Patient?");
|
||||
responseBundle = ourClient.transaction().withBundle(bundle).execute();
|
||||
responseBundle = (Bundle) responseBundle.getEntry().get(0).getResource();
|
||||
patient = (Patient) responseBundle.getEntry().get(0).getResource();
|
||||
assertEquals("Tester", patient.getNameFirstRep().getFamily());
|
||||
|
||||
} finally {
|
||||
ourClient.unregisterInterceptor(interceptor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* See #751
|
||||
*/
|
||||
|
|
|
@ -34,9 +34,7 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
@ -145,4 +143,18 @@ public class ServletRequestDetails extends RequestDetails {
|
|||
this.myServletResponse = myServletResponse;
|
||||
}
|
||||
|
||||
public Map<String,List<String>> getHeaders() {
|
||||
Map<String, List<String>> retVal = new HashMap<>();
|
||||
Enumeration<String> names = myServletRequest.getHeaderNames();
|
||||
while (names.hasMoreElements()) {
|
||||
String nextName = names.nextElement();
|
||||
ArrayList<String> headerValues = new ArrayList<>();
|
||||
retVal.put(nextName, headerValues);
|
||||
Enumeration<String> valuesEnum = myServletRequest.getHeaders(nextName);
|
||||
while (valuesEnum.hasMoreElements()) {
|
||||
headerValues.add(valuesEnum.nextElement());
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableMap(retVal);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -277,6 +277,12 @@
|
|||
part of the chain was lost when the chain was described in the server
|
||||
CapabilityStatement. This has been corrected.
|
||||
</action>
|
||||
<action type="fix">
|
||||
In the JPA server, search/read operations being performed within a transaction bundle
|
||||
did not pass the client request HTTP headers to the sub-request. This meant that
|
||||
AuthorizationInterceptor could not authorize these requests if it was depending on
|
||||
headers being present.
|
||||
</action>
|
||||
</release>
|
||||
<release version="3.6.0" date="2018-11-12" description="Food">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue