Fixing functionality
This commit is contained in:
parent
edb16382f3
commit
25ef7b5675
14 changed files with 76 additions and 27 deletions
16
CHANGELOG
16
CHANGELOG
|
@ -1,3 +1,19 @@
|
||||||
|
Mon, 02 Sep 2019 09:42:24 -0500
|
||||||
|
Keaton <kii-chan@tutanota.com>
|
||||||
|
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
|
Mon, 02 Sep 2019 04:56:45 -0500
|
||||||
Keaton <kii-chan@tutanota.com>
|
Keaton <kii-chan@tutanota.com>
|
||||||
Completing functional conversions
|
Completing functional conversions
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
|
Django
|
||||||
|
django-braces
|
||||||
ed25519
|
ed25519
|
||||||
|
|
|
@ -1,3 +1,30 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from django.contrib import admin
|
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)
|
||||||
|
|
|
@ -190,6 +190,10 @@ class RequestForm(forms.Form):
|
||||||
pidk = self.cleaned_data['client'].get('pidk')
|
pidk = self.cleaned_data['client'].get('pidk')
|
||||||
pids = self.cleaned_data.get('pids')
|
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)):
|
if not all((pids, pidk)):
|
||||||
raise forms.ValidationError(
|
raise forms.ValidationError(
|
||||||
'Cannot validate previous ID signature without server knowing pid public and secret keys.'
|
'Cannot validate previous ID signature without server knowing pid public and secret keys.'
|
||||||
|
|
|
@ -45,11 +45,11 @@ class SQRLHttpResponse(HttpResponse):
|
||||||
for k, v in normalized_data.items():
|
for k, v in normalized_data.items():
|
||||||
self['X-SQRL-{}'.format(k)] = v
|
self['X-SQRL-{}'.format(k)] = v
|
||||||
|
|
||||||
log.debug('Response encoded data:\n{}'
|
log.error('Response encoded data:\n{}'
|
||||||
''.format(content))
|
''.format(content))
|
||||||
log.debug('Response data:\n{}'
|
log.error('Response data:\n{}'
|
||||||
''.format(pformat(normalized_data)))
|
''.format(pformat(normalized_data)))
|
||||||
log.debug('Response TIF breakdown:\n{}'
|
log.error('Response TIF breakdown:\n{}'
|
||||||
''.format(pformat(TIF(int(data['tif'], 16)).breakdown())))
|
''.format(pformat(TIF(int(data['tif'], 16)).breakdown())))
|
||||||
|
|
||||||
def sign_response(self, nut, data):
|
def sign_response(self, nut, data):
|
||||||
|
|
|
@ -139,7 +139,7 @@ class SQRLInitialization(object):
|
||||||
"""
|
"""
|
||||||
return (
|
return (
|
||||||
'{scheme}://{host}{url}'
|
'{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(),
|
host=self.request.get_host(),
|
||||||
url=self.url)
|
url=self.url)
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
return input.length > 0 ? input[0].value : null;
|
return input.length > 0 ? input[0].value : null;
|
||||||
},
|
},
|
||||||
current_url = window.location.href,
|
current_url = window.location.href,
|
||||||
sqrl_frequency = 1500,
|
sqrl_frequency = 2500,
|
||||||
sqrl_call = function() {
|
sqrl_call = function() {
|
||||||
setTimeout(sqrl_handler, sqrl_frequency);
|
setTimeout(sqrl_handler, sqrl_frequency);
|
||||||
},
|
},
|
||||||
|
@ -29,6 +29,7 @@
|
||||||
var data = JSON.parse(this.responseText);
|
var data = JSON.parse(this.responseText);
|
||||||
if (data.transaction_complete === true) {
|
if (data.transaction_complete === true) {
|
||||||
if (data.redirect_to !== undefined) {
|
if (data.redirect_to !== undefined) {
|
||||||
|
console.log(data.redirect_to);
|
||||||
window.location.href = data.redirect_to;
|
window.location.href = data.redirect_to;
|
||||||
} else {
|
} else {
|
||||||
console.error('Server indicated that SQRL transaction is complete ' +
|
console.error('Server indicated that SQRL transaction is complete ' +
|
||||||
|
@ -44,6 +45,7 @@
|
||||||
try {
|
try {
|
||||||
request.send(null);
|
request.send(null);
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
|
console.log("stopping requests due to error??");
|
||||||
// do not send anymore requests if error occurred
|
// do not send anymore requests if error occurred
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,6 @@
|
||||||
{% if user.has_usable_password %}
|
{% if user.has_usable_password %}
|
||||||
<a href="{% url 'admin:password_change' %}">{% trans 'Change password' %}</a> /
|
<a href="{% url 'admin:password_change' %}">{% trans 'Change password' %}</a> /
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'admin-sqrl_manage' %}">{% trans 'Manage SQRL' %}</a> /
|
<a href="{% url 'sqrl:admin-sqrl_manage' %}">{% trans 'Manage SQRL' %}</a> /
|
||||||
<a href="{% url 'admin:logout' %}">{% trans 'Log out' %}</a>
|
<a href="{% url 'admin:logout' %}">{% trans 'Log out' %}</a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{% sqrl as session_sqrl %}
|
{% sqrl as session_sqrl %}
|
||||||
{% sqrl_login_dropin session_sqrl %}
|
{% sqrl_login_dropin session_sqrl login %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% comment %}
|
{% comment %}
|
||||||
|
|
|
@ -7,11 +7,12 @@
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Already have account?
|
Already have account?
|
||||||
Login <a href="{% url 'login' %}">here</a> to associate
|
Login <a href="{% url 'sqrl:login' %}">here</a> to associate
|
||||||
SQRL identity with existing account.
|
SQRL identity with an existing account.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
{{ form.as_p }}
|
{{ form.as_p }}
|
||||||
<input type="submit">
|
<input type="submit">
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -28,13 +28,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input type="hidden" name="nut" value="{{ session_sqrl.nut.nonce }}">
|
<input type="hidden" name="nut" value="{{ session_sqrl.nut.nonce }}">
|
||||||
{% if session_sqrl.method == "manage" %}
|
<input type="hidden" name="next" value="{{ redir }}">
|
||||||
{# redirect to manage page after successful SQRL transaction #}
|
<input type="submit" value="Authenticate using SQRL">
|
||||||
<input type="hidden" name="next" value="{% url 'sqrl:manage' %}">
|
|
||||||
<input type="submit" value="Manage SQRL">
|
|
||||||
{% else %}
|
|
||||||
<input type="submit" value="Log in using SQRL">
|
|
||||||
{% endif %}
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<script>SQRL_CHECK_URL="{% sqrl_status_url_script_tag session_sqrl %}"</script>
|
<script>SQRL_CHECK_URL="{% sqrl_status_url_script_tag session_sqrl %}"</script>
|
||||||
|
|
|
@ -7,7 +7,6 @@ from ..sqrl import SQRLInitialization
|
||||||
|
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
print(register)
|
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag(takes_context=True)
|
@register.simple_tag(takes_context=True)
|
||||||
|
@ -16,7 +15,7 @@ def sqrl(context):
|
||||||
|
|
||||||
|
|
||||||
@register.inclusion_tag('sqrl/sqrl-dropin.html')
|
@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.
|
Creates a drop-in SQRL element in your template pages.
|
||||||
Add it to your login template to make it SQRL-aware.
|
Add it to your login template to make it SQRL-aware.
|
||||||
|
@ -24,19 +23,17 @@ def sqrl_login_dropin(session_sqrl, method="login"):
|
||||||
Usage:
|
Usage:
|
||||||
{% load sqrl %}
|
{% load sqrl %}
|
||||||
{% sqrl as session_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
|
REDIR is the registered name of the page to move to once the login
|
||||||
behaves. Possible arguments are:
|
is completed.
|
||||||
- login: The default method. No special redirections occur
|
|
||||||
- manage: Will redirect the user to sqrl/manage
|
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
The drop-in is defaulted to a max-width of 300px. Set the width
|
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
|
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.
|
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
|
@register.simple_tag
|
||||||
|
|
|
@ -7,6 +7,7 @@ from .views import (
|
||||||
SQRLIdentityManagementView,
|
SQRLIdentityManagementView,
|
||||||
SQRLLoginView,
|
SQRLLoginView,
|
||||||
SQRLStatusView,
|
SQRLStatusView,
|
||||||
|
AdminSiteSQRLIdentityManagementView
|
||||||
)
|
)
|
||||||
|
|
||||||
app_name = "sqrl"
|
app_name = "sqrl"
|
||||||
|
@ -17,4 +18,5 @@ urlpatterns = [
|
||||||
path("manage/", SQRLIdentityManagementView.as_view(), name='manage'),
|
path("manage/", SQRLIdentityManagementView.as_view(), name='manage'),
|
||||||
path("register/",SQRLCompleteRegistrationView.as_view(), name='complete-registration'),
|
path("register/",SQRLCompleteRegistrationView.as_view(), name='complete-registration'),
|
||||||
re_path(r"^status/(?P<transaction>[A-Za-z0-9_-]{43})/$", SQRLStatusView.as_view(), name='status'),
|
re_path(r"^status/(?P<transaction>[A-Za-z0-9_-]{43})/$", SQRLStatusView.as_view(), name='status'),
|
||||||
|
path('admin/sqrl_manage/', AdminSiteSQRLIdentityManagementView.as_view(), name='admin-sqrl_manage'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -17,6 +17,8 @@ from django.urls import reverse
|
||||||
from django.http import Http404, HttpResponse, JsonResponse, QueryDict
|
from django.http import Http404, HttpResponse, JsonResponse, QueryDict
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
from django.views.generic import FormView, TemplateView, View
|
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 .backends import SQRL_MODEL_BACKEND
|
||||||
from .exceptions import TIF, TIFException
|
from .exceptions import TIF, TIFException
|
||||||
|
@ -51,7 +53,7 @@ class SQRLLoginView(TemplateView):
|
||||||
"""
|
"""
|
||||||
template_name = 'sqrl/login.html'
|
template_name = 'sqrl/login.html'
|
||||||
|
|
||||||
|
@method_decorator(csrf_exempt,"dispatch")
|
||||||
class SQRLStatusView(View):
|
class SQRLStatusView(View):
|
||||||
"""
|
"""
|
||||||
Ajax view which returns the status of the SQRL transaction back to the user.
|
Ajax view which returns the status of the SQRL transaction back to the user.
|
||||||
|
@ -96,7 +98,7 @@ class SQRLStatusView(View):
|
||||||
else:
|
else:
|
||||||
url = self.success_url
|
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]):
|
SQRL_IDENTITY_SESSION_KEY in self.request.session]):
|
||||||
return reverse('sqrl:complete-registration') + '?next={}'.format(url)
|
return reverse('sqrl:complete-registration') + '?next={}'.format(url)
|
||||||
else:
|
else:
|
||||||
|
@ -140,6 +142,7 @@ class SQRLStatusView(View):
|
||||||
return JsonResponse(data)
|
return JsonResponse(data)
|
||||||
|
|
||||||
|
|
||||||
|
@method_decorator(csrf_exempt,"dispatch")
|
||||||
class SQRLAuthView(View):
|
class SQRLAuthView(View):
|
||||||
"""
|
"""
|
||||||
This is the main view responsible for all interactions with SQRL client.
|
This is the main view responsible for all interactions with SQRL client.
|
||||||
|
|
Loading…
Reference in a new issue