Captain-P-Goldfish / scim-for-keycloak

a third party module that extends keycloak by SCIM functionality
BSD 3-Clause "New" or "Revised" License
188 stars 48 forks source link

Scim plugin behind reverse proxy that strips a path prefix makes the scim console unaccessible #102

Open benzht opened 9 months ago

benzht commented 9 months ago

When the plugin is deployed with a KC container behind a reverse proxy (I'm using traefik) with a /login path prefix that the reverse proxy uses to select the KC container as target and strips from the URL that is passed to KC, then the plugin is not accessible.

My KC-container is built with these env variables: KC_HOSTNAME_URL=https://www.example.com/login KC_HOSTNAME_ADMIN_URL=https://www.example.com/login KC_HOSTNAME_PATH=/login

Keycloak itself works correctly at https://www.example.com/login/ (showing the landing page) and .../login/admin/master/console/ logging in to the console. The link to the SCIM Administration Console directs to https://www.example.com/login/realms/master/scim/admin/frontend/ but leads to a We are sorry... Page not found from KC.

The KC logs show this error message: keycloak-1 | 2024-02-07 16:19:22,036 INFO [de.captaingoldfish.scim.sdk.keycloak.administration.AdministrationBaseEndpoint] (executor-thread-1) SCIM webadmin backend access was rejected. Only accessible under 'https://www.example.com/login' but 'https://www.example.com/login' was used instead

Everything works correctly when I remove the path prefix, or 'bake it into KC' with KC_HTTP_RELATIVE_PATH=/login, which I prefer not to do.

Captain-P-Goldfish commented 9 months ago

Hi which version did you install exactly? Sorry for the log-message it does not show the URLs correctly. If you deploy the latest Release kc-22-1.5.0-RC1 or kc-21.1.2.2-RC1 you will get an appropriate errormessage.

This happens normally under two different conditions:

  1. reverse-proxy is communicating with keycloak over http and keycloak does not have the property KC_PROXY=edge set.
  2. reverse-proxy is communicating with keycloak over https and keycloak does have the property KC_PROXY=edge set.

The error in the comparison is normally the protocol that it is http instead of https or vice versa.

benzht commented 9 months ago

Thanks for the fast reply,

Plugin version: scim-for-keycloak-kc-23-1.5.0-RC1-enterprise.jar KC 23.0.6 KC is running in edge mode, proxy uses http

Env-vars in the container:

KC_HOSTNAME_STRICT_HTTPS=false
KC_PROXY=edge
KC_HOSTNAME_ADMIN_URL=https://www.example.com/login
KC_DB_USERNAME=keycloak
KC_DB_PASSWORD=password
KC_HOSTNAME_URL=https://www.example.com/login
KC_HOSTNAME_PATH=/login
KC_DB_URL=jdbc:postgresql://postgres:5432/keycloak?ssl=all
KC_HOSTNAME_STRICT=false
KC_HTTP_ENABLED=true

Keycloak startup message:

keycloak-1  | 2024-02-07 19:50:17,961 INFO  [org.keycloak.common.Profile] (main) Preview features enabled: account3, admin-fine-grained-authz, client-secret-rotation, declarative-user-profile, dpop, multi-site, recovery-codes, scripts, token-exchange, update-email
keycloak-1  | 2024-02-07 19:50:19,200 INFO  [org.keycloak.quarkus.runtime.hostname.DefaultHostnameProvider] (main) Hostname settings: Base URL: https://www.example.com/login, Hostname: www.example.com, Strict HTTPS: true, Path: /login, Strict BackChannel: false, Admin URL: https://www.example.com/login, Admin: www.example.com, Port: -1, Proxied: true
keycloak-1  | 2024-02-07 19:50:19,281 INFO  [de.captaingoldfish.scim.sdk.keycloak.EnterpriseLoader] (main)

When navigating the link, the error message is:

keycloak-1 | 2024-02-07 19:51:42,881 INFO [de.captaingoldfish.scim.sdk.keycloak.administration.AdministrationBaseEndpoint] (executor-thread-1) SCIM webadmin backend access was rejected. Only accessible under 'https://www.example.com/login' but 'https://www.example.com/realms/master/scim/admin/frontend/' was used instead

The was used instead url is exactly the one I would expect. The landing page links to https://www.example.com/login/realms/master/scim/admin/frontend/ and the proxy strips the login.

With KC_HTTP_RELATIVE_PATH not set and KC_HOSTNAME_PATH=/login, the plugin should not expect the /login to be there.

/Hartmut

Captain-P-Goldfish commented 9 months ago

I see, what is the problem. I will check later again in the sourcecode if I can fix this without workarounds. Until then I would recommend that you simply adjust the keycloak relative path until then:

KC_RELATIVE_PATH=/login

The context-path is read using the hostname-provider from keycloak itself:

HostnameProvider hostnameProvider = keycloakSession.getProvider(HostnameProvider.class);
String contextPath = hostnameProvider.getContextPath(keycloakUriInfo, UrlType.ADMIN)

So I am not reading the configuration manually. I am just using what keycloak already provides. For this reason I will need to check this in detail. I could try to remove the context-path in such checks. But I would prefer not to.

Is it an option for you to set KC_RELATIVE_PATH?

And I will see that I find a clean solution for this in due time.

benzht commented 9 months ago

Great! I do have a working system that I can go on using :-) This just bit me when I tried to get rid of the kc_relative_path. For the time being I will stick to the current situation. There is also another work-around available with slightly more complex reverse proxy rules exposing /realms/, /resources/, /robots.txt and optionally /js/ of the KC container (as described in the KC documentation Exposed path recommendations).

benzht commented 2 months ago

Hi! Any progress on this (preferably using hostname2)? I'd like to get rid of the kc_relative_path

Captain-P-Goldfish commented 1 month ago

It's documented by keycloak itself here: https://www.keycloak.org/server/reverseproxy Different context-path on reverse proxy

benzht commented 1 month ago

I'm not exactly sure which place you are pointing at. I'm running KC25 now with KC_HOSTNAME=https://${HOST_NAME}/auth and KC_HOSTNAME_ADMIN=https://${HOST_NAME}/auth and the reverse proxy is stripping the /auth prefix. From how I understand it, this simplicity in configuration is one of the major drivers of Keycloak's move to HOSTNAME2. Do I understand you right that for SCIM to work correctly, I have to remove the HOSTNAME's /auth, add KC_RELATIVE_PATH and not strip the prefix in the reverse proxy?

benzht commented 1 month ago

Got it working

And reverse proxy not stripping the /auth from the URL.

It would be nice, though, to have the SCIM plugin to 'understand' the other way of configuring (i.e., without the relative-path and with proxy doing prefix-stripping; the SCIM plugin then has to get it's clues from the path in KC_HOSTNAME(_ADMIN).

Captain-P-Goldfish commented 1 month ago

okay, I just added a new configuration property to make this work. It is also logged during startup:

environment: KC_SPI_REALM_RESTAPI_EXTENSION_SCIM_ADMIN_URL_CHECK = no-context-path
property   :    spi-realm-restapi-extension-scim-admin-url-check = no-context-path
values     : [strict, no-context-path]
default    : strict
description: strict          -> request URL and configured Keycloak URL must match exactly.
             no-context-path -> only http-scheme (http or https), hostname and port need to match the request URL.

I solved it like this because there are a few configuration possibilities that could make the access insecure. Therefore, the check needs to be changed by configuration.

I am going to release this later today