From bbf81e143e1a2f56546aa6457ac1eb63e4d192e7 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Fri, 29 Apr 2022 16:55:23 +0200 Subject: [PATCH] fails when user exists --- app/authentik/api.py | 16 ++++++++-------- app/authentik/models.py | 2 +- app/authentik/test_authentik.py | 6 +++--- app/event_controller.py | 6 ++++-- app/main.py | 4 ++-- app/routers/identityProvider.py | 6 +++++- app/test_event_controller.py | 6 +++--- app/test_integration.py | 20 +++++++++++++------- 8 files changed, 39 insertions(+), 27 deletions(-) diff --git a/app/authentik/api.py b/app/authentik/api.py index dddf834..c36ee5d 100644 --- a/app/authentik/api.py +++ b/app/authentik/api.py @@ -5,7 +5,7 @@ from requests import Request import structlog from app.authentik.settings import AuthentikSettings -from .models import User +from .models import AuthentikUser logging = structlog.get_logger() @@ -147,13 +147,13 @@ class Authentik: return r.json() raise Exception(r.status_code, r.url, r.text) - def get_user_by_pk(self, pk: str) -> Optional[User]: + def get_user_by_pk(self, pk: str) -> Optional[AuthentikUser]: r = self.get(f"core/users/{pk}").json() if "pk" in r: - return User(**r) + return AuthentikUser(**r) raise Exception(r) - def get_user(self, user: User) -> Optional[User]: + def get_user(self, user: AuthentikUser) -> Optional[AuthentikUser]: if user.pk: r = self.get(f"core/users/{user.pk}").json() else: @@ -165,16 +165,16 @@ class Authentik: r = r["results"][0] if "pk" in r: - return User(**r) + return AuthentikUser(**r) raise Exception(r) - def create_user(self, user: User) -> User: + def create_user(self, user: AuthentikUser) -> AuthentikUser: r = self.post("core/users/", user.dict()).json() if "pk" in r: - return User(**r) + return AuthentikUser(**r) raise Exception(r) - def delete_user(self, user: User) -> bool: + def delete_user(self, user: AuthentikUser) -> bool: if user == None or user.pk == None: raise Exception("Not a valid user") diff --git a/app/authentik/models.py b/app/authentik/models.py index e70206a..65adfb8 100644 --- a/app/authentik/models.py +++ b/app/authentik/models.py @@ -28,7 +28,7 @@ class GroupsObjItem(BaseModel): attributes: Dict[str, Any] users_obj: List[UsersObjItem] -class User(BaseUser): +class AuthentikUser(BaseUser): pk: Optional[str] username: str name: str diff --git a/app/authentik/test_authentik.py b/app/authentik/test_authentik.py index 6d54b8b..2d772cd 100644 --- a/app/authentik/test_authentik.py +++ b/app/authentik/test_authentik.py @@ -3,7 +3,7 @@ import logging from app.authentik.settings import AuthentikSettings from .api import Authentik -from .models import User +from .models import AuthentikUser import pytest @pytest.fixture() @@ -34,7 +34,7 @@ def test_create_event_rule_already_exists(api: Authentik): assert not exception == None # TODO create exception types def test_get_user_by_username(api: Authentik): - u = User(username="akadmin", + u = AuthentikUser(username="akadmin", name="", groups=[], email="", @@ -47,7 +47,7 @@ def test_get_user_by_username(api: Authentik): def test_create_user(api: Authentik): - u = User(username="banane", + u = AuthentikUser(username="banane", name="banane", groups=[], email="foo@example.org", diff --git a/app/event_controller.py b/app/event_controller.py index d1b2928..a4764c1 100644 --- a/app/event_controller.py +++ b/app/event_controller.py @@ -3,7 +3,7 @@ from typing import List from pydantic import BaseModel from fastapi import FastAPI, Depends from app.authentik.api import Authentik -from app.authentik.models import User +from app.authentik.models import AuthentikUser from app.consumer.baseConsumer import Consumer from app.consumer.wekan.api import WekanApi from app.consumer.wekan.main import WekanConsumer @@ -32,6 +32,7 @@ class EventController: # try: self._authentik = authentik_api self._sinks = [] + self._exceptions = [] for sc in Consumer.__subclasses__(): obj = sc() self._sinks.append(obj) @@ -47,11 +48,12 @@ class EventController: self._sinks = sinks def handle_model_created_event(self, model: Authentik_Hook_Model): - user: User = self._authentik.get_user_by_pk(model.pk) + user: AuthentikUser = self._authentik.get_user_by_pk(model.pk) for sink in self._sinks: # TODO this could run async logging.info(f"Creating User {user.username} in {sink.__class__}") try: sink.create_user(user) except Exception as e: logging.error("create user", exception=str(e), sink=sink, user=user) + self._exceptions.append(str(e)) return True diff --git a/app/main.py b/app/main.py index db3a671..82eac4b 100644 --- a/app/main.py +++ b/app/main.py @@ -5,7 +5,7 @@ from fastapi import Depends, FastAPI, Request, BackgroundTasks from pydantic import BaseModel from app.consumer.baseConsumer import BaseUser, Consumer from app.authentik.api import Authentik -from app.authentik.models import User +from app.authentik.models import AuthentikUser from app.event_controller import Authentik_Hook_Model, EventController, Http_request from app.authentik.settings import AuthentikSettings from .consumer.wekan.api import WekanApi @@ -42,7 +42,7 @@ async def create_demo_user(request: Request): a = Authentik(base="http://localhost:9000/", token="foobar123") try: user = a.create_user( - User(username="demo", name="dmeo", email="foo@example.org")) + AuthentikUser(username="demo", name="dmeo", email="foo@example.org")) except Exception as e: # TODO return e logging.info(user) diff --git a/app/routers/identityProvider.py b/app/routers/identityProvider.py index 44e46b5..b118069 100644 --- a/app/routers/identityProvider.py +++ b/app/routers/identityProvider.py @@ -7,6 +7,7 @@ from app.authentik.settings import AuthentikSettings router = APIRouter() +ec = EventController(Authentik(AuthentikSettings())) @router.post("/authentik/hook/") async def hook(model: Authentik_Hook_Model, @@ -15,7 +16,10 @@ async def hook(model: Authentik_Hook_Model, ): logging.info(model) logging.info(http_request) - ec = EventController(Authentik(AuthentikSettings())) if http_request.path == "/api/v3/core/users/": background_tasks.add_task(ec.handle_model_created_event, model) return 200 + +@router.get("/authentik/errors/") +async def errors(): + return ec._exceptions \ No newline at end of file diff --git a/app/test_event_controller.py b/app/test_event_controller.py index 4209cee..c160ffb 100644 --- a/app/test_event_controller.py +++ b/app/test_event_controller.py @@ -1,14 +1,14 @@ -from app.authentik.models import User +from app.authentik.models import AuthentikUser from pytest_mock import MockerFixture from .event_controller import Authentik_Hook_Model, EventController import pytest @pytest.fixture() def mock_user(): - return User(pk="5", username="asd", name="asd", email="asd@example.org") + return AuthentikUser(pk="5", username="asd", name="asd", email="asd@example.org") -def test_handle_model_created_event(mocker: MockerFixture, mock_user: User): +def test_handle_model_created_event(mocker: MockerFixture, mock_user: AuthentikUser): wekan_mock = mocker.MagicMock() wekan_mock.get_user.return_value = None nextcloud_mock = mocker.MagicMock() diff --git a/app/test_integration.py b/app/test_integration.py index 9f9fb33..eff461c 100644 --- a/app/test_integration.py +++ b/app/test_integration.py @@ -7,7 +7,7 @@ from fastapi.testclient import TestClient from .main import app from app.authentik.api import Authentik -from app.authentik.models import User +from app.authentik.models import AuthentikUser from app.authentik.settings import AuthentikSettings from app.consumer.wekan.models import User as WekanUser from app.consumer.wekan.api import WekanApi @@ -42,13 +42,13 @@ def authentik(settings: AuthentikSettings): @pytest.fixture() def authentik_user(authentik): - user = authentik.create_user(User(username="foobar", name="Foo Bar", email="foo@bar.com")) + user = authentik.create_user(AuthentikUser(username="foobar", name="Foo Bar", email="foo@bar.com")) yield user authentik.delete_user(user) -def test_create_user(mocker, authentik_user: WekanUser, wekan: WekanApi): +def test_create_user(mocker, authentik_user: AuthentikUser, wekan: WekanApi): # Actually authentik user creation should already trigger the hook, but in authentik it doesn't trigger when come from api # mock = mocker.patch("app.event_controller.EventController.handle_model_created_event") authentik_message = {"model": {"pk": authentik_user.pk, "app": "authentik_core", "name": authentik_user.name, @@ -68,7 +68,13 @@ def test_create_user_with_same_email(wekan_api, authentik_api): "authentik notifcation rule doesn't work with api?? , create two user with identical email in authentik") assert False - -@pytest.mark.skip() -def test_user_already_exists_excepts(): - assert False +def test_user_already_exists_excepts(authentik_user: AuthentikUser, wekan: WekanApi): + authentik_message = {"model": {"pk": authentik_user.pk, "app": "authentik_core", "name": authentik_user.name, + "model_name": "user"}, "http_request": {"args": {}, "path": "/api/v3/core/users/", "method": "POST"}} + response = client.post("/authentik/hook/", json=authentik_message) + response = client.post("/authentik/hook/", json=authentik_message) + assert response.status_code == 200 + errors = client.get("/authentik/errors/") + assert errors.status_code == 200 + assert errors.json() == ["[Wekan] User already exists"] # TODO introduce error models + wekan.delete_user(wekan.get_user(authentik_user.username).id)