1818from simcore_postgres_database .aiopg_errors import DatabaseError as AiopgDatabaseError
1919from sqlalchemy .exc import DatabaseError as SQLAlchemyDatabaseError
2020
21- from .. groups import api as groups_service
21+ from . import _authz_repository
2222from ._authz_access_model import (
2323 AuthContextDict ,
2424 OptionalContext ,
2525 RoleBasedAccessModel ,
2626 has_access_by_role ,
2727)
2828from ._authz_access_roles import NAMED_GROUP_PERMISSIONS
29- from ._authz_repository import (
30- ActiveUserIdAndRole ,
31- get_active_user_or_none ,
32- is_user_in_product_name ,
33- )
29+ from ._authz_repository import ActiveUserIdAndRole
3430from ._constants import MSG_AUTH_NOT_AVAILABLE , PERMISSION_PRODUCT_LOGIN_KEY
3531from ._identity_web import IdentityStr
3632
@@ -82,7 +78,7 @@ async def _get_authorized_user_or_none(
8278 web.HTTPServiceUnavailable: if database raises an exception
8379 """
8480 with _handle_exceptions_as_503 ():
85- return await get_active_user_or_none (
81+ return await _authz_repository . get_active_user_or_none (
8682 get_async_engine (self ._app ), email = email
8783 )
8884
@@ -99,17 +95,36 @@ async def _has_access_to_product(
9995 web.HTTPServiceUnavailable: if database raises an exception
10096 """
10197 with _handle_exceptions_as_503 ():
102- return await is_user_in_product_name (
98+ return await _authz_repository . is_user_in_product_name (
10399 get_async_engine (self ._app ), user_id = user_id , product_name = product_name
104100 )
105101
102+ @cached (
103+ ttl = _AUTHZ_BURST_CACHE_TTL ,
104+ namespace = __name__ ,
105+ key_builder = lambda f , * ag , ** kw : f"{ f .__name__ } /{ kw ['user_id' ]} /{ kw ['group_id' ]} " ,
106+ )
107+ async def _is_user_in_group (self , * , user_id : UserID , group_id : int ) -> bool :
108+ """
109+ Raises:
110+ web.HTTPServiceUnavailable: if database raises an exception
111+ """
112+ with _handle_exceptions_as_503 ():
113+ return await _authz_repository .is_user_in_group (
114+ get_async_engine (self ._app ), user_id = user_id , group_id = group_id
115+ )
116+
106117 @property
107118 def access_model (self ) -> RoleBasedAccessModel :
108119 return self ._access_model
109120
110121 async def clear_cache (self ):
111122 # pylint: disable=no-member
112- for fun in (self ._get_authorized_user_or_none , self ._has_access_to_product ):
123+ for fun in (
124+ self ._get_authorized_user_or_none ,
125+ self ._has_access_to_product ,
126+ self ._is_user_in_group ,
127+ ):
113128 autz_cache : BaseCache = fun .cache
114129 await autz_cache .clear ()
115130
@@ -184,19 +199,13 @@ async def permits(
184199
185200 # GROUP-BASED access policy (only if enabled in context and user is above GUEST role)
186201 product_support_group_id = context .get ("product_support_group_id" , None )
187- if (
202+ group_allowed = (
188203 product_support_group_id is not None
189204 and user_role > UserRole .GUEST
190205 and permission in NAMED_GROUP_PERMISSIONS .get ("PRODUCT_SUPPORT_GROUP" , [])
191- ):
192- with contextlib .suppress (
193- Exception
194- # If product or group check fails, continue to deny access
195- # NOTE: Logging omitted to avoid exposing internal errors
196- ):
197- if await groups_service .is_user_in_group (
198- self ._app , user_id = user_id , group_id = product_support_group_id
199- ):
200- return True
201-
202- return False
206+ and await self ._is_user_in_group (
207+ user_id = user_id , group_id = product_support_group_id
208+ )
209+ )
210+
211+ return group_allowed # noqa: RET504
0 commit comments