Compare commits
1 Commits
v2.2.1
...
passwordle
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1fbdab069 |
@@ -1,10 +1,7 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
## 2.2.1
|
|
||||||
* Fixed: A missing import Thanks @AndreasDickow
|
|
||||||
|
|
||||||
## 2.2.0
|
## 2.2.0 (Not released)
|
||||||
* Added: MFA_REDIRECT_AFTER_REGISTRATION settings parameter
|
* Added: MFA_REDIRECT_AFTER_REGISTRATION settings parameter
|
||||||
* Fixed: Deprecation error for NULBooleanField
|
|
||||||
|
|
||||||
## 2.1.2
|
## 2.1.2
|
||||||
* Fixed: Getting timestamp on Python 3.7 as ("%s") is raising an exception
|
* Fixed: Getting timestamp on Python 3.7 as ("%s") is raising an exception
|
||||||
@@ -12,7 +9,7 @@
|
|||||||
|
|
||||||
|
|
||||||
## 2.1.1
|
## 2.1.1
|
||||||
* Fixed: FIDO2 version in requirements.txt file.
|
* Fixed: FIDO2 version in requirments.txt file.
|
||||||
|
|
||||||
## 2.1.0
|
## 2.1.0
|
||||||
* Added Support for Touch ID for Mac OSx and iOS 14 on Safari
|
* Added Support for Touch ID for Mac OSx and iOS 14 on Safari
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ Depends on
|
|||||||
1. Somewhere in your app, add a link to 'mfa_home'
|
1. Somewhere in your app, add a link to 'mfa_home'
|
||||||
```<li><a href="{% url 'mfa_home' %}">Security</a> </li>```
|
```<li><a href="{% url 'mfa_home' %}">Security</a> </li>```
|
||||||
|
|
||||||
For Example, See 'example' app
|
For Example, See https://github.com/mkalioby/AutoDeploy/commit/5f1d94b1804e0aa33c79e9e8530ce849d9eb78cc in AutDeploy Project
|
||||||
|
|
||||||
# Going Passwordless
|
# Going Passwordless
|
||||||
|
|
||||||
@@ -182,7 +182,6 @@ function some_func() {
|
|||||||
* [swainn](https://github.com/swainn)
|
* [swainn](https://github.com/swainn)
|
||||||
* [unramk](https://github.com/unramk)
|
* [unramk](https://github.com/unramk)
|
||||||
* [willingham](https://github.com/willingham)
|
* [willingham](https://github.com/willingham)
|
||||||
* [AndreasDickow](https://github.com/AndreasDickow)
|
|
||||||
|
|
||||||
|
|
||||||
# Security contact information
|
# Security contact information
|
||||||
|
|||||||
@@ -28,3 +28,7 @@ def create_session(request,username):
|
|||||||
def logoutView(request):
|
def logoutView(request):
|
||||||
logout(request)
|
logout(request)
|
||||||
return render(request,"logout.html",{})
|
return render(request,"logout.html",{})
|
||||||
|
|
||||||
|
def register(request):
|
||||||
|
if request.method == "GET":
|
||||||
|
return
|
||||||
@@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
<!-- Custom styles for this template-->
|
<!-- Custom styles for this template-->
|
||||||
<link href="{% static 'css/sb-admin.css'%}" rel="stylesheet">
|
<link href="{% static 'css/sb-admin.css'%}" rel="stylesheet">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-dark">
|
<body class="bg-dark">
|
||||||
@@ -29,7 +28,6 @@
|
|||||||
{% if invalid %}
|
{% if invalid %}
|
||||||
<div class="alert alert-danger">Invalid Username or password</div>
|
<div class="alert alert-danger">Invalid Username or password</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<form action="{% url 'login' %}" method="post">
|
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="form-label-group">
|
<div class="form-label-group">
|
||||||
@@ -37,14 +35,9 @@
|
|||||||
<label for="inputUsername">Username</label>
|
<label for="inputUsername">Username</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
|
||||||
<div class="form-label-group">
|
|
||||||
<input type="password" id="inputPassword" name="password" class="form-control" placeholder="Password" required="required">
|
|
||||||
<label for="inputPassword">Password</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button class="btn btn-primary btn-block" type="submit">Login</button>
|
|
||||||
|
<button class="btn btn-primary btn-block" type="button" onclick="authen()">Login</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -56,7 +49,7 @@
|
|||||||
|
|
||||||
<!-- Core plugin JavaScript-->
|
<!-- Core plugin JavaScript-->
|
||||||
<script src="{% static 'vendor/jquery-easing/jquery.easing.min.js'%}"></script>
|
<script src="{% static 'vendor/jquery-easing/jquery.easing.min.js'%}"></script>
|
||||||
|
{% include 'FIDO2/login.html' %}
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ def start(request):
|
|||||||
"""Start Registeration a new FIDO Token"""
|
"""Start Registeration a new FIDO Token"""
|
||||||
context = csrf(request)
|
context = csrf(request)
|
||||||
context.update(get_redirect_url())
|
context.update(get_redirect_url())
|
||||||
|
context["mfa_invoke"] = True
|
||||||
return render(request, "FIDO2/Add.html", context)
|
return render(request, "FIDO2/Add.html", context)
|
||||||
|
|
||||||
|
|
||||||
@@ -97,8 +98,8 @@ def auth(request):
|
|||||||
|
|
||||||
def authenticate_begin(request):
|
def authenticate_begin(request):
|
||||||
server = getServer()
|
server = getServer()
|
||||||
credentials = getUserCredentials(request.session.get("base_username", request.user.username))
|
#credentials = getUserCredentials(request.session.get("base_username", request.user.username))
|
||||||
auth_data, state = server.authenticate_begin(credentials)
|
auth_data, state = server.authenticate_begin()
|
||||||
request.session['fido_state'] = state
|
request.session['fido_state'] = state
|
||||||
return HttpResponse(cbor.encode(auth_data), content_type = "application/octet-stream")
|
return HttpResponse(cbor.encode(auth_data), content_type = "application/octet-stream")
|
||||||
|
|
||||||
@@ -107,7 +108,7 @@ def authenticate_begin(request):
|
|||||||
def authenticate_complete(request):
|
def authenticate_complete(request):
|
||||||
try:
|
try:
|
||||||
credentials = []
|
credentials = []
|
||||||
username = request.session.get("base_username", request.user.username)
|
username = request.session.get("base_username", request.POST.get("username",request.user.username))
|
||||||
server = getServer()
|
server = getServer()
|
||||||
credentials = getUserCredentials(username)
|
credentials = getUserCredentials(username)
|
||||||
data = cbor.decode(request.body)
|
data = cbor.decode(request.body)
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ from django.conf import settings
|
|||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from .models import *
|
from .models import *
|
||||||
from .views import login
|
from .views import login
|
||||||
from .Common import get_redirect_url
|
|
||||||
import datetime
|
import datetime
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__="2.2.0"
|
__version__="2.2.0b1"
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 2.2 on 2021-05-30 06:22
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mfa', '0010_auto_20201110_0557'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='user_keys',
|
|
||||||
name='owned_by_enterprise',
|
|
||||||
field=models.BooleanField(blank=True, default=None, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -15,7 +15,7 @@ class User_Keys(models.Model):
|
|||||||
enabled=models.BooleanField(default=True)
|
enabled=models.BooleanField(default=True)
|
||||||
expires=models.DateTimeField(null=True,default=None,blank=True)
|
expires=models.DateTimeField(null=True,default=None,blank=True)
|
||||||
last_used=models.DateTimeField(null=True,default=None,blank=True)
|
last_used=models.DateTimeField(null=True,default=None,blank=True)
|
||||||
owned_by_enterprise=models.BooleanField(default=None,null=True,blank=True)
|
owned_by_enterprise=models.NullBooleanField(default=None,null=True,blank=True)
|
||||||
|
|
||||||
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
|
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
|
||||||
if self.key_type == "Trusted Device" and self.properties.get("signature","") == "":
|
if self.key_type == "Trusted Device" and self.properties.get("signature","") == "":
|
||||||
|
|||||||
71
mfa/templates/FIDO2/fido2_auth.html
Normal file
71
mfa/templates/FIDO2/fido2_auth.html
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
{% load static %}
|
||||||
|
<script type="application/javascript" src="{% static 'mfa/js/cbor.js' %}"></script>
|
||||||
|
<script type="application/javascript" src="{% static 'mfa/js/ua-parser.min.js' %}"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function authen()
|
||||||
|
{
|
||||||
|
fetch('{% url 'fido2_begin_auth' %}', {
|
||||||
|
method: 'GET',
|
||||||
|
}).then(function(response) {
|
||||||
|
if(response.ok) return response.arrayBuffer();
|
||||||
|
throw new Error('No credential available to authenticate!');
|
||||||
|
}).then(CBOR.decode).then(function(options) {
|
||||||
|
console.log(options)
|
||||||
|
return navigator.credentials.get(options);
|
||||||
|
}).then(function(assertion) {
|
||||||
|
res=CBOR.encode({
|
||||||
|
"credentialId": new Uint8Array(assertion.rawId),
|
||||||
|
"authenticatorData": new Uint8Array(assertion.response.authenticatorData),
|
||||||
|
"clientDataJSON": new Uint8Array(assertion.response.clientDataJSON),
|
||||||
|
"signature": new Uint8Array(assertion.response.signature)
|
||||||
|
});
|
||||||
|
|
||||||
|
return fetch('{% url 'fido2_complete_auth' %}', {
|
||||||
|
|
||||||
|
method: 'POST',
|
||||||
|
headers: {'Content-Type': 'application/cbor'},
|
||||||
|
body:res,
|
||||||
|
|
||||||
|
}).then(function (response) {if (response.ok) return res = response.json()}).then(function (res) {
|
||||||
|
if (res.status=="OK")
|
||||||
|
{
|
||||||
|
$("#msgdiv").addClass("alert alert-success").removeClass("alert-danger")
|
||||||
|
$("#msgdiv").html("Verified....please wait")
|
||||||
|
{% if mode == "auth" %}
|
||||||
|
window.location.href=res.redirect;
|
||||||
|
{% elif mode == "recheck" %}
|
||||||
|
mfa_success_function();
|
||||||
|
{% endif %}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#msgdiv").addClass("alert alert-danger").removeClass("alert-success")
|
||||||
|
$("#msgdiv").html("Verification Failed as " + res.message + ", <a href='javascript:void(0)' onclick='authen())'> try again</a> or <a href='javascript:void(0)' onclick='history.back()'> Go Back</a>")
|
||||||
|
|
||||||
|
{% if mode == "auth" %}
|
||||||
|
|
||||||
|
{% elif mode == "recheck" %}
|
||||||
|
|
||||||
|
mfa_failed_function();
|
||||||
|
{% endif %}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
$(document).ready(function () {
|
||||||
|
if (location.protocol != 'https:') {
|
||||||
|
$("#main_paragraph").addClass("alert alert-danger")
|
||||||
|
$("#main_paragraph").html("FIDO2 must work under secure context")
|
||||||
|
} else {
|
||||||
|
{% if mfa_invoke %}
|
||||||
|
ua=new UAParser().getResult()
|
||||||
|
if (ua.browser.name == "Safari")
|
||||||
|
$("#res").html("<button class='btn btn-success' onclick='authen()'>Authenticate...</button>")
|
||||||
|
else
|
||||||
|
authen()
|
||||||
|
{% endif %}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
1
mfa/templates/FIDO2/login.html
Normal file
1
mfa/templates/FIDO2/login.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{% include 'FIDO2/fido2_auth.html' %}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
{% load static %}
|
|
||||||
<script type="application/javascript" src="{% static 'mfa/js/cbor.js' %}"></script>
|
|
||||||
<script type="application/javascript" src="{% static 'mfa/js/ua-parser.min.js' %}"></script>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<div class="col-sm-10 col-sm-offset-1 col-xs-12 col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2">
|
<div class="col-sm-10 col-sm-offset-1 col-xs-12 col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2">
|
||||||
@@ -47,71 +45,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
{% include 'FIDO2/fido2_auth.html' %}
|
||||||
function authen()
|
|
||||||
{
|
|
||||||
fetch('{% url 'fido2_begin_auth' %}', {
|
|
||||||
method: 'GET',
|
|
||||||
}).then(function(response) {
|
|
||||||
if(response.ok) return response.arrayBuffer();
|
|
||||||
throw new Error('No credential available to authenticate!');
|
|
||||||
}).then(CBOR.decode).then(function(options) {
|
|
||||||
console.log(options)
|
|
||||||
return navigator.credentials.get(options);
|
|
||||||
}).then(function(assertion) {
|
|
||||||
res=CBOR.encode({
|
|
||||||
"credentialId": new Uint8Array(assertion.rawId),
|
|
||||||
"authenticatorData": new Uint8Array(assertion.response.authenticatorData),
|
|
||||||
"clientDataJSON": new Uint8Array(assertion.response.clientDataJSON),
|
|
||||||
"signature": new Uint8Array(assertion.response.signature)
|
|
||||||
});
|
|
||||||
|
|
||||||
return fetch('{% url 'fido2_complete_auth' %}', {
|
|
||||||
|
|
||||||
method: 'POST',
|
|
||||||
headers: {'Content-Type': 'application/cbor'},
|
|
||||||
body:res,
|
|
||||||
|
|
||||||
}).then(function (response) {if (response.ok) return res = response.json()}).then(function (res) {
|
|
||||||
if (res.status=="OK")
|
|
||||||
{
|
|
||||||
$("#msgdiv").addClass("alert alert-success").removeClass("alert-danger")
|
|
||||||
$("#msgdiv").html("Verified....please wait")
|
|
||||||
{% if mode == "auth" %}
|
|
||||||
window.location.href=res.redirect;
|
|
||||||
{% elif mode == "recheck" %}
|
|
||||||
mfa_success_function();
|
|
||||||
{% endif %}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$("#msgdiv").addClass("alert alert-danger").removeClass("alert-success")
|
|
||||||
$("#msgdiv").html("Verification Failed as " + res.message + ", <a href='javascript:void(0)' onclick='authen())'> try again</a> or <a href='javascript:void(0)' onclick='history.back()'> Go Back</a>")
|
|
||||||
|
|
||||||
{% if mode == "auth" %}
|
|
||||||
|
|
||||||
{% elif mode == "recheck" %}
|
|
||||||
|
|
||||||
mfa_failed_function();
|
|
||||||
{% endif %}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
$(document).ready(function () {
|
|
||||||
if (location.protocol != 'https:') {
|
|
||||||
$("#main_paragraph").addClass("alert alert-danger")
|
|
||||||
$("#main_paragraph").html("FIDO2 must work under secure context")
|
|
||||||
} else {
|
|
||||||
ua=new UAParser().getResult()
|
|
||||||
if (ua.browser.name == "Safari")
|
|
||||||
$("#res").html("<button class='btn btn-success' onclick='authen()'>Authenticate...</button>")
|
|
||||||
else
|
|
||||||
authen()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.views.decorators.cache import never_cache
|
from django.views.decorators.cache import never_cache
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from .Common import get_redirect_url
|
|
||||||
from .models import *
|
from .models import *
|
||||||
from django.template.context_processors import csrf
|
from django.template.context_processors import csrf
|
||||||
import simplejson
|
import simplejson
|
||||||
|
|||||||
6
setup.py
6
setup.py
@@ -4,7 +4,7 @@ from setuptools import find_packages, setup
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='django-mfa2',
|
name='django-mfa2',
|
||||||
version='2.2.0',
|
version='2.2.0b2 ',
|
||||||
description='Allows user to add 2FA to their accounts',
|
description='Allows user to add 2FA to their accounts',
|
||||||
long_description=open("README.md").read(),
|
long_description=open("README.md").read(),
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/markdown",
|
||||||
@@ -31,14 +31,12 @@ setup(
|
|||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
zip_safe=False, # because we're including static files
|
zip_safe=False, # because we're including static files
|
||||||
classifiers=[
|
classifiers=[
|
||||||
"Development Status :: 5 - Production/Stable",
|
"Development Status :: 4 - Beta",
|
||||||
"Environment :: Web Environment",
|
"Environment :: Web Environment",
|
||||||
"Framework :: Django",
|
"Framework :: Django",
|
||||||
"Framework :: Django :: 2.0",
|
"Framework :: Django :: 2.0",
|
||||||
"Framework :: Django :: 2.1",
|
"Framework :: Django :: 2.1",
|
||||||
"Framework :: Django :: 2.2",
|
"Framework :: Django :: 2.2",
|
||||||
"Framework :: Django :: 3.0",
|
|
||||||
"Framework :: Django :: 3.1",
|
|
||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
"Operating System :: OS Independent",
|
"Operating System :: OS Independent",
|
||||||
"Programming Language :: Python",
|
"Programming Language :: Python",
|
||||||
|
|||||||
Reference in New Issue
Block a user