Scenario
I have an spring-boot application which is accessed using context instead domain root:
domain root : http://app.com
my app : http://app.com/organization_a (redirects me to my app login)
my app login : http://app.com/organization_a/login (form is loaded perfectly)
Problem
After success login, using the classic configuration:
formLogin()
.loginPage("/login")
.defaultSuccessUrl("/my_form")
redirects me to : http://app.com/my_form throwing an error because the url must be : http://app.com/organization_a/my_form
So, I tried to use relative url (note the dot before /my_form) ./my_form instead /my_form
formLogin()
.loginPage("/login")
.defaultSuccessUrl("./my_form")
And spring throw me this error : defaultTarget must start with '/' or with 'http(s) due to this validation in spring-security-web jar:
//org.springframework.security.web.authentication.AbstractAuthenticationTargetUrlRequestHandler
public void setDefaultTargetUrl(String defaultTargetUrl) {
Assert.isTrue(UrlUtils.isValidRedirectUrl(defaultTargetUrl),
"defaultTarget must start with '/' or with 'http(s)'");
this.defaultTargetUrl = defaultTargetUrl;
}
So, I can say: Classic default success url method does not allow to use relative urls, because if I use root domain , works like charm as in my localhost.
Relative vs Absolute urls
More info here
I had similar troubles with html and assets in java an other languages like php and nodejs.
Basically if you are using context instead a domain root for your app, you must need to change this:
<link href="/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet"/>
to
<link href="./vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet"/>
Note the dot before /vendor/bootstrap/...
Without this dot, your assets will not download because the browser request to urls like :
http://app.com/main.css
http://app.com/app.js
When should it be:
http://app.com/organization_a/main.css
http://app.com/organization_a/app.js
Current workarounds
Use domain or subdomain instead context.
This is laborious because I will need to open a ticket to my ISP for every new app.
Put the entire url in defaultSuccessUrl method.
This is awful because my app will not be portable due to I must set the absolute url before build:
formLogin()
.loginPage("/login")
.defaultSuccessUrl("http://app.com/organization_a/my_form")
Question
Is there a way to use relative redirect in spring security?
I am using one of the latest spring boot versions: 2.1.7.RELEASE
Any help or comment are appreciated.
Thanks
I managed to enable relative redirects via the following spring properties:
server:
tomcat:
use-relative-redirects: true
Related
It looks like Spring Security's default login page uses bootstrap.min.css and signin.css to style itself. The login page displays correctly when running the project from Eclipse but not when running from the Spring Boot fat jar. The errors are :
Failed to load resource: net::ERR_CONNECTION_TIMED_OUT bootstrap.min.css
Failed to load resource: net::ERR_CONNECTION_TIMED_OUT signin.css
These files are managed by Spring Security and I do not know where they are even stored. Like I said the login page works perfectly when running from Eclipse and the rest of the app works perfectly in both environment (thymeleaf templates using bootstrap with Spring MVC backend controllers, secured by Spring Security).
What could be causing these errors?
Did you use matchers against your static resources to be served ?
In case of local resources in other location than default (not recomended)
http
.authorizeRequests()
.antMatchers("/lib/bootstrap/**",
"/css/**",
"/img/**",
"/js/**").permitAll();
In case of webjars
http
.authorizeRequests()
.antMatchers("/webjars/**").permitAll();
Did you even wanted to protect serving those resources with a login constraints? On what purpose?
In case of static resources in the default known directoriers :
While this may not be a new revelation to those of you that have been
following Spring Boot since the SpringOne announcement, there is one
detail for which you may not be aware. Spring Boot will automatically
add static web resources located within any of the following
directories:
/META-INF/resources/
/resources/
/static/
/public/
If you add those files in one of these defaut location of the project structure then no need to authorize requests to them.
See this article for further details
NB : When using default page of spring you can't have a standalone environment and an internet access is mandatory to laod resources. You have to implement you custom login page.
http
.formLogin()
.loginPage("/login")
.permitAll();
Don't forget to chain your spring security rules if needed
I have a web application written in Java and Javascript - java part is responsible for REST API (jax-rs) and UI is written in javascript. I need to set up redirecting from any not existing URL in the domain e.g.
localhost:8080/blabla
Except the URLs which are reserved for REST(starting with "rest" in the app)
localhost:8080/rest
Is there any way to set this up in web.xml etc
Just use the standard path mapping rules to your advantage.
Example:
Setup your RestServlet on the <url-pattern>/rest</url-pattern>
Then setup a your SpecialRedirectServlet at the url pattern <url-pattern>/</url-pattern>.
If a request comes in at /rest or /rest/ then it goes to the rest servlet, all other requested paths will goto the default path mapping at /
I am using spring security login mechanism for my application and tested everything.Things were working fine.I have the following use case
If customer is not logged in , application will redirect customer to the login page.
On successful login, application will redirect customer back to same page from where they were redirected to the login page
this is the Java code used to redirect user to his original location
final SavedRequest savedRequest = this.requestCache.getRequest(request, response);
targetUrl = savedRequest.getRedirectUrl();
getRedirectStrategy().sendRedirect(request, response, targetUrl);
RedirectionStrategy being used here is DefaultRedirectStrategy, things were working fine. Application is now deployed on the Pre Production server and now this seems not working and I am getting 404 error.
When customer is being redirected to the home page,targetUrl is coming out as "/", I have a Spring controller named with this mapping
#RequestMapping("/")
public class HomePageController{ // home page code }
my application's current Pre-Prod urs is prepd-www.mysite.com so when sendredirect come in to action, webpage URL is getting changed to prepd-www.mysite.com/prepd-www.mysite.com
I am not sure what is causing this issue. is it because of the proxy server settings ?
Can any one suggest me about the possible root cause of this issue?
I have already tried it on all local machines and well on our QA but everything is working perfectly fine.
Current setup for the environment where this is happening is
We have 4 app server
We have one load balancer which is redirecting traffic to one of the app server.
Just a wild guess since you could not give the reverse proxy configuration, nor the exact URL used in pre prod and in developpement.
You say you are using DefaultRedirectStrategy from Spring security. This strategy has an option (contextRelative) that prepends the ServletContext path to the URL. If in your developpement system you were using the root context, that is if you were accessing home page at (for example) : http://localhost:8080/ the serlet context was empty.
But if now in preprod, the servlet context is no longer root but is say /myApp once translated by apache reverse proxy, when you redirect you get an URL of /myApp/myApp that could be translated back to what you gave.
You could try to control whether you have contextRelative as true in DefaultRedirectStrategy and if yes if you can set if to false and also control if you redirect to absolute or relative URLs.
If you are using apache in front check rewrite rule and redirect rules of apache config. Best way would be to ssh tunnel directly to application server(by skipping apache) and test. If it's working that means your application config is fine and it needs to be fixed in apache.
Are you using in preproduction tomcat or another application server?, normally if your war is calling foo and your commit to tomcat, the path for this war is
http://localhost:8080/foo/
So if you are using servlet you need specify in your web.xml that the main path is foo/*
I have an application with name test.war.
Because of Apache installed on my server I have to use another port number for Tomcat applications so after deployment this application available at domain.com:8080/test/.
I decided to create a subdomain in order to remove that ugly 8080 from url, so I setted up the server like described here. So now test.domain.com reffers to domain.com:8080/test/.
Everything seems fine except of one problem - because my application is not ROOT.war and I am using spring:url function every url in the application is translated to /test/bla-bla. So I removed that function. But still have a problem with spring security because it still translates an urls relative to app name i.e. /test/bla-bla.
How can I solve that problem?
Thank you
UPD: I don't want to deploy it as a ROOT application because I have two or three such applications and I wanted to create a subdomain for each one of them
Spring Security doesn't "translate" URLs. In fact this isn't specific to Spring Security. You'll run into similar issues with any application which does redirects. If you want to hide the context paths of applications which are behind a proxy, then you need to rewrite the URLs at the proxy.
I'd recommend you read the Tomcat Generic Proxy Howto and the section on URL rewriting in particular, as it specifically addresses this issue.
I have 2 tomcat instances. both are behind proxying apache httpds. my code in the Spring controller looks like this:
#RequestMapping(value = "/doSuperSexyStuff", method = RequestMethod.GET)
public String viewSuperSexyStuff() {
return "redirect:/mySuperSexyStuff";
}
On my first tomcat installation on Windows I have somedomain1.dev redirected to http://localhost:8080/myapp and everything works flawlessly. redirect goes to http://somedomain1.dev/mySuperSexyStuff
On the other tomcat installation (which is on Linux) the redirect works relative to the context path and user end up at http://somedomain2.dev/myapp/mySuperSexyStuff which is obviously wrong.
What should I do for spring to ignore the context path and just redirect the user to where he "belongs"?
All URLs in my application are absolute(everything including links in jsps, redirect urls and all the places where links are used). I guess that's not the correct way to do stuff: if I have to implement HTTPS version of the site I'll be in trouble. So if you you think I must change something fundamentally in my approach please point me in the right direction.
Instead of returning a String, which is very inflexible, consider returning a View:
#RequestMapping(value = "/doSuperSexyStuff", method = RequestMethod.GET)
public View viewSuperSexyStuff(){
return new RedirectView("/mySuperSexyStuff");
}
The redirect view has a constructor which takes a boolean contextRelative so the following would do the opposite of the above:
return new RedirectView("/mySuperSexyStuff", true);
All your url's should be context relative unless you really them point off your site, so links to css, image assets etc. should in jsp's use <c:url /> tags to resolve paths.
One of the ways you can achieve this is to use your web application deployed to the root and not as context "myapp". This makes sense as you have separate domains configured. Just use put all your files on the tomcat root folder.
Spring documentation for MVC says that the path sould always be relative to your context path.
As far as I see you have two options:
Using an absolute path in your redirect like "http://somedomain...."
Check your configuration of the context path of the web application
Hope this helps a step further...