def test_public_key(session, users, http_client, base_url): user = users['*****@*****.**'] assert not get_public_keys_of_user(session, user.id) # add it 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 user = User.get(session, name=user.username) keys = get_public_keys_of_user(session, user.id) assert len(keys) == 1 assert keys[0].public_key == SSH_KEY_1 assert keys[0].fingerprint == 'e9:ae:c5:8f:39:9b:3a:9c:6a:b8:33:6b:cb:6f:ba:35' assert keys[0].fingerprint_sha256 == 'MP9uWaujW96EWxbjDtPdPWheoMDu6BZ8FZj0+CBkVWU' assert keys[0].comment == 'some-comment' # delete it fe_url = url(base_url, '/users/{}/public-key/{}/delete'.format(user.username, keys[0].id)) resp = yield http_client.fetch(fe_url, method="POST", body='', headers={'X-Grouper-User': user.username}) assert resp.code == 200 user = User.get(session, name=user.username) assert not get_public_keys_of_user(session, user.id)
def test_user_public_key(make_session, session, users): make_session.return_value = session # good key username = '******' good_key = ( 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCUQeasspT/etEJR2WUoR+h2sMOQYbJgr0Q' 'E+J8p97gEhmz107KWZ+3mbOwyIFzfWBcJZCEg9wy5Paj+YxbGONqbpXAhPdVQ2TLgxr41bNXvbcR' 'AxZC+Q12UZywR4Klb2kungKz4qkcmSZzouaKK12UxzGB3xQ0N+3osKFj3xA1+B6HqrVreU19XdVo' 'AJh0xLZwhw17/NDM+dAcEdMZ9V89KyjwjraXtOVfFhQF0EDF0ame8d6UkayGrAiXC2He0P2Cja+J' '371P27AlNLHFJij8WGxvcGGSeAxMLoVSDOOllLCYH5UieV8mNpX1kNe2LeA58ciZb0AXHaipSmCH' 'gh/ some-comment') call_main('user', 'add_public_key', username, good_key) user = User.get(session, name=username) keys = get_public_keys_of_user(session, user.id) assert len(keys) == 1 assert keys[0].public_key == good_key # bad key username = '******' bad_key = 'ssh-rsa AAAblahblahkey some-comment' call_main('user', 'add_public_key', username, good_key) user = User.get(session, name=username) keys = get_public_keys_of_user(session, user.id) assert len(keys) == 1 assert keys[0].public_key == good_key
def test_sa_pubkeys(session, users, http_client, base_url): user = users['*****@*****.**'] # Add account create_role_user(session, user, '*****@*****.**', 'Hi', 'canjoin') u = User.get(session, name="*****@*****.**") g = Group.get(session, name="*****@*****.**") assert u is not None assert g is not None assert is_role_user(session, user=u) assert is_role_user(session, group=g) assert get_role_user(session, user=u).group.id == g.id assert get_role_user(session, group=g).user.id == u.id assert not is_role_user(session, user=user) assert not is_role_user(session, group=Group.get(session, name="team-sre")) assert not get_public_keys_of_user(session, user.id) with pytest.raises(HTTPError): # add it fe_url = url(base_url, '/users/{}/public-key/add'.format("*****@*****.**")) resp = yield http_client.fetch(fe_url, method="POST", body=urlencode({'public_key': SSH_KEY_1}), headers={'X-Grouper-User': "******"}) # add it fe_url = url(base_url, '/users/{}/public-key/add'.format("*****@*****.**")) 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 # add bad key -- shouldn't add fe_url = url(base_url, '/users/{}/public-key/add'.format("*****@*****.**")) resp = yield http_client.fetch(fe_url, method="POST", body=urlencode({'public_key': SSH_KEY_BAD}), headers={'X-Grouper-User': user.username}) assert resp.code == 200 sa = User.get(session, name="*****@*****.**") keys = get_public_keys_of_user(session, sa.id) assert len(keys) == 1 assert keys[0].public_key == SSH_KEY_1 with pytest.raises(HTTPError): # delete it fe_url = url(base_url, '/users/{}/public-key/{}/delete'.format("*****@*****.**", keys[0].id)) resp = yield http_client.fetch(fe_url, method="POST", body='', headers={'X-Grouper-User': "******"}) # delete it fe_url = url(base_url, '/users/{}/public-key/{}/delete'.format("*****@*****.**", keys[0].id)) resp = yield http_client.fetch(fe_url, method="POST", body='', headers={'X-Grouper-User': user.username}) assert resp.code == 200 sa = User.get(session, name="*****@*****.**") assert not get_public_keys_of_user(session, sa.id)
def test_public_key(session, users, http_client, base_url): user = users['*****@*****.**'] assert not get_public_keys_of_user(session, user.id) # add it 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 user = User.get(session, name=user.username) keys = get_public_keys_of_user(session, user.id) assert len(keys) == 1 assert keys[0].public_key == SSH_KEY_1 assert keys[ 0].fingerprint == 'e9:ae:c5:8f:39:9b:3a:9c:6a:b8:33:6b:cb:6f:ba:35' assert keys[ 0].fingerprint_sha256 == 'MP9uWaujW96EWxbjDtPdPWheoMDu6BZ8FZj0+CBkVWU' assert keys[0].comment == 'some-comment' # delete it fe_url = url( base_url, '/users/{}/public-key/{}/delete'.format(user.username, keys[0].id)) resp = yield http_client.fetch(fe_url, method="POST", body='', headers={'X-Grouper-User': user.username}) assert resp.code == 200 user = User.get(session, name=user.username) assert not get_public_keys_of_user(session, user.id)
def test_add_service_account(session, users, http_client, base_url): user = users['*****@*****.**'] # Add account fe_url = url(base_url, '/service/create') resp = yield http_client.fetch(fe_url, method="POST", body=urlencode({'name': '*****@*****.**', "description": "Hi", "canjoin": "canjoin"}), headers={'X-Grouper-User': user.username}) assert resp.code == 200 assert User.get(session, name="*****@*****.**") is None assert Group.get(session, name="*****@*****.**") is None # Add account fe_url = url(base_url, '/service/create') resp = yield http_client.fetch(fe_url, method="POST", body=urlencode({'name': '*****@*****.**', "description": "Hi", "canjoin": "canjoin"}), headers={'X-Grouper-User': user.username}) assert resp.code == 200 u = User.get(session, name="*****@*****.**") g = Group.get(session, name="*****@*****.**") assert u is not None assert g is not None assert is_service_account(session, user=u) assert is_service_account(session, group=g) assert get_service_account(session, user=u).group.id == g.id assert get_service_account(session, group=g).user.id == u.id assert not is_service_account(session, user=user) assert not is_service_account(session, group=Group.get(session, name="team-sre"))
def test_user_status_changes(session, tmpdir, users, groups): # noqa: F811 username = "******" groupname = "team-sre" # add user to a group call_main(session, tmpdir, "group", "add_member", "--member", groupname, username) # disable the account call_main(session, tmpdir, "user", "disable", username) assert not User.get(session, name=username).enabled # double disabling is a no-op call_main(session, tmpdir, "user", "disable", username) assert not User.get(session, name=username).enabled # re-enable the account, preserving memberships call_main(session, tmpdir, "user", "enable", "--preserve-membership", username) assert User.get(session, name=username).enabled assert (u"User", username) in groups[groupname].my_members() # enabling an active account is a no-op call_main(session, tmpdir, "user", "enable", username) assert User.get(session, name=username).enabled # disable and re-enable without the --preserve-membership flag call_main(session, tmpdir, "user", "disable", username) call_main(session, tmpdir, "user", "enable", username) assert User.get(session, name=username).enabled assert (u"User", username) not in groups[groupname].my_members()
def test_public_key_admin(session, users, http_client, base_url): user = users['*****@*****.**'] assert not get_public_keys_of_user(session, user.id) # add it 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 user = User.get(session, name=user.username) keys = get_public_keys_of_user(session, user.id) assert len(keys) == 1 assert keys[0].public_key == SSH_KEY_1 # have an admin delete it fe_url = url( base_url, '/users/{}/public-key/{}/delete'.format(user.username, keys[0].id)) resp = yield http_client.fetch( fe_url, method="POST", body='', headers={'X-Grouper-User': "******"}) assert resp.code == 200 user = User.get(session, name=user.username) assert not get_public_keys_of_user(session, user.id)
def test_user_status_changes(make_user_session, make_group_session, session, users, groups): make_user_session.return_value = session make_group_session.return_value = session username = '******' groupname = 'team-sre' # add user to a group call_main('group', 'add_member', '--member', groupname, username) # disable the account call_main('user', 'disable', username) assert not User.get(session, name=username).enabled # double disabling is a no-op call_main('user', 'disable', username) assert not User.get(session, name=username).enabled # re-enable the account, preserving memberships call_main('user', 'enable', '--preserve-membership', username) assert User.get(session, name=username).enabled assert (u'User', username) in groups[groupname].my_members() # enabling an active account is a no-op call_main('user', 'enable', username) assert User.get(session, name=username).enabled # disable and re-enable without the --preserve-membership flag call_main('user', 'disable', username) call_main('user', 'enable', username) assert User.get(session, name=username).enabled assert (u'User', username) not in groups[groupname].my_members()
def test_user_create(make_session, session, users): make_session.return_value = session # simple username = '******' call_main('user', 'create', username) assert User.get(session, name=username), 'non-existent user should be created' # check username bad_username = '******' call_main('user', 'create', bad_username) assert not User.get(session, name=bad_username), 'bad user should not be created' # bulk usernames = ['*****@*****.**', '*****@*****.**', '*****@*****.**'] call_main('user', 'create', *usernames) users = [User.get(session, name=u) for u in usernames] assert all(users), 'all users created' usernames_with_one_bad = ['*****@*****.**', '*****@*****.**', 'not_valid_user'] call_main('user', 'create', *usernames_with_one_bad) users = [User.get(session, name=u) for u in usernames_with_one_bad] assert not any(users), 'one bad seed means no users created'
def test_user_create(make_session, session, users): # noqa: F811 make_session.return_value = session # simple username = "******" call_main(session, "user", "create", username) assert User.get(session, name=username), "non-existent user should be created" # check username bad_username = "******" call_main(session, "user", "create", bad_username) assert not User.get(session, name=bad_username), "bad user should not be created" # bulk usernames = ["*****@*****.**", "*****@*****.**", "*****@*****.**"] call_main(session, "user", "create", *usernames) users = [User.get(session, name=u) for u in usernames] assert all(users), "all users created" usernames_with_one_bad = ["*****@*****.**", "*****@*****.**", "not_valid_user"] call_main(session, "user", "create", *usernames_with_one_bad) users = [User.get(session, name=u) for u in usernames_with_one_bad] assert not any(users), "one bad seed means no users created"
def test_user_public_key(make_session, session, users): make_session.return_value = session # good key username = '******' good_key = ('ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCUQeasspT/etEJR2WUoR+h2sMOQYbJgr0Q' 'E+J8p97gEhmz107KWZ+3mbOwyIFzfWBcJZCEg9wy5Paj+YxbGONqbpXAhPdVQ2TLgxr41bNXvbcR' 'AxZC+Q12UZywR4Klb2kungKz4qkcmSZzouaKK12UxzGB3xQ0N+3osKFj3xA1+B6HqrVreU19XdVo' 'AJh0xLZwhw17/NDM+dAcEdMZ9V89KyjwjraXtOVfFhQF0EDF0ame8d6UkayGrAiXC2He0P2Cja+J' '371P27AlNLHFJij8WGxvcGGSeAxMLoVSDOOllLCYH5UieV8mNpX1kNe2LeA58ciZb0AXHaipSmCH' 'gh/ some-comment') call_main('user', 'add_public_key', username, good_key) user = User.get(session, name=username) keys = get_public_keys_of_user(session, user.id) assert len(keys) == 1 assert keys[0].public_key == good_key # bad key username = '******' bad_key = 'ssh-rsa AAAblahblahkey some-comment' call_main('user', 'add_public_key', username, good_key) user = User.get(session, name=username) keys = get_public_keys_of_user(session, user.id) assert len(keys) == 1 assert keys[0].public_key == good_key
def test_public_key_admin(session, users, http_client, base_url): # noqa: F811 user = users["*****@*****.**"] assert not get_public_keys_of_user(session, user.id) # add it 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 user = User.get(session, name=user.username) keys = get_public_keys_of_user(session, user.id) assert len(keys) == 1 assert keys[0].public_key == SSH_KEY_1 # have an admin delete it fe_url = url(base_url, "/users/{}/public-key/{}/delete".format(user.username, keys[0].id)) resp = yield http_client.fetch( fe_url, method="POST", body="", headers={"X-Grouper-User": "******"} ) assert resp.code == 200 user = User.get(session, name=user.username) assert not get_public_keys_of_user(session, user.id)
def test_public_key(session, users, http_client, base_url): # noqa: F811 user = users["*****@*****.**"] assert not get_public_keys_of_user(session, user.id) # add it 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_ED25519}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 user = User.get(session, name=user.username) keys = get_public_keys_of_user(session, user.id) assert len(keys) == 1 assert keys[0].public_key == SSH_KEY_ED25519 assert keys[0].fingerprint == "fa:d9:ca:40:bd:f7:64:37:a7:99:3a:8e:50:8a:c5:94" assert keys[0].fingerprint_sha256 == "ExrCZ0nqSJv+LqAEh8CWeKUxiAeZA+N0bKC18dK7Adg" assert keys[0].comment == "comment" # delete it fe_url = url(base_url, "/users/{}/public-key/{}/delete".format(user.username, keys[0].id)) resp = yield http_client.fetch( fe_url, method="POST", body="", headers={"X-Grouper-User": user.username} ) assert resp.code == 200 user = User.get(session, name=user.username) assert not get_public_keys_of_user(session, user.id)
def test_success_set_initial_metadata(setup): # type: (SetupTest) -> None with setup.transaction(): setup.add_user_to_group("*****@*****.**", "some-group") initial_metadata = {"test-item-1": "foo", "test-item-2": "bar"} mock_ui = MagicMock() usecase = setup.usecase_factory.create_create_service_account_usecase( "*****@*****.**", mock_ui) usecase.create_service_account("*****@*****.**", "some-group", "machine-set", "description", initial_metadata) user = User.get(setup.session, name="*****@*****.**") assert user is not None metadata_items = get_user_metadata(setup.session, user.id) actual_items = {mi.data_key: mi.data_value for mi in metadata_items} assert len(initial_metadata) == len(actual_items) for key, value in initial_metadata.items(): assert key in actual_items assert initial_metadata[key] == actual_items[key] usecase = setup.usecase_factory.create_create_service_account_usecase( "*****@*****.**", mock_ui) usecase.create_service_account("*****@*****.**", "some-group", "machine-set", "description") user = User.get(setup.session, name="*****@*****.**") assert user is not None metadata_items = get_user_metadata(setup.session, user.id) assert metadata_items == []
def test_shell(session, users, http_client, base_url): with patch('grouper.fe.handlers.user_shell.settings') as mock_settings: mock_settings.shell = [['/bin/bash', 'bash'], ['/bin/zsh', 'zsh']] user = users['*****@*****.**'] assert not get_user_metadata_by_key(session, user.id, USER_METADATA_SHELL_KEY) user = User.get(session, name=user.username) fe_url = url(base_url, '/users/{}/shell'.format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({'shell': "/bin/bash"}), 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_SHELL_KEY) is not None, \ "The user should have shell metadata" assert (get_user_metadata_by_key( session, user.id, USER_METADATA_SHELL_KEY).data_value == "/bin/bash") fe_url = url(base_url, '/users/{}/shell'.format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({'shell': "/bin/fish"}), 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_SHELL_KEY) is not None, \ "The user should have shell metadata" assert get_user_metadata_by_key( session, user.id, USER_METADATA_SHELL_KEY).data_value == "/bin/bash" fe_url = url(base_url, '/users/{}/shell'.format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({'shell': "/bin/zsh"}), 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_SHELL_KEY) is not None, \ "The user should have shell metadata" assert (get_user_metadata_by_key( session, user.id, USER_METADATA_SHELL_KEY).data_value == "/bin/zsh")
def test_shell(session, users, http_client, base_url): # noqa: F811 settings().shell = [["/bin/bash", "bash"], ["/bin/zsh", "zsh"]] user = users["*****@*****.**"] assert not get_user_metadata_by_key(session, user.id, USER_METADATA_SHELL_KEY) user = User.get(session, name=user.username) fe_url = url(base_url, "/users/{}/shell".format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"shell": "/bin/bash"}), 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_SHELL_KEY) is not None), "The user should have shell metadata" assert (get_user_metadata_by_key( session, user.id, USER_METADATA_SHELL_KEY).data_value == "/bin/bash") fe_url = url(base_url, "/users/{}/shell".format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"shell": "/bin/fish"}), 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_SHELL_KEY) is not None), "The user should have shell metadata" assert (get_user_metadata_by_key( session, user.id, USER_METADATA_SHELL_KEY).data_value == "/bin/bash") fe_url = url(base_url, "/users/{}/shell".format(user.username)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"shell": "/bin/zsh"}), 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_SHELL_KEY) is not None), "The user should have shell metadata" assert (get_user_metadata_by_key( session, user.id, USER_METADATA_SHELL_KEY).data_value == "/bin/zsh")
def action_permission_requests(setup: SetupTest) -> None: """Action (approve) the perm.hasgranter request, cancel (deny) the perm.nogranter request.""" granting_user = User.get(setup.session, name="*****@*****.**") assert granting_user admin_user = User.get(setup.session, name="*****@*****.**") assert admin_user with setup.transaction(): all_requests = setup.session.query(PermissionRequest) for request in all_requests: if request.status == "pending" and request.permission.name == "perm.hasgranter": update_request(setup.session, request, granting_user, "actioned", "reasons") if request.status == "pending" and request.permission.name == "perm.nogranter": update_request(setup.session, request, admin_user, "cancelled", "reasons")
def create_user(self, name): # type: (str) -> None """Create a user, does nothing if it already exists.""" if User.get(self.session, name=name): return user = User(username=name) user.add(self.session)
def post(self, user_id=None, name=None): user = User.get(self.session, user_id, name) if not user: return self.notfound() if not self.check_access(self.session, self.current_user, user): return self.forbidden() try: if user.role_user: disable_role_user(self.session, user=user) else: disable_user(self.session, user) except PluginRejectedDisablingUser as e: alert = Alert("danger", str(e)) return self.redirect("/users/{}".format(user.name), alerts=[alert]) self.session.commit() AuditLog.log(self.session, self.current_user.id, 'disable_user', 'Disabled user.', on_user_id=user.id) return self.redirect("/users/{}?refresh=yes".format(user.name))
def service_account_command(args, settings, session_factory): # type: (Namespace, CtlSettings, SessionFactory) -> None session = session_factory.create_session() actor_user = User.get(session, name=args.actor_name) if not actor_user: logging.fatal('Actor user "{}" is not a valid Grouper user'.format( args.actor_name)) return if args.subcommand == "create": name = args.name if ServiceAccount.get(session, name=name): logging.info("{}: Already exists. Doing nothing.".format(name)) return owner_group = Group.get(session, name=args.owner_group) if not owner_group: logging.fatal('Owner group "{}" does not exist.'.format( args.owner_group)) return logging.info("{}: No such service account, creating...".format(name)) description = args.description machine_set = args.machine_set create_service_account(session, actor_user, name, description, machine_set, owner_group) return
def notify_nonauditor_flagged(settings, session, edge): """Send notification that a nonauditor in an audited group has had their membership set to expire. Handles email notification and audit logging. Args: settings (Settings): Grouper Settings object for current run. session (Session): Object for db session. edge (GroupEdge): The expiring edge. """ # Pull data about the edge and the affected user group_name = edge.group.name assert OBJ_TYPES_IDX[edge.member_type] == "User" user = User.get(session, pk=edge.member_pk) member_name = user.username recipients = [member_name] audit_data = { "action": "nonauditor_flagged", "actor_id": user.id, "description": "Flagged {} as nonauditor approver in audited group".format(member_name), } AuditLog.log(session, on_user_id=user.id, on_group_id=edge.group_id, **audit_data) email_context = {"group_name": group_name, "member_name": member_name} send_email( session=session, recipients=recipients, subject="Membership in {} set to expire".format(group_name), template="nonauditor", settings=settings, context=email_context, )
def post(self, user_id=None, name=None): user = User.get(self.session, user_id, name) if not user: return self.notfound() if not self.check_access(self.session, self.current_user, user): return self.forbidden() form = UserShellForm(self.request.arguments) form.shell.choices = settings.shell if not form.validate(): return self.render( "user-shell.html", form=form, user=user, alerts=self.get_form_alerts(form.errors), ) user.set_metadata(USER_METADATA_SHELL_KEY, form.data["shell"]) user.add(self.session) self.session.commit() AuditLog.log(self.session, self.current_user.id, 'changed_shell', 'Changed shell: {}'.format(form.data["shell"]), on_user_id=user.id) return self.redirect("/users/{}?refresh=yes".format(user.name))
def post(self, *args, **kwargs): # type: (*Any, **Any) -> None user_id = kwargs.get("user_id") # type: Optional[int] name = kwargs.get("name") # type: Optional[str] user = User.get(self.session, user_id, name) if not user: return self.notfound() if not self.check_access(self.session, self.current_user, user): return self.forbidden() form = UserGitHubForm(self.request.arguments) if not form.validate(): return self.render( "user-github.html", form=form, user=user, alerts=self.get_form_alerts(form.errors) ) new_username = form.data["username"] if new_username == "": new_username = None set_user_metadata(self.session, user.id, USER_METADATA_GITHUB_USERNAME_KEY, new_username) AuditLog.log( self.session, self.current_user.id, "changed_github_username", "Changed GitHub username: {}".format(form.data["username"]), on_user_id=user.id, ) return self.redirect("/users/{}?refresh=yes".format(user.name))
def post(self): supplied_token = self.get_body_argument("token") match = TokenValidate.validator.match(supplied_token) if not match: return self.error(((1, "Token format not recognized"),)) sess = Session() token_name = match.group("token_name") token_secret = match.group("token_secret") owner = User.get(sess, name=match.group("name")) token = UserToken.get(sess, owner, token_name) if token is None: return self.error(((2, "Token specified does not exist"),)) if not token.enabled: return self.error(((3, "Token is disabled"),)) if not token.check_secret(token_secret): return self.error(((4, "Token secret mismatch"),)) return self.success({ "owner": owner.username, "identity": str(token), "act_as_owner": True, "valid": True, })
def post(self, user_id=None, name=None, key_id=None, tag_id=None): user = User.get(self.session, user_id, name) if not user: return self.notfound() if not self.check_access(self.session, self.current_user, user): return self.forbidden() try: key = get_public_key(self.session, user.id, key_id) except KeyNotFound: return self.notfound() tag = PublicKeyTag.get(self.session, id=tag_id) if not tag: return self.notfound() try: remove_tag_from_public_key(self.session, key, tag) except TagNotOnKey: return self.redirect("/users/{}?refresh=yes".format(user.name)) AuditLog.log( self.session, self.current_user.id, "untag_public_key", "Untagged public key: {}".format(key.fingerprint_sha256), on_tag_id=tag.id, on_user_id=user.id, ) return self.redirect("/users/{}?refresh=yes".format(user.name))
def cancel_user_request(self, user_request, reason, authorization): # type: (UserGroupRequest, str, Authorization) -> None now = datetime.utcnow() request = Request.get(self.session, id=user_request.id) if not request: raise UserGroupRequestNotFoundException(request) actor = User.get(self.session, name=authorization.actor) if not actor: raise UserNotFoundException(authorization.actor) request_status_change = RequestStatusChange( request=request, user_id=actor.id, from_status=request.status, to_status="cancelled", change_at=now, ).add(self.session) request.status = "cancelled" self.session.flush() Comment( obj_type=OBJ_TYPES["RequestStatusChange"], obj_pk=request_status_change.id, user_id=actor.id, comment=reason, created_on=now, ).add(self.session)
def test_user_public_key(make_session, session, users): make_session.return_value = session # good key username = '******' call_main('user', 'add_public_key', username, SSH_KEY_1) user = User.get(session, name=username) keys = get_public_keys_of_user(session, user.id) assert len(keys) == 1 assert keys[0].public_key == SSH_KEY_1 # duplicate key call_main('user', 'add_public_key', username, SSH_KEY_1) keys = get_public_keys_of_user(session, user.id) assert len(keys) == 1 assert keys[0].public_key == SSH_KEY_1 # bad key call_main('user', 'add_public_key', username, SSH_KEY_BAD) keys = get_public_keys_of_user(session, user.id) assert len(keys) == 1 assert keys[0].public_key == SSH_KEY_1
def role(self, role): prev_role = self._role self._role = GROUP_EDGE_ROLES.index(role) # Groups should always "member". if not (OBJ_TYPES_IDX[self.member_type] == "User"): return # If ownership status is unchanged, no notices need to be adjusted. if (self._role in OWNER_ROLE_INDICES) == (prev_role in OWNER_ROLE_INDICES): return recipient = User.get(self.session, pk=self.member_pk).username expiring_supergroups = self.group.my_expiring_groups() member_name = self.group.name if role in ["owner", "np-owner"]: # We're creating a new owner, who should find out when this group # they now own loses its membership in larger groups. for supergroup_name, expiration in expiring_supergroups: AsyncNotification.add_expiration(self.session, expiration, group_name=supergroup_name, member_name=member_name, recipients=[recipient], member_is_user=False) else: # We're removing an owner, who should no longer find out when this # group they no longer own loses its membership in larger groups. for supergroup_name, _ in expiring_supergroups: AsyncNotification.cancel_expiration(self.session, group_name=supergroup_name, member_name=member_name, recipients=[recipient])
def post(self, *args, **kwargs): # type: (*Any, **Any) -> None user_id = kwargs.get("user_id") # type: Optional[int] name = kwargs.get("name") # type: Optional[str] user = User.get(self.session, user_id, name) if not user: return self.notfound() if not self.check_access(self.session, self.current_user, user): return self.forbidden() form = UserShellForm(self.request.arguments) form.shell.choices = settings().shell if not form.validate(): return self.render( "user-shell.html", form=form, user=user, alerts=self.get_form_alerts(form.errors) ) set_user_metadata(self.session, user.id, USER_METADATA_SHELL_KEY, form.data["shell"]) AuditLog.log( self.session, self.current_user.id, "changed_shell", "Changed shell: {}".format(form.data["shell"]), on_user_id=user.id, ) return self.redirect("/users/{}?refresh=yes".format(user.name))
def post(self, user_id=None, name=None): user = User.get(self.session, user_id, name) if not user: return self.notfound() if not self.check_access(self.session, self.current_user, user): return self.forbidden() form = UserEnableForm(self.request.arguments) if not form.validate(): # TODO: add error message return self.redirect("/users/{}?refresh=yes".format(user.name)) if user.role_user: enable_service_account(self.session, actor=self.current_user, preserve_membership=form.preserve_membership.data, user=user) else: enable_user(self.session, user, self.current_user, preserve_membership=form.preserve_membership.data) self.session.commit() AuditLog.log(self.session, self.current_user.id, 'enable_user', 'Enabled user.', on_user_id=user.id) return self.redirect("/users/{}?refresh=yes".format(user.name))
def get(self, user_id=None, name=None): self.handle_refresh() user = User.get(self.session, user_id, name) if not user: return self.notfound() if user.role_user: return self.redirect("/service/{}".format(user_id or name)) if user.is_service_account: service_account = user.service_account if service_account.owner: return self.redirect("/groups/{}/service/{}".format( service_account.owner.group.name, user.username)) else: self.render("service-account.html", service_account=service_account, group=None, user=user, **get_user_view_template_vars( self.session, self.current_user, user, self.graph)) return self.render("user.html", user=user, **get_user_view_template_vars(self.session, self.current_user, user, self.graph))
def post(self): supplied_token = self.get_body_argument("token") match = TokenValidate.validator.match(supplied_token) if not match: return self.error(((1, "Token format not recognized"), )) sess = Session() token_name = match.group("token_name") token_secret = match.group("token_secret") owner = User.get(sess, name=match.group("name")) token = UserToken.get(sess, owner, token_name) if token is None: return self.error(((2, "Token specified does not exist"), )) if not token.enabled: return self.error(((3, "Token is disabled"), )) if not token.check_secret(token_secret): return self.error(((4, "Token secret mismatch"), )) return self.success({ "owner": owner.username, "identity": str(token), "act_as_owner": True, "valid": True, })
def post(self, *args: Any, **kwargs: Any) -> None: name = self.get_path_argument("name") user = User.get(self.session, name=name) if not user: return self.notfound() if not self.check_access(self.session, self.current_user, user): return self.forbidden() form = UserShellForm(self.request.arguments) form.shell.choices = settings().shell if not form.validate(): return self.render("user-shell.html", form=form, user=user, alerts=self.get_form_alerts(form.errors)) set_user_metadata(self.session, user.id, USER_METADATA_SHELL_KEY, form.data["shell"]) AuditLog.log( self.session, self.current_user.id, "changed_shell", "Changed shell: {}".format(form.data["shell"]), on_user_id=user.id, ) return self.redirect("/users/{}?refresh=yes".format(user.name))
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: return self.notfound() if user.role_user: return self.redirect("/service/{}".format(name)) if user.is_service_account: service_account = user.service_account if service_account.owner: return self.redirect("/groups/{}/service/{}".format( service_account.owner.group.name, user.username)) else: self.render("service-account.html", service_account=service_account, group=None, user=user, **get_user_view_template_vars( self.session, self.current_user, user, self.graph)) return self.render("user.html", user=user, **get_user_view_template_vars(self.session, self.current_user, user, self.graph))
def post(self, user_id=None, name=None): user = User.get(self.session, user_id, name) if not user: return self.notfound() if not self.check_access(self.session, self.current_user, user): return self.forbidden() form = UserEnableForm(self.request.arguments) if not form.validate(): # TODO: add error message return self.redirect("/users/{}?refresh=yes".format(user.name)) if user.role_user: enable_service_account( self.session, actor=self.current_user, preserve_membership=form.preserve_membership.data, user=user) else: enable_user(self.session, user, self.current_user, preserve_membership=form.preserve_membership.data) self.session.commit() AuditLog.log(self.session, self.current_user.id, 'enable_user', 'Enabled user.', on_user_id=user.id) return self.redirect("/users/{}?refresh=yes".format(user.name))
def post(self, *args, **kwargs): # type: (*Any, **Any) -> None user_id = kwargs.get("user_id") # type: Optional[int] name = kwargs.get("name") # type: Optional[str] user = User.get(self.session, user_id, name) if not user: return self.notfound() if not self.check_access(self.session, self.current_user, user): return self.forbidden() form = UserGitHubForm(self.request.arguments) if not form.validate(): return self.render("user-github.html", form=form, user=user, alerts=self.get_form_alerts(form.errors)) new_username = form.data["username"] if new_username == "": new_username = None set_user_metadata(self.session, user.id, USER_METADATA_GITHUB_USERNAME_KEY, new_username) AuditLog.log( self.session, self.current_user.id, "changed_github_username", "Changed GitHub username: {}".format(form.data["username"]), on_user_id=user.id, ) return self.redirect("/users/{}?refresh=yes".format(user.name))
def get(self, user_id=None, name=None): self.handle_refresh() user = User.get(self.session, user_id, name) if not user: return self.notfound() if user.role_user: return self.redirect("/service/{}".format(user_id or name)) if user.is_service_account: service_account = user.service_account if service_account.owner: return self.redirect("/groups/{}/service/{}".format( service_account.owner.group.name, user.username)) else: self.render( "service-account.html", service_account=service_account, group=None, user=user, **get_user_view_template_vars(self.session, self.current_user, user, self.graph) ) return self.render("user.html", user=user, **get_user_view_template_vars(self.session, self.current_user, user, self.graph) )
def get_role_user(session, user=None, group=None): # type: (Session, User, Group) -> RoleUser """ Takes in a User or a Group and returns a dictionary that contains all of the service account components for the service account that the user/group is part of. Args: session: the database session user: a User object to check group: a Group object to check Throws: RoleUserNotFound: if the user or group is not part of a service account Returns: a dictionary with all components of the service account of the user or group passed in """ if not is_role_user(session, user, group): raise RoleUserNotFound() if user: name = user.name else: assert group is not None name = group.name return RoleUser(User.get(session, name=name), Group.get(session, name=name))
def permission_grants_for_user(self, name): # type: (str) -> List[GroupPermissionGrant] """Return all permission grants a user has from whatever source. TODO(rra): Currently does not expand permission aliases, and therefore doesn't match the graph behavior. Use with caution until that is fixed. """ now = datetime.utcnow() user = User.get(self.session, name=name) if not user or user.role_user or user.is_service_account or not user.enabled: return [] # Get the groups of which this user is a direct member. groups = (self.session.query(Group.id).join( GroupEdge, Group.id == GroupEdge.group_id).join( User, User.id == GroupEdge.member_pk).filter( Group.enabled == True, User.id == user.id, GroupEdge.active == True, GroupEdge.member_type == OBJ_TYPES["User"], GroupEdge._role != GROUP_EDGE_ROLES.index("np-owner"), or_(GroupEdge.expiration > now, GroupEdge.expiration == None), ).distinct()) group_ids = [g.id for g in groups] # If the user was not a member of any group, we can return early. if not group_ids: return [] # Now, return all the permission grants for those groups. return self._permission_grants_for_group_ids(group_ids)
def is_role_user(session, user=None, group=None): # type: (Session, User, Group) -> bool """ Takes in a User or a Group and returns a boolean indicating whether that User/Group is a component of a service account. Args: session: the database session user: a User object to check group: a Group object to check Throws: AssertionError if neither a user nor a group is provided Returns: whether the User/Group is a component of a service account """ if user is not None: return user.role_user assert group is not None user = User.get(session, name=group.groupname) if not user: return False return user.role_user
def post(self, user_id=None, name=None, key_id=None): user = User.get(self.session, user_id, name) if not user: return self.notfound() if not self.check_access(self.session, self.current_user, user): return self.forbidden() try: key = get_public_key(self.session, user.id, key_id) delete_public_key(self.session, user.id, key_id) except KeyNotFound: return self.notfound() AuditLog.log(self.session, self.current_user.id, 'delete_public_key', 'Deleted public key: {}'.format(key.fingerprint), on_user_id=user.id) email_context = { "actioner": self.current_user.name, "changed_user": user.name, "action": "removed", } send_email(self.session, [user.name], 'Public SSH key removed', 'ssh_keys_changed', settings, email_context) return self.redirect("/users/{}?refresh=yes".format(user.name))
def get_role_user(session, user=None, group=None): # type: (Session, User, Group) -> RoleUser """ Takes in a User or a Group and returns a dictionary that contains all of the service account components for the service account that the user/group is part of. Args: session: the database session user: a User object to check group: a Group object to check Throws: RoleUserNotFound: if the user or group is not part of a service account Returns: a dictionary with all components of the service account of the user or group passed in """ if not is_role_user(session, user, group): raise RoleUserNotFound() if user: name = user.name else: assert group is not None name = group.name user_obj = User.get(session, name=name) assert user_obj, "User object for role user not found" group_obj = Group.get(session, name=name) assert group_obj, "Group object for role user not found" return RoleUser(user_obj, group_obj)
def test_user_public_key(make_session, session, users): # noqa: F811 make_session.return_value = session # good key username = "******" call_main(session, "user", "add_public_key", username, SSH_KEY_1) user = User.get(session, name=username) keys = get_public_keys_of_user(session, user.id) assert len(keys) == 1 assert keys[0].public_key == SSH_KEY_1 # duplicate key call_main(session, "user", "add_public_key", username, SSH_KEY_1) keys = get_public_keys_of_user(session, user.id) assert len(keys) == 1 assert keys[0].public_key == SSH_KEY_1 # bad key call_main(session, "user", "add_public_key", username, SSH_KEY_BAD) keys = get_public_keys_of_user(session, user.id) assert len(keys) == 1 assert keys[0].public_key == SSH_KEY_1
def post(self, user_id=None, name=None): user = User.get(self.session, user_id, name) if not user: return self.notfound() if not self.check_access(self.session, self.current_user, user): return self.forbidden() try: if user.role_user: disable_role_user(self.session, user=user) else: disable_user(self.session, user) except PluginRejectedDisablingUser as e: alert = Alert("danger", str(e)) return self.redirect("/users/{}".format(user.name), alerts=[alert]) self.session.commit() AuditLog.log( self.session, self.current_user.id, "disable_user", "Disabled user.", on_user_id=user.id, ) return self.redirect("/users/{}?refresh=yes".format(user.name))
def test_sa_tokens(session, users, http_client, base_url): user = users['*****@*****.**'] # Add account create_role_user(session, user, '*****@*****.**', 'Hi', 'canjoin') u = User.get(session, name="*****@*****.**") g = Group.get(session, name="*****@*****.**") assert u is not None assert g is not None assert is_role_user(session, user=u) assert is_role_user(session, group=g) assert get_role_user(session, user=u).group.id == g.id assert get_role_user(session, group=g).user.id == u.id assert not is_role_user(session, user=user) assert not is_role_user(session, group=Group.get(session, name="team-sre")) with pytest.raises(HTTPError): # Add token fe_url = url(base_url, '/users/{}/tokens/add'.format("*****@*****.**")) resp = yield http_client.fetch(fe_url, method="POST", body=urlencode({'name': 'myDHDToken'}), headers={'X-Grouper-User': "******"}) # Add token fe_url = url(base_url, '/users/{}/tokens/add'.format("*****@*****.**")) resp = yield http_client.fetch(fe_url, method="POST", body=urlencode({'name': 'myDHDToken'}), headers={'X-Grouper-User': user.username}) assert resp.code == 200 # Verify add fe_url = url(base_url, '/users/{}'.format("*****@*****.**")) resp = yield http_client.fetch(fe_url, method="GET", headers={'X-Grouper-User': user.username}) assert resp.code == 200 assert "Added token: myDHDToken" in resp.body with pytest.raises(HTTPError): # Disable token fe_url = url(base_url, '/users/{}/tokens/1/disable'.format("*****@*****.**")) resp = yield http_client.fetch(fe_url, method="POST", body="", headers={'X-Grouper-User': "******"}) # Disable token fe_url = url(base_url, '/users/{}/tokens/1/disable'.format("*****@*****.**")) resp = yield http_client.fetch(fe_url, method="POST", body="", headers={'X-Grouper-User': user.username}) assert resp.code == 200 # Verify disable fe_url = url(base_url, '/users/{}'.format("*****@*****.**")) resp = yield http_client.fetch(fe_url, method="GET", headers={'X-Grouper-User': user.username}) assert resp.code == 200 assert "Disabled token: myDHDToken" in resp.body
def test_shell(session, users, http_client, base_url): with patch('grouper.fe.handlers.user_shell.settings') as mock_settings: mock_settings.shell = [['/bin/bash', 'bash'], ['/bin/zsh', 'zsh']] user = users['*****@*****.**'] assert not get_user_metadata_by_key(session, user.id, USER_METADATA_SHELL_KEY) user = User.get(session, name=user.username) fe_url = url(base_url, '/users/{}/shell'.format(user.username)) resp = yield http_client.fetch(fe_url, method="POST", body=urlencode({'shell': "/bin/bash"}), 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_SHELL_KEY) is not None, \ "The user should have shell metadata" assert (get_user_metadata_by_key(session, user.id, USER_METADATA_SHELL_KEY).data_value == "/bin/bash") fe_url = url(base_url, '/users/{}/shell'.format(user.username)) resp = yield http_client.fetch(fe_url, method="POST", body=urlencode({'shell': "/bin/fish"}), 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_SHELL_KEY) is not None, \ "The user should have shell metadata" assert get_user_metadata_by_key(session, user.id, USER_METADATA_SHELL_KEY).data_value == "/bin/bash" fe_url = url(base_url, '/users/{}/shell'.format(user.username)) resp = yield http_client.fetch(fe_url, method="POST", body=urlencode({'shell': "/bin/zsh"}), 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_SHELL_KEY) is not None, \ "The user should have shell metadata" assert (get_user_metadata_by_key(session, user.id, USER_METADATA_SHELL_KEY).data_value == "/bin/zsh")
def post(self, *args, **kwargs): # type: (*Any, **Any) -> None user_id = kwargs.get("user_id") # type: Optional[int] name = kwargs.get("name") # type: Optional[str] user = User.get(self.session, user_id, name) if not user: return self.notfound() if not self.check_access(self.session, self.current_user, user): return self.forbidden() form = UserTokenForm(self.request.arguments) if not form.validate(): return self.render( "user-token-add.html", form=form, user=user, alerts=self.get_form_alerts(form.errors), ) try: token, secret = add_new_user_token( self.session, UserToken(name=form.data["name"], user=user) ) self.session.commit() except IntegrityError: self.session.rollback() form.name.errors.append("Name already in use.") return self.render( "user-token-add.html", form=form, user=user, alerts=self.get_form_alerts(form.errors), ) AuditLog.log( self.session, self.current_user.id, "add_token", "Added token: {}".format(token.name), on_user_id=user.id, ) email_context = { "actioner": self.current_user.name, "changed_user": user.name, "action": "added", } send_email( self.session, [user.name], "User token created", "user_tokens_changed", settings(), email_context, ) return self.render("user-token-created.html", token=token, secret=secret)
def post(self, *args, **kwargs): # type: (*Any, **Any) -> None user_id = kwargs.get("user_id") # type: Optional[int] name = kwargs.get("name") # type: Optional[str] user = User.get(self.session, user_id, name) if not user: return self.notfound() if not self.check_access(self.session, self.current_user, user): return self.forbidden() form = UserPasswordForm(self.request.arguments) if not form.validate(): return self.render( "user-password-add.html", form=form, user=user, alerts=self.get_form_alerts(form.errors), ) pass_name = form.data["name"] password = form.data["password"] try: add_new_user_password(self.session, pass_name, password, user.id) except PasswordAlreadyExists: self.session.rollback() form.name.errors.append("Name already in use.") return self.render( "user-password-add.html", form=form, user=user, alerts=self.get_form_alerts(form.errors), ) AuditLog.log( self.session, self.current_user.id, "add_password", "Added password: {}".format(pass_name), on_user_id=user.id, ) email_context = { "actioner": self.current_user.name, "changed_user": user.name, "pass_name": pass_name, } send_email( self.session, [user.name], "User password created", "user_password_created", settings(), email_context, ) return self.redirect("/users/{}?refresh=yes".format(user.name))
def get(self, user_id=None, name=None, pass_id=None): user = User.get(self.session, user_id, name) if not user: return self.notfound() if not self.check_access(self.session, self.current_user, user): return self.forbidden() password = UserPassword.get(self.session, user=user, id=pass_id) return self.render("user-password-delete.html", user=user, password=password)
def member(self): # TODO(cbguder): get around circular dependencies from grouper.models.group import Group if self.edge.member_type == 0: # User return User.get(self.session, pk=self.edge.member_pk) elif self.edge.member_type == 1: # Group return Group.get(self.session, pk=self.edge.member_pk) raise Exception("invalid member_type in AuditMember!")
def get(self, user_id=None, name=None): user = User.get(self.session, user_id, name) if not user: return self.notfound() if not self.check_access(self.session, self.current_user, user): return self.forbidden() self.render("user-token-add.html", form=UserTokenForm(), user=user)
def get(self, user_id=None, name=None, token_id=None): user = User.get(self.session, user_id, name) if not user: return self.notfound() if not self.check_access(self.session, self.current_user, user): return self.forbidden() token = UserToken.get(self.session, user=user, id=token_id) return self.render("user-token-disable.html", user=user, token=token)