Skip to content

Commit a724bbb

Browse files
Elson9ikethecoderrustyjux
authored
Feature/kc 26 (#251)
* upg keycloak python library * fix tests * fix namespace use * update poetry.lock for gatewayApi * fix test config * f-string fix for logs * Enhace logging for token.py * constructs the JWK URL directly from the same internal KC_SERVER_URL * Update gatewayJobScheduler for Keycloak 26 * fix version mismatch for proxies arg for python-keycloak and httpx * temp set keycloak ssl verify to false for scheduler * Fix 404 when namespace has no Keycloak group * Set verify back to True * Prevent accidental route deletions on Keycloak errors. abort sync and add logging in NamespaceService * Refactor Keycloak integration in gatewayJobScheduler - don't silence errors in namespace.py - raise error if transform_data_by_ns hits an exception - Use a single Keycloak admin instance. - Added Keycloak connection validation in sync_routes function. - add sanity check before syncing - Updated tests to ensure proper mocking of Keycloak interactions. * Revert changes * Use OIDCDiscovery for jwk again * Fix Keycloak realm base URL by adding slash before /realms * Test for Keycloak realm base URL with or without trailing slash * remove deprecated search_in_subgroups * stop using deprecated dev-dependencies --------- Co-authored-by: ikethecoder <ikethecoder@copeconsulting.ca> Co-authored-by: Russell Vinegar <russell.vinegar@gov.bc.ca>
1 parent 49a5189 commit a724bbb

File tree

22 files changed

+840
-539
lines changed

22 files changed

+840
-539
lines changed

microservices/gatewayApi/auth/token.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
import requests
23
import time
34
from authlib.jose import JsonWebToken
@@ -7,18 +8,29 @@
78
from flask import current_app, g
89
from config import Config
910

11+
logger = logging.getLogger(__name__)
12+
13+
14+
def realm_base_url(server_url: str, realm: str) -> str:
15+
"""Build Keycloak realm base URL, normalizing server_url with or without trailing slash."""
16+
return f"{server_url.rstrip('/')}/realms/{realm}"
17+
18+
1019
def OIDCDiscovery(base_url):
1120
conf = Config()
1221

1322
# Fetch the openid metadata so we may know the jwk endpoint uri
1423
server_metadata_url = f"{base_url}/.well-known/openid-configuration"
24+
logger.info(f"Fetching OIDC metadata from: {server_metadata_url}")
1525
server_metadata_r = requests.get(server_metadata_url)
1626
if server_metadata_r.status_code != 200:
1727
raise Exception(
18-
f"Error getting auth server metadata from url: {server_metadata_url}"
19-
+ ", status_code: {server_metadata_r.status_code}"
28+
f"Error getting auth server metadata from url: {server_metadata_url}, "
29+
f"status_code: {server_metadata_r.status_code}, "
30+
f"response: {server_metadata_r.text[:500]}"
2031
)
2132
server_metadata = server_metadata_r.json()
33+
logger.info(f"OIDC discovery succeeded. jwks_uri: {server_metadata.get('jwks_uri')}")
2234
return server_metadata
2335

2436
class OIDCTokenValidator(BearerTokenValidator):
@@ -31,20 +43,23 @@ def __init__(self, token_cls, realm=None):
3143

3244
server_url = conf.data['keycloak']['serverUrl']
3345
realm = conf.data['keycloak']['realm']
34-
baseUrl = "%srealms/%s" % (server_url, realm)
35-
46+
baseUrl = realm_base_url(server_url, realm)
3647
self.aud = conf.data['tokenMatch']['aud']
3748

3849
server_metadata = OIDCDiscovery(baseUrl)
3950

4051
# Fetch the public key for validating Bearer token
41-
jwk_r = requests.get(server_metadata['jwks_uri'])
52+
jwks_uri = server_metadata['jwks_uri']
53+
logger.info(f"Fetching JWK from: {jwks_uri}")
54+
jwk_r = requests.get(jwks_uri)
4255
if jwk_r.status_code != 200:
4356
raise Exception(
44-
f"Error getting jwk from url: {server_metadata['jwks_uri']}"
45-
+ ", status_code: {jwk_r.status_code}"
57+
f"Error getting jwk from url: {jwks_uri}, "
58+
f"status_code: {jwk_r.status_code}, "
59+
f"response: {jwk_r.text[:500]}"
4660
)
4761
self.jwk = jwk_r.json()
62+
logger.info("JWK fetched successfully")
4863

4964
def authenticate_token(self, token_string):
5065
jwt = JsonWebToken(['RS256'])
Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11

22
from flask import current_app as app
3-
from keycloak import KeycloakAdmin
3+
from keycloak import KeycloakAdmin, KeycloakOpenIDConnection
44
from keycloak.exceptions import KeycloakGetError
55

6-
def admin_api():
7-
conf = app.config['keycloak']
6+
# conf = app.config['keycloak']
87

9-
keycloak_admin = KeycloakAdmin(server_url=conf['serverUrl'],
8+
def admin_api(conf):
9+
10+
keycloak_connection = KeycloakOpenIDConnection(server_url=conf['serverUrl'],
1011
username=conf['username'],
1112
password=conf['password'],
1213
realm_name=conf['realm'],
1314
client_id=conf['clientId'],
1415
user_realm_name=conf['userRealm'],
1516
verify=True)
17+
18+
19+
keycloak_admin = KeycloakAdmin(connection=keycloak_connection)
1620
return keycloak_admin

microservices/gatewayApi/config/test.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,14 @@
3131
"kubeApiUser": "username"
3232
},
3333
"compatibilityApiUrl": "http://compatibility-api",
34-
"deckCLI": "deck"
34+
"deckCLI": "deck",
35+
"keycloak": {
36+
"serverUrl": "http://test-keycloak",
37+
"realm": "test-realm",
38+
"clientId": "test-client",
39+
"clientSecret": "test-secret",
40+
"userRealm": "test-user-realm",
41+
"username": "test-user",
42+
"password": "test-password"
43+
}
3544
}

0 commit comments

Comments
 (0)