Skip to content

Commit 2e59998

Browse files
committed
test: add multi-user data isolation tests
- ServerGroupIsolationTestCase: verify non-admin cannot fetch another user's server group properties - ServerDataIsolationGetTestCase: verify non-admin cannot access another user's private server - SharedServerAccessTestCase: verify shared servers remain accessible cross-user (positive regression test) Tests use create_user_wise_test_client pattern and only run in SERVER_MODE with pgAdmin4_test_non_admin_credentials configured.
1 parent f365785 commit 2e59998

File tree

2 files changed

+194
-0
lines changed

2 files changed

+194
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
##########################################################################
2+
#
3+
# pgAdmin 4 - PostgreSQL Tools
4+
#
5+
# Copyright (C) 2013 - 2026, The pgAdmin Development Team
6+
# This software is released under the PostgreSQL Licence
7+
#
8+
##########################################################################
9+
10+
"""Tests for server data isolation between users in server mode."""
11+
12+
import json
13+
import config
14+
from pgadmin.utils.route import BaseTestGenerator
15+
from regression.python_test_utils import test_utils as utils
16+
from regression.test_setup import config_data
17+
from regression.python_test_utils.test_utils import \
18+
create_user_wise_test_client
19+
from . import utils as servers_utils
20+
21+
test_user_details = None
22+
if config.SERVER_MODE:
23+
test_user_details = \
24+
config_data['pgAdmin4_test_non_admin_credentials']
25+
26+
27+
class ServerDataIsolationGetTestCase(BaseTestGenerator):
28+
"""Verify that a non-admin user cannot access another user's
29+
private (non-shared) server by ID."""
30+
31+
scenarios = [
32+
('User B gets 410 for User A private server',
33+
dict(is_positive_test=False)),
34+
]
35+
36+
def setUp(self):
37+
if not config.SERVER_MODE:
38+
self.skipTest(
39+
'Data isolation tests only apply to server mode.'
40+
)
41+
42+
# Create a private (non-shared) server as the admin user
43+
self.server['shared'] = False
44+
url = "/browser/server/obj/{0}/".format(utils.SERVER_GROUP)
45+
response = self.tester.post(
46+
url,
47+
data=json.dumps(self.server),
48+
content_type='html/json'
49+
)
50+
response_data = json.loads(response.data.decode('utf-8'))
51+
self.server_id = response_data['node']['_id']
52+
53+
@create_user_wise_test_client(test_user_details)
54+
def runTest(self):
55+
"""Non-admin user should NOT be able to GET another user's
56+
private server."""
57+
if not self.server_id:
58+
raise Exception("Server not found to test isolation")
59+
60+
url = '/browser/server/obj/{0}/{1}'.format(
61+
utils.SERVER_GROUP, self.server_id)
62+
response = self.tester.get(url, follow_redirects=True)
63+
# Expect 410 Gone (server not accessible to this user)
64+
self.assertIn(
65+
response.status_code, [404, 410],
66+
'Non-admin user should not access another user\'s '
67+
'private server. Got status {0}'.format(
68+
response.status_code)
69+
)
70+
71+
def tearDown(self):
72+
# Clean up with the admin tester (which owns the server)
73+
utils.delete_server_with_api(
74+
self.__class__.tester, self.server_id)
75+
76+
77+
class SharedServerAccessTestCase(BaseTestGenerator):
78+
"""Verify that a shared server IS accessible by a non-admin
79+
user (positive test — shared servers should work after the
80+
isolation fixes)."""
81+
82+
scenarios = [
83+
('User B can access shared server from User A',
84+
dict(is_positive_test=True)),
85+
]
86+
87+
def setUp(self):
88+
if not config.SERVER_MODE:
89+
self.skipTest(
90+
'Data isolation tests only apply to server mode.'
91+
)
92+
93+
# Create a shared server as the admin user
94+
self.server['shared'] = True
95+
url = "/browser/server/obj/{0}/".format(utils.SERVER_GROUP)
96+
response = self.tester.post(
97+
url,
98+
data=json.dumps(self.server),
99+
content_type='html/json'
100+
)
101+
response_data = json.loads(response.data.decode('utf-8'))
102+
self.server_id = response_data['node']['_id']
103+
104+
@create_user_wise_test_client(test_user_details)
105+
def runTest(self):
106+
"""Non-admin user SHOULD be able to GET a shared server."""
107+
if not self.server_id:
108+
raise Exception("Server not found to test shared access")
109+
110+
url = '/browser/server/obj/{0}/{1}'.format(
111+
utils.SERVER_GROUP, self.server_id)
112+
response = self.tester.get(url, follow_redirects=True)
113+
self.assertEqual(
114+
response.status_code, 200,
115+
'Non-admin user should be able to access shared server.'
116+
' Got status {0}'.format(response.status_code)
117+
)
118+
119+
def tearDown(self):
120+
utils.delete_server_with_api(
121+
self.__class__.tester, self.server_id)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
##########################################################################
2+
#
3+
# pgAdmin 4 - PostgreSQL Tools
4+
#
5+
# Copyright (C) 2013 - 2026, The pgAdmin Development Team
6+
# This software is released under the PostgreSQL Licence
7+
#
8+
##########################################################################
9+
10+
"""Tests for ServerGroup data isolation between users in server mode."""
11+
12+
import json
13+
import config
14+
from pgadmin.utils.route import BaseTestGenerator
15+
from regression.python_test_utils import test_utils as utils
16+
from regression.test_setup import config_data
17+
from regression.python_test_utils.test_utils import \
18+
create_user_wise_test_client
19+
from pgadmin.model import db, ServerGroup
20+
21+
test_user_details = None
22+
if config.SERVER_MODE:
23+
test_user_details = \
24+
config_data['pgAdmin4_test_non_admin_credentials']
25+
26+
27+
class ServerGroupIsolationTestCase(BaseTestGenerator):
28+
"""Verify that a non-admin user cannot fetch another user's
29+
server group properties by ID."""
30+
31+
scenarios = [
32+
('User B cannot fetch User A server group properties',
33+
dict(is_positive_test=False)),
34+
]
35+
36+
def setUp(self):
37+
if not config.SERVER_MODE:
38+
self.skipTest(
39+
'Data isolation tests only apply to server mode.'
40+
)
41+
42+
# Create a server group as the admin user
43+
url = '/browser/server_group/obj/'
44+
response = self.tester.post(
45+
url,
46+
data=json.dumps({'name': 'isolation_test_group'}),
47+
content_type='html/json'
48+
)
49+
response_data = json.loads(response.data.decode('utf-8'))
50+
self.sg_id = response_data['node']['_id']
51+
52+
@create_user_wise_test_client(test_user_details)
53+
def runTest(self):
54+
"""Non-admin user should NOT see another user's server
55+
group properties."""
56+
if not self.sg_id:
57+
raise Exception("Server group not created")
58+
59+
url = '/browser/server_group/obj/{0}'.format(self.sg_id)
60+
response = self.tester.get(url, content_type='html/json')
61+
self.assertIn(
62+
response.status_code, [404, 410],
63+
'Non-admin user should not access another user\'s '
64+
'server group. Got status {0}'.format(
65+
response.status_code)
66+
)
67+
68+
def tearDown(self):
69+
# Clean up with admin
70+
sg = ServerGroup.query.filter_by(id=self.sg_id).first()
71+
if sg:
72+
db.session.delete(sg)
73+
db.session.commit()

0 commit comments

Comments
 (0)