🚧(resource-server) Allow documents API via RS

This provides a base configuration to allow to access all "/documents"
API via OIDC resource server authentication.
This commit is contained in:
Quentin BEY
2025-05-13 23:42:56 +02:00
parent dd6e0b5072
commit cae2aab1ab
4 changed files with 116 additions and 0 deletions
+37
View File
@@ -1,9 +1,11 @@
"""Permission handlers for the impress core app."""
from django.conf import settings
from django.core import exceptions
from django.db.models import Q
from django.http import Http404
from lasuite.oidc_resource_server.authentication import ResourceServerAuthentication
from rest_framework import permissions
from core.models import DocumentAccess, RoleChoices, get_trashbin_cutoff
@@ -134,3 +136,38 @@ class DocumentAccessPermission(AccessPermission):
raise Http404
return has_permission
class ResourceServerClientPermission(permissions.BasePermission):
"""
Permission class for resource server views.
This provides a way to open the resource server views to a limited set of
Service Providers.
Note: we might add a more complex permission system in the future, based on
the Service Provider ID and the requested scopes.
"""
def has_permission(self, request, view):
"""
Check if the user is authenticated and the token introspection
provides an authorized Service Provider.
"""
if not isinstance(
request.successful_authenticator, ResourceServerAuthentication
):
# Not a resource server request
return True
# Check if the user is authenticated
if not request.user.is_authenticated:
return False
if view.action not in view.resource_server_actions:
return False
# When used as a resource server, the request has a token audience
return (
request.resource_server_token_audience in settings.OIDC_RS_ALLOWED_AUDIENCES
)
+18
View File
@@ -25,6 +25,7 @@ import requests
import rest_framework as drf
from botocore.exceptions import ClientError
from lasuite.malware_detection import malware_detection
from lasuite.oidc_resource_server.authentication import ResourceServerAuthentication
from rest_framework import filters, status, viewsets
from rest_framework import response as drf_response
from rest_framework.permissions import AllowAny
@@ -431,6 +432,7 @@ class DocumentViewSet(
pagination_class = Pagination
permission_classes = [
permissions.DocumentAccessPermission,
permissions.ResourceServerClientPermission,
]
queryset = models.Document.objects.all()
serializer_class = serializers.DocumentSerializer
@@ -440,6 +442,22 @@ class DocumentViewSet(
list_serializer_class = serializers.ListDocumentSerializer
trashbin_serializer_class = serializers.ListDocumentSerializer
tree_serializer_class = serializers.ListDocumentSerializer
resource_server_actions = {
"list",
"retrieve",
"create_for_owner",
}
def get_authenticators(self):
"""Allow resource server authentication for very specific actions."""
authenticators = super().get_authenticators()
# self.action does not exist yet
action = self.action_map[self.request.method.lower()]
if action in self.resource_server_actions:
authenticators.append(ResourceServerAuthentication())
return authenticators
def annotate_is_favorite(self, queryset):
"""
+2
View File
@@ -4,6 +4,7 @@ from django.conf import settings
from django.urls import include, path, re_path
from lasuite.oidc_login.urls import urlpatterns as oidc_urls
from lasuite.oidc_resource_server.urls import urlpatterns as resource_server_urls
from rest_framework.routers import DefaultRouter
from core.api import viewsets
@@ -44,6 +45,7 @@ urlpatterns = [
[
*router.urls,
*oidc_urls,
*resource_server_urls,
re_path(
r"^documents/(?P<resource_id>[0-9a-z-]*)/",
include(document_related_router.urls),
+59
View File
@@ -586,6 +586,65 @@ class Base(Configuration):
default=True, environ_name="ALLOW_LOGOUT_GET_METHOD", environ_prefix=None
)
# OIDC - Docs as a resource server
OIDC_OP_URL = values.Value(
default=None, environ_name="OIDC_OP_URL", environ_prefix=None
)
OIDC_OP_INTROSPECTION_ENDPOINT = values.Value(
environ_name="OIDC_OP_INTROSPECTION_ENDPOINT", environ_prefix=None
)
OIDC_VERIFY_SSL = values.BooleanValue(
default=True, environ_name="OIDC_VERIFY_SSL", environ_prefix=None
)
OIDC_TIMEOUT = values.IntegerValue(
default=3, environ_name="OIDC_TIMEOUT", environ_prefix=None
)
OIDC_PROXY = values.Value(None, environ_name="OIDC_PROXY", environ_prefix=None)
OIDC_RS_BACKEND_CLASS = "lasuite.oidc_resource_server.backend.ResourceServerBackend"
OIDC_RS_AUDIENCE_CLAIM = values.Value( # The claim used to identify the audience
default="client_id", environ_name="OIDC_RS_AUDIENCE_CLAIM", environ_prefix=None
)
OIDC_RS_PRIVATE_KEY_STR = values.Value(
default=None,
environ_name="OIDC_RS_PRIVATE_KEY_STR",
environ_prefix=None,
)
OIDC_RS_ENCRYPTION_KEY_TYPE = values.Value(
default="RSA",
environ_name="OIDC_RS_ENCRYPTION_KEY_TYPE",
environ_prefix=None,
)
OIDC_RS_ENCRYPTION_ALGO = values.Value(
default="RSA-OAEP",
environ_name="OIDC_RS_ENCRYPTION_ALGO",
environ_prefix=None,
)
OIDC_RS_ENCRYPTION_ENCODING = values.Value(
default="A256GCM",
environ_name="OIDC_RS_ENCRYPTION_ENCODING",
environ_prefix=None,
)
OIDC_RS_CLIENT_ID = values.Value(
None, environ_name="OIDC_RS_CLIENT_ID", environ_prefix=None
)
OIDC_RS_CLIENT_SECRET = values.Value(
None,
environ_name="OIDC_RS_CLIENT_SECRET",
environ_prefix=None,
)
OIDC_RS_SIGNING_ALGO = values.Value(
default="ES256", environ_name="OIDC_RS_SIGNING_ALGO", environ_prefix=None
)
OIDC_RS_SCOPES = values.ListValue(
[], environ_name="OIDC_RS_SCOPES", environ_prefix=None
)
OIDC_RS_ALLOWED_AUDIENCES = values.ListValue(
default=[],
environ_name="OIDC_RS_ALLOWED_AUDIENCES",
environ_prefix=None,
)
# AI service
AI_FEATURE_ENABLED = values.BooleanValue(
default=False, environ_name="AI_FEATURE_ENABLED", environ_prefix=None