def create_test_user(admin_credentials: authentication.Credentials,
                     add_password: bool = False) -> authentication.Credentials:
    username = get_random_string()
    create_user(username, admin_credentials)

    password = ""
    if add_password:
        password = get_random_string()
        assert change_user_password(username, password, admin_credentials) == 0

    return authentication.Credentials(username, password)
def test_logout(clean_auth: None) -> None:
    # Tests fallback to default determined user
    creds = create_test_user(ADMIN_CREDENTIALS, True)

    # Set Determined password to something in order to disable auto-login.
    password = get_random_string()
    assert change_user_password(constants.DEFAULT_DETERMINED_USER, password,
                                ADMIN_CREDENTIALS) == 0

    # Log in as new user.
    with logged_in_user(creds):
        # Now we should be able to list experiments.
        child = det_spawn(["e", "list"])
        child.read()
        child.wait()
        child.close()
        assert child.status == 0

        # Exiting the logged_in_user context logs out and asserts that the exit code is 0.

    # Now trying to list experiments should result in an error.
    child = det_spawn(["e", "list"])
    child.expect(".*Unauthenticated.*", timeout=EXPECT_TIMEOUT)
    child.read()
    child.wait()
    assert child.exitstatus != 0

    # Log in as determined.
    log_in_user(
        authentication.Credentials(constants.DEFAULT_DETERMINED_USER,
                                   password))

    # Log back in as new user.
    log_in_user(creds)

    # Now log out as determined.
    assert log_out_user(constants.DEFAULT_DETERMINED_USER) == 0

    # Should still be able to list experiments because new user is logged in.
    child = det_spawn(["e", "list"])
    child.read()
    child.wait()
    child.close()
    assert child.status == 0

    # Change Determined passwordback to "".
    change_user_password(constants.DEFAULT_DETERMINED_USER, "",
                         ADMIN_CREDENTIALS)
def test_change_password(clean_auth: None) -> None:
    # Create a user without a password.
    creds = create_test_user(ADMIN_CREDENTIALS, False)

    # Attempt to log in.
    assert log_in_user(creds) == 0

    # Log out.
    assert log_out_user() == 0

    newPassword = get_random_string()
    assert change_user_password(creds.username, newPassword,
                                ADMIN_CREDENTIALS) == 0

    assert log_in_user(authentication.Credentials(creds.username,
                                                  newPassword)) == 0
from typing import Dict, Generator, Iterator, List, Optional, Tuple, cast

import appdirs
import pexpect
import pytest
from pexpect import spawn

from determined.common import constants, yaml
from determined.common.api import authentication
from tests import command
from tests import config as conf
from tests import experiment as exp
from tests.filetree import FileTree

EXPECT_TIMEOUT = 5
ADMIN_CREDENTIALS = authentication.Credentials("admin", "")
logger = logging.getLogger(__name__)


@pytest.fixture(scope="session")
def clean_auth() -> Iterator[None]:
    """
    clean_auth is a session-level fixture that ensures that we run tests with no preconfigured
    authentication, and that any settings we save during tests are cleaned up afterwards.
    """
    authentication.TokenStore(conf.make_master_url()).delete_token_cache()
    yield None
    authentication.TokenStore(conf.make_master_url()).delete_token_cache()


@contextlib.contextmanager