mirror of
https://github.com/pretix/pretix.git
synced 2026-05-05 15:14:04 +00:00
Auth mechanism
This commit is contained in:
25
src/pretix/api/auth/device.py
Normal file
25
src/pretix/api/auth/device.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from rest_framework import exceptions
|
||||
from rest_framework.authentication import TokenAuthentication
|
||||
|
||||
from pretix.base.models import Device
|
||||
|
||||
|
||||
class DeviceTokenAuthentication(TokenAuthentication):
|
||||
model = Device
|
||||
keyword = 'Device'
|
||||
|
||||
def authenticate_credentials(self, key):
|
||||
model = self.get_model()
|
||||
try:
|
||||
device = model.objects.select_related('organizer').get(api_token=key)
|
||||
except model.DoesNotExist:
|
||||
raise exceptions.AuthenticationFailed('Invalid token.')
|
||||
|
||||
if not device.initialized:
|
||||
raise exceptions.AuthenticationFailed('Device has not been initialized.')
|
||||
|
||||
if not device.api_token:
|
||||
raise exceptions.AuthenticationFailed('Device access has been revoked.')
|
||||
|
||||
return AnonymousUser(), device
|
||||
@@ -1,7 +1,7 @@
|
||||
from rest_framework.permissions import SAFE_METHODS, BasePermission
|
||||
|
||||
from pretix.api.models import OAuthAccessToken
|
||||
from pretix.base.models import Event
|
||||
from pretix.base.models import Device, Event
|
||||
from pretix.base.models.organizer import Organizer, TeamAPIToken
|
||||
from pretix.helpers.security import (
|
||||
SessionInvalid, SessionReauthRequired, assert_session_valid,
|
||||
@@ -9,10 +9,9 @@ from pretix.helpers.security import (
|
||||
|
||||
|
||||
class EventPermission(BasePermission):
|
||||
model = TeamAPIToken
|
||||
|
||||
def has_permission(self, request, view):
|
||||
if not request.user.is_authenticated and not isinstance(request.auth, TeamAPIToken):
|
||||
if not request.user.is_authenticated and not isinstance(request.auth, (Device, TeamAPIToken)):
|
||||
return False
|
||||
|
||||
if request.method not in SAFE_METHODS and hasattr(view, 'write_permission'):
|
||||
@@ -31,7 +30,7 @@ class EventPermission(BasePermission):
|
||||
except SessionReauthRequired:
|
||||
return False
|
||||
|
||||
perm_holder = (request.auth if isinstance(request.auth, TeamAPIToken)
|
||||
perm_holder = (request.auth if isinstance(request.auth, (Device, TeamAPIToken))
|
||||
else request.user)
|
||||
if 'event' in request.resolver_match.kwargs and 'organizer' in request.resolver_match.kwargs:
|
||||
request.event = Event.objects.filter(
|
||||
|
||||
@@ -7,7 +7,8 @@ from rest_framework import routers
|
||||
from pretix.api.views import cart
|
||||
|
||||
from .views import (
|
||||
checkin, event, item, oauth, order, organizer, voucher, waitinglist,
|
||||
checkin, device, event, item, oauth, order, organizer, voucher,
|
||||
waitinglist,
|
||||
)
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
@@ -66,4 +67,5 @@ urlpatterns = [
|
||||
url(r"^oauth/authorize$", oauth.AuthorizationView.as_view(), name="authorize"),
|
||||
url(r"^oauth/token$", oauth.TokenView.as_view(), name="token"),
|
||||
url(r"^oauth/revoke_token$", oauth.RevokeTokenView.as_view(), name="revoke-token"),
|
||||
url(r"^device/initialize", device.InitializeView.as_view(), name="device.initialize"),
|
||||
]
|
||||
|
||||
59
src/pretix/api/views/device.py
Normal file
59
src/pretix/api/views/device.py
Normal file
@@ -0,0 +1,59 @@
|
||||
import logging
|
||||
|
||||
from django.utils.timezone import now
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from pretix.base.models import Device
|
||||
from pretix.base.models.devices import generate_api_token
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class InitializationRequestSerializer(serializers.Serializer):
|
||||
token = serializers.CharField(max_length=190)
|
||||
hardware_brand = serializers.CharField(max_length=190)
|
||||
hardware_model = serializers.CharField(max_length=190)
|
||||
software_brand = serializers.CharField(max_length=190)
|
||||
software_version = serializers.CharField(max_length=190)
|
||||
|
||||
|
||||
class DeviceSerializer(serializers.ModelSerializer):
|
||||
organizer = serializers.SlugRelatedField(slug_field='slug', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Device
|
||||
fields = [
|
||||
'organizer', 'device_id', 'unique_serial', 'api_token',
|
||||
'name'
|
||||
]
|
||||
|
||||
|
||||
class InitializeView(APIView):
|
||||
authentication_classes = tuple()
|
||||
permission_classes = tuple()
|
||||
|
||||
def post(self, request, format=None):
|
||||
serializer = InitializationRequestSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
try:
|
||||
device = Device.objects.get(initialization_token=serializer.validated_data.get('token'))
|
||||
except Device.DoesNotExist:
|
||||
raise ValidationError({'token': ['Unknown initialization token.']})
|
||||
|
||||
if device.initialized:
|
||||
raise ValidationError({'token': ['This initialization token has already been used.']})
|
||||
|
||||
device.initialized = now()
|
||||
device.hardware_brand = serializer.validated_data.get('hardware_brand')
|
||||
device.hardware_model = serializer.validated_data.get('hardware_model')
|
||||
device.software_brand = serializer.validated_data.get('software_brand')
|
||||
device.software_version = serializer.validated_data.get('software_version')
|
||||
device.api_token = generate_api_token()
|
||||
device.save()
|
||||
|
||||
serializer = DeviceSerializer(device)
|
||||
return Response(serializer.data)
|
||||
Reference in New Issue
Block a user