Example #1
0
    def test_action_generation_subscribed(self):
        """
            Given a set of wanted permissions
            And an existent subcription
            If we currently have all wanted permissions
            Then no action is generated
        """
        from ulearnhub.models.utils import generate_actions

        subscription = {'permissions': ['read', 'write']}
        policy_granted_permissions = set(['read', 'write'])
        wanted_permissions = set(['read', 'write'])

        actions = generate_actions(subscription, policy_granted_permissions,
                                   wanted_permissions)

        self.assertItemsEqual(actions.keys(), [])
Example #2
0
    def test_action_generation_subscribed_triggers_grant(self):
        """
            Given a set of wanted permissions
            And an existent subcription
            If there are some wanted permissions that we don't have
            Then a grant action is generated
        """
        from ulearnhub.models.utils import generate_actions

        subscription = {'permissions': ['read']}
        policy_granted_permissions = set(['read'])
        wanted_permissions = set(['read', 'write'])

        actions = generate_actions(subscription, policy_granted_permissions,
                                   wanted_permissions)

        self.assertItemsEqual(actions.keys(), ['grant'])
        self.assertItemsEqual(actions['grant'], ['write'])
Example #3
0
    def test_action_generation_new_subscription(self):
        """
            Given a set of wanted permissions
            And an inexistent subcription
            If all wanted permissions are in policy
            Then only subscription action is generated
        """
        from ulearnhub.models.utils import generate_actions

        subscription = {}
        policy_granted_permissions = set(['write', 'read'])
        wanted_permissions = set(['write', 'read'])

        actions = generate_actions(subscription, policy_granted_permissions,
                                   wanted_permissions)

        self.assertItemsEqual(actions.keys(), ['subscribe'])
        self.assertTrue(actions['subscribe'])
Example #4
0
    def test_action_generation_subscribed_triggers_revoke(self):
        """
            Given a set of wanted permissions
            And an existent subcription
            If we have some permissions that we must not have
            And that permissions has been granted
            Then a revoke action is generated
        """
        from ulearnhub.models.utils import generate_actions

        subscription = {'permissions': ['read', 'write']}
        policy_granted_permissions = set(['read', 'write'])
        wanted_permissions = set(['read'])

        actions = generate_actions(subscription, policy_granted_permissions,
                                   wanted_permissions)

        self.assertItemsEqual(actions.keys(), ['revoke'])
        self.assertItemsEqual(actions['revoke'], ['write'])
Example #5
0
    def test_action_generation_subscribed_triggers_revoke_and_grant(self):
        """
            Given a set of wanted permissions
            And an existent subcription
            If there are some wanted permissions not in current permissions
            If there are some not wanted permissions in current_permissions
            Then a subscription action is generated
            And a revoke action is generated
            And a grant action is generated
        """
        from ulearnhub.models.utils import generate_actions

        subscription = {'permissions': ['read', 'write']}
        policy_granted_permissions = set(['write'])
        wanted_permissions = set(['read', 'flag'])

        actions = generate_actions(subscription, policy_granted_permissions,
                                   wanted_permissions)

        self.assertItemsEqual(actions.keys(), ['revoke', 'grant'])
        self.assertItemsEqual(actions['revoke'], ['write'])
        self.assertItemsEqual(actions['grant'], ['flag'])
Example #6
0
    def test_action_generation_new_subscription_triggers_grant_and_revoke(
            self):
        """
            Given a set of wanted permissions
            And an inexistent subcription
            If there are some wanted permissions not in policy
            If there are some not wanted permissions in policy
            Then a subscription action is generated
            And a revoke action is generated
            And a grant action is generated
        """
        from ulearnhub.models.utils import generate_actions

        subscription = {}
        policy_granted_permissions = set(['write'])
        wanted_permissions = set(['read'])

        actions = generate_actions(subscription, policy_granted_permissions,
                                   wanted_permissions)

        self.assertItemsEqual(actions.keys(), ['subscribe', 'revoke', 'grant'])
        self.assertTrue(actions['subscribe'])
        self.assertItemsEqual(actions['revoke'], ['write'])
        self.assertItemsEqual(actions['grant'], ['read'])
Example #7
0
    def handle_rabbitmq(self, request, *args, **kwargs):
        """
            Update a context's users ACLS

            Decomposes given groups into a list of users. With that list of
            users generates the minimum set of tasks (SUB, UNSUB, REVOKE, GRANT)
            to sync the community status to max context and subscriptions.

            Each of the final tasks generated is feeded to rabbitmq
            to be processed asynchronously.

            Format of request to this service is as follows:

            {
                "component": {
                    "type": "communities",
                    "id": "url"
                }
                "context": "http://(...)",
                "acl": {
                    "groups": [
                        {"id": , "role": ""},
                        ...
                    ]
                    "users": [
                        {"id": , "role": ""},
                    ]
                },
                "permission_mapping": {
                    "reader": ['read'],
                    "writer": ['read', 'write'],
                    "owner": ['read', 'write']
                },
                "ignore_grants_and_vetos": true,

            }

            component: type and id of the component that's triggering this call
            context: The context on which the syncacl tasks will be performed
            acl.groups: list of group acls to process.
            acl.users: list of user acls to process.
            acl.*:  Each acl entry has an id identifing the group/user (cn) and a role
            permission_mapping: For each role in acls, there must be a list of permissions that
                a user with that role must have in its max subscription
            ignore_grants_and_vetos: if true, peristent grants and vetoes on context subscriptions
            will be overriden so that the final subscription state matches the requested state. This is
            the default behaviour.
        """

        data = request.json
        domain = self.__parent__
        context_url = data['context']

        # Get required components for this service
        maxserver = domain.get_component(MaxServer)
        ldapserver = domain.get_component(LdapServer)
        rabbitserver = domain.get_component(RabbitServer)

        # Get target context and all of its subscriptions
        maxclient = maxserver.maxclient
        authenticated_username, authenticated_token, scope = request.auth_headers
        maxclient.setActor(authenticated_username)
        maxclient.setToken(authenticated_token)

        policy_granted_permissions, subscriptions = get_context_data(
            maxclient, context_url)

        acl_groups = data['acl'].get('groups', [])
        acl_users = data['acl'].get('users', [])
        permission_mapping = data['permission_mapping']

        def expanded_users():
            """
                Returns iterator with groups in request expanded to get all individual users.

                Transform each user to mimic entries in requests's ['acl']['users'],
                picking the role specified in the group. Preserve group for further checks.

            """
            if not acl_groups:
                raise StopIteration()

            ldapserver.server.connect()
            for group in acl_groups:
                users = ldapserver.server.get_group_users(
                    group['id'].encode('utf-8'))
                for username in users:
                    yield {
                        'id': username,
                        'role': group['role'],
                        'group': group['id']
                    }

            # Disconnect ldap server, we won't need it outside here
            ldapserver.server.disconnect()

        # To keep track of overwrites caused by user duplication
        # At the end of the process, subscribed user NOT IN target users
        # will be unsubscribed
        actions_by_user = {}

        # Iterate over group users and single users acl's at once
        for user in chain(expanded_users(), acl_users):
            username = user['id']
            role = user['role']

            wanted_permissions = set(permission_mapping.get(role, []))

            # Get the previous defined actions on this user, if any
            actions = actions_by_user.get(username, None)

            # Generate actions based on current permissions, policy, and wanted permissions
            new_actions = generate_actions(subscriptions.get(username, {}),
                                           policy_granted_permissions,
                                           wanted_permissions)

            # Merge new actions into previous actions, preserving the most beneficient
            actions = merge_actions(actions, new_actions)

            # Store user to track overwrites
            actions_by_user[username] = actions

        client = rabbitserver.notifications

        # All the users present in subscription and not in the ACL's will be unsubscribed
        missing_users = set(subscriptions.keys()) - set(actions_by_user.keys())
        for username in missing_users:
            client.sync_acl(domain.name, context_url, username,
                            {"unsubscribe": True})
            gevent.sleep()

        for username, actions in actions_by_user.items():
            if actions:
                client.sync_acl(domain.name, context_url, username, actions)
                gevent.sleep()

        gevent.sleep(0.1)
        return {}