From 14d219eef7677d7effbf9ddf3c17aafc4b9d4815 Mon Sep 17 00:00:00 2001 From: TuxCoder Date: Sat, 18 Mar 2023 12:00:40 +0100 Subject: [PATCH] more oauth2 fixes --- lenticular_cloud/hydra.py | 4 ++-- ...0518a8625b50_remove_ldap_add_rest_to_db.py | 7 +++--- lenticular_cloud/model.py | 2 +- lenticular_cloud/translations/__init__.py | 23 ++++++++++++++++--- lenticular_cloud/views/admin.py | 11 +++++++-- lenticular_cloud/views/oauth2.py | 3 ++- .../api/o_auth_2/list_o_auth_2_clients.py | 12 ++++++---- 7 files changed, 45 insertions(+), 17 deletions(-) diff --git a/lenticular_cloud/hydra.py b/lenticular_cloud/hydra.py index 6c8be47..9c4d401 100644 --- a/lenticular_cloud/hydra.py +++ b/lenticular_cloud/hydra.py @@ -6,8 +6,8 @@ from typing import Optional class HydraService: def __init__(self): - self._hydra_client = None # type: Optional[Client] - self._oauth_client = None # type: Optional[Client] + self._hydra_client: Optional[Client] = None + self._oauth_client: Optional[Client] = None @property def hydra_client(self) -> Client: diff --git a/lenticular_cloud/migrations/versions/0518a8625b50_remove_ldap_add_rest_to_db.py b/lenticular_cloud/migrations/versions/0518a8625b50_remove_ldap_add_rest_to_db.py index f209d95..993e456 100644 --- a/lenticular_cloud/migrations/versions/0518a8625b50_remove_ldap_add_rest_to_db.py +++ b/lenticular_cloud/migrations/versions/0518a8625b50_remove_ldap_add_rest_to_db.py @@ -9,9 +9,6 @@ from alembic import op import sqlalchemy as sa from flask import current_app from lenticular_cloud.model import User -from ldap3_orm import AttrDef, EntryBase as _EntryBase, ObjectDef, EntryType -from ldap3_orm import Reader -from ldap3 import Connection, Server, ALL import logging @@ -23,6 +20,10 @@ depends_on = None def upgrade(): + from ldap3_orm import AttrDef, EntryBase as _EntryBase, ObjectDef, EntryType + from ldap3_orm import Reader + from ldap3 import Connection, Server, ALL + app = current_app server = Server(app.config['LDAP_URL'], get_info=ALL) ldap_conn = Connection(server, app.config['LDAP_BIND_DN'], app.config['LDAP_BIND_PW'], auto_bind=True) # TODO auto_bind read docu diff --git a/lenticular_cloud/model.py b/lenticular_cloud/model.py index 8f911f7..fb1eafe 100644 --- a/lenticular_cloud/model.py +++ b/lenticular_cloud/model.py @@ -11,7 +11,7 @@ import logging import crypt import secrets import string -from flask_sqlalchemy import SQLAlchemy, orm +from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate from datetime import datetime import uuid diff --git a/lenticular_cloud/translations/__init__.py b/lenticular_cloud/translations/__init__.py index 69895e2..21ffbdb 100644 --- a/lenticular_cloud/translations/__init__.py +++ b/lenticular_cloud/translations/__init__.py @@ -3,16 +3,15 @@ from flask_babel import Babel from flask_login import current_user from typing import Optional from lenticular_cloud.model import db, User +from importlib.metadata import version LANGUAGES = { 'en': 'English', 'de': 'Deutsch' } -babel = Babel() -@babel.localeselector def get_locale() -> str: # if a user is logged in, use the locale from the user settings user = current_user # type: Optional[User] @@ -34,13 +33,31 @@ def get_locale() -> str: # example. The best match wins. return request.accept_languages.best_match(['de']) -@babel.timezoneselector def get_timezone() -> Optional[str]: # user = getattr(g, 'user', None) # if user is not None: # return user.timezone return None +flask_babel_version = version('flask_babel') +kwargs = {} +if flask_babel_version >= "3.0.0": + kwargs = { + 'locale_selector': get_locale, + #'timezone_selector': get_timezone, + } + +babel = Babel(**kwargs) + +if flask_babel_version < "3.0.0": + @babel.localeselector + def _get_locale() -> str: + return get_locale() + + @babel.timezoneselector + def _get_timezone() -> Optional[str]: + return get_timezone() + def init_babel(app: Flask) -> None: babel.init_app(app) diff --git a/lenticular_cloud/views/admin.py b/lenticular_cloud/views/admin.py index 9678dec..e7fda1f 100644 --- a/lenticular_cloud/views/admin.py +++ b/lenticular_cloud/views/admin.py @@ -8,8 +8,10 @@ from oauthlib.oauth2.rfc6749.errors import TokenExpiredError from authlib.integrations.base_client.errors import InvalidTokenError from ory_hydra_client.api.o_auth_2 import list_o_auth_2_clients, get_o_auth_2_client, set_o_auth_2_client, create_o_auth_2_client from ory_hydra_client.models import OAuth20Client, GenericError -from typing import Optional +from typing import Optional, List from collections.abc import Iterable +from http import HTTPStatus +import httpx import logging from ..model import db, User @@ -77,7 +79,12 @@ def registration_accept(registration_id) -> ResponseReturnValue: @admin_views.route('/clients') async def clients() -> ResponseReturnValue: - clients = await list_o_auth_2_clients.asyncio_detailed(_client=hydra_service.hydra_client) + response = await list_o_auth_2_clients.asyncio_detailed(_client=hydra_service.hydra_client) + clients = response.parsed + if clients is None: + logger.error(f"could not fetch client list response {response}") + return 'internal error', 500 + logger.error(f'{clients}') return render_template('admin/clients.html.j2', clients=clients) @admin_views.route('/client/', methods=['GET', 'POST']) diff --git a/lenticular_cloud/views/oauth2.py b/lenticular_cloud/views/oauth2.py index acdb103..696cb67 100644 --- a/lenticular_cloud/views/oauth2.py +++ b/lenticular_cloud/views/oauth2.py @@ -92,11 +92,12 @@ def init_login_manager(app: Flask) -> None: name="custom", client_id=app.config['OAUTH_ID'], client_secret=app.config['OAUTH_SECRET'], + server_metadata_url=f'{base_url}/.well-known/openid-configuration', access_token_url=f"{base_url}/oauth2/token", authorize_url=f"{base_url}/oauth2/auth", api_base_url=base_url, - client_kwargs={'scope': ' '.join(['openid', 'profile', 'manage'])} + client_kwargs={'scope': ' '.join(['openid', 'profile', 'manage'])}, ) oauth2.init_app(app) login_manager.init_app(app) diff --git a/libs/ory-hydra-client/ory_hydra_client/api/o_auth_2/list_o_auth_2_clients.py b/libs/ory-hydra-client/ory_hydra_client/api/o_auth_2/list_o_auth_2_clients.py index b911d17..e03aa5a 100644 --- a/libs/ory-hydra-client/ory_hydra_client/api/o_auth_2/list_o_auth_2_clients.py +++ b/libs/ory-hydra-client/ory_hydra_client/api/o_auth_2/list_o_auth_2_clients.py @@ -8,6 +8,7 @@ from ...types import Response, UNSET from ... import errors from ...types import UNSET, Unset +from ...models import OAuth20Client from typing import Optional from typing import Union @@ -63,16 +64,17 @@ def _get_kwargs( } -def _parse_response(*, client: Client, response: httpx.Response) -> Optional[Any]: +def _parse_response(*, client: Client, response: httpx.Response) -> Optional[List[OAuth20Client]]: if response.status_code == HTTPStatus.OK: - return None + response_200 = list([ OAuth20Client.from_dict(data) for data in response.json() ]) + return response_200 if client.raise_on_unexpected_status: raise errors.UnexpectedStatus(f"Unexpected status code: {response.status_code}") else: return None -def _build_response(*, client: Client, response: httpx.Response) -> Response[Any]: +def _build_response(*, client: Client, response: httpx.Response) -> Response[List[OAuth20Client]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, @@ -89,7 +91,7 @@ def sync_detailed( client_name: Union[Unset, None, str] = UNSET, owner: Union[Unset, None, str] = UNSET, -) -> Response[Any]: +) -> Response[List[OAuth20Client]]: """List OAuth 2.0 Clients This endpoint lists all clients in the database, and never returns client secrets. @@ -135,7 +137,7 @@ async def asyncio_detailed( client_name: Union[Unset, None, str] = UNSET, owner: Union[Unset, None, str] = UNSET, -) -> Response[Any]: +) -> Response[List[OAuth20Client]]: """List OAuth 2.0 Clients This endpoint lists all clients in the database, and never returns client secrets.