From 60ce8f6053c57fca18488bb217504420b9ef97db Mon Sep 17 00:00:00 2001 From: GareArc Date: Wed, 28 May 2025 17:56:31 +0800 Subject: [PATCH] fix: adjust interceptor for web apis --- api/controllers/web/passport.py | 21 +++++++++-------- api/controllers/web/wraps.py | 36 +++++++++++++++++++++-------- api/services/webapp_auth_service.py | 2 -- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/api/controllers/web/passport.py b/api/controllers/web/passport.py index 017ed606a4..d83cd8de9c 100644 --- a/api/controllers/web/passport.py +++ b/api/controllers/web/passport.py @@ -27,11 +27,13 @@ class PassportResource(Resource): if app_code is None: raise Unauthorized("X-App-Code header is missing.") - # logic for exchange token for enterprise logined web user - enterprise_user_id = decode_enterprise_webapp_user_id(enterprise_login_token) - if enterprise_user_id: + # exchange token for enterprise logined web user + enterprise_user_decoded = decode_enterprise_webapp_user_id(enterprise_login_token) + if enterprise_user_decoded: # a web user has already logged in, exchange a token for this app without redirecting to the login page - return exchange_token_for_existing_web_user(app_code=app_code, user_id=enterprise_user_id) + return exchange_token_for_existing_web_user( + app_code=app_code, enterprise_user_decoded=enterprise_user_decoded + ) if system_features.webapp_auth.enabled: app_settings = EnterpriseService.WebAppAuth.get_app_access_mode_by_code(app_code=app_code) @@ -112,15 +114,16 @@ def decode_enterprise_webapp_user_id(auth_header: str | None): decoded = PassportService().verify(tk) source = decoded.get("token_source") if not source or source != "enterprise_login": - return None - user_id: str | None = decoded.get("user_id") - return user_id + raise Unauthorized("Invalid token source. Expected 'enterprise_login'.") + return decoded -def exchange_token_for_existing_web_user(app_code: str, user_id: str): +def exchange_token_for_existing_web_user(app_code: str, enterprise_user_decoded: dict): """ Exchange a token for an existing web user session. """ + user_id = enterprise_user_decoded.get("user_id") + end_user_id = enterprise_user_decoded.get("end_user_id") site = db.session.query(Site).filter(Site.code == app_code, Site.status == "normal").first() if not site: @@ -129,7 +132,7 @@ def exchange_token_for_existing_web_user(app_code: str, user_id: str): app_model = db.session.query(App).filter(App.id == site.app_id).first() if not app_model or app_model.status != "normal" or not app_model.enable_site: raise NotFound() - end_user = db.session.query(EndUser).filter(EndUser.app_id == app_model.id, EndUser.session_id == user_id).first() + end_user = db.session.query(EndUser).filter(EndUser.id == end_user_id).first() if not end_user: end_user = EndUser( tenant_id=app_model.tenant_id, diff --git a/api/controllers/web/wraps.py b/api/controllers/web/wraps.py index 3bb029d6eb..933b8ae228 100644 --- a/api/controllers/web/wraps.py +++ b/api/controllers/web/wraps.py @@ -8,7 +8,7 @@ from controllers.web.error import WebAppAuthAccessDeniedError, WebAppAuthRequire from extensions.ext_database import db from libs.passport import PassportService from models.model import App, EndUser, Site -from services.enterprise.enterprise_service import EnterpriseService +from services.enterprise.enterprise_service import EnterpriseService, WebAppSettings from services.feature_service import FeatureService @@ -44,7 +44,9 @@ def decode_jwt_token(): if auth_scheme != "bearer": raise Unauthorized("Invalid Authorization header format. Expected 'Bearer ' format.") decoded = PassportService().verify(tk) - app_code = decoded.get("app_code") + decoded_app_code = decoded.get("app_code") + if not decoded_app_code or decoded_app_code != app_code: + raise Unauthorized("Invalid app code in token.") app_model = db.session.query(App).filter(App.id == decoded["app_id"]).first() site = db.session.query(Site).filter(Site.code == app_code).first() if not app_model: @@ -59,13 +61,17 @@ def decode_jwt_token(): # for enterprise webapp auth app_web_auth_enabled = False + webapp_settings = None if system_features.webapp_auth.enabled: - app_web_auth_enabled = ( - EnterpriseService.WebAppAuth.get_app_access_mode_by_code(app_code=app_code).access_mode != "public" - ) + webapp_settings = EnterpriseService.WebAppAuth.get_app_access_mode_by_code(app_code=app_code) + if not webapp_settings: + raise NotFound("Web app settings not found.") + app_web_auth_enabled = webapp_settings.access_mode != "public" _validate_webapp_token(decoded, app_web_auth_enabled, system_features.webapp_auth.enabled) - _validate_user_accessibility(decoded, app_code, app_web_auth_enabled, system_features.webapp_auth.enabled) + _validate_user_accessibility( + decoded, app_code, app_web_auth_enabled, system_features.webapp_auth.enabled, webapp_settings + ) return app_model, end_user except Unauthorized as e: @@ -95,15 +101,27 @@ def _validate_webapp_token(decoded, app_web_auth_enabled: bool, system_webapp_au raise Unauthorized("webapp token expired.") -def _validate_user_accessibility(decoded, app_code, app_web_auth_enabled: bool, system_webapp_auth_enabled: bool): +def _validate_user_accessibility( + decoded, + app_code, + app_web_auth_enabled: bool, + system_webapp_auth_enabled: bool, + webapp_settings: WebAppSettings | None, +): if system_webapp_auth_enabled and app_web_auth_enabled: # Check if the user is allowed to access the web app user_id = decoded.get("user_id") if not user_id: raise WebAppAuthRequiredError() - if not EnterpriseService.WebAppAuth.is_user_allowed_to_access_webapp(user_id, app_code=app_code): - raise WebAppAuthAccessDeniedError() + if not webapp_settings: + raise WebAppAuthRequiredError("Web app settings not found.") + + access_modes_require_permission_check = ["private", "private_all"] + + if webapp_settings.access_mode in access_modes_require_permission_check: + if not EnterpriseService.WebAppAuth.is_user_allowed_to_access_webapp(user_id, app_code=app_code): + raise WebAppAuthAccessDeniedError() class WebApiResource(Resource): diff --git a/api/services/webapp_auth_service.py b/api/services/webapp_auth_service.py index f4186e7f6f..2993bd91c3 100644 --- a/api/services/webapp_auth_service.py +++ b/api/services/webapp_auth_service.py @@ -129,8 +129,6 @@ class WebAppAuthService: payload = { "iss": site.id, "sub": "Web API Passport", - "app_id": site.app_id, - "app_code": site.code, "user_id": account.id, "end_user_id": end_user_id, "token_source": "enterprise_login",