We have an application build on Java 1.6 with Spring 3.0.3 that use Spring Security 3.0.5 and implements REST API using Spring Web with RestEasy 2.1.0.
I need to place this application (server) behind a proxy that would translate HTTPS request traffic from a REST API Client application into HTTP traffic. This change creates a “cross domain” scenario for login request : Client sends HTTPS request for login, and Server answers with redirect URL of HTTP. Currently it responses with:
”http://192.168.0.10:8090/index.html;jsessionid=64FD79...86D”
,
what I need here is:
”/index.html;jsessionid=64FD79...86D”
We came with solution to make server to respond with “relative” URL instead “absolute” URL. So I tried to implement something similar with described situation here:
thread on forum.spring.io
I have set the RedirectStrategy bean with contextRelative="true" and override the redirectStrategy setter from AbstractAuthenticationTargetUrlRequestHandler within my LoginSuccessHandler extended class and I see that redirectStrategy property for HttpServletResponse object is set to true as expected. Still it not resolving the issue.
Also when changing redirectURLCC property of HttpServletResponse object using encodeRedirectURL("otherLogin") is sets something like
”http://192.168.0.10:8090/otherLogin”
and its not what I need. I need to remove whole protocol+ipaddress part of the URL. The URL property of response object is not accessible for change as it is wrapped by Filter and FilterChain interfaces implementation.
Please suggest any ideas. I suppose this kind of things should be resolved in web.xml or auth-AplicationContext.xml files not in code.
Best Regards.
Spring Security uses the following logic when sending a redirect:
public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url) throws IOException {
String redirectUrl = calculateRedirectUrl(request.getContextPath(), url);
redirectUrl = response.encodeRedirectURL(redirectUrl);
if (logger.isDebugEnabled()) {
logger.debug("Redirecting to '" + redirectUrl + "'");
}
response.sendRedirect(redirectUrl);
}
The sendRedirect
method is required to behave in the following way:
This method can accept relative URLs; the servlet container must
convert the relative URL to an absolute URL before sending the
response to the client.
That means you will by deafult always get an absolute URL, no matter what's the configuration or context setting.
You have multiple options:
- configure your container or application server to be aware of the public URL (for example by using
AJP
instead of HTTP reverse proxy, or passing HTTP headers with the public URL which is supported by some application servers), e.g. documentation for Tomcat
- configure your HTTP reverse proxy to perform correct rewriting, e.g. see
ProxyPassReverse
in Apache mod_proxy documentation
- implement a custom
org.springframework.security.web.RedirectStrategy
where you will manually set the Location
response header and HTTP 302 status code, this should allow you to send context relative redirect as you want
Not entirely relative, but probably you might want to have a look into a 4th option using the org.springframework.web.servlet.view.UrlBasedViewResolver
to rewrite the redirected URL with your external hostname as described in this answer: Override the default redirect URL in a SpringMVC application.
That should be achievable on Apache with:
ProxyPreserveHost Off
ProxyPass / http://192.168.0.10:8090
ProxyPassReverse / http://192.168.0.10:8090
and adding one more proxy reverse on the proxing host with the port.
E.g supposing your server name is proxy.example.com the fourth line would be:
ProxyPassReverse / http://proxy.exemple.com:8090
Look at this answer: Sending redirect in Tomcat web application behind a Apache 2 proxy (mod_proxy)