diff --git a/docs/index.rst b/docs/index.rst --- a/docs/index.rst +++ b/docs/index.rst @@ -9,7 +9,7 @@ If you have a user account registered on `Software Heritage Identity Provider`_, it is possible to authenticate requests made to the Web APIs through the use of -a OpenID Connect bearer token. Sending authenticated requests can notably +an OpenID Connect bearer token. Sending authenticated requests can notably allow to lift API rate limiting depending on your permissions. To get this token, a dedicated CLI tool is made available when installing @@ -28,24 +28,27 @@ Options: --oidc-server-url TEXT URL of OpenID Connect server (default to "https://auth.softwareheritage.org/auth/") + --realm-name TEXT Name of the OpenID Connect authentication realm (default to "SoftwareHeritage") + --client-id TEXT OpenID Connect client identifier in the realm (default to "swh-web") + -h, --help Show this message and exit. Commands: - login Login and create new offline OpenID Connect session. - logout Logout from an offline OpenID Connect session. + generate-token Generate a new bearer token for Web API authentication. + revoke-token Revoke a bearer token used for Web API authentication. -In order to get your tokens, you need to use the ``login`` subcommand of -that CLI tool by passing your username as argument. You will be prompted +In order to get your tokens, you need to use the ``generate-token`` subcommand of +the CLI tool by passing your username as argument. You will be prompted for your password and if the authentication succeeds a new OpenID Connect -session will be created and tokens will be dumped to standard output. +offline session will be created and token will be dumped to standard output. .. code-block:: text - $ swh auth login + $ swh auth generate-token Password: eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJmNjMzMD... @@ -70,13 +73,14 @@ # All requests to the Web API will be authenticated resp = client.get('swh:1:rev:aafb16d69fd30ff58afdd69036a26047f3aebdc6') -It is also possible to ``logout`` from the authenticated OpenID Connect session -which definitely revokes the token. +It is also possible to revoke a token, preventing future Web API authentication +when using it. The ``revoke-token`` subcommand of the CLI tool has to be used +to perform that task. .. code-block:: text - $ swh auth logout $REFRESH_TOKEN - Successfully logged out from OpenID Connect session + $ swh auth revoke-token $REFRESH_TOKEN + Token successfully revoked. API Reference ------------- diff --git a/swh/web/client/cli.py b/swh/web/client/cli.py --- a/swh/web/client/cli.py +++ b/swh/web/client/cli.py @@ -54,17 +54,17 @@ ) -@auth.command("login") +@auth.command("generate-token") @click.argument("username") @click.pass_context -def login(ctx: Context, username: str): +def generate_token(ctx: Context, username: str): """ - Login and create new offline OpenID Connect session. + Generate a new bearer token for Web API authentication. Login with USERNAME, create a new OpenID Connect session and get bearer token. - User will be prompted for his password and tokens will be printed + User will be prompted for his password and token will be printed to standard output. The created OpenID Connect session is an offline one so the provided @@ -82,16 +82,36 @@ print(oidc_info) -@auth.command("logout") +@auth.command("login", deprecated=True) +@click.argument("username") +@click.pass_context +def login(ctx: Context, username: str): + """ + Alias for 'generate-token' + """ + ctx.forward(generate_token) + + +@auth.command("revoke-token") @click.argument("token") @click.pass_context -def logout(ctx: Context, token: str): +def revoke_token(ctx: Context, token: str): """ - Logout from an offline OpenID Connect session. + Revoke a bearer token used for Web API authentication. Use TOKEN to logout from an offline OpenID Connect session. The token is definitely revoked after that operation. """ ctx.obj["oidc_session"].logout(token) - print("Successfully logged out from OpenID Connect session") + print("Token successfully revoked.") + + +@auth.command("logout", deprecated=True) +@click.argument("token") +@click.pass_context +def logout(ctx: Context, token: str): + """ + Alias for 'revoke-token' + """ + ctx.forward(revoke_token) diff --git a/swh/web/client/tests/test_cli.py b/swh/web/client/tests/test_cli.py --- a/swh/web/client/tests/test_cli.py +++ b/swh/web/client/tests/test_cli.py @@ -20,31 +20,35 @@ } -def test_auth_login(mocker): +def test_auth_generate_token(mocker): mock_getpass = mocker.patch("getpass.getpass") mock_getpass.return_value = "password" mock_oidc_session = mocker.patch("swh.web.client.auth.OpenIDConnectSession") mock_login = mock_oidc_session.return_value.login mock_login.return_value = oidc_profile - result = runner.invoke(auth, ["login", "username"], input="password\n") - assert result.exit_code == 0 - assert result.output[:-1] == oidc_profile["refresh_token"] + for command in ("generate-token", "login"): + mock_login.side_effect = None + result = runner.invoke(auth, [command, "username"], input="password\n") + assert result.exit_code == 0 + assert oidc_profile["refresh_token"] in result.output - mock_login.side_effect = Exception("Auth error") + mock_login.side_effect = Exception("Auth error") - result = runner.invoke(auth, ["login", "username"], input="password\n") - assert result.exit_code == 1 + result = runner.invoke(auth, [command, "username"], input="password\n") + assert result.exit_code == 1 -def test_auth_logout(mocker): +def test_auth_revoke_token(mocker): mock_oidc_session = mocker.patch("swh.web.client.auth.OpenIDConnectSession") mock_logout = mock_oidc_session.return_value.logout - result = runner.invoke(auth, ["logout", oidc_profile["refresh_token"]]) - assert result.exit_code == 0 + for command in ("revoke-token", "logout"): + mock_logout.side_effect = None + result = runner.invoke(auth, [command, oidc_profile["refresh_token"]]) + assert result.exit_code == 0 - mock_logout.side_effect = Exception("Auth error") - result = runner.invoke(auth, ["logout", oidc_profile["refresh_token"]]) - assert result.exit_code == 1 + mock_logout.side_effect = Exception("Auth error") + result = runner.invoke(auth, [command, oidc_profile["refresh_token"]]) + assert result.exit_code == 1