0001-add-roles-import-export-command-16514.patch
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 |
- |