Added application token for easier auth

This commit is contained in:
Agate 2020-08-19 11:41:17 +02:00
commit f2e5969c44
9 changed files with 130 additions and 4 deletions

View file

@ -129,6 +129,7 @@ class SuperUserFactory(UserFactory):
class ApplicationFactory(factory.django.DjangoModelFactory):
name = factory.Faker("name")
redirect_uris = factory.Faker("url")
token = factory.Faker("uuid4")
client_type = models.Application.CLIENT_CONFIDENTIAL
authorization_grant_type = models.Application.GRANT_AUTHORIZATION_CODE
scope = "read"

View file

@ -0,0 +1,18 @@
# Generated by Django 3.0.8 on 2020-08-19 08:58
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0019_auto_20200718_0741'),
]
operations = [
migrations.AddField(
model_name='application',
name='token',
field=models.CharField(blank=True, max_length=50, null=True, unique=True),
),
]

View file

@ -31,8 +31,8 @@ from funkwhale_api.federation import models as federation_models
from funkwhale_api.federation import utils as federation_utils
def get_token():
return binascii.b2a_hex(os.urandom(15)).decode("utf-8")
def get_token(length=15):
return binascii.b2a_hex(os.urandom(length)).decode("utf-8")
PERMISSIONS_CONFIGURATION = {
@ -350,6 +350,7 @@ class Invitation(models.Model):
class Application(oauth2_models.AbstractApplication):
scope = models.TextField(blank=True)
token = models.CharField(max_length=50, blank=True, null=True, unique=True)
@property
def normalized_scopes(self):

View file

@ -10,6 +10,12 @@ class ApplicationSerializer(serializers.ModelSerializer):
model = models.Application
fields = ["client_id", "name", "scopes", "created", "updated"]
def to_representation(self, obj):
repr = super().to_representation(obj)
if obj.user_id:
repr["token"] = obj.token
return repr
class CreateApplicationSerializer(serializers.ModelSerializer):
name = serializers.CharField(required=True, max_length=255)
@ -27,3 +33,9 @@ class CreateApplicationSerializer(serializers.ModelSerializer):
"redirect_uris",
]
read_only_fields = ["client_id", "client_secret", "created", "updated"]
def to_representation(self, obj):
repr = super().to_representation(obj)
if obj.user_id:
repr["token"] = obj.token
return repr

View file

@ -4,7 +4,8 @@ import urllib.parse
from django import http
from django.utils import timezone
from django.db.models import Q
from rest_framework import mixins, permissions, views, viewsets
from rest_framework import mixins, permissions, response, views, viewsets
from rest_framework.decorators import action
from oauth2_provider import exceptions as oauth2_exceptions
from oauth2_provider import views as oauth_views
@ -32,6 +33,7 @@ class ApplicationViewSet(
"destroy": "write:security",
"update": "write:security",
"partial_update": "write:security",
"refresh_token": "write:security",
"list": "read:security",
}
lookup_field = "client_id"
@ -54,6 +56,7 @@ class ApplicationViewSet(
client_type=models.Application.CLIENT_CONFIDENTIAL,
authorization_grant_type=models.Application.GRANT_AUTHORIZATION_CODE,
user=self.request.user if self.request.user.is_authenticated else None,
token=models.get_token(15) if self.request.user.is_authenticated else None,
)
def get_serializer(self, *args, **kwargs):
@ -70,10 +73,31 @@ class ApplicationViewSet(
def get_queryset(self):
qs = super().get_queryset()
if self.action in ["list", "destroy", "update", "partial_update"]:
if self.action in [
"list",
"destroy",
"update",
"partial_update",
"refresh_token",
]:
qs = qs.filter(user=self.request.user)
return qs
@action(
detail=True,
methods=["post"],
url_name="refresh_token",
url_path="refresh-token",
)
def refresh_token(self, request, *args, **kwargs):
app = self.get_object()
if not app.user_id or request.user != app.user:
return response.Response(status=404)
app.token = models.get_token(15)
app.save(update_fields=["token"])
serializer = serializers.CreateApplicationSerializer(app)
return response.Response(serializer.data, status=200)
class GrantViewSet(
mixins.RetrieveModelMixin,