diff options
| author | Claude Sonnet 4.6 | 2026-06-15 17:40:00 +0000 |
|---|---|---|
| committer | Frederick Muriuki Muriithi | 2026-06-15 13:01:36 -0500 |
| commit | 7039020ff904e82dfeab1b604263b1e6447ba908 (patch) | |
| tree | 48310dd6b09028174b60baac18759b49eb9355a2 /tests/test_gn_auth_auth_flow.py | |
| parent | b8d3cc1919f48272d6a88228c77a00101c96349e (diff) | |
| download | gn-integration-tests-7039020ff904e82dfeab1b604263b1e6447ba908.tar.gz | |
Test that POST /auth/user/masquerade/ enforces the system:user:masquerade privilege. 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: - Basic user → ForbiddenAccess → 403 - Admin user → can masquerade as basic user → 200 Adds three session-scoped fixtures to the test module: admin_masquerade_token, basic_masquerade_token, and basic_user_id.
Diffstat (limited to 'tests/test_gn_auth_auth_flow.py')
| -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" + ) |
