コード例 #1
0
def test_grantable_permissions(
    session, standard_graph, users, groups, grantable_permissions  # noqa: F811
):
    perm_grant, perm0, perm1, _ = grantable_permissions

    assert not user_grantable_permissions(session, users["*****@*****.**"]), "start with none"

    grant_permission(groups["auditors"], perm_grant, argument="notgrantable.one")
    assert not user_grantable_permissions(
        session, users["*****@*****.**"]
    ), "grant on non-existent is fine"

    grant_permission(groups["auditors"], perm_grant, argument=perm0.name)
    grants = user_grantable_permissions(session, users["*****@*****.**"])
    assert len(grants) == 1, "only specific permission grant"
    assert grants[0][0].name == perm0.name, "only specific permission grant"

    grant_permission(groups["auditors"], perm_grant, argument="grantable.*")
    grants = user_grantable_permissions(session, users["*****@*****.**"])
    assert len(grants) == 3, "wildcard grant should grab appropriat amount"
    assert sorted([x[0].name for x in grants]) == ["grantable", "grantable.one", "grantable.two"]

    args_by_perm = get_grantable_permissions(session, None)
    assert args_by_perm[perm1.name] == ["*"], "wildcard grant reflected in list of grantable"

    grant_permission(groups["auditors"], perm_grant, argument="{}/single_arg".format(perm1.name))
    args_by_perm = get_grantable_permissions(session, None)
    assert args_by_perm[perm1.name] == ["*"], "wildcard grant reflected cause no restricted perms"

    args_by_perm = get_grantable_permissions(session, [perm1.name])
    assert args_by_perm[perm1.name] == [
        "single_arg"
    ], "least permissive argument shown cause of restricted perms"
コード例 #2
0
ファイル: test_permissions.py プロジェクト: rra/grouper
def test_grantable_permissions(session, standard_graph, users, groups, grantable_permissions):
    perm_grant, perm0, perm1, _ = grantable_permissions

    assert not user_grantable_permissions(session, users["*****@*****.**"]), "start with none"

    grant_permission(groups["auditors"], perm_grant, argument="notgrantable.one")
    assert not user_grantable_permissions(session, users["*****@*****.**"]), "grant on non-existent is fine"

    grant_permission(groups["auditors"], perm_grant, argument=perm0.name)
    grants = user_grantable_permissions(session, users["*****@*****.**"])
    assert len(grants) == 1, "only specific permission grant"
    assert grants[0][0].name == perm0.name, "only specific permission grant"

    grant_permission(groups["auditors"], perm_grant, argument="grantable.*")
    grants = user_grantable_permissions(session, users["*****@*****.**"])
    assert len(grants) == 3, "wildcard grant should grab appropriat amount"
    assert sorted([x[0].name for x in grants]) == ["grantable", "grantable.one", "grantable.two"]

    args_by_perm = get_grantable_permissions(session, None)
    assert args_by_perm[perm1.name] == ["*"], "wildcard grant reflected in list of grantable"

    grant_permission(groups["auditors"], perm_grant, argument="{}/single_arg".format(perm1.name))
    args_by_perm = get_grantable_permissions(session, None)
    assert args_by_perm[perm1.name] == ["*"], "wildcard grant reflected cause no restricted perms"

    args_by_perm = get_grantable_permissions(session, [perm1.name])
    assert args_by_perm[perm1.name] == ["single_arg"], "least permissive argument shown cause of restricted perms"
コード例 #3
0
ファイル: template_variables.py プロジェクト: dropbox/grouper
def get_group_view_template_vars(session, actor, group, graph):
    # type: (Session, User, Group, GroupGraph) -> Dict[str, Any]
    ret = {}
    ret["grantable"] = user_grantable_permissions(session, actor)

    try:
        group_md = graph.get_group_details(group.name)
    except NoSuchGroup:
        # Very new group with no metadata yet, or it has been disabled and
        # excluded from in-memory cache.
        group_md = {}

    ret["members"] = group.my_members()
    ret["groups"] = group.my_groups()
    ret["service_accounts"] = get_service_accounts(session, group)
    ret["permissions"] = group_md.get("permissions", [])
    for permission in ret["permissions"]:
        permission["granted_on"] = datetime.fromtimestamp(permission["granted_on"])

    ret["permission_requests_pending"] = []
    for req in get_pending_request_by_group(session, group):
        granters = []
        for owner, argument in get_owner_arg_list(session, req.permission, req.argument):
            granters.append(owner.name)
        ret["permission_requests_pending"].append((req, granters))

    ret["audited"] = group_md.get("audited", False)
    ret["log_entries"] = group.my_log_entries()
    ret["num_pending"] = count_requests_by_group(session, group, status="pending")
    ret["current_user_role"] = {
        "is_owner": user_role_index(actor, ret["members"]) in OWNER_ROLE_INDICES,
        "is_approver": user_role_index(actor, ret["members"]) in APPROVER_ROLE_INDICES,
        "is_manager": user_role(actor, ret["members"]) == "manager",
        "is_member": user_role(actor, ret["members"]) is not None,
        "role": user_role(actor, ret["members"]),
    }
    ret["can_leave"] = (
        ret["current_user_role"]["is_member"] and not ret["current_user_role"]["is_owner"]
    )
    ret["statuses"] = AUDIT_STATUS_CHOICES

    # Add mapping_id to permissions structure
    ret["my_permissions"] = group.my_permissions()
    for perm_up in ret["permissions"]:
        for perm_direct in ret["my_permissions"]:
            if (
                perm_up["permission"] == perm_direct.name
                and perm_up["argument"] == perm_direct.argument
            ):
                perm_up["mapping_id"] = perm_direct.mapping_id
                break

    ret["alerts"] = []
    ret["self_pending"] = count_requests_by_group(session, group, status="pending", user=actor)
    if ret["self_pending"]:
        ret["alerts"].append(Alert("info", "You have a pending request to join this group.", None))

    return ret
コード例 #4
0
def get_group_view_template_vars(session, actor, group, graph):
    ret = {}
    ret["grantable"] = user_grantable_permissions(session, actor)

    try:
        group_md = graph.get_group_details(group.name)
    except NoSuchGroup:
        # Very new group with no metadata yet, or it has been disabled and
        # excluded from in-memory cache.
        group_md = {}

    ret["members"] = group.my_members()
    ret["groups"] = group.my_groups()
    ret["service_accounts"] = get_service_accounts(session, group)
    ret["permissions"] = group_md.get('permissions', [])

    ret["permission_requests_pending"] = []
    for req in get_pending_request_by_group(session, group):
        granters = []
        for owner, argument in get_owner_arg_list(session, req.permission,
                                                  req.argument):
            granters.append(owner.name)
        ret["permission_requests_pending"].append((req, granters))

    ret["audited"] = group_md.get('audited', False)
    ret["log_entries"] = group.my_log_entries()
    ret["num_pending"] = group.my_requests("pending").count()
    ret["current_user_role"] = {
        'is_owner': user_role_index(actor,
                                    ret["members"]) in OWNER_ROLE_INDICES,
        'is_approver': user_role_index(actor, ret["members"])
        in APPROVER_ROLE_INDICES,
        'is_manager': user_role(actor, ret["members"]) == "manager",
        'is_member': user_role(actor, ret["members"]) is not None,
        'role': user_role(actor, ret["members"]),
    }
    ret["can_leave"] = (ret["current_user_role"]['is_member']
                        and not ret["current_user_role"]['is_owner'])
    ret["statuses"] = AUDIT_STATUS_CHOICES

    # Add mapping_id to permissions structure
    ret["my_permissions"] = group.my_permissions()
    for perm_up in ret["permissions"]:
        for perm_direct in ret["my_permissions"]:
            if (perm_up['permission'] == perm_direct.name
                    and perm_up['argument'] == perm_direct.argument):
                perm_up['mapping_id'] = perm_direct.mapping_id
                break

    ret["alerts"] = []
    ret["self_pending"] = group.my_requests("pending", user=actor).count()
    if ret["self_pending"]:
        ret["alerts"].append(
            Alert('info', 'You have a pending request to join this group.',
                  None))

    return ret
コード例 #5
0
ファイル: template_variables.py プロジェクト: Acidity/grouper
def get_group_view_template_vars(session, actor, group, graph):
    ret = {}
    ret["grantable"] = user_grantable_permissions(session, actor)

    try:
        group_md = graph.get_group_details(group.name)
    except NoSuchGroup:
        # Very new group with no metadata yet, or it has been disabled and
        # excluded from in-memory cache.
        group_md = {}

    ret["members"] = group.my_members()
    ret["groups"] = group.my_groups()
    ret["permissions"] = group_md.get('permissions', [])

    ret["permission_requests_pending"] = []
    for req in get_pending_request_by_group(session, group):
        granters = []
        for owner, argument in get_owner_arg_list(session, req.permission, req.argument):
            granters.append(owner.name)
        ret["permission_requests_pending"].append((req, granters))

    ret["audited"] = group_md.get('audited', False)
    ret["log_entries"] = group.my_log_entries()
    ret["num_pending"] = group.my_requests("pending").count()
    ret["current_user_role"] = {
        'is_owner': user_role_index(actor, ret["members"]) in OWNER_ROLE_INDICES,
        'is_approver': user_role_index(actor, ret["members"]) in APPROVER_ROLE_INDICIES,
        'is_manager': user_role(actor, ret["members"]) == "manager",
        'is_member': user_role(actor, ret["members"]) is not None,
        'role': user_role(actor, ret["members"]),
        }
    ret["can_leave"] = (ret["current_user_role"]['is_member'] and not
        ret["current_user_role"]['is_owner'])
    ret["statuses"] = AUDIT_STATUS_CHOICES

    # Add mapping_id to permissions structure
    ret["my_permissions"] = group.my_permissions()
    for perm_up in ret["permissions"]:
        for perm_direct in ret["my_permissions"]:
            if (perm_up['permission'] == perm_direct.name and
                    perm_up['argument'] == perm_direct.argument):
                perm_up['mapping_id'] = perm_direct.mapping_id
                break

    ret["alerts"] = []
    ret["self_pending"] = group.my_requests("pending", user=actor).count()
    if ret["self_pending"]:
        ret["alerts"].append(Alert('info', 'You have a pending request to join this group.',
            None))

    return ret
コード例 #6
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
コード例 #7
0
ファイル: permissions_revoke.py プロジェクト: Acidity/grouper
    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
コード例 #8
0
    def get(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()
        form.permission.choices = [["", "(select one)"]]
        for perm in grantable:
            grantable = "{} ({})".format(perm[0].name, perm[1])
            form.permission.choices.append([perm[0].name, grantable])

        return self.render("permission-grant.html", form=form, group=group)
コード例 #9
0
ファイル: permissions_grant.py プロジェクト: dropbox/grouper
    def get(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()
        form.permission.choices = [["", "(select one)"]]
        for perm in grantable:
            grantable = "{} ({})".format(perm[0].name, perm[1])
            form.permission.choices.append([perm[0].name, grantable])

        return self.render("permission-grant.html", form=form, group=group)
コード例 #10
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))
コード例 #11
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))
コード例 #12
0
def get_group_view_template_vars(session, actor, group, graph):
    # type: (Session, User, Group, GroupGraph) -> Dict[str, Any]
    ret = {}
    ret["grantable"] = user_grantable_permissions(session, actor)

    try:
        group_md = graph.get_group_details(group.name)
    except NoSuchGroup:
        # Very new group with no metadata yet, or it has been disabled and
        # excluded from in-memory cache.
        group_md = {}

    ret["members"] = group.my_members()
    ret["groups"] = group.my_groups()
    ret["service_accounts"] = get_service_accounts(session, group)
    ret["permissions"] = group_md.get("permissions", [])
    for permission in ret["permissions"]:
        permission["granted_on"] = datetime.fromtimestamp(
            permission["granted_on"])

    ret["permission_requests_pending"] = []
    for req in get_pending_request_by_group(session, group):
        granters = []
        for owner, argument in get_owner_arg_list(session, req.permission,
                                                  req.argument):
            granters.append(owner.name)
        ret["permission_requests_pending"].append((req, granters))

    ret["audited"] = group_md.get("audited", False)
    ret["log_entries"] = group.my_log_entries()
    ret["num_pending"] = count_requests_by_group(session,
                                                 group,
                                                 status="pending")
    ret["current_user_role"] = {
        "is_owner": user_role_index(actor,
                                    ret["members"]) in OWNER_ROLE_INDICES,
        "is_approver": user_role_index(actor, ret["members"])
        in APPROVER_ROLE_INDICES,
        "is_manager": user_role(actor, ret["members"]) == "manager",
        "is_member": user_role(actor, ret["members"]) is not None,
        "role": user_role(actor, ret["members"]),
    }
    ret["can_leave"] = (ret["current_user_role"]["is_member"]
                        and not ret["current_user_role"]["is_owner"])
    ret["statuses"] = AUDIT_STATUS_CHOICES

    # Add mapping_id to permissions structure
    ret["my_permissions"] = group.my_permissions()
    for perm_up in ret["permissions"]:
        for perm_direct in ret["my_permissions"]:
            if (perm_up["permission"] == perm_direct.name
                    and perm_up["argument"] == perm_direct.argument):
                perm_up["mapping_id"] = perm_direct.mapping_id
                break

    ret["alerts"] = []
    ret["self_pending"] = count_requests_by_group(session,
                                                  group,
                                                  status="pending",
                                                  user=actor)
    if ret["self_pending"]:
        ret["alerts"].append(
            Alert("info", "You have a pending request to join this group.",
                  None))

    return ret
コード例 #13
0
def test_exclude_disabled_permissions(
    session, standard_graph, graph, users, groups, permissions  # noqa: F811
):
    """
    Ensure that disabled permissions are excluded from various
    functions/methods that return data from the models.
    """
    perm_ssh = get_permission(session, "ssh")
    perm_grant = create_permission(session, PERMISSION_GRANT)
    session.commit()
    # this user has grouper.permission.grant with argument "ssh/*"
    grant_permission(groups["group-admins"], perm_grant, argument="ssh/*")
    graph.update_from_db(session)

    grant_perms = [
        x for x in user_permissions(session, users["*****@*****.**"]) if x.name == PERMISSION_GRANT
    ]
    assert "ssh" == filter_grantable_permissions(session, grant_perms)[0][0].name
    assert "ssh" in (p.name for p in get_all_permissions(session))
    assert "ssh" in (p.name for p in get_all_permissions(session, include_disabled=False))
    assert "ssh" in (p.name for p in get_all_permissions(session, include_disabled=True))
    assert "ssh" in get_grantable_permissions(session, [])
    assert "team-sre" in [g[0] for g in get_groups_by_permission(session, perm_ssh)]
    assert get_owner_arg_list(session, perm_ssh, "*")
    assert "ssh" in get_owners_by_grantable_permission(session)
    assert "ssh" in (x[0].name for x in user_grantable_permissions(session, users["*****@*****.**"]))
    assert user_has_permission(session, users["*****@*****.**"], "ssh")
    assert "ssh" in (p.name for p in user_permissions(session, users["*****@*****.**"]))
    assert "ssh" in (p["permission"] for p in graph.get_group_details("team-sre")["permissions"])
    assert "ssh" in (pt.name for pt in graph.get_permissions())
    assert "team-sre" in graph.get_permission_details("ssh")["groups"]
    assert "ssh" in (p["permission"] for p in graph.get_user_details("*****@*****.**")["permissions"])

    # now disable the ssh permission
    disable_permission(session, "ssh", users["*****@*****.**"].id)
    graph.update_from_db(session)

    grant_perms = [
        x for x in user_permissions(session, users["*****@*****.**"]) if x.name == PERMISSION_GRANT
    ]
    assert not filter_grantable_permissions(session, grant_perms)
    assert "ssh" not in (p.name for p in get_all_permissions(session))
    assert "ssh" not in (p.name for p in get_all_permissions(session, include_disabled=False))
    assert "ssh" in (p.name for p in get_all_permissions(session, include_disabled=True))
    assert "ssh" not in get_grantable_permissions(session, [])
    assert not get_groups_by_permission(session, perm_ssh)
    assert not get_owner_arg_list(session, perm_ssh, "*")
    assert "ssh" not in get_owners_by_grantable_permission(session)
    assert "ssh" not in (
        x[0].name for x in user_grantable_permissions(session, users["*****@*****.**"])
    )
    assert not user_has_permission(session, users["*****@*****.**"], "ssh")
    assert "ssh" not in (p.name for p in user_permissions(session, users["*****@*****.**"]))
    assert "ssh" not in (
        p["permission"] for p in graph.get_group_details("team-sre")["permissions"]
    )
    assert "ssh" not in (pt.name for pt in graph.get_permissions())
    assert not graph.get_permission_details("ssh")["groups"]
    assert "ssh" not in (
        p["permission"] for p in graph.get_user_details("*****@*****.**")["permissions"]
    )
コード例 #14
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 = 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
                    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))