Esempio n. 1
0
 def __init__(self, api, api_key):
     ExtensionController.__init__(self, api, api_key)
     self.guard  = api.get_guard()
     self.userdb = UserDB(self.guard)
Esempio n. 2
0
class Controller(ExtensionController):
    def __init__(self, api, api_key):
        ExtensionController.__init__(self, api, api_key)
        self.guard  = api.get_guard()
        self.userdb = UserDB(self.guard)


    def __show_user(self, user, path, errors = []):
        assert user is not None
        assert not user.is_group()
        assert path is not None

        # Make sure that current_user has "view" permissions on it.
        current_user = self.api.get_current_user()
        if user.get_id() is not None:
            view = self.guard.get_action(handle = 'view', type = UserAction)
            assert view is not None
            if not self.guard.has_permission(current_user, view, user):
                user     = User(user.get_name())
                errors   = [_("You do not have permission to view " +
                                 "this user.")]

        # Collect information for the browser.
        if user.get_id() is None:
            parent_id = path.crop().get_current_id()
            parent    = self.guard.get_resource(id = parent_id)
            parent.set_attribute('path_str', path.crop().get())
            parents   = [parent]
            acls      = []
        else:
            acls    = self.userdb.get_permission_list(user)
            parents = self.guard.get_resource_parents(user)
            # Abuse attributes to pass the path to the HTML template.
            for parent in parents:
                ppath = self.guard.get_resource_path_from_id(parent.get_id())
                parent.set_attribute('path_str', ppath.get())
        
        # Render the template.
        self.api.render('user_editor.tmpl',
                        path         = path,
                        user         = user,
                        groups       = parents,
                        acls         = acls,
                        get_resource = self.guard.get_resource,
                        errors       = errors)


    def __show_group(self, group, path, errors = []):
        assert group is not None
        assert group.is_group()
        assert path is not None

        # Make sure that current_user has "view" permissions on it.
        current_user = self.api.get_current_user()
        if group.get_id() is not None:
            view = self.guard.get_action(handle = 'view', type = UserAction)
            assert view is not None
            if not self.guard.has_permission(current_user, view, group):
                group     = Group(group.get_name())
                errors    = [_("You do not have permission to view " +
                                  "this group.")]

        # Collect information for the browser.
        users    = []
        groups   = []
        if group.get_id() is not None:
            acls     = self.userdb.get_permission_list(group)
            parents  = self.guard.get_resource_parents(group)
            children = self.guard.get_resource_children(group)
            for child in children:
                if child.is_group():
                    groups.append(child)
                else:
                    users.append(child)
        else:
            parent_id = path.crop().get_current_id()
            parent    = self.guard.get_resource(id = parent_id)
            parents   = [parent]
            acls      = []

        # Render the template.
        self.api.render('group_editor.tmpl',
                        path         = path,
                        parents      = parents,
                        group        = group,
                        users        = users,
                        groups       = groups,
                        acls         = acls,
                        get_resource = self.guard.get_resource,
                        errors       = errors)


    def __save_resource(self, resource):
        assert resource is not None
        self.guard = self.guard
        
        # Retrieve form data.
        get_data             = self.api.get_data()
        post_data            = self.api.post_data()
        path                 = None
        path_str             = get_data.get_str('path_str')
        name                 = post_data.get_str('name')
        description          = post_data.get_str('description')
        use_group_permission = post_data.get_bool('use_group_permission')
        default_owner_id     = post_data.get_int('default_owner_id')
        resource_list        = post_data.get('resource[]',   [])
        permission_list      = post_data.get('permission[]', [])
        if path_str is not None:
            path = SpiffGuard.ResourcePath(path_str) # FIXME: Take reference from elsewhere.
        if path is not None:
            parent_id = path.get_parent_id()
        if resource.is_group() and parent_id is None:
            parent_id = 0  # Given resource is a top-level group.
        if use_group_permission is not None:
            use_group_permission = int(use_group_permission)
        if default_owner_id is not None:
            default_owner_id = int(default_owner_id)

        # Validate form data.
        errors = []
        parent = None

        # Parent ID must be >= 0.
        if parent_id is None or parent_id < 0:
            msg = _("Invalid parent id.")
            errors.append(msg)

        # A resource can not be its own parent/child.
        elif parent_id == resource.get_id():
            msg = _("A resource can not be its own parent.")
            errors.append(msg)

        # Users and groups must have a parent, except existing ones.
        elif resource.get_id() is None and parent_id == 0:
            msg = _("Can not create a user or group without a parent.")
            errors.append(msg)

        # So a parent was given - make sure that it exists.
        elif parent_id > 0:
            parent = self.guard.get_resource(id = parent_id)
            if parent is None:
                msg = _("Specified parent does not exist.")
                errors.append(msg)

        # Check permissions.
        current_user    = self.api.get_current_user()
        current_user_id = current_user.get_id()

        # If the given user/group is new, make sure that current_user has
        # "administer" permissions on the parent.
        if resource.get_id() is None:
            admin = self.guard.get_action(handle = 'administer',
                                        type   = UserAction)
            assert admin is not None
            if not self.guard.has_permission(current_user, admin, parent):
                return [_("You do not have permission to add a group.")]

        # If the given group already exists, make sure that current_user
        # has "edit" permissions on it.
        elif resource.is_group():
            edit = self.guard.get_action(handle = 'edit', type = UserAction)
            assert edit is not None
            if not self.guard.has_permission(current_user, edit, resource):
                return [_("You do not have permission to edit this group.")]

        # If the given user already exists, make sure that current_user
        # has "edit" permissions on it.
        else:
            edit = self.guard.get_action(handle = 'edit',
                                       type   = UserAction)
            assert edit is not None
            if not self.guard.has_permission(current_user, edit, resource):
                return [_("You do not have permission to edit this user.")]

        # Minimum name length.
        if name is None or len(name) < 2:
            msg = _("The name must be at least two characters long.")
            errors.append(msg)

        # Make sure that the user/group name does not yet exist.
        elif resource.get_id() is None:
            res = self.guard.get_resource(name = name, type = User)
            if res is not None and res.is_group():
                msg = _("A group with the given name already exists.")
                errors.append(msg)
            elif res is not None:
                msg = _("A user with the given name already exists: %s" % res.get_name())
                errors.append(msg)

        # Groups require the use_group_permission field.
        if resource.is_group():
            if use_group_permission not in [0, 1]:
                msg = _("Group has an invalid default owner.")
                errors.append(msg)

        # New users require the default_owner_id field set to either 0 or
        # to the parent_id.
        elif parent is not None and resource.get_id() is None:
            if default_owner_id != 0 and default_owner_id != parent_id:
                msg = _("Specified parent does not exist.")
                errors.append(msg)

        # Existing users require the default_owner_id field set to either 0
        # or one of the parent ids.
        elif parent is not None and default_owner_id != 0:
            parents = self.guard.get_resource_parents(resource)
            found   = False
            if parents is not None:
                for parent in parents:
                    if int(default_owner_id) == parent.get_id():
                        found = True
                        break
            if not found:
                msg = _("User has an invalid default owner.")
                errors.append(msg)

        # Make sure that the user/group names for which permissions were
        # defined exist in the database.
        have_already = {}
        for rname in resource_list:
            res = self.guard.get_resource(name = rname, type = User)
            if res is not None:
                continue
            msg = _("User or group '%s' does not exists." % rname)
            errors.append(msg)

            # Make sure that a user does not have two sets of permissions
            # defined.
            if not have_already.has_key(rname):
                have_already[rname] = True
                continue

            if res.is_group():
                msg = _("Permission for group '%s' was specified twice."
                           % rname)
            else:
                msg = _("Permission for user '%s' was specified twice."
                           % rname)
            errors.append(msg)

        # Bail out if an error occured.
        if len(errors) > 0:
            return errors

        # Cool, everything looks clean! Store the data in the resource and
        # save it.
        resource.set_name(name)
        resource.set_attribute('description', description)
        if resource.is_group():
            resource.set_attribute('use_group_permission',
                                   use_group_permission)
        else:
            resource.set_attribute('default_owner_id', default_owner_id)
        if resource.get_id() is None:
            self.guard.add_resource(parent_id, resource)
        else:
            self.guard.save_resource(resource)

        #i = 0
        #for item in resource_list:
        #    print "RESOURCES:", item
        #    print "PERMS:", permission_list[i]
        #    i += 1

        # Get the list of current permissions from the database.
        search = { 'resource_type': User }
        acls   = self.guard.get_permission_list_from_id(resource.get_id(),
                                                      **search)

        resource_id_list = []
        for acl in acls:
            acl_id      = acl.get_id()
            actor_id    = acl.get_actor_id()
            action      = acl.get_action()
            action_id   = action.get_id()
            resource_id = acl.get_resource_id()
            res         = self.guard.get_resource(id = resource_id)
            resource_id_list.append(resource_id)
            cur_permit  = self.guard.has_permission_from_id(current_user_id,
                                                            action_id,
                                                            resource_id)

            # If the resource was removed from the UI, delete it from the DB.
            if res.get_name() not in resource_list:
                #print "Missing resource: Deleting permission %s" % acl_id
                # If deleting this permission would escalate the permission
                # of that user to something that is higher than current_user,
                # deny that.
                par_permit = self.guard.has_permission_from_id(parent_id,
                                                               action_id,
                                                               resource_id)
                if par_permit and not cur_permit:
                    return [_("Permission change would escalate rights " +
                                 "above the currently logged in user.")]
                assert self.guard.delete_permission_from_id(actor_id,
                                                            action.get_id(),
                                                            resource_id)
                continue

            # Get the permissions that were defined for the resource.
            resource_permission = None
            seq                 = 0
            for rname in resource_list:
                if rname == res.get_name():
                    resource_permission = split(permission_list[seq], '/')
                seq += 1
            assert resource_permission is not None

            # If the specific permission was removed from the UI, also remove
            # it from the DB.
            if action.get_handle() not in resource_permission:
                #print "Missing permission: Deleting permission %s" % acl_id
                # If deleting this permission would escalate the permission
                # of that user to something that is higher than current_user,
                # deny that.
                par_permit = self.guard.has_permission_from_id(parent_id,
                                                               action_id,
                                                               resource_id)
                if par_permit and not cur_permit:
                    return [_("Permission change would escalate rights " +
                                 "above the currently logged in user.")]
                assert self.guard.delete_permission_from_id(actor_id,
                                                            action.get_id(),
                                                            resource_id)
                continue

        # Walk through all permissions that were defined in the UI and make
        # sure that they exist in the database.
        seq      = 0
        view     = self.guard.get_action(handle = 'view',     type = UserAction)
        edit     = self.guard.get_action(handle = 'edit',     type = UserAction)
        moderate = self.guard.get_action(handle = 'moderate', type = UserAction)
        for name in resource_list:
            resource_permission = split(permission_list[seq], '/')
            seq += 1
            if 'default' in resource_permission:
                continue

            res = self.guard.get_resource(name = name, type = User)
            #print "Current:", resource.get_name(), res.get_name(), resource_permission

            # Walk through all permissions, granting all that were newly added.
            for permission in resource_permission:
                if permission == 'none':
                    continue
                #print "Granting %s on %s" % permission, res.get_name())
                action_id  = locals()[permission].get_id()
                cur_permit = self.guard.has_permission_from_id(current_user_id,
                                                               action_id,
                                                               resource_id)
                if not self.guard.has_permission_from_id(current_user_id,
                                                         action_id,
                                                         resource_id):
                    return [_("Permission change would escalate rights " +
                                 "above the currently logged in user.")]
                assert self.guard.grant_from_id(resource.get_id(),
                                                action_id,
                                                res.get_id())

            # Walk through all permissions, denying all that were listed as
            # rejected.
            for permission in ['view', 'edit', 'moderate']:
                if permission in resource_permission:
                    continue
                #print "Denying %s on %s" % permission, res.get_name())
                action_id = locals()[permission].get_id()
                assert self.guard.deny_from_id(resource.get_id(),
                                               action_id,
                                               res.get_id())

        return None


    def __delete_resource(self, resource):
        assert resource is not None

        # Check permissions.
        current_user = self.api.get_current_user()

        # Make sure that current_user has "edit" permissions on it.
        edit = self.guard.get_action(handle = 'edit', type = UserAction)
        assert edit is not None
        permit = self.guard.has_permission(current_user, edit, resource)
        if not permit and resource.is_group():
            return [_("You do not have permission to delete this group.")]
        elif not permit:
            return [_("You do not have permission to delete this user.")]

        assert self.guard.delete_resource(resource) > 0
        return None


    def index(self, **kwargs):
        # Find out which item was requested.
        path_str = self.api.get_data().get_str('path_str')
        if path_str is None:
            resource = self.guard.get_resource(handle = 'everybody',
                                               type   = Group)
            path = SpiffGuard.ResourcePath([resource.get_id()])
        else:
            path = SpiffGuard.ResourcePath(path_str)

        # Fetch the requested user or group info.
        errors = []
        id     = path.get_current_id()
        if self.api.post_data().get_bool('group_add'):
            resource = Group('')
            path     = path.append(0)
        elif self.api.post_data().get_bool('user_add'):
            resource = User('')
            path     = path.append(0)
        elif self.api.post_data().get_bool('group_save') and id == 0:
            resource = Group('')
            errors   = self.__save_resource(resource)
            if not errors:
                path = path.crop().append(resource.get_id())
        elif self.api.post_data().get_bool('group_save'):
            resource = self.guard.get_resource(id = id)
            errors   = self.__save_resource(resource)
            path     = path.crop().append(resource.get_id())
        elif self.api.post_data().get_bool('user_save') and id == 0:
            resource = User('')
            errors   = self.__save_resource(resource)
            if not errors:
                path = path.crop().append(resource.get_id())
        elif self.api.post_data().get_bool('user_save'):
            resource = self.guard.get_resource(id = id)
            errors   = self.__save_resource(resource)
            path     = path.crop().append(resource.get_id())
        elif (self.api.post_data().get_bool('group_delete') and
              self.api.post_data().get_str('group_delete_really') == 'yes'):
            resource = self.guard.get_resource(id = id)
            # Check if the group still has users in it.
            children = self.guard.get_resource_children(resource)
            if len(children) > 0:
                #FIXME: Rather ask what to do with the children.
                errors = [_("Group can not be deleted because " +
                                    "it still has users in it.")]
            else:
                errors   = self.__delete_resource(resource)
                path     = path.crop()
                id       = path.get_current_id()
                resource = self.guard.get_resource(id = id)
        elif (self.api.post_data().get_bool('user_delete') and
              self.api.post_data().get_str('user_delete_really') == 'yes'):
            resource = self.guard.get_resource(id = id)
            errors   = self.__delete_resource(resource)
            path     = path.crop()
            id       = path.get_current_id()
            resource = self.guard.get_resource(id = id)
        elif path_str is not None:
            resource = self.guard.get_resource(id = id)

        # Display the editor.
        if resource.is_group():
            self.__show_group(resource, path, errors)
        else:
            self.__show_user(resource, path, errors)