Skip to content

Commit

Permalink
OAuth setup
Browse files Browse the repository at this point in the history
  • Loading branch information
mariocesar committed Sep 12, 2021
1 parent 9e34105 commit 4c85c49
Show file tree
Hide file tree
Showing 10 changed files with 131 additions and 64 deletions.
32 changes: 1 addition & 31 deletions src/aseb/api/auth/viewsets.py
@@ -1,11 +1,9 @@
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework.authtoken.serializers import AuthTokenSerializer
from rest_framework.decorators import action
from rest_framework.response import Response

from aseb.api import viewsets
from aseb.apps.users.models import User

from ..users.serializers import UserSerializer
from .serializers import RegisterSerializer
Expand All @@ -15,37 +13,9 @@ class AuthViewSet(viewsets.ViewSet):
authentication_classes = ()
permission_classes = ()

@swagger_auto_schema(
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
"username": openapi.Schema(type=openapi.TYPE_STRING),
"password": openapi.Schema(
type=openapi.TYPE_STRING, format=openapi.FORMAT_PASSWORD
),
},
),
)
@action(detail=False, methods=["post"])
def login(self, request, *args, **kwargs):
serializer = AuthTokenSerializer(data=request.data, context={"request": request})
serializer.is_valid(raise_exception=True)

user: User = serializer.validated_data["user"]
user.tokens.all().delete() # TODO: Be smart about rotating tokens on every login
token = user.tokens.create(user=user)

return Response(
{
"token": token.token,
"expires": token.expires,
"scopes": token.scopes,
"user": UserSerializer(context={"request": request}).to_representation(user),
}
)

@swagger_auto_schema(
request_body=RegisterSerializer,
tags=["auth"],
responses={
200: openapi.Schema(
type=openapi.TYPE_OBJECT,
Expand Down
25 changes: 25 additions & 0 deletions src/aseb/api/oauth/viewsets.py
@@ -0,0 +1,25 @@
from oauth2_provider import views


class AuthorizationView(views.AuthorizationView):
...


class TokenView(views.TokenView):
...


class RevokeTokenView(views.RevokeTokenView):
...


class IntrospectTokenView(views.IntrospectTokenView):
...


class AuthorizedTokenDeleteView(views.AuthorizedTokenDeleteView):
...


class AuthorizedTokensListView(views.AuthorizedTokensListView):
...
29 changes: 27 additions & 2 deletions src/aseb/api/urls.py
@@ -1,5 +1,15 @@
from django.urls import re_path

from .auth.viewsets import AuthViewSet
from .members.viewsets import MemberViewSet
from .oauth.viewsets import (
AuthorizationView,
AuthorizedTokenDeleteView,
AuthorizedTokensListView,
IntrospectTokenView,
RevokeTokenView,
TokenView,
)
from .pages.viewsets import PageViewSet
from .router import Router
from .topics.viewsets import TopicViewSet
Expand All @@ -13,6 +23,21 @@
router.register("topics", TopicViewSet, basename="topic")
router.register("pages", PageViewSet, basename="page")

urlpatterns = [
*router.urls,
urlpatterns = [*router.urls]

oauth2_urlpatterns = [
re_path(r"^oauth/authorize/$", AuthorizationView.as_view(), name="authorize"),
re_path(r"^oauth/token/$", TokenView.as_view(), name="token"),
re_path(r"^oauth/revoke_token/$", RevokeTokenView.as_view(), name="revoke-token"),
re_path(r"^oauth/introspect/$", IntrospectTokenView.as_view(), name="introspect"),
re_path(
r"^oauth/authorized-tokens/$",
AuthorizedTokensListView.as_view(),
name="authorized-token-list",
),
re_path(
r"^oauth/authorized-tokens/(?P<pk>[\w-]+)/delete/$",
AuthorizedTokenDeleteView.as_view(),
name="authorized-token-delete",
),
]
11 changes: 1 addition & 10 deletions src/aseb/api/users/viewsets.py
@@ -1,6 +1,5 @@
from drf_yasg.utils import swagger_auto_schema
from rest_framework import parsers, permissions
from rest_framework.decorators import action
from rest_framework.response import Response

from aseb.api import viewsets
Expand All @@ -18,10 +17,7 @@ def list(self, request):
UserSerializer(context={"request": request}).to_representation(request.user)
)

@swagger_auto_schema(
request_body=UserUpdateSerializer,
responses={200: UserSerializer()},
)
@swagger_auto_schema(request_body=UserUpdateSerializer, responses={200: UserSerializer()})
def create(self, request):
serializer = UserUpdateSerializer(
context={"request": request},
Expand All @@ -33,11 +29,6 @@ def create(self, request):

return Response(UserSerializer(context={"request": request}).to_representation(user))

@action(detail=False, methods=["post"])
def logout(self, request, *args, **kwargs):
request.user.tokens.all().delete()
return Response()


class UserViewSet(viewsets.ModelViewSet):
permission_classes = [permissions.IsAuthenticated, permissions.IsAdminUser]
Expand Down
22 changes: 9 additions & 13 deletions src/aseb/apps/users/urls.py
@@ -1,7 +1,14 @@
from django.contrib.auth import views
from django.urls import path, re_path
from oauth2_provider.views import AuthorizedTokensListView, AuthorizedTokenDeleteView
from oauth2_provider.urls import base_urlpatterns as oauth2_urlpatterns

from .views import (
AuthorizationView,
IntrospectTokenView,
RevokeTokenView,
TokenView,
AuthorizedTokenDeleteView,
AuthorizedTokensListView,
)

urlpatterns = [
path(
Expand All @@ -24,15 +31,4 @@
views.PasswordResetCompleteView.as_view(),
name="password_reset_complete",
),
*oauth2_urlpatterns,
re_path(
r"^authorized_tokens/$",
AuthorizedTokensListView.as_view(),
name="authorized-token-list",
),
re_path(
r"^authorized_tokens/(?P<pk>[\w-]+)/delete/$",
AuthorizedTokenDeleteView.as_view(),
name="authorized-token-delete",
),
]
35 changes: 35 additions & 0 deletions src/aseb/apps/users/views.py
@@ -0,0 +1,35 @@
from oauth2_provider import views
from rest_framework.schemas import AutoSchema
from rest_framework.views import APIView
from django.utils.decorators import method_decorator
from drf_yasg.utils import swagger_auto_schema


class AuthorizationView(views.AuthorizationView):
...


@method_decorator(name="post", decorator=swagger_auto_schema(tags=["tokens"]))
class TokenView(APIView, views.TokenView):
...


@method_decorator(name="post", decorator=swagger_auto_schema(tags=["tokens"]))
class RevokeTokenView(APIView, views.RevokeTokenView):
...


@method_decorator(name="get", decorator=swagger_auto_schema(tags=["tokens"]))
@method_decorator(name="post", decorator=swagger_auto_schema(tags=["tokens"]))
class IntrospectTokenView(APIView, views.IntrospectTokenView):
...


@method_decorator(name="delete", decorator=swagger_auto_schema(tags=["tokens"]))
class AuthorizedTokenDeleteView(APIView, views.AuthorizedTokenDeleteView):
...


@method_decorator(name="get", decorator=swagger_auto_schema(tags=["tokens"]))
class AuthorizedTokensListView(APIView, views.AuthorizedTokensListView):
...
19 changes: 19 additions & 0 deletions src/aseb/fixtures/oauth2_provider.json
@@ -0,0 +1,19 @@
[
{
"model": "oauth2_provider.application",
"pk": 1,
"fields": {
"client_id": "CLIENT_ID",
"user": null,
"redirect_uris": "http://localhost:8000/static/drf-yasg/swagger-ui-dist/oauth2-redirect.html",
"client_type": "confidential",
"authorization_grant_type": "authorization-code",
"client_secret": "CLIENT_SECRET",
"name": "aseb.bo",
"skip_authorization": true,
"created": "2021-09-12T02:14:57.377Z",
"updated": "2021-09-12T02:19:14.020Z",
"algorithm": ""
}
}
]
8 changes: 4 additions & 4 deletions src/aseb/settings/base.py
Expand Up @@ -168,8 +168,8 @@
"SECURITY_DEFINITIONS": {
"ASEB API": {
"type": "oauth2",
"authorizationUrl": "/auth/authorize",
"tokenUrl": "/auth/token/",
"authorizationUrl": "/oauth/authorize",
"tokenUrl": "/oauth/token/",
"flow": "accessCode",
"scopes": {
"read": "read",
Expand All @@ -178,8 +178,8 @@
}
},
"OAUTH2_CONFIG": {
"clientId": "yourAppClientId",
"clientSecret": "yourAppClientSecret",
"clientId": env("OAUTH2_CLIENT_ID", ""),
"clientSecret": env("OAUTH2_CLIENT_SECRET", ""),
"appName": "aseb.bo",
},
}
Expand Down
7 changes: 6 additions & 1 deletion src/aseb/settings/develop.py
Expand Up @@ -15,12 +15,17 @@
"debug_toolbar.middleware.DebugToolbarMiddleware",
]

SWAGGER_SETTINGS["OAUTH2_CONFIG"]["clientId"] = "CLIENT_ID" # noqa:
SWAGGER_SETTINGS["OAUTH2_CONFIG"]["clientSecret"] = "CLIENT_SECRET" # noqa:
SWAGGER_SETTINGS[ # noqa:
"OAUTH2_REDIRECT_URL"
] = "http://localhost:8000/static/drf-yasg/swagger-ui-dist/oauth2-redirect.html"

EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"

DEBUG_TOOLBAR_CONFIG = {
"DISABLE_PANELS": ["debug_toolbar.panels.redirects.RedirectsPanel"],
"SHOW_TEMPLATE_CONTEXT": True,
"SHOW_TOOLBAR_CALLBACK": lambda request: True,
}

DEBUG_TOOLBAR_PANELS = [
Expand Down
7 changes: 4 additions & 3 deletions src/aseb/urls.py
Expand Up @@ -3,17 +3,18 @@
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import include, path
from django.urls import include, path, re_path
from django.views.static import serve
from aseb.api.urls import oauth2_urlpatterns

handler404 = "aseb.core.views.not_found"

urlpatterns = [
path("admin/docs/", include("django.contrib.admindocs.urls")),
path("admin/", admin.site.urls),
path("auth/", include("aseb.apps.users.urls")),
path("oauth/", include("oauth2_provider.urls", namespace="oauth2_provider")),
path("v1/", include("aseb.api.urls")),
*oauth2_urlpatterns, # ^oauth/
re_path("^v1/", include("aseb.api.urls")),
]

if settings.DEBUG:
Expand Down

0 comments on commit 4c85c49

Please sign in to comment.