Пример #1
0
async def test_create_token(driver: webdriver.Chrome,
                            selenium_config: SeleniumConfig) -> None:
    cookie = State(token=selenium_config.token).as_cookie()
    driver.header_overrides = {"Cookie": f"{COOKIE_NAME}={cookie}"}

    tokens_url = urljoin(selenium_config.url, "/auth/tokens")
    driver.get(tokens_url)

    tokens_page = TokensPage(driver)
    assert tokens_page.get_tokens(TokenType.user) == []
    session_tokens = tokens_page.get_tokens(TokenType.session)
    assert len(session_tokens) == 1
    assert session_tokens[0].token == selenium_config.token.key

    # Drop our cookie in favor of the one the browser is now sending, since
    # the browser one contains a CSRF token that will be required for token
    # creation.
    del driver.header_overrides

    create_modal = await tokens_page.click_create_token()
    create_modal.set_token_name("test token")
    await create_modal.submit()

    new_token_modal = tokens_page.get_new_token_modal()
    assert new_token_modal.token.startswith("gt-")
    new_token_modal.dismiss()

    user_tokens = tokens_page.get_tokens(TokenType.user)
    assert len(user_tokens) == 1
    assert user_tokens[0].name == "test token"
Пример #2
0
async def test_login_no_auth(setup: SetupTest) -> None:
    r = await setup.client.get("/auth/api/v1/login")
    assert_unauthorized_is_correct(r, setup.config)

    # An Authorization header with a valid token still redirects.
    token_data = await setup.create_session_token()
    r = await setup.client.get(
        "/auth/api/v1/login",
        headers={"Authorization": f"bearer {token_data.token}"},
    )
    assert_unauthorized_is_correct(r, setup.config)

    # A token with no underlying Redis representation is ignored.
    state = State(token=Token())
    r = await setup.client.get(
        "/auth/api/v1/login",
        cookies={COOKIE_NAME: state.as_cookie()},
    )
    assert_unauthorized_is_correct(r, setup.config)

    # Likewise with a cookie containing a malformed token.  This requires a
    # bit more work to assemble.
    key = setup.config.session_secret.encode()
    fernet = Fernet(key)
    data = {"token": "bad-token"}
    bad_cookie = fernet.encrypt(json.dumps(data).encode()).decode()
    r = await setup.client.get(
        "/auth/api/v1/login",
        cookies={COOKIE_NAME: bad_cookie},
    )
    assert_unauthorized_is_correct(r, setup.config)

    # And finally check with a mangled state that won't decrypt.
    bad_cookie = "XXX" + state.as_cookie()
    r = await setup.client.get(
        "/auth/api/v1/login",
        cookies={COOKIE_NAME: bad_cookie},
    )
    assert_unauthorized_is_correct(r, setup.config)
Пример #3
0
async def test_auth_required(setup: SetupTest) -> None:
    token_data = await setup.create_session_token()
    token = token_data.token
    csrf = await setup.login(token)

    # Replace the cookie with one containing the CSRF token but not the
    # authentication token.
    setup.logout()
    setup.client.cookies[COOKIE_NAME] = State(csrf=csrf).as_cookie()

    r = await setup.client.post(
        "/auth/api/v1/tokens",
        headers={"X-CSRF-Token": csrf},
        json={
            "username": "******",
            "token_type": "service"
        },
    )
    assert r.status_code == 401

    r = await setup.client.get("/auth/api/v1/users/example/tokens")
    assert r.status_code == 401

    r = await setup.client.post(
        "/auth/api/v1/users/example/tokens",
        headers={"X-CSRF-Token": csrf},
        json={"token_name": "some token"},
    )
    assert r.status_code == 401

    r = await setup.client.get(f"/auth/api/v1/users/example/tokens/{token.key}"
                               )
    assert r.status_code == 401

    r = await setup.client.get(
        f"/auth/api/v1/users/example/tokens/{token.key}/change-history")
    assert r.status_code == 401

    r = await setup.client.delete(
        f"/auth/api/v1/users/example/tokens/{token.key}",
        headers={"X-CSRF-Token": csrf},
    )
    assert r.status_code == 401

    r = await setup.client.patch(
        f"/auth/api/v1/users/example/tokens/{token.key}",
        headers={"X-CSRF-Token": csrf},
        json={"token_name": "some token"},
    )
    assert r.status_code == 401
Пример #4
0
async def test_login(setup: SetupTest) -> None:
    token_data = await setup.create_session_token(
        username="******", scopes=["read:all", "exec:admin"]
    )
    cookie = State(token=token_data.token).as_cookie()
    setup.client.cookies.set(COOKIE_NAME, cookie, domain=TEST_HOSTNAME)

    r = await setup.client.get("/auth/api/v1/login", allow_redirects=False)

    assert r.status_code == 200
    data = r.json()
    expected_scopes = [
        {"name": n, "description": d}
        for n, d in sorted(setup.config.known_scopes.items())
    ]
    assert data == {
        "csrf": ANY,
        "username": "******",
        "scopes": ["exec:admin", "read:all"],
        "config": {"scopes": expected_scopes},
    }
    state = State.from_cookie(r.cookies[COOKIE_NAME], None)
    assert state.csrf == data["csrf"]
    assert state.token == token_data.token
Пример #5
0
async def get_logout(
    return_url: Optional[str] = Depends(return_url),
    context: RequestContext = Depends(context_dependency),
) -> RedirectResponse:
    """Log out and redirect the user.

    The user is redirected to the URL given in the rd parameter, if any, and
    otherwise to the after_logout_url configuration setting.
    """
    if context.state.token:
        context.logger.info("Successful logout")
    else:
        context.logger.info("Logout of already-logged-out session")
    context.state = State()

    if not return_url:
        return_url = context.config.after_logout_url
    return RedirectResponse(return_url)
Пример #6
0
    async def login(self, token: Token) -> str:
        """Create a valid Gafaelfawr session.

        Add a valid Gafaelfawr session cookie to the `httpx.AsyncClient`, use
        the login URL, and return the resulting CSRF token.

        Parameters
        ----------
        token : `gafaelfawr.models.token.Token`
            The token for the client identity to use.

        Returns
        -------
        csrf : `str`
            The CSRF token to use in subsequent API requests.
        """
        cookie = State(token=token).as_cookie()
        self.client.cookies.set(COOKIE_NAME, cookie, domain=TEST_HOSTNAME)
        r = await self.client.get("/auth/api/v1/login")
        assert r.status_code == 200
        return r.json()["csrf"]
Пример #7
0
async def test_token_info(setup: SetupTest) -> None:
    user_info = TokenUserInfo(
        username="******",
        name="Example Person",
        email="*****@*****.**",
        uid=45613,
        groups=[TokenGroup(name="foo", id=12313)],
    )
    token_service = setup.factory.create_token_service()
    session_token = await token_service.create_session_token(
        user_info, scopes=["exec:admin", "user:token"], ip_address="127.0.0.1")

    r = await setup.client.get(
        "/auth/api/v1/token-info",
        headers={"Authorization": f"bearer {session_token}"},
    )
    assert r.status_code == 200
    data = r.json()
    assert data == {
        "token": session_token.key,
        "username": "******",
        "token_type": "session",
        "scopes": ["exec:admin", "user:token"],
        "created": ANY,
        "expires": ANY,
    }
    now = datetime.now(tz=timezone.utc)
    created = datetime.fromtimestamp(data["created"], tz=timezone.utc)
    assert now - timedelta(seconds=2) <= created <= now
    expires = created + timedelta(minutes=setup.config.issuer.exp_minutes)
    assert datetime.fromtimestamp(data["expires"], tz=timezone.utc) == expires

    r = await setup.client.get(
        "/auth/api/v1/user-info",
        headers={"Authorization": f"bearer {session_token}"},
    )
    assert r.status_code == 200
    session_user_info = r.json()
    assert session_user_info == {
        "username": "******",
        "name": "Example Person",
        "email": "*****@*****.**",
        "uid": 45613,
        "groups": [{
            "name": "foo",
            "id": 12313,
        }],
    }

    # Check the same with a user token, which has some additional associated
    # data.
    expires = now + timedelta(days=100)
    data = await token_service.get_data(session_token)
    user_token = await token_service.create_user_token(
        data,
        data.username,
        token_name="some-token",
        scopes=["exec:admin"],
        expires=expires,
        ip_address="127.0.0.1",
    )

    r = await setup.client.get(
        "/auth/api/v1/token-info",
        headers={"Authorization": f"bearer {user_token}"},
    )
    assert r.status_code == 200
    data = r.json()
    assert data == {
        "token": user_token.key,
        "username": "******",
        "token_type": "user",
        "token_name": "some-token",
        "scopes": ["exec:admin"],
        "created": ANY,
        "expires": int(expires.timestamp()),
    }

    r = await setup.client.get(
        "/auth/api/v1/user-info",
        headers={"Authorization": f"bearer {user_token}"},
    )
    assert r.status_code == 200
    assert r.json() == session_user_info

    # Test getting a list of tokens for a user.
    state = State(token=session_token)
    r = await setup.client.get(
        "/auth/api/v1/users/example/tokens",
        cookies={COOKIE_NAME: state.as_cookie()},
    )