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"])
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))
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))
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))
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))
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))
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))
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))
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))
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))
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))
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))
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))
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))
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))
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))
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))