Page Menu
Home
Software Heritage
Search
Configure Global Search
Log In
Files
F9312055
D5955.id21384.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
11 KB
Subscribers
None
D5955.id21384.diff
View Options
diff --git a/conftest.py b/conftest.py
new file mode 100644
--- /dev/null
+++ b/conftest.py
@@ -0,0 +1 @@
+pytest_plugins = ["swh.auth.pytest_plugin"]
diff --git a/docs/index.rst b/docs/index.rst
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -17,13 +17,13 @@
.. code-block:: text
- $ swh web auth
- Usage: swh web auth [OPTIONS] COMMAND [ARGS]...
+ $ swh auth
+ Usage: swh auth [OPTIONS] COMMAND [ARGS]...
- Authenticate Software Heritage users with OpenID Connect.
+ Software Heritage Authentication tools.
- This CLI tool eases the retrieval of bearer tokens to authenticate a user
- querying the Software Heritage Web API.
+ This CLI eases the retrieval of a bearer token to authenticate a user
+ querying Software Heritage Web APIs.
Options:
--oidc-server-url TEXT URL of OpenID Connect server (default to
@@ -38,10 +38,8 @@
-h, --help Show this message and exit.
Commands:
- generate-token Generate a new bearer token for Web API authentication.
- login Alias for 'generate-token'
- logout Alias for 'revoke-token'
- revoke-token Revoke a bearer token used for Web API authentication.
+ generate-token Generate a new bearer token for a Web API authentication.
+ revoke-token Revoke a bearer token used for a Web API authentication.
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
@@ -50,7 +48,7 @@
.. code-block:: text
- $ swh web auth generate-token <username>
+ $ swh auth --client-id swh-web generate-token <username>
Password:
eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJmNjMzMD...
@@ -81,7 +79,7 @@
.. code-block:: text
- $ swh web auth revoke-token $REFRESH_TOKEN
+ $ swh auth --client-id swh-web revoke-token $REFRESH_TOKEN
Token successfully revoked.
API Reference
diff --git a/requirements-swh.txt b/requirements-swh.txt
--- a/requirements-swh.txt
+++ b/requirements-swh.txt
@@ -1,3 +1,4 @@
# Add here internal Software Heritage dependencies, one per line.
+swh.auth >= 0.6
swh.core >= 0.3
swh.model
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -69,6 +69,6 @@
},
entry_points="""
[swh.cli.subcommands]
- auth=swh.web.client.cli
+ web=swh.web.client.cli
""",
)
diff --git a/swh/web/client/auth.py b/swh/web/client/auth.py
deleted file mode 100644
--- a/swh/web/client/auth.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# Copyright (C) 2020 The Software Heritage developers
-# See the AUTHORS file at the top-level directory of this distribution
-# License: GNU General Public License version 3, or any later version
-# See top-level LICENSE file for more information
-
-from typing import Any, Dict
-from urllib.parse import urljoin
-
-import requests
-
-SWH_OIDC_SERVER_URL = "https://auth.softwareheritage.org/auth/"
-SWH_REALM_NAME = "SoftwareHeritage"
-SWH_WEB_CLIENT_ID = "swh-web"
-
-
-class AuthenticationError(Exception):
- """Authentication related error.
-
- Example: A bearer token has been revoked.
-
- """
-
- pass
-
-
-class OpenIDConnectSession:
- """
- Simple class wrapping requests sent to an OpenID Connect server.
-
- Args:
- oidc_server_url: URL of OpenID Connect server
- realm_name: name of the OpenID Connect authentication realm
- client_id: OpenID Connect client identifier in the realm
- """
-
- def __init__(
- self,
- oidc_server_url: str = SWH_OIDC_SERVER_URL,
- realm_name: str = SWH_REALM_NAME,
- client_id: str = SWH_WEB_CLIENT_ID,
- ):
- realm_url = urljoin(oidc_server_url, f"realms/{realm_name}/")
- self.client_id = client_id
- self.token_url = urljoin(realm_url, "protocol/openid-connect/token/")
- self.logout_url = urljoin(realm_url, "protocol/openid-connect/logout/")
-
- def login(self, username: str, password: str) -> Dict[str, Any]:
- """
- Login and create new offline OpenID Connect session.
-
- Args:
- username: an existing username in the realm
- password: password associated to username
-
- Returns:
- The OpenID Connect session info
- """
- return requests.post(
- url=self.token_url,
- data={
- "grant_type": "password",
- "client_id": self.client_id,
- "scope": "openid offline_access",
- "username": username,
- "password": password,
- },
- ).json()
-
- def logout(self, token: str):
- """
- Logout from an offline OpenID Connect session and invalidate
- previously emitted tokens.
-
- Args:
- token: a bearer token retrieved after login
- """
- requests.post(
- url=self.logout_url,
- data={
- "client_id": self.client_id,
- "scope": "openid",
- "refresh_token": token,
- },
- )
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
@@ -11,6 +11,9 @@
import click
from click.core import Context
+from swh.auth.cli import auth as auth_cli
+from swh.auth.cli import generate_token as auth_generate_token
+from swh.auth.cli import revoke_token as auth_revoke_token
from swh.core.cli import swh as swh_cli_group
CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
@@ -178,48 +181,25 @@
print(json.dumps(processed_origins))
-@web.group(name="auth", context_settings=CONTEXT_SETTINGS)
-@click.option(
- "--oidc-server-url",
- "oidc_server_url",
- default="https://auth.softwareheritage.org/auth/",
- help=(
- "URL of OpenID Connect server (default to "
- '"https://auth.softwareheritage.org/auth/")'
- ),
-)
-@click.option(
- "--realm-name",
- "realm_name",
- default="SoftwareHeritage",
- help=(
- "Name of the OpenID Connect authentication realm "
- '(default to "SoftwareHeritage")'
- ),
-)
-@click.option(
- "--client-id",
- "client_id",
- default="swh-web",
- help=("OpenID Connect client identifier in the realm " '(default to "swh-web")'),
-)
+def _forward_context(ctx: Context, *args, **kwargs):
+ ctx.forward(*args, **kwargs)
+
+
+@web.group(name="auth", context_settings=CONTEXT_SETTINGS, deprecated=True)
@click.pass_context
-def auth(ctx: Context, oidc_server_url: str, realm_name: str, client_id: str):
+def auth(ctx: Context):
"""
Authenticate Software Heritage users with OpenID Connect.
This CLI tool eases the retrieval of a bearer token to authenticate
a user querying the Software Heritage Web API.
- """
- from swh.web.client.auth import OpenIDConnectSession
- ctx.ensure_object(dict)
- ctx.obj["oidc_session"] = OpenIDConnectSession(
- oidc_server_url, realm_name, client_id
- )
+ That command group is deprecated, use ``swh auth`` instead.
+ """
+ _forward_context(ctx, auth_cli, client_id="swh-web")
-@auth.command("generate-token")
+@auth.command("generate-token", deprecated=True)
@click.argument("username")
@click.pass_context
def generate_token(ctx: Context, username: str):
@@ -236,28 +216,10 @@
token has a much longer expiration time than classical OIDC
sessions (usually several dozens of days).
"""
- from getpass import getpass
-
- password = getpass()
-
- oidc_info = ctx.obj["oidc_session"].login(username, password)
- if "refresh_token" in oidc_info:
- print(oidc_info["refresh_token"])
- else:
- print(oidc_info)
+ _forward_context(ctx, auth_generate_token, username=username)
-@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")
+@auth.command("revoke-token", deprecated=True)
@click.argument("token")
@click.pass_context
def revoke_token(ctx: Context, token: str):
@@ -268,15 +230,4 @@
The token is definitely revoked after that operation.
"""
- ctx.obj["oidc_session"].logout(token)
- 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)
+ _forward_context(ctx, auth_revoke_token, token=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
@@ -8,53 +8,37 @@
from click.testing import CliRunner
-from swh.web.client.cli import auth, web
+from swh.web.client.cli import auth_cli, auth_generate_token, auth_revoke_token, web
runner = CliRunner()
-oidc_profile = {
- "access_token": "some-access-token",
- "expires_in": 600,
- "refresh_expires_in": 0,
- "refresh_token": "some-refresh-token",
- "token_type": "bearer",
- "session_state": "some-state",
- "scope": "openid email profile offline_access",
-}
-
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
-
- 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")
-
- result = runner.invoke(auth, [command, "username"], input="password\n")
- assert result.exit_code == 1
+ forward_context = mocker.patch("swh.web.client.cli._forward_context")
+ runner.invoke(web, ["auth", "generate-token", "username"])
+ assert forward_context.call_count == 2
+ ctx = forward_context.call_args_list[0][0][0]
+ ctx2 = forward_context.call_args_list[1][0][0]
+ forward_context.assert_has_calls(
+ [
+ mocker.call(ctx, auth_cli, client_id="swh-web"),
+ mocker.call(ctx2, auth_generate_token, username="username"),
+ ]
+ )
def test_auth_revoke_token(mocker):
-
- mock_oidc_session = mocker.patch("swh.web.client.auth.OpenIDConnectSession")
- mock_logout = mock_oidc_session.return_value.logout
-
- 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, [command, oidc_profile["refresh_token"]])
- assert result.exit_code == 1
+ forward_context = mocker.patch("swh.web.client.cli._forward_context")
+ runner.invoke(web, ["auth", "revoke-token", "token"])
+ assert forward_context.call_count == 2
+ ctx = forward_context.call_args_list[0][0][0]
+ ctx2 = forward_context.call_args_list[1][0][0]
+ forward_context.assert_has_calls(
+ [
+ mocker.call(ctx, auth_cli, client_id="swh-web"),
+ mocker.call(ctx2, auth_revoke_token, token="token"),
+ ]
+ )
def test_save_code_now_through_cli(mocker, web_api_mock, tmp_path, cli_config_path):
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Jul 2, 10:41 AM (2 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3217141
Attached To
D5955: cli: Deprecate auth command group
Event Timeline
Log In to Comment