-
Notifications
You must be signed in to change notification settings - Fork 32
/
webauthn_verify_view.py
72 lines (57 loc) · 2.49 KB
/
webauthn_verify_view.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
from __future__ import annotations
import datetime
import json
import logging
from typing import TYPE_CHECKING
from django.conf import settings
from django.contrib.auth import login as auth_login
from django.http import JsonResponse
from django.utils.translation import gettext_lazy as _
from django.views.generic import View
from webauthn import base64url_to_bytes, verify_authentication_response
from webauthn.helpers import parse_authentication_credential_json
from webauthn.helpers.exceptions import InvalidAuthenticationResponse
if TYPE_CHECKING:
from django.http import HttpRequest
from ....utils.mfa_utils import get_mfa_user
logger = logging.getLogger(__name__)
class WebAuthnVerifyView(View):
"""
Verify the response to the challenge generated in :class:`~integreat_cms.cms.views.authentication.webauthn.webauthn_assert_view.WebAuthnAssertView`.
After a successful verification, the user is logged in.
"""
def post(self, request: HttpRequest) -> JsonResponse:
"""
:param request: The current request
:return: The mfa challenge as JSON
"""
if not (user := get_mfa_user(request)):
return JsonResponse(
{"success": False, "error": _("You need to log in first")}, status=403
)
challenge = request.session["challenge"]
assertion_response = json.loads(request.body)
credential_id = assertion_response["id"]
key = user.fido_keys.get(key_id=base64url_to_bytes(credential_id))
try:
authentication_verification = verify_authentication_response(
credential=parse_authentication_credential_json(
json.loads(request.body)
),
expected_challenge=base64url_to_bytes(challenge),
expected_rp_id=settings.HOSTNAME,
expected_origin=settings.BASE_URL,
credential_public_key=key.public_key,
credential_current_sign_count=key.sign_count,
)
except InvalidAuthenticationResponse as e:
logger.exception(e)
return JsonResponse(
{"success": False, "error": "Authentication rejected"}, status=403
)
# Update counter.
key.sign_count = authentication_verification.new_sign_count
key.last_usage = datetime.datetime.now()
key.save()
auth_login(request, user, backend="django.contrib.auth.backends.ModelBackend")
return JsonResponse({"success": True})