From 8a9d8df7536e2c9423246eec183a46a18a567dd8 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Mon, 4 Jan 2016 14:08:28 +0100 Subject: [PATCH] agent/authentic2: provision the is_superuser attribute (fixes #9230) --- hobo/agent/authentic2/apps.py | 41 +++++++++++++-------- .../common/management/commands/hobo_notify.py | 2 ++ tests_authentic/test_provisionning.py | 42 +++++++++++++++------- 3 files changed, 58 insertions(+), 27 deletions(-) diff --git a/hobo/agent/authentic2/apps.py b/hobo/agent/authentic2/apps.py index a52423b..51601e2 100644 --- a/hobo/agent/authentic2/apps.py +++ b/hobo/agent/authentic2/apps.py @@ -45,7 +45,7 @@ def get_audience(role_or_through): qs = LibertyProvider.objects.filter(ou=ou) else: qs = LibertyProvider.objects.filter(ou__isnull=True) - return list(qs.values_list('entity_id', flat=True)) + return [(service, service.entity_id) for service in qs] def get_related_roles(role_or_through): @@ -75,7 +75,7 @@ def notify_roles(sender, instance, **kwargs): try: notify_agents({ '@type': 'provision', - 'audience': get_audience(instance), + 'audience': [audience for service, audience in get_audience(instance)], 'full': True, 'objects': { '@type': 'role', @@ -111,6 +111,10 @@ def provision_user(sender, instance, **kwargs): data = {} for av in AttributeValue.objects.with_owner(instance): data[str(av.attribute.name)] = av.to_python() + + roles = instance.roles_and_parents() \ + .prefetch_related('attributes') + is_superuser = instance.is_superuser data.update({ 'uuid': instance.uuid, 'username': instance.username, @@ -122,19 +126,28 @@ def provision_user(sender, instance, **kwargs): 'uuid': role.uuid, 'name': role.name, 'slug': role.slug, - } for role in instance.roles_and_parents()], + } for role in roles], }) - notify_agents({ - '@type': 'provision', - 'issuer': unicode(get_entity_id()), - 'audience': get_audience(instance), - 'full': False, - 'objects': { - '@type': 'user', - 'data': [data], - } - }) + for service, audience in get_audience(instance): + role_is_superuser = False + for role in roles: + if role.service_id != service.pk: + continue + for attribute in role.attributes.all(): + if attribute.name == 'is_superuser' and attribute.value == 'true': + role_is_superuser = True + data['is_superuser'] = is_superuser or role_is_superuser + notify_agents({ + '@type': 'provision', + 'issuer': unicode(get_entity_id()), + 'audience': [audience], + 'full': False, + 'objects': { + '@type': 'user', + 'data': [data], + } + }) def deprovision_user(sender, instance, **kwargs): @@ -146,7 +159,7 @@ def deprovision_user(sender, instance, **kwargs): notify_agents({ '@type': 'deprovision', 'issuer': unicode(get_entity_id()), - 'audience': get_audience(instance), + 'audience': [audience for service, audience in get_audience(instance)], 'full': False, 'objects': { '@type': 'user', diff --git a/hobo/agent/common/management/commands/hobo_notify.py b/hobo/agent/common/management/commands/hobo_notify.py index d3855e4..334ab5f 100644 --- a/hobo/agent/common/management/commands/hobo_notify.py +++ b/hobo/agent/common/management/commands/hobo_notify.py @@ -64,6 +64,7 @@ class Command(BaseCommand): @classmethod def check_valid_user(cls, o): return 'uuid' in o \ + and 'is_superuser' in o \ and 'email' in o \ and 'first_name' in o \ and 'last_name' in o \ @@ -98,6 +99,7 @@ class Command(BaseCommand): user.last_name = o['last_name'] user.email = o['email'] user.username = o['uuid'][:30] + user.is_superuser = o['is_superuser'] user.save() role_uuids = [role['uuid'] for role in o.get('roles', [])] user.groups = Role.objects.filter(uuid__in=role_uuids) diff --git a/tests_authentic/test_provisionning.py b/tests_authentic/test_provisionning.py index 814e186..422e69d 100644 --- a/tests_authentic/test_provisionning.py +++ b/tests_authentic/test_provisionning.py @@ -50,9 +50,16 @@ def test_provision_role(tenant): def test_provision_user(tenant): + import lasso + from authentic2.saml.models import LibertyProvider + with patch('hobo.agent.authentic2.apps.notify_agents') as notify_agents: with tenant_context(tenant): - role = Role.objects.create(name='coin', ou=get_default_ou()) + service = LibertyProvider.objects.create(ou=get_default_ou(), name='provider', + entity_id='http://provider.com', + protocol_conformance=lasso.PROTOCOL_SAML_2_0) + role = Role.objects.create(name='coin', service=service, ou=get_default_ou()) + role.attributes.create(kind='string', name='is_superuser', value='true') notify_agents.reset_mock() User = get_user_model() attribute = Attribute.objects.create(label='Code postal', name='code_postal', @@ -71,7 +78,7 @@ def test_provision_user(tenant): 'issuer', 'audience', '@type', 'objects', 'full']) assert arg['issuer'] == \ 'http://%s/idp/saml2/metadata' % tenant.domain_url - assert arg['audience'] == [] + assert arg['audience'] == ['http://provider.com'] assert arg['@type'] == 'provision' assert arg['full'] is False objects = arg['objects'] @@ -82,7 +89,7 @@ def test_provision_user(tenant): assert isinstance(data, list) assert len(data) == 1 for o in data: - assert set(o.keys()) == set(['uuid', 'username', 'first_name', + assert set(o.keys()) == set(['uuid', 'username', 'first_name', 'is_superuser', 'last_name', 'email', 'roles']) assert o['uuid'] == user.uuid assert o['username'] == user.username @@ -90,11 +97,14 @@ def test_provision_user(tenant): assert o['last_name'] == user.last_name assert o['email'] == user.email assert o['roles'] == [] + assert o['is_superuser'] is False notify_agents.reset_mock() attribute.set_value(user, '13400') + user.is_superuser = True + user.save() - assert notify_agents.call_count == 1 + assert notify_agents.call_count == 2 arg = notify_agents.call_args assert arg == call(ANY) arg = arg[0][0] @@ -103,7 +113,7 @@ def test_provision_user(tenant): 'issuer', 'audience', '@type', 'objects', 'full']) assert arg['issuer'] == \ 'http://%s/idp/saml2/metadata' % tenant.domain_url - assert arg['audience'] == [] + assert arg['audience'] == ['http://provider.com'] assert arg['@type'] == 'provision' assert arg['full'] is False objects = arg['objects'] @@ -115,7 +125,7 @@ def test_provision_user(tenant): assert len(data) == 1 for o in data: assert set(o.keys()) == set(['code_postal', 'uuid', 'username', 'first_name', - 'last_name', 'email', 'roles']) + 'is_superuser', 'last_name', 'email', 'roles']) assert o['uuid'] == user.uuid assert o['username'] == user.username assert o['first_name'] == user.first_name @@ -123,6 +133,7 @@ def test_provision_user(tenant): assert o['email'] == user.email assert o['roles'] == [] assert o['code_postal'] == '13400' + assert o['is_superuser'] is True notify_agents.reset_mock() AttributeValue.objects.get().delete() @@ -136,7 +147,7 @@ def test_provision_user(tenant): 'issuer', 'audience', '@type', 'objects', 'full']) assert arg['issuer'] == \ 'http://%s/idp/saml2/metadata' % tenant.domain_url - assert arg['audience'] == [] + assert arg['audience'] == ['http://provider.com'] assert arg['@type'] == 'provision' assert arg['full'] is False objects = arg['objects'] @@ -148,14 +159,17 @@ def test_provision_user(tenant): assert len(data) == 1 for o in data: assert set(o.keys()) == set(['uuid', 'username', 'first_name', - 'last_name', 'email', 'roles']) + 'is_superuser', 'last_name', 'email', 'roles']) assert o['uuid'] == user.uuid assert o['username'] == user.username assert o['first_name'] == user.first_name assert o['last_name'] == user.last_name assert o['email'] == user.email assert o['roles'] == [] + assert o['is_superuser'] is True + user.is_superuser = False + user.save() notify_agents.reset_mock() role.members.add(user) @@ -168,7 +182,7 @@ def test_provision_user(tenant): 'issuer', 'audience', '@type', 'objects', 'full']) assert arg['issuer'] == \ 'http://%s/idp/saml2/metadata' % tenant.domain_url - assert arg['audience'] == [] + assert arg['audience'] == ['http://provider.com'] assert arg['@type'] == 'provision' assert arg['full'] is False objects = arg['objects'] @@ -180,7 +194,7 @@ def test_provision_user(tenant): assert len(data) == 1 for o in data: assert set(o.keys()) == set(['uuid', 'username', 'first_name', - 'last_name', 'email', 'roles']) + 'is_superuser', 'last_name', 'email', 'roles']) assert o['uuid'] == user.uuid assert o['username'] == user.username assert o['first_name'] == user.first_name @@ -191,6 +205,7 @@ def test_provision_user(tenant): 'name': role.name, 'slug': role.slug }] + assert o['is_superuser'] is True notify_agents.reset_mock() user.roles.remove(role) @@ -204,7 +219,7 @@ def test_provision_user(tenant): 'issuer', 'audience', '@type', 'objects', 'full']) assert arg['issuer'] == \ 'http://%s/idp/saml2/metadata' % tenant.domain_url - assert arg['audience'] == [] + assert arg['audience'] == ['http://provider.com'] assert arg['@type'] == 'provision' assert arg['full'] is False objects = arg['objects'] @@ -216,13 +231,14 @@ def test_provision_user(tenant): assert len(data) == 1 for o in data: assert set(o.keys()) == set(['uuid', 'username', 'first_name', - 'last_name', 'email', 'roles']) + 'is_superuser', 'last_name', 'email', 'roles']) assert o['uuid'] == user.uuid assert o['username'] == user.username assert o['first_name'] == user.first_name assert o['last_name'] == user.last_name assert o['email'] == user.email assert o['roles'] == [] + assert o['is_superuser'] is False notify_agents.reset_mock() user.delete() assert notify_agents.call_count == 1 @@ -234,7 +250,7 @@ def test_provision_user(tenant): 'issuer', 'audience', '@type', 'objects', 'full']) assert arg['issuer'] == \ 'http://%s/idp/saml2/metadata' % tenant.domain_url - assert arg['audience'] == [] + assert arg['audience'] == ['http://provider.com'] assert arg['@type'] == 'deprovision' assert arg['full'] is False objects = arg['objects'] -- 2.1.4