Compare commits

..

1 Commits

Author SHA1 Message Date
Mohamed ElKalioby
7a154cfa34 Releasing v2.2.0 2021-05-30 09:24:25 +03:00
11 changed files with 113 additions and 93 deletions

View File

@@ -1,7 +1,8 @@
# Change Log # Change Log
## 2.2.0 (Not released) ## 2.2.0
* 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
@@ -9,7 +10,7 @@
## 2.1.1 ## 2.1.1
* Fixed: FIDO2 version in requirments.txt file. * Fixed: FIDO2 version in requirements.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

View File

@@ -28,7 +28,3 @@ 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

View File

@@ -17,6 +17,7 @@
<!-- 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">
@@ -28,6 +29,7 @@
{% 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">
@@ -35,9 +37,14 @@
<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>
@@ -49,7 +56,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>

View File

@@ -80,7 +80,6 @@ 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)
@@ -98,8 +97,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() auth_data, state = server.authenticate_begin(credentials)
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")
@@ -108,7 +107,7 @@ def authenticate_begin(request):
def authenticate_complete(request): def authenticate_complete(request):
try: try:
credentials = [] credentials = []
username = request.session.get("base_username", request.POST.get("username",request.user.username)) username = request.session.get("base_username", request.user.username)
server = getServer() server = getServer()
credentials = getUserCredentials(username) credentials = getUserCredentials(username)
data = cbor.decode(request.body) data = cbor.decode(request.body)

View File

@@ -1 +1 @@
__version__="2.2.0b1" __version__="2.2.0"

View File

@@ -0,0 +1,18 @@
# 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),
),
]

View File

@@ -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.NullBooleanField(default=None,null=True,blank=True) owned_by_enterprise=models.BooleanField(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","") == "":

View File

@@ -1,71 +0,0 @@
{% 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>

View File

@@ -1 +0,0 @@
{% include 'FIDO2/fido2_auth.html' %}

View File

@@ -1,4 +1,6 @@
{% 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">
@@ -45,4 +47,71 @@
</div> </div>
</div> </div>
{% include 'FIDO2/fido2_auth.html' %} <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 {
ua=new UAParser().getResult()
if (ua.browser.name == "Safari")
$("#res").html("<button class='btn btn-success' onclick='authen()'>Authenticate...</button>")
else
authen()
}
});
</script>

View File

@@ -4,7 +4,7 @@ from setuptools import find_packages, setup
setup( setup(
name='django-mfa2', name='django-mfa2',
version='2.2.0b2 ', version='2.2.0',
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,12 +31,14 @@ 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 :: 4 - Beta", "Development Status :: 5 - Production/Stable",
"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",