Projet

Général

Profil

0001-add-roles-import-export-command-16514.patch

Josué Kouka, 29 septembre 2017 09:47

Télécharger (9,51 ko)

Voir les différences:

Subject: [PATCH] add roles import/export command (#16514)

 src/authentic2/a2_rbac/models.py                   | 65 ++++++++++++++++++++++
 src/authentic2/management/commands/export-roles.py | 26 +++++++++
 src/authentic2/management/commands/import-roles.py | 27 +++++++++
 src/authentic2/models.py                           | 13 +++++
 src/authentic2/utils.py                            | 63 ++++++++++++++++++++-
 5 files changed, 193 insertions(+), 1 deletion(-)
 create mode 100644 src/authentic2/management/commands/export-roles.py
 create mode 100644 src/authentic2/management/commands/import-roles.py
src/authentic2/a2_rbac/models.py
10 10
                                CHANGE_OP, Operation)
11 11
from django_rbac import utils as rbac_utils
12 12

  
13
from authentic2.utils import get_object_by_main_attr, ImportExportError
14

  
13 15
try:
14 16
    from django.contrib.contenttypes.fields import GenericForeignKey, \
15 17
        GenericRelation
......
195 197
            'ou__slug': self.ou.slug if self.ou else None,
196 198
        }
197 199

  
200
    @classmethod
201
    def import_json(cls, data):
202
        from authentic2.models import Service
203
        ou_json = data.pop('ou', {})
204
        service_json = data.pop('service', {})
205
        attributes_json = data.pop('attributes', {})
206

  
207
        # if not ou stop import
208
        ou = get_object_by_main_attr(OrganizationalUnit, **ou_json)
209
        if not ou:
210
            raise ImportExportError('OU (%(uuid)s, %(slug)s, %(name)s) does not exist.' % ou_json)
211
        # get role's service or raise an exception if none is found
212
        service = None
213
        if service_json:
214
            service_json.pop('ou')
215
            service = get_object_by_main_attr(Service, **service_json)
216
            if not service:
217
                raise ImportExportError('Service (%(slug)s, %(name)s) does not exist.' % service_json)
218

  
219
        kwargs = {'uuid': data['uuid'], 'slug': data['slug'], 'name': data['name']}
220
        role, created = cls.objects.get_or_create(ou=ou, **kwargs)
221
        # set service
222
        if service:
223
            service.roles.add(role)
224
        # set attributes
225
        for attr in attributes_json:
226
            attribute, created = RoleAttribute.objects.get_or_create(
227
                role=role, name=attr['name'], kind=attr['kind'], defaults={
228
                    'value': attr['value']})
229
            if created:
230
                attribute.value = attr['value']
231
                attribute.save()
232

  
233
    def export_json(self):
234
        data = {
235
            'uuid': self.uuid,
236
            'slug': self.slug,
237
            'name': self.name,
238
        }
239
        if self.ou:
240
            data['ou'] = {
241
                'uuid': self.ou.uuid,
242
                'name': self.ou.name,
243
                'slug': self.ou.slug
244
            }
245

  
246
        if self.service:
247
            data['service'] = self.service.export_json()
248

  
249
        attributes = []
250
        for attr in self.attributes.all():
251
            attributes.append({
252
                'name': attr.name, 'kind': attr.kind,
253
                'value': attr.value})
254
        data['attributes'] = attributes
255

  
256
        parents = []
257
        for parent in self.parents(include_self=False):
258
            parents.append({
259
                'uuid': parent.uuid, 'slug': parent.slug, 'name': parent.name})
260
        data['parents'] = parents
261
        return data
262

  
198 263

  
199 264
class RoleParenting(RoleParentingAbstractBase):
200 265
    class Meta(RoleParentingAbstractBase.Meta):
src/authentic2/management/commands/export-roles.py
1
import json
2
from optparse import make_option
3
import sys
4

  
5
from django.core.management import BaseCommand
6

  
7
from authentic2.utils import export_roles
8

  
9

  
10
class Command(BaseCommand):
11
    help = 'Export roles as json'
12

  
13
    args = '<filename>'
14

  
15
    option_list = BaseCommand.option_list + (
16
        make_option('--ou', dest='ou', default=None, type=str,
17
                    help='restrict to the organizational unit slug'),)
18

  
19
    def handle(self, *args, **options):
20
        if len(args) < 1:
21
            output = sys.stdout
22
        else:
23
            output = open(args[0], 'w')
24

  
25
        data = export_roles(ou_slug=options['ou'])
26
        json.dump(data, output, encoding='utf-8', indent=4)
src/authentic2/management/commands/import-roles.py
1
import json
2
from optparse import make_option
3

  
4
from django.core.management.base import BaseCommand, CommandError
5

  
6
from authentic2.utils import import_roles, ImportExportError
7

  
8

  
9
class Command(BaseCommand):
10
    help = 'Import roles from json file'
11

  
12
    args = '<filename>'
13

  
14
    option_list = BaseCommand.option_list + (
15
        make_option('--ou', dest='ou', default=None, type=str,
16
                    help='restrict to the organizational unit slug'),
17
        make_option('--stop-on-absent-parent', action='store_true', dest='stop_absent_parent', default=False,
18
                    help='stop if parent is absent')
19
    )
20

  
21
    def handle(self, *args, **options):
22
        if args:
23
            fd = open(args[0])
24
            try:
25
                import_roles(json.load(fd), **options)
26
            except(ImportExportError,) as exc:
27
                raise CommandError(exc.message)
src/authentic2/models.py
399 399
            'roles': [role.to_json() for role in roles],
400 400
        }
401 401

  
402
    @classmethod
403
    def import_json(cls, data):
404
        ou = data.pop('ou')
405
        cls.objects.get_or_create(ou=ou, **data)
406

  
407
    def export_json(self):
408
        return {
409
            'name': self.name, 'slug': self.slug,
410
            'ou': {
411
                'uuid': self.ou.uuid, 'slug': self.ou.slug, 'name': self.ou.name
412
            }
413
        }
414

  
402 415

  
403 416
class AuthorizedRole(models.Model):
404 417
    service = models.ForeignKey(Service, on_delete=models.CASCADE)
src/authentic2/utils.py
16 16

  
17 17
import django
18 18
from django.conf import settings
19
from django.db import transaction
19 20
from django.http import HttpResponseRedirect, HttpResponse
20
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
21
from django.core.exceptions import ImproperlyConfigured, PermissionDenied, FieldError
21 22
from django.http.request import QueryDict
22 23
from django.contrib.auth import (REDIRECT_FIELD_NAME, login as auth_login, SESSION_KEY,
23 24
                                 HASH_SESSION_KEY, BACKEND_SESSION_KEY, authenticate)
......
942 943
    user = copy.deepcopy(user)
943 944
    user.backend = backend
944 945
    return login(request, user, method, **kwargs)
946

  
947

  
948
class ImportExportError(Exception):
949
    pass
950

  
951

  
952
def get_object_by_main_attr(obj, uuid=None, slug=None, name=None, create=False):
953
    """Sequentially try to get an object by uuid, slug, then name.
954
    Creates one if <create> is True
955
    """
956
    try:
957
        return obj.objects.get(uuid=uuid)
958
    except (obj.DoesNotExist, FieldError):
959
        try:
960
            return obj.objects.get(slug=slug)
961
        except (obj.DoesNotExist, FieldError):
962
            try:
963
                return obj.objects.get(name=name)
964
            except (obj.DoesNotExist, FieldError):
965
                pass
966
    if create:
967
        return obj.objects.create(uuid=uuid, slug=slug, name=name)
968
    return None
969

  
970

  
971
def export_roles(ou_slug=None):
972
    from django_rbac.utils import get_role_model
973
    Role = get_role_model()
974
    filters = {'slug__startswith': '_'}
975
    if ou_slug:
976
        roles = Role.objects.filter(ou__slug=ou_slug).exclude(**filters)
977
    else:
978
        roles = Role.objects.exclude(**filters)
979
    return [role.export_json() for role in roles]
980

  
981

  
982
def import_roles(data, **options):
983
    from django_rbac.utils import get_role_model
984

  
985
    Role = get_role_model()
986
    ou_slug = options.pop('ou')
987
    stop_absent_parent = options.pop('stop_absent_parent')
988

  
989
    if ou_slug:
990
        data = [datum for datum in data if datum['ou']['slug'] == ou_slug]
991
    with transaction.atomic():
992
        for role_json in data:
993
            Role.import_json(role_json)
994

  
995
        # once all roles are created, set their relationships
996
        for role_json in data:
997
            role = Role.objects.get(uuid=role_json['uuid'])
998
            for parent_json in role_json.get('parents', []):
999
                parent = get_object_by_main_attr(Role, **parent_json)
1000
                if parent:
1001
                    role.add_parent(parent)
1002
                else:
1003
                    if stop_absent_parent:
1004
                        raise ImportExportError(
1005
                            'Parent role (%(uuid)s, %(slug)s, %(name)s does not exist.' % parent_json)
945
-