Skip to content

Commit bab4794

Browse files
authored
Merge commit from fork
Additional logic for handling missing auth sessions
2 parents a14dff8 + a63ee07 commit bab4794

10 files changed

Lines changed: 84 additions & 55 deletions

File tree

web/server/codechecker_server/api/authentication.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,13 @@ def __require_privilaged_access(self):
6868
"The server must be start by using privilaged access to "
6969
"execute this action.")
7070

71-
def __has_permission(self, permission) -> bool:
72-
""" True if the current user has given permission rights. """
73-
if self.__manager.is_enabled and not self.__auth_session:
74-
return False
75-
76-
return self.hasPermission(permission, None)
77-
7871
def __require_permission_view(self):
7972
"""
8073
Checks if the curret user has PERMISSION_VIEW rights. Throws an
8174
exception if it is not.
8275
"""
8376
permission = codechecker_api_shared.ttypes.Permission.PERMISSION_VIEW
84-
if not self.__has_permission(permission):
77+
if not self.hasPermission(permission, None):
8578
raise codechecker_api_shared.ttypes.RequestFailed(
8679
codechecker_api_shared.ttypes.ErrorCode.UNAUTHORIZED,
8780
"You are not authorized to execute this action.")
@@ -598,21 +591,23 @@ def getPermissionsForUser(self, scope, extra_params, perm_filter):
598591
# handler.
599592
params = ThriftAuthHandler.__unpack_extra_params(extra_params,
600593
session)
594+
is_auth_enabled = self.__manager.is_enabled
601595

602596
perms = []
603597
for perm in permissions.get_permissions(scope):
604598
should_return = True
605599
handler = make_handler(perm, params)
606600

607601
if should_return and perm_filter.given:
608-
should_return = handler.has_permission(self.__auth_session)
602+
should_return = handler.has_permission(self.__auth_session,
603+
is_auth_enabled)
609604

610605
if should_return and perm_filter.canManage:
611606
# If the user has any of the permissions that are
612607
# authorised to manage the currently iterated permission,
613608
# the filter passes.
614609
should_return = require_manager(
615-
perm, params, self.__auth_session)
610+
perm, params, self.__auth_session, is_auth_enabled)
616611

617612
if should_return:
618613
perms.append(perm)
@@ -631,7 +626,8 @@ def getAuthorisedNames(self, permission, extra_params):
631626
perm, params = ThriftAuthHandler.__create_permission_args(
632627
permission, extra_params, session)
633628

634-
if not require_manager(perm, params, self.__auth_session):
629+
if not require_manager(perm, params, self.__auth_session,
630+
self.__manager.is_enabled):
635631
raise codechecker_api_shared.ttypes.RequestFailed(
636632
codechecker_api_shared.ttypes.ErrorCode.UNAUTHORIZED,
637633
f"You can not manage the permission '{perm.name}'")
@@ -654,7 +650,8 @@ def addPermission(self, permission, auth_name, is_group, extra_params):
654650
perm, params = ThriftAuthHandler.__create_permission_args(
655651
permission, extra_params, session)
656652

657-
if not require_manager(perm, params, self.__auth_session):
653+
if not require_manager(perm, params, self.__auth_session,
654+
self.__manager.is_enabled):
658655
raise codechecker_api_shared.ttypes.RequestFailed(
659656
codechecker_api_shared.ttypes.ErrorCode.UNAUTHORIZED,
660657
f"You can not manage the permission '{perm.name}'")
@@ -677,7 +674,8 @@ def removePermission(self, permission, auth_name, is_group, extra_params):
677674
perm, params = ThriftAuthHandler.__create_permission_args(
678675
permission, extra_params, session)
679676

680-
if not require_manager(perm, params, self.__auth_session):
677+
if not require_manager(perm, params, self.__auth_session,
678+
self.__manager.is_enabled):
681679
raise codechecker_api_shared.ttypes.RequestFailed(
682680
codechecker_api_shared.ttypes.ErrorCode.UNAUTHORIZED,
683681
f"You can not manage the permission '{perm.name}'")
@@ -703,7 +701,8 @@ def hasPermission(self, permission, extra_params):
703701
permission, extra_params, session)
704702

705703
return require_permission(perm, params,
706-
self.__auth_session)
704+
self.__auth_session,
705+
self.__manager.is_enabled)
707706

708707
# ============= Authorization, permission management =============
709708

web/server/codechecker_server/api/product_server.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,9 @@ def __require_permission(self, required, args=None):
7676
if 'config_db_session' not in args:
7777
args['config_db_session'] = session
7878

79-
# Anonymous access is only allowed if authentication is
80-
# turned off
81-
if self.__server.manager.is_enabled and not self.__auth_session:
82-
raise codechecker_api_shared.ttypes.RequestFailed(
83-
codechecker_api_shared.ttypes.ErrorCode.UNAUTHORIZED,
84-
"You are not authorized to execute this action.")
85-
8679
if not any(permissions.require_permission(
87-
perm, args, self.__auth_session)
80+
perm, args, self.__auth_session,
81+
self.__server.manager.is_enabled)
8882
for perm in required):
8983
raise codechecker_api_shared.ttypes.RequestFailed(
9084
codechecker_api_shared.ttypes.ErrorCode.UNAUTHORIZED,
@@ -95,11 +89,13 @@ def __require_permission(self, required, args=None):
9589
def __administrating(self, args):
9690
""" True if the current user can administrate the given product. """
9791
if permissions.require_permission(permissions.SUPERUSER, args,
98-
self.__auth_session):
92+
self.__auth_session,
93+
self.__server.manager.is_enabled):
9994
return True
10095

10196
if permissions.require_permission(permissions.PRODUCT_ADMIN, args,
102-
self.__auth_session):
97+
self.__auth_session,
98+
self.__server.manager.is_enabled):
10399
return True
104100

105101
return False
@@ -126,9 +122,11 @@ def __get_product(self, session, product):
126122
'productID': product.id}
127123

128124
has_product_permission = permissions.require_permission(
129-
permissions.PRODUCT_VIEW, args, self.__auth_session)
125+
permissions.PRODUCT_VIEW, args, self.__auth_session,
126+
self.__server.manager.is_enabled)
130127
has_global_permission = permissions.require_permission(
131-
permissions.PERMISSION_VIEW, args, self.__auth_session)
128+
permissions.PERMISSION_VIEW, args, self.__auth_session,
129+
self.__server.manager.is_enabled)
132130
has_access_permission = has_product_permission or has_global_permission
133131

134132
admin_perm_name = permissions.PRODUCT_ADMIN.name
@@ -180,7 +178,8 @@ def isAdministratorOfAnyProduct(self):
180178
'productID': prod.id}
181179
if permissions.require_permission(
182180
permissions.PRODUCT_ADMIN,
183-
args, self.__auth_session):
181+
args, self.__auth_session,
182+
self.__server.manager.is_enabled):
184183
return True
185184

186185
return False

web/server/codechecker_server/api/report_server.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,15 +1509,9 @@ def __require_permission(self, required):
15091509
args = dict(self.__permission_args)
15101510
args['config_db_session'] = session
15111511

1512-
# Anonymous access is only allowed if authentication is
1513-
# turned off
1514-
if self._manager.is_enabled and not self._auth_session:
1515-
raise codechecker_api_shared.ttypes.RequestFailed(
1516-
codechecker_api_shared.ttypes.ErrorCode.UNAUTHORIZED,
1517-
"You are not authorized to execute this action.")
1518-
15191512
if not any(permissions.require_permission(
1520-
perm, args, self._auth_session)
1513+
perm, args, self._auth_session,
1514+
self._manager.is_enabled)
15211515
for perm in required):
15221516
raise codechecker_api_shared.ttypes.RequestFailed(
15231517
codechecker_api_shared.ttypes.ErrorCode.UNAUTHORIZED,
@@ -3023,6 +3017,8 @@ def getGuidelineRules(
30233017
guidelines: List[ttypes.Guideline]
30243018
):
30253019
""" Return the list of rules to each guideline that given. """
3020+
self.__require_view()
3021+
30263022
guideline_rules = defaultdict(list)
30273023
for guideline in guidelines:
30283024
rules = self._context.guideline.rules_of_guideline(

web/server/codechecker_server/api/tasks.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from codechecker_common.logger import get_logger
2323

2424
from codechecker_server.profiler import timeit
25+
from codechecker_server.session_manager import SessionManager
2526

2627
from ..database.config_db_model import BackgroundTask as DBTask, Product
2728
from ..database.database import DBSession, conv
@@ -113,9 +114,11 @@ class ThriftTaskHandler:
113114

114115
def __init__(self,
115116
configuration_database_sessionmaker,
117+
session_manager: SessionManager,
116118
task_manager: TaskManager,
117119
auth_session):
118120
self._config_db = configuration_database_sessionmaker
121+
self._session_manager = session_manager
119122
self._task_manager = task_manager
120123
self._auth_session = auth_session
121124

@@ -152,12 +155,14 @@ def getTaskInfo(self, token: str) -> TaskInfo:
152155
permissions.PRODUCT_ACCESS,
153156
{"config_db_session": session,
154157
"productID": associated_product.id},
155-
self._auth_session)
158+
self._auth_session,
159+
self._session_manager.is_enabled)
156160
else:
157161
has_right_to_query_status = permissions.require_permission(
158162
permissions.SUPERUSER,
159163
{"config_db_session": session},
160-
self._auth_session)
164+
self._auth_session,
165+
self._session_manager.is_enabled)
161166

162167
if not has_right_to_query_status:
163168
raise RequestFailed(
@@ -188,7 +193,8 @@ def getTasks(self, filters: TaskFilter) -> List[AdministratorTaskInfo]:
188193
if not permissions.require_permission(
189194
permissions.SUPERUSER,
190195
{"config_db_session": session},
191-
self._auth_session):
196+
self._auth_session,
197+
self._session_manager.is_enabled):
192198
raise RequestFailed(
193199
ErrorCode.UNAUTHORIZED,
194200
"Querying service tasks (not associated with a "
@@ -199,7 +205,8 @@ def getTasks(self, filters: TaskFilter) -> List[AdministratorTaskInfo]:
199205
if not permissions.require_permission(
200206
permissions.PRODUCT_ACCESS,
201207
{"config_db_session": session, "productID": prod_id},
202-
self._auth_session)]
208+
self._auth_session,
209+
self._session_manager.is_enabled)]
203210
if no_access_products:
204211
no_access_products = [session.get(Product, product_id)
205212
.endpoint
@@ -299,7 +306,8 @@ def getTasks(self, filters: TaskFilter) -> List[AdministratorTaskInfo]:
299306
has_superuser = permissions.require_permission(
300307
permissions.SUPERUSER,
301308
{"config_db_session": session},
302-
self._auth_session)
309+
self._auth_session,
310+
self._session_manager.is_enabled)
303311
if not has_superuser:
304312
continue
305313
else:
@@ -314,7 +322,8 @@ def getTasks(self, filters: TaskFilter) -> List[AdministratorTaskInfo]:
314322
permissions.PRODUCT_ACCESS,
315323
{"config_db_session": session,
316324
"productID": db_task.product_id},
317-
self._auth_session)
325+
self._auth_session,
326+
self._session_manager.is_enabled)
318327
if not product_access_rights[db_task.product_id]:
319328
continue
320329

@@ -351,12 +360,14 @@ def cancelTask(self, token: str) -> bool:
351360
permissions.PRODUCT_ADMIN,
352361
{"config_db_session": session,
353362
"productID": associated_product.id},
354-
self._auth_session)
363+
self._auth_session,
364+
self._session_manager.is_enabled)
355365
else:
356366
has_right_to_cancel = permissions.require_permission(
357367
permissions.SUPERUSER,
358368
{"config_db_session": session},
359-
self._auth_session)
369+
self._auth_session,
370+
self._session_manager.is_enabled)
360371

361372
if not has_right_to_cancel:
362373
raise RequestFailed(

web/server/codechecker_server/permissions.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -198,17 +198,17 @@ def remove_permission(self, auth_name, is_group=False,
198198
self._perm_name, 'group' if is_group else 'user',
199199
auth_name)
200200

201-
def has_permission(self, auth_session):
201+
def has_permission(self, auth_session, is_auth_enabled):
202202
"""
203203
Returns whether or not the given authenticated user session
204204
(or None, if authentication is disabled on the server!) is given
205205
the current permission.
206206
"""
207207
if not auth_session:
208-
# If the user does not have an auth_session it means it is a guest
209-
# and the server is running in authentication disabled mode.
210-
# All permissions are automatically granted in this case.
211-
return True
208+
# If the user does not have an auth_session it means it is a guest.
209+
# All permissions are automatically granted when authentication is
210+
# not enabled on the server.
211+
return not is_auth_enabled
212212

213213
elif auth_session.is_root and self._perm_name == 'SUPERUSER':
214214
# The special master superuser (root) automatically has the
@@ -644,17 +644,19 @@ def initialise_defaults(scope, extra_params):
644644
handler._rem_perm_impl('*', False)
645645

646646

647-
def require_permission(permission, extra_params, user):
647+
def require_permission(permission, extra_params, user, is_auth_enabled):
648648
"""
649649
Returns whether or not the given user has the given permission.
650650
651651
:param extra_params: The scope-specific argument dict, which already
652652
contains a valid database session.
653+
:param is_auth_enabled: Guest users are handled differently when
654+
authentication is disabled on the server.
653655
"""
654656

655657
handler = handler_from_scope_params(permission,
656658
extra_params)
657-
if handler.has_permission(user):
659+
if handler.has_permission(user, is_auth_enabled):
658660
return True
659661

660662
# If the user for some reason does not have the permission directly
@@ -663,27 +665,29 @@ def require_permission(permission, extra_params, user):
663665
while ancestors:
664666
handler = handler_from_scope_params(ancestors[0], extra_params)
665667

666-
if handler.has_permission(user):
668+
if handler.has_permission(user, is_auth_enabled):
667669
return True
668670
else:
669671
ancestors = ancestors[1:] + ancestors[0].inherited_from
670672

671673
return False
672674

673675

674-
def require_manager(permission, extra_params, user):
676+
def require_manager(permission, extra_params, user, is_auth_enabled):
675677
"""
676678
Returns whether or not the given user has rights to manage the given
677679
permission.
678680
679681
:param extra_params: The scope-specific argument dict, which already
680682
contains a valid database session.
683+
:param is_auth_enabled: Guest users are handled differently when
684+
authentication is disabled on the server.
681685
"""
682686

683687
for manager in permission.managed_by:
684688
manager_handler = handler_from_scope_params(manager,
685689
extra_params)
686-
if manager_handler.has_permission(user):
690+
if manager_handler.has_permission(user, is_auth_enabled):
687691
return True
688692

689693
return False

web/server/codechecker_server/server.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,7 @@ def do_POST(self):
469469
elif request_endpoint == "Tasks":
470470
task_handler = TaskHandler_v6(
471471
self.server.config_session,
472+
self.server.manager,
472473
self.server.task_manager,
473474
self.auth_session)
474475
processor = TaskAPI_v6.Processor(task_handler)

web/tests/functional/authentication/test_authentication.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,8 @@ def test_announcement_showing_in_cli(self):
738738
session_token='_PROHIBIT')
739739
session_token = auth_client.performLogin(
740740
"Username:Password", "root:root")
741+
auth_client = env.setup_auth_client(self._test_workspace,
742+
session_token=session_token)
741743

742744
auth_client.addPermission(Permission.SUPERUSER, "root", False, "")
743745

web/tests/functional/component/test_component.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,10 @@ def setup_method(self, _):
136136
session_token='_PROHIBIT')
137137

138138
# Create a PRODUCT_ADMIN login.
139-
admin_token = self._auth_client.performLogin("Username:Password",
140-
"admin:admin123")
139+
root_token = self._auth_client.performLogin("Username:Password",
140+
"root:root")
141+
self._auth_client = env.setup_auth_client(self._test_workspace,
142+
session_token=root_token)
141143

142144
extra_params = '{"productID":' + str(product_id) + '}'
143145
ret = self._auth_client.addPermission(Permission.PRODUCT_ADMIN,
@@ -146,6 +148,9 @@ def setup_method(self, _):
146148
extra_params)
147149
self.assertTrue(ret)
148150

151+
admin_token = self._auth_client.performLogin("Username:Password",
152+
"admin:admin123")
153+
149154
self._cc_client = env.setup_viewer_client(self._test_workspace,
150155
session_token=admin_token)
151156
self.assertIsNotNone(self._cc_client)

web/tests/functional/products/test_config_db_share.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,14 @@ def setup_method(self, _):
7575
# Create a SUPERUSER login.
7676
root_token = self._auth_client.performLogin("Username:Password",
7777
"root:root")
78+
self._auth_client = env.setup_auth_client(self.test_workspace_main,
79+
session_token=root_token)
7880

7981
# Add SUPERUSER permission to the root user and test that the white
8082
# spaces are being removed from the user name.
83+
# TODO: I'm not sure if this test makes sense, because "root" user has
84+
# SUPERUSER permission already. "root" is set as "super_user" in
85+
# server_config.json.
8186
ret = self._auth_client.addPermission(Permission.SUPERUSER,
8287
" root ",
8388
False,

0 commit comments

Comments
 (0)