From 93be2f5a3209b388f591b6731788f78aab2c99b5 Mon Sep 17 00:00:00 2001 From: Danielle McLean Date: Thu, 26 Oct 2017 11:35:57 +1100 Subject: [PATCH] Half-implement an IndieAuth authorization endpoint - it accepts the right parameters, verifies your client_id, and displays a prompt, but you can't actually approve the auth yet --- Pipfile | 1 + Pipfile.lock | 65 ++++++++++++++++++++- lemonauth/templates/lemonauth/indie.html | 24 ++++++++ lemonauth/urls.py | 1 + lemonauth/views/__init__.py | 1 + lemonauth/views/indie.py | 53 +++++++++++++++++ lemoncurry/templates/lemoncurry/layout.html | 1 + 7 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 lemonauth/templates/lemonauth/indie.html create mode 100644 lemonauth/views/indie.py diff --git a/Pipfile b/Pipfile index eeb9042..ea9df0e 100644 --- a/Pipfile +++ b/Pipfile @@ -22,6 +22,7 @@ qrcode = "*" django-otp-agents = "*" python-slugify = "*" django-markdown-deux = "*" +"mf2py" = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index b42c4f8..591247a 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "c32114b4f91b4ef6f4023a180c8db8c0567a6f9206da1af2136af17dd6026b93" + "sha256": "ead57b340efa8b663100364efa6b9037299456bb3e37d533b6d7c4404608749c" }, "host-environment-markers": { "implementation_name": "cpython", @@ -27,6 +27,28 @@ ] }, "default": { + "beautifulsoup4": { + "hashes": [ + "sha256:7015e76bf32f1f574636c4288399a6de66ce08fb7b2457f628a8d70c0fbabb11", + "sha256:11a9a27b7d3bddc6d86f59fb76afb70e921a25ac2d6cc55b40d072bd68435a76", + "sha256:808b6ac932dccb0a4126558f7dfdcf41710dd44a4ef497a0bb59a77f9f078e89" + ], + "version": "==4.6.0" + }, + "certifi": { + "hashes": [ + "sha256:54a07c09c586b0e4c619f02a5e94e36619da8e2b053e20f594348c0611803704", + "sha256:40523d2efb60523e113b44602298f0960e900388cf3bb6043f645cf57ea9e3f5" + ], + "version": "==2017.7.27.1" + }, + "chardet": { + "hashes": [ + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691", + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae" + ], + "version": "==3.0.4" + }, "django": { "hashes": [ "sha256:7ab6a9c798a5f9f359ee6da3677211f883fb02ef32cebe9b29751eb7a871febf", @@ -120,6 +142,20 @@ ], "version": "==19.7.1" }, + "html5lib": { + "hashes": [ + "sha256:b8934484cf22f1db684c0fae27569a0db404d0208d20163fbf51cc537245d008", + "sha256:ee747c0ffd3028d2722061936b5c65ee4fe13c8e4613519b4447123fc4546298" + ], + "version": "==0.999999999" + }, + "idna": { + "hashes": [ + "sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4", + "sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f" + ], + "version": "==2.6" + }, "lxml": { "hashes": [ "sha256:7a8715539adb41c78129983ba69d852e0102a3f51d559eeb91dce1f6290c4ad0", @@ -159,6 +195,12 @@ ], "version": "==2.3.4" }, + "mf2py": { + "hashes": [ + "sha256:021b675c0732bdbc3b8c153e1ee8e1f476c3d0ffc56a7908f9e9f90147c5fccd" + ], + "version": "==1.0.5" + }, "olefile": { "hashes": [ "sha256:61f2ca0cd0aa77279eb943c07f607438edf374096b66332fae1ee64a6f0f73ad" @@ -300,6 +342,13 @@ ], "version": "==2.10.6" }, + "requests": { + "hashes": [ + "sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b", + "sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e" + ], + "version": "==2.18.4" + }, "rjsmin": { "hashes": [ "sha256:dd9591aa73500b08b7db24367f8d32c6470021f39d5ab4e50c7c02e4401386f1" @@ -319,6 +368,20 @@ "sha256:280a6ab88e1f2eb5af79edff450021a0d3f0448952847cd79677e55e58bad051" ], "version": "==0.4.21" + }, + "urllib3": { + "hashes": [ + "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b", + "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f" + ], + "version": "==1.22" + }, + "webencodings": { + "hashes": [ + "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", + "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" + ], + "version": "==0.5.1" } }, "develop": {} diff --git a/lemonauth/templates/lemonauth/indie.html b/lemonauth/templates/lemonauth/indie.html new file mode 100644 index 0000000..adacbc2 --- /dev/null +++ b/lemonauth/templates/lemonauth/indie.html @@ -0,0 +1,24 @@ +{% extends 'lemoncurry/layout.html' %} +{% block main %} +
+
+

+ {{ params.client_id }} +

+ +
+

do you want to confirm your identity, {{ params.me }}, with this app?

+
+ + + + {% csrf_token %} +
+
+{% endblock %} diff --git a/lemonauth/urls.py b/lemonauth/urls.py index a52aa57..4107cf2 100644 --- a/lemonauth/urls.py +++ b/lemonauth/urls.py @@ -5,4 +5,5 @@ app_name = 'lemonauth' urlpatterns = [ url('^login$', views.login, name='login'), url('^logout$', views.logout, name='logout'), + url('^indie$', views.IndieView.as_view(), name='indie'), ] diff --git a/lemonauth/views/__init__.py b/lemonauth/views/__init__.py index 927e309..c53d50a 100644 --- a/lemonauth/views/__init__.py +++ b/lemonauth/views/__init__.py @@ -1,2 +1,3 @@ from .login import login from .logout import logout +from .indie import IndieView diff --git a/lemonauth/views/indie.py b/lemonauth/views/indie.py new file mode 100644 index 0000000..7ca2e09 --- /dev/null +++ b/lemonauth/views/indie.py @@ -0,0 +1,53 @@ +import mf2py + +from django.contrib.auth.decorators import login_required +from django.http import HttpResponseForbidden, HttpResponseBadRequest +from django.shortcuts import render +from django.utils.decorators import method_decorator +from django.views.generic import TemplateView +from lemoncurry import breadcrumbs + +breadcrumbs.add('lemonauth:indie', label='indieauth', parent='home:index') + + +class IndieView(TemplateView): + template_name = 'lemonauth/indie.html' + required_params = ('me', 'client_id', 'redirect_uri') + + @method_decorator(login_required) + def dispatch(self, *args, **kwargs): + return super(IndieView, self).dispatch(*args, **kwargs) + + def get(self, request): + params = request.GET + for param in self.required_params: + if param not in params: + return HttpResponseBadRequest( + 'parameter {0} is required'.format(param), + content_type='text/plain', + ) + + me = params['me'] + user = '{0}://{1}{2}'.format( + request.scheme, + request.META['HTTP_HOST'], + request.user.url + ) + if me != user: + return HttpResponseForbidden( + 'you are logged in but not as {0}'.format(me), + content_type='text/plain', + ) + + client = mf2py.parse(url=params['client_id']) + rels = client['rel-urls'].get(params['redirect_uri'], {}).get('rels', ()) + if 'redirect_uri' not in rels: + return HttpResponseBadRequest( + 'your redirect_uri is not published on your client_id page', + content_type='text/plain' + ) + + return render(request, self.template_name, { + 'params': params, + 'title': 'indieauth', + }) diff --git a/lemoncurry/templates/lemoncurry/layout.html b/lemoncurry/templates/lemoncurry/layout.html index cd01ea5..2914305 100644 --- a/lemoncurry/templates/lemoncurry/layout.html +++ b/lemoncurry/templates/lemoncurry/layout.html @@ -11,6 +11,7 @@ {% include 'meta/meta.html' %} {% placeFavicon %} + {% compress css %}