From 5e3f4e72e7ad6d028b82989db30c0ff9487d0f62 Mon Sep 17 00:00:00 2001 From: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> Date: Thu, 6 Aug 2026 19:05:36 +0800 Subject: [PATCH] fix(deploy): keep PR 576 backport focused Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> --- .../skillhub/compat/WellKnownController.java | 9 ++++-- .../skillhub/auth/config/SecurityConfig.java | 9 ++++-- .../auth/oauth/OAuthLoginRedirectSupport.java | 29 +------------------ .../auth/oauth/OAuth2LoginHandlersTest.java | 9 ------ 4 files changed, 14 insertions(+), 42 deletions(-) diff --git a/server/skillhub-app/src/main/java/com/iflytek/skillhub/compat/WellKnownController.java b/server/skillhub-app/src/main/java/com/iflytek/skillhub/compat/WellKnownController.java index c131d84b..263634aa 100644 --- a/server/skillhub-app/src/main/java/com/iflytek/skillhub/compat/WellKnownController.java +++ b/server/skillhub-app/src/main/java/com/iflytek/skillhub/compat/WellKnownController.java @@ -1,6 +1,5 @@ package com.iflytek.skillhub.compat; -import com.iflytek.skillhub.auth.oauth.OAuthLoginRedirectSupport; import jakarta.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @@ -12,8 +11,14 @@ import java.util.Map; */ @RestController public class WellKnownController { + @GetMapping("/.well-known/clawhub.json") public Map clawhubConfig(HttpServletRequest request) { - return Map.of("apiBase", OAuthLoginRedirectSupport.apiBase(request)); + // Honor the deployment sub-path so CLI clients discover //api/v1 instead of + // the domain-root /api/v1. With forward-headers-strategy=framework, an upstream + // X-Forwarded-Prefix is reflected into the request context path. + String contextPath = request.getContextPath(); + String prefix = (contextPath == null) ? "" : contextPath; + return Map.of("apiBase", prefix + "/api/v1"); } } diff --git a/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/config/SecurityConfig.java b/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/config/SecurityConfig.java index 354c1502..7f5154a4 100644 --- a/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/config/SecurityConfig.java +++ b/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/config/SecurityConfig.java @@ -4,7 +4,6 @@ import com.iflytek.skillhub.auth.oauth.CustomOAuth2UserService; import com.iflytek.skillhub.auth.oauth.CustomOidcUserService; import com.iflytek.skillhub.auth.oauth.OAuth2LoginFailureHandler; import com.iflytek.skillhub.auth.oauth.OAuth2LoginSuccessHandler; -import com.iflytek.skillhub.auth.oauth.OAuthLoginRedirectSupport; import com.iflytek.skillhub.auth.oauth.SkillHubOAuth2AuthorizationRequestResolver; import com.iflytek.skillhub.auth.mock.MockAuthFilter; import com.iflytek.skillhub.auth.policy.RouteSecurityPolicyRegistry; @@ -153,8 +152,12 @@ public class SecurityConfig { ) .logout(logout -> logout .logoutUrl("/api/v1/auth/logout") - .logoutSuccessHandler((request, response, authentication) -> - response.sendRedirect(OAuthLoginRedirectSupport.webRoot(request))) + // Redirect to the deployment root honoring any sub-path prefix (X-Forwarded-Prefix + // is reflected into the context path), so logout does not escape a sub-path deployment. + .logoutSuccessHandler((request, response, authentication) -> { + String contextPath = request.getContextPath(); + response.sendRedirect(((contextPath == null) ? "" : contextPath) + "/"); + }) .invalidateHttpSession(true) .deleteCookies("SESSION") ) diff --git a/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/oauth/OAuthLoginRedirectSupport.java b/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/oauth/OAuthLoginRedirectSupport.java index c8e369f5..feb60816 100644 --- a/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/oauth/OAuthLoginRedirectSupport.java +++ b/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/oauth/OAuthLoginRedirectSupport.java @@ -1,10 +1,7 @@ package com.iflytek.skillhub.auth.oauth; -import jakarta.servlet.http.HttpServletRequest; - /** - * Utility methods and constants for safely handling OAuth redirect targets and - * deployment-path aware browser-visible URLs. + * Utility methods and constants for safely handling post-login redirect targets in OAuth flows. */ public final class OAuthLoginRedirectSupport { @@ -14,30 +11,6 @@ public final class OAuthLoginRedirectSupport { private OAuthLoginRedirectSupport() { } - public static String apiBase(HttpServletRequest request) { - return deploymentPrefix(request) + "/api/v1"; - } - - public static String webRoot(HttpServletRequest request) { - return deploymentPrefix(request) + "/"; - } - - static String deploymentPrefix(HttpServletRequest request) { - if (request == null) { - return ""; - } - String rawPrefix = request.getContextPath(); - if (rawPrefix == null || rawPrefix.isBlank() || "/".equals(rawPrefix)) { - return ""; - } - String prefix = rawPrefix.endsWith("/") ? rawPrefix.substring(0, rawPrefix.length() - 1) : rawPrefix; - if (!prefix.startsWith("/") || prefix.contains("//") || prefix.contains("\\") - || prefix.contains("?") || prefix.contains("#")) { - return ""; - } - return prefix; - } - public static String sanitizeReturnTo(String candidate) { if (candidate == null || candidate.isBlank()) { return null; diff --git a/server/skillhub-auth/src/test/java/com/iflytek/skillhub/auth/oauth/OAuth2LoginHandlersTest.java b/server/skillhub-auth/src/test/java/com/iflytek/skillhub/auth/oauth/OAuth2LoginHandlersTest.java index 2e46908f..de3a8411 100644 --- a/server/skillhub-auth/src/test/java/com/iflytek/skillhub/auth/oauth/OAuth2LoginHandlersTest.java +++ b/server/skillhub-auth/src/test/java/com/iflytek/skillhub/auth/oauth/OAuth2LoginHandlersTest.java @@ -108,15 +108,6 @@ class OAuth2LoginHandlersTest { assertThat(response.getRedirectedUrl()).isEqualTo("/skillhub/dashboard/publish"); } - @Test - void deploymentPathSupport_returnsPrefixedApiAndWebRoot() { - MockHttpServletRequest request = new MockHttpServletRequest(); - request.setContextPath("/skillhub"); - - assertThat(OAuthLoginRedirectSupport.apiBase(request)).isEqualTo("/skillhub/api/v1"); - assertThat(OAuthLoginRedirectSupport.webRoot(request)).isEqualTo("/skillhub/"); - } - /** * Regression test: when an unauthenticated client hits a protected API endpoint, Spring Security * caches that request. With {@code SavedRequestAwareAuthenticationSuccessHandler} the post-login