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

1from django.conf import settings 

2from django.core.checks import Error 

3from webauthn.helpers.structs import COSEAlgorithmIdentifier 

4 

5from django_otp_webauthn.settings import app_settings 

6 

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" 

13 

14 

15def check_settings_relying_party(app_configs, **kwargs): 

16 errors = [] 

17 

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 ) 

27 

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 ) 

37 

38 return errors 

39 

40 

41def check_settings_supported_cose_algorithms(app_configs, **kwargs): 

42 errors = [] 

43 algorithms = app_settings.OTP_WEBAUTHN_SUPPORTED_COSE_ALGORITHMS 

44 

45 # No need to check - no explicit algorithms provided 

46 if algorithms == "all": 

47 return [] 

48 

49 unsupported_algorithms = [] 

50 for algorithm in algorithms: 

51 if algorithm not in COSEAlgorithmIdentifier: 

52 unsupported_algorithms.append(algorithm) 

53 

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 

64 

65 

66def check_settings_allowed_origins_missing(app_configs, **kwargs): 

67 errors = [] 

68 allowed_origins = app_settings.OTP_WEBAUTHN_ALLOWED_ORIGINS 

69 

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 

80 

81 

82def check_settings_allowed_origins_misconfigured(app_configs, **kwargs): 

83 errors = [] 

84 allowed_origins = app_settings.OTP_WEBAUTHN_ALLOWED_ORIGINS 

85 

86 if not allowed_origins: 

87 return [] 

88 

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 

99 

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 ) 

110 

111 return errors 

112 

113 

114def check_settings_dangerous_session_backend_used(app_configs, **kwargs): 

115 errors = [] 

116 session_engine = settings.SESSION_ENGINE 

117 

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