mirror of
https://github.com/langgenius/dify.git
synced 2026-07-15 17:37:38 +08:00
Fetch the caller's tenant role once in a new load_workspace_role prepare step (stashed on AuthData.tenant_role) instead of querying TenantAccountJoin twice — once for membership, once for role. check_workspace_role becomes a pure assertion over the stashed role; non-members get 404 (no cross-tenant ID leak), out-of-set roles 403. Other cleanups: - All prepare steps are now skip-if-already-loaded for safe re-entry. - Move the app.enable_api policy check out of load_app into a dedicated check_app_api_enabled verify step (data-load vs policy-assert separation). - Validate workspace_id is a UUID in load_tenant_from_request (malformed id -> 404, not 500). - Collapse guard/guard_workspace duplication into a shared _make_decorator. - Delete the now-unused role_gate.require_workspace_role decorator and its tests; enforcement lives entirely in the auth pipeline.
75 lines
2.5 KiB
Python
75 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
from controllers.openapi.auth.conditions import (
|
|
EDITION_EE,
|
|
HAS_ALLOWED_ROLES,
|
|
LOADED_APP_IS_PRIVATE,
|
|
PATH_HAS_APP_ID,
|
|
WEBAPP_AUTH_ENABLED,
|
|
WORKSPACE_MEMBERSHIP_REQUIRED,
|
|
)
|
|
from controllers.openapi.auth.data import Edition
|
|
from controllers.openapi.auth.flow import When
|
|
from controllers.openapi.auth.pipeline import AuthPipeline, PipelineRoute, PipelineRouter
|
|
from controllers.openapi.auth.prepare import (
|
|
load_account,
|
|
load_app,
|
|
load_app_access_mode,
|
|
load_tenant,
|
|
load_tenant_from_request,
|
|
load_workspace_role,
|
|
resolve_external_user,
|
|
)
|
|
from controllers.openapi.auth.verify import (
|
|
check_acl,
|
|
check_app_api_enabled,
|
|
check_membership,
|
|
check_private_app_permission,
|
|
check_scope,
|
|
check_workspace_mismatch,
|
|
check_workspace_role,
|
|
)
|
|
from libs.oauth_bearer import TokenType
|
|
|
|
account_pipeline = AuthPipeline(
|
|
prepare=[
|
|
When(PATH_HAS_APP_ID, then=load_app),
|
|
When(PATH_HAS_APP_ID, then=load_tenant),
|
|
When(WORKSPACE_MEMBERSHIP_REQUIRED & ~PATH_HAS_APP_ID, then=load_tenant_from_request),
|
|
load_account,
|
|
When(HAS_ALLOWED_ROLES, then=load_workspace_role),
|
|
When(PATH_HAS_APP_ID & EDITION_EE, then=load_app_access_mode),
|
|
],
|
|
auth=[
|
|
When(PATH_HAS_APP_ID, then=check_app_api_enabled),
|
|
check_scope,
|
|
When((PATH_HAS_APP_ID | WORKSPACE_MEMBERSHIP_REQUIRED) & ~HAS_ALLOWED_ROLES, then=check_membership),
|
|
When(WORKSPACE_MEMBERSHIP_REQUIRED & PATH_HAS_APP_ID, then=check_workspace_mismatch),
|
|
When(HAS_ALLOWED_ROLES, then=check_workspace_role),
|
|
When(PATH_HAS_APP_ID & EDITION_EE & WEBAPP_AUTH_ENABLED, then=check_acl),
|
|
When(EDITION_EE & LOADED_APP_IS_PRIVATE, then=check_private_app_permission),
|
|
],
|
|
)
|
|
|
|
external_sso_pipeline = AuthPipeline(
|
|
prepare=[
|
|
When(PATH_HAS_APP_ID, then=load_app),
|
|
When(PATH_HAS_APP_ID, then=load_tenant),
|
|
When(PATH_HAS_APP_ID, then=resolve_external_user),
|
|
When(PATH_HAS_APP_ID, then=load_app_access_mode),
|
|
],
|
|
auth=[
|
|
When(PATH_HAS_APP_ID, then=check_app_api_enabled),
|
|
check_scope,
|
|
When(PATH_HAS_APP_ID & WEBAPP_AUTH_ENABLED, then=check_acl),
|
|
When(LOADED_APP_IS_PRIVATE, then=check_private_app_permission),
|
|
],
|
|
)
|
|
|
|
auth_router = PipelineRouter(
|
|
{
|
|
TokenType.OAUTH_ACCOUNT: PipelineRoute(account_pipeline),
|
|
TokenType.OAUTH_EXTERNAL_SSO: PipelineRoute(external_sso_pipeline, required_edition=frozenset({Edition.EE})),
|
|
}
|
|
)
|