Coverage for src/django_otp_webauthn/utils.py: 25%
59 statements
« prev ^ index » next coverage.py v7.5.4, created at 2024-06-23 20:15 +0000
« prev ^ index » next coverage.py v7.5.4, created at 2024-06-23 20:15 +0000
1from logging import Logger
2from typing import TYPE_CHECKING, Optional
4from django.apps import apps
5from django.core.exceptions import ImproperlyConfigured
6from django.urls import reverse
7from webauthn.helpers import exceptions as pywebauthn_exceptions
9from django_otp_webauthn import exceptions
10from django_otp_webauthn.settings import app_settings
12if TYPE_CHECKING:
13 from .models import AbstractWebAuthnAttestation, AbstractWebAuthnCredential
16class rewrite_exceptions:
17 """Context manager that swallows py_webauthn exceptions and raises
18 appropriate django_otp_webauthn api exceptions that are handled nicely by rest
19 framework.
21 To aid in debugging, this context manager accepts an optional logger
22 argument that will be used to log the py_webauthn exceptions raised.
24 """
26 def __init__(self, logger: Optional[Logger] = None):
27 self.logger = logger
29 def log_exception(self, exc: Exception):
30 if self.logger:
31 self.logger.exception(exc)
33 def __enter__(self):
34 pass
36 def __exit__(self, exc_type, exc_val, exc_tb):
37 self.log_exception(exc_val)
38 if exc_type is pywebauthn_exceptions.InvalidCBORData:
39 raise exceptions.UnprocessableEntity(code="invalid_cbor", detail="Invalid CBOR data provided.") from exc_val
40 elif exc_type is pywebauthn_exceptions.InvalidRegistrationResponse:
41 raise exceptions.UnprocessableEntity(
42 code="invalid_registration_response",
43 detail="Invalid registration response provided.",
44 ) from exc_val
45 elif exc_type is pywebauthn_exceptions.InvalidAuthenticationResponse:
46 raise exceptions.UnprocessableEntity(
47 code="invalid_authentication_response",
48 detail="Invalid authentication response provided.",
49 ) from exc_val
50 elif exc_type is pywebauthn_exceptions.InvalidJSONStructure:
51 raise exceptions.UnprocessableEntity(
52 code="invalid_json_structure",
53 detail="There is a problem with the provided JSON data.",
54 ) from exc_val
55 elif exc_type is pywebauthn_exceptions.UnsupportedAlgorithm:
56 raise exceptions.UnprocessableEntity(
57 code="unsupported_algorithm",
58 detail="The specified COSE algorithm is not supported by this server.",
59 ) from exc_val
60 elif (
61 exc_type is pywebauthn_exceptions.UnsupportedPublicKey
62 or exc_type is pywebauthn_exceptions.InvalidPublicKeyStructure
63 ):
64 raise exceptions.UnprocessableEntity(
65 code="unsupported_public_key",
66 detail="The public key is malformed or not supported.",
67 ) from exc_val
68 elif exc_type is pywebauthn_exceptions.InvalidAuthenticatorDataStructure:
69 raise exceptions.UnprocessableEntity(
70 code="invalid_authenticator_data_structure",
71 detail="The provided authenticator data is malformed.",
72 ) from exc_val
73 elif exc_type is pywebauthn_exceptions.InvalidCertificateChain:
74 raise exceptions.UnprocessableEntity(
75 code="invalid_certificate_chain",
76 detail="The certificate chain in the attestation could not be validated.",
77 ) from exc_val
78 elif exc_type is pywebauthn_exceptions.UnsupportedEC2Curve:
79 raise exceptions.UnprocessableEntity(
80 code="unsupported_ec2_curve", detail="The EC2 curve is not supported."
81 ) from exc_val
82 elif exc_type is pywebauthn_exceptions.InvalidBackupFlags:
83 raise exceptions.UnprocessableEntity(
84 code="invalid_backup_flags",
85 detail="Impossible backup flags combination was provided.",
86 ) from exc_val
87 return False
90def get_exempt_urls() -> list:
91 """Returns the list of urls that should be allowed without 2FA verification."""
92 return [
93 # Registration
94 reverse("otp_webauthn:credential-registration-begin"),
95 reverse("otp_webauthn:credential-registration-complete"),
96 # Login
97 reverse("otp_webauthn:credential-authentication-begin"),
98 reverse("otp_webauthn:credential-authentication-complete"),
99 ]
102def get_credential_model() -> "AbstractWebAuthnCredential":
103 """Returns the WebAuthnCredential model that is active in this project."""
104 # Inspired by Django's django.contrib.auth.get_user_model
105 try:
106 return apps.get_model(app_settings.OTP_WEBAUTHN_CREDENTIAL_MODEL, require_ready=False)
107 except ValueError:
108 raise ImproperlyConfigured("OTP_WEBAUTHN_CREDENTIAL_MODEL must be of the form 'app_label.model_name'")
109 except LookupError:
110 raise ImproperlyConfigured(
111 f"OTP_WEBAUTHN_CREDENTIAL_MODEL refers to model '{app_settings.OTP_WEBAUTHN_CREDENTIAL_MODEL}' that has not been installed"
112 )
115def get_attestation_model() -> "AbstractWebAuthnAttestation":
116 """Returns the WebAuthnAttestation model that is active in this project."""
117 # Inspired by Django's django.contrib.auth.get_user_model
118 try:
119 return apps.get_model(app_settings.OTP_WEBAUTHN_ATTESTATION_MODEL, require_ready=False)
120 except ValueError:
121 raise ImproperlyConfigured("OTP_WEBAUTHN_ATTESTATION_MODEL must be of the form 'app_label.model_name'")
122 except LookupError:
123 raise ImproperlyConfigured(
124 f"OTP_WEBAUTHN_ATTESTATION_MODEL refers to model '{app_settings.OTP_WEBAUTHN_ATTESTATION_MODEL}' that has not been installed"
125 )
128def get_credential_model_string() -> str:
129 """Returns the string representation of the WebAuthnCredential model that is
130 active in this project."""
131 return app_settings.OTP_WEBAUTHN_CREDENTIAL_MODEL
134def get_attestation_model_string() -> str:
135 """Returns the string representation of the WebAuthnAttestation model
136 that is active in this project."""
137 return app_settings.OTP_WEBAUTHN_ATTESTATION_MODEL