mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Enhancement: support remote user auth directly against API (DRF) (#5386)
This commit is contained in:
		| @@ -47,3 +47,11 @@ class HttpRemoteUserMiddleware(PersistentRemoteUserMiddleware): | ||||
|     """ | ||||
|  | ||||
|     header = settings.HTTP_REMOTE_USER_HEADER_NAME | ||||
|  | ||||
|  | ||||
| class PaperlessRemoteUserAuthentication(authentication.RemoteUserAuthentication): | ||||
|     """ | ||||
|     REMOTE_USER authentication for DRF which overrides the default header. | ||||
|     """ | ||||
|  | ||||
|     header = settings.HTTP_REMOTE_USER_HEADER_NAME | ||||
|   | ||||
| @@ -420,19 +420,31 @@ if AUTO_LOGIN_USERNAME: | ||||
|     # regular login in case the provided user does not exist. | ||||
|     MIDDLEWARE.insert(_index + 1, "paperless.auth.AutoLoginMiddleware") | ||||
|  | ||||
| ENABLE_HTTP_REMOTE_USER = __get_boolean("PAPERLESS_ENABLE_HTTP_REMOTE_USER") | ||||
| HTTP_REMOTE_USER_HEADER_NAME = os.getenv( | ||||
|     "PAPERLESS_HTTP_REMOTE_USER_HEADER_NAME", | ||||
|     "HTTP_REMOTE_USER", | ||||
| ) | ||||
|  | ||||
| if ENABLE_HTTP_REMOTE_USER: | ||||
|     MIDDLEWARE.append("paperless.auth.HttpRemoteUserMiddleware") | ||||
|     AUTHENTICATION_BACKENDS.insert(0, "django.contrib.auth.backends.RemoteUserBackend") | ||||
|     REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"].append( | ||||
|         "rest_framework.authentication.RemoteUserAuthentication", | ||||
| def _parse_remote_user_settings() -> str: | ||||
|     global MIDDLEWARE, AUTHENTICATION_BACKENDS, REST_FRAMEWORK | ||||
|     enable = __get_boolean("PAPERLESS_ENABLE_HTTP_REMOTE_USER") | ||||
|     if enable: | ||||
|         MIDDLEWARE.append("paperless.auth.HttpRemoteUserMiddleware") | ||||
|         AUTHENTICATION_BACKENDS.insert( | ||||
|             0, | ||||
|             "django.contrib.auth.backends.RemoteUserBackend", | ||||
|         ) | ||||
|         REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"].insert( | ||||
|             0, | ||||
|             "paperless.auth.PaperlessRemoteUserAuthentication", | ||||
|         ) | ||||
|  | ||||
|     header_name = os.getenv( | ||||
|         "PAPERLESS_HTTP_REMOTE_USER_HEADER_NAME", | ||||
|         "HTTP_REMOTE_USER", | ||||
|     ) | ||||
|  | ||||
|     return header_name | ||||
|  | ||||
|  | ||||
| HTTP_REMOTE_USER_HEADER_NAME = _parse_remote_user_settings() | ||||
|  | ||||
| # X-Frame options for embedded PDF display: | ||||
| X_FRAME_OPTIONS = "ANY" if DEBUG else "SAMEORIGIN" | ||||
|  | ||||
|   | ||||
							
								
								
									
										75
									
								
								src/paperless/tests/test_remote_user.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/paperless/tests/test_remote_user.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| import os | ||||
| from unittest import mock | ||||
|  | ||||
| from django.contrib.auth.models import User | ||||
| from rest_framework import status | ||||
| from rest_framework.test import APITestCase | ||||
|  | ||||
| from documents.tests.utils import DirectoriesMixin | ||||
| from paperless.settings import _parse_remote_user_settings | ||||
|  | ||||
|  | ||||
| class TestRemoteUser(DirectoriesMixin, APITestCase): | ||||
|     def setUp(self): | ||||
|         super().setUp() | ||||
|  | ||||
|         self.user = User.objects.create_superuser( | ||||
|             username="temp_admin", | ||||
|         ) | ||||
|  | ||||
|     def test_remote_user(self): | ||||
|         """ | ||||
|         GIVEN: | ||||
|             - Configured user | ||||
|             - Remote user auth is enabled | ||||
|         WHEN: | ||||
|             - API call is made to get documents | ||||
|         THEN: | ||||
|             - Call succeeds | ||||
|         """ | ||||
|  | ||||
|         with mock.patch.dict( | ||||
|             os.environ, | ||||
|             { | ||||
|                 "PAPERLESS_ENABLE_HTTP_REMOTE_USER": "True", | ||||
|             }, | ||||
|         ): | ||||
|             _parse_remote_user_settings() | ||||
|  | ||||
|             response = self.client.get("/api/documents/") | ||||
|  | ||||
|             # 403 testing locally, 401 on ci... | ||||
|             self.assertIn( | ||||
|                 response.status_code, | ||||
|                 [status.HTTP_401_UNAUTHORIZED, status.HTTP_403_FORBIDDEN], | ||||
|             ) | ||||
|  | ||||
|             response = self.client.get( | ||||
|                 "/api/documents/", | ||||
|                 headers={ | ||||
|                     "Remote-User": self.user.username, | ||||
|                 }, | ||||
|             ) | ||||
|  | ||||
|             self.assertEqual(response.status_code, status.HTTP_200_OK) | ||||
|  | ||||
|     def test_remote_user_header_setting(self): | ||||
|         """ | ||||
|         GIVEN: | ||||
|             - Remote user header name is set | ||||
|         WHEN: | ||||
|             - Settings are parsed | ||||
|         THEN: | ||||
|             - Correct header name is returned | ||||
|         """ | ||||
|  | ||||
|         with mock.patch.dict( | ||||
|             os.environ, | ||||
|             { | ||||
|                 "PAPERLESS_ENABLE_HTTP_REMOTE_USER": "True", | ||||
|                 "PAPERLESS_HTTP_REMOTE_USER_HEADER_NAME": "HTTP_FOO", | ||||
|             }, | ||||
|         ): | ||||
|             header_name = _parse_remote_user_settings() | ||||
|  | ||||
|             self.assertEqual(header_name, "HTTP_FOO") | ||||
		Reference in New Issue
	
	Block a user
	 shamoon
					shamoon