Skip to content
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

Allow Users to Register Client Credentials #132

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.env

# IDE files
.vscode/
.idea/
Expand Down
25 changes: 25 additions & 0 deletions backend/accounts/serializers.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,37 @@
from django.utils import timezone
from django.utils.crypto import get_random_string
from oauth2_provider.models import Application
from rest_framework import serializers

from accounts.mixins import ManyToManySaveMixin
from accounts.models import Email, Major, PhoneNumber, School, Student, User
from accounts.verification import sendEmailVerification, sendSMSVerification


class ApplicationSerializer(serializers.ModelSerializer):
# Hardcode grant type (for now) so it's impossible for someone to create a copycat
# Penn Labs login flow to collect access tokens on behalf of unsuspecting users.
# We may want to relax this if we add more a explicit permission grant prompt
# to the authentication flow for non-Labs applications. For now we are just
# allowing application registration on behalf of a user's own resources,
# via the client credentials grant:
# https://oauth.net/2/grant-types/client-credentials/
authorization_grant_type = serializers.CharField(
default=Application.GRANT_CLIENT_CREDENTIALS
)
client_type = serializers.CharField(default=Application.CLIENT_CONFIDENTIAL)

class Meta:
model = Application
read_only = [
"client_id",
"client_secret",
"authorization_grant_type",
"client_type",
]
fields = read_only + ["name", "redirect_uris"]


class SchoolSerializer(serializers.ModelSerializer):
class Meta:
model = School
Expand Down
2 changes: 2 additions & 0 deletions backend/accounts/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from rest_framework import routers

from accounts.views import (
ApplicationViewSet,
DevLoginView,
DevLogoutView,
EmailViewSet,
Expand All @@ -22,6 +23,7 @@
app_name = "accounts"

router = routers.SimpleRouter()
router.register("application", ApplicationViewSet, basename="application")
router.register("me/phonenumber", PhoneNumberViewSet, basename="me-phonenumber")
router.register("me/email", EmailViewSet, basename="me-email")
router.register("majors", MajorViewSet, basename="majors")
Expand Down
19 changes: 19 additions & 0 deletions backend/accounts/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

from accounts.models import Major, School, User
from accounts.serializers import (
ApplicationSerializer,
EmailSerializer,
MajorSerializer,
PhoneNumberSerializer,
Expand Down Expand Up @@ -123,6 +124,24 @@ def get(self, request):
return redirect("accounts:login")


class ApplicationViewSet(viewsets.ModelViewSet):
"""
A ViewSet for managing Applications, through which users can register
confidential client credentials to access API resources on their behalf
(e.g. for external developers writing automated scripts that access authenticated
Penn Labs routes, logged into their own Penn Labs account).
See ApplicationSerializer for an explanation of why we are not currently allowing
applications of other grant types (other than `client-credentials`).
"""

serializer_class = ApplicationSerializer
lookup_field = "client_id"
permission_classes = [IsAuthenticated]

def get_queryset(self):
return self.request.user.oauth2_provider_application.all()


@method_decorator(csrf_exempt, name="dispatch")
class UUIDIntrospectTokenView(IntrospectTokenView):
@staticmethod
Expand Down