mirror of
https://github.com/langgenius/dify.git
synced 2026-08-28 19:38:30 +08:00
fix(api): normalize web app permission dependency errors
This commit is contained in:
parent
eaa5241b07
commit
7af391b482
@ -162,6 +162,7 @@ class AppWebAuthPermission(Resource):
|
||||
400: "Bad Request",
|
||||
401: "Unauthorized",
|
||||
500: "Internal Server Error",
|
||||
503: "Web App Access Service Unavailable",
|
||||
}
|
||||
)
|
||||
@web_ns.response(200, "Success", web_ns.models[BooleanResultResponse.__name__])
|
||||
@ -172,7 +173,11 @@ class AppWebAuthPermission(Resource):
|
||||
raise ValueError("appId must be provided")
|
||||
|
||||
webapp_access = application_services().webapp_access
|
||||
if not webapp_access.requires_permission_check(app_id):
|
||||
try:
|
||||
requires_permission_check = webapp_access.requires_permission_check(app_id)
|
||||
except WebAppAccessUnavailableError:
|
||||
raise WebAppAccessServiceUnavailableError() from None
|
||||
if not requires_permission_check:
|
||||
return dump_response(BooleanResultResponse, {"result": True})
|
||||
|
||||
try:
|
||||
@ -187,7 +192,8 @@ class AppWebAuthPermission(Resource):
|
||||
logger.exception("Unexpected error during auth verification")
|
||||
raise
|
||||
|
||||
return dump_response(
|
||||
BooleanResultResponse,
|
||||
{"result": webapp_access.is_user_allowed(user_id=str(user_id), app_id=app_id)},
|
||||
)
|
||||
try:
|
||||
is_allowed = webapp_access.is_user_allowed(user_id=str(user_id), app_id=app_id)
|
||||
except WebAppAccessUnavailableError:
|
||||
raise WebAppAccessServiceUnavailableError() from None
|
||||
return dump_response(BooleanResultResponse, {"result": is_allowed})
|
||||
|
||||
@ -55,6 +55,13 @@ def _get_enterprise_webapp_access_mode(app_id: str) -> WebAppAccessMode:
|
||||
raise WebAppAccessUnavailableError from e
|
||||
|
||||
|
||||
def _is_user_allowed_to_access_webapp(user_id: str, app_id: str) -> bool:
|
||||
try:
|
||||
return EnterpriseService.WebAppAuth.is_user_allowed_to_access_webapp(user_id, app_id)
|
||||
except (EnterpriseServiceError, httpx.RequestError, json.JSONDecodeError, UnicodeDecodeError) as e:
|
||||
raise WebAppAccessUnavailableError from e
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class ApplicationServices:
|
||||
app_definitions: AppDefinitionQueryService
|
||||
@ -87,7 +94,7 @@ def build_application_services(
|
||||
access=WebAppAccessQueryRepository(session_factory=database_client),
|
||||
webapp_auth_enabled=FeatureService.is_webapp_auth_enabled(),
|
||||
access_mode_for_app=_get_enterprise_webapp_access_mode,
|
||||
is_user_allowed_for_app=EnterpriseService.WebAppAuth.is_user_allowed_to_access_webapp,
|
||||
is_user_allowed_for_app=_is_user_allowed_to_access_webapp,
|
||||
),
|
||||
explore_banner_queries=ExploreBannerQueryService(
|
||||
banners=ExploreBannerQueryRepository(client=database_client),
|
||||
|
||||
@ -847,6 +847,7 @@ Check if user has permission to access a web application.
|
||||
| 400 | Bad Request | |
|
||||
| 401 | Unauthorized | |
|
||||
| 500 | Internal Server Error | |
|
||||
| 503 | Web App Access Service Unavailable | |
|
||||
|
||||
### [POST] /workflows/run
|
||||
**Run workflow**
|
||||
|
||||
@ -227,6 +227,35 @@ class TestAppWebAuthPermission:
|
||||
passport_service.return_value.verify.assert_called_once_with("passport")
|
||||
webapp_access.is_user_allowed.assert_called_once_with(user_id=expected_user_id, app_id="app-1")
|
||||
|
||||
@pytest.mark.parametrize("failing_method", ["requires_permission_check", "is_user_allowed"])
|
||||
@patch("controllers.web.app.application_services")
|
||||
def test_maps_access_dependency_failure_to_service_unavailable(
|
||||
self, application_services: MagicMock, failing_method: str, app: Flask
|
||||
) -> None:
|
||||
webapp_access = MagicMock()
|
||||
webapp_access.requires_permission_check.return_value = True
|
||||
if failing_method == "requires_permission_check":
|
||||
webapp_access.requires_permission_check.side_effect = WebAppAccessUnavailableError()
|
||||
else:
|
||||
webapp_access.is_user_allowed.side_effect = WebAppAccessUnavailableError()
|
||||
application_services.return_value = SimpleNamespace(webapp_access=webapp_access)
|
||||
|
||||
passport_service = MagicMock()
|
||||
passport_service.return_value.verify.return_value = {"user_id": "user-1"}
|
||||
with (
|
||||
app.test_request_context("/webapp/permission?appId=app-1", headers={"X-App-Code": "code1"}),
|
||||
patch("controllers.web.app.extract_webapp_passport", return_value="passport"),
|
||||
patch("controllers.web.app.PassportService", passport_service),
|
||||
pytest.raises(WebAppAccessServiceUnavailableError) as raised,
|
||||
):
|
||||
AppWebAuthPermission().get()
|
||||
|
||||
assert raised.value.data == {
|
||||
"code": "web_app_access_unavailable",
|
||||
"message": "Web app access service is unavailable.",
|
||||
"status": 503,
|
||||
}
|
||||
|
||||
@patch("controllers.web.app.application_services")
|
||||
def test_private_app_requires_passport(self, application_services: MagicMock, app: Flask) -> None:
|
||||
webapp_access = MagicMock()
|
||||
|
||||
@ -266,9 +266,10 @@ def test_build_application_services_wires_webapp_permission(
|
||||
return_value=False,
|
||||
) as is_user_allowed,
|
||||
):
|
||||
services = build_application_services(
|
||||
services = ext_application_services.build_application_services(
|
||||
database_client=sqlite_session_factory,
|
||||
deployment_edition=DeploymentEdition.COMMUNITY,
|
||||
initialization_password="",
|
||||
redis=MagicMock(spec=RedisClientWrapper),
|
||||
)
|
||||
requires_permission = services.webapp_access.requires_permission_check("app-1")
|
||||
@ -279,3 +280,17 @@ def test_build_application_services_wires_webapp_permission(
|
||||
enabled.assert_called_once_with()
|
||||
get_access_mode.assert_called_once_with("app-1")
|
||||
is_user_allowed.assert_called_once_with("user-1", "app-1")
|
||||
|
||||
|
||||
def test_webapp_permission_adapter_maps_connection_failure() -> None:
|
||||
failure = httpx.ConnectError("connection failed")
|
||||
with (
|
||||
patch(
|
||||
"extensions.ext_application_services.EnterpriseService.WebAppAuth.is_user_allowed_to_access_webapp",
|
||||
side_effect=failure,
|
||||
),
|
||||
pytest.raises(WebAppAccessUnavailableError) as raised,
|
||||
):
|
||||
ext_application_services._is_user_allowed_to_access_webapp("user-1", "app-1")
|
||||
|
||||
assert raised.value.__cause__ is failure
|
||||
|
||||
@ -1568,6 +1568,7 @@ export type GetWebappPermissionErrors = {
|
||||
400: unknown
|
||||
401: unknown
|
||||
500: unknown
|
||||
503: unknown
|
||||
}
|
||||
|
||||
export type GetWebappPermissionResponses = {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user