Coverage for src/django_otp_webauthn/checks.py: 19%
53 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 django.conf import settings
2from django.core.checks import Error
3from webauthn.helpers.structs import COSEAlgorithmIdentifier
5from django_otp_webauthn.settings import app_settings
7ERR_NO_RP_ID = "otp_webauthn.E010"
8ERR_NO_RP_NAME = "otp_webauthn.E011"
9ERR_UNSUPPORTED_COSE_ALGORITHM = "otp_webauthn.E020"
10ERR_NO_ALLOWED_ORIGINS = "otp_webauthn.E030"
11ERR_ALLOWED_ORIGINS_MALFORMED = "otp_webauthn.E031"
12ERR_DANGEROUS_SESSION_BACKEND = "otp_webauthn.E040"
15def check_settings_relying_party(app_configs, **kwargs):
16 errors = []
18 if not app_settings.OTP_WEBAUTHN_RP_ID_CALLABLE and not app_settings.OTP_WEBAUTHN_RP_ID:
19 errors.append(
20 Error(
21 "Relying party ID not configured.",
22 hint="Set the OTP_WEBAUTHN_RP_ID setting to the main domain of the web application, like: 'example.com'.",
23 obj=None,
24 id=ERR_NO_RP_ID,
25 )
26 )
28 if not app_settings.OTP_WEBAUTHN_RP_NAME_CALLABLE and not app_settings.OTP_WEBAUTHN_RP_NAME:
29 errors.append(
30 Error(
31 "Relying party name not configured.",
32 hint="Set the OTP_WEBAUTHN_RP_NAME setting to a human-readable name for the relying party, like: 'Acme Corp.'.",
33 obj=None,
34 id=ERR_NO_RP_NAME,
35 )
36 )
38 return errors
41def check_settings_supported_cose_algorithms(app_configs, **kwargs):
42 errors = []
43 algorithms = app_settings.OTP_WEBAUTHN_SUPPORTED_COSE_ALGORITHMS
45 # No need to check - no explicit algorithms provided
46 if algorithms == "all":
47 return []
49 unsupported_algorithms = []
50 for algorithm in algorithms:
51 if algorithm not in COSEAlgorithmIdentifier:
52 unsupported_algorithms.append(algorithm)
54 if unsupported_algorithms:
55 errors.append(
56 Error(
57 f"Unknown or unsupported COSE algorithm(s) detected in settings: {unsupported_algorithms!r}",
58 hint="Check that the OTP_WEBAUTHN_SUPPORTED_COSE_ALGORITHMS setting only contains COSE algorithm identifier values that are supported.",
59 obj=None,
60 id=ERR_UNSUPPORTED_COSE_ALGORITHM,
61 )
62 )
63 return errors
66def check_settings_allowed_origins_missing(app_configs, **kwargs):
67 errors = []
68 allowed_origins = app_settings.OTP_WEBAUTHN_ALLOWED_ORIGINS
70 if not allowed_origins:
71 errors.append(
72 Error(
73 "No allowed origins configured.",
74 hint="Set the OTP_WEBAUTHN_ALLOWED_ORIGINS setting to a list of allowed origins. Origins should be in the format 'https://example.com'.",
75 obj=None,
76 id=ERR_NO_ALLOWED_ORIGINS,
77 )
78 )
79 return errors
82def check_settings_allowed_origins_misconfigured(app_configs, **kwargs):
83 errors = []
84 allowed_origins = app_settings.OTP_WEBAUTHN_ALLOWED_ORIGINS
86 if not allowed_origins:
87 return []
89 if not isinstance(allowed_origins, list):
90 errors.append(
91 Error(
92 "Allowed origins are not a list.",
93 hint="Allowed origins should be a list of strings. Check the OTP_WEBAUTHN_ALLOWED_ORIGINS setting.",
94 obj=None,
95 id=ERR_ALLOWED_ORIGINS_MALFORMED,
96 )
97 )
98 return errors
100 for origin in allowed_origins:
101 if not origin.startswith("https://") and not origin.startswith("http://localhost"):
102 errors.append(
103 Error(
104 f"Allowed origin {origin!r} is not a secure origin.",
105 hint="Expected origins should start with 'https://'. Check the OTP_WEBAUTHN_ALLOWED_ORIGINS setting.",
106 obj=None,
107 id=ERR_ALLOWED_ORIGINS_MALFORMED,
108 )
109 )
111 return errors
114def check_settings_dangerous_session_backend_used(app_configs, **kwargs):
115 errors = []
116 session_engine = settings.SESSION_ENGINE
118 if session_engine == "django.contrib.sessions.backends.signed_cookies":
119 errors.append(
120 Error(
121 "You are using the signed cookies session backend. This is an unsupported configuration because it leaves your application vulnerable to replay attacks.",
122 hint="Set SESSION_ENGINE to a more secure backend, such as a database, cache or file-based backend.",
123 obj=None,
124 id=ERR_DANGEROUS_SESSION_BACKEND,
125 )
126 )
127 return errors