diff --git a/docs/configuration/optional-settings.md b/docs/configuration/optional-settings.md index 88dd809182d..a88322badbc 100644 --- a/docs/configuration/optional-settings.md +++ b/docs/configuration/optional-settings.md @@ -447,6 +447,15 @@ Default width (in pixels) of a unit within a rack elevation. --- +## REMOTE_AUTH_AUTO_CREATE_GROUPS + +Default: `False` + +If `True`, NetBox will automatically create local groups to mirror +remote user groups (requires `REMOTE_AUTH_GROUP_SYNC_ENABLED`). + +--- + ## REMOTE_AUTH_AUTO_CREATE_USER Default: `False` diff --git a/netbox/netbox/authentication.py b/netbox/netbox/authentication.py index 653fad3b055..18007c26784 100644 --- a/netbox/netbox/authentication.py +++ b/netbox/netbox/authentication.py @@ -104,17 +104,32 @@ class RemoteUserBackend(_RemoteUserBackend): def create_unknown_user(self): return settings.REMOTE_AUTH_AUTO_CREATE_USER + @property + def create_unknown_groups(self): + return settings.REMOTE_AUTH_AUTO_CREATE_GROUPS + def configure_groups(self, user, remote_groups): logger = logging.getLogger('netbox.authentication.RemoteUserBackend') - # Assign default groups to the user + # Assign remote groups to the user group_list = [] for name in remote_groups: try: - group_list.append(Group.objects.get(name=name)) + if self.create_unknown_groups: + group, created = Group._default_manager.get_or_create(name=name) + if created: + logger.debug(f"Created group {name}") + else: + group = Group.objects.get(name=name) + + group_list.append(group) except Group.DoesNotExist: - logging.error( - f"Could not assign group {name} to remotely-authenticated user {user}: Group not found") + if settings.REMOTE_AUTH_AUTO_CREATE_GROUPS: + group_list.append(Group.objects.create(name=name)) + else: + logging.error( + f"Could not assign group {name} to remotely-authenticated user {user}: Group not found") + if group_list: user.groups.set(group_list) logger.debug( diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 35e0c6714cb..85a559a379f 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -115,6 +115,7 @@ RACK_ELEVATION_DEFAULT_UNIT_HEIGHT = getattr(configuration, 'RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', 22) RACK_ELEVATION_DEFAULT_UNIT_WIDTH = getattr(configuration, 'RACK_ELEVATION_DEFAULT_UNIT_WIDTH', 220) REMOTE_AUTH_AUTO_CREATE_USER = getattr(configuration, 'REMOTE_AUTH_AUTO_CREATE_USER', False) +REMOTE_AUTH_AUTO_CREATE_GROUPS = getattr(configuration, 'REMOTE_AUTH_AUTO_CREATE_GROUPS', False) REMOTE_AUTH_BACKEND = getattr(configuration, 'REMOTE_AUTH_BACKEND', 'netbox.authentication.RemoteUserBackend') REMOTE_AUTH_DEFAULT_GROUPS = getattr(configuration, 'REMOTE_AUTH_DEFAULT_GROUPS', []) REMOTE_AUTH_DEFAULT_PERMISSIONS = getattr(configuration, 'REMOTE_AUTH_DEFAULT_PERMISSIONS', {}) diff --git a/netbox/netbox/tests/test_authentication.py b/netbox/netbox/tests/test_authentication.py index 7fc12b4fd41..ae4a3ff5f08 100644 --- a/netbox/netbox/tests/test_authentication.py +++ b/netbox/netbox/tests/test_authentication.py @@ -176,6 +176,50 @@ def test_remote_auth_default_permissions(self): self.assertTrue(new_user.has_perms( ['dcim.add_site', 'dcim.change_site'])) + @override_settings( + REMOTE_AUTH_ENABLED=True, + REMOTE_AUTH_AUTO_CREATE_USER=True, + REMOTE_AUTH_AUTO_CREATE_GROUPS=True, + REMOTE_AUTH_GROUP_SYNC_ENABLED=True, + LOGIN_REQUIRED=True + ) + def test_remote_auth_auto_create_groups(self): + """ + Test auto creating groups with group sync enabled. + """ + + group_names = ( + 'Group 1', + 'Group 2', + 'Group 3', + ) + + headers = { + 'HTTP_REMOTE_USER': 'remoteuser2', + 'HTTP_REMOTE_USER_GROUP': '|'.join(group_names), + } + + self.assertTrue(settings.REMOTE_AUTH_ENABLED) + self.assertTrue(settings.REMOTE_AUTH_AUTO_CREATE_USER) + self.assertTrue(settings.REMOTE_AUTH_AUTO_CREATE_GROUPS) + self.assertTrue(settings.REMOTE_AUTH_GROUP_SYNC_ENABLED) + self.assertEqual(settings.REMOTE_AUTH_HEADER, 'HTTP_REMOTE_USER') + self.assertEqual(settings.REMOTE_AUTH_GROUP_HEADER, + 'HTTP_REMOTE_USER_GROUP') + self.assertEqual(settings.REMOTE_AUTH_GROUP_SEPARATOR, '|') + + response = self.client.get(reverse('home'), follow=True, **headers) + self.assertEqual(response.status_code, 200) + + new_user = User.objects.get(username='remoteuser2') + self.assertEqual(int(self.client.session.get( + '_auth_user_id')), new_user.pk, msg='Authentication failed') + + self.assertListEqual( + group_names, + [g.name for g in new_user.groups.all()], + ) + @override_settings( REMOTE_AUTH_ENABLED=True, REMOTE_AUTH_AUTO_CREATE_USER=True,