Coverage for paperless/auth.py: 60%

48 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-10 09:07 +0000

1import logging 

2 

3from allauth.mfa.adapter import get_adapter as get_mfa_adapter 

4from django.conf import settings 

5from django.contrib import auth 

6from django.contrib.auth.middleware import PersistentRemoteUserMiddleware 

7from django.contrib.auth.models import User 

8from django.http import HttpRequest 

9from django.utils.deprecation import MiddlewareMixin 

10from rest_framework import authentication 

11from rest_framework import exceptions 

12 

13logger = logging.getLogger("paperless.auth") 

14 

15 

16class AutoLoginMiddleware(MiddlewareMixin): 

17 def process_request(self, request: HttpRequest) -> None: 

18 # Dont use auto-login with token request 

19 if request.path.startswith("/api/token/") and request.method == "POST": 

20 return None 

21 try: 

22 request.user = User.objects.get( 

23 username=settings.AUTO_LOGIN_USERNAME, 

24 is_active=True, 

25 ) 

26 auth.login( 

27 request=request, 

28 user=request.user, 

29 backend="django.contrib.auth.backends.ModelBackend", 

30 ) 

31 except User.DoesNotExist: 

32 pass 

33 

34 

35class AngularApiAuthenticationOverride(authentication.BaseAuthentication): 

36 """This class is here to provide authentication to the angular dev server 

37 during development. This is disabled in production. 

38 """ 

39 

40 def authenticate(self, request): 

41 if ( 

42 settings.DEBUG 

43 and "Referer" in request.headers 

44 and request.headers["Referer"].startswith("http://localhost:4200/") 

45 ): 

46 user = User.objects.filter(is_staff=True).first() 

47 logger.debug(f"Auto-Login with user {user}") 

48 return (user, None) 

49 else: 

50 return None 

51 

52 

53class HttpRemoteUserMiddleware(PersistentRemoteUserMiddleware): 

54 """This class allows authentication via HTTP_REMOTE_USER which is set for 

55 example by certain SSO applications. 

56 """ 

57 

58 header = settings.HTTP_REMOTE_USER_HEADER_NAME 

59 

60 def __call__(self, request: HttpRequest) -> None: 

61 # If remote user auth is enabled only for the frontend, not the API, 

62 # then we need dont want to authenticate the user for API requests. 

63 if ( 

64 "/api/" in request.path 

65 and "paperless.auth.PaperlessRemoteUserAuthentication" 

66 not in settings.REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"] 

67 ): 

68 return self.get_response(request) 

69 return super().__call__(request) 

70 

71 

72class PaperlessRemoteUserAuthentication(authentication.RemoteUserAuthentication): 

73 """ 

74 REMOTE_USER authentication for DRF which overrides the default header. 

75 """ 

76 

77 header = settings.HTTP_REMOTE_USER_HEADER_NAME 

78 

79 

80class PaperlessBasicAuthentication(authentication.BasicAuthentication): 

81 def authenticate(self, request): 

82 user_tuple = super().authenticate(request) 

83 user = user_tuple[0] if user_tuple else None 

84 mfa_adapter = get_mfa_adapter() 

85 if user and mfa_adapter.is_mfa_enabled(user): 85 ↛ 86line 85 didn't jump to line 86 because the condition on line 85 was never true

86 raise exceptions.AuthenticationFailed("MFA required") 

87 

88 return user_tuple 

89 

90 def authenticate_header(self, request): 

91 auth_header = request.META.get("HTTP_AUTHORIZATION", "") 

92 if auth_header.lower().startswith("basic "): 

93 return super().authenticate_header(request) 

94 

95 # Still 401 for anonymous API access 

96 return authentication.TokenAuthentication.keyword