Skip to content

Commit 2be2462

Browse files
committed
refactor: rename AuthInfoDict to ActiveUserIdAndRole and update related methods
1 parent 3e5b267 commit 2be2462

File tree

3 files changed

+35
-22
lines changed

3 files changed

+35
-22
lines changed

services/web/server/src/simcore_service_webserver/security/_authz_policy.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
has_access_by_role,
2525
)
2626
from ._authz_repository import (
27-
AuthInfoDict,
27+
ActiveUserIdAndRole,
2828
get_active_user_or_none,
2929
is_user_in_product_name,
3030
)
@@ -71,7 +71,9 @@ def __init__(self, app: web.Application, access_model: RoleBasedAccessModel):
7171
namespace=__name__,
7272
key_builder=lambda f, *ag, **kw: f"{f.__name__}/{kw['email']}",
7373
)
74-
async def _get_auth_or_none(self, *, email: str) -> AuthInfoDict | None:
74+
async def _get_authorized_user_or_none(
75+
self, *, email: str
76+
) -> ActiveUserIdAndRole | None:
7577
"""
7678
Raises:
7779
web.HTTPServiceUnavailable: if database raises an exception
@@ -104,7 +106,7 @@ def access_model(self) -> RoleBasedAccessModel:
104106

105107
async def clear_cache(self):
106108
# pylint: disable=no-member
107-
for fun in (self._get_auth_or_none, self._has_access_to_product):
109+
for fun in (self._get_authorized_user_or_none, self._has_access_to_product):
108110
autz_cache: BaseCache = fun.cache
109111
await autz_cache.clear()
110112

@@ -118,7 +120,9 @@ async def authorized_userid(self, identity: IdentityStr) -> int | None:
118120
Return the user_id of the user identified by the identity
119121
or "None" if no user exists related to the identity.
120122
"""
121-
user_info: AuthInfoDict | None = await self._get_auth_or_none(email=identity)
123+
user_info: ActiveUserIdAndRole | None = await self._get_authorized_user_or_none(
124+
email=identity
125+
)
122126
if user_info is None:
123127
return None
124128

@@ -141,24 +145,33 @@ async def permits(
141145
if identity is None or permission is None:
142146
return False
143147

144-
auth_info = await self._get_auth_or_none(email=identity)
145-
if auth_info is None:
148+
# authorized user info
149+
authorized_user_info = await self._get_authorized_user_or_none(email=identity)
150+
if authorized_user_info is None:
146151
return False
147152

153+
user_id = authorized_user_info["id"]
154+
user_role = authorized_user_info["role"]
155+
156+
# context info: product_name
148157
context = context or AuthContextDict()
158+
product_name = context.get("product_name")
159+
160+
assert user_id == context.get( # nosec
161+
"authorized_uid"
162+
), f"{user_id}!={context.get('authorized_uid')}"
149163

150164
# product access
151165
if permission == PERMISSION_PRODUCT_LOGIN_KEY:
152-
product_name = context.get("product_name")
153166
ok: bool = product_name is not None and await self._has_access_to_product(
154-
user_id=auth_info["id"], product_name=product_name
167+
user_id=user_id, product_name=product_name
155168
)
156169
return ok
157170

158171
# role-based access
159172
return await has_access_by_role(
160173
self._access_model,
161-
role=auth_info["role"],
174+
role=user_role,
162175
operations=permission,
163176
context=context,
164177
)

services/web/server/src/simcore_service_webserver/security/_authz_repository.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616
_logger = logging.getLogger(__name__)
1717

1818

19-
class AuthInfoDict(TypedDict, total=True):
19+
class ActiveUserIdAndRole(TypedDict, total=True):
2020
id: IdInt
2121
role: UserRole
2222

2323

2424
async def get_active_user_or_none(
2525
engine: AsyncEngine, *, email: str
26-
) -> AuthInfoDict | None:
26+
) -> ActiveUserIdAndRole | None:
2727
"""Gets a user with email if ACTIVE othewise return None
2828
2929
Raises:
@@ -46,7 +46,7 @@ async def get_active_user_or_none(
4646
row is None or TypeAdapter(UserRole).validate_python(row.role) is not None
4747
)
4848

49-
return AuthInfoDict(id=row.id, role=row.role) if row else None
49+
return ActiveUserIdAndRole(id=row.id, role=row.role) if row else None
5050

5151

5252
async def is_user_in_product_name(

services/web/server/tests/unit/isolated/test_security__authz.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
UserRole,
3030
)
3131
from simcore_service_webserver.security._authz_policy import AuthorizationPolicy
32-
from simcore_service_webserver.security._authz_repository import AuthInfoDict
32+
from simcore_service_webserver.security._authz_repository import ActiveUserIdAndRole
3333

3434

3535
@pytest.fixture
@@ -248,9 +248,9 @@ def mock_db(mocker: MockerFixture) -> MagicMock:
248248
return_value="FAKE-ENGINE",
249249
)
250250

251-
users_db: dict[str, AuthInfoDict] = {
252-
"[email protected]": AuthInfoDict(id=1, role=UserRole.GUEST),
253-
"[email protected]": AuthInfoDict(id=55, role=UserRole.GUEST),
251+
users_db: dict[str, ActiveUserIdAndRole] = {
252+
"[email protected]": ActiveUserIdAndRole(id=1, role=UserRole.GUEST),
253+
"[email protected]": ActiveUserIdAndRole(id=55, role=UserRole.GUEST),
254254
}
255255

256256
async def _fake_db(engine, email):
@@ -280,11 +280,11 @@ async def test_authorization_policy_cache(mocker: MockerFixture, mock_db: MagicM
280280
# cache under test
281281

282282
# pylint: disable=no-member
283-
autz_cache: BaseCache = authz_policy._get_auth_or_none.cache
283+
autz_cache: BaseCache = authz_policy._get_authorized_user_or_none.cache
284284

285285
assert not (await autz_cache.exists("_get_auth_or_none/[email protected]"))
286286
for _ in range(3):
287-
got = await authz_policy._get_auth_or_none(email="[email protected]")
287+
got = await authz_policy._get_authorized_user_or_none(email="[email protected]")
288288
assert mock_db.call_count == 1
289289
assert got["id"] == 1
290290

@@ -295,15 +295,15 @@ async def test_authorization_policy_cache(mocker: MockerFixture, mock_db: MagicM
295295
assert (await autz_cache.get("_get_auth_or_none/[email protected]"))["id"] == 1
296296

297297
# gets cache, db is NOT called
298-
got = await authz_policy._get_auth_or_none(email="[email protected]")
298+
got = await authz_policy._get_authorized_user_or_none(email="[email protected]")
299299
assert mock_db.call_count == 1
300300
assert got["id"] == 1
301301

302302
# clear cache
303303
await authz_policy.clear_cache()
304304

305305
# gets new value
306-
got = await authz_policy._get_auth_or_none(email="[email protected]")
306+
got = await authz_policy._get_authorized_user_or_none(email="[email protected]")
307307
assert mock_db.call_count == 2
308308
assert got["id"] == 2
309309

@@ -312,10 +312,10 @@ async def test_authorization_policy_cache(mocker: MockerFixture, mock_db: MagicM
312312

313313
for _ in range(4):
314314
# NOTE: None
315-
assert await authz_policy._get_auth_or_none(email="[email protected]")
315+
assert await authz_policy._get_authorized_user_or_none(email="[email protected]")
316316
assert await autz_cache.exists("_get_auth_or_none/[email protected]")
317317
assert mock_db.call_count == 3
318318

319319
# should raise web.HTTPServiceUnavailable on db failure
320320
with pytest.raises(web.HTTPServiceUnavailable):
321-
await authz_policy._get_auth_or_none(email="[email protected]")
321+
await authz_policy._get_authorized_user_or_none(email="[email protected]")

0 commit comments

Comments
 (0)