Compare commits

...

7 Commits
v1.1.6 ... v1.3

Author SHA1 Message Date
Mohamed ElKalioby
22b5d0884c Upgrade to FIDO2 (0.6) and Supporting Windows Hello 2019-05-29 13:30:32 +03:00
Mohamed ElKalioby
9569b0cfcd Hiding Delete Button 2019-05-19 16:20:00 +03:00
Mohamed ElKalioby
1f3fca0f48 Allowing admins to disable the diable key 2019-05-19 16:08:32 +03:00
Mohamed ElKalioby
7c2958bebf Load Static 2019-04-23 13:36:45 +03:00
Mohamed ElKalioby
d06f860611 Fixing static for U2F 2019-04-23 12:01:18 +03:00
Mohamed ElKalioby
ef3a5d4f40 Removed STATIC_URL 2019-04-23 11:57:05 +03:00
Mohamed El-Kalioby
9465042d7b Update README.md 2019-04-23 11:36:55 +03:00
9 changed files with 36 additions and 17 deletions

View File

@@ -7,9 +7,9 @@ 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, **security keys**, **Apple's Touch ID (Chrome)** and **android-safetynet** are supported. For FIDO2, **security keys**, **Windows Hello**, **Apple's Touch ID (Chrome)** and **android-safetynet** are supported.
In English :), It allows you to verify the user by security keys on PC, Laptops, Touch ID on Macboks (Chrome) and Fingerprint/PIN on Andriod Phones. In English :), It allows you to verify the user by security keys on PC, Laptops, Windows Hello (Fingerprint, PIN) on Windows 10 Build 1903 (May 2019 Update) Touch ID on Macbooks (Chrome) and Fingerprint/PIN on Andriod Phones.
Trusted device is a mode for the user to add a device that doesn't support security keys like iOS and andriod without fingerprints or NFC. Trusted device is a mode for the user to add a device that doesn't support security keys like iOS and andriod without fingerprints or NFC.
@@ -36,6 +36,8 @@ Depends on
'mfa', 'mfa',
'......') '......')
``` ```
1. Collect Static Files
`python manage.py collectstatic`
1. Add the following settings to your file 1. Add the following settings to your file
```python ```python
@@ -44,7 +46,8 @@ Depends on
MFA_RECHECK=True # Allow random rechecking of the user MFA_RECHECK=True # Allow random rechecking of the user
MFA_RECHECK_MIN=10 # Minimum interval in seconds MFA_RECHECK_MIN=10 # Minimum interval in seconds
MFA_RECHECK_MAX=30 # Maximum in seconds MFA_RECHECK_MAX=30 # Maximum in seconds
MFA_QUICKLOGIN=True # Allow quick login for returning users by provide only their 2FA MFA_QUICKLOGIN=True # Allow quick login for returning users by provide only their 2FA
MFA_HIDE_DISABLE=('FIDO2',) # Can the user disable his key (Added in 1.2.0).
TOKEN_ISSUER_NAME="PROJECT_NAME" #TOTP Issuer name TOKEN_ISSUER_NAME="PROJECT_NAME" #TOTP Issuer name
@@ -141,4 +144,4 @@ function some_func() {
//MUST_BE_MFA true or false, if the user must has with MFA //MUST_BE_MFA true or false, if the user must has with MFA
} }
```` ````

4
mfa/CHANGELOG.md Normal file
View File

@@ -0,0 +1,4 @@
# Change Log
## v1.2.0
* Added: MFA_HIDE_DISABLE setting option to disable users from deactivating their keys.

View File

@@ -34,11 +34,11 @@ def begin_registeration(request):
}, getUserCredentials(request.user.username)) }, getUserCredentials(request.user.username))
request.session['fido_state'] = state request.session['fido_state'] = state
return HttpResponse(cbor.dumps(registration_data),content_type='application/octet-stream') return HttpResponse(cbor.encode(registration_data),content_type='application/octet-stream')
@csrf_exempt @csrf_exempt
def complete_reg(request): def complete_reg(request):
try: try:
data = cbor.loads(request.body)[0] data = cbor.decode(request.body)
client_data = ClientData(data['clientDataJSON']) client_data = ClientData(data['clientDataJSON'])
att_obj = AttestationObject((data['attestationObject'])) att_obj = AttestationObject((data['attestationObject']))
@@ -79,7 +79,7 @@ def authenticate_begin(request):
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(credentials)
request.session['fido_state'] = state request.session['fido_state'] = state
return HttpResponse(cbor.dumps(auth_data),content_type="application/octet-stream") return HttpResponse(cbor.encode(auth_data),content_type="application/octet-stream")
@csrf_exempt @csrf_exempt
def authenticate_complete(request): def authenticate_complete(request):
@@ -87,7 +87,7 @@ def authenticate_complete(request):
username=request.session.get("base_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.loads(request.body)[0] data = cbor.decode(request.body)
credential_id = data['credentialId'] credential_id = data['credentialId']
client_data = ClientData(data['clientDataJSON']) client_data = ClientData(data['clientDataJSON'])
auth_data = AuthenticatorData(data['authenticatorData']) auth_data = AuthenticatorData(data['authenticatorData'])

View File

@@ -20,6 +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,
@@ -33,6 +34,7 @@
} }
}) })
} }
{% 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>
@@ -87,8 +89,16 @@
<td>{{ key.expires }}</td> <td>{{ key.expires }}</td>
<td>{% if key.device %}{{ key.device }}{% endif %}</td> <td>{% if key.device %}{{ key.device }}{% endif %}</td>
<td>{{ key.last_used }}</td> <td>{{ key.last_used }}</td>
<td><input type="checkbox" id="toggle_{{ key.id }}" {% if key.enabled %}checked{% endif %} data-onstyle="success" data-offstyle="danger" onchange="toggleKey({{ key.id }})" data-toggle="toggle"></td> {% if key.key_type in HIDE_DISABLE %}
<td><a href="javascript:void(0)" onclick="deleteKey({{ key.id }},'{{ key.key_type }}')"> <span class="fa fa-trash"></span></a></td> <td>{% if key.enabled %}On{% else %} Off{% endif %}</td>
{% else %}
<td><input type="checkbox" id="toggle_{{ key.id }}" {% if key.enabled %}checked{% endif %} data-onstyle="success" data-offstyle="danger" onchange="toggleKey({{ key.id }})" data-toggle="toggle" class="status_chk"></td>
{% endif %}
<td>{% if key.key_type in HIDE_DISABLE %}
----
{% else %}
<a href="javascript:void(0)" onclick="deleteKey({{ key.id }},'{{ key.key_type }}')"> <span class="fa fa-trash"></span></a></td>
{% endif %}
</tr> </tr>
{% empty %} {% empty %}
<tr><td colspan="7" align="center">You didn't have any keys yet.</td> </tr> <tr><td colspan="7" align="center">You didn't have any keys yet.</td> </tr>

View File

@@ -62,7 +62,6 @@
<fieldset> <fieldset>
<div class="row"> <div class="row">
<div class="col-sm-12 col-md-12"> <div class="col-sm-12 col-md-12">
{# <img class="profile-img" src="{{ STATIC_URL }}img/users.png" alt="">#}
</div> </div>
</div> </div>
<div class="row"> <div class="row">

View File

@@ -1,4 +1,5 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load static %}
{% block head %} {% block head %}
<style> <style>
#two-factor-steps { #two-factor-steps {
@@ -10,7 +11,7 @@
margin: 0px; margin: 0px;
} }
</style> </style>
<script src="{{ STATIC_URL }}js/u2f-api.js" type="text/javascript"></script> <script src="{% static 'mfa/js/u2f-api.js' %}" type="text/javascript"></script>
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function addToken() { $(document).ready(function addToken() {
data=JSON.parse('{{ token|safe }}') data=JSON.parse('{{ token|safe }}')

View File

@@ -1,3 +1,4 @@
{% load static %}
<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">
@@ -34,7 +35,7 @@
</div> </div>
</div> </div>
</div> </div>
<script src="{{ STATIC_URL }}js/u2f-api.js" type="text/javascript"></script> <script src="{% static 'mfa/js/u2f-api.js' %}" type="text/javascript"></script>
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function () { $(document).ready(function () {

View File

@@ -12,14 +12,15 @@ from . import TrustedDevice
from user_agents import parse from user_agents import parse
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
,"HIDE_DISABLE":getattr(settings,"MFA_HIDE_DISABLE",[])}
for k in context["keys"]: for k in context["keys"]:
if k.key_type =="Trusted Device" : if k.key_type =="Trusted Device" :
setattr(k,"device",parse(k.properties.get("user_agent","-----"))) setattr(k,"device",parse(k.properties.get("user_agent","-----")))
elif k.key_type == "FIDO2": elif k.key_type == "FIDO2":
setattr(k,"device",k.properties.get("type","----")) setattr(k,"device",k.properties.get("type","----"))
keys.append(k) keys.append(k)
context["keys"]=keys context["keys"]=keys
return render_to_response("MFA.html",context,context_instance=RequestContext(request)) return render_to_response("MFA.html",context,context_instance=RequestContext(request))
def verify(request,username): def verify(request,username):

View File

@@ -4,7 +4,7 @@ from setuptools import find_packages, setup
setup( setup(
name='django-mfa2', name='django-mfa2',
version='1.1.6', version='1.3.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.5', 'fido2 == 0.6',
'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.*",