Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

invalid OAuth2 (Keycloak) connection to FHIR #1703

Closed
cerbelding opened this issue Nov 12, 2020 · 3 comments
Closed

invalid OAuth2 (Keycloak) connection to FHIR #1703

cerbelding opened this issue Nov 12, 2020 · 3 comments
Labels
bug Something isn't working

Comments

@cerbelding
Copy link

Describe the bug
After managing to integrate Keycloak into the FHIR-Authentication process, Login via Browser works fine. (Access FHIR-Url, redirect to Keycloak, Login, redirect back to FHIR)
When attempting to access the FHIR-server via command-line, FHIR-client, or Postman, (even with Bearer-Token supplied) one gets informed that FHIR wants to redirect to the Keycloak-Login page.
Is there any configuration on enabling login-token handling?

To Reproduce
Steps to reproduce the behavior:

  1. Integrate Keycloak /OAuth2
  2. Generate/Get valid Token from Keycloak
  3. Access FHIR-BaseURL (.../fhir-server/api/v4)
  4. See error

Expected behavior
Accept the token as Login-Method

Additional context
IBM-FHIR version 4.4.2 (occured already with version 4.3.3)

Configuration in server.xml:

<webApplication contextRoot="fhir-server/api/v4" id="fhir-server-webapp" location="fhir-server.war" name="fhir-server-webapp">
        <classloader commonLibraryRef="fhirSharedLib" privateLibraryRef="configResources,fhirUserLib"/>
        <!-- Include id attributes to make it easier to override this via dropinConfig -->
        <application-bnd>
            <security-role name="FHIRUsers">
                <special-subject type="ALL_AUTHENTICATED_USERS" />
            </security-role>
        </application-bnd>
    </webApplication>

Configuration of oauthResourceServer.xml:

<server description="fhir-server">

    <!-- Enable features -->
    <featureManager>
        <feature>openidConnectClient-1.0</feature>
    </featureManager>
    
    <!-- the variable `id` equals `clientId`, but can't be auto-replaced by environment variables. Instead, a `sed`-script within `docker-compose.yml` replaces it's content. -->
    <openidConnectClient id="${id}"
                         clientId="${keycloak_client_id}"
                         signatureAlgorithm="RS256"
                         discoveryEndpointUrl="${keycloak_url}/auth/realms/${keycloak_realm_name}/.well-known/openid-configuration"/>
    <authFilter id="filter">
        <requestUrl urlPattern="/fhir-server"/>
        <requestUrl urlPattern="/fhir-bulkimportexport-webapp"/>
    </authFilter>
</server>

Keycloak settings:
grafik

@cerbelding cerbelding added the bug Something isn't working label Nov 12, 2020
@cerbelding
Copy link
Author

possibly related to #1546 & #1672

@lmsurpre
Copy link
Member

lmsurpre commented Nov 12, 2020

<special-subject type="ALL_AUTHENTICATED_USERS" />

I'm not sure if its your issue or not, but I've had troubles with using this special-subject together with the JAX-RS security annotations I added to our REST layer. I opened #1020 and I'm waiting for a fix from the OpenLiberty project.

Its also worth mentioning that I've moved to the use of the liberty mpJwt feature for supporting SMART app launch with Keycloak.
Here's a configDropin I've had some luck with:

<server>
    <featureManager>
        <!-- mpJwt-1.1 is already enabled in the default server.xml, but it doesn't hurt to repeat it here -->
        <feature>mpJwt-1.1</feature>
    </featureManager>

    <!-- Override the application-bnd binding of the main webapp -->
    <webApplication contextRoot="fhir-server/api/v4" id="fhir-server-webapp" location="fhir-server.war" name="fhir-server-webapp">
        <application-bnd id="bind">
            <security-role id="users" name="FHIRUsers">
                <group id="usersGroup" access-id="group:https://host/auth/realms/${env.KEYCLOAK_REALM}/fhirUser"/>
            </security-role>
        </application-bnd>
    </webApplication>

    <!-- The MP JWT configuration that injects the caller's JWT into a
         ResourceScoped bean for inspection. -->
    <mpJwt id="jwtConsumer"
           jwksUri="http://host/auth/realms/${env.KEYCLOAK_REALM}/protocol/openid-connect/certs"
           audiences="https://host/fhir-server/api/v4"
           userNameAttribute="sub"
           groupNameAttribute="group"
           issuer="https://host/auth/realms/${env.KEYCLOAK_REALM}"
           signatureAlgorithm="RS256"
           authFilterRef="filter"/>

    <authFilter id="filter">
        <requestUrl urlPattern="/fhir-server" />
    </authFilter>
</server>

I hope to document this better when I get to #1546

@cerbelding
Copy link
Author

cerbelding commented Nov 16, 2020

Final Report

Thanks to @lmsurpre's help via FHIR Chat, i managed to solve my problem.
For all of you, who are facing the same problem, I will post my working configuration:

1. FHIR-Server Configuration:

You have to modify/create the following files and place them within the specified sub-directory of your fhir-server folder.
In case you're running your FHIR-Server via Docker, please make sure to mount the modified files to the correct location in your container.

1.1 fhir-server/configDropins/overrides/keycloakRP.xml

<server>
    <featureManager>
        <!-- mpJwt-1.1 is already enabled in the default server.xml, but it doesn't hurt to repeat it here -->
        <feature>mpJwt-1.1</feature>
    </featureManager>

    <!-- Override the application-bnd binding of the main webapp -->
    <webApplication contextRoot="fhir-server/api/v4" id="fhir-server-webapp" location="fhir-server.war" name="fhir-server-webapp">
        <application-bnd id="bind">
            <security-role id="users" name="FHIRUsers">
                <group id="usersGroup" access-id="group:${keycloak_url}/auth/realms/${keycloak_realm_name}/${keycloak_user_group}"/>
            </security-role>
        </application-bnd>
    </webApplication>

    <!-- The MP JWT configuration that injects the caller's JWT into a
         ResourceScoped bean for inspection. -->
    <mpJwt id="jwtConsumer"
           jwksUri="${keycloak_url}/auth/realms/${keycloak_realm_name}/protocol/openid-connect/certs"
           audiences="${fhir_https_url}:${fhir_https_port}/fhir-server/api/v4"
           userNameAttribute="sub"
           groupNameAttribute="group"
           issuer="${keycloak_url}/auth/realms/${keycloak_realm_name}"
           signatureAlgorithm="RS256"
           authFilterRef="filter"/>

    <authFilter id="filter">
        <requestUrl urlPattern="/fhir-server" />
    </authFilter>
</server>

1.2 fhir-server/configDropins/defaults/oauthResourceServer.xml

<server description="fhir-server">

    <!-- Enable features -->
    <featureManager>
        <feature>openidConnectClient-1.0</feature>
    </featureManager>
    
    <!-- the variable `id` equals `clientId`, but can't be auto-replaced by environment variables. Instead, a `sed`-script within `docker-compose.yml` replaces it's content. -->
    <openidConnectClient id="${id}"
                         clientId="${keycloak_client_id}"
                         clientSecret="${keycloak_client_secret}"
                         inboundPropagation="supported"
                         signatureAlgorithm="RS256"
                         discoveryEndpointUrl="${keycloak_url}/auth/realms/${keycloak_realm_name}/.well-known/openid-configuration"/>
    <authFilter id="filter">
        <requestUrl urlPattern="/fhir-server"/>
    </authFilter>
</server>

1.3 server.xml

[...]
    <webApplication contextRoot="fhir-server/api/v4" id="fhir-server-webapp" location="fhir-server.war" name="fhir-server-webapp">
        <classloader commonLibraryRef="fhirSharedLib" privateLibraryRef="configResources,fhirUserLib"/>
        <!-- Include id attributes to make it easier to override this via dropinConfig -->
        <application-bnd>
            <security-role name="FHIRUsers">
                <special-subject type="ALL_AUTHENTICATED_USERS" />
            </security-role>
        </application-bnd>
    </webApplication>

[...]

<!-- this part seems to be obsolete, as BasicAuth isn't used when oAuth2is enabled -->
    <basicRegistry id="basic" realm="BasicRealm">
        <user name="${fhir_admin_username}" password="${fhir_admin_password}"/>
        <user name="${keycloak_user_username}" password="${keycloak_user_password"/>
        <group name="FHIRUsers">
        </group>
        <group name="clientAdministrator">
            <member name="${fhir_admin_username}"/>
        </group>
    </basicRegistry>
[...]

2. Keycloak Configuration:

  • Add a realm where only Name needs to be set

  • Create a keycloak client as specified below with FHIR_SERVER_URL and CLIENT_ID replaced by their actual values

    Variable Value
    Client ID CLIENT_ID
    Client Protocol openid-connect
    Root URL FHIR_SERVER_URL/fhir-server/api/v4
  • Make sure, the client configuration matches the following:
    (all variables that are not mentioned here, are optional / irrelevant for our purpose)

    Variable Value
    Client ID CLIENT_ID
    Access type confidential
    Direct Access Grants Enabled ON
    Service Accounts Enabled ON
    Authorization Enabled OFF
    Root URL FHIR_SERVER_URL/fhir-server/api/v4
    Valid Redirect URLs FHIR_SERVER_URL/oidcclient/redirect/CLIENT_ID
  • Switch to Tab "Credentials" and save the Client Secret as displayed. (or copy/paste it directly to your .env-File)

  • Switch to Tab "Mappers", click "Create" and create a mapper as follows:

    Variable Value
    Mapper Type Audience
    Included Client Audience leave empty
    Included Custom Audience FHIR_SERVER_URL/fhir-server/api/v4
    Add to ID token OFF
    Add to access token ON
    This mapper is used by mpJwt-component of the FHIR-Server to map requests that are authenticated using user-credentials. (Keycloak users of a given group)

Client Scope:

  • open section "Client Scopes"

  • create client scope CLIENT ID with default settings

  • switch to tab "Mappers", create new Mapper:

    Variable Value
    Mapper Type Audience
    Included Client Audience CLIENT ID
    Included Custom Audience leave empty
    Add to ID token OFF
    Add to access token ON
    This mapper is used by openidConnectClient-component of the FHIR-Server to map requests that are authenticated using ClientID & Secret. (e.g. Client-to-Client requests)
  • make sure the created client scope is added to the client's client scopes:
    Section "Client", edit CLIENT ID, Tab "Client Scopes",
    assign client scope to default client scopes)

User Management:

  • add existing Keycloak-Users to realm (& client), assign necessary permissions (e.g. for realm/client administration)
  • Optional: create users where only Username and Password need to be set. (e.g. for automated CLI/API usage)
  • create User Group fhirUser
  • add all relevant users to group fhirUser

Only registered users or clients providing ClientID&Client Secret are allowed to make API calls or access the FHIR-Server via Browser.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants