-
Notifications
You must be signed in to change notification settings - Fork 23
✨(back) integrate resource server API #195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
lunika
wants to merge
14
commits into
main
Choose a base branch
from
feat/resource-server
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
89fa805
✨(back) expose an external api using resource server authentication
lunika 402bb25
🔥(back) remove mozilla OIDCAuthentication fron DRF settings
lunika a53e7e5
🔧(helm) configure ingress for external_api route
lunika 015fffb
🚧(ci) publish image for resource-server feature
lunika c6bf6f6
🔧(back) allow to enable swagger in production
lunika e471d14
🚧(back) allow to connect to the exernal api with a JWT token
lunika d8dec4f
🐛(external_api) add /external_api route to the nginx config
sylvinus a13e017
✨(back) add new flags for creating users and enabling auth via JWT
sylvinus 6a13264
🔒️(frontend) hide Nginx server version in error responses
sylvinus 5c0cdde
🚧(back) add users endpoint to the external api
lunika 79bdc5b
🐛(email) avoid trying to send emails if no provider is configured
sylvinus de4d995
🔧(settings) configure INVITATION_VALIDITY_DURATION as positive int
sylvinus 2b92055
✨(external_api) add Invitations to the external API
sylvinus 105dbd1
🚨(backend) replace 401 status by 403 in tests
lunika File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| """Drive core resource_server package.""" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| """Authentication for external API using JWT token.""" | ||
|
|
||
| import logging | ||
|
|
||
| from django.conf import settings | ||
|
|
||
| import jwt | ||
| from rest_framework import authentication | ||
|
|
||
| from core.models import User | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| class JWTAuthentication(authentication.BaseAuthentication): | ||
| """Authentication for external API using JWT token.""" | ||
|
|
||
| def authenticate(self, request): | ||
| """Authenticate the request using JWT token.""" | ||
|
|
||
| auth_header = request.headers.get("Authorization") | ||
| if not auth_header: | ||
| logger.warning("No Authorization header found in request") | ||
| return None | ||
|
|
||
| # Check if the header starts with 'Bearer ' | ||
| if not auth_header.startswith("Bearer "): | ||
| logger.warning( | ||
| "Invalid Authorization header format. Expected 'Bearer <token>'" | ||
| ) | ||
| return None | ||
|
|
||
| # Extract the token | ||
| token = auth_header.split(" ")[1] | ||
|
|
||
| # Validate the token | ||
| try: | ||
| payload = jwt.decode( | ||
| token, | ||
| settings.JWT_SECRET_KEY, | ||
| options={"require": settings.JWT_REQUIRED_CLAIMS}, | ||
| algorithms=[settings.JWT_ALGORITHM], | ||
| ) | ||
| except jwt.InvalidTokenError as e: | ||
| logger.error("Invalid JWT token: %s", e) | ||
| return None | ||
|
|
||
| if not payload.get("sub") or not payload.get("email"): | ||
| logger.warning("Invalid JWT token. Missing 'sub' or 'email' in payload") | ||
| return None | ||
|
|
||
| user = User.objects.get_user_by_sub_or_email( | ||
| payload.get("sub"), payload.get("email") | ||
| ) | ||
| if not user: | ||
| if settings.JWT_CREATE_USER: | ||
| user = User(sub=payload.get("sub"), email=payload.get("email")) | ||
| user.set_unusable_password() | ||
| user.save() | ||
| else: | ||
| logger.warning("User not found") | ||
| return None | ||
|
|
||
| return user, None | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| """Resource Server Permissions for the Drive app.""" | ||
|
|
||
| from django.conf import settings | ||
|
|
||
| from lasuite.oidc_resource_server.authentication import ResourceServerAuthentication | ||
| from rest_framework import permissions | ||
|
|
||
| from .authentication import JWTAuthentication | ||
|
|
||
|
|
||
| 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, | ||
| (JWTAuthentication, ResourceServerAuthentication), | ||
| ): | ||
| # Not a resource server request | ||
| return False | ||
|
|
||
| # Check if the user is authenticated | ||
| if not request.user.is_authenticated: | ||
| return False | ||
| if ( | ||
| hasattr(view, "resource_server_actions") | ||
| and view.action not in view.resource_server_actions | ||
| ): | ||
| return False | ||
|
|
||
| # When used as a resource server, the request has a token audience | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The comment needs an update and so the docstring (class & method) |
||
| return ( | ||
| getattr(request, "resource_server_token_audience", None) | ||
| in settings.OIDC_RS_ALLOWED_AUDIENCES | ||
| ) or isinstance( | ||
| request.successful_authenticator, | ||
| JWTAuthentication, # JWT Token are forcibly allowed | ||
| ) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| """Resource Server Viewsets for the Drive app.""" | ||
|
|
||
| from django.conf import settings | ||
|
|
||
| from lasuite.oidc_resource_server.authentication import ResourceServerAuthentication | ||
|
|
||
| from ..api.permissions import ( | ||
| AccessPermission, | ||
| CanCreateInvitationPermission, | ||
| IsSelf, | ||
| ItemAccessPermission, | ||
| ) | ||
| from ..api.viewsets import ( | ||
| InvitationViewset, | ||
| ItemAccessViewSet, | ||
| ItemViewSet, | ||
| UserViewSet, | ||
| ) | ||
| from .authentication import JWTAuthentication | ||
| from .permissions import ResourceServerClientPermission | ||
|
|
||
| # pylint: disable=too-many-ancestors | ||
|
|
||
|
|
||
| if settings.JWT_AUTH_ENABLED: | ||
| EXTERNAL_API_AUTH_CLASSES = [JWTAuthentication, ResourceServerAuthentication] | ||
| else: | ||
| EXTERNAL_API_AUTH_CLASSES = [ResourceServerAuthentication] | ||
|
|
||
|
|
||
| class ResourceServerItemViewSet(ItemViewSet): | ||
| """Resource Server Viewset for the Drive app.""" | ||
|
|
||
| authentication_classes = EXTERNAL_API_AUTH_CLASSES | ||
|
|
||
| permission_classes = [ResourceServerClientPermission & ItemAccessPermission] | ||
|
|
||
|
|
||
| class ResourceServerItemAccessViewSet(ItemAccessViewSet): | ||
| """Resource Server Viewset for the Drive app.""" | ||
|
|
||
| authentication_classes = EXTERNAL_API_AUTH_CLASSES | ||
|
|
||
| permission_classes = [ResourceServerClientPermission & AccessPermission] | ||
|
|
||
|
|
||
| class ResourceServerInvitationViewSet(InvitationViewset): | ||
| """Resource Server Viewset for the Drive app.""" | ||
|
|
||
| authentication_classes = EXTERNAL_API_AUTH_CLASSES | ||
|
|
||
| permission_classes = [ | ||
| ResourceServerClientPermission & CanCreateInvitationPermission | ||
| ] | ||
|
|
||
|
|
||
| class ResourceServerUserViewSet(UserViewSet): | ||
| """Resource Server UserViewset for the Drive app.""" | ||
|
|
||
| authentication_classes = EXTERNAL_API_AUTH_CLASSES | ||
|
|
||
| permission_classes = [ResourceServerClientPermission & IsSelf] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may add a
authenticate_headermethod to return a 401 instead of a 403 when no authentication is provided.