Пример #1
0
    def get(self):
        user = self.get_current_user()
        if not (user_has_permission(self.session, user, AUDIT_VIEWER) or
                user_has_permission(self.session, user, 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(self.session, user, 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,
        )
Пример #2
0
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
Пример #3
0
def test_expire_edges(expired_graph, session):  # noqa: F811
    """ 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 = BackgroundProcessor(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
Пример #4
0
    def get(self):
        user = self.get_current_user()
        if not (user_has_permission(self.session, user, AUDIT_VIEWER) or
                user_has_permission(self.session, user, 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(self.session, user, 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,
        )
Пример #5
0
    def my_log_entries(self):
        # type: () -> List[AuditLog]
        """Returns the 20 most recent audit log entries involving this tag

        Returns:
            a list of AuditLog entries
        """
        return AuditLog.get_entries(self.session, on_tag_id=self.id, limit=20)
Пример #6
0
def get_log_entries_by_user(session, user, limit=20):
    """For a given user, return the audit logs that pertain.

    Args:
        session(models.base.session.Session): database session
        user(User): user in question
        limit(int): number of results to return
    """
    return AuditLog.get_entries(session, involve_user_id=user.id, limit=limit)
Пример #7
0
def get_log_entries_by_permission(session, permission, limit=20):
    """For a given permission, return the audit logs that pertain.

    Args:
        session(models.base.session.Session): database session
        permission_name(Permission): permission in question
        limit(int): number of results to return
    """
    return AuditLog.get_entries(session, on_permission_id=permission.id, limit=limit)
Пример #8
0
def get_log_entries_by_user(session, user, limit=20):
    """For a given user, return the audit logs that pertain.

    Args:
        session(models.base.session.Session): database session
        user(User): user in question
        limit(int): number of results to return
    """
    return AuditLog.get_entries(session, involve_user_id=user.id, limit=limit)
Пример #9
0
def get_log_entries_by_permission(session, permission, limit=20):
    """For a given permission, return the audit logs that pertain.

    Args:
        session(models.base.session.Session): database session
        permission_name(Permission): permission in question
        limit(int): number of results to return
    """
    return AuditLog.get_entries(session, on_permission_id=permission.id, limit=limit)
Пример #10
0
def test_github(session, users, http_client, base_url):  # noqa: F811
    user = users["*****@*****.**"]
    assert get_user_metadata_by_key(session, user.id,
                                    USER_METADATA_GITHUB_USERNAME_KEY) is None

    user = User.get(session, name=user.username)
    fe_url = url(base_url, "/users/{}/github".format(user.username))
    resp = yield http_client.fetch(
        fe_url,
        method="POST",
        body=urlencode({"username": "******"}),
        headers={"X-Grouper-User": user.username},
    )
    assert resp.code == 200
    user = User.get(session, name=user.username)
    assert (get_user_metadata_by_key(session, user.id,
                                     USER_METADATA_GITHUB_USERNAME_KEY)
            is not None)
    assert (get_user_metadata_by_key(
        session, user.id,
        USER_METADATA_GITHUB_USERNAME_KEY).data_value == "joe-on-github")

    audit_entries = AuditLog.get_entries(session,
                                         on_user_id=user.id,
                                         action="changed_github_username")
    assert len(audit_entries) == 1
    assert audit_entries[
        0].description == "Changed GitHub username: joe-on-github"

    fe_url = url(base_url, "/users/{}/github".format(user.username))
    resp = yield http_client.fetch(
        fe_url,
        method="POST",
        body=urlencode({"username": ""}),
        headers={"X-Grouper-User": user.username},
    )
    assert resp.code == 200
    user = User.get(session, name=user.username)
    assert get_user_metadata_by_key(session, user.id,
                                    USER_METADATA_GITHUB_USERNAME_KEY) is None
Пример #11
0
    def my_log_entries(self):

        return AuditLog.get_entries(self.session, involve_user_id=self.id, limit=20)
Пример #12
0
    def my_log_entries(self):

        return AuditLog.get_entries(self.session,
                                    on_group_id=self.id,
                                    limit=20)
Пример #13
0
def test_promote_nonauditors(
        mock_gagn,
        standard_graph,
        graph,
        users,
        groups,
        session,
        permissions  # noqa: F811
):
    """ Test expiration auditing and notification. """

    assert graph.get_group_details("audited-team")["audited"]

    #
    # Ensure auditors promotion for all approvers
    #
    approver_roles = ["owner", "np-owner", "manager"]

    affected_users = set(
        ["*****@*****.**", "*****@*****.**", "*****@*****.**", "*****@*****.**"])
    for idx, role in enumerate(approver_roles):

        # Add non-auditor as an approver to an audited group
        add_member(groups["audited-team"], users["*****@*****.**"], role=role)
        graph.update_from_db(session)
        assert not affected_users.intersection(get_users(graph, "auditors"))

        # do the promotion logic
        background = BackgroundProcessor(settings, None)
        background.promote_nonauditors(session)

        # Check that the users now added to auditors group
        graph.update_from_db(session)
        assert affected_users.intersection(get_users(
            graph, "auditors")) == affected_users
        unsent_emails = _get_unsent_emails_and_send(session)
        assert any([
            'Subject: Added as member to group "auditors"' in email.body
            and "To: [email protected]" in email.body for email in unsent_emails
        ])
        assert any([
            'Subject: Added as member to group "auditors"' in email.body
            and "To: [email protected]" in email.body for email in unsent_emails
        ])
        assert any([
            'Subject: Added as member to group "auditors"' in email.body
            and "To: [email protected]" in email.body for email in unsent_emails
        ])

        audits = AuditLog.get_entries(session, action="nonauditor_promoted")
        assert len(audits) == len(affected_users) * (idx + 1)

        # reset for next iteration
        revoke_member(groups["audited-team"], users["*****@*****.**"])
        for username in affected_users:
            revoke_member(groups["auditors"], users[username])

    #
    # Ensure nonauditor, nonapprovers in audited groups do not get promoted
    #

    # first, run a promotion to get any other promotion that we don't
    # care about out of the way
    background = BackgroundProcessor(settings, None)
    background.promote_nonauditors(session)

    prev_audit_log_count = len(
        AuditLog.get_entries(session, action="nonauditor_promoted"))

    member_roles = ["member"]
    for idx, role in enumerate(member_roles):

        # Add non-auditor as a non-approver to an audited group
        add_member(groups["audited-team"], users["*****@*****.**"], role=role)

        # do the promotion logic
        background = BackgroundProcessor(settings, None)
        background.promote_nonauditors(session)

        # Check that the user is not added to auditors group
        graph.update_from_db(session)
        assert "*****@*****.**" not in get_users(graph, "auditors")

        assert not any([
            'Subject: Added as member to group "auditors"' in email.body
            and "To: [email protected]" in email.body
            for email in _get_unsent_emails_and_send(session)
        ])

        audits = AuditLog.get_entries(session, action="nonauditor_promoted")
        assert len(audits) == prev_audit_log_count

        revoke_member(groups["audited-team"], users["*****@*****.**"])
Пример #14
0
def test_expire_nonauditors(standard_graph, users, groups, session, permissions):
    """ Test expiration auditing and notification. """

    graph = standard_graph  # noqa

    # Test audit autoexpiration for all approvers

    approver_roles = ["owner", "np-owner", "manager"]

    for role in approver_roles:

        # Add non-auditor as an owner to an audited group
        add_member(groups["audited-team"], users["*****@*****.**"], role=role)
        session.commit()
        graph.update_from_db(session)

        group_md = graph.get_group_details("audited-team")

        assert group_md.get('audited', False)

        # Expire the edges.
        background = BackgroundThread(settings, None)
        background.expire_nonauditors(session)

        # Check that the edges are now marked as inactive.
        edge = session.query(GroupEdge).filter_by(group_id=groups["audited-team"].id, member_pk=users["*****@*****.**"].id).scalar()
        assert edge.expiration is not None
        assert edge.expiration < datetime.utcnow() + timedelta(days=settings.nonauditor_expiration_days)
        assert edge.expiration > datetime.utcnow() + timedelta(days=settings.nonauditor_expiration_days - 1)

        assert any(["Subject: Membership in audited-team set to expire" in email.body and "To: [email protected]" in email.body for email in _get_unsent_emails_and_send(session)])

        audits = AuditLog.get_entries(session, action="nonauditor_flagged")
        assert len(audits) == 3 + 1 * (approver_roles.index(role) + 1)

        revoke_member(groups["audited-team"], users["*****@*****.**"])

    # Ensure nonauditor, nonapprovers in audited groups do not get set to expired

    member_roles = ["member"]

    for role in member_roles:

        # Add non-auditor as an owner to an audited group
        add_member(groups["audited-team"], users["*****@*****.**"], role=role)
        session.commit()
        graph.update_from_db(session)

        group_md = graph.get_group_details("audited-team")

        assert group_md.get('audited', False)

        # Expire the edges.
        background = BackgroundThread(settings, None)
        background.expire_nonauditors(session)

        # Check that the edges are now marked as inactive.
        edge = session.query(GroupEdge).filter_by(group_id=groups["audited-team"].id, member_pk=users["*****@*****.**"].id).scalar()
        assert edge.expiration is None

        assert not any(["Subject: Membership in audited-team set to expire" in email.body and "To: [email protected]" in email.body for email in _get_unsent_emails_and_send(session)])

        audits = AuditLog.get_entries(session, action="nonauditor_flagged")
        assert len(audits) == 3 + 1 * len(approver_roles)

        revoke_member(groups["audited-team"], users["*****@*****.**"])
Пример #15
0
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
    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,
            next(iter(x.group.my_owners())),
            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 = 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"
Пример #16
0
def test_github(session, users, http_client, base_url, mocker):  # noqa: F811
    user = users["*****@*****.**"]
    assert get_user_metadata_by_key(session, user.id,
                                    USER_METADATA_GITHUB_USERNAME_KEY) is None

    user = User.get(session, name=user.username)
    fe_url = url(base_url, "/github/link_begin/{}".format(user.id))
    mocker.patch.object(settings(), "github_app_client_id", "a-client-id")
    resp = yield http_client.fetch(
        fe_url,
        method="GET",
        headers={"X-Grouper-User": user.username},
        follow_redirects=False,
        raise_error=False,
    )
    assert resp.code == 302
    redir_url = urlparse(resp.headers["Location"])
    assert redir_url.netloc == "github.com"
    assert redir_url.path == "/login/oauth/authorize"
    query_params = parse_qs(redir_url.query)
    assert query_params["client_id"] == ["a-client-id"]
    (state, ) = query_params["state"]
    assert "github-link-state={}".format(state) in resp.headers["Set-cookie"]
    assert query_params["redirect_uri"] == [
        "http://127.0.0.1:8888/github/link_complete/{}".format(user.id)
    ]

    fe_url = url(
        base_url, "/github/link_complete/{}?code=tempcode&state={}".format(
            user.id, state))
    with pytest.raises(HTTPError) as excinfo:
        yield http_client.fetch(
            fe_url,
            method="GET",
            headers={
                "X-Grouper-User": user.username,
                "Cookie": "github-link-state=bogus-state"
            },
        )
    assert excinfo.value.code == 400

    recorder = FakeGitHubHttpClient()
    proxy_plugin = PluginProxy([SecretPlugin()])
    mocker.patch("grouper.fe.handlers.github._get_github_http_client",
                 lambda: recorder)
    mocker.patch("grouper.fe.handlers.github.get_plugin_proxy",
                 lambda: proxy_plugin)
    mocker.patch.object(settings(), "http_proxy_host", "proxy-server")
    mocker.patch.object(settings(), "http_proxy_port", 42)
    resp = yield http_client.fetch(
        fe_url,
        method="GET",
        headers={
            "X-Grouper-User": user.username,
            "Cookie": "github-link-state=" + state
        },
    )
    authorize_request, user_request = recorder.requests
    assert authorize_request.proxy_host == "proxy-server"
    assert authorize_request.proxy_port == 42
    assert user_request.proxy_host == "proxy-server"
    assert user_request.proxy_port == 42
    authorize_params = parse_qs(authorize_request.body)
    assert authorize_params[b"code"] == [b"tempcode"]
    assert authorize_params[b"state"] == [state.encode("ascii")]
    assert authorize_params[b"client_id"] == [b"a-client-id"]
    assert authorize_params[b"client_secret"] == [b"client-secret"]
    assert user_request.headers["Authorization"] == "token a-access-token"
    assert (get_user_metadata_by_key(session, user.id,
                                     USER_METADATA_GITHUB_USERNAME_KEY)
            is not None)
    assert (get_user_metadata_by_key(
        session, user.id,
        USER_METADATA_GITHUB_USERNAME_KEY).data_value == "zorkian-on-gh")

    audit_entries = AuditLog.get_entries(session,
                                         on_user_id=user.id,
                                         action="changed_github_username")
    assert len(audit_entries) == 1
    assert audit_entries[
        0].description == "Changed GitHub username: zorkian-on-gh"

    fe_url = url(base_url, "/users/{}/github/clear".format(user.username))
    resp = yield http_client.fetch(fe_url,
                                   method="POST",
                                   headers={"X-Grouper-User": user.username},
                                   body=b"")
    assert resp.code == 200
    assert get_user_metadata_by_key(session, user.id,
                                    USER_METADATA_GITHUB_USERNAME_KEY) is None

    audit_entries = AuditLog.get_entries(session,
                                         on_user_id=user.id,
                                         action="changed_github_username")
    assert len(audit_entries) == 2
    audit_entries.sort(key=operator.attrgetter("id"))
    assert audit_entries[1].description == "Cleared GitHub link"
Пример #17
0
    def my_log_entries(self):

        return AuditLog.get_entries(self.session, on_group_id=self.id, limit=20)
Пример #18
0
def test_expire_nonauditors(standard_graph, users, groups, session, permissions):
    """ Test expiration auditing and notification. """

    graph = standard_graph  # noqa

    # Test audit autoexpiration for all approvers

    approver_roles = ["owner", "np-owner", "manager"]

    for role in approver_roles:

        # Add non-auditor as an owner to an audited group
        add_member(groups["audited-team"], users["*****@*****.**"], role=role)
        session.commit()
        graph.update_from_db(session)

        group_md = graph.get_group_details("audited-team")

        assert group_md.get('audited', False)

        # Expire the edges.
        background = BackgroundProcessor(settings, None)
        background.expire_nonauditors(session)

        # Check that the edges are now marked as inactive.
        edge = session.query(GroupEdge).filter_by(group_id=groups["audited-team"].id, member_pk=users["*****@*****.**"].id).scalar()
        assert edge.expiration is not None
        assert edge.expiration < datetime.utcnow() + timedelta(days=settings.nonauditor_expiration_days)
        assert edge.expiration > datetime.utcnow() + timedelta(days=settings.nonauditor_expiration_days - 1)

        assert any(["Subject: Membership in audited-team set to expire" in email.body and "To: [email protected]" in email.body for email in _get_unsent_emails_and_send(session)])

        audits = AuditLog.get_entries(session, action="nonauditor_flagged")
        assert len(audits) == 3 + 1 * (approver_roles.index(role) + 1)

        revoke_member(groups["audited-team"], users["*****@*****.**"])

    # Ensure nonauditor, nonapprovers in audited groups do not get set to expired

    member_roles = ["member"]

    for role in member_roles:

        # Add non-auditor as an owner to an audited group
        add_member(groups["audited-team"], users["*****@*****.**"], role=role)
        session.commit()
        graph.update_from_db(session)

        group_md = graph.get_group_details("audited-team")

        assert group_md.get('audited', False)

        # Expire the edges.
        background = BackgroundProcessor(settings, None)
        background.expire_nonauditors(session)

        # Check that the edges are now marked as inactive.
        edge = session.query(GroupEdge).filter_by(group_id=groups["audited-team"].id, member_pk=users["*****@*****.**"].id).scalar()
        assert edge.expiration is None

        assert not any(["Subject: Membership in audited-team set to expire" in email.body and "To: [email protected]" in email.body for email in _get_unsent_emails_and_send(session)])

        audits = AuditLog.get_entries(session, action="nonauditor_flagged")
        assert len(audits) == 3 + 1 * len(approver_roles)

        revoke_member(groups["audited-team"], users["*****@*****.**"])
Пример #19
0
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"
Пример #20
0
def test_audit_end_to_end(session, users, groups, http_client, base_url,
                          graph):  # 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["*****@*****.**"])

    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
    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'