diff --git a/application/src/main/java/run/halo/app/security/HaloServerRequestCache.java b/application/src/main/java/run/halo/app/security/HaloServerRequestCache.java index 02f1460509..9b786d68c2 100644 --- a/application/src/main/java/run/halo/app/security/HaloServerRequestCache.java +++ b/application/src/main/java/run/halo/app/security/HaloServerRequestCache.java @@ -4,6 +4,7 @@ import java.net.URI; import java.util.Collections; +import java.util.Objects; import org.apache.commons.lang3.StringUtils; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; @@ -58,24 +59,49 @@ public Mono getRedirectUri(ServerWebExchange exchange) { @Override public Mono removeMatchingRequest(ServerWebExchange exchange) { - return super.removeMatchingRequest(exchange); + return getRedirectUri(exchange) + .flatMap(redirectUri -> { + if (redirectUri.getFragment() != null) { + var redirectUriInApplication = + uriInApplication(exchange.getRequest(), redirectUri, false); + var uriInApplication = + uriInApplication(exchange.getRequest(), exchange.getRequest().getURI()); + // compare the path and query only + if (!Objects.equals(redirectUriInApplication, uriInApplication)) { + return Mono.empty(); + } + // remove the exchange + return exchange.getSession().map(WebSession::getAttributes) + .doOnNext(attributes -> attributes.remove(this.sessionAttrName)) + .thenReturn(exchange.getRequest()); + } + return super.removeMatchingRequest(exchange); + }); } private Mono saveRedirectUri(ServerWebExchange exchange, URI redirectUri) { - var requestPath = exchange.getRequest().getPath(); - var redirectPath = RequestPath.parse(redirectUri, requestPath.contextPath().value()); - var query = redirectUri.getRawQuery(); - var fragment = redirectUri.getRawFragment(); - var finalRedirect = redirectPath.pathWithinApplication() - + (query == null ? "" : "?" + query) - + (fragment == null ? "" : "#" + fragment); - + var redirectUriInApplication = uriInApplication(exchange.getRequest(), redirectUri); return exchange.getSession() .map(WebSession::getAttributes) - .doOnNext(attributes -> attributes.put(this.sessionAttrName, finalRedirect)) + .doOnNext(attributes -> attributes.put(this.sessionAttrName, redirectUriInApplication)) .then(); } + private static String uriInApplication(ServerHttpRequest request, URI uri) { + return uriInApplication(request, uri, true); + } + + private static String uriInApplication( + ServerHttpRequest request, URI uri, boolean appendFragment + ) { + var path = RequestPath.parse(uri, request.getPath().contextPath().value()); + var query = uri.getRawQuery(); + var fragment = uri.getRawFragment(); + return path.pathWithinApplication().value() + + (query == null ? "" : "?" + query) + + (fragment == null || !appendFragment ? "" : "#" + fragment); + } + private static ServerWebExchangeMatcher createDefaultRequestMatcher() { var get = pathMatchers(HttpMethod.GET, "/**"); var notFavicon = new NegatedServerWebExchangeMatcher( diff --git a/application/src/test/java/run/halo/app/security/HaloServerRequestCacheTest.java b/application/src/test/java/run/halo/app/security/HaloServerRequestCacheTest.java index aa5c09bf9b..eabd2f0ea1 100644 --- a/application/src/test/java/run/halo/app/security/HaloServerRequestCacheTest.java +++ b/application/src/test/java/run/halo/app/security/HaloServerRequestCacheTest.java @@ -59,9 +59,31 @@ void shouldSaveIfRedirectUriPresent() { @Test void shouldRemoveIfRedirectUriFound() { + var sessionManager = new DefaultWebSessionManager(); + var mockExchange = MockServerWebExchange.builder(MockServerHttpRequest.get("/login") + .queryParam("redirect_uri", "/halo") + ) + .sessionManager(sessionManager) + .build(); + var removeExchange = mockExchange.mutate() + .request(builder -> builder.uri(URI.create("/halo"))) + .build(); + requestCache.saveRequest(mockExchange) + .then(Mono.defer(() -> requestCache.removeMatchingRequest(removeExchange))) + .as(StepVerifier::create) + .assertNext(request -> { + Assertions.assertEquals(URI.create("/halo"), request.getURI()); + }) + .verifyComplete(); + } + + @Test + void shouldRemoveIfRedirectUriFoundAndContainsFragment() { var sessionManager = new DefaultWebSessionManager(); var mockExchange = - MockServerWebExchange.builder(MockServerHttpRequest.get("/login?redirect_uri=/halo")) + MockServerWebExchange.builder(MockServerHttpRequest.get("/login") + .queryParam("redirect_uri", "/halo#fragment") + ) .sessionManager(sessionManager) .build(); var removeExchange = mockExchange.mutate()