test(auth): add regression for OAuth2 success redirect; restore clearAuthenticationAttributes

Cover the no-returnTo + cached-API-request branch with HttpSessionRequestCache so
the original bug (post-login redirect resolving to /api/web/skills) cannot be
silently reintroduced. Also restore clearAuthenticationAttributes() in the
returnTo branch so it stays symmetric with the default branch (super clears it).
This commit is contained in:
xiose 2026-05-19 09:50:07 +08:00
parent 026797c9fa
commit 16704ffa06
2 changed files with 39 additions and 2 deletions

View file

@ -47,10 +47,10 @@ public class OAuth2LoginSuccessHandler extends SimpleUrlAuthenticationSuccessHan
String returnTo = oauthLoginFlowService.consumeReturnTo(request.getSession(false));
if (returnTo != null) {
getRedirectStrategy().sendRedirect(request, response, returnTo);
// The default branch below clears these via super; clear here too so both paths behave consistently.
clearAuthenticationAttributes(request);
return;
}
// Use default target URL (/dashboard)
super.onAuthenticationSuccess(request, response, authentication);
}
}

View file

@ -10,6 +10,7 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import java.util.List;
import java.util.Map;
@ -59,6 +60,42 @@ class OAuth2LoginHandlersTest {
assertThat(session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY)).isNotNull();
}
/**
* Regression test: when an unauthenticated client hits a protected API endpoint, Spring Security
* caches that request. With {@code SavedRequestAwareAuthenticationSuccessHandler} the post-login
* redirect would resolve to the cached API URL, leaving the user staring at raw JSON instead of
* the dashboard. The handler must ignore the saved request and fall back to the default target.
*/
@Test
void successHandler_ignoresSavedApiRequestAndRedirectsToDefault() throws Exception {
OAuthLoginFlowService oauthLoginFlowService = mock(OAuthLoginFlowService.class);
OAuth2LoginSuccessHandler handler = new OAuth2LoginSuccessHandler(
new com.iflytek.skillhub.auth.session.PlatformSessionService(),
oauthLoginFlowService
);
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
request.setRequestURI("/api/web/skills");
MockHttpServletResponse response = new MockHttpServletResponse();
// Simulate Spring Security saving the API request that triggered login.
new HttpSessionRequestCache().saveRequest(request, response);
var principal = new com.iflytek.skillhub.auth.rbac.PlatformPrincipal(
"user-1", "User", "user@example.com", null, "github", Set.of()
);
Authentication authentication = new UsernamePasswordAuthenticationToken(
new DefaultOAuth2User(List.of(), Map.of("platformPrincipal", principal, "login", "user"), "login"),
null,
List.of()
);
org.mockito.Mockito.when(oauthLoginFlowService.consumeReturnTo(org.mockito.ArgumentMatchers.any()))
.thenReturn(null);
handler.onAuthenticationSuccess(request, response, authentication);
assertThat(response.getRedirectedUrl()).isEqualTo("/dashboard");
}
@Test
void failureHandler_redirectsBackToLoginWithReturnTo() throws Exception {
OAuthLoginFlowService oauthLoginFlowService = mock(OAuthLoginFlowService.class);