From 25ef7b5675952ec7ec476f174f04d4e6d030966b Mon Sep 17 00:00:00 2001 From: = Date: Mon, 2 Sep 2019 09:42:24 -0500 Subject: [PATCH] Fixing functionality --- CHANGELOG | 16 +++++++++++++++ requirements.txt | 2 ++ sqrl/admin.py | 29 +++++++++++++++++++++++++++- sqrl/forms.py | 4 ++++ sqrl/response.py | 6 +++--- sqrl/sqrl.py | 2 +- sqrl/static/sqrl/sqrl.js | 4 +++- sqrl/templates/admin/base.html | 2 +- sqrl/templates/sqrl/login.html | 2 +- sqrl/templates/sqrl/register.html | 5 +++-- sqrl/templates/sqrl/sqrl-dropin.html | 9 ++------- sqrl/templatetags/sqrl.py | 13 +++++-------- sqrl/urls.py | 2 ++ sqrl/views.py | 7 +++++-- 14 files changed, 76 insertions(+), 27 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6508aea..bf12dbc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,19 @@ +Mon, 02 Sep 2019 09:42:24 -0500 +Keaton +Fixing functionality + +A bare-bones test server was set up and account creation and authentication was +achieved through SQRL. Old documentation needs to be updated, and new +documentation needs to be written (mostly for using the drop-in login). + +At this point, the SQRL authentication protocol for Django is functional! + +Further work needs to be done to test drop-in support for already-running sites. +If possible, that would be the ideal end goal; making it as easy as possible to +propagate SQRL through the internet. + +-------------------- + Mon, 02 Sep 2019 04:56:45 -0500 Keaton Completing functional conversions diff --git a/requirements.txt b/requirements.txt index 1da7fc0..e8c729a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,3 @@ +Django +django-braces ed25519 diff --git a/sqrl/admin.py b/sqrl/admin.py index 8c38f3f..e7d7db6 100644 --- a/sqrl/admin.py +++ b/sqrl/admin.py @@ -1,3 +1,30 @@ +# -*- coding: utf-8 -*- + from django.contrib import admin -# Register your models here. +from .models import SQRLIdentity, SQRLNut + + +class SQRLIdentityAdmin(admin.ModelAdmin): + model = SQRLIdentity + list_display = ( + 'user', + 'is_enabled', + 'is_only_sqrl', + ) + raw_id_fields = ( + 'user', + ) + + +class SQRLNutAdmin(admin.ModelAdmin): + model = SQRLNut + list_display = ( + 'nonce', + 'is_transaction_complete', + 'ip_address', + ) + + +admin.site.register(SQRLNut, SQRLNutAdmin) +admin.site.register(SQRLIdentity, SQRLIdentityAdmin) diff --git a/sqrl/forms.py b/sqrl/forms.py index a595032..5dac433 100644 --- a/sqrl/forms.py +++ b/sqrl/forms.py @@ -190,6 +190,10 @@ class RequestForm(forms.Form): pidk = self.cleaned_data['client'].get('pidk') pids = self.cleaned_data.get('pids') + if not any((pids, pidk)): + # There are no previous ID key/secrets, which shouldn't break the validation. + return pids + if not all((pids, pidk)): raise forms.ValidationError( 'Cannot validate previous ID signature without server knowing pid public and secret keys.' diff --git a/sqrl/response.py b/sqrl/response.py index dd4c5f8..82b4682 100644 --- a/sqrl/response.py +++ b/sqrl/response.py @@ -45,11 +45,11 @@ class SQRLHttpResponse(HttpResponse): for k, v in normalized_data.items(): self['X-SQRL-{}'.format(k)] = v - log.debug('Response encoded data:\n{}' + log.error('Response encoded data:\n{}' ''.format(content)) - log.debug('Response data:\n{}' + log.error('Response data:\n{}' ''.format(pformat(normalized_data))) - log.debug('Response TIF breakdown:\n{}' + log.error('Response TIF breakdown:\n{}' ''.format(pformat(TIF(int(data['tif'], 16)).breakdown()))) def sign_response(self, nut, data): diff --git a/sqrl/sqrl.py b/sqrl/sqrl.py index 2bdb90a..4754429 100644 --- a/sqrl/sqrl.py +++ b/sqrl/sqrl.py @@ -139,7 +139,7 @@ class SQRLInitialization(object): """ return ( '{scheme}://{host}{url}' - ''.format(scheme='sqrl', if self.request.is_secure() else 'qrl', + ''.format(scheme='sqrl' if self.request.is_secure() else 'qrl', host=self.request.get_host(), url=self.url) ) diff --git a/sqrl/static/sqrl/sqrl.js b/sqrl/static/sqrl/sqrl.js index 0f61af4..a41e330 100644 --- a/sqrl/static/sqrl/sqrl.js +++ b/sqrl/static/sqrl/sqrl.js @@ -4,7 +4,7 @@ return input.length > 0 ? input[0].value : null; }, current_url = window.location.href, - sqrl_frequency = 1500, + sqrl_frequency = 2500, sqrl_call = function() { setTimeout(sqrl_handler, sqrl_frequency); }, @@ -29,6 +29,7 @@ var data = JSON.parse(this.responseText); if (data.transaction_complete === true) { if (data.redirect_to !== undefined) { + console.log(data.redirect_to); window.location.href = data.redirect_to; } else { console.error('Server indicated that SQRL transaction is complete ' + @@ -44,6 +45,7 @@ try { request.send(null); } catch (exception) { + console.log("stopping requests due to error??"); // do not send anymore requests if error occurred } }; diff --git a/sqrl/templates/admin/base.html b/sqrl/templates/admin/base.html index 5a22282..cbb4351 100644 --- a/sqrl/templates/admin/base.html +++ b/sqrl/templates/admin/base.html @@ -14,6 +14,6 @@ {% if user.has_usable_password %} {% trans 'Change password' %} / {% endif %} - {% trans 'Manage SQRL' %} / + {% trans 'Manage SQRL' %} / {% trans 'Log out' %} {% endblock %} diff --git a/sqrl/templates/sqrl/login.html b/sqrl/templates/sqrl/login.html index 1ecb89d..19b8cf1 100644 --- a/sqrl/templates/sqrl/login.html +++ b/sqrl/templates/sqrl/login.html @@ -12,7 +12,7 @@

{% sqrl as session_sqrl %} - {% sqrl_login_dropin session_sqrl %} + {% sqrl_login_dropin session_sqrl login %} {% endblock %} {% comment %} diff --git a/sqrl/templates/sqrl/register.html b/sqrl/templates/sqrl/register.html index 9120b86..2b4b111 100644 --- a/sqrl/templates/sqrl/register.html +++ b/sqrl/templates/sqrl/register.html @@ -7,11 +7,12 @@

Already have account? - Login here to associate - SQRL identity with existing account. + Login here to associate + SQRL identity with an existing account.

+ {% csrf_token %} {{ form.as_p }}
diff --git a/sqrl/templates/sqrl/sqrl-dropin.html b/sqrl/templates/sqrl/sqrl-dropin.html index 442d6f2..2d864dd 100644 --- a/sqrl/templates/sqrl/sqrl-dropin.html +++ b/sqrl/templates/sqrl/sqrl-dropin.html @@ -28,13 +28,8 @@ - {% if session_sqrl.method == "manage" %} - {# redirect to manage page after successful SQRL transaction #} - - - {% else %} - - {% endif %} + + diff --git a/sqrl/templatetags/sqrl.py b/sqrl/templatetags/sqrl.py index 7d4620e..2d596db 100644 --- a/sqrl/templatetags/sqrl.py +++ b/sqrl/templatetags/sqrl.py @@ -7,7 +7,6 @@ from ..sqrl import SQRLInitialization register = template.Library() -print(register) @register.simple_tag(takes_context=True) @@ -16,7 +15,7 @@ def sqrl(context): @register.inclusion_tag('sqrl/sqrl-dropin.html') -def sqrl_login_dropin(session_sqrl, method="login"): +def sqrl_login_dropin(session_sqrl, redir): """ Creates a drop-in SQRL element in your template pages. Add it to your login template to make it SQRL-aware. @@ -24,19 +23,17 @@ def sqrl_login_dropin(session_sqrl, method="login"): Usage: {% load sqrl %} {% sqrl as session_sqrl %} - {% sqrl_login_dropin session_sqrl [method=METHOD] %} + {% sqrl_login_dropin session_sqrl REDIR %} - METHOD is an optional argument that changes the way the form - behaves. Possible arguments are: - - login: The default method. No special redirections occur - - manage: Will redirect the user to sqrl/manage + REDIR is the registered name of the page to move to once the login + is completed. Notes: The drop-in is defaulted to a max-width of 300px. Set the width property of the parent if you want or need it smaller. You will likely want to change the font-size as well in this case. """ - return {'session_sqrl':session_sqrl, 'method': method} + return {'session_sqrl':session_sqrl, 'redir': reverse(redir)} @register.simple_tag diff --git a/sqrl/urls.py b/sqrl/urls.py index 86d9c4d..e032870 100644 --- a/sqrl/urls.py +++ b/sqrl/urls.py @@ -7,6 +7,7 @@ from .views import ( SQRLIdentityManagementView, SQRLLoginView, SQRLStatusView, + AdminSiteSQRLIdentityManagementView ) app_name = "sqrl" @@ -17,4 +18,5 @@ urlpatterns = [ path("manage/", SQRLIdentityManagementView.as_view(), name='manage'), path("register/",SQRLCompleteRegistrationView.as_view(), name='complete-registration'), re_path(r"^status/(?P[A-Za-z0-9_-]{43})/$", SQRLStatusView.as_view(), name='status'), + path('admin/sqrl_manage/', AdminSiteSQRLIdentityManagementView.as_view(), name='admin-sqrl_manage'), ] diff --git a/sqrl/views.py b/sqrl/views.py index 016f185..d73039e 100644 --- a/sqrl/views.py +++ b/sqrl/views.py @@ -17,6 +17,8 @@ from django.urls import reverse from django.http import Http404, HttpResponse, JsonResponse, QueryDict from django.shortcuts import get_object_or_404, redirect from django.views.generic import FormView, TemplateView, View +from django.utils.decorators import method_decorator +from django.views.decorators.csrf import csrf_exempt from .backends import SQRL_MODEL_BACKEND from .exceptions import TIF, TIFException @@ -51,7 +53,7 @@ class SQRLLoginView(TemplateView): """ template_name = 'sqrl/login.html' - +@method_decorator(csrf_exempt,"dispatch") class SQRLStatusView(View): """ Ajax view which returns the status of the SQRL transaction back to the user. @@ -96,7 +98,7 @@ class SQRLStatusView(View): else: url = self.success_url - if all([not self.request.user.is_authenticated(), + if all([not self.request.user.is_authenticated, SQRL_IDENTITY_SESSION_KEY in self.request.session]): return reverse('sqrl:complete-registration') + '?next={}'.format(url) else: @@ -140,6 +142,7 @@ class SQRLStatusView(View): return JsonResponse(data) +@method_decorator(csrf_exempt,"dispatch") class SQRLAuthView(View): """ This is the main view responsible for all interactions with SQRL client.