"""Role mapping is deny-by-default: unmapped groups grant nothing.""" from __future__ import annotations from datetime import UTC, datetime, timedelta from uuid import uuid4 import pytest from ragcore.application.authorization import AuthorizationService from ragcore.domain.auth import OidcClaims, Session, map_roles from ragcore.domain.authorization import Permission, PermissionDenied, Principal, PrincipalType from ragcore.domain.control import Role def test_recognized_groups_map_to_their_configured_role() -> None: roles = map_roles(("ragcore-admins",), {"ragcore-admins": Role.PLATFORM_ADMIN}) assert roles == frozenset({Role.PLATFORM_ADMIN}) def test_unrecognized_groups_grant_nothing() -> None: roles = map_roles(("some-other-app-group",), {"ragcore-admins": Role.PLATFORM_ADMIN}) assert roles == frozenset() def test_no_groups_at_all_grants_nothing() -> None: roles = map_roles((), {"ragcore-admins": Role.PLATFORM_ADMIN}) assert roles == frozenset() def test_mixed_recognized_and_unrecognized_groups_only_map_the_known_ones() -> None: roles = map_roles( ("ragcore-editors", "some-unrelated-group", "ragcore-viewers"), {"ragcore-editors": Role.EDITOR, "ragcore-viewers": Role.VIEWER}, ) assert roles == frozenset({Role.EDITOR, Role.VIEWER}) def test_oidc_claims_bounds_are_enforced() -> None: with pytest.raises(ValueError, match="subject"): OidcClaims(subject="", email=None, groups=()) with pytest.raises(ValueError, match="groups"): OidcClaims(subject="alice", email=None, groups=tuple(f"g{i}" for i in range(101))) def test_a_session_with_no_mapped_roles_is_denied_everywhere() -> None: """Ties role mapping's deny-by-default guarantee to the real, already- established authorization system: an authenticated identity with an empty roles set (because none of its groups were recognized) is denied exactly like any other roleless principal -- there is no separate "authenticated but unmapped" bypass anywhere in the authorization path. """ workspace_id = uuid4() claims = OidcClaims(subject="alice", email="alice@example.test", groups=("unmapped-group",)) roles = map_roles(claims.groups, {"ragcore-admins": Role.PLATFORM_ADMIN}) now = datetime.now(UTC) session = Session( id=uuid4(), subject=claims.subject, workspace_id=workspace_id, issued_at=now, expires_at=now + timedelta(hours=1), csrf_token="a" * 32, roles=roles, ) assert session.roles == frozenset() principal = Principal(uuid4(), workspace_id, PrincipalType.HUMAN, session.roles) with pytest.raises(PermissionDenied): AuthorizationService().authorize( principal, Permission.SEARCH, resource_workspace_id=workspace_id )