Identity and Access Management (IAM)¶
The shared.iam package provides a unified system for authentication and authorization across all Alan applications.
Overview¶
The IAM system is built around three core concepts:
- Authentication Context - Tracks who is making a request (the "principal") and on whose behalf
- Auth Context Providers - Extract authentication information from incoming requests
- Access Policies (ABAC) - Define and enforce fine-grained access control rules
flowchart LR
A[Request] --> B[AuthContextProvider]
B --> C[AuthContext]
C --> D[AccessPolicy]
B -.- B1["Extract auth from headers"]
C -.- C1["Store principal info"]
D -.- D1["Enforce access rules"]
Key Components¶
AuthPrincipal¶
A principal is any entity that can be authenticated - members, alaners, external contractors, service accountsโฆ All
authenticatable models must implement the AuthPrincipal mixin:
from shared.iam.auth_principal import AuthPrincipal, AuthPrincipalType
from shared.models.orm.base import BaseModel
class User(AuthPrincipal, BaseModel):
__auth_principal_type__ = AuthPrincipalType.front_office
__identifier_column__ = "email" # Column used for lookups
@property
def is_active(self) -> bool:
return not self.deleted
@property
def principal_name(self) -> str:
return self.full_name
Principal Types:
front_office- End users (members, company admins)back_office- principals with anAlanEmployeeentry (Alaners, contractors, service accounts)
AuthContext¶
The AuthContext is a frozen dataclass that stores authentication state for each request. It tracks:
- Real principal - The actual actor performing the action
- Effective principal - The subject of the action (same as real, or an impersonated user)
- Delegate principal - Optional principal acting on behalf of the real principal
- Session info - Session ID, scopes, and metadata
Never create AuthContext manually
Always access the auth context via current_auth_context. The context is managed by auth providers and must never be
instantiated directly. Creating an AuthContext manually bypasses security controls and breaks audit trails.
Access it via current_auth_context:
from shared.iam.helpers import current_auth_context
# Check authentication status
if current_auth_context.is_authenticated:
user = current_auth_context.real_principal_as(User)
print(f"Request by {user.email}")
# Check for impersonation
if current_auth_context.is_impersonated:
actor = current_auth_context.real_principal # Alaner or ExternalUser
subject = current_auth_context.effective_principal # Impersonated user
See Authentication Context โง for detailed documentation.
Auth Context Providers¶
Providers extract authentication information from incoming requests (JWT tokens, cookies, headers) and set up the
AuthContext. They're evaluated in a chain until exactly one matches.
Default setup: The default provider chain is configured at app initialization via
CustomApi.register_default_auth_context_providers(). Most blueprints inherit this default.
Blueprint customization: Individual blueprints can override the chain:
- In the
CustomBlueprintconstructor viaauth_context_providersparameter - During blueprint registration
from shared.api.custom_smorest_blueprint import CustomBlueprint
from shared.iam.auth_context.providers.zero_trust import ZeroTrustAuthContextProvider
from shared.iam.auth_context.providers.anonymous import AnonymousAuthContextProvider
from apps.eu_tools.alan_home.models.alaner import Alaner
# Blueprint with custom auth providers
public_blueprint = CustomBlueprint(
"public",
__name__,
auth_context_providers=[
ZeroTrustAuthContextProvider(Alaner),
AnonymousAuthContextProvider(), # Allow unauthenticated access
],
)
See Authentication Context โง for provider documentation.
Access Policies (ABAC)¶
Attribute-Based Access Control policies define who can do what. Policies are generally enforced using the
@enforce_policy decorator:
from shared.iam.abac.access_policy import AccessPolicy, enforce_policy
class DocumentOwnerPolicy(AccessPolicy):
"""Only document owners can access their documents"""
policy_id = "document-owner"
@classmethod
def evaluate(cls, document_id: int) -> bool:
doc = get_document(document_id)
return doc.owner_id == current_auth_context.effective_principal.id
@enforce_policy(DocumentOwnerPolicy)
def get_document(document_id: int) -> Document:
return get_or_404(Document, document_id)
See Access Control โง for detailed ABAC documentation.
Quick Reference¶
| Component | Purpose | Key Import |
|---|---|---|
current_auth_context |
Access current request's auth info | from shared.iam.helpers import current_auth_context |
set_auth_context |
Set auth context (for providers) | from shared.iam.helpers import set_auth_context |
AuthContextProvider |
Base class for auth extraction | from shared.iam.auth_context.providers.base import AuthContextProvider |
AccessPolicy |
Base class for access rules | from shared.iam.abac.access_policy import AccessPolicy |
enforce_policy |
Decorator to enforce policies | from shared.iam.abac.access_policy import enforce_policy |
Reference¶
- Authentication Context โง - AuthContext, providers, impersonation
- Access Control โง - AccessPolicy, enforce_policy, built-in policies
- Audit Trail โง - TransactionAuthContext, versioning integration, structured logging