From 611df4632b3df5a04a1fdfcd8974f30701493969 Mon Sep 17 00:00:00 2001 From: Josue Kouka Date: Wed, 27 Sep 2017 18:06:04 +0200 Subject: [PATCH] add roles import/export command (#16514) --- src/authentic2/a2_rbac/models.py | 34 +++++++++++++++++++++- .../commands/{export_roles.py => export-roles.py} | 15 +++++----- src/authentic2/management/commands/import-roles.py | 21 +++++++++++++ src/authentic2/models.py | 13 +++++++++ src/authentic2/utils.py | 26 ++++++++++++----- 5 files changed, 92 insertions(+), 17 deletions(-) rename src/authentic2/management/commands/{export_roles.py => export-roles.py} (53%) 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 f936f78c..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: @@ -197,7 +210,26 @@ class Role(RoleAbstractBase): @classmethod def import_json(cls, data): - pass + 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 = { diff --git a/src/authentic2/management/commands/export_roles.py b/src/authentic2/management/commands/export-roles.py similarity index 53% rename from src/authentic2/management/commands/export_roles.py rename to src/authentic2/management/commands/export-roles.py index 87554b6f..8389bd95 100644 --- a/src/authentic2/management/commands/export_roles.py +++ b/src/authentic2/management/commands/export-roles.py @@ -1,5 +1,6 @@ import json from optparse import make_option +import sys from django.core.management import BaseCommand @@ -7,21 +8,19 @@ from authentic2.utils import export_roles class Command(BaseCommand): - help = 'Dumps roles as json' + help = 'Export roles as json' args = '' option_list = BaseCommand.option_list + ( make_option('--ou', dest='ou', default=None, type=str, - help='organizational unit name of roles to be dumped'),) + help='restrict to the organizational unit slug'),) def handle(self, *args, **options): if len(args) < 1: - filename = 'roles.json' + output = sys.stdout else: - filename = args[0] + output = open(args[0], 'w') - ou = options['ou'] - data = export_roles(ou=ou) - with open(filename, 'wb') as fd: - json.dump(data, fd, encoding='utf-8') + 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 88ae18ee..8ce1f395 100644 --- a/src/authentic2/utils.py +++ b/src/authentic2/utils.py @@ -944,16 +944,26 @@ def simulate_authentication(request, user, method, return login(request, user, method, **kwargs) -def export_roles(ou=None): - from django_rbac.utils import get_role_model, get_ou_model +def export_roles(ou_slug=None): + from django_rbac.utils import get_role_model Role = get_role_model() - if ou: - ou = get_ou_model().get(slug=ou) - roles = Role.objects.filter(ou=ou) + filters = {'slug__startswith': '_'} + if ou_slug: + roles = Role.objects.filter(ou__slug=ou_slug).exclude(**filters) else: - roles = Role.objects.all() + roles = Role.objects.exclude(**filters) return [role.export_json() for role in roles] -def import_roles(data): - pass +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