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: diff --git a/VERSION b/VERSION index a67ceba..2157409 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.21.1 +0.22.0 diff --git a/configuration/ldap_config.py b/configuration/ldap_config.py index 39fc894..ba2067c 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 = { diff --git a/initializers/groups.yml b/initializers/groups.yml index 7bdd0a7..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 @@ -8,9 +20,16 @@ # users: # - writer # permissions: -# - add_device -# - change_device # - delete_device -# - add_virtualmachine -# - change_virtualmachine # - delete_virtualmachine +# - add_* +# - change_* +# vm_managers: +# permissions: +# - '*_virtualmachine' +# device_managers: +# permissions: +# - '*device*' +# creators: +# permissions: +# - add_* diff --git a/initializers/users.yml b/initializers/users.yml index 64c005c..2aea62e 100644 --- a/initializers/users.yml +++ b/initializers/users.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: + # technical_user: # api_token: 0123456789technicaluser789abcdef01234567 # must be looooong! # reader: @@ -5,9 +17,7 @@ # writer: # password: writer # permissions: -# - add_device -# - change_device # - delete_device -# - add_virtualmachine -# - change_virtualmachine # - delete_virtualmachine +# - add_* +# - change_* diff --git a/startup_scripts/000_users.py b/startup_scripts/000_users.py index a1340a1..6962df0 100644 --- a/startup_scripts/000_users.py +++ b/startup_scripts/000_users.py @@ -20,15 +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']) - 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', []) + if yaml_permissions: + subject = user.user_permissions + subject.clear() + for yaml_permission in yaml_permissions: + if '*' in yaml_permission: + permission_filter = '^' + yaml_permission.replace('*','.*') + '$' + permissions = Permission.objects.filter(codename__iregex=permission_filter) + print(" ⚿ Granting", permissions.count(), "permissions matching '" + yaml_permission + "'") + else: + permissions = Permission.objects.filter(codename=yaml_permission) + print(" ⚿ Granting permission", yaml_permission) + + for permission in permissions: + subject.add(permission) diff --git a/startup_scripts/010_groups.py b/startup_scripts/010_groups.py index e68a5f0..08fb4bf 100644 --- a/startup_scripts/010_groups.py +++ b/startup_scripts/010_groups.py @@ -24,9 +24,18 @@ 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', []) + if yaml_permissions: + subject = group.permissions + subject.clear() + for yaml_permission in yaml_permissions: + if '*' in yaml_permission: + permission_filter = '^' + yaml_permission.replace('*','.*') + '$' + permissions = Permission.objects.filter(codename__iregex=permission_filter) + print(" ⚿ Granting", permissions.count(), "permissions matching '" + yaml_permission + "'") + else: + permissions = Permission.objects.filter(codename=yaml_permission) + print(" ⚿ Granting permission", yaml_permission) + + for permission in permissions: + subject.add(permission) 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)