diff options
| -rw-r--r-- | tests/test_gn_auth_auth_flow.py | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/tests/test_gn_auth_auth_flow.py b/tests/test_gn_auth_auth_flow.py index cb164cd..98d792a 100644 --- a/tests/test_gn_auth_auth_flow.py +++ b/tests/test_gn_auth_auth_flow.py @@ -191,3 +191,111 @@ class TestUserProfileWithoutToken: f"Expected 401 from /auth/user/ with garbage token, " f"got {resp.status_code}: {resp.text}" ) + + +# --------------------------------------------------------------------------- +# POST /auth/user/masquerade/ — role-based privilege check +# +# The masquerade endpoint requires the "system:user:masquerade" privilege +# which only system-administrators hold. Both admin and basic users can +# obtain a token with "masquerade" scope (the test client supports it), but +# gn-auth's can_masquerade decorator checks the user's roles and raises +# ForbiddenAccess (→ 403) for users without the privilege. +# --------------------------------------------------------------------------- + +@pytest.fixture(scope="session") +def admin_masquerade_token(gn_auth_url, http, oauth2_credentials): + """Admin Bearer token with masquerade scope.""" + email, password, client_id, client_secret = oauth2_credentials + resp = http.post( + f"{gn_auth_url}/auth/token", + json={ + "grant_type": "password", + "username": email, + "password": password, + "scope": "profile group resource user masquerade", + "client_id": client_id, + "client_secret": client_secret, + }, + timeout=30, + ) + assert resp.status_code == 200, f"Admin masquerade token request failed: {resp.text}" + return resp.json()["access_token"] + + +@pytest.fixture(scope="session") +def basic_masquerade_token(gn_auth_url, http, basic_oauth2_credentials): + """Unprivileged user Bearer token with masquerade scope.""" + email, password, client_id, client_secret = basic_oauth2_credentials + resp = http.post( + f"{gn_auth_url}/auth/token", + json={ + "grant_type": "password", + "username": email, + "password": password, + "scope": "profile group resource user masquerade", + "client_id": client_id, + "client_secret": client_secret, + }, + timeout=30, + ) + assert resp.status_code == 200, f"Basic masquerade token request failed: {resp.text}" + return resp.json()["access_token"] + + +@pytest.fixture(scope="session") +def basic_user_id(gn_auth_url, http, basic_access_token): + """User ID of the unprivileged test user, fetched via GET /auth/user/.""" + resp = http.get( + f"{gn_auth_url}/auth/user/", + headers={"Authorization": f"Bearer {basic_access_token}"}, + timeout=30, + ) + assert resp.status_code == 200, f"Could not fetch basic user profile: {resp.text}" + return resp.json()["user_id"] + + +class TestMasqueradePrivilege: + """POST /auth/user/masquerade/ enforces the system:user:masquerade privilege.""" + + def test_basic_user_cannot_masquerade_returns_403( + self, gn_auth_url, http, basic_masquerade_token, basic_user_id, + access_token): + # Basic user tries to masquerade as the admin; the admin's user_id is + # obtained via the profile endpoint. + admin_profile = http.get( + f"{gn_auth_url}/auth/user/", + headers={"Authorization": f"Bearer {access_token}"}, + timeout=30, + ) + assert admin_profile.status_code == 200 + admin_id = admin_profile.json()["user_id"] + + resp = http.post( + f"{gn_auth_url}/auth/user/masquerade/", + json={"masquerade_as": admin_id}, + headers={"Authorization": f"Bearer {basic_masquerade_token}"}, + timeout=30, + ) + assert resp.status_code == 403, ( + f"Expected 403 when unprivileged user attempts masquerade, " + f"got {resp.status_code}: {resp.text}" + ) + + def test_admin_can_masquerade_as_basic_user( + self, gn_auth_url, http, admin_masquerade_token, basic_user_id): + resp = http.post( + f"{gn_auth_url}/auth/user/masquerade/", + json={"masquerade_as": basic_user_id}, + headers={"Authorization": f"Bearer {admin_masquerade_token}"}, + timeout=30, + ) + assert resp.status_code == 200, ( + f"Expected 200 when admin masquerades as basic user, " + f"got {resp.status_code}: {resp.text}" + ) + data = resp.json() + assert "masquerade_as" in data, f"Missing 'masquerade_as' in response: {data}" + assert data["masquerade_as"]["user"]["user_id"] == basic_user_id, ( + "Masquerade response user_id does not match target user" + ) |
