Fingerprint-based authentication and Authorization in Python(Django) web applications - Hacking your way out (Part 3)
Tags: django, webauthn, passwordless, webdev
Published: 2021-06-08 21:26:03

Here comes the concluding part of this series. In this part, we'll focus on extending the registration flow of the third-party application we have been using to implement the specification we want for our app. 



##### <span style="color:red">NOTE: This section is optional and as a result, it was not included in this tutorial's [github repository](https://github.com/Sirneij/django_mfa2_example). The feature was also not incorporated in its [live version](https://django-mfa2-example.herokuapp.com/)</span>

The specification we'll be addressing says that if a user fails to identify himself/herself using his/her device's authenticator or external authenticator(s) [supported by python-fido2](https://github.com/Yubico/python-fido2/tree/master/fido2/attestation), such user should be removed from the database, logged out of the application and then redirected to the registration page to restart the process. This is to ensure that only verified users who used the [supported attestation formats](https://github.com/Yubico/python-fido2/tree/master/fido2/attestation) during registration are authenticated and authorized.

Unfortunately, [django-mfa2](https://github.com/mkalioby/django-mfa2) was not built to support that out-of-the-box. However, to add this feature, one needs to have a local version of the application so as to be able to extend its functionalities.

Going by the idea stated above, we need to move the `mfa` package which should be located in `site-packages` directory of your virtual environment folder. The path to mine is `django-mfa-example/env/lib/python3.8/site-packages`.

#### It should be noted that you may not be able to get this path if you used `pipenv` for your virtual environment. One option you have, in this case, is to download the [mfa](https://github.com/mkalioby/django-mfa2/tree/master/mfa) application and move it to your application directory.

Now to the codes. A careful inspection of [mfa's](https://github.com/mkalioby/django-mfa2/tree/master/mfa) source code reveals that most of the redirections, in case of failure, can be intercepted in the `script` section of the `FIDO2/Add.html` file located in its `templates` directory. We'll be modifying [line 37](https://github.com/mkalioby/django-mfa2/blob/7a154cfa340819363f1f076e7d96b4464a56ae8a/mfa/templates/FIDO2/Add.html#L37) and [line 40](https://github.com/mkalioby/django-mfa2/blob/7a154cfa340819363f1f076e7d96b4464a56ae8a/mfa/templates/FIDO2/Add.html#L40). 

First, to address removing and logging out users, append this function to your `accounts/views.py` file:
```python
def remove_user_and_redirect(request):
    User.objects.filter(username=request.user.username).delete()
    logout(request)
    messages.error(request, f'Your fingerprint capture was not valid. Kindly re-register and try again.')
    return redirect(reverse('accounts:register'))
```
This simply fetches out the user using its username and deletes it from the database using Django ORM's `delete()` method. Then, such user will be logged out using one of [Django's auth methods](https://docs.djangoproject.com/en/3.2/ref/contrib/auth/), `logout`. An error message will then be flashed to inform the user of the action taken and finally, redirected to the registration page.

Add this view function to your `accounts/urls.py`.
```python
...
urlpatterns = [
   ...
    path('remove_user_and_redirect', views.remove_user_and_redirect, name='remove_user_and_redirect'),
]
```
Now, proceed to the lines pointed out earlier ([line 37](https://github.com/mkalioby/django-mfa2/blob/7a154cfa340819363f1f076e7d96b4464a56ae8a/mfa/templates/FIDO2/Add.html#L37) and [line 40](https://github.com/mkalioby/django-mfa2/blob/7a154cfa340819363f1f076e7d96b4464a56ae8a/mfa/templates/FIDO2/Add.html#L40)) and append the following:
```javascript
...
else{
...
setTimeout(function () {
  window.location.href = "{% url 'accounts:remove_user_and_redirect' %}" }, 1000);
}
```
to each of the lines.

There is nothing much here. We just instruct the app to wait for about `1000ms` so that the user can read the error message outputted and then redirect automatically by calling the function added above through the url, `accounts:remove_user_and_redirect`. [setTimeout() method executes a function or specified piece of code once the timer expires](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout). 

Hurray!!! We have come to the end of this rather long piece. Hope you learned something. 

Do you have any suggestions, comments or reactions? Kindly drop them in the comment section below. Let's keep learning and practicing.

## References
  - [Django-mfa2 github repository](https://github.com/mkalioby/django-mfa2)
  - [Yubico python-fido2 github repository](https://github.com/Yubico/python-fido2/tree/master/fido2/attestation)
  - [Django auth methods](https://docs.djangoproject.com/en/3.2/ref/contrib/auth/#django-contrib-auth)
  - [MDN setTimeout() documentation](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout)