diff --git a/src/oidc_test/auth_utils.py b/src/oidc_test/auth_utils.py index 33ca582..4c3b98c 100644 --- a/src/oidc_test/auth_utils.py +++ b/src/oidc_test/auth_utils.py @@ -25,8 +25,8 @@ oidc_providers_settings: dict[str, OIDCProvider] = dict( oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") -def fetch_token(name, request): - breakpoint() +async def fetch_token(name, request): + logger.warn("TODO: fetch_token") ... # if name in oidc_providers: # model = OAuth2Token @@ -37,8 +37,8 @@ def fetch_token(name, request): # return token.to_token() -def update_token(*args, **kwargs): - breakpoint() +async def update_token(*args, **kwargs): + logger.warn("TODO: update_token") ... @@ -211,7 +211,8 @@ async def get_user_from_token( ) try: user = await db.get_user(user_id) - user.access_token = payload + if user.access_token != token: + user.access_token = token except UserNotInDB: logger.info( f"User {user_id} not found in DB, creating it (real apps can behave differently" @@ -221,6 +222,6 @@ async def get_user_from_token( user_info=payload, oidc_provider=getattr(authlib_oauth, auth_provider_id), user_info_from_endpoint={}, - access_token=payload, + access_token=token, ) return user diff --git a/src/oidc_test/database.py b/src/oidc_test/database.py index b2cf1b9..1b682ef 100644 --- a/src/oidc_test/database.py +++ b/src/oidc_test/database.py @@ -30,7 +30,7 @@ class Database: user_info: dict, oidc_provider: StarletteOAuth2App, user_info_from_endpoint: dict, - access_token: dict, + access_token: str, ) -> User: user = User.from_auth(userinfo=user_info, oidc_provider=oidc_provider) user.access_token = access_token diff --git a/src/oidc_test/main.py b/src/oidc_test/main.py index ef19245..3d95009 100644 --- a/src/oidc_test/main.py +++ b/src/oidc_test/main.py @@ -200,7 +200,7 @@ async def auth(request: Request, oidc_provider_id: str) -> RedirectResponse: user_info=userinfo, oidc_provider=oidc_provider, user_info_from_endpoint=user_info_from_endpoint, - access_token=access_token, + access_token=token["access_token"], ) # Add the id_token to the session request.session["token"] = token["id_token"] @@ -229,7 +229,7 @@ async def account( raise HTTPException( status.HTTP_406_NOT_ACCEPTABLE, detail="No oidc provider settings" ) - return RedirectResponse(f"{oidc_provider_settings.account_url}") + return RedirectResponse(f"{oidc_provider_settings.account_url_template}") @app.get("/logout") @@ -243,7 +243,9 @@ async def logout( if ( provider_logout_uri := oidc_provider.server_metadata.get("end_session_endpoint") ) is None: - logger.warn(f"Cannot find end_session_endpoint for provider {provider.name}") + logger.warn( + f"Cannot find end_session_endpoint for provider {oidc_provider.name}" + ) return RedirectResponse(request.url_for("non_compliant_logout")) post_logout_uri = request.url_for("home") if (token := await db.get_token(request.session.pop("token", None))) is None: diff --git a/src/oidc_test/models.py b/src/oidc_test/models.py index 542a9c4..db5d6ad 100644 --- a/src/oidc_test/models.py +++ b/src/oidc_test/models.py @@ -25,14 +25,14 @@ class UserBase(SQLModel, extra="ignore"): class User(UserBase): - model_config = ConfigDict(arbitrary_types_allowed=True) + model_config = ConfigDict(arbitrary_types_allowed=True) # type:ignore sub: str = Field( description="""subject id of the user given by the oidc provider, also the key for the database 'table'""", ) userinfo: dict = {} - access_token: dict = {} + access_token: str | None = None oidc_provider: StarletteOAuth2App | None = None @classmethod @@ -54,5 +54,15 @@ class User(UserBase): def has_scope(self, scope: str) -> bool: """Check if the scope is present in user info or access token""" info_scopes = self.userinfo.get("scope", "").split(" ") - access_token_scopes = self.access_token.get("scope", "").split(" ") + access_token_scopes = self.access_token_parsed().get("scope", "").split(" ") return scope in set(info_scopes + access_token_scopes) + + def access_token_parsed(self): + assert self.access_token is not None + assert self.oidc_provider is not None + assert self.oidc_provider.name is not None + from .auth_utils import oidc_providers_settings + + return oidc_providers_settings[self.oidc_provider.name].decode( + self.access_token + ) diff --git a/src/oidc_test/static/styles.css b/src/oidc_test/static/styles.css index cc84736..4552ca0 100644 --- a/src/oidc_test/static/styles.css +++ b/src/oidc_test/static/styles.css @@ -3,9 +3,9 @@ body { background-color: floralwhite; margin: 0; font-family: system-ui; + text-align: center; } h1 { - text-align: center; background-color: #f7c7867d; margin: 0 0 0.2em 0; box-shadow: 0px 0.2em 0.2em #f7c7867d; @@ -21,9 +21,6 @@ hr { .hidden { display: none; } -.center { - text-align: center; -} .content { width: 100%; display: flex; @@ -55,7 +52,6 @@ hr { border: 2px solid darkkhaki; padding: 3px 6px; text-decoration: none; - text-align: center; color: black; } .user-info a.logout:hover { @@ -70,7 +66,6 @@ hr { margin: 0; } .debug-auth p { - text-align: center; border-bottom: 1px solid black; } .debug-auth ul { @@ -101,16 +96,24 @@ hr { .hasResponseStatus.status-503 { background-color: #ffA88050; } -.role { + +.role, .scope { padding: 3px 6px; - background-color: #44228840; + margin: 3px; border-radius: 6px; } +.role { + background-color: #44228840; +} + +.scope { + background-color: #8888FF80; +} + /* For home */ .login-box { - text-align: center; background-color: antiquewhite; margin: 0.5em auto; width: fit-content; @@ -137,7 +140,6 @@ hr { max-height: 2em; } .providers .provider .link div { - text-align: center; background-color: #f7c7867d; border-radius: 8px; padding: 6px; @@ -152,13 +154,11 @@ hr { } .providers .error { padding: 3px 6px; - text-align: center; font-weight: bold; flex: 1 1 auto; } .content .links-to-check { display: flex; - text-align: center; justify-content: center; gap: 0.5em; flex-flow: wrap; diff --git a/src/oidc_test/static/utils.js b/src/oidc_test/static/utils.js index 6b40d3d..142fa6e 100644 --- a/src/oidc_test/static/utils.js +++ b/src/oidc_test/static/utils.js @@ -17,3 +17,24 @@ function checkPerms(className) { Array.from(elem.children).forEach(elem => checkHref(elem)) ) } + +async function get_resource(id, token, authProvider) { + //if (!keycloak.keycloak) { return } + const resp = await fetch("resource/" + id, { + method: "GET", + headers: new Headers({ + "Content-type": "application/json", + "Authorization": `Bearer ${token}`, + "auth_provider": authProvider, + }), + }) + /* + resource.value = resp['data'] + msg.value = "" + } + ).catch ( + err => msg.value = err + ) +*/ + console.log(await resp.json()) +} diff --git a/src/oidc_test/templates/home.html b/src/oidc_test/templates/home.html index c062101..bba2f2a 100644 --- a/src/oidc_test/templates/home.html +++ b/src/oidc_test/templates/home.html @@ -30,6 +30,10 @@ {% endif %}
{{ user.email }}
+
+ Provider: + {{ oidc_provider_settings.name }} +
{% if user.roles %}
Roles: @@ -38,17 +42,43 @@ {% endfor %}
{% endif %} -
- Provider: - {{ oidc_provider_settings.name }} -
+ {% if user.access_token.scope %} +
+ Scopes: + {% for scope in user.access_token.scope.split(' ') %} + {{ scope }} + {% endfor %} +
+ {% endif %} {% if oidc_provider_settings.account_url_template %} - + {% endif %} {% endif %}
+

+ Fetch resources from the resource server with your authentication token: +

+
+ + +
+
+
+
+
{{ key }}
+
{{ value }}
+
{{ value }}
+
+
+
+
{{ msg }}
+

These links should get different response codes depending on the authorization: