From 9ef003e50a764bb3a6b974758285a889ad29d6bd Mon Sep 17 00:00:00 2001 From: Josue Kouka Date: Fri, 4 Aug 2017 12:03:34 +0200 Subject: [PATCH] add roles import/export command (#16514) --- src/authentic2/a2_rbac/models.py | 63 ++++++++++++++++++++++ src/authentic2/management/commands/export-roles.py | 26 +++++++++ src/authentic2/management/commands/import-roles.py | 21 ++++++++ src/authentic2/models.py | 13 +++++ src/authentic2/utils.py | 25 +++++++++ 5 files changed, 148 insertions(+) create mode 100644 src/authentic2/management/commands/export-roles.py create mode 100644 src/authentic2/management/commands/import-roles.py diff --git a/src/authentic2/a2_rbac/models.py b/src/authentic2/a2_rbac/models.py index 42cd2a95..ac44eb93 100644 --- a/src/authentic2/a2_rbac/models.py +++ b/src/authentic2/a2_rbac/models.py @@ -80,6 +80,19 @@ class OrganizationalUnit(OrganizationalUnitAbstractBase): def natural_key(self): return [self.slug] + @classmethod + def get_ou_or_default(cls, uuid, slug, name): + try: + ou = cls.objects.get(uuid=uuid) + return ou + except cls.DoesNotExist: + ou = cls.objects.get(slug=slug) + return ou + except cls.DoesNotExist: + ou = cls.objects.get(name=name) + return ou + return rbac_utils.get_default_ou() + class Permission(PermissionAbstractBase): class Meta: @@ -195,6 +208,56 @@ class Role(RoleAbstractBase): 'ou__slug': self.ou.slug if self.ou else None, } + @classmethod + def import_json(cls, data): + from authentic2.models import Service + ou_json = data.pop('ou', {}) + service_json = data.pop('service', {}) + attributes_json = data.pop('attributes', {}) + + ou = OrganizationalUnit.get_ou_or_default(**ou_json) + kwargs = {'uuid': data['uuid'], 'slug': data['slug'], 'name': data['name']} + role, created = cls.objects.get_or_create(ou=ou, **kwargs) + # set attributes + for attr in attributes_json: + attribute, created = RoleAttribute.objects.get_or_create( + role=role, name=attr['name'], kind=attr['kind'], defaults={ + 'value': attr['value']}) + if created: + attribute.value = attr['value'] + attribute.save() + # set service if any + if service_json: + service_json.pop('ou') + Service.import_json(ou=ou, **service_json) + + def export_json(self): + data = { + 'uuid': self.uuid, + 'slug': self.slug, + 'name': self.name, + } + if self.ou: + data['ou'] = { + 'uuid': self.ou.uuid, + 'name': self.ou.name, + 'slug': self.ou.slug + } + + attributes = [] + for attr in self.attributes.all(): + attributes.append({ + 'name': attr.name, 'kind': attr.kind, + 'value': attr.value}) + data['attributes'] = attributes + + parents = [] + for parent in self.parents(include_self=False): + parents.append({ + 'uuid': parent.uuid, 'slug': parent.slug, 'name': parent.name}) + data['parents'] = parents + return data + class RoleParenting(RoleParentingAbstractBase): class Meta(RoleParentingAbstractBase.Meta): diff --git a/src/authentic2/management/commands/export-roles.py b/src/authentic2/management/commands/export-roles.py new file mode 100644 index 00000000..8389bd95 --- /dev/null +++ b/src/authentic2/management/commands/export-roles.py @@ -0,0 +1,26 @@ +import json +from optparse import make_option +import sys + +from django.core.management import BaseCommand + +from authentic2.utils import export_roles + + +class Command(BaseCommand): + help = 'Export roles as json' + + args = '' + + option_list = BaseCommand.option_list + ( + make_option('--ou', dest='ou', default=None, type=str, + help='restrict to the organizational unit slug'),) + + def handle(self, *args, **options): + if len(args) < 1: + output = sys.stdout + else: + output = open(args[0], 'w') + + data = export_roles(ou_slug=options['ou']) + json.dump(data, output, encoding='utf-8', indent=4) diff --git a/src/authentic2/management/commands/import-roles.py b/src/authentic2/management/commands/import-roles.py new file mode 100644 index 00000000..c09a2a56 --- /dev/null +++ b/src/authentic2/management/commands/import-roles.py @@ -0,0 +1,21 @@ +import json +from optparse import make_option + +from django.core.management.base import BaseCommand + +from authentic2.utils import import_roles + + +class Command(BaseCommand): + help = 'Import roles from json file' + + args = '' + + option_list = BaseCommand.option_list + ( + make_option('--ou', dest='ou', default=None, type=str, + help='restrict to the organizational unit slug'),) + + def handle(self, *args, **options): + if args: + fd = open(args[0]) + import_roles(json.load(fd), ou_slug=options['ou']) diff --git a/src/authentic2/models.py b/src/authentic2/models.py index 40afd94e..96345ff2 100644 --- a/src/authentic2/models.py +++ b/src/authentic2/models.py @@ -399,6 +399,19 @@ class Service(models.Model): 'roles': [role.to_json() for role in roles], } + @classmethod + def import_json(cls, data): + ou = data.pop('ou') + cls.objects.get_or_create(ou=ou, **data) + + def export_json(self): + return { + 'name': self.name, 'slug': self.slug, + 'ou': { + 'uuid': self.ou.uuid, 'slug': self.ou.slug, 'name': self.ou.name + } + } + class AuthorizedRole(models.Model): service = models.ForeignKey(Service, on_delete=models.CASCADE) diff --git a/src/authentic2/utils.py b/src/authentic2/utils.py index 3ca79e14..8ce1f395 100644 --- a/src/authentic2/utils.py +++ b/src/authentic2/utils.py @@ -942,3 +942,28 @@ def simulate_authentication(request, user, method, user = copy.deepcopy(user) user.backend = backend return login(request, user, method, **kwargs) + + +def export_roles(ou_slug=None): + from django_rbac.utils import get_role_model + Role = get_role_model() + filters = {'slug__startswith': '_'} + if ou_slug: + roles = Role.objects.filter(ou__slug=ou_slug).exclude(**filters) + else: + roles = Role.objects.exclude(**filters) + return [role.export_json() for role in roles] + + +def import_roles(data, ou_slug=None): + from django_rbac.utils import get_role_model + Role = get_role_model() + if ou_slug: + data = [datum for datum in data if datum['ou']['slug'] == ou_slug] + for role_json in data: + Role.import_json(role_json) + # once all roles are created, set their relationships + for role_json in data: + role = Role.objects.get(uuid=role_json['uuid']) + for parent in role_json.get('parents', []): + role.add_parent(Role.objects.get(uuid=parent['uuid'])) -- 2.11.0