-
Notifications
You must be signed in to change notification settings - Fork 20k
fix: clear all default providers in tenant for enterprise mode #31567
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
4d25384
be55d68
9c47054
577c5f3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,10 @@ | |
| import logging | ||
| from collections.abc import Mapping | ||
| from pathlib import Path | ||
| from typing import Any | ||
| from typing import TYPE_CHECKING, Any | ||
|
|
||
| if TYPE_CHECKING: | ||
| from models.account import Account | ||
|
|
||
| from sqlalchemy import exists, select | ||
| from sqlalchemy.orm import Session | ||
|
|
@@ -406,20 +409,33 @@ def delete_builtin_tool_provider(tenant_id: str, provider: str, credential_id: s | |
| return {"result": "success"} | ||
|
|
||
| @staticmethod | ||
| def set_default_provider(tenant_id: str, user_id: str, provider: str, id: str): | ||
| def set_default_provider(tenant_id: str, user_id: str, provider: str, id: str, account: "Account | None" = None): | ||
| """ | ||
| set default provider | ||
| """ | ||
| with Session(db.engine) as session: | ||
| # get provider | ||
| target_provider = session.query(BuiltinToolProvider).filter_by(id=id).first() | ||
| # get provider (verify tenant ownership to prevent IDOR) | ||
| target_provider = session.query(BuiltinToolProvider).filter_by(id=id, tenant_id=tenant_id).first() | ||
| if target_provider is None: | ||
| raise ValueError("provider not found") | ||
|
|
||
| # clear default provider | ||
| session.query(BuiltinToolProvider).filter_by( | ||
| tenant_id=tenant_id, user_id=user_id, provider=provider, is_default=True | ||
| ).update({"is_default": False}) | ||
| if dify_config.ENTERPRISE_ENABLED: | ||
| # Enterprise: verify admin permission for tenant-wide operation | ||
| from models.account import TenantAccountRole | ||
|
|
||
| if account and not TenantAccountRole.is_privileged_role(account.current_role): | ||
| raise ValueError("Only workspace admins/owners can set default credentials in enterprise mode") | ||
|
Comment on lines
+427
to
+428
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The permission check |
||
| # Enterprise: clear ALL defaults for this provider in the tenant | ||
| # (regardless of user_id, since enterprise credentials may have different user_id) | ||
| session.query(BuiltinToolProvider).filter_by( | ||
| tenant_id=tenant_id, provider=provider, is_default=True | ||
| ).update({"is_default": False}) | ||
|
Comment on lines
+431
to
+433
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change correctly implements the core logic for enterprise mode, clearing all |
||
| else: | ||
| # Non-enterprise: only clear defaults for the current user | ||
| session.query(BuiltinToolProvider).filter_by( | ||
| tenant_id=tenant_id, user_id=user_id, provider=provider, is_default=True | ||
| ).update({"is_default": False}) | ||
|
|
||
| # set new default provider | ||
| target_provider.is_default = True | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
set_default_providermethod currently lacks validation to ensure theprovidername from the request matches theproviderattribute of the credential being updated. This logic flaw could allow an attacker to bypass the intended clearing mechanism and create multiple default credentials for a single provider, leading to unpredictable behavior. While the inclusion oftenant_id=tenant_idcorrectly prevents IDOR vulnerabilities, theprovidervalidation is still crucial for maintaining data integrity and preventing unintended credential assignments.