def get(self, *args: Any, **kwargs: Any) -> None: name = self.get_path_argument("name") self.handle_refresh() group = Group.get(self.session, name=name) if not group: return self.notfound() if is_role_user(self.session, group=group): return self.redirect("/service/{}".format(group.groupname)) self.render("group.html", group=group, audit_members_infos=get_group_audit_members_infos( self.session, group), **get_group_view_template_vars(self.session, self.current_user, group, self.graph))
def get(self, *args, **kwargs): # type: (*Any, **Any) -> None group_id = kwargs.get("group_id") # type: Optional[int] name = kwargs.get("name") # type: Optional[str] self.handle_refresh() group = Group.get(self.session, group_id, name) if not group: return self.notfound() if is_role_user(self.session, group=group): return self.redirect("/service/{}".format(group.groupname)) self.render("group.html", group=group, audit_members_infos=get_group_audit_members_infos( self.session, group), **get_group_view_template_vars(self.session, self.current_user, group, self.graph))
def get(self, *args: Any, **kwargs: Any) -> None: name = self.get_path_argument("name") self.handle_refresh() user = User.get(self.session, name=name) if not user or not user.role_user: return self.notfound() group = Group.get(self.session, name=name) if not group: return self.notfound() actor = self.current_user graph = self.graph session = self.session self.render("role-user.html", user=user, group=group, audit_members_infos=get_group_audit_members_infos( self.session, group), **get_role_user_view_template_vars(session, actor, user, group, graph))
def get(self, *args, **kwargs): # type: (*Any, **Any) -> None user_id = kwargs.get("user_id") # type: Optional[int] name = kwargs.get("name") # type: Optional[str] self.handle_refresh() user = User.get(self.session, user_id, name) if not user or not user.role_user: return self.notfound() group = Group.get(self.session, name=name) actor = self.current_user graph = self.graph session = self.session self.render("service.html", user=user, group=group, audit_members_infos=get_group_audit_members_infos( self.session, group), **get_role_user_view_template_vars(session, actor, user, group, graph))
def test_audit_end_to_end(session, users, groups, http_client, base_url, graph): # noqa: F811 """ Tests an end-to-end audit cycle. """ groupname = "audited-team" gary_id = users["*****@*****.**"].id # make everyone an auditor or global audit will have issues add_member(groups["auditors"], users["*****@*****.**"]) add_member(groups["auditors"], users["*****@*****.**"]) add_member(groups["auditors"], users["*****@*****.**"]) add_member(groups["auditors"], users["*****@*****.**"]) # add some users to test removal add_member(groups[groupname], users["*****@*****.**"]) add_member(groups[groupname], users["*****@*****.**"]) graph.update_from_db(session) # start the audit end_at_str = (datetime.now() + timedelta(days=10)).strftime("%m/%d/%Y") fe_url = url(base_url, "/audits/create") resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"ends_at": end_at_str}), headers={"X-Grouper-User": "******"}, ) assert resp.code == 200 open_audits = get_audits(session, only_open=True).all() assert len(open_audits) == 4, "audits created" assert groupname in [x.group.name for x in open_audits ], "group we expect also gets audit" # pull all the info we need to resolve audits, avoids detached sqlalchemy sessions # (DetachedInstanceError) all_group_ids = [x.group.id for x in open_audits] open_audits = [ Audit( x.id, next(iter(x.group.my_owners())), x.group.name, [ MyAuditMemberInfo( ami.audit_member_obj.id, ami.audit_member_obj.edge.member_type, ami.audit_member_obj.edge_id, ) for ami in get_group_audit_members_infos(session, x.group) ], ) for x in open_audits ] # approve everything but the one we added members to for one_audit in open_audits: fe_url = url(base_url, "/audits/{}/complete".format(one_audit.audit_id)) if one_audit.group_name == groupname: continue # blanket approval body = urlencode({ "audit_{}".format(ami.am_id): "approved" for ami in one_audit.audit_members_infos }) resp = yield http_client.fetch( fe_url, method="POST", body=body, headers={"X-Grouper-User": one_audit.owner_name}) assert resp.code == 200 open_audits = get_audits(session, only_open=True).all() assert len(open_audits) == 1, "only our test group remaining" one_audit = open_audits[0] one_audit.id body_dict = {} for ami in get_group_audit_members_infos(session, one_audit.group): if gary_id == ami.member_obj.id: # deny body_dict["audit_{}".format(ami.audit_member_obj.id)] = "remove" else: # approve body_dict["audit_{}".format(ami.audit_member_obj.id)] = "approved" owner_name = next(iter(one_audit.group.my_owners())) fe_url = url(base_url, "/audits/{}/complete".format(one_audit.id)) resp = yield http_client.fetch(fe_url, method="POST", body=urlencode(body_dict), headers={"X-Grouper-User": owner_name}) assert resp.code == 200 # check all the logs assert len(AuditLog.get_entries( session, action="start_audit")) == 1, "global start is logged" assert (len(AuditLog.get_entries( session, action="complete_global_audit")) == 1), "global complete is logged" for group_id in all_group_ids: assert (len( AuditLog.get_entries( session, on_group_id=group_id, action="complete_audit", category=AuditLogCategory.audit, )) == 1), "complete entry for each group" assert (len( AuditLog.get_entries(session, on_user_id=gary_id, category=AuditLogCategory.audit)) == 1 ), "removal AuditLog entry on user"
def post(self, audit_id): if not user_has_permission(self.session, self.current_user, PERMISSION_AUDITOR): return self.forbidden() audit = self.session.query(Audit).filter(Audit.id == audit_id).one() # only owners can complete owner_ids = {member.id for member in audit.group.my_owners().values()} if self.current_user.id not in owner_ids: return self.forbidden() if audit.complete: return self.redirect("/groups/{}".format(audit.group.name)) edges = {} for argument in self.request.arguments: if argument.startswith("audit_"): edges[int(argument.split("_") [1])] = self.request.arguments[argument][0].decode() for audit_member_info in get_group_audit_members_infos( self.session, audit.group): if audit_member_info.audit_member_obj.id in edges: # You can only approve yourself (otherwise you can remove yourself # from the group and leave it ownerless) if audit_member_info.member_obj.id == self.current_user.id: audit_member_info.audit_member_obj.status = "approved" elif edges[audit_member_info.audit_member_obj. id] in AUDIT_STATUS_CHOICES: audit_member_info.audit_member_obj.status = edges[ audit_member_info.audit_member_obj.id] self.session.commit() # If there are still pending statuses, then redirect to the group page. if group_has_pending_audit_members(self.session, audit.group): return self.redirect("/groups/{}".format(audit.group.name)) # Complete audits have to be "enacted" now. This means anybody marked as remove has to # be removed from the group now. try: for audit_member_info in get_group_audit_members_infos( self.session, audit.group): member_obj = audit_member_info.member_obj if audit_member_info.audit_member_obj.status == "remove": audit.group.revoke_member(self.current_user, member_obj, "Revoked as part of audit.") AuditLog.log( self.session, self.current_user.id, "remove_member", "Removed membership in audit: {}".format( member_obj.name), on_group_id=audit.group.id, on_user_id=member_obj.id, category=AuditLogCategory.audit, ) except PluginRejectedGroupMembershipUpdate as e: alert = Alert("danger", str(e)) return self.redirect("/groups/{}".format(audit.group.name), alerts=[alert]) audit.complete = True self.session.commit() # Now cancel pending emails cancel_async_emails(self.session, "audit-{}".format(audit.group.id)) AuditLog.log( self.session, self.current_user.id, "complete_audit", "Completed group audit.", on_group_id=audit.group.id, category=AuditLogCategory.audit, ) # check if all audits are complete if get_audits(self.session, only_open=True).count() == 0: AuditLog.log( self.session, self.current_user.id, "complete_global_audit", "last open audit have been completed", category=AuditLogCategory.audit, ) return self.redirect("/groups/{}".format(audit.group.name))