Changeset View
Changeset View
Standalone View
Standalone View
swh/web/tests/auth/test_views.py
Show All 10 Lines | |||||
import pytest | import pytest | ||||
from django.contrib.auth.models import AnonymousUser, User | from django.contrib.auth.models import AnonymousUser, User | ||||
from django.http import QueryDict | from django.http import QueryDict | ||||
from swh.web.auth.models import OIDCUser, OIDCUserOfflineTokens | from swh.web.auth.models import OIDCUser, OIDCUserOfflineTokens | ||||
from swh.web.auth.utils import OIDC_SWH_WEB_CLIENT_ID | from swh.web.auth.utils import OIDC_SWH_WEB_CLIENT_ID | ||||
from swh.web.common.utils import reverse | from swh.web.common.utils import reverse | ||||
from swh.web.tests.django_asserts import assert_contains, assert_template_used | from swh.web.tests.django_asserts import assert_contains | ||||
from swh.web.tests.utils import ( | |||||
check_html_get_response, | |||||
check_http_get_response, | |||||
check_http_post_response, | |||||
) | |||||
from swh.web.urls import _default_view as homepage_view | from swh.web.urls import _default_view as homepage_view | ||||
from . import sample_data | from . import sample_data | ||||
from .keycloak_mock import mock_keycloak | from .keycloak_mock import mock_keycloak | ||||
@pytest.mark.django_db | @pytest.mark.django_db | ||||
def test_oidc_login_views_success(client, mocker): | def test_oidc_login_views_success(client, mocker): | ||||
""" | """ | ||||
Simulate a successful login authentication with OpenID Connect | Simulate a successful login authentication with OpenID Connect | ||||
authorization code flow with PKCE. | authorization code flow with PKCE. | ||||
""" | """ | ||||
# mock Keycloak client | # mock Keycloak client | ||||
kc_oidc_mock = mock_keycloak(mocker) | kc_oidc_mock = mock_keycloak(mocker) | ||||
# user initiates login process | # user initiates login process | ||||
login_url = reverse("oidc-login") | login_url = reverse("oidc-login") | ||||
response = client.get(login_url) | |||||
request = response.wsgi_request | |||||
# should redirect to Keycloak authentication page in order | # should redirect to Keycloak authentication page in order | ||||
# for a user to login with its username / password | # for a user to login with its username / password | ||||
assert response.status_code == 302 | response = check_html_get_response(client, login_url, status_code=302) | ||||
request = response.wsgi_request | |||||
assert isinstance(request.user, AnonymousUser) | assert isinstance(request.user, AnonymousUser) | ||||
parsed_url = urlparse(response["location"]) | parsed_url = urlparse(response["location"]) | ||||
authorization_url = kc_oidc_mock.well_known()["authorization_endpoint"] | authorization_url = kc_oidc_mock.well_known()["authorization_endpoint"] | ||||
query_dict = QueryDict(parsed_url.query) | query_dict = QueryDict(parsed_url.query) | ||||
# check redirect url is valid | # check redirect url is valid | ||||
Show All 32 Lines | login_complete_url = reverse( | ||||
"oidc-login-complete", | "oidc-login-complete", | ||||
query_params={ | query_params={ | ||||
"code": code, | "code": code, | ||||
"state": login_data["state"], | "state": login_data["state"], | ||||
"session_state": session_state, | "session_state": session_state, | ||||
}, | }, | ||||
) | ) | ||||
# login process finalization | # login process finalization, should redirect to root url by default | ||||
response = client.get(login_complete_url) | response = check_html_get_response(client, login_complete_url, status_code=302) | ||||
request = response.wsgi_request | request = response.wsgi_request | ||||
# should redirect to root url by default | |||||
assert response.status_code == 302 | |||||
assert response["location"] == request.build_absolute_uri("/") | assert response["location"] == request.build_absolute_uri("/") | ||||
# user should be authenticated | # user should be authenticated | ||||
assert isinstance(request.user, OIDCUser) | assert isinstance(request.user, OIDCUser) | ||||
# check remote user has not been saved to Django database | # check remote user has not been saved to Django database | ||||
with pytest.raises(User.DoesNotExist): | with pytest.raises(User.DoesNotExist): | ||||
User.objects.get(username=request.user.username) | User.objects.get(username=request.user.username) | ||||
@pytest.mark.django_db | @pytest.mark.django_db | ||||
def test_oidc_logout_view_success(client, mocker): | def test_oidc_logout_view_success(client, mocker): | ||||
""" | """ | ||||
Simulate a successful logout operation with OpenID Connect. | Simulate a successful logout operation with OpenID Connect. | ||||
""" | """ | ||||
# mock Keycloak client | # mock Keycloak client | ||||
kc_oidc_mock = mock_keycloak(mocker) | kc_oidc_mock = mock_keycloak(mocker) | ||||
# login our test user | # login our test user | ||||
client.login(code="", code_verifier="", redirect_uri="") | client.login(code="", code_verifier="", redirect_uri="") | ||||
kc_oidc_mock.authorization_code.assert_called() | kc_oidc_mock.authorization_code.assert_called() | ||||
# user initiates logout | # user initiates logout | ||||
oidc_logout_url = reverse("oidc-logout") | oidc_logout_url = reverse("oidc-logout") | ||||
response = client.get(oidc_logout_url) | |||||
request = response.wsgi_request | |||||
# should redirect to logout page | # should redirect to logout page | ||||
assert response.status_code == 302 | response = check_html_get_response(client, oidc_logout_url, status_code=302) | ||||
request = response.wsgi_request | |||||
logout_url = reverse("logout", query_params={"remote_user": 1}) | logout_url = reverse("logout", query_params={"remote_user": 1}) | ||||
assert response["location"] == request.build_absolute_uri(logout_url) | assert response["location"] == request.build_absolute_uri(logout_url) | ||||
# should have been logged out in Keycloak | # should have been logged out in Keycloak | ||||
kc_oidc_mock.logout.assert_called_with(sample_data.oidc_profile["refresh_token"]) | kc_oidc_mock.logout.assert_called_with(sample_data.oidc_profile["refresh_token"]) | ||||
# check effective logout in Django | # check effective logout in Django | ||||
assert isinstance(request.user, AnonymousUser) | assert isinstance(request.user, AnonymousUser) | ||||
@pytest.mark.django_db | @pytest.mark.django_db | ||||
def test_oidc_login_view_failure(client, mocker): | def test_oidc_login_view_failure(client, mocker): | ||||
""" | """ | ||||
Simulate a failed authentication with OpenID Connect. | Simulate a failed authentication with OpenID Connect. | ||||
""" | """ | ||||
# mock Keycloak client | # mock Keycloak client | ||||
mock_keycloak(mocker, auth_success=False) | mock_keycloak(mocker, auth_success=False) | ||||
# user initiates login process | # user initiates login process | ||||
login_url = reverse("oidc-login") | login_url = reverse("oidc-login") | ||||
response = client.get(login_url) | |||||
request = response.wsgi_request | |||||
# should render an error page | # should render an error page | ||||
assert response.status_code == 500 | response = check_html_get_response( | ||||
assert_template_used(response, "error.html") | client, login_url, status_code=500, template_used="error.html" | ||||
) | |||||
request = response.wsgi_request | |||||
# no users should be logged in | # no users should be logged in | ||||
assert isinstance(request.user, AnonymousUser) | assert isinstance(request.user, AnonymousUser) | ||||
# Simulate possible errors with OpenID Connect in the login complete view. | # Simulate possible errors with OpenID Connect in the login complete view. | ||||
def test_oidc_login_complete_view_no_login_data(client, mocker): | def test_oidc_login_complete_view_no_login_data(client, mocker): | ||||
# user initiates login process | # user initiates login process | ||||
login_url = reverse("oidc-login-complete") | login_url = reverse("oidc-login-complete") | ||||
response = client.get(login_url) | |||||
# should render an error page | # should render an error page | ||||
assert_template_used(response, "error.html") | response = check_html_get_response( | ||||
client, login_url, status_code=500, template_used="error.html" | |||||
) | |||||
assert_contains( | assert_contains( | ||||
response, "Login process has not been initialized.", status_code=500 | response, "Login process has not been initialized.", status_code=500 | ||||
) | ) | ||||
def test_oidc_login_complete_view_missing_parameters(client, mocker): | def test_oidc_login_complete_view_missing_parameters(client, mocker): | ||||
# simulate login process has been initialized | # simulate login process has been initialized | ||||
session = client.session | session = client.session | ||||
session["login_data"] = { | session["login_data"] = { | ||||
"code_verifier": "", | "code_verifier": "", | ||||
"state": str(uuid.uuid4()), | "state": str(uuid.uuid4()), | ||||
"redirect_uri": "", | "redirect_uri": "", | ||||
"next_path": "", | "next_path": "", | ||||
"prompt": "", | "prompt": "", | ||||
} | } | ||||
session.save() | session.save() | ||||
# user initiates login process | # user initiates login process | ||||
login_url = reverse("oidc-login-complete") | login_url = reverse("oidc-login-complete") | ||||
response = client.get(login_url) | |||||
request = response.wsgi_request | |||||
# should render an error page | # should render an error page | ||||
assert_template_used(response, "error.html") | response = check_html_get_response( | ||||
client, login_url, status_code=400, template_used="error.html" | |||||
) | |||||
request = response.wsgi_request | |||||
assert_contains( | assert_contains( | ||||
response, "Missing query parameters for authentication.", status_code=400 | response, "Missing query parameters for authentication.", status_code=400 | ||||
) | ) | ||||
# no user should be logged in | # no user should be logged in | ||||
assert isinstance(request.user, AnonymousUser) | assert isinstance(request.user, AnonymousUser) | ||||
Show All 12 Lines | def test_oidc_login_complete_wrong_csrf_token(client, mocker): | ||||
} | } | ||||
session.save() | session.save() | ||||
# user initiates login process | # user initiates login process | ||||
login_url = reverse( | login_url = reverse( | ||||
"oidc-login-complete", query_params={"code": "some-code", "state": "some-state"} | "oidc-login-complete", query_params={"code": "some-code", "state": "some-state"} | ||||
) | ) | ||||
response = client.get(login_url) | |||||
request = response.wsgi_request | |||||
# should render an error page | # should render an error page | ||||
assert_template_used(response, "error.html") | response = check_html_get_response( | ||||
client, login_url, status_code=400, template_used="error.html" | |||||
) | |||||
request = response.wsgi_request | |||||
assert_contains( | assert_contains( | ||||
response, "Wrong CSRF token, aborting login process.", status_code=400 | response, "Wrong CSRF token, aborting login process.", status_code=400 | ||||
) | ) | ||||
# no user should be logged in | # no user should be logged in | ||||
assert isinstance(request.user, AnonymousUser) | assert isinstance(request.user, AnonymousUser) | ||||
Show All 14 Lines | def test_oidc_login_complete_wrong_code_verifier(client, mocker): | ||||
session.save() | session.save() | ||||
# check authentication error is reported | # check authentication error is reported | ||||
login_url = reverse( | login_url = reverse( | ||||
"oidc-login-complete", | "oidc-login-complete", | ||||
query_params={"code": "some-code", "state": session["login_data"]["state"]}, | query_params={"code": "some-code", "state": session["login_data"]["state"]}, | ||||
) | ) | ||||
response = client.get(login_url) | |||||
request = response.wsgi_request | |||||
# should render an error page | # should render an error page | ||||
assert_template_used(response, "error.html") | response = check_html_get_response( | ||||
client, login_url, status_code=500, template_used="error.html" | |||||
) | |||||
request = response.wsgi_request | |||||
assert_contains(response, "User authentication failed.", status_code=500) | assert_contains(response, "User authentication failed.", status_code=500) | ||||
# no user should be logged in | # no user should be logged in | ||||
assert isinstance(request.user, AnonymousUser) | assert isinstance(request.user, AnonymousUser) | ||||
@pytest.mark.django_db | @pytest.mark.django_db | ||||
def test_oidc_logout_view_failure(client, mocker): | def test_oidc_logout_view_failure(client, mocker): | ||||
""" | """ | ||||
Simulate a failed logout operation with OpenID Connect. | Simulate a failed logout operation with OpenID Connect. | ||||
""" | """ | ||||
# mock Keycloak client | # mock Keycloak client | ||||
kc_oidc_mock = mock_keycloak(mocker) | kc_oidc_mock = mock_keycloak(mocker) | ||||
# login our test user | # login our test user | ||||
client.login(code="", code_verifier="", redirect_uri="") | client.login(code="", code_verifier="", redirect_uri="") | ||||
err_msg = "Authentication server error" | err_msg = "Authentication server error" | ||||
kc_oidc_mock.logout.side_effect = Exception(err_msg) | kc_oidc_mock.logout.side_effect = Exception(err_msg) | ||||
# user initiates logout process | # user initiates logout process | ||||
logout_url = reverse("oidc-logout") | logout_url = reverse("oidc-logout") | ||||
response = client.get(logout_url) | |||||
request = response.wsgi_request | |||||
# should render an error page | # should render an error page | ||||
assert_template_used(response, "error.html") | response = check_html_get_response( | ||||
client, logout_url, status_code=500, template_used="error.html" | |||||
) | |||||
request = response.wsgi_request | |||||
assert_contains(response, err_msg, status_code=500) | assert_contains(response, err_msg, status_code=500) | ||||
# user should be logged out from Django anyway | # user should be logged out from Django anyway | ||||
assert isinstance(request.user, AnonymousUser) | assert isinstance(request.user, AnonymousUser) | ||||
@pytest.mark.django_db | @pytest.mark.django_db | ||||
def test_oidc_silent_refresh_failure(client, mocker): | def test_oidc_silent_refresh_failure(client, mocker): | ||||
# mock Keycloak client | # mock Keycloak client | ||||
mock_keycloak(mocker) | mock_keycloak(mocker) | ||||
next_path = reverse("swh-web-homepage") | next_path = reverse("swh-web-homepage") | ||||
# silent session refresh initialization | # silent session refresh initialization | ||||
login_url = reverse( | login_url = reverse( | ||||
"oidc-login", query_params={"next_path": next_path, "prompt": "none"} | "oidc-login", query_params={"next_path": next_path, "prompt": "none"} | ||||
) | ) | ||||
response = client.get(login_url) | response = check_http_get_response(client, login_url, status_code=302) | ||||
request = response.wsgi_request | request = response.wsgi_request | ||||
login_data = request.session["login_data"] | login_data = request.session["login_data"] | ||||
# check prompt value has been registered in user session | # check prompt value has been registered in user session | ||||
assert "prompt" in login_data | assert "prompt" in login_data | ||||
assert login_data["prompt"] == "none" | assert login_data["prompt"] == "none" | ||||
# simulate a failed silent session refresh | # simulate a failed silent session refresh | ||||
session_state = str(uuid.uuid4()) | session_state = str(uuid.uuid4()) | ||||
login_complete_url = reverse( | login_complete_url = reverse( | ||||
"oidc-login-complete", | "oidc-login-complete", | ||||
query_params={ | query_params={ | ||||
"error": "login_required", | "error": "login_required", | ||||
"state": login_data["state"], | "state": login_data["state"], | ||||
"session_state": session_state, | "session_state": session_state, | ||||
}, | }, | ||||
) | ) | ||||
# login process finalization | # login process finalization, should redirect to logout page | ||||
response = client.get(login_complete_url) | response = check_http_get_response(client, login_complete_url, status_code=302) | ||||
request = response.wsgi_request | request = response.wsgi_request | ||||
# should redirect to logout page | |||||
assert response.status_code == 302 | |||||
logout_url = reverse( | logout_url = reverse( | ||||
"logout", query_params={"next_path": next_path, "remote_user": 1} | "logout", query_params={"next_path": next_path, "remote_user": 1} | ||||
) | ) | ||||
assert response["location"] == logout_url | assert response["location"] == logout_url | ||||
def test_view_rendering_when_user_not_set_in_request(request_factory): | def test_view_rendering_when_user_not_set_in_request(request_factory): | ||||
request = request_factory.get("/") | request = request_factory.get("/") | ||||
# Django RequestFactory do not set any user by default | # Django RequestFactory do not set any user by default | ||||
assert not hasattr(request, "user") | assert not hasattr(request, "user") | ||||
response = homepage_view(request) | response = homepage_view(request) | ||||
assert response.status_code == 200 | assert response.status_code == 200 | ||||
def test_oidc_generate_bearer_token_anonymous_user(client): | def test_oidc_generate_bearer_token_anonymous_user(client): | ||||
""" | """ | ||||
Anonymous user should be refused access with forbidden response. | Anonymous user should be refused access with forbidden response. | ||||
""" | """ | ||||
url = reverse("oidc-generate-bearer-token") | url = reverse("oidc-generate-bearer-token") | ||||
response = client.post(url, data={"password": "secret"}) | check_http_post_response(client, url, data={"password": "secret"}, status_code=403) | ||||
assert response.status_code == 403 | |||||
def _generate_bearer_token(client, password): | def _generate_bearer_token(client, password): | ||||
client.login( | client.login( | ||||
code="code", code_verifier="code-verifier", redirect_uri="redirect-uri" | code="code", code_verifier="code-verifier", redirect_uri="redirect-uri" | ||||
) | ) | ||||
url = reverse("oidc-generate-bearer-token") | url = reverse("oidc-generate-bearer-token") | ||||
return client.post( | return client.post( | ||||
Show All 32 Lines | |||||
def test_oidc_list_bearer_tokens_anonymous_user(client): | def test_oidc_list_bearer_tokens_anonymous_user(client): | ||||
""" | """ | ||||
Anonymous user should be refused access with forbidden response. | Anonymous user should be refused access with forbidden response. | ||||
""" | """ | ||||
url = reverse( | url = reverse( | ||||
"oidc-list-bearer-tokens", query_params={"draw": 1, "start": 0, "length": 10} | "oidc-list-bearer-tokens", query_params={"draw": 1, "start": 0, "length": 10} | ||||
) | ) | ||||
response = client.get(url) | check_http_get_response(client, url, status_code=403) | ||||
assert response.status_code == 403 | |||||
@pytest.mark.django_db | @pytest.mark.django_db | ||||
def test_oidc_list_bearer_tokens(client, mocker): | def test_oidc_list_bearer_tokens(client, mocker): | ||||
""" | """ | ||||
User with correct credentials should be allowed to list his tokens. | User with correct credentials should be allowed to list his tokens. | ||||
""" | """ | ||||
mock_keycloak(mocker) | mock_keycloak(mocker) | ||||
nb_tokens = 3 | nb_tokens = 3 | ||||
password = "secret" | password = "secret" | ||||
for _ in range(nb_tokens): | for _ in range(nb_tokens): | ||||
response = _generate_bearer_token(client, password) | response = _generate_bearer_token(client, password) | ||||
url = reverse( | url = reverse( | ||||
"oidc-list-bearer-tokens", query_params={"draw": 1, "start": 0, "length": 10} | "oidc-list-bearer-tokens", query_params={"draw": 1, "start": 0, "length": 10} | ||||
) | ) | ||||
response = client.get(url) | |||||
assert response.status_code == 200 | response = check_http_get_response(client, url, status_code=200) | ||||
tokens_data = list(reversed(json.loads(response.content.decode("utf-8"))["data"])) | tokens_data = list(reversed(json.loads(response.content.decode("utf-8"))["data"])) | ||||
for oidc_token in OIDCUserOfflineTokens.objects.all(): | for oidc_token in OIDCUserOfflineTokens.objects.all(): | ||||
assert ( | assert ( | ||||
oidc_token.creation_date.isoformat() | oidc_token.creation_date.isoformat() | ||||
== tokens_data[oidc_token.id - 1]["creation_date"] | == tokens_data[oidc_token.id - 1]["creation_date"] | ||||
) | ) | ||||
def test_oidc_get_bearer_token_anonymous_user(client): | def test_oidc_get_bearer_token_anonymous_user(client): | ||||
""" | """ | ||||
Anonymous user should be refused access with forbidden response. | Anonymous user should be refused access with forbidden response. | ||||
""" | """ | ||||
url = reverse("oidc-get-bearer-token") | url = reverse("oidc-get-bearer-token") | ||||
response = client.post(url) | check_http_post_response(client, url, status_code=403) | ||||
assert response.status_code == 403 | |||||
@pytest.mark.django_db | @pytest.mark.django_db | ||||
def test_oidc_get_bearer_token(client, mocker): | def test_oidc_get_bearer_token(client, mocker): | ||||
""" | """ | ||||
User with correct credentials should be allowed to display a token. | User with correct credentials should be allowed to display a token. | ||||
""" | """ | ||||
mock_keycloak(mocker) | mock_keycloak(mocker) | ||||
nb_tokens = 3 | nb_tokens = 3 | ||||
password = "secret" | password = "secret" | ||||
for i in range(nb_tokens): | for i in range(nb_tokens): | ||||
response = _generate_bearer_token(client, password) | response = _generate_bearer_token(client, password) | ||||
token = response.content | token = response.content | ||||
url = reverse("oidc-get-bearer-token") | url = reverse("oidc-get-bearer-token") | ||||
response = client.post( | |||||
response = check_http_post_response( | |||||
client, | |||||
url, | url, | ||||
status_code=200, | |||||
data={"password": password, "token_id": i + 1}, | data={"password": password, "token_id": i + 1}, | ||||
content_type="application/json", | content_type="text/plain", | ||||
) | ) | ||||
assert response.status_code == 200 | |||||
assert response.content == token | assert response.content == token | ||||
@pytest.mark.django_db | @pytest.mark.django_db | ||||
def test_oidc_get_bearer_token_invalid_password(client, mocker): | def test_oidc_get_bearer_token_invalid_password(client, mocker): | ||||
""" | """ | ||||
User with wrong credentials should not be allowed to display a token. | User with wrong credentials should not be allowed to display a token. | ||||
""" | """ | ||||
mock_keycloak(mocker) | mock_keycloak(mocker) | ||||
password = "secret" | password = "secret" | ||||
_generate_bearer_token(client, password) | _generate_bearer_token(client, password) | ||||
url = reverse("oidc-get-bearer-token") | url = reverse("oidc-get-bearer-token") | ||||
response = client.post( | check_http_post_response( | ||||
client, | |||||
url, | url, | ||||
status_code=401, | |||||
data={"password": "invalid-password", "token_id": 1}, | data={"password": "invalid-password", "token_id": 1}, | ||||
content_type="application/json", | |||||
) | ) | ||||
assert response.status_code == 401 | |||||
def test_oidc_revoke_bearer_tokens_anonymous_user(client): | def test_oidc_revoke_bearer_tokens_anonymous_user(client): | ||||
""" | """ | ||||
Anonymous user should be refused access with forbidden response. | Anonymous user should be refused access with forbidden response. | ||||
""" | """ | ||||
url = reverse("oidc-revoke-bearer-tokens") | url = reverse("oidc-revoke-bearer-tokens") | ||||
response = client.post(url) | check_http_post_response(client, url, status_code=403) | ||||
assert response.status_code == 403 | |||||
@pytest.mark.django_db | @pytest.mark.django_db | ||||
def test_oidc_revoke_bearer_tokens(client, mocker): | def test_oidc_revoke_bearer_tokens(client, mocker): | ||||
""" | """ | ||||
User with correct credentials should be allowed to revoke tokens. | User with correct credentials should be allowed to revoke tokens. | ||||
""" | """ | ||||
mock_keycloak(mocker) | mock_keycloak(mocker) | ||||
nb_tokens = 3 | nb_tokens = 3 | ||||
password = "secret" | password = "secret" | ||||
for _ in range(nb_tokens): | for _ in range(nb_tokens): | ||||
_generate_bearer_token(client, password) | _generate_bearer_token(client, password) | ||||
url = reverse("oidc-revoke-bearer-tokens") | url = reverse("oidc-revoke-bearer-tokens") | ||||
response = client.post( | |||||
url, | check_http_post_response( | ||||
data={"password": password, "token_ids": [1]}, | client, url, status_code=200, data={"password": password, "token_ids": [1]}, | ||||
content_type="application/json", | |||||
) | ) | ||||
assert response.status_code == 200 | |||||
assert len(OIDCUserOfflineTokens.objects.all()) == 2 | assert len(OIDCUserOfflineTokens.objects.all()) == 2 | ||||
response = client.post( | check_http_post_response( | ||||
url, | client, url, status_code=200, data={"password": password, "token_ids": [2, 3]}, | ||||
data={"password": password, "token_ids": [2, 3]}, | |||||
content_type="application/json", | |||||
) | ) | ||||
assert response.status_code == 200 | |||||
assert len(OIDCUserOfflineTokens.objects.all()) == 0 | assert len(OIDCUserOfflineTokens.objects.all()) == 0 | ||||
@pytest.mark.django_db | @pytest.mark.django_db | ||||
def test_oidc_revoke_bearer_token_invalid_password(client, mocker): | def test_oidc_revoke_bearer_token_invalid_password(client, mocker): | ||||
""" | """ | ||||
User with wrong credentials should not be allowed to revoke tokens. | User with wrong credentials should not be allowed to revoke tokens. | ||||
""" | """ | ||||
mock_keycloak(mocker) | mock_keycloak(mocker) | ||||
password = "secret" | password = "secret" | ||||
_generate_bearer_token(client, password) | _generate_bearer_token(client, password) | ||||
url = reverse("oidc-revoke-bearer-tokens") | url = reverse("oidc-revoke-bearer-tokens") | ||||
response = client.post( | |||||
check_http_post_response( | |||||
client, | |||||
url, | url, | ||||
status_code=401, | |||||
data={"password": "invalid-password", "token_ids": [1]}, | data={"password": "invalid-password", "token_ids": [1]}, | ||||
content_type="application/json", | |||||
) | ) | ||||
assert response.status_code == 401 |