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
def test_grant_permission_to_tag(users, http_client, base_url, session): # noqa: F811 user = session.query(User).filter_by(username="******").scalar() perm = create_permission(session, TAG_EDIT) session.commit() grant_permission( session.query(Group).filter_by(groupname="all-teams").scalar(), get_permission(session, TAG_EDIT), "*", ) fe_url = url(base_url, "/tags") resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"tagname": "tyler_was_here", "description": "Test Tag Please Ignore"}), headers={"X-Grouper-User": user.username}, ) tag = PublicKeyTag.get(session, name="tyler_was_here") user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/permissions/grant_tag/{}".format(tag.name)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"permission": TAG_EDIT, "argument": "*"}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 tag = PublicKeyTag.get(session, name="tyler_was_here") perm = get_permission(session, TAG_EDIT) assert ( len(get_public_key_tag_permissions(session, tag)) == 1 ), "The tag should have exactly 1 permission" assert ( get_public_key_tag_permissions(session, tag)[0].name == perm.name ), "The tag's permission should be the one we added" assert ( get_public_key_tag_permissions(session, tag)[0].argument == "*" ), "The tag's permission should be the one we added" # Make sure trying to add a permission to a tag doesn't fail horribly if it's already there user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/permissions/grant_tag/{}".format(tag.name)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"permission": TAG_EDIT, "argument": "*"}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200
def test_revoke_permission_from_tag(users, http_client, base_url, session): # noqa: F811 user = session.query(User).filter_by(username="******").scalar() create_permission(session, TAG_EDIT) session.commit() grant_permission( session.query(Group).filter_by(groupname="all-teams").scalar(), get_permission(session, TAG_EDIT), "*", ) fe_url = url(base_url, "/tags") resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"tagname": "tyler_was_here", "description": "Test Tag Please Ignore"}), headers={"X-Grouper-User": user.username}, ) tag = PublicKeyTag.get(session, name="tyler_was_here") user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/permissions/grant_tag/{}".format(tag.name)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"permission": TAG_EDIT, "argument": "*"}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 tag = PublicKeyTag.get(session, name="tyler_was_here") get_permission(session, TAG_EDIT) assert ( len(get_public_key_tag_permissions(session, tag)) == 1 ), "The tag should have exactly 1 permission" user = session.query(User).filter_by(username="******").scalar() mapping = get_public_key_tag_permissions(session, tag)[0] fe_url = url(base_url, "/permissions/{}/revoke_tag/{}".format(TAG_EDIT, mapping.mapping_id)) resp = yield http_client.fetch( fe_url, method="POST", body="", headers={"X-Grouper-User": user.username} ) assert resp.code == 200 tag = PublicKeyTag.get(session, name="tyler_was_here") assert ( len(get_public_key_tag_permissions(session, tag)) == 0 ), "The tag should have no permissions"
def test_basic_request(graph, groups, permissions, session, standard_graph, users): # noqa: F811 group_sre = groups["team-sre"] group_not_sre = [g for name, g in iteritems(groups) if name != "team-sre"] assert not any( [ get_requests_by_group(session, group, status="pending").all() for group in itervalues(groups) ] ), "no group should start with pending requests" group_sre.add_member(users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz") session.commit() request_not_sre = [ get_requests_by_group(session, group, status="pending").all() for group in group_not_sre ] assert not any(request_not_sre), "only affected group should show pending requests" request_sre = get_requests_by_group(session, group_sre, status="pending").all() assert len(request_sre) == 1, "affected group should have request" request = session.query(Request).filter_by(id=request_sre[0].id).scalar() request.update_status(users["*****@*****.**"], "actioned", "for being a good person") session.commit() assert not any( [ get_requests_by_group(session, group, status="pending").all() for group in itervalues(groups) ] ), "no group should have requests after being actioned"
def test_request_emails_reference( session, groups, permissions, users, base_url, http_client # noqa: F811 ): tech = groups["tech-ops"] tech.canjoin = "canask" tech.add(session) session.commit() # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/groups/{}/join".format(tech.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({ "reason": "Test Request Please Ignore", "member": "User: {}".format(user.name) }), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 zay_emails = _get_unsent_and_mark_as_sent_emails_with_username( session, "*****@*****.**") assert any(["References: " in email.body for email in zay_emails])
def test_basic_request(graph, groups, permissions, session, standard_graph, users): # noqa: F811 group_sre = groups["team-sre"] group_not_sre = [g for name, g in groups.items() if name != "team-sre"] assert not any([ get_requests_by_group(session, group, status="pending").all() for group in groups.values() if not is_role_user(session, group=group) ]), "no group should start with pending requests" group_sre.add_member(users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz") session.commit() request_not_sre = [ get_requests_by_group(session, group, status="pending").all() for group in group_not_sre ] assert not any( request_not_sre), "only affected group should show pending requests" request_sre = get_requests_by_group(session, group_sre, status="pending").all() assert len(request_sre) == 1, "affected group should have request" request = session.query(Request).filter_by(id=request_sre[0].id).scalar() request.update_status(users["*****@*****.**"], "actioned", "for being a good person") session.commit() assert not any([ get_requests_by_group(session, group, status="pending").all() for group in groups.values() ]), "no group should have requests after being actioned"
def _get_unsent_emails_and_send(session): # noqa: F811 """Helper to count unsent emails and then mark them as sent.""" emails = session.query(AsyncNotification).filter_by(sent=False).all() for email in emails: email.sent = True session.commit() return emails
def _get_unsent_and_mark_as_sent_emails_with_username(session, username): # noqa: F811 """Helper to count unsent emails and then mark them as sent.""" emails = session.query(AsyncNotification).filter_by(sent=False, email=username).all() for email in emails: email.sent = True session.commit() return emails
def test_edit_tag(users, http_client, base_url, session): # noqa: F811 user = session.query(User).filter_by(username="******").scalar() create_permission(session, TAG_EDIT) session.commit() grant_permission( session.query(Group).filter_by(groupname="all-teams").scalar(), get_permission(session, TAG_EDIT), "*", ) fe_url = url(base_url, "/tags") resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({ "tagname": "tyler_was_here", "description": "Test Tag Please Ignore" }), headers={"X-Grouper-User": user.username}, ) tag = PublicKeyTag.get(session, name="tyler_was_here") assert (tag.description == "Test Tag Please Ignore" ), "The description should match what we created it with" user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/tags/{}/edit".format(tag.id)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"description": "Don't tag me bro"}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 tag = PublicKeyTag.get(session, name="tyler_was_here") assert tag.description == "Don't tag me bro", "The description should have been updated"
def do_action_requests(session, permissions, users, do_request_perms): # noqa: F811 # Action (approve) the request for PERM_WITH_GRANTER, and # cancel (deny) the request for PERM_NO_GRANTER. all_requests = session.query(PermissionRequest) for request in all_requests: if request.status == "pending" and request.permission.name == PERM_WITH_GRANTER: update_request(session, request, users[GRANTING_USER], "actioned", REASON) if request.status == "pending" and request.permission.name == PERM_NO_GRANTER: update_request(session, request, users[ADMIN_USER], "cancelled", REASON) session.commit()
def test_create_tag(users, http_client, base_url, session): # noqa: F811 user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/tags") resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"tagname": "tyler_was_here", "description": "Test Tag Please Ignore"}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 tag = PublicKeyTag.get(session, name="tyler_was_here") assert tag is not None, "The tag should be created" assert tag.name == "tyler_was_here", "The tag's name should be tyler_was_here"
def test_new_user_login(client, mocker, session): # noqa mocker.patch('rr.queries.user_by_fb_id', side_effect=no_existing_user) requests_get_mock = mocker.patch('requests.get', side_effect=MockResponse( 200, graph_me_with_friends)) data = {'timezone': 'US/Pacific', 'access_token': '123'} res = client.post(flask.url_for('auth.login'), data=json.dumps(data), headers={'Content-Type': 'application/json'}) url = ('https://graph.facebook.com/me?fields=id,name,picture,' 'friends&access_token={}').format(data['access_token']) requests_get_mock.assert_called_with(url) u = session.query(User).one() # login # FIXME # assert flask.session.get('user_id') == str(u.id) # request succeeded assert res.status_code == 200
def test_existing_user_login(client, session, mocker): # noqa existing, friend_one, friend_two = seed_existing_users() session.add_all([existing, friend_one, friend_two]) session.commit() assert existing.all_friends == [] mocker.patch('requests.get', MockResponse(200, graph_me_with_friends)) mocker.patch('rr.queries.user_by_fb_id', no_existing_user) data = {'timezone': 'US/Pacific', 'access_token': '123'} res = client.post(flask.url_for('auth.login'), data=json.dumps(data), headers={'Content-Type': 'application/json'}) # no new users created assert session.query(User).count() == 3 # fb access token updated assert existing.fb_access_token == '123' # friends updated assert set(existing.friends) == set([friend_one, friend_two])
def test_request_emails_reference( session, groups, permissions, users, base_url, http_client # noqa: F811 ): tech = groups["tech-ops"] tech.canjoin = "canask" tech.add(session) session.commit() # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/groups/{}/join".format(tech.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( {"reason": "Test Request Please Ignore", "member": "User: {}".format(user.name)} ), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 zay_emails = _get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**") assert any(["References: " in email.body for email in zay_emails])
def test_request_emails( graph, groups, permissions, session, standard_graph, users, base_url, http_client # noqa: F811 ): tech = groups["tech-ops"] tech.canjoin = "canask" tech.add(session) session.commit() # REQUEST 1 before_reqs = session.query(Request).count() # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/groups/{}/join".format(tech.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( {"reason": "Test Request Please Ignore", "member": "User: {}".format(user.name)} ), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 zaya_emails = len(_get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**")) fh_emails = len(_get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**")) assert ( zaya_emails + fh_emails == 2 ), "Only approvers for the requested group should receive an email" assert zaya_emails == 1, "Owners should receive exactly one email per canask request" assert fh_emails == 1, "NP-Owners should receive exactly one email per canask request" assert ( session.query(Request).count() == before_reqs + 1 ), "There should only be one added request" # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() request_id = ( session.query(Request).filter_by(requesting_id=tech.id, requester_id=user.id).scalar().id ) fe_url = url(base_url, "/groups/{}/requests/{}".format(tech.groupname, request_id)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"reason": "Test Response Please Ignore", "status": "actioned"}), headers={"X-Grouper-User": "******"}, ) assert resp.code == 200 fh_emails = len(_get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**")) testuser_emails = len( _get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**") ) assert ( fh_emails + testuser_emails == 2 ), "Only the approver that didn't action the request and the reqester should get an email" assert fh_emails == 1, "NP-owners that did not action the request should receive an email" assert ( testuser_emails == 1 ), "The requester should receive an email when the request is handled" # REQUEST 2 before_reqs = session.query(Request).count() # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/groups/{}/join".format(tech.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( {"reason": "Test Request Please Ignore 2", "member": "User: {}".format(user.name)} ), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 zaya_emails = len(_get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**")) fh_emails = len(_get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**")) assert ( zaya_emails + fh_emails == 2 ), "Only approvers for the requested group should receive an email" assert zaya_emails == 1, "Owners should receive exactly one email per canask request" assert fh_emails == 1, "NP-Owners should receive exactly one email per canask request" assert ( session.query(Request).count() == before_reqs + 1 ), "There should only be one added request" # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() request_id = ( session.query(Request).filter_by(requesting_id=tech.id, requester_id=user.id).scalar().id ) fe_url = url(base_url, "/groups/{}/requests/{}".format(tech.groupname, request_id)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"reason": "Test Response Please Ignore 2", "status": "actioned"}), headers={"X-Grouper-User": "******"}, ) assert resp.code == 200 zaya_emails = len(_get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**")) oliver_emails = len(_get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**")) assert ( zaya_emails + oliver_emails == 2 ), "Only the approver that didn't action the request and the reqester should get an email" assert zaya_emails == 1, "NP-owners that did not action the request should receive an email" assert oliver_emails == 1, "The requester should receive an email when the request is handled"
def test_aggregate_request( graph, groups, permissions, session, standard_graph, users # noqa: F811 ): gary = users["*****@*****.**"] not_involved = [ user for name, user in users.items() if name not in ("*****@*****.**", "*****@*****.**") ] assert not any([ user_requests_aggregate(session, u).all() for u in users.values() ]), "should have no pending requests to begin with" # one request to one team groups["team-sre"].add_member(users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz") session.commit() assert len(user_requests_aggregate( session, gary).all()) == 1, "one pending request for owner" assert not any( [user_requests_aggregate(session, u).all() for u in not_involved]), "no pending requests if you're not the owner" # two request to two teams, same owner groups["team-infra"].add_member(users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz") session.commit() request_gary = user_requests_aggregate(session, gary).all() assert len(request_gary) == 2, "two pending request for owner" assert not any( [user_requests_aggregate(session, u).all() for u in not_involved]), "no pending requests if you're not the owner" # resolving one request should reflect request = session.query(Request).filter_by(id=request_gary[0].id).scalar() request.update_status(users["*****@*****.**"], "actioned", "for being a good person") session.commit() assert len(user_requests_aggregate( session, gary).all()) == 1, "one pending request for owner" assert not any( [user_requests_aggregate(session, u).all() for u in not_involved]), "no pending requests if you're not the owner" # requests to dependent teams should reflect apprpriately groups["security-team"].add_member(users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz") session.commit() assert (len(user_requests_aggregate( session, gary).all()) == 1), "super owner should not get request" assert (len(user_requests_aggregate( session, users["*****@*****.**"]).all()) == 1), "owner should get request" user_not_gary_oliver = [ u for n, u in users.items() if n not in ("*****@*****.**", "*****@*****.**") ] assert not any([ user_requests_aggregate(session, u).all() for u in user_not_gary_oliver ]) # manager and np-owner should get requests figurehead = users["*****@*****.**"] add_member(groups["audited-team"], figurehead, role="manager") assert (len(user_requests_aggregate( session, figurehead).all()) == 0), "no request for np-owner at first" groups["tech-ops"].add_member(users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz") assert len(user_requests_aggregate( session, figurehead).all()) == 1, "request for np-owner" groups["audited-team"].add_member(users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz") assert (len(user_requests_aggregate( session, figurehead).all()) == 2), "request for np-owner and manager"
def test_mysql_to_sqlite(session): Base.metadata.create_all(bind=session.bind) foo = Foo(foo=1) session.add(foo) session.commit() assert [(1, )] == session.query(Foo.foo).all()
def test_mysql_to_sqlite(session): Base.metadata.create_all(bind=session.bind) foo = Foo(foo=1) session.add(foo) session.commit() assert [(1,)] == session.query(Foo.foo).all()
def test_add_tag(users, http_client, base_url, session): # noqa: F811 user = session.query(User).filter_by(username="******").scalar() # add SSH key fe_url = url(base_url, "/users/{}/public-key/add".format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"public_key": SSH_KEY_1}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 key = session.query(PublicKey).filter_by(user_id=user.id).scalar() # add SSH key fe_url = url(base_url, "/users/{}/public-key/add".format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"public_key": SSH_KEY_2}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 key2 = session.query(PublicKey).filter_by(public_key=SSH_KEY_2).scalar() fe_url = url(base_url, "/tags") resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"tagname": "tyler_was_here", "description": "Test Tag Please Ignore"}), headers={"X-Grouper-User": user.username}, ) PublicKeyTag.get(session, name="tyler_was_here") key = session.query(PublicKey).filter_by(public_key=SSH_KEY_1).scalar() assert ( get_public_key_tags(session, key) == [] ), "No public keys should have a tag unless it's been added to the key" fe_url = url(base_url, "/tags") resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"tagname": "dont_tag_me_bro", "description": "Test Tag Please Ignore"}), headers={"X-Grouper-User": user.username}, ) PublicKeyTag.get(session, name="dont_tag_me_bro") key = session.query(PublicKey).filter_by(public_key=SSH_KEY_1).scalar() assert ( get_public_key_tags(session, key) == [] ), "No public keys should have a tag unless it's been added to the key" fe_url = url(base_url, "/users/{}/public-key/{}/tag".format(user.username, key.id)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"tagname": "tyler_was_here"}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 key = session.query(PublicKey).filter_by(public_key=SSH_KEY_1).scalar() assert len(get_public_key_tags(session, key)) == 1, "The key should have exactly 1 tag" assert get_public_key_tags(session, key)[0].name == "tyler_was_here" key2 = session.query(PublicKey).filter_by(public_key=SSH_KEY_2).scalar() assert ( len(get_public_key_tags(session, key2)) == 0 ), "Keys other than the one with the added tag should not gain tags" # Non-admin and not user adding tag should fail fe_url = url(base_url, "/users/{}/public-key/{}/tag".format(user.username, key.id)) with pytest.raises(HTTPError): resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"tagname": "tyler_was_here"}), headers={"X-Grouper-User": "******"}, ) key = session.query(PublicKey).filter_by(public_key=SSH_KEY_1).scalar() assert len(get_public_key_tags(session, key)) == 1, "The key should have exactly 1 tag" assert get_public_key_tags(session, key)[0].name == "tyler_was_here" # User admins test fe_url = url(base_url, "/users/{}/public-key/{}/tag".format(user.username, key.id)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"tagname": "dont_tag_me_bro"}), headers={"X-Grouper-User": "******"}, ) assert resp.code == 200 key = session.query(PublicKey).filter_by(public_key=SSH_KEY_1).scalar() assert len(get_public_key_tags(session, key)) == 2, "The key should have 2 tags now" assert set([x.name for x in get_public_key_tags(session, key)]) == set( ["tyler_was_here", "dont_tag_me_bro"] )
def test_permissions(users, http_client, base_url, session): # noqa: F811 user = session.query(User).filter_by(username="******").scalar() create_permission(session, TAG_EDIT) session.commit() create_permission(session, "it.literally.does.not.matter") session.commit() grant_permission( session.query(Group).filter_by(groupname="all-teams").scalar(), get_permission(session, TAG_EDIT), "*", ) grant_permission( session.query(Group).filter_by(groupname="all-teams").scalar(), get_permission(session, "it.literally.does.not.matter"), "*", ) fe_url = url(base_url, "/tags") yield http_client.fetch( fe_url, method="POST", body=urlencode({"tagname": "tyler_was_here", "description": "Test Tag Please Ignore"}), headers={"X-Grouper-User": user.username}, ) tag = PublicKeyTag.get(session, name="tyler_was_here") user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/permissions/grant_tag/{}".format(tag.name)) yield http_client.fetch( fe_url, method="POST", body=urlencode({"permission": TAG_EDIT, "argument": "prod"}), headers={"X-Grouper-User": user.username}, ) user = session.query(User).filter_by(username="******").scalar() # add SSH key fe_url = url(base_url, "/users/{}/public-key/add".format(user.username)) yield http_client.fetch( fe_url, method="POST", body=urlencode({"public_key": SSH_KEY_1}), headers={"X-Grouper-User": user.username}, ) key = session.query(PublicKey).filter_by(user_id=user.id).scalar() user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/users/{}/public-key/{}/tag".format(user.username, key.id)) yield http_client.fetch( fe_url, method="POST", body=urlencode({"tagname": "tyler_was_here"}), headers={"X-Grouper-User": user.username}, ) user = session.query(User).filter_by(username="******").scalar() key = session.query(PublicKey).filter_by(user_id=user.id).scalar() assert ( len(get_public_key_permissions(session, key)) == 1 ), "The SSH Key should have only 1 permission" assert ( get_public_key_permissions(session, key)[0].name == TAG_EDIT ), "The SSH key's permission should be TAG_EDIT" assert ( get_public_key_permissions(session, key)[0].argument == "prod" ), "The SSH key's permission argument should be restricted to the tag's argument" assert len(user_permissions(session, user)) > 1, "The user should have more than 1 permission"
def test_tags(session, http_client, base_url, graph): # noqa: F811 perm = create_permission(session, TAG_EDIT) session.commit() create_permission(session, "it.literally.does.not.matter") session.commit() grant_permission( session.query(Group).filter_by(groupname="all-teams").scalar(), get_permission(session, TAG_EDIT), "*", ) grant_permission( session.query(Group).filter_by(groupname="all-teams").scalar(), get_permission(session, "it.literally.does.not.matter"), "*", ) tag = PublicKeyTag(name="tyler_was_here") tag.add(session) session.commit() tag = PublicKeyTag.get(session, name="tyler_was_here") grant_permission_to_tag(session, tag.id, perm.id, "prod") with pytest.raises(AssertionError): grant_permission_to_tag(session, tag.id, perm.id, "question?") user = session.query(User).filter_by(username="******").scalar() add_public_key(session, user, SSH_KEY_1) key = session.query(PublicKey).filter_by(user_id=user.id).scalar() add_tag_to_public_key(session, key, tag) user = session.query(User).filter_by(username="******").scalar() key = session.query(PublicKey).filter_by(user_id=user.id).scalar() assert ( len(get_public_key_permissions(session, key)) == 1 ), "The SSH Key should have only 1 permission" assert ( get_public_key_permissions(session, key)[0].name == TAG_EDIT ), "The SSH key's permission should be TAG_EDIT" assert ( get_public_key_permissions(session, key)[0].argument == "prod" ), "The SSH key's permission argument should be restricted to the tag's argument" assert len(user_permissions(session, user)) > 1, "The user should have more than 1 permission" graph.update_from_db(session) fe_url = url(base_url, "/users/{}".format(user.username)) resp = yield http_client.fetch(fe_url) assert resp.code == 200 body = json.loads(resp.body) pub_key = body["data"]["user"]["public_keys"][0] assert len(pub_key["tags"]) == 1, "The public key should only have 1 tag" assert pub_key["fingerprint"] == "e9:ae:c5:8f:39:9b:3a:9c:6a:b8:33:6b:cb:6f:ba:35" assert pub_key["fingerprint_sha256"] == "MP9uWaujW96EWxbjDtPdPWheoMDu6BZ8FZj0+CBkVWU" assert pub_key["tags"][0] == "tyler_was_here", "The public key should have the tag we gave it"
def test_remove_tag(users, http_client, base_url, session): # noqa: F811 user = session.query(User).filter_by(username="******").scalar() # add SSH key fe_url = url(base_url, "/users/{}/public-key/add".format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"public_key": SSH_KEY_1}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 key = session.query(PublicKey).filter_by(user_id=user.id).scalar() # add SSH key fe_url = url(base_url, "/users/{}/public-key/add".format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"public_key": SSH_KEY_2}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 key2 = session.query(PublicKey).filter_by(public_key=SSH_KEY_2).scalar() fe_url = url(base_url, "/tags") resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"tagname": "tyler_was_here", "description": "Test Tag Please Ignore"}), headers={"X-Grouper-User": user.username}, ) tag = PublicKeyTag.get(session, name="tyler_was_here") key = session.query(PublicKey).filter_by(public_key=SSH_KEY_1).scalar() assert ( get_public_key_tags(session, key) == [] ), "No public keys should have a tag unless it's been added to the key" fe_url = url(base_url, "/tags") resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"tagname": "dont_tag_me_bro", "description": "Test Tag Please Ignore"}), headers={"X-Grouper-User": user.username}, ) PublicKeyTag.get(session, name="dont_tag_me_bro") key = session.query(PublicKey).filter_by(public_key=SSH_KEY_1).scalar() assert ( get_public_key_tags(session, key) == [] ), "No public keys should have a tag unless it's been added to the key" fe_url = url(base_url, "/users/{}/public-key/{}/tag".format(user.username, key.id)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"tagname": "tyler_was_here"}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 key = session.query(PublicKey).filter_by(public_key=SSH_KEY_1).scalar() assert len(get_public_key_tags(session, key)) == 1, "The key should have exactly 1 tag" assert get_public_key_tags(session, key)[0].name == "tyler_was_here" key2 = session.query(PublicKey).filter_by(public_key=SSH_KEY_2).scalar() assert ( len(get_public_key_tags(session, key2)) == 0 ), "Keys other than the one with the added tag should not gain tags" fe_url = url(base_url, "/users/{}/public-key/{}/tag".format(user.username, key2.id)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"tagname": "tyler_was_here"}), headers={"X-Grouper-User": user.username}, ) key = session.query(PublicKey).filter_by(public_key=SSH_KEY_1).scalar() # Fail Remove tag tag = PublicKeyTag.get(session, name="dont_tag_me_bro") fe_url = url( base_url, "/users/{}/public-key/{}/delete_tag/{}".format(user.username, key.id, tag.id) ) with pytest.raises(HTTPError): resp = yield http_client.fetch( fe_url, method="POST", body="", headers={"X-Grouper-User": "******"} ) # Remove tag that isn't on key: should fail silently tag = PublicKeyTag.get(session, name="dont_tag_me_bro") fe_url = url( base_url, "/users/{}/public-key/{}/delete_tag/{}".format(user.username, key.id, tag.id) ) resp = yield http_client.fetch( fe_url, method="POST", body="", headers={"X-Grouper-User": user.username} ) assert resp.code == 200 # Remove tag tag = PublicKeyTag.get(session, name="tyler_was_here") fe_url = url( base_url, "/users/{}/public-key/{}/delete_tag/{}".format(user.username, key.id, tag.id) ) resp = yield http_client.fetch( fe_url, method="POST", body="", headers={"X-Grouper-User": user.username} ) assert resp.code == 200 key = session.query(PublicKey).filter_by(public_key=SSH_KEY_1).scalar() assert len(get_public_key_tags(session, key)) == 0, "The key should have exactly 0 tags" key2 = session.query(PublicKey).filter_by(public_key=SSH_KEY_2).scalar() assert ( len(get_public_key_tags(session, key2)) == 1 ), "Removing a tag from one key should not affect other keys" # User admin remove tag # readd tag fe_url = url(base_url, "/users/{}/public-key/{}/tag".format(user.username, key.id)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"tagname": "tyler_was_here"}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 key = session.query(PublicKey).filter_by(public_key=SSH_KEY_1).scalar() assert len(get_public_key_tags(session, key)) == 1, "The key should have exactly 1 tag" assert get_public_key_tags(session, key)[0].name == "tyler_was_here" # Nonuser admin fail Remove tag tag = PublicKeyTag.get(session, name="tyler_was_here") fe_url = url( base_url, "/users/{}/public-key/{}/delete_tag/{}".format(user.username, key.id, tag.id) ) with pytest.raises(HTTPError): resp = yield http_client.fetch( fe_url, method="POST", body="", headers={"X-Grouper-User": "******"} ) key = session.query(PublicKey).filter_by(public_key=SSH_KEY_1).scalar() assert len(get_public_key_tags(session, key)) == 1, "The key should have exactly 1 tags" # Remove tag tag = PublicKeyTag.get(session, name="tyler_was_here") fe_url = url( base_url, "/users/{}/public-key/{}/delete_tag/{}".format(user.username, key.id, tag.id) ) resp = yield http_client.fetch( fe_url, method="POST", body="", headers={"X-Grouper-User": "******"} ) assert resp.code == 200 key = session.query(PublicKey).filter_by(public_key=SSH_KEY_1).scalar() assert len(get_public_key_tags(session, key)) == 0, "The key should have exactly 0 tags"
def test_grant_and_revoke( session, standard_graph, graph, groups, permissions, http_client, base_url # noqa: F811 ): """Test that permission grant and revokes are reflected correctly.""" group_name = "team-sre" permission_name = "sudo" user_name = "*****@*****.**" def _check_graph_for_perm(graph): # type: (GroupGraph) -> bool return any([ g["permission"] == permission_name and g["distance"] == 0 for g in graph.get_group_details(group_name)["permissions"] ]) # make some permission admins grant_permission(groups["security-team"], permissions[PERMISSION_ADMIN]) # grant attempt by non-permission admin fe_url = url(base_url, "/permissions/grant/{}".format(group_name)) with pytest.raises(HTTPError): yield http_client.fetch( fe_url, method="POST", body=urlencode({ "permission": permission_name, "argument": "specific_arg" }), headers={"X-Grouper-User": "******"}, ) graph.update_from_db(session) assert not _check_graph_for_perm(graph), "no permissions granted" # grant by permission admin resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({ "permission": permission_name, "argument": "specific_arg" }), headers={"X-Grouper-User": user_name}, ) assert resp.code == 200 graph.update_from_db(session) assert _check_graph_for_perm(graph), "permissions granted, successfully" # figure out mapping_id of grant permission_id = get_permission(session, permission_name).id group_id = Group.get(session, name=group_name).id mapping = (session.query(PermissionMap).filter( PermissionMap.permission_id == permission_id, PermissionMap.group_id == group_id).first()) # revoke permission by non-admin fe_url = url( base_url, "/permissions/{}/revoke/{}".format(permission_name, mapping.id)) with pytest.raises(HTTPError): yield http_client.fetch(fe_url, method="POST", body=urlencode({}), headers={"X-Grouper-User": "******"}) graph.update_from_db(session) assert _check_graph_for_perm(graph), "permissions not revoked" # revoke permission for realz resp = yield http_client.fetch(fe_url, method="POST", body=urlencode({}), headers={"X-Grouper-User": user_name}) assert resp.code == 200 graph.update_from_db(session) assert not _check_graph_for_perm(graph), "permissions revoked successfully"
def test_grant_and_revoke( session, standard_graph, graph, groups, permissions, http_client, base_url # noqa: F811 ): """Test that permission grant and revokes are reflected correctly.""" group_name = "team-sre" permission_name = "sudo" user_name = "*****@*****.**" def _check_graph_for_perm(graph): # type: (GroupGraph) -> bool return any( [ g["permission"] == permission_name and g["distance"] == 0 for g in graph.get_group_details(group_name)["permissions"] ] ) # make some permission admins grant_permission(groups["security-team"], permissions[PERMISSION_ADMIN]) # grant attempt by non-permission admin fe_url = url(base_url, "/permissions/grant/{}".format(group_name)) with pytest.raises(HTTPError): yield http_client.fetch( fe_url, method="POST", body=urlencode({"permission": permission_name, "argument": "specific_arg"}), headers={"X-Grouper-User": "******"}, ) graph.update_from_db(session) assert not _check_graph_for_perm(graph), "no permissions granted" # grant by permission admin resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"permission": permission_name, "argument": "specific_arg"}), headers={"X-Grouper-User": user_name}, ) assert resp.code == 200 graph.update_from_db(session) assert _check_graph_for_perm(graph), "permissions granted, successfully" # figure out mapping_id of grant permission_id = get_permission(session, permission_name).id group_id = Group.get(session, name=group_name).id mapping = ( session.query(PermissionMap) .filter(PermissionMap.permission_id == permission_id, PermissionMap.group_id == group_id) .first() ) # revoke permission by non-admin fe_url = url(base_url, "/permissions/{}/revoke/{}".format(permission_name, mapping.id)) with pytest.raises(HTTPError): yield http_client.fetch( fe_url, method="POST", body=urlencode({}), headers={"X-Grouper-User": "******"} ) graph.update_from_db(session) assert _check_graph_for_perm(graph), "permissions not revoked" # revoke permission for realz resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({}), headers={"X-Grouper-User": user_name} ) assert resp.code == 200 graph.update_from_db(session) assert not _check_graph_for_perm(graph), "permissions revoked successfully"
def test_aggregate_request( graph, groups, permissions, session, standard_graph, users # noqa: F811 ): gary = users["*****@*****.**"] not_involved = [ user for name, user in iteritems(users) if name not in ("*****@*****.**", "*****@*****.**") ] assert not any( [user_requests_aggregate(session, u).all() for u in itervalues(users)] ), "should have no pending requests to begin with" # one request to one team groups["team-sre"].add_member( users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz" ) session.commit() assert len(user_requests_aggregate(session, gary).all()) == 1, "one pending request for owner" assert not any( [user_requests_aggregate(session, u).all() for u in not_involved] ), "no pending requests if you're not the owner" # two request to two teams, same owner groups["team-infra"].add_member( users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz" ) session.commit() request_gary = user_requests_aggregate(session, gary).all() assert len(request_gary) == 2, "two pending request for owner" assert not any( [user_requests_aggregate(session, u).all() for u in not_involved] ), "no pending requests if you're not the owner" # resolving one request should reflect request = session.query(Request).filter_by(id=request_gary[0].id).scalar() request.update_status(users["*****@*****.**"], "actioned", "for being a good person") session.commit() assert len(user_requests_aggregate(session, gary).all()) == 1, "one pending request for owner" assert not any( [user_requests_aggregate(session, u).all() for u in not_involved] ), "no pending requests if you're not the owner" # requests to dependent teams should reflect apprpriately groups["security-team"].add_member( users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz" ) session.commit() assert ( len(user_requests_aggregate(session, gary).all()) == 1 ), "super owner should not get request" assert ( len(user_requests_aggregate(session, users["*****@*****.**"]).all()) == 1 ), "owner should get request" user_not_gary_oliver = [ u for n, u in iteritems(users) if n not in ("*****@*****.**", "*****@*****.**") ] assert not any([user_requests_aggregate(session, u).all() for u in user_not_gary_oliver]) # manager and np-owner should get requests figurehead = users["*****@*****.**"] add_member(groups["audited-team"], figurehead, role="manager") assert ( len(user_requests_aggregate(session, figurehead).all()) == 0 ), "no request for np-owner at first" groups["tech-ops"].add_member( users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz" ) assert len(user_requests_aggregate(session, figurehead).all()) == 1, "request for np-owner" groups["audited-team"].add_member( users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz" ) assert ( len(user_requests_aggregate(session, figurehead).all()) == 2 ), "request for np-owner and manager"
def test_request_autoexpiration( graph, groups, permissions, session, standard_graph, users, base_url, http_client # noqa: F811 ): tech = groups["tech-ops"] sre = groups["team-sre"] security = groups["security-team"] sad = groups["sad-team"] infra = groups["team-infra"] tech.canjoin = "canask" tech.auto_expire = timedelta(days=5) tech.add(session) session.commit() sre.canjoin = "canjoin" sre.auto_expire = timedelta(days=500) sre.add(session) session.commit() security.canjoin = "canjoin" security.add(session) session.commit() sad.canjoin = "canjoin" sad.add(session) session.commit() infra.canjoin = "canjoin" infra.add(session) session.commit() # REQUEST 1 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() tech = session.query(Group).filter_by(groupname="tech-ops").scalar() fe_url = url(base_url, "/groups/{}/join".format(tech.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( {"reason": "Test Request Please Ignore", "member": "User: {}".format(user.name)} ), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() request = ( session.query(Request).filter_by(requesting_id=tech.id, requester_id=user.id).scalar() ) assert datetime.strptime(request.changes["expiration"], "%m/%d/%Y").date() == ( datetime.utcnow().date() + tech.auto_expire ), "Request expirations should be the current date + group.auto_expire for canask groups" # REQUEST 2 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() sre = session.query(Group).filter_by(groupname="team-sre").scalar() fe_url = url(base_url, "/groups/{}/join".format(sre.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( {"reason": "Test Request Please Ignore", "member": "User: {}".format(user.name)} ), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() request = session.query(Request).filter_by(requesting_id=sre.id, requester_id=user.id).scalar() assert datetime.strptime(request.changes["expiration"], "%m/%d/%Y").date() == ( datetime.utcnow().date() + sre.auto_expire ), "Request expirations should be the current date + group.auto_expire for canjoin groups" # REQUEST 3 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() security = session.query(Group).filter_by(groupname="security-team").scalar() fe_url = url(base_url, "/groups/{}/join".format(security.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( {"reason": "Test Request Please Ignore", "member": "User: {}".format(user.name)} ), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() request = ( session.query(Request).filter_by(requesting_id=security.id, requester_id=user.id).scalar() ) assert "expiration" not in request.changes, ( "The request should not have an expiration if none is provided and there is no" " auto_expiration" ) # REQUEST 4 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() sad = session.query(Group).filter_by(groupname="sad-team").scalar() fe_url = url(base_url, "/groups/{}/join".format(sad.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( { "reason": "Test Request Please Ignore", "member": "User: {}".format(user.name), "expiration": "01/19/2038", } ), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() request = session.query(Request).filter_by(requesting_id=sad.id, requester_id=user.id).scalar() assert datetime.strptime(request.changes["expiration"], "%m/%d/%Y").date() == date( year=2038, month=1, day=19 ), "User provided expiration times should not be overwritten by the auto_expiration" # REQUEST 5 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() infra = session.query(Group).filter_by(groupname="team-infra").scalar() fe_url = url(base_url, "/groups/{}/add".format(infra.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( {"reason": "Test Request Please Ignore", "member": "User: {}".format(user.name)} ), headers={"X-Grouper-User": "******"}, ) assert resp.code == 200 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() request = ( session.query(Request).filter_by(requesting_id=infra.id, requester_id=user.id).scalar() ) assert "expiration" not in request.changes, ( "The request should not have an expiration if none is provided and the request was" " created by adding a member" ) # REQUEST 6 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() sre = session.query(Group).filter_by(groupname="team-sre").scalar() fe_url = url(base_url, "/groups/{}/edit/user/{}".format(sre.groupname, user.name)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( { "reason": "Test Request Please Ignore", "member": "User: {}".format(user.name), "role": "member", "expiration": "", } ), headers={"X-Grouper-User": "******"}, ) assert resp.code == 200 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() group_edge = session.query(GroupEdge).filter_by(group_id=sre.id, member_pk=user.id).scalar() assert group_edge.expiration is None, ( "The request should not have an expiration if none is provided and the user was edited" " by an approver" )
def test_fe_password_add(session, users, http_client, base_url): # noqa: F811 user = users["*****@*****.**"] fe_url = url(base_url, "/users/{}/passwords/add".format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({ "name": "test", "password": TEST_PASSWORD }), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 user = session.query(User).filter_by(name="*****@*****.**").scalar() assert len(user_passwords( session, user)) == 1, "The user should have a password now" assert (user_passwords( session, user)[0].name == "test"), "The password should have the name given" assert (user_passwords(session, user)[0].password_hash != TEST_PASSWORD ), "The password should not be available as plain text" with pytest.raises(HTTPError): fe_url = url(base_url, "/users/{}/passwords/add".format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({ "name": "test", "password": TEST_PASSWORD }), headers={"X-Grouper-User": "******"}, ) fe_url = url(base_url, "/users/{}/passwords/add".format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({ "name": "test", "password": TEST_PASSWORD }), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 user = session.query(User).filter_by(name="*****@*****.**").scalar() assert (len(user_passwords( session, user)) == 1), "Adding a password with the same name should fail" user = session.query(User).filter_by(name="*****@*****.**").scalar() fe_url = url(base_url, "/users/{}/passwords/add".format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({ "name": "test", "password": TEST_PASSWORD }), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 user = session.query(User).filter_by(name="*****@*****.**").scalar() assert ( len(user_passwords(session, user)) == 1 ), "The user should have a password now (duplicate names are permitted for distinct users)" assert (user_passwords( session, user)[0].name == "test"), "The password should have the name given" assert (user_passwords(session, user)[0].password_hash != TEST_PASSWORD ), "The password should not be available as plain text"
def test_fe_password_add(session, users, http_client, base_url): # noqa: F811 user = users["*****@*****.**"] fe_url = url(base_url, "/users/{}/passwords/add".format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"name": "test", "password": TEST_PASSWORD}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 user = session.query(User).filter_by(name="*****@*****.**").scalar() assert len(user_passwords(session, user)) == 1, "The user should have a password now" assert ( user_passwords(session, user)[0].name == "test" ), "The password should have the name given" assert ( user_passwords(session, user)[0].password_hash != TEST_PASSWORD ), "The password should not be available as plain text" with pytest.raises(HTTPError): fe_url = url(base_url, "/users/{}/passwords/add".format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"name": "test", "password": TEST_PASSWORD}), headers={"X-Grouper-User": "******"}, ) fe_url = url(base_url, "/users/{}/passwords/add".format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"name": "test", "password": TEST_PASSWORD}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 user = session.query(User).filter_by(name="*****@*****.**").scalar() assert ( len(user_passwords(session, user)) == 1 ), "Adding a password with the same name should fail" user = session.query(User).filter_by(name="*****@*****.**").scalar() fe_url = url(base_url, "/users/{}/passwords/add".format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"name": "test", "password": TEST_PASSWORD}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 user = session.query(User).filter_by(name="*****@*****.**").scalar() assert ( len(user_passwords(session, user)) == 1 ), "The user should have a password now (duplicate names are permitted for distinct users)" assert ( user_passwords(session, user)[0].name == "test" ), "The password should have the name given" assert ( user_passwords(session, user)[0].password_hash != TEST_PASSWORD ), "The password should not be available as plain text"