OHSUCMP / ecp-sds-hardfork

eCare Plan Supplemental Data Store (hard-forked from hapi-fhir-jpaserver-starter v6.4.0)
Apache License 2.0
0 stars 4 forks source link

throwing 500 Internal Server Error getting Linkage resources #12

Closed mattStorer closed 1 month ago

mattStorer commented 1 month ago

SDS is throwing 500 Internal Server Errors when eCarePlanner attempts to query Linkage resources:

image

Response body:

{
  "resourceType": "OperationOutcome",
  "issue": [ {
    "severity": "error",
    "code": "processing",
    "diagnostics": "Cannot invoke \"String.equalsIgnoreCase(String)\" because \"this.userResourceType\" is null"
  } ]
}

Stack trace:

2024-09-24 12:05:45.583 [http-nio-50103-exec-39] ERROR c.u.f.r.s.i.ExceptionHandlingInterceptor [ExceptionHandlingInterceptor.java:219] Failure during REST processing: java.lang.NullPointerException: Cannot invoke "String.equalsIgnoreCase(String)" because "this.userResourceType" is null
java.lang.NullPointerException: Cannot invoke "String.equalsIgnoreCase(String)" because "this.userResourceType" is null
        at edu.ohsu.cmp.ecp.sds.UserIdentity.requireMatchingIdType(UserIdentity.java:21)
        at java.base/java.util.Optional.ifPresent(Optional.java:178)
        at edu.ohsu.cmp.ecp.sds.UserIdentity.<init>(UserIdentity.java:30)
        at edu.ohsu.cmp.ecp.sds.SupplementalDataStorePermissionsInterceptor.buildUserIdentity(SupplementalDataStorePermissionsInterceptor.java:95)
        at edu.ohsu.cmp.ecp.sds.SupplementalDataStorePermissionsInterceptor.buildUserIdentity(SupplementalDataStorePermissionsInterceptor.java:79)
        at edu.ohsu.cmp.ecp.sds.SupplementalDataStorePermissionsInterceptor.permissionsForPractitionerInPatientContext(SupplementalDataStorePermissionsInterceptor.java:111)
        at edu.ohsu.cmp.ecp.sds.SupplementalDataStorePermissionsInterceptor.permissionsForPractitioner(SupplementalDataStorePermissionsInterceptor.java:100)
        at edu.ohsu.cmp.ecp.sds.SupplementalDataStorePermissionsInterceptor.identifyPermissions(SupplementalDataStorePermissionsInterceptor.java:65)
        at jdk.internal.reflect.GeneratedMethodAccessor98.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:569)
        at ca.uhn.fhir.interceptor.executor.BaseInterceptorService$HookInvoker.invoke(BaseInterceptorService.java:550)
        at ca.uhn.fhir.interceptor.executor.BaseInterceptorService.doCallHooks(BaseInterceptorService.java:287)
        at ca.uhn.fhir.interceptor.executor.BaseInterceptorService.callHooks(BaseInterceptorService.java:275)
        at ca.uhn.fhir.interceptor.executor.BaseInterceptorService.callHooks(BaseInterceptorService.java:63)
        at ca.uhn.fhir.rest.server.method.PageMethodBinding.callPreHandledHooks(PageMethodBinding.java:177)
        at ca.uhn.fhir.rest.server.method.BaseMethodBinding.invokeServerMethod(BaseMethodBinding.java:258)
        at ca.uhn.fhir.rest.server.method.SearchMethodBinding.invokeServer(SearchMethodBinding.java:311)
        at ca.uhn.fhir.rest.server.method.SearchMethodBinding.invokeServer(SearchMethodBinding.java:53)
        at ca.uhn.fhir.rest.server.method.BaseResourceReturningMethodBinding.doInvokeServer(BaseResourceReturningMethodBinding.java:146)
        at ca.uhn.fhir.rest.server.method.BaseResourceReturningMethodBinding.invokeServer(BaseResourceReturningMethodBinding.java:275)
        at ca.uhn.fhir.rest.server.RestfulServer.handleRequest(RestfulServer.java:1190)
        at ca.uhn.fhir.rest.server.RestfulServer.doGet(RestfulServer.java:420)
        at ca.uhn.fhir.rest.server.RestfulServer.service(RestfulServer.java:1923)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:337)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)
        at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)
        at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter.doFilterInternal(BearerTokenAuthenticationFilter.java:142)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:117)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
        at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:112)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:82)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:221)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354)
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1791)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.base/java.lang.Thread.run(Thread.java:840)
timcoffman commented 1 month ago

This is thrown from code in edu.ohsu.cmp.ecp.sds.UserIdentity:

  private void requireMatchingIdType( IIdType id ) {
    if ( !this.userResourceType.equalsIgnoreCase( id.getResourceType() ) )
      ...
  }

This means that the authorized patient id, which is determined from the introspect response, is lacking a resource type.

This would happen if using the introspect endpoint is returning "sub": "abcd-1234" instead of "sub": "Patient/abcd-1234" or "sub": "Practitioner/efgh-5678"

mattStorer commented 1 month ago

@timcoffman yes, that tracks. This is an example of the introspect response for an eCarePlanner-generated access token:

{
    "active": true,
    "scope": "user/CarePlan.read user/CareTeam.read user/Condition.read user/DiagnosticReport.read user/Encounter.read user/Flag.read user/Goal.read user/Immunization.read user/Location.read user/Medication.read user/MedicationRequest.read user/Observation.read user/Organization.read user/Patient.read user/Practitioner.read user/PractitionerRole.read user/Procedure.read user/Provenance.read user/Questionnaire.read user/QuestionnaireResponse.Read user/RelatedPerson.read user/ServiceRequest.read user/Task.read launch/patient",
    "client_id": "7666b9ec-8caa-43bd-8231-2eea4f5d281d",
    "username": "STORER",
    "exp": 1727108173,
    "sub": "https://epicmobile.ohsu.edu/FHIRDEV/api/FHIR/R4/Practitioner/eUNWe-TcUNZJgyQxTiyPyWA3",
    "iss": "https://epicmobile.ohsu.edu/FHIRDEV/oauth2",
    "jti": "D876CC94DDAF4601953E6A1789523056",
    "epic_user_type": "EMP",
    "patient": "edBu5co.Z6y7bjOHAfSfm8hXaEzYfFgw4WKpc.A6WwP83",
    "fhirUser": "https://epicmobile.ohsu.edu/FHIRDEV/api/FHIR/R4/Practitioner/eUNWe-TcUNZJgyQxTiyPyWA3"
}

Note the patient element, which is just the ID part, and contains no resource type.

I think in this case, because "patient" is specified in the element name, that in this case it would be safe to prepend the ID with "Patient/" for use in downstream operations.

Is that doable?

timcoffman commented 1 month ago

OK, that explains it. The same code for identifying linked compartments is used for this purpose, so what you just identified is triggering it. My tests all included a Patient/ prefix.

I've crafted an update, will push it momentarily.

mattStorer commented 1 month ago

nice! I've pulled your update and am building it now

mattStorer commented 1 month ago

just tested, still throwing a 500 error, but the error changed.

new Linkage query response:

{
  "resourceType": "OperationOutcome",
  "issue": [ {
    "severity": "error",
    "code": "processing",
    "diagnostics": "cannot build UserIdentity when basisUserId is missing the resource type (\"eFTHaVbQzCEwOEE97maN2MC2jJi-r8nnkhRh.umMUlz03\")"
  } ]
}

Stack trace:

2024-09-24 13:54:19.890 [http-nio-50103-exec-7] ERROR c.u.f.r.s.i.ExceptionHandlingInterceptor [ExceptionHandlingInterceptor.java:219] Failure during REST processing: java.lang.NullPointerException: cannot build UserIdentity when basisUserId is missing the resource type ("eFTHaVbQzCEwOEE97maN2MC2jJi-r8nnkhRh.umMUlz03")
java.lang.NullPointerException: cannot build UserIdentity when basisUserId is missing the resource type ("eFTHaVbQzCEwOEE97maN2MC2jJi-r8nnkhRh.umMUlz03")
        at java.base/java.util.Objects.requireNonNull(Objects.java:235)
        at edu.ohsu.cmp.ecp.sds.UserIdentity.<init>(UserIdentity.java:29)
        at edu.ohsu.cmp.ecp.sds.SupplementalDataStorePermissionsInterceptor.buildUserIdentity(SupplementalDataStorePermissionsInterceptor.java:95)
        at edu.ohsu.cmp.ecp.sds.SupplementalDataStorePermissionsInterceptor.buildUserIdentity(SupplementalDataStorePermissionsInterceptor.java:79)
        at edu.ohsu.cmp.ecp.sds.SupplementalDataStorePermissionsInterceptor.permissionsForPractitionerInPatientContext(SupplementalDataStorePermissionsInterceptor.java:111)
        at edu.ohsu.cmp.ecp.sds.SupplementalDataStorePermissionsInterceptor.permissionsForPractitioner(SupplementalDataStorePermissionsInterceptor.java:100)
        at edu.ohsu.cmp.ecp.sds.SupplementalDataStorePermissionsInterceptor.identifyPermissions(SupplementalDataStorePermissionsInterceptor.java:65)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:569)
        at ca.uhn.fhir.interceptor.executor.BaseInterceptorService$HookInvoker.invoke(BaseInterceptorService.java:550)
        at ca.uhn.fhir.interceptor.executor.BaseInterceptorService.doCallHooks(BaseInterceptorService.java:287)
        at ca.uhn.fhir.interceptor.executor.BaseInterceptorService.callHooks(BaseInterceptorService.java:275)
        at ca.uhn.fhir.interceptor.executor.BaseInterceptorService.callHooks(BaseInterceptorService.java:63)
        at ca.uhn.fhir.rest.server.method.PageMethodBinding.callPreHandledHooks(PageMethodBinding.java:177)
        at ca.uhn.fhir.rest.server.method.BaseMethodBinding.invokeServerMethod(BaseMethodBinding.java:258)
        at ca.uhn.fhir.rest.server.method.SearchMethodBinding.invokeServer(SearchMethodBinding.java:311)
        at ca.uhn.fhir.rest.server.method.SearchMethodBinding.invokeServer(SearchMethodBinding.java:53)
        at ca.uhn.fhir.rest.server.method.BaseResourceReturningMethodBinding.doInvokeServer(BaseResourceReturningMethodBinding.java:146)
        at ca.uhn.fhir.rest.server.method.BaseResourceReturningMethodBinding.invokeServer(BaseResourceReturningMethodBinding.java:275)
        at ca.uhn.fhir.rest.server.RestfulServer.handleRequest(RestfulServer.java:1190)
        at ca.uhn.fhir.rest.server.RestfulServer.doGet(RestfulServer.java:420)
        at ca.uhn.fhir.rest.server.RestfulServer.service(RestfulServer.java:1923)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:337)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)
        at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)
        at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter.doFilterInternal(BearerTokenAuthenticationFilter.java:142)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:117)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
        at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:112)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:82)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:221)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354)
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1791)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.base/java.lang.Thread.run(Thread.java:840)
mattStorer commented 1 month ago

excellent! Linkage resources are now coming through correctly. however, what's happening now is that 403 Forbidden errors are getting thrown for Goals, Conditions, and QuestionnaireResponses:

image

Goal request: image

Goal response body:

{
  "resourceType": "OperationOutcome",
  "issue": [ {
    "severity": "error",
    "code": "processing",
    "diagnostics": "HAPI-0333: Access denied by rule: no access rules grant permission"
  } ]
}

I confirm that local patient 40182467-621e-42f9-adcc-d4583d4a672b is the correct one for Rose Fhir (who has OHSU POC patient ID eFTHaVbQzCEwOEE97maN2MC2jJi-r8nnkhRh.umMUlz03): image

This is the access token introspect response for the current session - as we can see, the patient element contains Rose Fhir's patient ID eFTHaVbQzCEwOEE97maN2MC2jJi-r8nnkhRh.umMUlz03, which connects via Linkage above to local Patient resource 40182467-621e-42f9-adcc-d4583d4a672b: image

Linkage:

{
  "resourceType": "Linkage",
  "item": [
    {
      "type": "source",
      "resource": {
        "extension": [
          {
            "url": "urn:sds:partition-name",
            "valueUrl": "SDS-LOCAL"
          }
        ],
        "reference": "Patient/40182467-621e-42f9-adcc-d4583d4a672b"
      }
    },
    {
      "type": "alternate",
      "resource": {
        "extension": [
          {
            "url": "urn:sds:partition-name",
            "valueUrl": "https://epicmobile.ohsu.edu/FHIRDEV/api/FHIR/R4"
          }
        ],
        "reference": "Patient/eFTHaVbQzCEwOEE97maN2MC2jJi-r8nnkhRh.umMUlz03"
      }
    }
  ]
}

Thoughts on why this is throwing 403 Forbidden?

mattStorer commented 1 month ago

Testing recent SDS updates, it looks like Linkage queries are now no longer getting Linkage resources for other patients, which is great.

However, it does appear that each Linkage that's queried for, is the same one that comes back -

Linkage 1:

image

Linkage 2:

image

Linkage 3:

image

Linkage 4:

image

I think this may have to do with the SDS returning Linkage resources associated with the OHSU Patient ID and not the Local patient ID, so it may need to be the case that the SDS would need to query for the Local Patient ID first, and then get all Linkages associated with that.

I think that must be what's going on, which is unfortunate because it would require annoying additional custom coding to be embedded in the SDS.

Thoughts?

mattStorer commented 1 month ago

A thought : when processing a Practitioner-based access token as we do in eCarePlanner, maybe it would just involve an extra search for Linkage for that specified ID, grab the source patient ID from that, and then work with that for all downstream operations?

Would that work? It seems that could be a clean translation.

Thoughts?

mattStorer commented 1 month ago

I think I know why we're getting these 403 Forbidden errors!

My thought is that because eCarePlanner is requesting resources for the local Patient ID and getting "access denied" in response - and given what I'm seeing with Linkages above where evidently the only Linkages returned are those associated with the OHSU POC patient ID - it may be that those 403s are a result of the specified local Patient ID being different from the OHSU POC patient ID from the access token, and the SDS not compiling a set of authorized Patient IDs as a result?

How does the SDS operate when it's working with MyCarePlanner and regular Patient-based access tokens?

I'm not sure this is the actual cause, but it sure smells like these things are related.

mattStorer commented 1 month ago

this is fixed!