From 78818ba541cb390385f34992a66d23a9fd1d6f56 Mon Sep 17 00:00:00 2001 From: lebaudantoine Date: Mon, 29 Jul 2024 19:26:50 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=A9=B9(backend)=20enable=20resource=20ser?= =?UTF-8?q?ver=20authentication=20if=20properly=20configured?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests are missing, let's ship it, I'll open an issue. Without such protection, the whole app would crash if the resource server is not configured. The fallback backend would return an appropriate error to the client if the resource server is improperly configured. --- .../core/resource_server/authentication.py | 25 +++++++++++-------- src/backend/core/resource_server/backend.py | 22 +++++++++++++++- src/backend/core/resource_server/clients.py | 7 ++++++ 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/src/backend/core/resource_server/authentication.py b/src/backend/core/resource_server/authentication.py index 7be60e5..aaac211 100644 --- a/src/backend/core/resource_server/authentication.py +++ b/src/backend/core/resource_server/authentication.py @@ -9,7 +9,7 @@ from django.core.exceptions import ImproperlyConfigured from mozilla_django_oidc.contrib.drf import OIDCAuthentication -from .backend import ResourceServerBackend +from .backend import ResourceServerBackend, ResourceServerImproperlyConfiguredBackend from .clients import AuthorizationServerClient logger = logging.getLogger(__name__) @@ -21,16 +21,21 @@ class ResourceServerAuthentication(OIDCAuthentication): def __init__(self): super().__init__() - authorization_server_client = AuthorizationServerClient( - url=settings.OIDC_OP_URL, - verify_ssl=settings.OIDC_VERIFY_SSL, - timeout=settings.OIDC_TIMEOUT, - proxy=settings.OIDC_PROXY, - url_jwks=settings.OIDC_OP_JWKS_ENDPOINT, - url_introspection=settings.OIDC_OP_INTROSPECTION_ENDPOINT, - ) + try: + authorization_server_client = AuthorizationServerClient( + url=settings.OIDC_OP_URL, + verify_ssl=settings.OIDC_VERIFY_SSL, + timeout=settings.OIDC_TIMEOUT, + proxy=settings.OIDC_PROXY, + url_jwks=settings.OIDC_OP_JWKS_ENDPOINT, + url_introspection=settings.OIDC_OP_INTROSPECTION_ENDPOINT, + ) + self.backend = ResourceServerBackend(authorization_server_client) - self.backend = ResourceServerBackend(authorization_server_client) + except ImproperlyConfigured as err: + message = "Resource Server authentication is disabled" + logger.debug("%s. Exception: %s", message, err) + self.backend = ResourceServerImproperlyConfiguredBackend() def get_access_token(self, request): """Retrieve and decode the access token from the request. diff --git a/src/backend/core/resource_server/backend.py b/src/backend/core/resource_server/backend.py index fbee913..87dbbc4 100644 --- a/src/backend/core/resource_server/backend.py +++ b/src/backend/core/resource_server/backend.py @@ -4,12 +4,13 @@ import logging from django.conf import settings from django.contrib import auth -from django.core.exceptions import SuspiciousOperation +from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation from joserfc import jwe as jose_jwe from joserfc import jwt as jose_jwt from joserfc.errors import InvalidClaimError, InvalidTokenError from requests.exceptions import HTTPError +from rest_framework.exceptions import AuthenticationFailed from . import utils @@ -41,6 +42,16 @@ class ResourceServerBackend: self._encryption_algorithm = settings.OIDC_RS_ENCRYPTION_ALGO self._signing_algorithm = settings.OIDC_RS_SIGNING_ALGO self._scopes = settings.OIDC_RS_SCOPES + + if ( + not self._client_id + or not self._client_secret + or not authorization_server_client + ): + raise ImproperlyConfigured( + "Could not instantiate ResourceServerBackend, some parameters are missing." + ) + self._authorization_server_client = authorization_server_client self._claims_registry = jose_jwt.JWTClaimsRegistry( @@ -56,6 +67,7 @@ class ResourceServerBackend: Params 'id_token', 'payload' won't be used, and our implementation will only support 'get_user', not 'get_or_create_user'. """ + return self.get_user(access_token) def get_user(self, access_token): @@ -201,3 +213,11 @@ class ResourceServerBackend: raise SuspiciousOperation(message) from err return token.claims + + +class ResourceServerImproperlyConfiguredBackend: + """Fallback backend for improperly configured Resource Servers.""" + + def get_or_create_user(self, access_token, id_token, payload): + """Indicate that the Resource Server is improperly configured.""" + raise AuthenticationFailed("Resource Server is improperly configured") diff --git a/src/backend/core/resource_server/clients.py b/src/backend/core/resource_server/clients.py index 5acd648..ea9aed6 100644 --- a/src/backend/core/resource_server/clients.py +++ b/src/backend/core/resource_server/clients.py @@ -1,5 +1,7 @@ """Resource Server Clients classes""" +from django.core.exceptions import ImproperlyConfigured + import requests from joserfc.jwk import KeySet @@ -28,6 +30,11 @@ class AuthorizationServerClient: timeout, proxy, ): + if not url or not url_jwks or not url_introspection: + raise ImproperlyConfigured( + "Could not instantiate AuthorizationServerClient, some parameters are missing." + ) + self.url = url self._url_introspection = url_introspection self._url_jwks = url_jwks