2024-07-29 15:52:19 +02:00
|
|
|
"""Resource Server Authentication"""
|
|
|
|
|
|
|
|
|
|
import base64
|
|
|
|
|
import binascii
|
|
|
|
|
import logging
|
|
|
|
|
|
|
|
|
|
from django.conf import settings
|
|
|
|
|
from django.core.exceptions import ImproperlyConfigured
|
|
|
|
|
|
|
|
|
|
from mozilla_django_oidc.contrib.drf import OIDCAuthentication
|
|
|
|
|
|
2024-07-29 19:26:50 +02:00
|
|
|
from .backend import ResourceServerBackend, ResourceServerImproperlyConfiguredBackend
|
2024-07-29 15:52:19 +02:00
|
|
|
from .clients import AuthorizationServerClient
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ResourceServerAuthentication(OIDCAuthentication):
|
|
|
|
|
"""Authenticate clients using the token received from the authorization server."""
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
2024-10-25 14:59:02 +02:00
|
|
|
"""Require authentication to be configured in order to instantiate."""
|
2024-07-29 15:52:19 +02:00
|
|
|
super().__init__()
|
|
|
|
|
|
2024-07-29 19:26:50 +02:00
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
except ImproperlyConfigured as err:
|
|
|
|
|
message = "Resource Server authentication is disabled"
|
|
|
|
|
logger.debug("%s. Exception: %s", message, err)
|
|
|
|
|
self.backend = ResourceServerImproperlyConfiguredBackend()
|
2024-07-29 15:52:19 +02:00
|
|
|
|
|
|
|
|
def get_access_token(self, request):
|
|
|
|
|
"""Retrieve and decode the access token from the request.
|
|
|
|
|
|
2024-10-25 14:59:02 +02:00
|
|
|
This method overrides the 'get_access_token' method from the parent class,
|
2024-07-29 15:52:19 +02:00
|
|
|
to support service providers that would base64 encode the bearer token.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
access_token = super().get_access_token(request)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
access_token = base64.b64decode(access_token).decode("utf-8")
|
|
|
|
|
except (binascii.Error, TypeError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
return access_token
|
2024-11-04 11:32:41 +01:00
|
|
|
|
|
|
|
|
def authenticate(self, request):
|
|
|
|
|
"""
|
|
|
|
|
Authenticate the request and return a tuple of (user, token) or None.
|
|
|
|
|
|
|
|
|
|
We override the 'authenticate' method from the parent class to store
|
|
|
|
|
the introspected token audience inside the request.
|
|
|
|
|
"""
|
|
|
|
|
result = super().authenticate(request) # Might raise AuthenticationFailed
|
|
|
|
|
|
|
|
|
|
if result is None: # Case when there is no access token
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
# Note: at this stage, the request is a "drf_request" object
|
|
|
|
|
request.resource_server_token_audience = self.backend.token_origin_audience
|
|
|
|
|
|
|
|
|
|
return result
|