Coverage for src/lexigram/auth/authz/scopes.py: 100%
39 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-26 00:58 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-26 00:58 +0800
1"""OAuth2 scopes and scope management"""
3from __future__ import annotations
5from enum import StrEnum
6import threading
9class OAuthScope(StrEnum):
10 """Standard OAuth2 scopes"""
12 OPENID = "openid"
13 EMAIL = "email"
14 PROFILE = "profile"
15 ADDRESS = "address"
16 PHONE = "phone"
18 # Custom scopes for applications
19 READ = "read"
20 WRITE = "write"
21 DELETE = "delete"
22 ADMIN = "admin"
25class ScopeManager:
26 """Manages OAuth2 scopes and their mappings.
28 Thread-safe class for managing scope-to-permission mappings.
30 .. note::
31 Register as a singleton through ``AuthorizationProvider``.
32 """
34 def __init__(self) -> None:
35 self._lock = threading.Lock()
36 self.scope_permissions: dict[str, set[str]] = {
37 OAuthScope.READ: {"read"},
38 OAuthScope.WRITE: {"read", "write"},
39 OAuthScope.DELETE: {"read", "write", "delete"},
40 OAuthScope.ADMIN: {"read", "write", "delete", "admin"},
41 }
43 def get_scope_permissions(self, scope: str) -> set[str]:
44 """Get permissions associated with a scope."""
45 with self._lock:
46 return set(self.scope_permissions.get(scope, set()))
48 def get_scopes_for_permissions(self, permissions: list[str]) -> set[str]:
49 """Get minimum scopes required for permissions."""
50 with self._lock:
51 required_scopes = set()
52 for perm in permissions:
53 for scope, scope_perms in self.scope_permissions.items():
54 if perm in scope_perms:
55 required_scopes.add(scope)
56 return required_scopes
58 def validate_scopes(
59 self,
60 requested_scopes: list[str],
61 allowed_scopes: list[str],
62 ) -> list[str]:
63 """Validate requested scopes against allowed scopes."""
64 with self._lock:
65 allowed_set = set(allowed_scopes)
66 return list(
67 filter(lambda scope: scope in allowed_set, requested_scopes),
68 )
70 def expand_scope_permissions(self, scopes: list[str]) -> set[str]:
71 """Expand scopes to their associated permissions."""
72 with self._lock:
73 permissions = set()
74 for scope in scopes:
75 permissions.update(self.scope_permissions.get(scope, set()))
76 return permissions
79__all__ = [
80 "OAuthScope",
81 "ScopeManager",
82]