diff --git a/swh/auth/keycloak.py b/swh/auth/keycloak.py --- a/swh/auth/keycloak.py +++ b/swh/auth/keycloak.py @@ -83,6 +83,26 @@ **extra_params, ) + def login( + self, username: str, password: str, **extra_params: str + ) -> Dict[str, Any]: + """ + Get OpenID Connect authentication tokens using Direct Access Grant flow. + + Args: + username: an existing username in the realm + password: password associated to username + extra_params: Extra parameters to add in the authorization request + payload. + """ + return self._keycloak.token( + grant_type="password", + scope="openid", + username=username, + password=password, + **extra_params, + ) + def refresh_token(self, refresh_token: str) -> Dict[str, Any]: """ Request a new access token from Keycloak using a refresh token. diff --git a/swh/auth/pytest_plugin.py b/swh/auth/pytest_plugin.py --- a/swh/auth/pytest_plugin.py +++ b/swh/auth/pytest_plugin.py @@ -124,12 +124,14 @@ # method "Cannot assign to a method affecting mock". Ignore for now. self.authorization_code = Mock() # type: ignore self.refresh_token = Mock() # type: ignore + self.login = Mock() # type: ignore self.userinfo = Mock() # type: ignore self.logout = Mock() # type: ignore self.auth_success = auth_success if auth_success: self.authorization_code.return_value = copy(oidc_profile) self.refresh_token.return_value = copy(oidc_profile) + self.login.return_value = copy(oidc_profile) self.userinfo.return_value = copy(user_info) else: self.authorization_url = Mock() # type: ignore diff --git a/swh/auth/tests/test_keycloak.py b/swh/auth/tests/test_keycloak.py --- a/swh/auth/tests/test_keycloak.py +++ b/swh/auth/tests/test_keycloak.py @@ -93,3 +93,8 @@ expected_decoded_token.pop(dynamic_valued_key) assert actual_decoded_data2 == expected_decoded_token + + +def test_keycloak_login(keycloak_mock): + actual_response = keycloak_mock.login("username", "password") + assert actual_response == OIDC_PROFILE