예제 #1
0
def test_assert_can_join(users, groups):  # noqa
    """ Test various audit constraints to ensure that users can/can't join as appropriate. """

    # Non-auditor can join non-audited group as owner.
    assert assert_can_join(groups["team-infra"], users["zay"], role="owner")

    # Auditor can join non-audited group as owner.
    assert assert_can_join(groups["team-infra"], users["zorkian"], role="owner")

    # Non-auditor can NOT join audited group as owner.
    with pytest.raises(UserNotAuditor):
        assert not assert_can_join(groups["serving-team"], users["zay"], role="owner")

    # Non-auditor can join audited group as member.
    assert assert_can_join(groups["serving-team"], users["zay"])

    # Group with non-auditor owner can NOT join audited group.
    with pytest.raises(UserNotAuditor):
        assert not assert_can_join(groups["serving-team"], groups["tech-ops"])

    # Group with auditor owner can join audited group.
    assert assert_can_join(groups["serving-team"], groups["sad-team"])

    # Group with non-auditor owner can join non-audited group.
    assert assert_can_join(groups["team-infra"], groups["tech-ops"])

    # Group with auditor owner, but sub-group with non-auditor owner, can NOT join audited group.
    with pytest.raises(UserNotAuditor):
        assert not assert_can_join(groups["audited-team"], groups["serving-team"])
예제 #2
0
    def post(self, *args, **kwargs):
        # type: (*Any, **Any) -> None
        request_id = kwargs["request_id"]  # type: int
        group_id = kwargs.get("group_id")  # type: Optional[int]
        name = kwargs.get("name")  # type: Optional[str]

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

        members = group.my_members()
        my_role = user_role(self.current_user, members)
        if my_role not in ("manager", "owner", "np-owner"):
            return self.forbidden()

        request = self.session.query(Request).filter_by(id=request_id).scalar()
        if not request:
            return self.notfound()

        on_behalf = get_on_behalf_by_request(self.session, request)

        form = GroupRequestModifyForm(self.request.arguments)
        form.status.choices = self._get_choices(request.status)

        updates = request.my_status_updates()

        if not form.status.choices:
            alerts = [Alert("info", "Request has already been processed")]
            return self.render(
                "group-request-update.html",
                group=group,
                request=request,
                on_behalf=on_behalf,
                members=members,
                form=form,
                alerts=alerts,
                statuses=REQUEST_STATUS_CHOICES,
                updates=updates,
            )

        if not form.validate():
            return self.render(
                "group-request-update.html",
                group=group,
                request=request,
                on_behalf=on_behalf,
                members=members,
                form=form,
                alerts=self.get_form_alerts(form.errors),
                statuses=REQUEST_STATUS_CHOICES,
                updates=updates,
            )

        # We have to test this here, too, to ensure that someone can't sneak in with a pending
        # request that used to be allowed.
        if form.data["status"] != "cancelled":
            fail_message = "This join is denied with this role at this time."
            try:
                user_can_join = assert_can_join(
                    request.requesting, on_behalf, role=request.edge.role
                )
            except UserNotAuditor as e:
                user_can_join = False
                fail_message = str(e)
            if not user_can_join:
                return self.render(
                    "group-request-update.html",
                    group=group,
                    request=request,
                    on_behalf=on_behalf,
                    members=members,
                    form=form,
                    statuses=REQUEST_STATUS_CHOICES,
                    updates=updates,
                    alerts=[Alert("danger", fail_message, "Audit Policy Enforcement")],
                )

        request.update_status(self.current_user, form.data["status"], form.data["reason"])
        self.session.commit()

        AuditLog.log(
            self.session,
            self.current_user.id,
            "update_request",
            "Updated request to status: {}".format(form.data["status"]),
            on_group_id=group.id,
            on_user_id=request.requester.id,
        )

        edge = self.session.query(GroupEdge).filter_by(id=request.edge_id).one()

        approver_mail_to = [
            user.name
            for user in group.my_approver_users()
            if user.name != self.current_user.name and user.name != request.requester.username
        ]

        subj = "Re: " + self.render_template(
            "email/pending_request_subj.tmpl", group=group.name, user=request.requester.username
        )

        send_email(
            self.session,
            approver_mail_to,
            subj,
            "approver_request_updated",
            settings(),
            {
                "group_name": group.name,
                "requester": request.requester.username,
                "changed_by": self.current_user.name,
                "status": form.data["status"],
                "role": edge.role,
                "reason": form.data["reason"],
                "references_header": request.reference_id,
            },
        )

        if form.data["status"] == "actioned":
            send_email(
                self.session,
                [request.requester.name],
                "Added to group: {}".format(group.groupname),
                "request_actioned",
                settings(),
                {
                    "group_name": group.name,
                    "actioned_by": self.current_user.name,
                    "reason": form.data["reason"],
                    "expiration": edge.expiration,
                    "role": edge.role,
                },
            )
        elif form.data["status"] == "cancelled":
            send_email(
                self.session,
                [request.requester.name],
                "Request to join cancelled: {}".format(group.groupname),
                "request_cancelled",
                settings(),
                {
                    "group_name": group.name,
                    "cancelled_by": self.current_user.name,
                    "reason": form.data["reason"],
                    "expiration": edge.expiration,
                    "role": edge.role,
                },
            )

        # No explicit refresh because handler queries SQL.
        if form.data["redirect_aggregate"]:
            return self.redirect("/user/requests")
        else:
            return self.redirect("/groups/{}/requests".format(group.name))
예제 #3
0
    def post(self, *args: Any, **kwargs: Any) -> None:
        name = self.get_path_argument("name")

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

        members = group.my_members()
        member_groups = {g for t, g in members if t == "Group"}
        user_is_member = self._is_user_a_member(group, members)

        form = GroupJoinForm(self.request.arguments)
        form.member.choices = self._get_choices(group, member_groups,
                                                user_is_member)
        if not form.validate():
            return self.render("group-join.html",
                               form=form,
                               group=group,
                               alerts=self.get_form_alerts(form.errors))

        member = self._get_member(form.data["member"])
        if not member:
            return self.render(
                "group-join.html",
                form=form,
                group=group,
                alerts=[
                    Alert(
                        "danger", "Unknown user or group: {}".format(
                            form.data["member"]))
                ],
            )

        try:
            assert_can_join(group, member, role=form.data["role"])
        except UserNotAuditor as e:
            return self.render(
                "group-join.html",
                form=form,
                group=group,
                alerts=[Alert("danger", str(e), "Audit Policy Enforcement")],
            )

        if group.canjoin == "nobody":
            fail_message = "This group cannot be joined at this time."
            return self.render("group-join.html",
                               form=form,
                               group=group,
                               alerts=[Alert("danger", fail_message)])

        if group.require_clickthru_tojoin:
            if not form.data["clickthru_agreement"]:
                return self.render(
                    "group-join.html",
                    form=form,
                    group=group,
                    alerts=[
                        Alert(
                            "danger",
                            "please accept review of the group's description",
                            "Clickthru Enforcement",
                        )
                    ],
                )

        # We only use the default expiration time if no expiration time was given
        # This does mean that if a user wishes to join a group with no expiration
        # (even with an owner's permission) that has an auto expiration, they must
        # first be accepted to the group and then have the owner edit the user to
        # have no expiration.

        expiration = None
        if form.data["expiration"]:
            expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y")
        elif group.auto_expire:
            expiration = datetime.utcnow() + group.auto_expire

        # If the requested role is member, set the status based on the group's canjoin setting,
        # which automatically actions the request if the group can be joined by anyone and
        # otherwise sets it pending.
        #
        # However, we don't want to let people autojoin as owner or np-owner even to otherwise open
        # groups, so if the role is not member, force the status to pending.
        if form.data["role"] == "member":
            status = GROUP_JOIN_CHOICES[group.canjoin]
        else:
            status = "pending"

        try:
            request = group.add_member(
                requester=self.current_user,
                user_or_group=member,
                reason=form.data["reason"],
                status=status,
                expiration=expiration,
                role=form.data["role"],
            )
        except InvalidRoleForMember as e:
            return self.render(
                "group-join.html",
                form=form,
                group=group,
                alerts=[Alert("danger", str(e), "Invalid Role")],
            )
        self.session.commit()

        if status == "pending":
            AuditLog.log(
                self.session,
                self.current_user.id,
                "join_group",
                "{} requested to join with role: {}".format(
                    member.name, form.data["role"]),
                on_group_id=group.id,
            )

            mail_to = [
                user.name for user in group.my_users()
                if GROUP_EDGE_ROLES[user.role] in ("manager", "owner",
                                                   "np-owner")
            ]

            email_context = {
                "requester": member.name,
                "requested_by": self.current_user.name,
                "request_id": request.id,
                "group_name": group.name,
                "reason": form.data["reason"],
                "expiration": expiration,
                "role": form.data["role"],
                "references_header": request.reference_id,
            }

            subj = self.render_template("email/pending_request_subj.tmpl",
                                        group=group.name,
                                        user=self.current_user.name)
            send_email(self.session, mail_to, subj, "pending_request",
                       settings(), email_context)

        elif status == "actioned":
            AuditLog.log(
                self.session,
                self.current_user.id,
                "join_group",
                "{} auto-approved to join with role: {}".format(
                    member.name, form.data["role"]),
                on_group_id=group.id,
            )
        else:
            raise Exception(f"Unknown join status {status}")

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
예제 #4
0
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        form = GroupJoinForm(self.request.arguments)
        form.member.choices = self._get_choices(group)
        if not form.validate():
            return self.render(
                "group-join.html", form=form, group=group,
                alerts=self.get_form_alerts(form.errors)
            )

        member = self._get_member(form.data["member"])

        fail_message = 'This join is denied with this role at this time.'
        try:
            user_can_join = assert_can_join(group, member, role=form.data["role"])
        except UserNotAuditor as e:
            user_can_join = False
            fail_message = e
        if not user_can_join:
            return self.render(
                "group-join.html", form=form, group=group,
                alerts=[
                    Alert('danger', fail_message, 'Audit Policy Enforcement')
                ]
            )

        if group.canjoin == "nobody":
            fail_message = 'This group cannot be joined at this time.'
            return self.render(
                "group-join.html", form=form, group=group,
                alerts=[
                    Alert('danger', fail_message)
                ]
            )

        # We only use the default expiration time if no expiration time was given
        # This does mean that if a user wishes to join a group with no expiration
        # (even with an owner's permission) that has an auto expiration, they must
        # first be accepted to the group and then have the owner edit the user to
        # have no expiration.

        expiration = None
        if form.data["expiration"]:
            expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y")
        elif group.auto_expire:
            expiration = datetime.utcnow() + group.auto_expire

        request = group.add_member(
            requester=self.current_user,
            user_or_group=member,
            reason=form.data["reason"],
            status=GROUP_JOIN_CHOICES[group.canjoin],
            expiration=expiration,
            role=form.data["role"]
        )
        self.session.commit()

        if group.canjoin == 'canask':
            AuditLog.log(self.session, self.current_user.id, 'join_group',
                         '{} requested to join with role: {}'.format(
                             member.name, form.data["role"]),
                         on_group_id=group.id)

            mail_to = [
                user.name
                for user in group.my_users()
                if GROUP_EDGE_ROLES[user.role] in ('manager', 'owner', 'np-owner')
            ]

            email_context = {
                    "requester": member.name,
                    "requested_by": self.current_user.name,
                    "request_id": request.id,
                    "group_name": group.name,
                    "reason": form.data["reason"],
                    "expiration": expiration,
                    "role": form.data["role"],
                    "references_header": request.reference_id,
                    }

            subj = self.render_template(
                'email/pending_request_subj.tmpl',
                group=group.name,
                user=self.current_user.name
            )
            send_email(self.session, mail_to, subj,
                    'pending_request', settings, email_context)

        elif group.canjoin == 'canjoin':
            AuditLog.log(self.session, self.current_user.id, 'join_group',
                         '{} auto-approved to join with role: {}'.format(
                             member.name, form.data["role"]),
                         on_group_id=group.id)
        else:
            raise Exception('Need to update the GroupJoin.post audit logging')

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
예제 #5
0
    def post(self, request_id, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        members = group.my_members()
        my_role = self.current_user.my_role(members)
        if my_role not in ("manager", "owner", "np-owner"):
            return self.forbidden()

        request = self.session.query(Request).filter_by(id=request_id).scalar()
        if not request:
            return self.notfound()

        form = GroupRequestModifyForm(self.request.arguments)
        form.status.choices = self._get_choices(request.status)

        updates = request.my_status_updates()

        if not form.validate():
            return self.render(
                "group-request-update.html", group=group, request=request,
                members=members, form=form, alerts=self.get_form_alerts(form.errors),
                statuses=REQUEST_STATUS_CHOICES, updates=updates
            )

        # We have to test this here, too, to ensure that someone can't sneak in with a pending
        # request that used to be allowed.
        if form.data["status"] != "cancelled":
            fail_message = 'This join is denied with this role at this time.'
            try:
                user_can_join = assert_can_join(request.requesting, request.get_on_behalf(),
                                                role=request.edge.role)
            except UserNotAuditor as e:
                user_can_join = False
                fail_message = e
            if not user_can_join:
                return self.render(
                    "group-request-update.html", group=group, request=request,
                    members=members, form=form, statuses=REQUEST_STATUS_CHOICES, updates=updates,
                    alerts=[
                        Alert('danger', fail_message, 'Audit Policy Enforcement')
                    ]
                )

        request.update_status(
            self.current_user,
            form.data["status"],
            form.data["reason"]
        )
        self.session.commit()

        AuditLog.log(self.session, self.current_user.id, 'update_request',
                     'Updated request to status: {}'.format(form.data["status"]),
                     on_group_id=group.id, on_user_id=request.requester.id)

        edge = self.session.query(GroupEdge).filter_by(
            id=request.edge_id
        ).one()
        if form.data['status'] == 'actioned':
            send_email(
                self.session,
                [request.requester.name],
                'Added to group: {}'.format(group.groupname),
                'request_actioned',
                settings,
                {
                    'group': group.name,
                    'actioned_by': self.current_user.name,
                    'reason': form.data['reason'],
                    'expiration': edge.expiration,
                    'role': edge.role,
                }
            )
        elif form.data['status'] == 'cancelled':
            send_email(
                self.session,
                [request.requester.name],
                'Request to join cancelled: {}'.format(group.groupname),
                'request_cancelled',
                settings,
                {
                    'group': group.name,
                    'cancelled_by': self.current_user.name,
                    'reason': form.data['reason'],
                    'expiration': edge.expiration,
                    'role': edge.role,
                }
            )

        # No explicit refresh because handler queries SQL.
        if form.data['redirect_aggregate']:
            return self.redirect("/user/requests")
        else:
            return self.redirect("/groups/{}/requests".format(group.name))
예제 #6
0
    def post(self, *args, **kwargs):
        # type: (*Any, **Any) -> None
        group_id = kwargs.get("group_id")  # type: Optional[int]
        name = kwargs.get("name")  # type: Optional[str]

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

        members = group.my_members()
        member_groups = {g for t, g in members if t == "Group"}
        user_is_member = self._is_user_a_member(group, members)

        form = GroupJoinForm(self.request.arguments)
        form.member.choices = self._get_choices(group, member_groups,
                                                user_is_member)
        if not form.validate():
            return self.render("group-join.html",
                               form=form,
                               group=group,
                               alerts=self.get_form_alerts(form.errors))

        member = self._get_member(form.data["member"])
        if not member:
            return self.render(
                "group-join.html",
                form=form,
                group=group,
                alerts=[
                    Alert(
                        "danger", "Unknown user or group: {}".format(
                            form.data["member"]))
                ],
            )

        fail_message = "This join is denied with this role at this time."
        try:
            user_can_join = assert_can_join(group,
                                            member,
                                            role=form.data["role"])
        except UserNotAuditor as e:
            user_can_join = False
            fail_message = str(e)
        if not user_can_join:
            return self.render(
                "group-join.html",
                form=form,
                group=group,
                alerts=[
                    Alert("danger", fail_message, "Audit Policy Enforcement")
                ],
            )

        if group.canjoin == "nobody":
            fail_message = "This group cannot be joined at this time."
            return self.render("group-join.html",
                               form=form,
                               group=group,
                               alerts=[Alert("danger", fail_message)])

        if group.require_clickthru_tojoin:
            if not form.data["clickthru_agreement"]:
                return self.render(
                    "group-join.html",
                    form=form,
                    group=group,
                    alerts=[
                        Alert(
                            "danger",
                            "please accept review of the group's description",
                            "Clickthru Enforcement",
                        )
                    ],
                )

        # We only use the default expiration time if no expiration time was given
        # This does mean that if a user wishes to join a group with no expiration
        # (even with an owner's permission) that has an auto expiration, they must
        # first be accepted to the group and then have the owner edit the user to
        # have no expiration.

        expiration = None
        if form.data["expiration"]:
            expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y")
        elif group.auto_expire:
            expiration = datetime.utcnow() + group.auto_expire

        request = group.add_member(
            requester=self.current_user,
            user_or_group=member,
            reason=form.data["reason"],
            status=GROUP_JOIN_CHOICES[group.canjoin],
            expiration=expiration,
            role=form.data["role"],
        )
        self.session.commit()

        if group.canjoin == "canask":
            AuditLog.log(
                self.session,
                self.current_user.id,
                "join_group",
                "{} requested to join with role: {}".format(
                    member.name, form.data["role"]),
                on_group_id=group.id,
            )

            mail_to = [
                user.name for user in group.my_users()
                if GROUP_EDGE_ROLES[user.role] in ("manager", "owner",
                                                   "np-owner")
            ]

            email_context = {
                "requester": member.name,
                "requested_by": self.current_user.name,
                "request_id": request.id,
                "group_name": group.name,
                "reason": form.data["reason"],
                "expiration": expiration,
                "role": form.data["role"],
                "references_header": request.reference_id,
            }

            subj = self.render_template("email/pending_request_subj.tmpl",
                                        group=group.name,
                                        user=self.current_user.name)
            send_email(self.session, mail_to, subj, "pending_request",
                       settings(), email_context)

        elif group.canjoin == "canjoin":
            AuditLog.log(
                self.session,
                self.current_user.id,
                "join_group",
                "{} auto-approved to join with role: {}".format(
                    member.name, form.data["role"]),
                on_group_id=group.id,
            )
        else:
            raise Exception("Need to update the GroupJoin.post audit logging")

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
예제 #7
0
    def post(self, request_id, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        members = group.my_members()
        my_role = user_role(self.current_user, members)
        if my_role not in ("manager", "owner", "np-owner"):
            return self.forbidden()

        request = self.session.query(Request).filter_by(id=request_id).scalar()
        if not request:
            return self.notfound()

        form = GroupRequestModifyForm(self.request.arguments)
        form.status.choices = self._get_choices(request.status)

        updates = request.my_status_updates()

        if not form.validate():
            return self.render("group-request-update.html",
                               group=group,
                               request=request,
                               members=members,
                               form=form,
                               alerts=self.get_form_alerts(form.errors),
                               statuses=REQUEST_STATUS_CHOICES,
                               updates=updates)

        # We have to test this here, too, to ensure that someone can't sneak in with a pending
        # request that used to be allowed.
        if form.data["status"] != "cancelled":
            fail_message = 'This join is denied with this role at this time.'
            try:
                user_can_join = assert_can_join(request.requesting,
                                                request.get_on_behalf(),
                                                role=request.edge.role)
            except UserNotAuditor as e:
                user_can_join = False
                fail_message = e
            if not user_can_join:
                return self.render("group-request-update.html",
                                   group=group,
                                   request=request,
                                   members=members,
                                   form=form,
                                   statuses=REQUEST_STATUS_CHOICES,
                                   updates=updates,
                                   alerts=[
                                       Alert('danger', fail_message,
                                             'Audit Policy Enforcement')
                                   ])

        request.update_status(self.current_user, form.data["status"],
                              form.data["reason"])
        self.session.commit()

        AuditLog.log(self.session,
                     self.current_user.id,
                     'update_request',
                     'Updated request to status: {}'.format(
                         form.data["status"]),
                     on_group_id=group.id,
                     on_user_id=request.requester.id)

        edge = self.session.query(GroupEdge).filter_by(
            id=request.edge_id).one()

        approver_mail_to = [
            user.name for user in group.my_approver_users()
            if user.name != self.current_user.name
            and user.name != request.requester.username
        ]

        send_email(
            self.session,
            approver_mail_to,
            "Request to join {} by {} has been {}".format(
                group.groupname, request.requester.name, form.data['status']),
            "approver_request_updated",
            settings,
            {
                'group_name': group.name,
                'requester': request.requester.username,
                'changed_by': self.current_user.name,
                'status': form.data['status'],
                'role': edge.role,
                'reason': form.data['reason'],
            },
        )

        if form.data['status'] == 'actioned':
            send_email(
                self.session, [request.requester.name],
                'Added to group: {}'.format(group.groupname),
                'request_actioned', settings, {
                    'group_name': group.name,
                    'actioned_by': self.current_user.name,
                    'reason': form.data['reason'],
                    'expiration': edge.expiration,
                    'role': edge.role,
                })
        elif form.data['status'] == 'cancelled':
            send_email(
                self.session, [request.requester.name],
                'Request to join cancelled: {}'.format(group.groupname),
                'request_cancelled', settings, {
                    'group_name': group.name,
                    'cancelled_by': self.current_user.name,
                    'reason': form.data['reason'],
                    'expiration': edge.expiration,
                    'role': edge.role,
                })

        # No explicit refresh because handler queries SQL.
        if form.data['redirect_aggregate']:
            return self.redirect("/user/requests")
        else:
            return self.redirect("/groups/{}/requests".format(group.name))
예제 #8
0
    def post(self, *args, **kwargs):
        # type: (*Any, **Any) -> None
        group_id = kwargs.get("group_id")  # type: Optional[int]
        name = kwargs.get("name")  # type: Optional[str]

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

        if not user_can_manage_group(self.session, group, self.current_user):
            return self.forbidden()

        members = group.my_members()
        my_role = user_role(self.current_user, members)
        form = self.get_form(role=my_role)
        if not form.validate():
            return self.render(
                "group-add.html", form=form, group=group, alerts=self.get_form_alerts(form.errors)
            )

        member = get_user_or_group(self.session, form.data["member"])
        if member.type == "User" and is_role_user(self.session, member):
            # For service accounts, we want to always add the group to other groups, not the user
            member = get_role_user(self.session, user=member).group
        if not member:
            form.member.errors.append("User or group not found.")
        elif (member.type, member.name) in group.my_members():
            form.member.errors.append("User or group is already a member of this group.")
        elif group.name == member.name:
            form.member.errors.append("By definition, this group is a member of itself already.")

        # Ensure this doesn't violate auditing constraints
        fail_message = "This join is denied with this role at this time."
        try:
            user_can_join = assert_can_join(group, member, role=form.data["role"])
        except UserNotAuditor as e:
            user_can_join = False
            fail_message = str(e)
        if not user_can_join:
            form.member.errors.append(fail_message)

        if form.member.errors:
            return self.render(
                "group-add.html", form=form, group=group, alerts=self.get_form_alerts(form.errors)
            )

        expiration = None
        if form.data["expiration"]:
            expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y")

        try:
            group.add_member(
                requester=self.current_user,
                user_or_group=member,
                reason=form.data["reason"],
                status="actioned",
                expiration=expiration,
                role=form.data["role"],
            )
        except InvalidRoleForMember as e:
            return self.render(
                "group-add.html", form=form, group=group, alerts=[Alert("danger", str(e))]
            )

        self.session.commit()

        on_user_id = member.id if member.type == "User" else None
        AuditLog.log(
            self.session,
            self.current_user.id,
            "join_group",
            "{} added to group with role: {}".format(member.name, form.data["role"]),
            on_group_id=group.id,
            on_user_id=on_user_id,
        )

        if member.type == "User":
            send_email(
                self.session,
                [member.name],
                "Added to group: {}".format(group.name),
                "request_actioned",
                settings(),
                {
                    "group_name": group.name,
                    "actioned_by": self.current_user.name,
                    "reason": form.data["reason"],
                    "expiration": expiration,
                    "role": form.data["role"],
                },
            )

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
예제 #9
0
    def post(self, group_id=None, name=None, name2=None, member_type=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if self.current_user.name == name2:
            return self.forbidden()

        members = group.my_members()
        my_role = user_role(self.current_user, members)
        if my_role not in ("manager", "owner", "np-owner"):
            return self.forbidden()

        member = members.get((member_type.capitalize(), name2), None)
        if not member:
            return self.notfound()

        if member.type == "Group":
            user_or_group = Group.get(self.session, member.id)
        else:
            user_or_group = User.get(self.session, member.id)
        if not user_or_group:
            return self.notfound()

        edge = GroupEdge.get(
            self.session,
            group_id=group.id,
            member_type=OBJ_TYPES[member.type],
            member_pk=member.id,
        )
        if not edge:
            return self.notfound()

        form = GroupEditMemberForm(self.request.arguments)
        form.role.choices = [["member", "Member"]]
        if my_role in ("owner", "np-owner"):
            form.role.choices.append(["manager", "Manager"])
            form.role.choices.append(["owner", "Owner"])
            form.role.choices.append(["np-owner", "No-Permissions Owner"])

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

        fail_message = 'This join is denied with this role at this time.'
        try:
            user_can_join = assert_can_join(group,
                                            user_or_group,
                                            role=form.data["role"])
        except UserNotAuditor as e:
            user_can_join = False
            fail_message = e
        if not user_can_join:
            return self.render("group-edit-member.html",
                               form=form,
                               group=group,
                               member=member,
                               edge=edge,
                               alerts=[
                                   Alert('danger', fail_message,
                                         'Audit Policy Enforcement')
                               ])

        expiration = None
        if form.data["expiration"]:
            expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y")

        try:
            group.edit_member(self.current_user,
                              user_or_group,
                              form.data["reason"],
                              role=form.data["role"],
                              expiration=expiration)
        except (InvalidRoleForMember,
                PluginRejectedGroupMembershipUpdate) as e:
            return self.render("group-edit-member.html",
                               form=form,
                               group=group,
                               member=member,
                               edge=edge,
                               alerts=[Alert('danger', e.message)])

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
예제 #10
0
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        form = GroupJoinForm(self.request.arguments)
        form.member.choices = self._get_choices(group)
        if not form.validate():
            return self.render(
                "group-join.html", form=form, group=group,
                alerts=self.get_form_alerts(form.errors)
            )

        member = self._get_member(form.data["member"])

        fail_message = 'This join is denied with this role at this time.'
        try:
            user_can_join = assert_can_join(group, member, role=form.data["role"])
        except UserNotAuditor as e:
            user_can_join = False
            fail_message = e
        if not user_can_join:
            return self.render(
                "group-join.html", form=form, group=group,
                alerts=[
                    Alert('danger', fail_message, 'Audit Policy Enforcement')
                ]
            )

        if group.canjoin == "nobody":
            fail_message = 'This group cannot be joined at this time.'
            return self.render(
                "group-join.html", form=form, group=group,
                alerts=[
                    Alert('danger', fail_message)
                ]
            )

        expiration = None
        if form.data["expiration"]:
            expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y")

        group.add_member(
            requester=self.current_user,
            user_or_group=member,
            reason=form.data["reason"],
            status=GROUP_JOIN_CHOICES[group.canjoin],
            expiration=expiration,
            role=form.data["role"]
        )
        self.session.commit()

        if group.canjoin == 'canask':
            AuditLog.log(self.session, self.current_user.id, 'join_group',
                         '{} requested to join with role: {}'.format(
                             member.name, form.data["role"]),
                         on_group_id=group.id)

            mail_to = [
                user.name
                for user in group.my_users()
                if GROUP_EDGE_ROLES[user.role] in ('manager', 'owner', 'np-owner')
            ]

            email_context = {
                    "requester": member.name,
                    "requested_by": self.current_user.name,
                    "requested": group.name,
                    "reason": form.data["reason"],
                    "expiration": expiration,
                    "role": form.data["role"],
                    }
            send_email(self.session, mail_to, 'Request to join: {}'.format(group.name),
                    'pending_request', settings, email_context)

        elif group.canjoin == 'canjoin':
            AuditLog.log(self.session, self.current_user.id, 'join_group',
                         '{} auto-approved to join with role: {}'.format(
                             member.name, form.data["role"]),
                         on_group_id=group.id)
        else:
            raise Exception('Need to update the GroupJoin.post audit logging')

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
예제 #11
0
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        form = GroupJoinForm(self.request.arguments)
        form.member.choices = self._get_choices(group)
        if not form.validate():
            return self.render("group-join.html",
                               form=form,
                               group=group,
                               alerts=self.get_form_alerts(form.errors))

        member = self._get_member(form.data["member"])

        fail_message = 'This join is denied with this role at this time.'
        try:
            user_can_join = assert_can_join(group,
                                            member,
                                            role=form.data["role"])
        except UserNotAuditor as e:
            user_can_join = False
            fail_message = e
        if not user_can_join:
            return self.render("group-join.html",
                               form=form,
                               group=group,
                               alerts=[
                                   Alert('danger', fail_message,
                                         'Audit Policy Enforcement')
                               ])

        if group.canjoin == "nobody":
            fail_message = 'This group cannot be joined at this time.'
            return self.render("group-join.html",
                               form=form,
                               group=group,
                               alerts=[Alert('danger', fail_message)])

        # We only use the default expiration time if no expiration time was given
        # This does mean that if a user wishes to join a group with no expiration
        # (even with an owner's permission) that has an auto expiration, they must
        # first be accepted to the group and then have the owner edit the user to
        # have no expiration.

        expiration = None
        if form.data["expiration"]:
            expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y")
        elif group.auto_expire:
            expiration = datetime.utcnow() + group.auto_expire

        request = group.add_member(requester=self.current_user,
                                   user_or_group=member,
                                   reason=form.data["reason"],
                                   status=GROUP_JOIN_CHOICES[group.canjoin],
                                   expiration=expiration,
                                   role=form.data["role"])
        self.session.commit()

        if group.canjoin == 'canask':
            AuditLog.log(self.session,
                         self.current_user.id,
                         'join_group',
                         '{} requested to join with role: {}'.format(
                             member.name, form.data["role"]),
                         on_group_id=group.id)

            mail_to = [
                user.name for user in group.my_users()
                if GROUP_EDGE_ROLES[user.role] in ('manager', 'owner',
                                                   'np-owner')
            ]

            email_context = {
                "requester": member.name,
                "requested_by": self.current_user.name,
                "request_id": request.id,
                "group_name": group.name,
                "reason": form.data["reason"],
                "expiration": expiration,
                "role": form.data["role"],
                "references_header": request.reference_id,
            }

            subj = self.render_template('email/pending_request_subj.tmpl',
                                        group=group.name,
                                        user=self.current_user.name)
            send_email(self.session, mail_to, subj, 'pending_request',
                       settings, email_context)

        elif group.canjoin == 'canjoin':
            AuditLog.log(self.session,
                         self.current_user.id,
                         'join_group',
                         '{} auto-approved to join with role: {}'.format(
                             member.name, form.data["role"]),
                         on_group_id=group.id)
        else:
            raise Exception('Need to update the GroupJoin.post audit logging')

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
예제 #12
0
파일: group_add.py 프로젝트: yasaswyk/merou
    def post(self, *args: Any, **kwargs: Any) -> None:
        name = self.get_path_argument("name")

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

        if not user_can_manage_group(self.session, group, self.current_user):
            return self.forbidden()

        members = group.my_members()
        my_role = user_role(self.current_user, members)
        form = self.get_form(role=my_role)
        if not form.validate():
            return self.render("group-add.html",
                               form=form,
                               group=group,
                               alerts=self.get_form_alerts(form.errors))

        member = get_user_or_group(self.session, form.data["member"])
        if member.type == "User" and is_role_user(self.session, member):
            # For service accounts, we want to always add the group to other groups, not the user
            member = get_role_user(self.session, user=member).group
        if not member:
            form.member.errors.append("User or group not found.")
        elif (member.type, member.name) in group.my_members():
            form.member.errors.append(
                "User or group is already a member of this group.")
        elif group.name == member.name:
            form.member.errors.append(
                "By definition, this group is a member of itself already.")

        # Ensure this doesn't violate auditing constraints
        try:
            assert_can_join(group, member, role=form.data["role"])
        except UserNotAuditor as e:
            form.member.errors.append(str(e))

        if form.member.errors:
            return self.render("group-add.html",
                               form=form,
                               group=group,
                               alerts=self.get_form_alerts(form.errors))

        expiration = None
        if form.data["expiration"]:
            expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y")

        try:
            group.add_member(
                requester=self.current_user,
                user_or_group=member,
                reason=form.data["reason"],
                status="actioned",
                expiration=expiration,
                role=form.data["role"],
            )
        except InvalidRoleForMember as e:
            return self.render("group-add.html",
                               form=form,
                               group=group,
                               alerts=[Alert("danger", str(e))])

        self.session.commit()

        on_user_id = member.id if member.type == "User" else None
        AuditLog.log(
            self.session,
            self.current_user.id,
            "join_group",
            "{} added to group with role: {}".format(member.name,
                                                     form.data["role"]),
            on_group_id=group.id,
            on_user_id=on_user_id,
        )

        if member.type == "User":
            send_email(
                self.session,
                [member.name],
                "Added to group: {}".format(group.name),
                "request_actioned",
                settings(),
                {
                    "group_name": group.name,
                    "actioned_by": self.current_user.name,
                    "reason": form.data["reason"],
                    "expiration": expiration,
                    "role": form.data["role"],
                },
            )

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
예제 #13
0
    def post(self, *args: Any, **kwargs: Any) -> None:
        name = self.get_path_argument("name")
        member_name = self.get_path_argument("member_name")
        member_type = self.get_path_argument("member_type")

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

        members = group.my_members()
        my_role = user_role(self.current_user, members)
        if my_role not in ("manager", "owner", "np-owner"):
            return self.forbidden()

        member = members.get((member_type.capitalize(), member_name), None)
        if not member:
            return self.notfound()

        if member.type == "Group":
            user_or_group = Group.get(self.session, member.id)
        else:
            user_or_group = User.get(self.session, member.id)
        if not user_or_group:
            return self.notfound()

        edge = GroupEdge.get(
            self.session,
            group_id=group.id,
            member_type=OBJ_TYPES[member.type],
            member_pk=member.id,
        )
        if not edge:
            return self.notfound()

        form = self._get_form(member_name, my_role, member_type)
        if not form.validate():
            return self.render(
                "group-edit-member.html",
                group=group,
                member=member,
                edge=edge,
                form=form,
                alerts=self.get_form_alerts(form.errors),
            )

        try:
            assert_can_join(group, user_or_group, role=form.data["role"])
        except UserNotAuditor as e:
            return self.render(
                "group-edit-member.html",
                form=form,
                group=group,
                member=member,
                edge=edge,
                alerts=[Alert("danger", str(e), "Audit Policy Enforcement")],
            )

        expiration = None
        if form.data["expiration"]:
            expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y")

        try:
            group.edit_member(
                self.current_user,
                user_or_group,
                form.data["reason"],
                role=form.data["role"],
                expiration=expiration,
            )
        except (InvalidRoleForMember,
                PluginRejectedGroupMembershipUpdate) as e:
            return self.render(
                "group-edit-member.html",
                form=form,
                group=group,
                member=member,
                edge=edge,
                alerts=[Alert("danger", str(e))],
            )

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
예제 #14
0
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if not user_can_manage_group(self.session, group, self.current_user):
            return self.forbidden()

        members = group.my_members()
        my_role = user_role(self.current_user, members)
        form = self.get_form(role=my_role)
        if not form.validate():
            return self.render("group-add.html",
                               form=form,
                               group=group,
                               alerts=self.get_form_alerts(form.errors))

        member = get_user_or_group(self.session, form.data["member"])
        if member.type == "User" and is_role_user(self.session, member):
            # For service accounts, we want to always add the group to other groups, not the user
            member = get_role_user(self.session, user=member).group
        if not member:
            form.member.errors.append("User or group not found.")
        elif (member.type, member.name) in group.my_members():
            form.member.errors.append(
                "User or group is already a member of this group.")
        elif group.name == member.name:
            form.member.errors.append(
                "By definition, this group is a member of itself already.")

        # Ensure this doesn't violate auditing constraints
        fail_message = 'This join is denied with this role at this time.'
        try:
            user_can_join = assert_can_join(group,
                                            member,
                                            role=form.data["role"])
        except UserNotAuditor as e:
            user_can_join = False
            fail_message = e
        if not user_can_join:
            form.member.errors.append(fail_message)

        if form.member.errors:
            return self.render("group-add.html",
                               form=form,
                               group=group,
                               alerts=self.get_form_alerts(form.errors))

        expiration = None
        if form.data["expiration"]:
            expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y")

        try:
            group.add_member(requester=self.current_user,
                             user_or_group=member,
                             reason=form.data["reason"],
                             status='actioned',
                             expiration=expiration,
                             role=form.data["role"])
        except InvalidRoleForMember as e:
            return self.render("group-add.html",
                               form=form,
                               group=group,
                               alerts=[Alert('danger', e.message)])

        self.session.commit()

        on_user_id = member.id if member.type == "User" else None
        AuditLog.log(self.session,
                     self.current_user.id,
                     'join_group',
                     '{} added to group with role: {}'.format(
                         member.name, form.data["role"]),
                     on_group_id=group.id,
                     on_user_id=on_user_id)

        if member.type == "User":
            send_email(
                self.session, [member.name],
                'Added to group: {}'.format(group.name), 'request_actioned',
                settings, {
                    'group_name': group.name,
                    'actioned_by': self.current_user.name,
                    'reason': form.data['reason'],
                    'expiration': expiration,
                    'role': form.data['role'],
                })

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
예제 #15
0
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if not self.current_user.can_manage(group):
            return self.forbidden()

        members = group.my_members()
        my_role = self.current_user.my_role(members)
        form = self.get_form(role=my_role)
        if not form.validate():
            return self.render(
                "group-add.html", form=form, group=group,
                alerts=self.get_form_alerts(form.errors)
            )

        member = get_user_or_group(self.session, form.data["member"])
        if not member:
            form.member.errors.append("User or group not found.")
        elif (member.type, member.name) in group.my_members():
            form.member.errors.append("User or group is already a member of this group.")
        elif group.name == member.name:
            form.member.errors.append("By definition, this group is a member of itself already.")

        # Ensure this doesn't violate auditing constraints
        fail_message = 'This join is denied with this role at this time.'
        try:
            user_can_join = assert_can_join(group, member, role=form.data["role"])
        except UserNotAuditor as e:
            user_can_join = False
            fail_message = e
        if not user_can_join:
            form.member.errors.append(fail_message)

        if form.member.errors:
            return self.render(
                "group-add.html", form=form, group=group,
                alerts=self.get_form_alerts(form.errors)
            )

        expiration = None
        if form.data["expiration"]:
            expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y")

        group.add_member(
            requester=self.current_user,
            user_or_group=member,
            reason=form.data["reason"],
            status='actioned',
            expiration=expiration,
            role=form.data["role"]
        )
        self.session.commit()

        AuditLog.log(self.session, self.current_user.id, 'join_group',
                     '{} added to group with role: {}'.format(
                         member.name, form.data["role"]),
                     on_group_id=group.id)

        if member.type == "User":
            send_email(
                self.session,
                [member.name],
                'Added to group: {}'.format(group.name),
                'request_actioned',
                settings,
                {
                    'group': group.name,
                    'actioned_by': self.current_user.name,
                    'reason': form.data['reason'],
                    'expiration': expiration,
                    'role': form.data['role'],
                }
            )

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
예제 #16
0
    def post(self, group_id=None, name=None, name2=None, member_type=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if self.current_user.name == name2:
            return self.forbidden()

        members = group.my_members()
        my_role = self.current_user.my_role(members)
        if my_role not in ("manager", "owner", "np-owner"):
            return self.forbidden()

        member = members.get((member_type.capitalize(), name2), None)
        if not member:
            return self.notfound()

        if member.type == "Group":
            user_or_group = Group.get(self.session, member.id)
        else:
            user_or_group = User.get(self.session, member.id)
        if not user_or_group:
            return self.notfound()

        edge = GroupEdge.get(
            self.session,
            group_id=group.id,
            member_type=OBJ_TYPES[member.type],
            member_pk=member.id,
        )
        if not edge:
            return self.notfound()

        form = GroupEditMemberForm(self.request.arguments)
        form.role.choices = [["member", "Member"]]
        if my_role in ("owner", "np-owner"):
            form.role.choices.append(["manager", "Manager"])
            form.role.choices.append(["owner", "Owner"])
            form.role.choices.append(["np-owner", "No-Permissions Owner"])

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

        fail_message = 'This join is denied with this role at this time.'
        try:
            user_can_join = assert_can_join(group, user_or_group, role=form.data["role"])
        except UserNotAuditor as e:
            user_can_join = False
            fail_message = e
        if not user_can_join:
            return self.render(
                "group-edit-member.html", form=form, group=group, member=member, edge=edge,
                alerts=[
                    Alert('danger', fail_message, 'Audit Policy Enforcement')
                ]
            )

        expiration = None
        if form.data["expiration"]:
            expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y")

        group.edit_member(self.current_user, user_or_group, form.data["reason"],
                          role=form.data["role"], expiration=expiration)

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
예제 #17
0
    def post(self, *args, **kwargs):
        # type: (*Any, **Any) -> None
        group_id = kwargs.get("group_id")  # type: Optional[int]
        name = kwargs.get("name")  # type: Optional[str]

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

        form = GroupJoinForm(self.request.arguments)
        form.member.choices = self._get_choices(group)
        if not form.validate():
            return self.render(
                "group-join.html", form=form, group=group, alerts=self.get_form_alerts(form.errors)
            )

        member = self._get_member(form.data["member"])
        if not member:
            return self.render(
                "group-join.html",
                form=form,
                group=group,
                alerts=[Alert("danger", "Unknown user or group: {}".format(form.data["member"]))],
            )

        fail_message = "This join is denied with this role at this time."
        try:
            user_can_join = assert_can_join(group, member, role=form.data["role"])
        except UserNotAuditor as e:
            user_can_join = False
            fail_message = str(e)
        if not user_can_join:
            return self.render(
                "group-join.html",
                form=form,
                group=group,
                alerts=[Alert("danger", fail_message, "Audit Policy Enforcement")],
            )

        if group.canjoin == "nobody":
            fail_message = "This group cannot be joined at this time."
            return self.render(
                "group-join.html", form=form, group=group, alerts=[Alert("danger", fail_message)]
            )

        if group.require_clickthru_tojoin:
            if not form.data["clickthru_agreement"]:
                return self.render(
                    "group-join.html",
                    form=form,
                    group=group,
                    alerts=[
                        Alert(
                            "danger",
                            "please accept review of the group's description",
                            "Clickthru Enforcement",
                        )
                    ],
                )

        # We only use the default expiration time if no expiration time was given
        # This does mean that if a user wishes to join a group with no expiration
        # (even with an owner's permission) that has an auto expiration, they must
        # first be accepted to the group and then have the owner edit the user to
        # have no expiration.

        expiration = None
        if form.data["expiration"]:
            expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y")
        elif group.auto_expire:
            expiration = datetime.utcnow() + group.auto_expire

        request = group.add_member(
            requester=self.current_user,
            user_or_group=member,
            reason=form.data["reason"],
            status=GROUP_JOIN_CHOICES[group.canjoin],
            expiration=expiration,
            role=form.data["role"],
        )
        self.session.commit()

        if group.canjoin == "canask":
            AuditLog.log(
                self.session,
                self.current_user.id,
                "join_group",
                "{} requested to join with role: {}".format(member.name, form.data["role"]),
                on_group_id=group.id,
            )

            mail_to = [
                user.name
                for user in group.my_users()
                if GROUP_EDGE_ROLES[user.role] in ("manager", "owner", "np-owner")
            ]

            email_context = {
                "requester": member.name,
                "requested_by": self.current_user.name,
                "request_id": request.id,
                "group_name": group.name,
                "reason": form.data["reason"],
                "expiration": expiration,
                "role": form.data["role"],
                "references_header": request.reference_id,
            }

            subj = self.render_template(
                "email/pending_request_subj.tmpl", group=group.name, user=self.current_user.name
            )
            send_email(self.session, mail_to, subj, "pending_request", settings(), email_context)

        elif group.canjoin == "canjoin":
            AuditLog.log(
                self.session,
                self.current_user.id,
                "join_group",
                "{} auto-approved to join with role: {}".format(member.name, form.data["role"]),
                on_group_id=group.id,
            )
        else:
            raise Exception("Need to update the GroupJoin.post audit logging")

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