From d9a788aac8bc93d838f4677486dd807f56111162 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Fri, 21 May 2021 20:14:03 +0200 Subject: [PATCH] api: rename auth to authentication, add authorization for rest_framework permission class Signed-off-by: Jens Langhammer --- authentik/api/{auth.py => authentication.py} | 2 +- authentik/api/authorization.py | 24 ++++++++++++++++++++ authentik/api/tests/test_auth.py | 2 +- authentik/core/channels.py | 2 +- authentik/root/settings.py | 2 +- 5 files changed, 28 insertions(+), 4 deletions(-) rename authentik/api/{auth.py => authentication.py} (97%) create mode 100644 authentik/api/authorization.py diff --git a/authentik/api/auth.py b/authentik/api/authentication.py similarity index 97% rename from authentik/api/auth.py rename to authentik/api/authentication.py index 97f821b56..54d555d03 100644 --- a/authentik/api/auth.py +++ b/authentik/api/authentication.py @@ -42,7 +42,7 @@ def token_from_header(raw_header: bytes) -> Optional[Token]: return tokens.first() -class AuthentikTokenAuthentication(BaseAuthentication): +class TokenAuthentication(BaseAuthentication): """Token-based authentication using HTTP Bearer authentication""" def authenticate(self, request: Request) -> Union[tuple[User, Any], None]: diff --git a/authentik/api/authorization.py b/authentik/api/authorization.py new file mode 100644 index 000000000..eba573836 --- /dev/null +++ b/authentik/api/authorization.py @@ -0,0 +1,24 @@ +"""API Authorization""" +from django.db.models import Model +from rest_framework.permissions import BasePermission +from rest_framework.request import Request + + +class OwnerPermissions(BasePermission): + """Authorize requests by an object's owner matching the requesting user""" + + owner_key = "user" + + def has_permission(self, request: Request, view) -> bool: + """If the user is authenticated, we allow all requests here. For listing, the + object-level permissions are done by the filter backend""" + return request.user.is_authenticated + + def has_object_permission(self, request: Request, view, obj: Model) -> bool: + """Check if the object's owner matches the currently logged in user""" + if not hasattr(obj, self.owner_key): + return False + owner = getattr(obj, self.owner_key) + if owner != request.user: + return False + return True diff --git a/authentik/api/tests/test_auth.py b/authentik/api/tests/test_auth.py index 4f6a6120f..b7ef750cc 100644 --- a/authentik/api/tests/test_auth.py +++ b/authentik/api/tests/test_auth.py @@ -5,7 +5,7 @@ from django.test import TestCase from guardian.shortcuts import get_anonymous_user from rest_framework.exceptions import AuthenticationFailed -from authentik.api.auth import token_from_header +from authentik.api.authentication import token_from_header from authentik.core.models import Token, TokenIntents diff --git a/authentik/core/channels.py b/authentik/core/channels.py index cb124e4b4..a081ec985 100644 --- a/authentik/core/channels.py +++ b/authentik/core/channels.py @@ -4,7 +4,7 @@ from channels.generic.websocket import JsonWebsocketConsumer from rest_framework.exceptions import AuthenticationFailed from structlog.stdlib import get_logger -from authentik.api.auth import token_from_header +from authentik.api.authentication import token_from_header from authentik.core.models import User LOGGER = get_logger() diff --git a/authentik/root/settings.py b/authentik/root/settings.py index cbca48760..e8a219280 100644 --- a/authentik/root/settings.py +++ b/authentik/root/settings.py @@ -161,7 +161,7 @@ REST_FRAMEWORK = { "rest_framework.permissions.DjangoObjectPermissions", ), "DEFAULT_AUTHENTICATION_CLASSES": ( - "authentik.api.auth.AuthentikTokenAuthentication", + "authentik.api.authentication.TokenAuthentication", "rest_framework.authentication.SessionAuthentication", ), "DEFAULT_RENDERER_CLASSES": [