726 lines
36 KiB
Python
726 lines
36 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from govoplan_access.backend.configuration_provider import ACCESS_CONFIGURATION_CAPABILITY
|
|
from govoplan_access.backend.db.base import AccessBase
|
|
from govoplan_access.backend.db import models as access_models # noqa: F401 - populate access metadata
|
|
from govoplan_core.core.access import (
|
|
CAPABILITY_ACCESS_ADMINISTRATION,
|
|
CAPABILITY_ACCESS_DIRECTORY,
|
|
CAPABILITY_ACCESS_EXPLANATION,
|
|
CAPABILITY_ACCESS_GOVERNANCE_MATERIALIZER,
|
|
CAPABILITY_ACCESS_PERMISSION_EVALUATOR,
|
|
CAPABILITY_ACCESS_PRINCIPAL_RESOLVER,
|
|
CAPABILITY_ACCESS_TENANT_PROVISIONER,
|
|
CAPABILITY_ACCESS_SEMANTIC_DIRECTORY,
|
|
CAPABILITY_AUTH_API_PRINCIPAL_PROVIDER,
|
|
CAPABILITY_AUTH_AUTOMATION_PRINCIPAL_PROVIDER,
|
|
CAPABILITY_AUTH_PERMISSION_EVALUATOR,
|
|
CAPABILITY_AUTH_PRINCIPAL_RESOLVER,
|
|
CAPABILITY_AUTH_TENANT_CONTEXT_SWITCHER,
|
|
ResourceAccessExplanationProvider,
|
|
)
|
|
from govoplan_core.core.campaigns import CAPABILITY_CAMPAIGNS_ACCESS
|
|
from govoplan_core.core.files import CAPABILITY_FILES_ACCESS
|
|
from govoplan_core.core.identity import CAPABILITY_IDENTITY_DIRECTORY, IdentityDirectory
|
|
from govoplan_core.core.idm import CAPABILITY_IDM_DIRECTORY, IdmDirectory
|
|
from govoplan_core.core.organizations import CAPABILITY_ORGANIZATION_DIRECTORY, OrganizationDirectory
|
|
from govoplan_core.core.module_guards import persistent_table_uninstall_guard
|
|
from govoplan_core.core.modules import (
|
|
DocumentationCondition,
|
|
DocumentationLink,
|
|
DocumentationTopic,
|
|
FrontendModule,
|
|
FrontendRoute,
|
|
MigrationSpec,
|
|
ModuleContext,
|
|
ModuleInterfaceProvider,
|
|
ModuleManifest,
|
|
NavItem,
|
|
PermissionDefinition,
|
|
RoleTemplate,
|
|
)
|
|
from govoplan_core.core.people import CAPABILITY_ACCESS_PEOPLE_SEARCH
|
|
from govoplan_core.core.views import ViewSurface
|
|
|
|
|
|
def _permission(scope: str, label: str, description: str, category: str, level: str) -> PermissionDefinition:
|
|
module_id, resource, action = scope.split(":", 2)
|
|
return PermissionDefinition(
|
|
scope=scope,
|
|
label=label,
|
|
description=description,
|
|
category=category,
|
|
level=level, # type: ignore[arg-type]
|
|
module_id=module_id,
|
|
resource=resource,
|
|
action=action,
|
|
)
|
|
|
|
|
|
ACCESS_PERMISSIONS: tuple[PermissionDefinition, ...] = (
|
|
_permission("access:tenant:read", "View tenants", "List and inspect tenant registry entries.", "Access", "system"),
|
|
_permission("access:tenant:create", "Create tenants", "Create tenant registry entries.", "Access", "system"),
|
|
_permission("access:tenant:update", "Update tenants", "Update tenant metadata and activation state.", "Access", "system"),
|
|
_permission("access:tenant:suspend", "Suspend tenants", "Activate or suspend tenant spaces while preserving evidence.", "Access", "system"),
|
|
_permission("access:account:read", "View accounts", "List and inspect global login accounts.", "Access", "system"),
|
|
_permission("access:account:create", "Create accounts", "Create global login accounts.", "Access", "system"),
|
|
_permission("access:account:update", "Update accounts", "Update or suspend global login accounts.", "Access", "system"),
|
|
_permission("access:account:suspend", "Suspend accounts", "Activate or suspend global login accounts while preserving a system owner.", "Access", "system"),
|
|
_permission("access:system_role:read", "View system roles", "Inspect instance-wide role definitions and their permissions.", "Access", "system"),
|
|
_permission("access:system_role:write", "Define system roles", "Create and edit instance-wide role definitions within delegation limits.", "Access", "system"),
|
|
_permission("access:system_role:assign", "Assign system roles", "Assign instance-wide roles to accounts while preserving a system owner.", "Access", "system"),
|
|
_permission("access:system_setting:read", "View system settings", "Read instance defaults and tenant-governance defaults.", "Access", "system"),
|
|
_permission("access:system_setting:write", "Manage system settings", "Change instance defaults and tenant-governance defaults.", "Access", "system"),
|
|
_permission("access:system_credential:read", "View system credentials", "List instance-wide reusable credential envelopes without revealing secret values.", "Access", "system"),
|
|
_permission("access:system_credential:write", "Manage system credentials", "Create, update, and retire instance-wide reusable credential envelopes.", "Access", "system"),
|
|
_permission("access:maintenance:access", "Access during maintenance", "Use the system while maintenance mode is active.", "Access", "system"),
|
|
_permission("access:audit:read", "View system audit", "Read audit records across tenants.", "Access", "system"),
|
|
_permission("access:membership:read", "View memberships", "List tenant memberships and effective access.", "Tenant access", "tenant"),
|
|
_permission("access:membership:create", "Create memberships", "Create tenant-local account memberships.", "Tenant access", "tenant"),
|
|
_permission("access:membership:update", "Update memberships", "Update or suspend tenant memberships.", "Tenant access", "tenant"),
|
|
_permission("access:group:read", "View groups", "List tenant groups and members.", "Tenant access", "tenant"),
|
|
_permission("access:group:write", "Manage groups", "Create and update tenant groups.", "Tenant access", "tenant"),
|
|
_permission("access:group:manage_members", "Manage group members", "Add and remove memberships from groups.", "Tenant access", "tenant"),
|
|
_permission("access:role:read", "View roles", "Inspect tenant and system role definitions.", "Tenant access", "tenant"),
|
|
_permission("access:role:write", "Manage roles", "Create and update assignable roles.", "Tenant access", "tenant"),
|
|
_permission("access:role:assign", "Assign roles", "Bind roles to memberships, groups, accounts or services.", "Tenant access", "tenant"),
|
|
_permission("access:function:read", "View functions", "Inspect organization-bound functions and assignments.", "Tenant access", "tenant"),
|
|
_permission("access:function:write", "Manage functions", "Create and update organization units, functions, and role mappings.", "Tenant access", "tenant"),
|
|
_permission("access:function:assign", "Assign functions", "Assign organization-bound functions to accounts.", "Tenant access", "tenant"),
|
|
_permission("access:function:delegate", "Delegate functions", "Create and revoke permitted function delegations.", "Tenant access", "tenant"),
|
|
_permission("access:api_key:read", "View API keys", "List API keys without revealing secrets.", "Tenant access", "tenant"),
|
|
_permission("access:api_key:create", "Create API keys", "Create tenant API keys within delegation limits.", "Tenant access", "tenant"),
|
|
_permission("access:api_key:revoke", "Revoke API keys", "Revoke tenant API keys.", "Tenant access", "tenant"),
|
|
_permission("access:setting:read", "View settings", "Read access and governance settings.", "Tenant access", "tenant"),
|
|
_permission("access:setting:write", "Manage settings", "Update access and governance settings.", "Tenant access", "tenant"),
|
|
_permission("access:credential:read", "View credentials", "List reusable credential envelopes without revealing secret values.", "Tenant access", "tenant"),
|
|
_permission("access:credential:write", "Manage credentials", "Create, update, and retire reusable credential envelopes.", "Tenant access", "tenant"),
|
|
_permission("access:credential:manage_own", "Manage own credentials", "Manage reusable credentials owned by the current membership.", "Tenant access", "tenant"),
|
|
_permission("access:policy:read", "View tenant policies", "Read tenant policy and governance settings.", "Tenant access", "tenant"),
|
|
_permission("access:policy:write", "Manage tenant policies", "Change tenant policy and governance settings where system policy permits it.", "Tenant access", "tenant"),
|
|
_permission("access:governance:read", "View governance", "Inspect managed role and group templates.", "Access", "system"),
|
|
_permission("access:governance:write", "Manage governance", "Create and assign managed role and group templates.", "Access", "system"),
|
|
)
|
|
|
|
ACCESS_ROLE_TEMPLATES: tuple[RoleTemplate, ...] = (
|
|
RoleTemplate(
|
|
slug="system_owner",
|
|
name="System owner",
|
|
description="Protected full instance-wide administration.",
|
|
permissions=("system:*",),
|
|
level="system",
|
|
managed=True,
|
|
protected=True,
|
|
),
|
|
RoleTemplate(
|
|
slug="system_admin",
|
|
name="System administrator",
|
|
description="Manage tenants, accounts, settings, and governance without protected owner status.",
|
|
permissions=(
|
|
"access:tenant:read",
|
|
"access:tenant:create",
|
|
"access:tenant:update",
|
|
"access:tenant:suspend",
|
|
"access:account:read",
|
|
"access:account:create",
|
|
"access:account:update",
|
|
"access:account:suspend",
|
|
"access:system_role:read",
|
|
"access:system_role:write",
|
|
"access:system_role:assign",
|
|
"access:system_setting:read",
|
|
"access:system_setting:write",
|
|
"access:system_credential:read",
|
|
"access:system_credential:write",
|
|
"access:governance:read",
|
|
"access:governance:write",
|
|
),
|
|
level="system",
|
|
managed=False,
|
|
protected=False,
|
|
),
|
|
RoleTemplate(
|
|
slug="system_auditor",
|
|
name="System auditor",
|
|
description="Read tenant registry, accounts, system roles, settings, governance, and cross-tenant audit records.",
|
|
permissions=(
|
|
"access:tenant:read",
|
|
"access:account:read",
|
|
"access:system_role:read",
|
|
"access:audit:read",
|
|
"access:system_setting:read",
|
|
"access:governance:read",
|
|
),
|
|
level="system",
|
|
managed=False,
|
|
protected=False,
|
|
),
|
|
RoleTemplate(
|
|
slug="maintenance_operator",
|
|
name="Maintenance operator",
|
|
description="Access the system while maintenance mode is active.",
|
|
permissions=("access:system_setting:read", "access:maintenance:access"),
|
|
level="system",
|
|
managed=False,
|
|
protected=False,
|
|
),
|
|
RoleTemplate(
|
|
slug="owner",
|
|
name="Tenant owner",
|
|
description="Protected full tenant administration and module access.",
|
|
permissions=("tenant:*",),
|
|
level="tenant",
|
|
managed=True,
|
|
protected=True,
|
|
),
|
|
RoleTemplate(
|
|
slug="tenant_admin",
|
|
name="Tenant administrator",
|
|
description="Manage tenant settings, policies, users, groups, roles and API keys.",
|
|
permissions=(
|
|
"access:membership:read",
|
|
"access:membership:create",
|
|
"access:membership:update",
|
|
"access:group:read",
|
|
"access:group:write",
|
|
"access:group:manage_members",
|
|
"access:role:read",
|
|
"access:role:write",
|
|
"access:role:assign",
|
|
"access:api_key:read",
|
|
"access:api_key:create",
|
|
"access:api_key:revoke",
|
|
"access:setting:read",
|
|
"access:setting:write",
|
|
"access:credential:read",
|
|
"access:credential:write",
|
|
"access:policy:read",
|
|
"access:policy:write",
|
|
),
|
|
level="tenant",
|
|
managed=True,
|
|
protected=False,
|
|
),
|
|
RoleTemplate(
|
|
slug="admin",
|
|
name="Administrator (legacy)",
|
|
description="Legacy broad tenant role retained for upgraded installations.",
|
|
permissions=("tenant:*",),
|
|
level="tenant",
|
|
managed=True,
|
|
protected=False,
|
|
),
|
|
RoleTemplate(
|
|
slug="access_admin",
|
|
name="Access administrator",
|
|
description="Manage memberships, groups, roles, and API keys within delegation limits.",
|
|
permissions=(
|
|
"access:membership:read",
|
|
"access:membership:create",
|
|
"access:membership:update",
|
|
"access:group:read",
|
|
"access:group:write",
|
|
"access:group:manage_members",
|
|
"access:role:read",
|
|
"access:role:assign",
|
|
"access:function:read",
|
|
"access:function:write",
|
|
"access:function:assign",
|
|
"access:function:delegate",
|
|
"access:api_key:read",
|
|
"access:api_key:create",
|
|
"access:api_key:revoke",
|
|
),
|
|
level="tenant",
|
|
managed=True,
|
|
protected=False,
|
|
),
|
|
)
|
|
|
|
ADMIN_READ_SCOPES = (
|
|
"admin:users:read",
|
|
"admin:groups:read",
|
|
"admin:roles:read",
|
|
"admin:api_keys:read",
|
|
"admin:settings:read",
|
|
"system:tenants:read",
|
|
"system:accounts:read",
|
|
"system:roles:read",
|
|
"system:settings:read",
|
|
"system:governance:read",
|
|
"system:audit:read",
|
|
"access:tenant:read",
|
|
"access:account:read",
|
|
"access:governance:read",
|
|
"access:function:read",
|
|
"views:definition:read",
|
|
"views:assignment:read",
|
|
"views:system_definition:read",
|
|
"views:system_assignment:read",
|
|
)
|
|
|
|
ACCESS_DOCUMENTATION: tuple[DocumentationTopic, ...] = (
|
|
DocumentationTopic(
|
|
id="access.workflow.grant-user-access",
|
|
title="Grant a person access",
|
|
summary="Use the access administration screens to create or update a tenant membership, place the person in groups, and assign only the roles they need.",
|
|
body="The common path is to find or create the person, review their existing membership, then use groups and roles to grant access. If a role or group is not available, the active governance rules or your own delegation limit may block the change.",
|
|
layer="configured",
|
|
documentation_types=("admin", "user"),
|
|
audience=("tenant_admin", "access_admin"),
|
|
order=30,
|
|
conditions=(
|
|
DocumentationCondition(
|
|
required_modules=("access",),
|
|
any_scopes=(
|
|
"admin:users:read",
|
|
"admin:groups:read",
|
|
"admin:roles:read",
|
|
"access:membership:read",
|
|
"access:group:read",
|
|
"access:role:read",
|
|
),
|
|
),
|
|
),
|
|
links=(
|
|
DocumentationLink(label="Access administration", href="/admin", kind="runtime"),
|
|
DocumentationLink(label="Users API", href="/api/v1/admin/users", kind="api"),
|
|
DocumentationLink(label="Groups API", href="/api/v1/admin/groups", kind="api"),
|
|
DocumentationLink(label="Roles API", href="/api/v1/admin/roles", kind="api"),
|
|
),
|
|
configuration_keys=("access_governance",),
|
|
metadata={
|
|
"kind": "workflow",
|
|
"outcome": "A person can sign in to the tenant and receives the intended access through groups and roles.",
|
|
"prerequisites": [
|
|
"You can open Admin.",
|
|
"You may read users, groups, and roles.",
|
|
"Write or assignment actions require matching management permissions.",
|
|
],
|
|
"steps": [
|
|
"Open Admin and go to Users.",
|
|
"Find the existing person or create a membership with their email address and display name.",
|
|
"Review current groups and direct roles before changing anything.",
|
|
"Add the person to the smallest group that grants the needed shared access.",
|
|
"Assign direct roles only when a group does not match the case.",
|
|
"Save and review any blocker message before asking a system or tenant owner for help.",
|
|
],
|
|
"result": "The membership has the intended effective permissions and no broader roles than necessary.",
|
|
"verification": "Open the user again and compare groups, direct roles, and effective permissions with the request.",
|
|
"related_field_ids": [
|
|
"access.user.email",
|
|
"access.user.display_name",
|
|
"access.user.groups",
|
|
"access.user.roles",
|
|
],
|
|
"related_topic_ids": [
|
|
"access.reference.admin-access-fields",
|
|
"docs.pattern.field-help",
|
|
],
|
|
},
|
|
),
|
|
DocumentationTopic(
|
|
id="access.reference.admin-access-fields",
|
|
title="Access administration fields",
|
|
summary="The access administration screens show tenant memberships, groups, roles, and API keys. Admin docs map the visible fields to API payloads and permission scopes.",
|
|
body="Users need the visible labels and a short explanation. Admins also need the backing route, API field, permission, and governance note so they can diagnose unavailable actions.",
|
|
layer="configured",
|
|
documentation_types=("admin", "user"),
|
|
audience=("tenant_admin", "access_admin", "operator"),
|
|
order=31,
|
|
conditions=(
|
|
DocumentationCondition(
|
|
required_modules=("access",),
|
|
any_scopes=(
|
|
"admin:users:read",
|
|
"admin:groups:read",
|
|
"admin:roles:read",
|
|
"admin:api_keys:read",
|
|
"access:membership:read",
|
|
"access:group:read",
|
|
"access:role:read",
|
|
"access:api_key:read",
|
|
),
|
|
),
|
|
),
|
|
links=(
|
|
DocumentationLink(label="Access administration", href="/admin", kind="runtime"),
|
|
DocumentationLink(label="Users API", href="/api/v1/admin/users", kind="api"),
|
|
DocumentationLink(label="Groups API", href="/api/v1/admin/groups", kind="api"),
|
|
DocumentationLink(label="Roles API", href="/api/v1/admin/roles", kind="api"),
|
|
DocumentationLink(label="API keys API", href="/api/v1/admin/api-keys", kind="api"),
|
|
),
|
|
configuration_keys=("access_governance",),
|
|
metadata={
|
|
"kind": "reference",
|
|
"route": "/admin",
|
|
"screen": "Admin",
|
|
"section": "Users, groups, roles, and API keys",
|
|
"fields": [
|
|
{
|
|
"field_id": "access.user.email",
|
|
"label": "Email",
|
|
"user_description": "The address used to identify the person when they sign in.",
|
|
"admin_description": "Stored on the account and membership payloads. It must be normalized and unique for the relevant login account.",
|
|
"api_path": "/api/v1/admin/users",
|
|
"api_field": "email",
|
|
"permission_scope": "access:membership:create",
|
|
"validation": "Must be a valid email address.",
|
|
"provenance": "Tenant membership creation or account lookup.",
|
|
},
|
|
{
|
|
"field_id": "access.user.display_name",
|
|
"label": "Display name",
|
|
"user_description": "The readable name shown in user lists and review screens.",
|
|
"admin_description": "Maps to display_name on user and account responses where available.",
|
|
"api_path": "/api/v1/admin/users",
|
|
"api_field": "display_name",
|
|
"permission_scope": "access:membership:update",
|
|
"validation": "Human-readable text; keep it recognizable for administrators.",
|
|
"provenance": "Tenant membership profile.",
|
|
},
|
|
{
|
|
"field_id": "access.user.groups",
|
|
"label": "Groups",
|
|
"user_description": "Shared access bundles that can add roles for many people at once.",
|
|
"admin_description": "Maps to group_ids when updating a user or group membership.",
|
|
"api_path": "/api/v1/admin/users/{user_id}",
|
|
"api_field": "group_ids",
|
|
"permission_scope": "access:group:manage_members",
|
|
"validation": "Groups must belong to the same tenant.",
|
|
"provenance": "User-group membership rows.",
|
|
},
|
|
{
|
|
"field_id": "access.user.roles",
|
|
"label": "Roles",
|
|
"user_description": "Direct access grants assigned to one person or inherited from groups.",
|
|
"admin_description": "Maps to role_ids on user and group role update requests.",
|
|
"api_path": "/api/v1/admin/users/{user_id}",
|
|
"api_field": "role_ids",
|
|
"permission_scope": "access:role:assign",
|
|
"validation": "Roles must be assignable and cannot exceed the actor's delegation limit.",
|
|
"provenance": "Direct user roles plus group role inheritance.",
|
|
},
|
|
{
|
|
"field_id": "access.api_key.scopes",
|
|
"label": "Scopes",
|
|
"user_description": "The actions an API key may perform.",
|
|
"admin_description": "Maps to scopes when creating an API key and is intersected with the owner's current permissions.",
|
|
"api_path": "/api/v1/admin/api-keys",
|
|
"api_field": "scopes",
|
|
"permission_scope": "access:api_key:create",
|
|
"validation": "Use the narrowest scopes possible.",
|
|
"provenance": "API key grant plus owner delegation.",
|
|
},
|
|
],
|
|
"related_topic_ids": [
|
|
"access.workflow.grant-user-access",
|
|
"docs.pattern.field-help",
|
|
],
|
|
},
|
|
),
|
|
DocumentationTopic(
|
|
id="access.reference.external-function-role-mappings",
|
|
title="Organization function facts and access roles",
|
|
summary="Organizations defines function facts, IDM assigns them to identities, and Access maps accepted facts to roles and permissions.",
|
|
body=(
|
|
"Organizations owns the organization meta-model, concrete units, structures, and functions. IDM owns the fact that an identity, through one of its accounts, holds a function in an organization unit, including delegated and acting-for assignments. "
|
|
"Access consumes those accepted IDM facts through the directory capability, validates function identifiers against Organizations, and turns them into rights only when an explicit external function role mapping connects the organization function ID to an assignable tenant role. "
|
|
"The assignment itself does not grant rights. Removing the IDM assignment, disabling the Organizations function, or removing the Access mapping stops the derived role source from contributing effective permissions. "
|
|
"Tenant administrators inspect this from the user access explanation dialog: role sources link back to the Organizations function or unit that defines the fact and to the IDM assignment that produced it. "
|
|
"The same explanation is exposed by the admin API, while mapping management remains under Admin > Function role mappings. This keeps the audit trail clear: Organizations records what can exist, IDM records who holds it, and Access records which accepted facts produce permissions."
|
|
),
|
|
layer="configured",
|
|
documentation_types=("admin", "user"),
|
|
audience=("tenant_admin", "access_admin", "operator"),
|
|
order=32,
|
|
conditions=(
|
|
DocumentationCondition(
|
|
required_modules=("access", "organizations"),
|
|
any_scopes=("access:function:read", "access:role:read", "admin:roles:read"),
|
|
),
|
|
),
|
|
links=(
|
|
DocumentationLink(label="Function role mappings", href="/admin?section=tenant-function-role-mappings", kind="runtime"),
|
|
DocumentationLink(label="External function role mappings API", href="/api/v1/admin/external-function-role-mappings", kind="api"),
|
|
DocumentationLink(label="Effective user access explanation API", href="/api/v1/admin/users/{user_id}/access-explanation", kind="api"),
|
|
DocumentationLink(label="Organizations functions", href="/organizations?section=functions", kind="runtime"),
|
|
DocumentationLink(label="IDM assignments", href="/idm", kind="runtime"),
|
|
),
|
|
metadata={
|
|
"kind": "reference",
|
|
"route": "/admin",
|
|
"api_path": "/api/v1/admin/external-function-role-mappings",
|
|
"explanation_api_path": "/api/v1/admin/users/{user_id}/access-explanation",
|
|
"runtime_routes": ["/admin?section=tenant-function-role-mappings", "/organizations?section=functions", "/idm"],
|
|
"permission_scopes": ["access:function:write", "access:role:assign"],
|
|
"responsibility_boundaries": {
|
|
"organizations": "Defines organization units, structures, function types, and functions.",
|
|
"idm": "Assigns organization functions to identities and accounts, including delegation and acting-for facts.",
|
|
"access": "Maps accepted function facts to tenant roles and explains effective permissions.",
|
|
},
|
|
"related_topic_ids": [
|
|
"idm.workflow.assign-function-to-identity",
|
|
"docs.reference.organization-identity-idm-access-boundary",
|
|
],
|
|
},
|
|
),
|
|
)
|
|
|
|
|
|
def _legacy_principal_resolver(context: ModuleContext) -> object:
|
|
from govoplan_access.backend.auth.dependencies import LegacyPrincipalResolver
|
|
|
|
return LegacyPrincipalResolver(
|
|
idm_directory=_optional_idm_directory(context),
|
|
identity_directory=_optional_identity_directory(context),
|
|
organization_directory=_optional_organization_directory(context),
|
|
)
|
|
|
|
|
|
def _legacy_permission_evaluator(context: ModuleContext) -> object:
|
|
del context
|
|
from govoplan_access.backend.auth.dependencies import LegacyPermissionEvaluator
|
|
|
|
return LegacyPermissionEvaluator()
|
|
|
|
|
|
def _api_principal_provider(context: ModuleContext) -> object:
|
|
del context
|
|
from govoplan_access.backend.auth.dependencies import AccessApiPrincipalProvider
|
|
|
|
return AccessApiPrincipalProvider()
|
|
|
|
|
|
def _automation_principal_provider(context: ModuleContext) -> object:
|
|
from govoplan_access.backend.auth.dependencies import (
|
|
AccessAutomationPrincipalProvider,
|
|
)
|
|
|
|
return AccessAutomationPrincipalProvider(
|
|
idm_directory=_optional_idm_directory(context),
|
|
identity_directory=_optional_identity_directory(context),
|
|
organization_directory=_optional_organization_directory(context),
|
|
)
|
|
|
|
|
|
def _tenant_context_switcher(context: ModuleContext) -> object:
|
|
del context
|
|
from govoplan_access.backend.auth.tenant_context import AccessTenantContextSwitcher
|
|
|
|
return AccessTenantContextSwitcher()
|
|
|
|
|
|
def _access_directory(context: ModuleContext) -> object:
|
|
from govoplan_access.backend.directory import SqlAccessDirectory
|
|
|
|
return SqlAccessDirectory(
|
|
idm_directory=_optional_idm_directory(context),
|
|
identity_directory=_optional_identity_directory(context),
|
|
organization_directory=_optional_organization_directory(context),
|
|
)
|
|
|
|
|
|
def _access_semantic_directory(context: ModuleContext) -> object:
|
|
from govoplan_access.backend.directory import SqlAccessDirectory
|
|
|
|
return SqlAccessDirectory(
|
|
idm_directory=_optional_idm_directory(context),
|
|
identity_directory=_optional_identity_directory(context),
|
|
organization_directory=_optional_organization_directory(context),
|
|
)
|
|
|
|
|
|
def _optional_identity_directory(context: ModuleContext) -> IdentityDirectory | None:
|
|
if not context.registry.has_capability(CAPABILITY_IDENTITY_DIRECTORY):
|
|
return None
|
|
capability = context.registry.require_capability(CAPABILITY_IDENTITY_DIRECTORY)
|
|
if not isinstance(capability, IdentityDirectory):
|
|
raise RuntimeError(f"Invalid capability: {CAPABILITY_IDENTITY_DIRECTORY}")
|
|
return capability
|
|
|
|
|
|
def _optional_idm_directory(context: ModuleContext) -> IdmDirectory | None:
|
|
if not context.registry.has_capability(CAPABILITY_IDM_DIRECTORY):
|
|
return None
|
|
capability = context.registry.require_capability(CAPABILITY_IDM_DIRECTORY)
|
|
if not isinstance(capability, IdmDirectory):
|
|
raise RuntimeError(f"Invalid capability: {CAPABILITY_IDM_DIRECTORY}")
|
|
return capability
|
|
|
|
|
|
def _optional_organization_directory(context: ModuleContext) -> OrganizationDirectory | None:
|
|
if not context.registry.has_capability(CAPABILITY_ORGANIZATION_DIRECTORY):
|
|
return None
|
|
capability = context.registry.require_capability(CAPABILITY_ORGANIZATION_DIRECTORY)
|
|
if not isinstance(capability, OrganizationDirectory):
|
|
raise RuntimeError(f"Invalid capability: {CAPABILITY_ORGANIZATION_DIRECTORY}")
|
|
return capability
|
|
|
|
|
|
def _resource_explanation_providers(context: ModuleContext) -> tuple[ResourceAccessExplanationProvider, ...]:
|
|
providers: list[ResourceAccessExplanationProvider] = []
|
|
for capability_name in (CAPABILITY_FILES_ACCESS, CAPABILITY_CAMPAIGNS_ACCESS):
|
|
if not context.registry.has_capability(capability_name):
|
|
continue
|
|
capability = context.registry.require_capability(capability_name)
|
|
if isinstance(capability, ResourceAccessExplanationProvider):
|
|
providers.append(capability)
|
|
return tuple(providers)
|
|
|
|
|
|
def _access_explanation_service(context: ModuleContext) -> object:
|
|
from govoplan_access.backend.explanation import SqlAccessExplanationService
|
|
|
|
return SqlAccessExplanationService(
|
|
identity_directory=_optional_identity_directory(context),
|
|
idm_directory=_optional_idm_directory(context),
|
|
organization_directory=_optional_organization_directory(context),
|
|
resource_explanation_providers=_resource_explanation_providers(context),
|
|
)
|
|
|
|
|
|
def _tenant_provisioner(context: ModuleContext) -> object:
|
|
del context
|
|
from govoplan_access.backend.tenancy.provisioning import LegacyTenantAccessProvisioner
|
|
|
|
return LegacyTenantAccessProvisioner()
|
|
|
|
|
|
def _access_administration(context: ModuleContext) -> object:
|
|
del context
|
|
from govoplan_access.backend.administration import SqlAccessAdministration
|
|
|
|
return SqlAccessAdministration()
|
|
|
|
|
|
def _governance_materializer(context: ModuleContext) -> object:
|
|
del context
|
|
from govoplan_access.backend.governance_materializer import SqlAccessGovernanceMaterializer
|
|
|
|
return SqlAccessGovernanceMaterializer()
|
|
|
|
|
|
def _configuration_provider(context: ModuleContext) -> object:
|
|
del context
|
|
from govoplan_access.backend.configuration_provider import SqlAccessConfigurationProvider
|
|
|
|
return SqlAccessConfigurationProvider()
|
|
|
|
|
|
def _route_factory(context: ModuleContext):
|
|
from fastapi import APIRouter
|
|
|
|
from govoplan_access.backend.runtime import configure_runtime
|
|
|
|
configure_runtime(context)
|
|
|
|
from govoplan_access.backend.api.v1.auth import router as auth_router
|
|
from govoplan_access.backend.api.v1.routes import router as access_admin_router
|
|
|
|
router = APIRouter()
|
|
router.include_router(auth_router)
|
|
router.include_router(access_admin_router)
|
|
return router
|
|
|
|
|
|
def _people_search(context: ModuleContext) -> object:
|
|
from govoplan_access.backend.people_search import people_search_capability
|
|
|
|
return people_search_capability(context)
|
|
|
|
|
|
manifest = ModuleManifest(
|
|
id="access",
|
|
name="Access",
|
|
version="0.1.11",
|
|
optional_dependencies=("identity", "organizations", "tenancy", "idm"),
|
|
provides_interfaces=(
|
|
ModuleInterfaceProvider(name=CAPABILITY_ACCESS_PEOPLE_SEARCH, version="0.1.0"),
|
|
ModuleInterfaceProvider(
|
|
name="auth.automation_principal",
|
|
version="0.1.0",
|
|
),
|
|
),
|
|
permissions=ACCESS_PERMISSIONS,
|
|
role_templates=ACCESS_ROLE_TEMPLATES,
|
|
route_factory=_route_factory,
|
|
migration_spec=MigrationSpec(
|
|
module_id="access",
|
|
metadata=AccessBase.metadata,
|
|
script_location=str(Path(__file__).with_name("migrations") / "versions"),
|
|
),
|
|
uninstall_guard_providers=(
|
|
persistent_table_uninstall_guard(
|
|
access_models.Account,
|
|
access_models.Identity,
|
|
access_models.IdentityAccountLink,
|
|
access_models.User,
|
|
access_models.Group,
|
|
access_models.Role,
|
|
access_models.OrganizationUnit,
|
|
access_models.Function,
|
|
access_models.FunctionRoleAssignment,
|
|
access_models.ExternalFunctionRoleAssignment,
|
|
access_models.FunctionAssignment,
|
|
access_models.FunctionDelegation,
|
|
access_models.SystemRoleAssignment,
|
|
access_models.UserGroupMembership,
|
|
access_models.UserRoleAssignment,
|
|
access_models.GroupRoleAssignment,
|
|
access_models.ApiKey,
|
|
access_models.AuthSession,
|
|
label="Access",
|
|
),
|
|
),
|
|
nav_items=(NavItem(path="/admin", label="Admin", icon="admin", required_any=ADMIN_READ_SCOPES, order=900),),
|
|
frontend=FrontendModule(
|
|
module_id="access",
|
|
package_name="@govoplan/access-webui",
|
|
routes=(FrontendRoute(path="/admin", component="AdminPage", required_any=ADMIN_READ_SCOPES, order=900),),
|
|
nav_items=(NavItem(path="/admin", label="Admin", icon="admin", required_any=ADMIN_READ_SCOPES, order=900),),
|
|
view_surfaces=(
|
|
ViewSurface(id="access.admin.system-tenants", module_id="access", kind="section", label="System tenants", order=10),
|
|
ViewSurface(id="access.admin.system-roles", module_id="access", kind="section", label="System roles", order=20),
|
|
ViewSurface(id="access.admin.system-users", module_id="access", kind="section", label="System users", order=50),
|
|
ViewSurface(id="access.admin.system-credentials", module_id="access", kind="section", label="System credentials", order=80),
|
|
ViewSurface(id="access.admin.tenant-roles", module_id="access", kind="section", label="Tenant roles", order=10),
|
|
ViewSurface(id="access.admin.tenant-function-mappings", module_id="access", kind="section", label="Function mappings", order=20),
|
|
ViewSurface(id="access.admin.tenant-groups", module_id="access", kind="section", label="Tenant groups", order=30),
|
|
ViewSurface(id="access.admin.tenant-users", module_id="access", kind="section", label="Tenant users", order=40),
|
|
ViewSurface(id="access.admin.tenant-credentials", module_id="access", kind="section", label="Tenant credentials", order=70),
|
|
ViewSurface(id="access.admin.tenant-api-keys", module_id="access", kind="section", label="Tenant API keys", order=80),
|
|
ViewSurface(id="access.admin.tenant-settings", module_id="access", kind="section", label="Tenant settings", order=90),
|
|
ViewSurface(id="access.admin.group-credentials", module_id="access", kind="section", label="Group credentials", order=30),
|
|
ViewSurface(id="access.admin.user-credentials", module_id="access", kind="section", label="User credentials", order=30),
|
|
ViewSurface(id="access.settings.credentials", module_id="access", kind="section", label="Personal credentials", order=30),
|
|
),
|
|
),
|
|
capability_factories={
|
|
CAPABILITY_AUTH_API_PRINCIPAL_PROVIDER: _api_principal_provider,
|
|
CAPABILITY_AUTH_AUTOMATION_PRINCIPAL_PROVIDER: (
|
|
_automation_principal_provider
|
|
),
|
|
CAPABILITY_AUTH_PRINCIPAL_RESOLVER: _legacy_principal_resolver,
|
|
CAPABILITY_AUTH_PERMISSION_EVALUATOR: _legacy_permission_evaluator,
|
|
CAPABILITY_AUTH_TENANT_CONTEXT_SWITCHER: _tenant_context_switcher,
|
|
CAPABILITY_ACCESS_PRINCIPAL_RESOLVER: _legacy_principal_resolver,
|
|
CAPABILITY_ACCESS_PERMISSION_EVALUATOR: _legacy_permission_evaluator,
|
|
CAPABILITY_ACCESS_DIRECTORY: _access_directory,
|
|
CAPABILITY_ACCESS_SEMANTIC_DIRECTORY: _access_semantic_directory,
|
|
CAPABILITY_ACCESS_EXPLANATION: _access_explanation_service,
|
|
CAPABILITY_ACCESS_TENANT_PROVISIONER: _tenant_provisioner,
|
|
CAPABILITY_ACCESS_ADMINISTRATION: _access_administration,
|
|
CAPABILITY_ACCESS_GOVERNANCE_MATERIALIZER: _governance_materializer,
|
|
CAPABILITY_ACCESS_PEOPLE_SEARCH: _people_search,
|
|
ACCESS_CONFIGURATION_CAPABILITY: _configuration_provider,
|
|
},
|
|
documentation=ACCESS_DOCUMENTATION,
|
|
)
|
|
|
|
|
|
def get_manifest() -> ModuleManifest:
|
|
return manifest
|