class PermissionController(MetaResourceController):

    def __init__(self, connection=None, loglevel="INFO"):
        MetaResourceController.__init__(self, connection, loglevel)
        from porper.models.permission import Permission
        from porper.models.user_group import UserGroup
        self.permission = Permission(self.connection, loglevel)
        self.user_group = UserGroup(self.connection, loglevel)
        from porper.models.user import User
        from porper.models.group import Group
        self.user = User(self.connection, loglevel)
        self.group = Group(self.connection, loglevel)
        from porper.models.access_token import AccessToken
        self.access_token = AccessToken(self.connection, loglevel)
        # from porper.controllers.token_controller import TokenController
        # self.token_controller = TokenController(self.connection)
        # from porper.controllers.user_group_controller import UserGroupController
        # self.user_group_controller = UserGroupController(self.connection)

        from porper.models.permission import ALL
        self.PERMITTED_TO_ALL = ALL



    # def is_admin(self, user_id):
    #     return self.user_group_controller.is_admin(user_id)
    #
    # def is_group_admin(self, user_id, group_id):
    #     return self.user_group_controller.is_group_admin(user_id, group_id)
    #
    # def is_member(self, user_id, group_id):
    #     return self.user_group_controller.is_member(user_id, group_id)
    #
    # def is_permitted(self, access_token, params):
    #     """
    #     possible attributes in params
    #         - None
    #         - [user_id | group_id], action, resource, value
    #     """
    #     current_user_id = self.token_controller.find_user_id(access_token)
    #     if self.is_admin(current_user_id):    return True
    #
    #     #params['all'] = True
    #     rows = self.find(access_token, params)
    #     print("permitted : {}".format(rows))
    #     if len(rows) == 0:  return False
    #     return True

    def find_user_id(self, access_token):
        params = {
            'access_token': access_token
        }
        return self.access_token.find(params)[0]['user_id']


    def add_permissions_to_groups(self, resource_name, resource_id, permissions):
        #permissions:
        #[
        #    {"action": "r"},
        #    ...
        #]

        permission_params = {
            "resource": resource_name,
            "value": resource_id
        }
        for permission in permissions:
            permission_params["group_id"] = permission['id']
            permission_params["action"] = permission['action']
            if permission.get('condition'):
                permission_params['condition'] = permission['condition']
            if permission['state'].lower() == "a":
                self.permission.create(permission_params)
            elif permission['state'].lower() == "u":
                self.permission.update(permission_params)
            elif permission['state'].lower() == "d":
                self.permission.delete(permission_params)


    def add_permissions_to_users(self, resource_name, resource_id, permissions):
        #permissions:
        #[
        #    {"action": "r"},
        #    ...
        #]

        permission_params = {
            "resource": resource_name,
            "value": resource_id
        }
        for permission in permissions:
            permission_params["user_id"] = permission['id']
            permission_params["action"] = permission['action']
            if permission.get('condition'):
                permission_params['condition'] = permission['condition']
            if permission['state'].lower() == "a":
                self.permission.create(permission_params)
            elif permission['state'].lower() == "u":
                self.permission.update(permission_params)
            elif permission['state'].lower() == "d":
                self.permission.delete(permission_params)


    def add_permissions_to_customers(self, resource_name, resource_id, permissions):
        #permissions:
        #[
        #    {"action": "r"},
        #    ...
        #]

        permission_params = {
            "resource": resource_name,
            "value": resource_id
        }
        for permission in permissions:
            permission_params["customer_id"] = permission['id']
            permission_params["action"] = permission['action']
            if permission.get('condition'):
                permission_params['condition'] = permission['condition']
            if permission['state'].lower() == "a":
                self.permission.create(permission_params)
            elif permission['state'].lower() == "u":
                self.permission.update(permission_params)
            elif permission['state'].lower() == "d":
                self.permission.delete(permission_params)


    def create_permissions_to_groups(self, resource_name, resource_id, to_group_ids):
       #permissions:
        #[
        #    {"action": "r"},
        #    ...
        #]

        # current_user_id = self.token_controller.find_user_id(access_token)
        #
        # # if the current is admin, allow it
        # if self.is_admin(current_user_id):
        #     return self.add_permissions_to_group(resource_name, resource_id, permissions, to_group_id)

        if not self.is_admin:
            group_ids = [g['id'] for g in to_group_ids]
            customer_id = None
            user_id = None
            # if self.is_customer_admin:
            #     customer_id = self.customer_id
            # else:
            #     user_id = self.user_id
            # allow all users in the same customer
            customer_id = self.customer_id
            groups = self.group.find_by_ids(group_ids, customer_id= customer_id, user_id=user_id)
            if len(groups) != len(group_ids):
                self.logger.info("len(groups) = {} whereas len(to_group_ids) = {}".format(len(groups), len(group_ids)))
                raise Exception("not permitted")

        return self.add_permissions_to_groups(resource_name, resource_id, to_group_ids)

        """
        # if the current user is NOT group admin of the given group, don't allow it
        if not self.is_group_admin(user_id, to_group_id):
            raise Exception("not permitted")
        # if 'create' is NOT in permissions to give
        # and the current user has 'create' permission in the speicified resource, allow it
        # if the specified group has a permission to 'create' on the specified resource, allow it
        if self.PERMISSION_TO_CREATE not in permissions:
            params = {
                'action': 'create',
                'resource': resource_name,
                'value': resource_id
            }
            if self.is_permitted(access_token, params):
                return self.add_permissions_to_group(resource_name, resource_id, permissions, to_group_id)
        """

        #raise Exception("not permitted")


    def create_permissions_to_users(self, resource_name, resource_id, to_user_ids):
        #permissions:
        #[
        #    {"action": "r"},
        #    ...
        #]

        if not self.is_admin:
            user_ids = [u['id'] for u in to_user_ids]
            customer_id = None
            user_id = None
            # if self.is_customer_admin:
            #     customer_id = self.customer_id
            # else:
            #     user_id = self.user_id
            # allow all users in the same customer
            customer_id = self.customer_id
            users = self.user.find_by_ids(user_ids, customer_id=customer_id, user_id=user_id)
            # get the unique users
            users = list(dict.fromkeys([u['id'] for u in users]))
            if len(users) != len(user_ids):
                self.logger.info("len(users) = {} whereas len(to_user_ids) = {}".format(len(users), len(user_ids)))
                raise Exception("not permitted")

        return self.add_permissions_to_users(resource_name, resource_id, to_user_ids)

        """
        # if 'create' is NOT in permissions to give
        # and the current user has 'create' permission in the speicified resource, allow it
        # if the specified group has a permission to 'create' on the specified resource, allow it
        if self.PERMISSION_TO_CREATE not in permissions:
            params = {
                'action': 'create',
                'resource': resource_name,
                'value': resource_id
            }
            if self.is_permitted(access_token, params):
                return self.add_permissions_to_group(resource_name, resource_id, permissions, to_group_id)
        """

        #raise Exception("not permitted")


    def create_permissions_to_customer(self, resource_name, resource_id, to_customer_ids):
        #permissions:
        #[
        #    {"action": "r"},
        #    ...
        #]

        if not self.is_admin:
            # check if this user is in the same customer with the customer to give access
            for customer_id in [c['id'] for c in to_customer_ids]:
                if self.customer_id != customer_id:
                    raise Exception("not permitted")

        return self.add_permissions_to_customers(resource_name, resource_id, to_customer_ids)


    def create(self, access_token, params):
        # {
        #     "owner_id": "35925", "res_name": "meta", "res_id": "d392909c-d15f-43ff-98b4-9fd7e3ca80e9",
        #     "to_user_ids": [{"id": "*****@*****.**", "action": "w", "state": "A"},
        #                     {"id": "*****@*****.**", "action": "r", "state, "state": "A"}],
        #     "to_group_ids": [{"id": "group_id1", "action": "w", "state": "A"},
        #                     {"id": "group_id2", "action": "r", "state": "A"}],
        #     "to_customer_ids": [{"id": "customer_id1", "action": "w", "state": "A"}
        #                     {"id": "customer_id1", "action": "r", "state": "A"}]
        # }

        owner_id = params.get('owner_id')

        self.find_user_level(access_token)
        if self.user_id != owner_id:
            raise Exception("not permitted")

        if params.get('to_group_ids'):
            self.create_permissions_to_groups(params['res_name'], params['res_id'], params['to_group_ids'])
        if params.get('to_user_ids'):
            self.create_permissions_to_users(params['res_name'], params['res_id'], params['to_user_ids'])
        if params.get('to_customer_ids'):
            self.create_permissions_to_customer(params['res_name'], params['res_id'], params['to_customer_ids'])

        return True


    def update(self, access_token, params):
        user_id = self.find_user_id(access_token)
        raise Exception("not supported")


    # This is to remove all permissions of given resource
    def delete(self, access_token, params):
        user_id = self.find_user_id(access_token)

        owner_id = params.get('owner_id')

        self.find_user_level(access_token)
        if self.user_id != owner_id:
            raise Exception("not permitted")

        if 'res_name' not in params or 'res_id' not in params:
            raise Exception("resource name and id are not provided")

        params['value'] = params['res_id']
        del params['res_id']
        return self.permission.delete(params)


    # def _filter_conditions(self, user_id, rows):
    #
    #     filtered = [ row for row in rows if not row.get('condition') ]
    #     if len(filtered) == len(filtered):
    #         # there is no row with a condition
    #         return rows
    #
    #     permissions = [ row for row in rows if row.get('condition') ]
    #     for permission in permissions:
    #         condition = json.loads(permission['condition'])
    #         # check when the condition is 'is_admin' and it is satisified, add it to the return list if so
    #         if 'is_admin' in condition:
    #             if not user_id \
    #             or not condition['is_admin'] \
    #             or ( permission.get('group_id') and self.is_group_admin(user_id, permission['group_id']) ):
    #                 filtered.append(permission)
    #
    #     return filtered


    def find(self, access_token, params):
        """
        possible attributes in params
            - None
            - [user_id | group_id], action, resource, [value]
        """

        search_params = {}
        if params:
            if 'res_name' in params:
                search_params['res_name'] = params['res_name']
            if 'action' in params:
                search_params['action'] = params['action']
            if 'res_id' in params:
                search_params['value'] = params['res_id']

        self.find_user_level(access_token)
        owner_id = params.get('owner_id')

        search_cid = None
        search_gids = None
        search_uids = None
        if not self.is_admin and ('res_id' not in params or owner_id != self.user_id):
            customer_id = None
            user_id = None
            # Allow customer admin to see only its and shared graphs like normal users
            # if self.is_customer_admin:
            #     customer_id = self.customer_id
            # else:
            #     user_id = self.user_id
            user_id = self.user_id
            groups = self.group.find({}, customer_id= customer_id, user_id=user_id)
            # do not allow users in the same groups with this user
            # users = self.user.find({}, customer_id= customer_id, user_id=user_id)

            search_cid = self.customer_id
            search_gids = [g['id'] for g in groups]
            # search_uids = [u['id'] for u in users]
            search_uids = [user_id]

        ret = self.permission.find_resource_permissions(search_params, search_cid, search_gids, search_uids)
        if params.get("value_only"):
            ret = self.get_values(ret)

        return ret


    def get_values(self, permissions):
        ret = []
        for permission in permissions:
            if permission['value'] not in ret:
                ret.append(permission['value'])
        return ret
Example #2
0
class GroupController(MetaResourceController):
    def __init__(self, connection=None, loglevel="INFO"):
        #self.connection = connection
        MetaResourceController.__init__(self, connection, loglevel)
        from porper.models.group import Group
        self.group = Group(self.connection, loglevel)
        from porper.models.user import User
        self.user = User(self.connection, loglevel)
        # from porper.controllers.user_group_controller import UserGroupController
        # self.user_group_controller = UserGroupController(self.connection)

        self.permission_name = 'group'

    # only the admin can create a group
    def create(self, access_token, params):
        """
        possible attributes in params
            - [id], name
        """
        self.logger.info(f"params={params}")
        self.logger.info(f"access_token={access_token}")
        # self.logger.info(f"paths={paths}")

        self.find_user_level(access_token)
        if not self.is_permitted(self.permission_name, self.permission_write):
            raise Exception("not permitted")

        if "customer_id" not in params or not self.is_member(
                customer_id=params['customer_id']):
            raise Exception("not permitted")

        return self.group.create(params)

    def update(self, access_token, params):
        """
        possible attributes in params
            - id, name
        """
        self.logger.info(f'group_controller_update-params={params}')
        self.logger.info(
            f'group_controller_update-access_token={access_token}')

        self.find_user_level(access_token)
        if not self.is_permitted(self.permission_name, self.permission_write):
            raise Exception("not permitted")

        item = self.group.find_by_id(params['id'])
        if not item or not self.is_member(customer_id=item['customer_id']):
            raise Exception("not permitted")

        if params.get('customer_id'):
            raise Exception('You cannot update the group customer')

        if 'name' in params:
            ret = self.group.find({'name': params['name']})
            if ret and ret[0]['id'] != params['id']:
                raise Exception("the group name already exists")

        return self.group.update(params)

    def delete(self, access_token, params):
        """
        possible attributes in params
            - id
        """

        self.find_user_level(access_token)
        if not self.is_permitted(self.permission_name, self.permission_write):
            raise Exception("not permitted")

        item = self.group.find_by_id(params['id'])
        if not item or not self.is_member(customer_id=item['customer_id']):
            raise Exception("not permitted")

        # cannot remove it when it has users
        users = self.user.find({'group_id': params['id']})
        if len(users) > 0:
            raise Exception(
                "You must remove all users before removing this group")

        return self.group.delete(params['id'])

    def find(self, access_token, params):
        """
        possible attributes in params
            - user_id: find all groups where this given user belongs
            - id: find a specific group
            - ids: find specific groups
            - None: No condition
            - name
        """

        self.find_user_level(access_token)

        if 'closed' in params:
            if not self.is_permitted(self.permission_name,
                                     self.permission_read):
                raise Exception("not permitted")

        customer_id = None
        user_id = None
        if 'closed' in params:
            # allow users/groups of the groups only this user belongs
            if self.is_customer_admin:
                customer_id = self.customer_id
            elif not self.is_admin:
                user_id = self.user_id
            del params['closed']
        else:
            # allow all users/groups of the customer this user belongs
            if not self.is_admin:
                customer_id = self.customer_id

        if 'ids' in params:
            groups = self.group.find_by_ids(params['ids'],
                                            customer_id=customer_id,
                                            user_id=user_id)
            return groups

        else:
            groups = self.group.find(params,
                                     customer_id=customer_id,
                                     user_id=user_id)
            if groups and 'id' in params:
                return groups[0]
            return groups