Repository: netbox-community/netbox

Issue:
Allow Full Name to be set by remote authentication
### NetBox version

v3.4.7

### Feature type

Change to existing functionality

### Proposed functionality

Add a variable `REMOTE_AUTH_FULL_NAME` or similar which would define a header that provides the user's full name. This would then update the Full Name field in the user's profile.


### Use case

Netbox displays the full name in various places since https://github.com/netbox-community/netbox/issues/8556 and https://github.com/netbox-community/netbox/issues/8894, so it would be good to be able to automatically populate that field.

### Database changes

n/a

### External dependencies

n/a


Discussion:
Happy to take this on board.

Resolving patch:
diff --git a/netbox/netbox/configuration_example.py b/netbox/netbox/configuration_example.py
--- a/netbox/netbox/configuration_example.py
+++ b/netbox/netbox/configuration_example.py
@@ -193,6 +193,9 @@
 REMOTE_AUTH_ENABLED = False
 REMOTE_AUTH_BACKEND = 'netbox.authentication.RemoteUserBackend'
 REMOTE_AUTH_HEADER = 'HTTP_REMOTE_USER'
+REMOTE_AUTH_USER_FIRST_NAME = 'HTTP_REMOTE_USER_FIRST_NAME'
+REMOTE_AUTH_USER_LAST_NAME = 'HTTP_REMOTE_USER_LAST_NAME'
+REMOTE_AUTH_USER_EMAIL = 'HTTP_REMOTE_USER_EMAIL'
 REMOTE_AUTH_AUTO_CREATE_USER = True
 REMOTE_AUTH_DEFAULT_GROUPS = []
 REMOTE_AUTH_DEFAULT_PERMISSIONS = {}
diff --git a/netbox/netbox/middleware.py b/netbox/netbox/middleware.py
--- a/netbox/netbox/middleware.py
+++ b/netbox/netbox/middleware.py
@@ -87,7 +87,17 @@ def process_request(self, request):
         else:
             user = auth.authenticate(request, remote_user=username)
         if user:
-            # User is valid.  Set request.user and persist user in the session
+            # User is valid.
+            # Update the User's Profile if set by request headers
+            if settings.REMOTE_AUTH_USER_FIRST_NAME in request.META:
+                user.first_name = request.META[settings.REMOTE_AUTH_USER_FIRST_NAME]
+            if settings.REMOTE_AUTH_USER_LAST_NAME in request.META:
+                user.last_name = request.META[settings.REMOTE_AUTH_USER_LAST_NAME]
+            if settings.REMOTE_AUTH_USER_EMAIL in request.META:
+                user.email = request.META[settings.REMOTE_AUTH_USER_EMAIL]
+            user.save()
+
+            # Set request.user and persist user in the session
             # by logging the user in.
             request.user = user
             auth.login(request, user)
diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py
--- a/netbox/netbox/settings.py
+++ b/netbox/netbox/settings.py
@@ -113,6 +113,9 @@
 REMOTE_AUTH_DEFAULT_PERMISSIONS = getattr(configuration, 'REMOTE_AUTH_DEFAULT_PERMISSIONS', {})
 REMOTE_AUTH_ENABLED = getattr(configuration, 'REMOTE_AUTH_ENABLED', False)
 REMOTE_AUTH_HEADER = getattr(configuration, 'REMOTE_AUTH_HEADER', 'HTTP_REMOTE_USER')
+REMOTE_AUTH_USER_FIRST_NAME = getattr(configuration, 'REMOTE_AUTH_USER_FIRST_NAME', 'HTTP_REMOTE_USER_FIRST_NAME')
+REMOTE_AUTH_USER_LAST_NAME = getattr(configuration, 'REMOTE_AUTH_USER_LAST_NAME', 'HTTP_REMOTE_USER_LAST_NAME')
+REMOTE_AUTH_USER_EMAIL = getattr(configuration, 'REMOTE_AUTH_USER_EMAIL', 'HTTP_REMOTE_USER_EMAIL')
 REMOTE_AUTH_GROUP_HEADER = getattr(configuration, 'REMOTE_AUTH_GROUP_HEADER', 'HTTP_REMOTE_USER_GROUP')
 REMOTE_AUTH_GROUP_SYNC_ENABLED = getattr(configuration, 'REMOTE_AUTH_GROUP_SYNC_ENABLED', False)
 REMOTE_AUTH_SUPERUSER_GROUPS = getattr(configuration, 'REMOTE_AUTH_SUPERUSER_GROUPS', [])


Test patch:
diff --git a/netbox/netbox/tests/test_authentication.py b/netbox/netbox/tests/test_authentication.py
--- a/netbox/netbox/tests/test_authentication.py
+++ b/netbox/netbox/tests/test_authentication.py
@@ -151,6 +151,29 @@ def test_remote_auth_custom_header(self):
         self.assertEqual(int(self.client.session.get(
             '_auth_user_id')), self.user.pk, msg='Authentication failed')
 
+    @override_settings(
+        REMOTE_AUTH_ENABLED=True,
+        LOGIN_REQUIRED=True
+    )
+    def test_remote_auth_user_profile(self):
+        """
+        Test remote authentication with user profile details.
+        """
+        headers = {
+            'HTTP_REMOTE_USER': 'remoteuser1',
+            'HTTP_REMOTE_USER_FIRST_NAME': 'John',
+            'HTTP_REMOTE_USER_LAST_NAME': 'Smith',
+            'HTTP_REMOTE_USER_EMAIL': 'johnsmith@example.com',
+        }
+
+        response = self.client.get(reverse('home'), follow=True, **headers)
+        self.assertEqual(response.status_code, 200)
+
+        self.user = User.objects.get(username='remoteuser1')
+        self.assertEqual(self.user.first_name, "John", msg='User first name was not updated')
+        self.assertEqual(self.user.last_name, "Smith", msg='User last name was not updated')
+        self.assertEqual(self.user.email, "johnsmith@example.com", msg='User email was not updated')
+
     @override_settings(
         REMOTE_AUTH_ENABLED=True,
         REMOTE_AUTH_AUTO_CREATE_USER=True,