From 00986573d907ea6e79fdf144b01992d56fe43d51 Mon Sep 17 00:00:00 2001 From: Kevin Newland Date: Tue, 28 Jan 2020 17:36:45 -0600 Subject: [PATCH 01/12] Update LDAP Caching Options Update LDAP caching configuration to match changes made to django-auth-ldap in 1.6.0 Django social auth now uses different cache configuration options: https://github.com/django-auth-ldap/django-auth-ldap/blob/master/django_auth_ldap/backend.py#L1041-L1056 NetBox settings.py reference: https://github.com/netbox-community/netbox/blob/master/netbox/netbox/settings.py#L360 --- configuration/ldap_config.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/configuration/ldap_config.py b/configuration/ldap_config.py index 39fc894..2ec75cd 100644 --- a/configuration/ldap_config.py +++ b/configuration/ldap_config.py @@ -70,8 +70,7 @@ AUTH_LDAP_USER_FLAGS_BY_GROUP = { AUTH_LDAP_FIND_GROUP_PERMS = os.environ.get('AUTH_LDAP_FIND_GROUP_PERMS', 'True').lower() == 'true' # Cache groups for one hour to reduce LDAP traffic -AUTH_LDAP_CACHE_GROUPS = os.environ.get('AUTH_LDAP_CACHE_GROUPS', 'True').lower() == 'true' -AUTH_LDAP_GROUP_CACHE_TIMEOUT = int(os.environ.get('AUTH_LDAP_GROUP_CACHE_TIMEOUT', 3600)) +AUTH_LDAP_CACHE_TIMEOUT = = int(os.environ.get('AUTH_LDAP_CACHE_TIMEOUT', 3600)) # Populate the Django user from the LDAP directory. AUTH_LDAP_USER_ATTR_MAP = { From 74eaae6bc82a959a752751e905c39255adc0c307 Mon Sep 17 00:00:00 2001 From: Kevin Newland Date: Tue, 28 Jan 2020 17:43:35 -0600 Subject: [PATCH 02/12] Update ldap_config.py --- configuration/ldap_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configuration/ldap_config.py b/configuration/ldap_config.py index 2ec75cd..ba2067c 100644 --- a/configuration/ldap_config.py +++ b/configuration/ldap_config.py @@ -70,7 +70,7 @@ AUTH_LDAP_USER_FLAGS_BY_GROUP = { AUTH_LDAP_FIND_GROUP_PERMS = os.environ.get('AUTH_LDAP_FIND_GROUP_PERMS', 'True').lower() == 'true' # Cache groups for one hour to reduce LDAP traffic -AUTH_LDAP_CACHE_TIMEOUT = = int(os.environ.get('AUTH_LDAP_CACHE_TIMEOUT', 3600)) +AUTH_LDAP_CACHE_TIMEOUT = int(os.environ.get('AUTH_LDAP_CACHE_TIMEOUT', 3600)) # Populate the Django user from the LDAP directory. AUTH_LDAP_USER_ATTR_MAP = { From 778f7546b8e4d5f20fbc9b2cb7000bf0495749fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20M=C3=A4der?= Date: Thu, 30 Jan 2020 15:48:01 +0100 Subject: [PATCH 03/12] Enable push workflow for PRs --- .github/workflows/push.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 569b333..4932ae8 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -4,6 +4,9 @@ on: push: branches-ignore: - release + pull_request: + branches-ignore: + - release jobs: build: From 927a545f41b6ca8490e12de63ca0d346043884e9 Mon Sep 17 00:00:00 2001 From: Les Begnaud Date: Thu, 5 Dec 2019 09:41:11 -0600 Subject: [PATCH 04/12] adjust groups and users startup scripts to allow custom codename filter --- initializers/groups.yml | 14 ++++++++++---- initializers/users.yml | 8 ++++---- startup_scripts/000_users.py | 27 ++++++++++++++++++++------- startup_scripts/010_groups.py | 24 ++++++++++++++++++------ 4 files changed, 52 insertions(+), 21 deletions(-) diff --git a/initializers/groups.yml b/initializers/groups.yml index 7bdd0a7..fc9ff28 100644 --- a/initializers/groups.yml +++ b/initializers/groups.yml @@ -7,10 +7,16 @@ # writers: # users: # - writer +## specify explicit permission codenames or codename filter functions and filters to match on # permissions: -# - add_device -# - change_device # - delete_device -# - add_virtualmachine -# - change_virtualmachine # - delete_virtualmachine +# - codename__startswith: +# - add_ +# - change_ +# vm_managers: +# - codename__endswith: +# - _virtualmachine +# creators: +# - codename__startswith: +# - add_ diff --git a/initializers/users.yml b/initializers/users.yml index 64c005c..a7a57a3 100644 --- a/initializers/users.yml +++ b/initializers/users.yml @@ -4,10 +4,10 @@ # password: reader # writer: # password: writer +## specify explicit permission codenames or codename filter functions and filters to match on # permissions: -# - add_device -# - change_device # - delete_device -# - add_virtualmachine -# - change_virtualmachine # - delete_virtualmachine +# - codename__startswith: +# - add_ +# - change_ diff --git a/startup_scripts/000_users.py b/startup_scripts/000_users.py index a1340a1..0037ee1 100644 --- a/startup_scripts/000_users.py +++ b/startup_scripts/000_users.py @@ -25,10 +25,23 @@ with file.open('r') as stream: if user_details.get('api_token', 0): Token.objects.create(user=user, key=user_details['api_token']) - user_permissions = user_details.get('permissions', []) - if user_permissions: - user.user_permissions.clear() - for permission_codename in user_details.get('permissions', []): - for permission in Permission.objects.filter(codename=permission_codename): - user.user_permissions.add(permission) - user.save() + yaml_permissions = user_details.get('permissions', []) + permission_object = user + if yaml_permissions: + permission_object.permissions.clear() + for yaml_permission in yaml_permissions: + if isinstance(yaml_permission,dict): + # assume this is the specific codename filter function instead of an exact codename + permission_codename_function = list(yaml_permission.keys())[0] + permission_codenames = yaml_permission[permission_codename_function] + else: + permission_codename_function = 'codename' + permission_codenames = list({yaml_permission}) + + # supports either one codename from the permissions list, or multiple codenames in a codename_function dict + for permission_codename in permission_codenames: + # supports non-unique permission codenames + for permission in eval('Permission.objects.filter(' + permission_codename_function + '=permission_codename)'): + permission_object.permissions.add(permission) + + permission_object.save() diff --git a/startup_scripts/010_groups.py b/startup_scripts/010_groups.py index e68a5f0..49b6678 100644 --- a/startup_scripts/010_groups.py +++ b/startup_scripts/010_groups.py @@ -24,9 +24,21 @@ with file.open('r') as stream: if user: user.groups.add(group) - group_permissions = group_details.get('permissions', []) - if group_permissions: - group.permissions.clear() - for permission_codename in group_details.get('permissions', []): - for permission in Permission.objects.filter(codename=permission_codename): - group.permissions.add(permission) + yaml_permissions = group_details.get('permissions', []) + permission_object = group + if yaml_permissions: + permission_object.permissions.clear() + for yaml_permission in yaml_permissions: + if isinstance(yaml_permission,dict): + # assume this is the specific codename filter function instead of an exact codename + permission_codename_function = list(yaml_permission.keys())[0] + permission_codenames = yaml_permission[permission_codename_function] + else: + permission_codename_function = 'codename' + permission_codenames = list({yaml_permission}) + + # supports either one codename from the permissions list, or multiple codenames in a codename_function dict + for permission_codename in permission_codenames: + # supports non-unique permission codenames + for permission in eval('Permission.objects.filter(' + permission_codename_function + '=permission_codename)'): + permission_object.permissions.add(permission) From cce4370d4141db79b1df37fdcf905b4e6b6d1189 Mon Sep 17 00:00:00 2001 From: Les Begnaud Date: Thu, 5 Dec 2019 09:44:40 -0600 Subject: [PATCH 05/12] add permission example --- initializers/groups.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/initializers/groups.yml b/initializers/groups.yml index fc9ff28..6d0665f 100644 --- a/initializers/groups.yml +++ b/initializers/groups.yml @@ -17,6 +17,9 @@ # vm_managers: # - codename__endswith: # - _virtualmachine +# device_managers: +# - codename__contains: +# - device # creators: # - codename__startswith: # - add_ From aa0d2a6e01b7ace9e81f91a56b09eae844352278 Mon Sep 17 00:00:00 2001 From: Les Begnaud Date: Wed, 11 Dec 2019 10:14:38 -0600 Subject: [PATCH 06/12] simplify yml definitions to use wildcard syntax --- initializers/groups.yml | 16 ++++++---------- initializers/users.yml | 7 +++---- startup_scripts/000_users.py | 19 ++++++++----------- startup_scripts/010_groups.py | 19 ++++++++----------- 4 files changed, 25 insertions(+), 36 deletions(-) diff --git a/initializers/groups.yml b/initializers/groups.yml index 6d0665f..d471fe3 100644 --- a/initializers/groups.yml +++ b/initializers/groups.yml @@ -7,19 +7,15 @@ # writers: # users: # - writer -## specify explicit permission codenames or codename filter functions and filters to match on +## specify explicit permission codenames or include wildcard to match multiple permissions # permissions: # - delete_device # - delete_virtualmachine -# - codename__startswith: -# - add_ -# - change_ +# - add_* +# - change_* # vm_managers: -# - codename__endswith: -# - _virtualmachine +# - *_virtualmachine # device_managers: -# - codename__contains: -# - device +# - *device* # creators: -# - codename__startswith: -# - add_ +# - add_* diff --git a/initializers/users.yml b/initializers/users.yml index a7a57a3..ad654b7 100644 --- a/initializers/users.yml +++ b/initializers/users.yml @@ -4,10 +4,9 @@ # password: reader # writer: # password: writer -## specify explicit permission codenames or codename filter functions and filters to match on +## specify explicit permission codenames or include wildcard to match multiple permissions # permissions: # - delete_device # - delete_virtualmachine -# - codename__startswith: -# - add_ -# - change_ +# - add_* +# - change_* diff --git a/startup_scripts/000_users.py b/startup_scripts/000_users.py index 0037ee1..cb04a16 100644 --- a/startup_scripts/000_users.py +++ b/startup_scripts/000_users.py @@ -30,18 +30,15 @@ with file.open('r') as stream: if yaml_permissions: permission_object.permissions.clear() for yaml_permission in yaml_permissions: - if isinstance(yaml_permission,dict): - # assume this is the specific codename filter function instead of an exact codename - permission_codename_function = list(yaml_permission.keys())[0] - permission_codenames = yaml_permission[permission_codename_function] + if '*' in yaml_permission: + permission_codename_function = 'codename__iregex' + permission_codename = '^' + yaml_permission.replace('*','.*') + '$' else: permission_codename_function = 'codename' - permission_codenames = list({yaml_permission}) - - # supports either one codename from the permissions list, or multiple codenames in a codename_function dict - for permission_codename in permission_codenames: - # supports non-unique permission codenames - for permission in eval('Permission.objects.filter(' + permission_codename_function + '=permission_codename)'): - permission_object.permissions.add(permission) + permission_codename = yaml_permission + + # supports non-unique permission codenames + for permission in eval('Permission.objects.filter(' + permission_codename_function + '=permission_codename)'): + permission_object.permissions.add(permission) permission_object.save() diff --git a/startup_scripts/010_groups.py b/startup_scripts/010_groups.py index 49b6678..990e065 100644 --- a/startup_scripts/010_groups.py +++ b/startup_scripts/010_groups.py @@ -29,16 +29,13 @@ with file.open('r') as stream: if yaml_permissions: permission_object.permissions.clear() for yaml_permission in yaml_permissions: - if isinstance(yaml_permission,dict): - # assume this is the specific codename filter function instead of an exact codename - permission_codename_function = list(yaml_permission.keys())[0] - permission_codenames = yaml_permission[permission_codename_function] + if '*' in yaml_permission: + permission_codename_function = 'codename__iregex' + permission_codename = '^' + yaml_permission.replace('*','.*') + '$' else: permission_codename_function = 'codename' - permission_codenames = list({yaml_permission}) - - # supports either one codename from the permissions list, or multiple codenames in a codename_function dict - for permission_codename in permission_codenames: - # supports non-unique permission codenames - for permission in eval('Permission.objects.filter(' + permission_codename_function + '=permission_codename)'): - permission_object.permissions.add(permission) + permission_codename = yaml_permission + + # supports non-unique permission codenames + for permission in eval('Permission.objects.filter(' + permission_codename_function + '=permission_codename)'): + permission_object.permissions.add(permission) From f4e243d5ad55c56090164e14fc68173b002eaa78 Mon Sep 17 00:00:00 2001 From: Les Begnaud Date: Wed, 11 Dec 2019 10:21:28 -0600 Subject: [PATCH 07/12] update example to note yaml restriction --- initializers/groups.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/initializers/groups.yml b/initializers/groups.yml index d471fe3..67a9290 100644 --- a/initializers/groups.yml +++ b/initializers/groups.yml @@ -14,8 +14,9 @@ # - add_* # - change_* # vm_managers: -# - *_virtualmachine +## yaml doesn't allow starting a key with an asterisk without explicit use of single quote +# - '*_virtualmachine' # device_managers: -# - *device* +# - '*device*' # creators: # - add_* From a2c06026d57ff2a5160df9eed116ba713e019e8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20M=C3=A4der?= Date: Fri, 31 Jan 2020 11:35:25 +0100 Subject: [PATCH 08/12] Ajdust indents in __main__.py ... so that the match the style of the other python code in this project --- startup_scripts/__main__.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/startup_scripts/__main__.py b/startup_scripts/__main__.py index 50d2613..b13b8dd 100644 --- a/startup_scripts/__main__.py +++ b/startup_scripts/__main__.py @@ -7,12 +7,12 @@ from os.path import dirname, abspath this_dir = dirname(abspath(__file__)) def filename(f): - return f.name + return f.name with scandir(dirname(abspath(__file__))) as it: - for f in sorted(it, key = filename): - if f.name.startswith('__') or not f.is_file(): - continue - - print(f"Running {f.path}") - runpy.run_path(f.path) + for f in sorted(it, key = filename): + if f.name.startswith('__') or not f.is_file(): + continue + + print(f"Running {f.path}") + runpy.run_path(f.path) From ba3176f140973b6bad219269a24467e6aa1b3a3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20M=C3=A4der?= Date: Fri, 31 Jan 2020 11:37:05 +0100 Subject: [PATCH 09/12] Added missing keywords to the yaml ... and moved some documentatory comments to the beginning of the file. --- initializers/groups.yml | 17 +++++++++++++++-- initializers/users.yml | 13 ++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/initializers/groups.yml b/initializers/groups.yml index 67a9290..b91ef39 100644 --- a/initializers/groups.yml +++ b/initializers/groups.yml @@ -1,3 +1,15 @@ +## To list all permissions, run: +## +## docker-compose run --rm --entrypoint /bin/bash netbox +## $ ./manage.py migrate +## $ ./manage.py shell +## > from django.contrib.auth.models import Permission +## > print('\n'.join([p.codename for p in Permission.objects.all()])) +## +## Permission lists support wildcards. See the examples below. +## +## Examples: + # applications: # users: # - technical_user @@ -7,16 +19,17 @@ # writers: # users: # - writer -## specify explicit permission codenames or include wildcard to match multiple permissions # permissions: # - delete_device # - delete_virtualmachine # - add_* # - change_* # vm_managers: -## yaml doesn't allow starting a key with an asterisk without explicit use of single quote +# permissions: # - '*_virtualmachine' # device_managers: +# permissions: # - '*device*' # creators: +# permissions: # - add_* diff --git a/initializers/users.yml b/initializers/users.yml index ad654b7..2aea62e 100644 --- a/initializers/users.yml +++ b/initializers/users.yml @@ -1,10 +1,21 @@ +## To list all permissions, run: +## +## docker-compose run --rm --entrypoint /bin/bash netbox +## $ ./manage.py migrate +## $ ./manage.py shell +## > from django.contrib.auth.models import Permission +## > print('\n'.join([p.codename for p in Permission.objects.all()])) +## +## Permission lists support wildcards. See the examples below. +## +## Examples: + # technical_user: # api_token: 0123456789technicaluser789abcdef01234567 # must be looooong! # reader: # password: reader # writer: # password: writer -## specify explicit permission codenames or include wildcard to match multiple permissions # permissions: # - delete_device # - delete_virtualmachine From 69ef7b78272654ea8e3610da8b30eb981e391275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20M=C3=A4der?= Date: Fri, 31 Jan 2020 11:39:05 +0100 Subject: [PATCH 10/12] Removed the eval from the code ... and changed it to make it work with the latest Netbox version. --- startup_scripts/000_users.py | 22 ++++++++++------------ startup_scripts/010_groups.py | 20 ++++++++++---------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/startup_scripts/000_users.py b/startup_scripts/000_users.py index cb04a16..446aaeb 100644 --- a/startup_scripts/000_users.py +++ b/startup_scripts/000_users.py @@ -20,25 +20,23 @@ with file.open('r') as stream: username = username, password = user_details.get('password', 0) or User.objects.make_random_password) - print("👤 Created user ",username) + print("👤 Created user",username) if user_details.get('api_token', 0): Token.objects.create(user=user, key=user_details['api_token']) yaml_permissions = user_details.get('permissions', []) - permission_object = user + subject = user.user_permissions if yaml_permissions: - permission_object.permissions.clear() + subject.clear() for yaml_permission in yaml_permissions: if '*' in yaml_permission: - permission_codename_function = 'codename__iregex' - permission_codename = '^' + yaml_permission.replace('*','.*') + '$' + permission_filter = '^' + yaml_permission.replace('*','.*') + '$' + permissions = Permission.objects.filter(codename__iregex=permission_filter) + print(" ⚿ Granting", permissions.count(), "permissions matching '" + yaml_permission + "'") else: - permission_codename_function = 'codename' - permission_codename = yaml_permission + permissions = Permission.objects.filter(codename=yaml_permission) + print(" ⚿ Granting permission", yaml_permission) - # supports non-unique permission codenames - for permission in eval('Permission.objects.filter(' + permission_codename_function + '=permission_codename)'): - permission_object.permissions.add(permission) - - permission_object.save() + for permission in permissions: + subject.add(permission) diff --git a/startup_scripts/010_groups.py b/startup_scripts/010_groups.py index 990e065..0a35387 100644 --- a/startup_scripts/010_groups.py +++ b/startup_scripts/010_groups.py @@ -25,17 +25,17 @@ with file.open('r') as stream: user.groups.add(group) yaml_permissions = group_details.get('permissions', []) - permission_object = group + subject = group.permissions if yaml_permissions: - permission_object.permissions.clear() + subject.clear() for yaml_permission in yaml_permissions: if '*' in yaml_permission: - permission_codename_function = 'codename__iregex' - permission_codename = '^' + yaml_permission.replace('*','.*') + '$' + permission_filter = '^' + yaml_permission.replace('*','.*') + '$' + permissions = Permission.objects.filter(codename__iregex=permission_filter) + print(" ⚿ Granting", permissions.count(), "permissions matching '" + yaml_permission + "'") else: - permission_codename_function = 'codename' - permission_codename = yaml_permission - - # supports non-unique permission codenames - for permission in eval('Permission.objects.filter(' + permission_codename_function + '=permission_codename)'): - permission_object.permissions.add(permission) + permissions = Permission.objects.filter(codename=yaml_permission) + print(" ⚿ Granting permission", yaml_permission) + + for permission in permissions: + subject.add(permission) From 3d80cc5a722c80285be4b803ecbdde60e0199f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20M=C3=A4der?= Date: Sun, 2 Feb 2020 09:48:02 +0100 Subject: [PATCH 11/12] Tiny code refactoring --- startup_scripts/000_users.py | 2 +- startup_scripts/010_groups.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/startup_scripts/000_users.py b/startup_scripts/000_users.py index 446aaeb..6962df0 100644 --- a/startup_scripts/000_users.py +++ b/startup_scripts/000_users.py @@ -26,8 +26,8 @@ with file.open('r') as stream: Token.objects.create(user=user, key=user_details['api_token']) yaml_permissions = user_details.get('permissions', []) - subject = user.user_permissions if yaml_permissions: + subject = user.user_permissions subject.clear() for yaml_permission in yaml_permissions: if '*' in yaml_permission: diff --git a/startup_scripts/010_groups.py b/startup_scripts/010_groups.py index 0a35387..08fb4bf 100644 --- a/startup_scripts/010_groups.py +++ b/startup_scripts/010_groups.py @@ -25,8 +25,8 @@ with file.open('r') as stream: user.groups.add(group) yaml_permissions = group_details.get('permissions', []) - subject = group.permissions if yaml_permissions: + subject = group.permissions subject.clear() for yaml_permission in yaml_permissions: if '*' in yaml_permission: From e99a222a70fe3ae27762a3ced8882f71ca614ac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20M=C3=A4der?= Date: Fri, 31 Jan 2020 09:19:53 +0100 Subject: [PATCH 12/12] Prepare v0.22.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index a67ceba..2157409 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.21.1 +0.22.0