From: Radek Czajka Date: Fri, 8 Feb 2019 10:18:58 +0000 (+0100) Subject: Last Piston view replaced using OAuthlib. X-Git-Url: https://git.mdrn.pl/wolnelektury.git/commitdiff_plain/29f694eea94d09bd66976321ddfd80ac30b73d38 Last Piston view replaced using OAuthlib. --- diff --git a/src/api/request_validator.py b/src/api/request_validator.py index 6e3c0c22b..916636b91 100644 --- a/src/api/request_validator.py +++ b/src/api/request_validator.py @@ -21,18 +21,37 @@ class PistonRequestValidator(RequestValidator): nonce_length = 8, 250 # Because piston.models.Token.key is char(18). + request_token_length = 18, 32 access_token_length = 18, 32 + # TODO: oauthlib request-access switch. def check_client_key(self, client_key): """We control the keys anyway.""" return True + def get_request_token_secret(self, client_key, token, request): + return request.token.secret + def get_access_token_secret(self, client_key, token, request): return request.token.secret def get_default_realms(self, client_key, request): return ['API'] + def validate_request_token(self, client_key, token, request): + try: + token = Token.objects.get( + token_type=Token.REQUEST, + consumer__key=client_key, + key=token, + is_approved=True, + ) + except Token.DoesNotExist: + return False + else: + request.token = token + return True + def validate_access_token(self, client_key, token, request): try: token = Token.objects.get( @@ -76,6 +95,9 @@ class PistonRequestValidator(RequestValidator): def validate_redirect_uri(self, *args, **kwargs): return True + def validate_verifier(self, client_key, token, verifier, request): + return True + def get_client_secret(self, client_key, request): return request.oauth_consumer.secret @@ -88,6 +110,16 @@ class PistonRequestValidator(RequestValidator): consumer=request.oauth_consumer, ) + def save_access_token(self, token, request): + Token.objects.create( + token_type=Token.ACCESS, + timestamp=request.timestamp, + key=token['oauth_token'], + secret=token['oauth_token_secret'], + consumer=request.oauth_consumer, + user=request.token.user, + ) + def verify_request_token(self, token, request): return Token.objects.filter( token_type=Token.REQUEST, key=token, is_approved=False @@ -108,3 +140,10 @@ class PistonRequestValidator(RequestValidator): def get_redirect_uri(self, token, request): return request.redirect_uri + + def invalidate_request_token(self, client_key, request_token, request): + Token.objects.filter( + token_type=Token.REQUEST, + key=request_token, + consumer__key=client_key, + ) diff --git a/src/api/tests/tests.py b/src/api/tests/tests.py index ee3d66e6f..c8e07d26c 100644 --- a/src/api/tests/tests.py +++ b/src/api/tests/tests.py @@ -45,7 +45,7 @@ class ApiTest(TestCase): with open(filename) as f: good_content = f.read().rstrip() self.assertEqual(content, good_content, content) - + def assert_json_response(self, url, name): data = self.load_json(url) filename = path.join(path.dirname(__file__), 'res', 'responses', name) diff --git a/src/api/urls.py b/src/api/urls.py index 5936e1b64..8f9914113 100644 --- a/src/api/urls.py +++ b/src/api/urls.py @@ -5,7 +5,6 @@ from django.conf.urls import url, include from django.views.decorators.csrf import csrf_exempt from django.views.generic import TemplateView -from piston.authentication import oauth_access_token import catalogue.views from api import handlers from api.piston_patch import oauth_user_auth @@ -15,7 +14,7 @@ from . import views urlpatterns = [ url(r'^oauth/request_token/$', views.OAuth1RequestTokenView.as_view()), url(r'^oauth/authorize/$', oauth_user_auth, name='oauth_user_auth'), - url(r'^oauth/access_token/$', csrf_exempt(oauth_access_token)), + url(r'^oauth/access_token/$', csrf_exempt(views.OAuth1AccessTokenView.as_view())), url(r'^$', TemplateView.as_view(template_name='api/main.html'), name='api'), diff --git a/src/api/views.py b/src/api/views.py index 3cf957ed9..518445dd0 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -3,8 +3,9 @@ # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # from django.http import Http404 +from django.views.generic.base import View from oauthlib.common import urlencode -from oauthlib.oauth1 import RequestTokenEndpoint +from oauthlib.oauth1 import RequestTokenEndpoint, AccessTokenEndpoint from piston.models import KEY_SIZE, SECRET_SIZE from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response @@ -34,7 +35,7 @@ class OAuth1RequestTokenEndpoint(RequestTokenEndpoint): return urlencode(token.items()) -class OAuth1RequestTokenView(APIView): +class OAuth1RequestTokenView(View): def __init__(self): self.endpoint = OAuth1RequestTokenEndpoint(PistonRequestValidator()) @@ -46,6 +47,37 @@ class OAuth1RequestTokenView(APIView): ) +class OAuth1AccessTokenEndpoint(AccessTokenEndpoint): + def _create_request(self, *args, **kwargs): + r = super(OAuth1AccessTokenEndpoint, self)._create_request(*args, **kwargs) + r.verifier = 'x' * 20 + return r + + def create_access_token(self, request, credentials): + request.realms = self.request_validator.get_realms( + request.resource_owner_key, request) + token = { + 'oauth_token': self.token_generator()[:KEY_SIZE], + 'oauth_token_secret': self.token_generator()[:SECRET_SIZE], + 'oauth_authorized_realms': ' '.join(request.realms) + } + token.update(credentials) + self.request_validator.save_access_token(token, request) + return urlencode(token.items()) + + +class OAuth1AccessTokenView(View): + def __init__(self): + self.endpoint = OAuth1AccessTokenEndpoint(PistonRequestValidator()) + + def dispatch(self, request): + return oauthlib_response( + self.endpoint.create_access_token_response( + **oauthlib_request(request) + ) + ) + + class UserView(RetrieveAPIView): permission_classes = [IsAuthenticated] serializer_class = serializers.UserSerializer