Example #1
0
def filter_grantable_permissions(session, grants, all_permissions=None):
    """For a given set of PERMISSION_GRANT permissions, return all permissions
    that are grantable.

    Args:
        session (sqlalchemy.orm.session.Session); database session
        grants ([Permission, ...]): PERMISSION_GRANT permissions
        all_permissions ({name: Permission}): all permissions to check against

    Returns:
        list of (Permission, argument) that is grantable by list of grants
        sorted by permission name and argument.
    """

    if all_permissions is None:
        all_permissions = {permission.name: permission for permission in
                Permission.get_all(session)}

    result = []
    for grant in grants:
        assert grant.name == PERMISSION_GRANT

        grantable = grant.argument.split('/', 1)
        if not grantable:
            continue
        for name, permission_obj in all_permissions.iteritems():
            if matches_glob(grantable[0], name):
                result.append((permission_obj,
                               grantable[1] if len(grantable) > 1 else '*', ))

    return sorted(result, key=lambda x: x[0].name + x[1])
Example #2
0
def get_owner_arg_list(session,
                       permission,
                       argument,
                       owners_by_arg_by_perm=None):
    """Return the grouper group(s) responsible for approving a request for the
    given permission + argument along with the actual argument they were
    granted.

    Args:
        session(sqlalchemy.orm.session.Session): database session
        permission(models.Permission): permission in question
        argument(str): argument for the permission
        owners_by_arg_by_perm(Dict): list of groups that can grant a given
            permission, argument pair in the format of
            {perm_name: {argument: [group1, group2, ...], ...}, ...}
            This is for convenience/caching if the value has already been fetched.
    Returns:
        list of 2-tuple of (group, argument) where group is the models.Group
        grouper groups responsibile for permimssion+argument and argument is
        the argument actually granted to that group. can be empty.
    """
    if owners_by_arg_by_perm is None:
        owners_by_arg_by_perm = get_owners_by_grantable_permission(session)

    all_owner_arg_list = []
    owners_by_arg = owners_by_arg_by_perm[permission.name]
    for arg, owners in owners_by_arg.items():
        if matches_glob(arg, argument):
            all_owner_arg_list += [(owner, arg) for owner in owners]

    return all_owner_arg_list
Example #3
0
def filter_grantable_permissions(
    session: Session,
    grants: List[Any],
    all_permissions: Optional[Dict[str, Permission]] = None
) -> List[Tuple[Permission, str]]:
    """For a set of PERMISSION_GRANT permissions, return all permissions that are grantable.

    Args:
        session: Database session
        grants: PERMISSION_GRANT permissions
        all_permissions: All permissions to check against (defaults to all permissions)

    Returns:
        List of (Permission, argument) that is grantable by list of grants, sorted by permission
        name and argument.
    """
    if all_permissions is None:
        all_permissions = {
            permission.name: permission
            for permission in get_all_permissions(session)
        }

    result = []
    for grant in grants:
        assert grant.name == PERMISSION_GRANT

        grantable = grant.argument.split("/", 1)
        if not grantable:
            continue
        for name, permission_obj in all_permissions.items():
            if matches_glob(grantable[0], name):
                result.append((permission_obj,
                               grantable[1] if len(grantable) > 1 else "*"))

    return sorted(result, key=lambda x: x[0].name + x[1])
Example #4
0
    def post(self, name=None, mapping_id=None):
        grantable = self.current_user.my_grantable_permissions()
        if not grantable:
            return self.forbidden()

        mapping = PermissionMap.get(self.session, id=mapping_id)
        if not mapping:
            return self.notfound()

        allowed = False
        for perm in grantable:
            if perm[0].name == mapping.permission.name:
                if matches_glob(perm[1], mapping.argument):
                    allowed = True
        if not allowed:
            return self.forbidden()

        permission = mapping.permission
        group = mapping.group

        mapping.delete(self.session)
        self.session.commit()

        AuditLog.log(self.session, self.current_user.id, 'revoke_permission',
                     'Revoked permission with argument: {}'.format(mapping.argument),
                     on_group_id=group.id, on_permission_id=permission.id)

        return self.redirect('/groups/{}?refresh=yes'.format(group.name))
Example #5
0
def get_owner_arg_list(
    session: Session,
    permission: Permission,
    argument: str,
    owners_by_arg_by_perm: Optional[Dict[object, Dict[str,
                                                      List[Group]]]] = None,
) -> List[Tuple[Group, str]]:
    """Determine the Grouper groups responsible for approving a request.

    Return the grouper groups responsible for approving a request for the given permission +
    argument along with the actual argument they were granted.

    Args:
        session: Database session
        permission: Permission in question
        argument: Argument for the permission
        owners_by_arg_by_perm: Groups that can grant a given permission, argument pair in the
            format of {perm_name: {argument: [group1, group2, ...], ...}, ...}
            This is for convenience/caching if the value has already been fetched.

    Returns:
        List of 2-tuple of (group, argument) where group is the Group for the Grouper groups
        responsibile for permimssion + argument, and argument is the argument actually granted to
        that group. Can be empty.
    """
    if owners_by_arg_by_perm is None:
        owners_by_arg_by_perm = get_owners_by_grantable_permission(session)

    all_owner_arg_list: List[Tuple[Group, str]] = []
    owners_by_arg = owners_by_arg_by_perm[permission.name]
    for arg, owners in owners_by_arg.items():
        if matches_glob(arg, argument):
            all_owner_arg_list += [(owner, arg) for owner in owners]

    return all_owner_arg_list
Example #6
0
def get_owner_arg_list(session,
                       permission,
                       argument,
                       owners_by_arg_by_perm=None):
    """Return the grouper group(s) responsible for approving a request for the
    given permission + argument along with the actual argument they were
    granted.

    Args:
        session(sqlalchemy.orm.session.Session): database session
        permission(models.Permission): permission in question
        argument(str): argument for the permission
    Returns:
        list of 2-tuple of (group, argument) where group is the models.Group
        grouper groups responsibile for permimssion+argument and argument is
        the argument actually granted to that group. can be empty.
    """
    if owners_by_arg_by_perm is None:
        owners_by_arg_by_perm = get_owners_by_grantable_permission(session)

    all_owner_arg_list = []
    owners_by_arg = owners_by_arg_by_perm[permission.name]
    for arg, owners in owners_by_arg.items():
        if matches_glob(arg, argument):
            all_owner_arg_list += [(owner, arg) for owner in owners]

    return all_owner_arg_list
Example #7
0
def filter_grantable_permissions(session, grants, all_permissions=None):
    """For a given set of PERMISSION_GRANT permissions, return all permissions
    that are grantable.

    Args:
        session (sqlalchemy.orm.session.Session); database session
        grants ([Permission, ...]): PERMISSION_GRANT permissions
        all_permissions ({name: Permission}): all permissions to check against

    Returns:
        list of (Permission, argument) that is grantable by list of grants
        sorted by permission name and argument.
    """

    if all_permissions is None:
        all_permissions = {permission.name: permission for permission in
                Permission.get_all(session)}

    result = []
    for grant in grants:
        assert grant.name == PERMISSION_GRANT

        grantable = grant.argument.split('/', 1)
        if not grantable:
            continue
        for name, permission_obj in all_permissions.iteritems():
            if matches_glob(grantable[0], name):
                result.append((permission_obj,
                               grantable[1] if len(grantable) > 1 else '*', ))

    return sorted(result, key=lambda x: x[0].name + x[1])
Example #8
0
    def permissions_grantable_by_service_account(self, service):
        # type: (str) -> List[Tuple[str, str]]
        """Returns a name-sorted list of (permission, argument glob) pairs a service can grant."""
        pagination = Pagination(sort_key=ListPermissionsSortKey.NAME,
                                reverse_sort=False,
                                offset=0,
                                limit=None)
        all_permissions = self.permission_repository.list_permissions(
            pagination, False).values

        if self.service_account_is_permission_admin(service):
            return [(p.name, "*") for p in all_permissions]

        grants = self.permission_grant_repository.permission_grants_for_service_account(
            service)
        grants_of_permission_grant = [
            g for g in grants if g.permission == PERMISSION_GRANT
        ]

        result = []
        for grant in grants_of_permission_grant:
            grantable = grant.argument.split("/", 1)
            if not grantable:
                continue
            for permission in all_permissions:
                if matches_glob(grantable[0], permission.name):
                    result.append(
                        (permission.name,
                         grantable[1] if len(grantable) > 1 else "*"))

        return result
Example #9
0
def get_owner_arg_list(session, permission, argument, owners_by_arg_by_perm=None):
    """Return the grouper group(s) responsible for approving a request for the
    given permission + argument along with the actual argument they were
    granted.

    Args:
        session(sqlalchemy.orm.session.Session): database session
        permission(models.Permission): permission in question
        argument(str): argument for the permission
        owners_by_arg_by_perm(Dict): list of groups that can grant a given
            permission, argument pair in the format of
            {perm_name: {argument: [group1, group2, ...], ...}, ...}
            This is for convenience/caching if the value has already been fetched.
    Returns:
        list of 2-tuple of (group, argument) where group is the models.Group
        grouper groups responsibile for permimssion+argument and argument is
        the argument actually granted to that group. can be empty.
    """
    if owners_by_arg_by_perm is None:
        owners_by_arg_by_perm = get_owners_by_grantable_permission(session)

    all_owner_arg_list = []
    owners_by_arg = owners_by_arg_by_perm[permission.name]
    for arg, owners in iteritems(owners_by_arg):
        if matches_glob(arg, argument):
            all_owner_arg_list += [(owner, arg) for owner in owners]

    return all_owner_arg_list
    def post(self):
        can_create = user_creatable_permissions(self.session,
                                                self.current_user)
        if not can_create:
            return self.forbidden()

        form = PermissionCreateForm(self.request.arguments)
        if not form.validate():
            return self.render("permission-create.html",
                               form=form,
                               alerts=self.get_form_alerts(form.errors))

        # A user is allowed to create a permission if the name matches any of the globs that they
        # are given access to via PERMISSION_CREATE, as long as the permission does not match a
        # reserved name. (Unless specifically granted.)
        allowed = False
        for creatable in can_create:
            if matches_glob(creatable, form.data["name"]):
                allowed = True

        for failure_message in test_reserved_names(form.data["name"]):
            form.name.errors.append(failure_message)

        if not allowed:
            form.name.errors.append(
                "Permission name does not match any of your allowed patterns.")

        if form.name.errors:
            return self.render("permission-create.html",
                               form=form,
                               alerts=self.get_form_alerts(form.errors))

        try:
            permission = create_permission(self.session, form.data["name"],
                                           form.data["description"])
            self.session.flush()
        except IntegrityError:
            self.session.rollback()
            form.name.errors.append(
                "Name already in use. Permissions must be unique.")
            return self.render(
                "permission-create.html",
                form=form,
                can_create=can_create,
                alerts=self.get_form_alerts(form.errors),
            )

        self.session.commit()

        AuditLog.log(
            self.session,
            self.current_user.id,
            "create_permission",
            "Created permission.",
            on_permission_id=permission.id,
        )

        # No explicit refresh because handler queries SQL.
        return self.redirect("/permissions/{}".format(permission.name))
Example #11
0
    def post(self):
        can_create = user_creatable_permissions(self.session, self.current_user)
        if not can_create:
            return self.forbidden()

        form = PermissionCreateForm(self.request.arguments)
        if not form.validate():
            return self.render(
                "permission-create.html", form=form, alerts=self.get_form_alerts(form.errors)
            )

        # A user is allowed to create a permission if the name matches any of the globs that they
        # are given access to via PERMISSION_CREATE, as long as the permission does not match a
        # reserved name. (Unless specifically granted.)
        allowed = False
        for creatable in can_create:
            if matches_glob(creatable, form.data["name"]):
                allowed = True

        for failure_message in test_reserved_names(form.data["name"]):
            form.name.errors.append(failure_message)

        if not allowed:
            form.name.errors.append("Permission name does not match any of your allowed patterns.")

        if form.name.errors:
            return self.render(
                "permission-create.html", form=form, alerts=self.get_form_alerts(form.errors)
            )

        try:
            permission = create_permission(
                self.session, form.data["name"], form.data["description"]
            )
            self.session.flush()
        except IntegrityError:
            self.session.rollback()
            form.name.errors.append("Name already in use. Permissions must be unique.")
            return self.render(
                "permission-create.html",
                form=form,
                can_create=sorted(can_create),
                alerts=self.get_form_alerts(form.errors),
            )

        self.session.commit()

        AuditLog.log(
            self.session,
            self.current_user.id,
            "create_permission",
            "Created permission.",
            on_permission_id=permission.id,
        )

        # No explicit refresh because handler queries SQL.
        return self.redirect("/permissions/{}".format(permission.name))
Example #12
0
 def group_has_matching_permission_grant(self, group, permission, argument):
     # type: (str, str, str) -> bool
     grants = self.permission_grant_repository.permission_grants_for_group(
         group)
     for grant in grants:
         if grant.permission == permission:
             if matches_glob(grant.argument, argument):
                 return True
     return False
    def post(self, group_id=None, name=None, account_id=None, accountname=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()
        service_account = ServiceAccount.get(self.session, account_id, accountname)
        if not service_account:
            return self.notfound()
        user = service_account.user

        if not self.check_access(self.session, self.current_user, service_account):
            return self.forbidden()

        grantable = group.my_permissions()
        form = self.get_form(grantable)
        if not form.validate():
            return self.render(
                "service-account-permission-grant.html", form=form, user=user, group=group,
                alerts=self.get_form_alerts(form.errors)
            )

        permission = Permission.get(self.session, form.data["permission"])
        if not permission:
            return self.notfound()

        allowed = False
        for perm in grantable:
            if perm[1] == permission.name:
                if matches_glob(perm[3], form.data["argument"]):
                    allowed = True
                    break
        if not allowed:
            form.argument.errors.append(
                "The group {} does not have that permission".format(group.name))
            return self.render(
                "service-account-permission-grant.html", form=form, user=user, group=group,
                alerts=self.get_form_alerts(form.errors)
            )

        try:
            grant_permission_to_service_account(
                self.session, service_account, permission, form.data["argument"])
        except IntegrityError:
            self.session.rollback()
            return self.render(
                "service-account-permission-grant.html", form=form, user=user,
                alerts=self.get_form_alerts(form.errors)
            )

        AuditLog.log(self.session, self.current_user.id, "grant_permission",
                     "Granted permission with argument: {}".format(form.data["argument"]),
                     on_permission_id=permission.id, on_group_id=group.id,
                     on_user_id=service_account.user.id)

        return self.redirect("/groups/{}/service/{}?refresh=yes".format(
            group.name, service_account.user.username))
Example #14
0
    def check_access(session: Session, mapping: PermissionMap, user: User):
        user_is_owner = user_is_owner_of_group(session, mapping.group, user)

        if user_is_owner:
            return True

        grantable = user_grantable_permissions(session, user)

        for perm in grantable:
            if perm[0].name == mapping.permission.name:
                if matches_glob(perm[1], mapping.argument):
                    return True

        return False
Example #15
0
    def check_access(session, mapping, user):
        user_is_owner = user_is_owner_of_group(session, mapping.group, user)

        if user_is_owner:
            return True

        grantable = user_grantable_permissions(session, user)

        for perm in grantable:
            if perm[0].name == mapping.permission.name:
                if matches_glob(perm[1], mapping.argument):
                    return True

        return False
Example #16
0
    def grant_permission_to_service_account(self, permission, argument,
                                            service):
        # type: (str, str, str) -> None
        if not self.service_account_service.service_account_is_enabled(
                service):
            self.ui.grant_permission_to_service_account_failed_service_account_not_found(
                service)
            return

        valid, error = self.permission_service.is_valid_permission_argument(
            permission, argument)
        if not valid:
            assert error
            self.ui.grant_permission_to_service_account_failed_invalid_argument(
                permission, argument, service, error)
            return

        allowed = False
        grantable = self.permissions_grantable_to_service_account(service)
        for grantable_perm, grantable_arg in grantable:
            if grantable_perm == permission and matches_glob(
                    grantable_arg, argument):
                allowed = True
                break
        if not allowed:
            message = (
                "Permission denied. To grant a permission to a service account you must either "
                "independently have the ability to grant that permission, or the owner group "
                "must have that permission and you must be a member of that owning group."
            )
            self.ui.grant_permission_to_service_account_failed_permission_denied(
                permission, argument, service, message)
            return

        authorization = Authorization(self.actor)
        with self.transaction_service.transaction():
            try:
                self.service_account_service.grant_permission_to_service_account(
                    permission, argument, service, authorization)
            except PermissionNotFoundException:
                # It should be impossible to hit this exception. In order to get this far, the
                # perm must be on the list of perms the actor can grant, and thus must exist.
                # Leaving the logic here however in case that changes in the future.
                self.ui.grant_permission_to_service_account_failed_permission_not_found(
                    permission, service)
                return
        self.ui.granted_permission_to_service_account(permission, argument,
                                                      service)
Example #17
0
    def get(self, name=None, mapping_id=None):
        grantable = self.current_user.my_grantable_permissions()
        if not grantable:
            return self.forbidden()

        mapping = PermissionMap.get(self.session, id=mapping_id)
        if not mapping:
            return self.notfound()

        allowed = False
        for perm in grantable:
            if perm[0].name == mapping.permission.name:
                if matches_glob(perm[1], mapping.argument):
                    allowed = True
        if not allowed:
            return self.forbidden()

        self.render("permission-revoke.html", mapping=mapping)
Example #18
0
    def permissions_grantable_by_user(self, user):
        # type: (str) -> List[Tuple[str, str]]
        """Returns a name-sorted list of all (permission, argument glob) pairs a user can grant.

        NOTE: The list of grantable permissions is calculated based on _all_ grants of the
        PERMISSION_GRANT permission that the user has. In particular this includes indirectly
        inherited grants. As of writing, this behavior differs from the legacy non-hexagonal
        logic, so anything relying on that old logic will act differently.
        """
        pagination = Pagination(sort_key=ListPermissionsSortKey.NAME,
                                reverse_sort=False,
                                offset=0,
                                limit=None)
        all_permissions = self.permission_repository.list_permissions(
            pagination, False).values

        if self.user_is_permission_admin(user):
            return [(p.name, "*") for p in all_permissions]

        all_grants = self.permission_grant_repository.permission_grants_for_user(
            user)
        grants_of_permission_grant = [
            g for g in all_grants if g.permission == PERMISSION_GRANT
        ]

        result = []
        for grant in grants_of_permission_grant:
            grantable = grant.argument.split("/", 1)
            if not grantable:
                continue
            for permission in all_permissions:
                if matches_glob(grantable[0], permission.name):
                    result.append(
                        (permission.name,
                         grantable[1] if len(grantable) > 1 else "*"))

        return result
Example #19
0
def get_owner_arg_list(session, permission, argument, owners_by_arg_by_perm=None):
    """Return the grouper group(s) responsible for approving a request for the
    given permission + argument along with the actual argument they were
    granted.

    Args:
        session(sqlalchemy.orm.session.Session): database session
        permission(models.Permission): permission in question
        argument(str): argument for the permission
    Returns:
        list of 2-tuple of (group, argument) where group is the models.Group
        grouper groups responsibile for permimssion+argument and argument is
        the argument actually granted to that group. can be empty.
    """
    if owners_by_arg_by_perm is None:
        owners_by_arg_by_perm = get_owners_by_grantable_permission(session)

    all_owner_arg_list = []
    owners_by_arg = owners_by_arg_by_perm[permission.name]
    for arg, owners in owners_by_arg.items():
        if matches_glob(arg, argument):
            all_owner_arg_list += [(owner, arg) for owner in owners]

    return all_owner_arg_list
Example #20
0
    def post(self, name=None):
        grantable = self.current_user.my_grantable_permissions()
        if not grantable:
            return self.forbidden()

        group = Group.get(self.session, None, name)
        if not group:
            return self.notfound()

        form = PermissionGrantForm(self.request.arguments)
        form.permission.choices = [["", "(select one)"]]
        for perm in grantable:
            grantable_str = "{} ({})".format(perm[0].name, perm[1])
            form.permission.choices.append([perm[0].name, grantable_str])

        if not form.validate():
            return self.render(
                "permission-grant.html", form=form, group=group, alerts=self.get_form_alerts(form.errors)
            )

        permission = Permission.get(self.session, form.data["permission"])
        if not permission:
            return self.notfound()  # Shouldn't happen.

        allowed = False
        for perm in grantable:
            if perm[0].name == permission.name:
                if matches_glob(perm[1], form.data["argument"]):
                    allowed = True
        if not allowed:
            form.argument.errors.append("You do not have grant authority over that permission/argument combination.")
            return self.render(
                "permission-grant.html", form=form, group=group, alerts=self.get_form_alerts(form.errors)
            )

        # If the permission is audited, then see if the subtree meets auditing requirements.
        if permission.audited:
            fail_message = (
                "Permission is audited and this group (or a subgroup) contains "
                + "owners, np-owners, or managers who have not received audit training."
            )
            try:
                permission_ok = assert_controllers_are_auditors(group)
            except UserNotAuditor as e:
                permission_ok = False
                fail_message = e
            if not permission_ok:
                form.permission.errors.append(fail_message)
                return self.render(
                    "permission-grant.html", form=form, group=group, alerts=self.get_form_alerts(form.errors)
                )

        try:
            group.grant_permission(permission, argument=form.data["argument"])
        except IntegrityError:
            form.argument.errors.append("Permission and Argument already mapped to this group.")
            return self.render(
                "permission-grant.html", form=form, group=group, alerts=self.get_form_alerts(form.errors)
            )

        self.session.commit()

        AuditLog.log(
            self.session,
            self.current_user.id,
            "grant_permission",
            "Granted permission with argument: {}".format(form.data["argument"]),
            on_permission_id=permission.id,
            on_group_id=group.id,
        )

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
Example #21
0
    def post(self,
             group_id=None,
             name=None,
             account_id=None,
             accountname=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()
        service_account = ServiceAccount.get(self.session, account_id,
                                             accountname)
        if not service_account:
            return self.notfound()
        user = service_account.user

        if not self.check_access(self.session, self.current_user,
                                 service_account):
            return self.forbidden()

        grantable = group.my_permissions()
        form = self.get_form(grantable)
        if not form.validate():
            return self.render("service-account-permission-grant.html",
                               form=form,
                               user=user,
                               group=group,
                               alerts=self.get_form_alerts(form.errors))

        permission = Permission.get(self.session, form.data["permission"])
        if not permission:
            return self.notfound()

        allowed = False
        for perm in grantable:
            if perm[1] == permission.name:
                if matches_glob(perm[3], form.data["argument"]):
                    allowed = True
                    break
        if not allowed:
            form.argument.errors.append(
                "The group {} does not have that permission".format(
                    group.name))
            return self.render("service-account-permission-grant.html",
                               form=form,
                               user=user,
                               group=group,
                               alerts=self.get_form_alerts(form.errors))

        try:
            grant_permission_to_service_account(self.session, service_account,
                                                permission,
                                                form.data["argument"])
        except IntegrityError:
            self.session.rollback()
            return self.render("service-account-permission-grant.html",
                               form=form,
                               user=user,
                               alerts=self.get_form_alerts(form.errors))

        AuditLog.log(self.session,
                     self.current_user.id,
                     "grant_permission",
                     "Granted permission with argument: {}".format(
                         form.data["argument"]),
                     on_permission_id=permission.id,
                     on_group_id=group.id,
                     on_user_id=service_account.user.id)

        return self.redirect("/groups/{}/service/{}?refresh=yes".format(
            group.name, service_account.user.username))
Example #22
0
    def post(self, *args: Any, **kwargs: Any) -> None:
        name = self.get_path_argument("name")

        grantable = user_grantable_permissions(self.session, self.current_user)
        if not grantable:
            return self.forbidden()

        group = Group.get(self.session, name=name)
        if not group:
            return self.notfound()

        form = PermissionGrantForm(self.request.arguments)
        form.permission.choices = [["", "(select one)"]]
        for perm in grantable:
            grantable_str = "{} ({})".format(perm[0].name, perm[1])
            form.permission.choices.append([perm[0].name, grantable_str])

        if not form.validate():
            return self.render(
                "permission-grant.html",
                form=form,
                group=group,
                alerts=self.get_form_alerts(form.errors),
            )

        permission = get_permission(self.session, form.data["permission"])
        if not permission:
            return self.notfound()  # Shouldn't happen.

        argument = form.argument.data.strip()

        allowed = False
        for perm in grantable:
            if perm[0].name == permission.name:
                if matches_glob(perm[1], argument):
                    allowed = True
                    break
        if not allowed:
            form.argument.errors.append(
                "You do not have grant authority over that permission/argument combination."
            )
            return self.render(
                "permission-grant.html",
                form=form,
                group=group,
                alerts=self.get_form_alerts(form.errors),
            )

        # If the permission is audited, then see if the subtree meets auditing requirements.
        if permission.audited:
            try:
                assert_controllers_are_auditors(group)
            except UserNotAuditor as e:
                form.permission.errors.append(str(e))
                return self.render(
                    "permission-grant.html",
                    form=form,
                    group=group,
                    alerts=self.get_form_alerts(form.errors),
                )

        try:
            self.plugins.check_permission_argument(permission.name, argument)
            grant_permission(self.session,
                             group.id,
                             permission.id,
                             argument=argument)
        except PluginRejectedPermissionArgument as e:
            self.session.rollback()
            form.argument.errors.append(f"Rejected by plugin: {e}")
            return self.render(
                "permission-grant.html",
                form=form,
                group=group,
                alerts=self.get_form_alerts(form.errors),
            )
        except IntegrityError:
            self.session.rollback()
            form.argument.errors.append(
                "Permission and Argument already mapped to this group.")
            return self.render(
                "permission-grant.html",
                form=form,
                group=group,
                alerts=self.get_form_alerts(form.errors),
            )

        self.session.commit()

        AuditLog.log(
            self.session,
            self.current_user.id,
            "grant_permission",
            "Granted permission with argument: {}".format(
                form.data["argument"]),
            on_permission_id=permission.id,
            on_group_id=group.id,
        )

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
Example #23
0
    def post(self, name=None):
        grantable = user_grantable_permissions(self.session, self.current_user)
        if not grantable:
            return self.forbidden()

        group = Group.get(self.session, None, name)
        if not group:
            return self.notfound()

        form = PermissionGrantForm(self.request.arguments)
        form.permission.choices = [["", "(select one)"]]
        for perm in grantable:
            grantable_str = "{} ({})".format(perm[0].name, perm[1])
            form.permission.choices.append([perm[0].name, grantable_str])

        if not form.validate():
            return self.render(
                "permission-grant.html",
                form=form,
                group=group,
                alerts=self.get_form_alerts(form.errors),
            )

        permission = get_permission(self.session, form.data["permission"])
        if not permission:
            return self.notfound()  # Shouldn't happen.

        allowed = False
        for perm in grantable:
            if perm[0].name == permission.name:
                if matches_glob(perm[1], form.data["argument"]):
                    allowed = True
                    break
        if not allowed:
            form.argument.errors.append(
                "You do not have grant authority over that permission/argument combination."
            )
            return self.render(
                "permission-grant.html",
                form=form,
                group=group,
                alerts=self.get_form_alerts(form.errors),
            )

        # If the permission is audited, then see if the subtree meets auditing requirements.
        if permission.audited:
            fail_message = (
                "Permission is audited and this group (or a subgroup) contains "
                +
                "owners, np-owners, or managers who have not received audit training."
            )
            try:
                permission_ok = assert_controllers_are_auditors(group)
            except UserNotAuditor as e:
                permission_ok = False
                fail_message = e
            if not permission_ok:
                form.permission.errors.append(fail_message)
                return self.render(
                    "permission-grant.html",
                    form=form,
                    group=group,
                    alerts=self.get_form_alerts(form.errors),
                )

        try:
            grant_permission(self.session,
                             group.id,
                             permission.id,
                             argument=form.data["argument"])
        except IntegrityError:
            self.session.rollback()
            form.argument.errors.append(
                "Permission and Argument already mapped to this group.")
            return self.render(
                "permission-grant.html",
                form=form,
                group=group,
                alerts=self.get_form_alerts(form.errors),
            )

        self.session.commit()

        AuditLog.log(
            self.session,
            self.current_user.id,
            "grant_permission",
            "Granted permission with argument: {}".format(
                form.data["argument"]),
            on_permission_id=permission.id,
            on_group_id=group.id,
        )

        return self.redirect("/groups/{}?refresh=yes".format(group.name))