Stream: ibm
Topic: Connect with Keycloak to validate access tokens
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!
Lee Surprenant (Jan 21 2021 at 17:44):
hi Burak. have you seen https://github.com/IBM/FHIR/issues/1703 yet?
Lee Surprenant (Jan 21 2021 at 17:45):
specifically https://github.com/IBM/FHIR/issues/1703#issuecomment-728132487
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?
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
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
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.
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
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
Mahesh Dabi (Jul 22 2021 at 12:40):
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
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>"]}]}
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