marcospereirampj / python-keycloak

MIT License
728 stars 303 forks source link

keycloak.exceptions.KeycloakGetError: 404: b'404 page not found\n' #591

Open GuilhemUPSILON opened 2 months ago

GuilhemUPSILON commented 2 months ago

Architecture : I have a keycloak configured behind a reverse proxy (traefik) to the path /auth

requirements.txt

anyio==4.4.0
async-property==0.2.2
authlib==1.3.2
bandit==1.7.9
blinker==1.8.2
certifi==2024.8.30
cffi==1.17.1
charset-normalizer==3.3.2
click==8.1.7
cryptography==43.0.1
deprecation==2.1.0
exceptiongroup==1.2.2
flask==3.0.3
flask-cors==4.0.1
gunicorn==23.0.0
h11==0.14.0
httpcore==1.0.5
httpx==0.27.2
idna==3.8
iniconfig==2.0.0
itsdangerous==2.2.0
jinja2==3.1.4
jwcrypto==1.5.6
markdown-it-py==3.0.0
markupsafe==2.1.5
mdurl==0.1.2
packaging==24.1
pbr==6.0.0
pluggy==1.5.0
pycparser==2.22
pygments==2.18.0
pyjwt==2.9.0
pytest==8.3.2
python-dotenv==1.0.1
python-keycloak==4.3.0
pyyaml==6.0.2
requests==2.32.3
requests-toolbelt==1.0.0
rich==13.7.1
sniffio==1.3.1
stevedore==5.2.0
tomli==2.0.1
typing-extensions==4.12.2
urllib3==2.2.2
werkzeug==3.0.3

I'm trying to follow the docs: https://python-keycloak.readthedocs.io/en/latest/modules/openid_client.html#get-certs

I got this error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/guilhem/UPSILON/23038-TouIST/23038-API/venv/lib/python3.10/site-packages/keycloak/keycloak_openid.py", line 486, in certs
    return raise_error_from_response(data_raw, KeycloakGetError)
  File "/home/guilhem/UPSILON/23038-TouIST/23038-API/venv/lib/python3.10/site-packages/keycloak/exceptions.py", line 192, in raise_error_from_response
    raise error(
keycloak.exceptions.KeycloakGetError: 404: b'404 page not found\n'

Steps to reproduce:

$ python3
Python 3.10.12 (main, Jul 29 2024, 16:56:48) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from keycloak import KeycloakOpenID
>>> keycloak_ = KeycloakOpenID(server_url = "http://localhost/auth", realm_name = "realm", client_id = "client", client_secret_key = "TheSecret")
>>> config_well_known = keycloak_.well_known()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/guilhem/UPSILON/23038-TouIST/23038-API/venv/lib/python3.10/site-packages/keycloak/keycloak_openid.py", line 252, in well_known
    return raise_error_from_response(data_raw, KeycloakGetError)
  File "/home/guilhem/UPSILON/23038-TouIST/23038-API/venv/lib/python3.10/site-packages/keycloak/exceptions.py", line 192, in raise_error_from_response
    raise error(
keycloak.exceptions.KeycloakGetError: 404: b'404 page not found\n'
>>> certs = keycloak_.certs()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/guilhem/UPSILON/23038-TouIST/23038-API/venv/lib/python3.10/site-packages/keycloak/keycloak_openid.py", line 486, in certs
    return raise_error_from_response(data_raw, KeycloakGetError)
  File "/home/guilhem/UPSILON/23038-TouIST/23038-API/venv/lib/python3.10/site-packages/keycloak/exceptions.py", line 192, in raise_error_from_response
    raise error(
keycloak.exceptions.KeycloakGetError: 404: b'404 page not found\n'
>>> 
Output with curl : 
$ curl http://localhost/auth/realms/touist/protocol/openid-connect/certs --silent | jq
{
  "keys": [
...
  ]
}

compose.yaml

services:
  reverse-proxy:
    container_name: touist-reverse-proxy
    image: docker.io/library/traefik:latest
    command: --configFile=/etc/traefik/config.toml

    ports:
      - "0.0.0.0:80:80"
      - "0.0.0.0:443:443"
      - "0.0.0.0:8080:8080"

    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./traefik/:/etc/traefik/:ro"

    security_opt:
      - "label=type:container_runtime_t"
      - "no-new-privileges:true"

    cap_drop:
      - ALL

    cap_add:
      - NET_ADMIN

  keycloak:
    container_name: touist-keycloak
    image: quay.io/keycloak/keycloak:latest

    env_file:
      - keycloak/keycloak.env

    expose:
      - 8080

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.keycloak.entrypoints=web"
      - "traefik.http.routers.keycloak.rule=Host(`localhost`) && PathPrefix(`/auth`)"

    depends_on:
      postgres:
        condition: service_healthy
    command: start --verbose

  postgres:
    container_name: touist-postgres
    image: postgres:latest
    volumes:
      - ./db/data:/var/lib/postgresql/data
    env_file:
      - db/db.env
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 5s
      timeout: 5s
      retries: 5
      start_period: 30s

keycloak.env

KEYCLOAK_LOGLEVEL=DEBUG
KEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=admin

KC_HOSTNAME=http://localhost/auth
KC_HTTP_ENABLED="true"
KC_HTTP_RELATIVE_PATH=/auth

KC_HEALTH_ENABLED="true"

KC_DB=postgres
KC_DB_URL=jdbc:postgresql://postgres/keycloak_db
KC_DB_USERNAME=postgres
KC_DB_PASSWORD=postgres_pwd
jjustin commented 1 month ago

Hello. I am facing the same issue.

I've done some code digging and it seems it's the urljoin that causes the relative path to be stripped. What I've done is suffixed the server_url with /. Here is an example:

$ python3
>>> from urllib.parse import urljoin
>>> urljoin("https://my.keycloak.host/auth", "api/token")
'https://my.keycloak.host/api/token'
>>> urljoin("https://my.keycloak.host/auth/", "api/token")
'https://my.keycloak.host/auth/api/token'

without a / present at the end of the url the relative path is stripped. Adding / fixes that issue.