-
Notifications
You must be signed in to change notification settings - Fork 5.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support absolute URI’s in authentication success redirects for WebFlux #11656
Comments
Hi @DidierLoiseau, thanks for reaching out! Sorry for the delay in responding. I'd like to understand the issue better.
This is possible as the stackoverflow post mentioned. For example: public class AbsoluteUrlRedirectStrategy implements ServerRedirectStrategy {
private final ServerRedirectStrategy delegate = new DefaultServerRedirectStrategy();
@Override
public Mono<Void> sendRedirect(ServerWebExchange exchange, URI location) {
return Mono.fromCallable(() -> this.createLocation(exchange, location))
.flatMap(redirectUri -> this.delegate.sendRedirect(exchange, redirectUri));
}
private URI createLocation(ServerWebExchange exchange, URI location) {
String url = location.toASCIIString();
String contextPath = null;
if (url.startsWith("/")) {
contextPath = exchange.getRequest().getPath().contextPath().value();
}
return UriComponentsBuilder.fromHttpRequest(exchange.getRequest())
.replacePath(contextPath)
.path(url)
.build()
.toUri();
}
} Since the
Is it just the As an aside: I look at adding absolute URLs to the location header as a cross-cutting concern that the gateway could handle without any impact on Spring Security configuration. Since Spring Security is consistent in how it reflects the |
Thanks @sjohnr for your answer. This ticket is indeed just about making it easier do this, ideally through configuration instead of code, in order to get the same behavior as Spring Security provides for Spring MVC. I’m not sure this should be specific to the gateway since this affects the general behavior of the As a side note, in the end we opted for extending the import static org.springframework.security.web.util.UrlUtils.buildFullRequestUrl;
import java.net.URI;
import reactor.core.publisher.Mono;
import org.springframework.security.web.server.savedrequest.WebSessionServerRequestCache;
import org.springframework.web.server.ServerWebExchange;
class AbsoluteRedirectWebSessionServerRequestCache extends WebSessionServerRequestCache {
@Override
public Mono<URI> getRedirectUri(ServerWebExchange exchange) {
return super.getRedirectUri(exchange).map(redirectURI -> {
URI uri = exchange.getRequest().getURI();
return URI.create(
buildFullRequestUrl(uri.getScheme(), uri.getHost(), uri.getPort(), redirectURI.getPath(),
redirectURI.getQuery()));
});
}
} Ideally, I suppose this should be done by changing the behavior of If I’m not wrong, the behavior I’d like to have could be implemented by changing the line String requestPath = pathInApplication(exchange.getRequest()); to something like String requestPath = absolute ? exchange.getRequest().getURI().toString() : pathInApplication(exchange.getRequest()); and provide a way to configure this |
Thanks @DidierLoiseau. It sounds like you are solely focused on the redirect after authentication success, correct?
This can be configured in a single spot in this case, which would be customizing the @Configuration
@EnableWebFluxSecurity
public class SecurityConfiguration {
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange((authorizeExchange) -> authorizeExchange
.anyExchange().authenticated()
)
.formLogin((formLogin) -> formLogin
.authenticationSuccessHandler(authenticationSuccessHandler())
);
return http.build();
}
private ServerAuthenticationSuccessHandler authenticationSuccessHandler() {
RedirectServerAuthenticationSuccessHandler authenticationSuccessHandler =
new RedirectServerAuthenticationSuccessHandler();
// see above definition of AbsoluteUrlRedirectStrategy
authenticationSuccessHandler.setRedirectStrategy(new AbsoluteUrlRedirectStrategy());
return authenticationSuccessHandler;
}
} Perhaps I'm missing why you chose to customize the |
Indeed.
Well, both approaches are possible, but the Also note that configuring the request cache is just as easy with I suppose if #7273 is implemented, having an easy way to switch back to absolute URL’s would be welcome too, considering the burden it creates with reverse proxies (or at least, with Nginx). ¹ Note that in both cases those caches appear to be there solely for authentication purposes, according to their Javadoc. |
True! However, I was focused on the case where more than just saved requests would be used as redirects. Even if your particular use case doesn't require the
Modern browsers can handle relative URLs in the |
I don’t know why the MVC
See initial issue description but to summarize: Nginx’s |
Thanks for clarifying. If your nginx proxy is rewriting all URLs before it gets to Spring Cloud Gateway, I could see how this is a problem. |
Hi @DidierLoiseau, I spoke to the team about this issue and I wanted to give you an update. Regarding Spring WebFlux specifically, we believe that this issue is broader than authentication success, and in fact is even broader than Spring Security. If your nginx proxy has issues with relative redirects, the best place to add a configuration option would be in Spring Framework itself, as this is managed in In the meantime, a passive solution would be to add a @Component
@Order(-100)
public class AbsoluteUrlLocationHeaderWebFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain filterChain) {
return filterChain.filter(exchange).then(checkLocation(exchange));
}
private Mono<Void> checkLocation(ServerWebExchange exchange) {
return Mono.fromRunnable(() -> {
HttpHeaders headers = exchange.getResponse().getHeaders();
URI location = headers.getLocation();
if (location != null) {
headers.setLocation(createLocation(exchange, location));
}
});
}
private URI createLocation(ServerWebExchange exchange, URI location) {
String url = location.toASCIIString();
if (url.startsWith("/")) {
return UriComponentsBuilder.fromHttpRequest(exchange.getRequest())
.query(null)
.fragment(null)
.replacePath(url)
.build()
.toUri();
}
return location;
}
} I'm going to close this issue for now as we probably wouldn't pursue a specific change for success redirects and application-wide redirect handling for Spring WebFlux could be addressed at the framework level. |
Expected Behavior
RedirectServerAuthenticationSuccessHandler
/ServerRequestCache.getRedirectUri()
should allow to redirect using an absolute URL (e.g.http://localhost/secured-path
) so that reverse proxies can automatically rewrite the location header, like with Web MVC (SavedRequestAwareAuthenticationSuccessHandler
/RequestCache
).Current Behavior
The WebFlux success handler uses a relative URI, such as
/secured-path
. Reverse proxies will not rewrite those paths by default as they can’t know to what this path is relative (as I understand it, tested with Nginx’sproxy_pass
setup).I understand from #7273 that this behavior is intentional, however it would be good to make it easier to change the behavior. Currently the only solution seems to be to provide a custom
ServerRequestCache
or a customRedirectServerAuthenticationSuccessHandler
, as a user did in this SO answer. Moreover neitherWebSessionServerRequestCache
norCookieServerRequestCache
can be extended to customize this behavior during thesaveRequest()
call because they both use static methods to build the stored URL, and the attribute/cookie name is private.Context
We are currently upgrading from Zuul 1 to Spring Cloud Gateway. As we deploy it behind Nginx in our test environment, we noticed that it does not rewrite relative
location
headers by default, so the raw internal value is forwarded. As a workaround, it is possible to force Nginx to rewrite it usingproxy_redirect
(which also converts thelocation
to an absolute URI):but we would rather avoid the trouble of asking our customer to change their reverse proxy configuration (this would involve another team to whom we need to explain the issue, it’s unlikely to work on first try etc. – we are likely to end up implementing a workaround in our gateway anyway).
The text was updated successfully, but these errors were encountered: