Compare commits

..

16 Commits

Author SHA1 Message Date
Mohamed El-Kalioby
b39fa1a99b Adding Touch ID to Django 1.8 2021-01-30 17:10:33 +03:00
Mohamed ElKalioby
c5b62ada65 Update Changlog 2020-08-28 18:33:46 +03:00
Mohamed ElKalioby
3d37d0a51f closes #6 2020-06-18 18:54:20 +03:00
Mohamed ElKalioby
a820206a24 Fix is_authenticated #13 2020-06-18 18:24:42 +03:00
Mohamed ElKalioby
bc407ca39b Closes #14 2020-06-18 18:16:39 +03:00
Mohamed El-Kalioby
9786f4a888 Add Contributors
Add Thanks to the contributors
2020-06-06 11:08:30 +03:00
Mohamed El-Kalioby
804b76518e Merge pull request #9 from opalstack/import7
Fix for #8
2020-06-06 11:01:32 +03:00
John Spounias
91d08cdafc Fix for #8 2020-06-05 15:29:42 -06:00
Mohamed El-Kalioby
7ee2281785 Update README.md 2020-04-15 11:38:20 +03:00
Mohamed El-Kalioby
288ab96425 Added Downloads Count 2020-04-15 11:35:29 +03:00
Mohamed El-Kalioby
36e9bf154a Update README.md 2019-12-14 16:17:09 +03:00
Mohamed El-Kalioby
0b0a3230fa Closes #5
Move to True and False
2019-12-13 10:31:32 +02:00
Mohamed El-Kalioby
5d31b83fae Add Firefox for Andriod 2019-11-14 19:57:13 +03:00
Mohamed El-Kalioby
c134cd87e2 Update README.md 2019-11-08 13:06:57 +03:00
Mohamed El-Kalioby
ab4b1fdf5a Up tot fido2==0.7.2 2019-10-27 09:43:18 +03:00
Mohamed El-Kalioby
2d5b507a50 Bumped up version 2019-10-20 16:03:34 +03:00
10 changed files with 68 additions and 19 deletions

View File

@@ -1,5 +1,14 @@
# Change Log # Change Log
## v1.9.1
* Fixed: is_authenticated #13
* Fixed: is_anonymous #6
thanks to @d3cline,
## v1.7
* Better Error Management
* Better Token recheck
## v 1.6.0 ## v 1.6.0
* Fixed some issues for django>= 2.0 * Fixed some issues for django>= 2.0
* Added example app. * Added example app.

View File

@@ -8,10 +8,10 @@ Web Authencation API (WebAuthn) is state-of-the art techology that is expected t
![Andriod Fingerprint](https://cdn-images-1.medium.com/max/800/1*1FWkRE8D7NTA2Kn1DrPjPA.png) ![Andriod Fingerprint](https://cdn-images-1.medium.com/max/800/1*1FWkRE8D7NTA2Kn1DrPjPA.png)
For FIDO2, the following are supported For FIDO2, the following are supported
* **security keys** (Firefox 60+, Chrome 67+, Edge 18+), * **security keys** (Firefox 60+, Chrome 67+, Edge 18+, Safari 13 on Mac OS, Chrome on Andriod, Safari on iOS 13.3+),
* **Windows Hello** (Firefox 67+, Chrome 72+ , Edge) , * **Windows Hello** (Firefox 67+, Chrome 72+ , Edge) ,
* **Apple's Touch ID** (Chrome 70+ on Mac OS X ), * **Apple's Touch ID** (Chrome 70+ on Mac OS X ),
* **android-safetynet** (Chrome 70+) * **android-safetynet** (Chrome 70+, Firefox 68+)
* **NFC devices using PCSC** (Not Tested, but as supported in fido2) * **NFC devices using PCSC** (Not Tested, but as supported in fido2)
In English :), It allows you to verify the user by security keys on PC, Laptops or Mobiles, Windows Hello (Fingerprint, PIN) on Windows 10 Build 1903+ (May 2019 Update) Touch ID on Macbooks (Chrome) and Fingerprint/Face/Iris/PIN on Andriod Phones. In English :), It allows you to verify the user by security keys on PC, Laptops or Mobiles, Windows Hello (Fingerprint, PIN) on Windows 10 Build 1903+ (May 2019 Update) Touch ID on Macbooks (Chrome) and Fingerprint/Face/Iris/PIN on Andriod Phones.
@@ -152,3 +152,7 @@ function some_func() {
} }
```` ````
# Contributors
* [mahmoodnasr](https://github.com/mahmoodnasr)
* [d3cline](https://github.com/d3cline)

View File

@@ -136,7 +136,11 @@ def authenticate_complete(request):
mfa["next_check"] = int((datetime.datetime.now()+ datetime.timedelta( mfa["next_check"] = int((datetime.datetime.now()+ datetime.timedelta(
seconds=random.randint(settings.MFA_RECHECK_MIN, settings.MFA_RECHECK_MAX))).strftime("%s")) seconds=random.randint(settings.MFA_RECHECK_MIN, settings.MFA_RECHECK_MAX))).strftime("%s"))
request.session["mfa"] = mfa request.session["mfa"] = mfa
if not request.user.is_authenticated(): try:
authenticated=request.user.is_authenticated
except:
authenticated = request.user.is_authenticated()
if not authenticated:
res=login(request) res=login(request)
if not "location" in res: return reset_cookie(request) if not "location" in res: return reset_cookie(request)
return HttpResponse(simplejson.dumps({'status':"OK","redirect":res["location"]}),content_type="application/json") return HttpResponse(simplejson.dumps({'status':"OK","redirect":res["location"]}),content_type="application/json")

View File

@@ -16,5 +16,5 @@ class Migration(migrations.Migration):
name='owned_by_enterprise', name='owned_by_enterprise',
field=models.NullBooleanField(default=None), field=models.NullBooleanField(default=None),
), ),
migrations.RunSQL("update mfa_user_keys set owned_by_enterprise = %s where key_type='FIDO2'"%(1 if getattr(settings,"MFA_OWNED_BY_ENTERPRISE",False) else 0 )) migrations.RunSQL("update mfa_user_keys set owned_by_enterprise = %s where key_type='FIDO2'"%(True if getattr(settings,"MFA_OWNED_BY_ENTERPRISE",False) else False ))
] ]

9
mfa/static/mfa/js/ua-parser.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -2,6 +2,7 @@
{% load static %} {% load static %}
{% block head %} {% block head %}
<script type="application/javascript" src="{% static 'mfa/js/cbor.js'%}"></script> <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="application/javascript"> <script type="application/javascript">
function begin_reg(){ function begin_reg(){
fetch('{% url 'fido2_begin_reg' %}',{}).then(function(response) { fetch('{% url 'fido2_begin_reg' %}',{}).then(function(response) {
@@ -40,7 +41,17 @@
$("#res").html("<div class='alert alert-danger'>Registeration Failed as " +reason +", <a href='javascript:void(0)' onclick='begin_reg()'> try again </a> or <a href='{% url 'mfa_home' %}'> Go to Security Home</a></div>") $("#res").html("<div class='alert alert-danger'>Registeration Failed as " +reason +", <a href='javascript:void(0)' onclick='begin_reg()'> try again </a> or <a href='{% url 'mfa_home' %}'> Go to Security Home</a></div>")
}) })
} }
$(document).ready(setTimeout(begin_reg,500)) $(document).ready(function (){
ua=new UAParser()
if (ua.getBrowser().name == "Safari")
{
$("#res").html("<button class='btn btn-primary' onclick='begin_reg()'>Start...</button>")
}
else
{
setTimeout(begin_reg, 500)
}
})
</script> </script>
{% endblock %} {% endblock %}
@@ -56,7 +67,7 @@
<div class="row alert alert-pr" id="res"> <div class="row alert alert-pr" id="res">
<p style="color: green">Your broswer should ask you to confirm you indentity.</p> <p style="color: green">Your browser should ask you to confirm you identity.</p>
</div> </div>
</div> </div>

View File

@@ -1,5 +1,6 @@
{% load static %} {% load static %}
<script type="application/javascript" src="{% static 'mfa/js/cbor.js' %}"></script> <script type="application/javascript" src="{% static 'mfa/js/cbor.js' %}"></script>
<script type="application/javascript" src="{% static 'mfa/js/us-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">
@@ -17,7 +18,9 @@
<br/> <br/>
{% endif %} {% endif %}
<p style="color: green">please press the button on your security key to prove it is you.</p> <div id="res">
<p style="color: green">please press the button on your security key to prove it is you.</p>
</div>
<div id="msgdiv"></div> <div id="msgdiv"></div>
{% if mode == "auth" %} {% if mode == "auth" %}
<form id="u2f_login" action="{% url 'fido2_complete_auth' %}" method="post" enctype="multipart/form-data"> <form id="u2f_login" action="{% url 'fido2_complete_auth' %}" method="post" enctype="multipart/form-data">
@@ -101,7 +104,11 @@
$("#main_paragraph").addClass("alert alert-danger") $("#main_paragraph").addClass("alert alert-danger")
$("#main_paragraph").html("FIDO2 must work under secure context") $("#main_paragraph").html("FIDO2 must work under secure context")
} else { } else {
authen() ua=UAParser()
if (ua.getBrowser().name == "Safari")
$("#res").html("<button class='btn btn-success' onclick='authen()'>Authenticate...</button>")
else
authen()
} }
}); });

View File

@@ -20,7 +20,7 @@
$("#modal-footer").prepend("<button id='actionBtn' class='btn btn-danger' onclick='confirmDel("+id+")'>Confirm Deletion</button>") $("#modal-footer").prepend("<button id='actionBtn' class='btn btn-danger' onclick='confirmDel("+id+")'>Confirm Deletion</button>")
$("#popUpModal").modal() $("#popUpModal").modal()
} }
{% if not HIDE_DISABLE %}
function toggleKey(id) { function toggleKey(id) {
$.ajax({ $.ajax({
url:"{% url 'toggle_key' %}?id="+id, url:"{% url 'toggle_key' %}?id="+id,
@@ -34,7 +34,6 @@
} }
}) })
} }
{% endif %}
</script> </script>
<link href="{% static 'mfa/css/bootstrap-toggle.min.css' %}" rel="stylesheet"> <link href="{% static 'mfa/css/bootstrap-toggle.min.css' %}" rel="stylesheet">
<script src="{% static 'mfa/js/bootstrap-toggle.min.js'%}"></script> <script src="{% static 'mfa/js/bootstrap-toggle.min.js'%}"></script>

View File

@@ -1,5 +1,5 @@
from django.shortcuts import render from django.shortcuts import render
#from django.http import HttpResponse,HttpResponseRedirect from django.http import HttpResponse,HttpResponseRedirect
from .models import * from .models import *
try: try:
from django.urls import reverse from django.urls import reverse
@@ -7,10 +7,12 @@ except:
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.template.context_processors import csrf from django.template.context_processors import csrf
from django.template.context import RequestContext from django.template.context import RequestContext
from django.http import HttpResponseRedirect
from django.conf import settings from django.conf import settings
from . import TrustedDevice from . import TrustedDevice
from django.contrib.auth.decorators import login_required
from user_agents import parse from user_agents import parse
@login_required
def index(request): def index(request):
keys=[] keys=[]
context={"keys":User_Keys.objects.filter(username=request.user.username),"UNALLOWED_AUTHEN_METHODS":settings.MFA_UNALLOWED_METHODS context={"keys":User_Keys.objects.filter(username=request.user.username),"UNALLOWED_AUTHEN_METHODS":settings.MFA_UNALLOWED_METHODS
@@ -52,6 +54,8 @@ def login(request):
callable_func = __get_callable_function__(settings.MFA_LOGIN_CALLBACK) callable_func = __get_callable_function__(settings.MFA_LOGIN_CALLBACK)
return callable_func(request,username=request.session["base_username"]) return callable_func(request,username=request.session["base_username"])
@login_required
def delKey(request): def delKey(request):
key=User_Keys.objects.get(id=request.GET["id"]) key=User_Keys.objects.get(id=request.GET["id"])
if key.username == request.user.username: if key.username == request.user.username:
@@ -73,18 +77,20 @@ def __get_callable_function__(func_path):
raise Exception("Module does not have requested function") raise Exception("Module does not have requested function")
return callable_func return callable_func
@login_required
def toggleKey(request): def toggleKey(request):
id=request.GET["id"] id=request.GET["id"]
q=User_Keys.objects.filter(username=request.user.username, id=id) q=User_Keys.objects.filter(username=request.user.username, id=id)
if q.count()==1: if q.count()==1:
key=q[0] key=q[0]
key.enabled=not key.enabled if not key.key_type in settings.MFA_HIDE_DISABLE:
key.save() key.enabled=not key.enabled
return HttpResponse("OK") key.save()
return HttpResponse("OK")
else:
return HttpResponse("You can't change this method.")
else: else:
return HttpResponse("Error") return HttpResponse("Error")
def goto(request,method): def goto(request,method):
return HttpResponseRedirect(reverse(method.lower()+"_auth")) return HttpResponseRedirect(reverse(method.lower()+"_auth"))

View File

@@ -4,7 +4,7 @@ from setuptools import find_packages, setup
setup( setup(
name='django-mfa2', name='django-mfa2',
version='1.7.11', version='1.10.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",
@@ -24,7 +24,7 @@ setup(
'ua-parser', 'ua-parser',
'user-agents', 'user-agents',
'python-jose', 'python-jose',
'fido2 == 0.7', 'fido2 == 0.9',
'jsonLookup' 'jsonLookup'
], ],
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",