FHIR Chat · Connect with Keycloak to validate access tokens · ibm

Stream: ibm

Topic: Connect with Keycloak to validate access tokens


view this post on Zulip Burak Şentuna (Jan 21 2021 at 17:42):

Hi all, i am having an issue with connecting the IBM/FHIR project to an external keycloak auth server to validate access tokens which are generated by the external keycloak server. I just enabled oauth in fhir-server-config.json file and set the auth server endpoints but i am not sure which files should i modify to connect the keycloak server from the IBM/FHIR project and validate tokens successfully. Is there any documentation, blog post etc. about it or can somebody guide me about the issue? Thanks for your support!

view this post on Zulip Lee Surprenant (Jan 21 2021 at 17:44):

hi Burak. have you seen https://github.com/IBM/FHIR/issues/1703 yet?

view this post on Zulip Lee Surprenant (Jan 21 2021 at 17:45):

specifically https://github.com/IBM/FHIR/issues/1703#issuecomment-728132487

view this post on Zulip Burak Şentuna (Jan 21 2021 at 17:50):

yeah, i've implemented all the steps but i got 403 Forbidden error always and there is no log about it. Is there any way to display more detailed logs?

view this post on Zulip Lee Surprenant (Jan 21 2021 at 17:53):

one scenario where I've found the logs lacking (from our underlying app server) is if you have not properly configured the usersGroup. not sure if thats your issue or not, but you could double-check your server.xml / configDropins

view this post on Zulip Lee Surprenant (Jan 21 2021 at 17:53):

for example, see https://github.com/IBM/FHIR/blob/master/fhir-server/liberty-config/configDropins/disabled/keycloakRP.xml#L13

view this post on Zulip Lee Surprenant (Jan 21 2021 at 17:56):

specifically, if you use this pattern, liberty will look in the JWT access token for the value of whatever you've configured as the groupNameAttribute, then append that to the issuer and use that as the access-id in that group field.

view this post on Zulip Burak Şentuna (Jan 21 2021 at 18:08):

Thanks Lee! Let me check all the configuration and i will inform you about the result. Thanks for your support

view this post on Zulip Mahesh Dabi (Jul 22 2021 at 05:39):

Hi Burak

Do you have any sample token of Keycloak? We are trying to enable smart-fhir but it is not honoring scopes given in config file.

thanks
mahesh

view this post on Zulip Mahesh Dabi (Jul 22 2021 at 12:40):

trace.log

Here is detailed log where trace is enabled. We have done change in config file and dropped the Smart Jar with exactly same version as FHIR server (4.8.3) in userlib. Still it is not honoring scopes. Do you get any clue from logs?

Mahesh

view this post on Zulip Mahesh Dabi (Jul 22 2021 at 14:12):

Hi

Seems that we are getting there. Please ignore all previous messages. Now we are able to hit the URL which is denying scope properly. Here is error message. So what scope we can give so that we can create patients?

[7/22/21, 14:07:19:605 UTC] 0000001f AuthzPolicyEn 1 write permission for 'Patient/5cbc121b-cd71-4428-b8b7-31e53eba8184' is not granted by any of the provided scopes: [patient/Medication.read, patient/AllergyIntolerance.read, patient/CarePlan.read, patient/CareTeam.read, patient/Condition.read, patient/Device.read, patient/DiagnosticReport.read, patient/DocumentReference.read, patient/Encounter.read, patient/Goal.read, patient/Immunization.read, patient/Location.read, patient/MedicationRequest.read, patient/Observation.read, patient/Organization.read, patient/Patient.read, patient/Practitioner.read, patient/Procedure.read, patient/Provenance.read, patient/Patient.write, user/Patient.write, user/., patient/.] with context id(s): [17ab437f80b-f1907e67-e141-467c-b3d9-c3f8ebd867be]
[7/22/21, 14:07:19:605 UTC] 0000001f FHIRUserTrans 1 Marking transaction for rollback.
[7/22/21, 14:07:19:605 UTC] 0000001f FHIRUserTrans 1 Rolling back transaction on current thread...
[7/22/21, 14:07:19:606 UTC] 0000001f CacheTransact I Transaction failed - afterCompletion(status = 4)
[7/22/21, 14:07:19:606 UTC] 0000001f FHIRPersisten 1 Transaction rolled back - clearing local maps
[7/22/21, 14:07:19:606 UTC] 0000001f FHIRResource 1 Requested interaction is not permitted by any of the passed scopes.
com.ibm.fhir.persistence.interceptor.FHIRPersistenceInterceptorException: Requested interaction is not permitted by any of the passed scopes. [probeId=ac-1e-0-b2-0895b081-94c8-44d2-9a58-4b80224bf722]
at com.ibm.fhir.smart.AuthzPolicyEnforcementPersistenceInterceptor.enforce(AuthzPolicyEnforcementPersistenceInterceptor.java:374)
at com.ibm.fhir.smart.AuthzPolicyEnforcementPersistenceInterceptor.beforeCreate(AuthzPolicyEnforcementPersistenceInterceptor.java:178)
at com.ibm.fhir.persistence.interceptor.impl.FHIRPersistenceInterceptorMgr.fireBeforeCreateEvent(FHIRPersistenceInterceptorMgr.java:91)
at com.ibm.fhir.server.util.FHIRRestHelper.doCreate(FHIRRestHelper.java:265)
at com.ibm.fhir.server.operation.spi.FHIRResourceHelpers.doCreate(FHIRResourceHelpers.java:46)
at com.ibm.fhir.server.resources.Create.create(Create.java:74)
at com.ibm.fhir.server.resources.Create$Proxy$_$$_WeldClientProxy.create(Unknown Source)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.ibm.ws.jaxrs20.cdi.component.JaxRsFactoryImplicitBeanCDICustomizer.serviceInvoke(JaxRsFactoryImplicitBeanCDICustomizer.java:342)
at com.ibm.ws.jaxrs20.server.LibertyJaxRsServerFactoryBean.performInvocation(LibertyJaxRsServerFactoryBean.java:641)
at com.ibm.ws.jaxrs20.server.LibertyJaxRsInvoker.performInvocation(LibertyJaxRsInvoker.java:160)
at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:101)
at com.ibm.ws.jaxrs20.server.LibertyJaxRsInvoker.invoke(LibertyJaxRsInvoker.java:273)
at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:213)
at com.ibm.ws.jaxrs20.server.LibertyJaxRsInvoker.invoke(LibertyJaxRsInvoker.java:444)
at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:112)
at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:59)
at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:96)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:123)
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:274)
at com.ibm.ws.jaxrs20.endpoint.AbstractJaxRsWebEndpoint.invoke(AbstractJaxRsWebEndpoint.java:137)
at com.ibm.websphere.jaxrs.server.IBMRestServlet.handleRequest(IBMRestServlet.java:146)
at com.ibm.websphere.jaxrs.server.IBMRestServlet.doPost(IBMRestServlet.java:104)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:706)
at com.ibm.websphere.jaxrs.server.IBMRestServlet.service(IBMRestServlet.java:96)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1258)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:746)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:443)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.invokeTarget(WebAppFilterChain.java:183)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:94)
at com.ibm.fhir.server.filter.rest.FHIRRestServletFilter.doFilter(FHIRRestServletFilter.java:155)
at javax.servlet.http.HttpFilter.doFilter(HttpFilter.java:127)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:197)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:91)
at com.ibm.ws.security.jaspi.JaspiServletFilter.doFilter(JaspiServletFilter.java:56)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:197)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:91)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:1002)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1140)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1011)
at com.ibm.ws.webcontainer.servlet.CacheServletWrapper.handleRequest(CacheServletWrapper.java:75)
at com.ibm.ws.webcontainer40.servlet.CacheServletWrapper40.handleRequest(CacheServletWrapper40.java:85)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:938)
at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost$2.run(DynamicVirtualHost.java:279)
at com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink$TaskWrapper.run(HttpDispatcherLink.java:1159)
at com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink.wrapHandlerAndExecute(HttpDispatcherLink.java:428)
at com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink.ready(HttpDispatcherLink.java:387)
at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:566)
at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.handleNewRequest(HttpInboundLink.java:500)
at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.processRequest(HttpInboundLink.java:360)
at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.ready(HttpInboundLink.java:327)
at com.ibm.ws.tcpchannel.internal.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:167)
at com.ibm.ws.tcpchannel.internal.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:75)
at com.ibm.ws.tcpchannel.internal.WorkQueueManager.requestComplete(WorkQueueManager.java:504)
at com.ibm.ws.tcpchannel.internal.WorkQueueManager.attemptIO(WorkQueueManager.java:574)
at com.ibm.ws.tcpchannel.internal.WorkQueueManager.workerRun(WorkQueueManager.java:958)
at com.ibm.ws.tcpchannel.internal.WorkQueueManager$Worker.run(WorkQueueManager.java:1047)
at com.ibm.ws.threading.internal.ExecutorServiceImpl$RunnableWrapper.run(ExecutorServiceImpl.java:238)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:829)

[7/22/21, 14:07:19:607 UTC] 0000001f FHIRResource 1
OperationOutcome:
{"resourceType":"OperationOutcome","id":"ac-1e-0-b2-0895b081-94c8-44d2-9a58-4b80224bf722","issue":[{"severity":"fatal","code":"forbidden","details":{"text":"Requested interaction is not permitted by any of the passed scopes."},"expression":["<empty>"]}]}

view this post on Zulip Lee Surprenant (Aug 02 2021 at 20:05):

Hi Mahesh, I'm back from vacation now. Glad to hear you found some success. The way the fhir-smart interceptor is currently designed, I think it would only allow a user to create resources to which they would have access.
For example, a user bearing a token with patient_id = 17ab437f80b-f1907e67-e141-467c-b3d9-c3f8ebd867be that includes scope patient/Patient.write would ONLY be able to create a Patient resource by that same id.
However, even then, its a case that will require some testing because most of the SMART use cases we've dealt with to date are read-only (i.e. the server is loaded some other way...typically a second instance that is not exposed externally with a different auth strategy).


Last updated: Apr 12 2022 at 19:14 UTC