def get(self): user = self.get_current_user() if not (user.has_permission(AUDIT_VIEWER) or user.has_permission(AUDIT_MANAGER)): return self.forbidden() offset = int(self.get_argument("offset", 0)) limit = int(self.get_argument("limit", 50)) if limit > 200: limit = 200 open_filter = self.get_argument("filter", "Open Audits") audits = get_audits(self.session, only_open=(open_filter == "Open Audits")) open_audits = any([not audit.complete for audit in audits]) total = audits.count() audits = audits.offset(offset).limit(limit).all() open_audits = self.session.query(Audit).filter( Audit.complete == False).all() can_start = user.has_permission(AUDIT_MANAGER) # FIXME(herb): make limit selected from ui audit_log_entries = AuditLog.get_entries(self.session, category=AuditLogCategory.audit, limit=100) self.render( "audits.html", audits=audits, open_filter=open_filter, can_start=can_start, offset=offset, limit=limit, total=total, open_audits=open_audits, audit_log_entries=audit_log_entries, )
def test_expire_edges(expired_graph, session): # noqa """ Test expiration auditing and notification. """ email = session.query(AsyncNotification).all() assert email == [] for edge in session.query(GroupEdge).all(): assert edge.active == True # Expire the edges. background = BackgroundThread(settings, None) background.expire_edges(session) # Check that the edges are now marked as inactive. edges = ( session.query(GroupEdge) .filter(GroupEdge.group_id == Group.id, Group.enabled == True, GroupEdge.expiration != None) .all() ) for edge in edges: assert edge.active == False # Check that we have two queued email messages. # # TODO(rra): It would be nice to check the contents as well. email = session.query(AsyncNotification).all() assert len(email) == 2 # Check that we have three audit log entries: one for the expired user and # two for both "sides" of the expired group membership. audits = AuditLog.get_entries(session, action="expired_from_group") assert len(audits) == 3
def test_audit_end_to_end(session, users, groups, http_client, base_url): # noqa """ Tests an end-to-end audit cycle. """ groupname = 'audited-team' zay_id = users["*****@*****.**"].id 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["*****@*****.**"]) # 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 AuditMember = namedtuple('AuditMember', 'am_id, edge_type, edge_id') Audit = namedtuple('Audit', 'audit_id, owner_name, group_name, audit_members') all_group_ids = [x.group.id for x in open_audits] open_audits = [Audit(x.id, x.group.my_owners().iterkeys().next(), x.group.name, [AuditMember(am.id, am.edge.member_type, am.edge_id) for am in x.my_members()]) 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(am.am_id): "approved" for am in one_audit.audit_members}) 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 am in one_audit.my_members(): if gary_id == am.member.id: # deny body_dict["audit_{}".format(am.id)] = "remove" else: # approve body_dict["audit_{}".format(am.id)] = "approved" owner_name = one_audit.group.my_owners().iterkeys().next() 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'