mirror of
https://github.com/langgenius/dify.git
synced 2026-11-12 06:11:12 +08:00
feat(rbac): agent RBAC/ACL scenes and resource-locator check bundles (#41768)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
60e983c493
commit
86134ea99e
152 files changed
+5360
-3405
No files matched your search
@@ -6,7 +6,7 @@ from enum import StrEnum
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from werkzeug.exceptions import InternalServerError
|
||||
|
||||
from core.rbac import RBACPermission, RBACResourceScope
|
||||
from controllers.common.rbac import RBACCheck
|
||||
from libs.oauth_bearer import Scope, TokenType
|
||||
from models.account import Account, Tenant, TenantAccountRole
|
||||
from models.model import App, EndUser
|
||||
@@ -25,23 +25,15 @@ class ExternalIdentity(BaseModel):
|
||||
issuer: str | None = None
|
||||
|
||||
|
||||
class RBACRequirement(BaseModel):
|
||||
model_config = ConfigDict(frozen=True)
|
||||
|
||||
resource_type: RBACResourceScope
|
||||
scene: RBACPermission
|
||||
resource_required: bool = True
|
||||
|
||||
|
||||
class RequestContext(BaseModel):
|
||||
model_config = ConfigDict(frozen=True)
|
||||
model_config = ConfigDict(frozen=True, arbitrary_types_allowed=True)
|
||||
|
||||
token_type: TokenType
|
||||
scope: Scope | None = None
|
||||
path_params: dict[str, str]
|
||||
workspace_membership: bool = False
|
||||
allowed_roles: frozenset[TenantAccountRole] | None = None
|
||||
rbac: RBACRequirement | None = None
|
||||
rbac: RBACCheck | None = None
|
||||
|
||||
|
||||
class AuthData(BaseModel):
|
||||
@@ -58,7 +50,7 @@ class AuthData(BaseModel):
|
||||
path_params: dict[str, str] = Field(default_factory=dict)
|
||||
|
||||
allowed_roles: frozenset[TenantAccountRole] | None = None
|
||||
rbac: RBACRequirement | None = None
|
||||
rbac: RBACCheck | None = None
|
||||
|
||||
app: App | None = None
|
||||
tenant: Tenant | None = None
|
||||
|
||||
@@ -17,11 +17,11 @@ from flask_login import user_logged_in
|
||||
from werkzeug.exceptions import Forbidden, NotFound, Unauthorized
|
||||
|
||||
from configs import dify_config
|
||||
from controllers.common.rbac import RBACCheck
|
||||
from controllers.openapi._audit import emit_wrong_surface
|
||||
from controllers.openapi.auth.data import (
|
||||
AuthData,
|
||||
ExternalIdentity,
|
||||
RBACRequirement,
|
||||
RequestContext,
|
||||
)
|
||||
from controllers.openapi.auth.flow import When
|
||||
@@ -61,7 +61,7 @@ class AuthPipeline:
|
||||
scope: Scope | None,
|
||||
workspace_membership: bool = False,
|
||||
allowed_roles: frozenset[TenantAccountRole] | None = None,
|
||||
rbac: RBACRequirement | None = None,
|
||||
rbac: RBACCheck | None = None,
|
||||
) -> Any:
|
||||
req_ctx = RequestContext(
|
||||
token_type=identity.token_type,
|
||||
@@ -135,7 +135,7 @@ class PipelineRouter:
|
||||
require_valid_enterprise_license: bool = False,
|
||||
workspace_membership: bool = False,
|
||||
allowed_roles: frozenset[TenantAccountRole] | None = None,
|
||||
rbac: RBACRequirement | None = None,
|
||||
rbac: RBACCheck | None = None,
|
||||
) -> Callable:
|
||||
return self._make_decorator(
|
||||
scope=scope,
|
||||
@@ -155,7 +155,7 @@ class PipelineRouter:
|
||||
edition: frozenset[DeploymentEdition] | None = None,
|
||||
require_valid_enterprise_license: bool = False,
|
||||
allowed_roles: frozenset[TenantAccountRole] | None = None,
|
||||
rbac: RBACRequirement | None = None,
|
||||
rbac: RBACCheck | None = None,
|
||||
) -> Callable:
|
||||
return self._make_decorator(
|
||||
scope=scope,
|
||||
@@ -176,7 +176,7 @@ class PipelineRouter:
|
||||
require_valid_enterprise_license: bool,
|
||||
workspace_membership: bool,
|
||||
allowed_roles: frozenset[TenantAccountRole] | None,
|
||||
rbac: RBACRequirement | None,
|
||||
rbac: RBACCheck | None,
|
||||
) -> Callable:
|
||||
def decorator(view: Callable) -> Callable:
|
||||
@wraps(view)
|
||||
@@ -210,7 +210,7 @@ class PipelineRouter:
|
||||
require_valid_enterprise_license: bool,
|
||||
workspace_membership: bool = False,
|
||||
allowed_roles: frozenset[TenantAccountRole] | None = None,
|
||||
rbac: RBACRequirement | None = None,
|
||||
rbac: RBACCheck | None = None,
|
||||
) -> Any:
|
||||
# 404 not 403 — this edition doesn't expose the feature at all
|
||||
if edition is not None and dify_config.DEPLOYMENT_EDITION not in edition:
|
||||
|
||||
@@ -4,7 +4,7 @@ from flask import request
|
||||
from werkzeug.exceptions import Forbidden, NotFound, UnprocessableEntity
|
||||
|
||||
from configs import dify_config
|
||||
from controllers.common.wraps import enforce_rbac_access
|
||||
from controllers.common.rbac import enforce_rbac_checks
|
||||
from controllers.openapi.auth.data import AuthData, CallerKind
|
||||
from extensions.ext_database import db
|
||||
from libs.oauth_bearer import Scope, TokenType
|
||||
@@ -62,12 +62,10 @@ def check_rbac_permission(data: AuthData) -> None:
|
||||
return
|
||||
if data.account_id is None or data.tenant is None:
|
||||
raise Forbidden("rbac context missing")
|
||||
enforce_rbac_access(
|
||||
enforce_rbac_checks(
|
||||
tenant_id=str(data.tenant.id),
|
||||
account_id=str(data.account_id),
|
||||
resource_type=req.resource_type,
|
||||
scene=req.scene,
|
||||
resource_required=req.resource_required,
|
||||
checks=[req],
|
||||
path_args=dict(data.path_params),
|
||||
)
|
||||
|
||||
|
||||
Reference in new issue
Block a user