Skip to content

Throw exception if URL does not include context path when context relative #8399

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

Merged

Conversation

yoshikawaa
Copy link
Contributor

@yoshikawaa yoshikawaa commented Apr 16, 2020

Versions

  • Spring 5.2.3
  • Spring Security 5.2.1
  • Tomcat 9.0.7.B

Problem

#4142
DefaultRedirectStrategy send redirect to "" if redirect argument url not contains application context path.

But on Tomcat, it may not redirect to the context root as intended.
When HttpServletResponse#sendRedirect(""), Tomcat response with empty Location header.

If the request url is /context-root/login and response empty Location header:

Browser Redierct url ?
Chrome /context-root/login NG
Firefox /context-root/login NG
IE 11 /context-root OK

https://javaee.github.io/javaee-spec/javadocs/javax/servlet/http/HttpServletResponse.html#sendRedirect-java.lang.String-

If the location is relative without a leading '/' the container interprets it as relative to the current request URI.
If the location is relative with a leading '/' the container interprets it as relative to the servlet container root.

It seems to be the case in the latter case.

Note:
On Weblogic, "" is converted to the context path and set in the Location header.

Solution

Change to send redirect to explicitly specifying the context path.

HttpServletResponse#sendRedirect("")
-> HttpServletResponse#sendRedirect(contextPath)

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Apr 16, 2020
@eleftherias eleftherias self-assigned this Apr 16, 2020
@eleftherias
Copy link
Contributor

Thanks for the report @yoshikawaa.

Could you explain how you arrived at this behaviour?
What is the scenario in which the application is set to use relative context, but also needs to redirect somewhere outside of the root context?

It would be very helpful if you produce a minimal sample that demonstrates the issue.

@eleftherias eleftherias added status: waiting-for-feedback We need additional information before we can continue in: web An issue in web modules (web, webmvc) and removed status: waiting-for-triage An issue we've not yet triaged labels Apr 20, 2020
@yoshikawaa
Copy link
Contributor Author

yoshikawaa commented Apr 21, 2020

Dear. @eleftherias
I uploaded the sample application.

Could you explain how you arrived at this behaviour?

Please check sample application.
Depending on the browser, "" may be interpreted as the context root or as a relative path from the request. And at least in my environment, Chrome can't interpret "" correctly.

What is the scenario in which the application is set to use relative context, but also needs to redirect somewhere outside of the root context?

When a URL that does not contains the context path is specified, I expected to redirect always to the context root.

... However, if it is determined that "" should indicate a relative path from the request path (the request path itself), then further correction is required.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Apr 21, 2020
@eleftherias
Copy link
Contributor

Thank you for the sample @yoshikawaa.

While this sample demonstrates the issue, I am not able to see the cause of it, due to the multitude of dependencies that seem to hide the configuration.

Please modify the sample to confirm to these minimal sample guidelines.

Here are a few key things that are troubling about the sample in its current state:

  • You appear to be setting the context-path to redirect-test but I do not see the context set anywhere in the code
  • You may be setting tomcat.use-relative-redirects to true but I do not see that setting anywhere in the code
  • There are many dependencies in this sample that appear to have side-affects, which makes it impossible to determine the cause of this issue

@eleftherias eleftherias removed the status: feedback-provided Feedback has been provided label May 1, 2020
@yoshikawaa
Copy link
Contributor Author

yoshikawaa commented May 11, 2020

@eleftherias
Thank you for the advice.
I reviewed the sample and made it a minimal code.
The code should be easy to understand.
https://github.com/yoshikawaa/spring-security-gh8399

@eleftherias
Copy link
Contributor

Thank you for the updated sample @yoshikawaa.

This scenario occurs when there is a disconnect between what the application is expecting to receive (context relative URL) and what it is actually given (not context relative URL).

When looking at gh-4142, I was hesitant to throw an exception in this case, but now I think that may be the best response.

This situation happens what a developer does something unexpected, not a user, so it may be best to warn the developer that they are doing something that the application is not expecting.

What do you think about throwing an exception in this case, rather than redirecting to the root context path?

@yoshikawaa
Copy link
Contributor Author

@eleftherias
Looks good.
Considering the role of context relative, I think that it is the correct response to throw an error when a redirect URL outside the context is entered.

Based on this, I will fix this pull request.

@yoshikawaa yoshikawaa force-pushed the redirect-context-root branch from 76ac2d4 to adf1901 Compare May 18, 2020 02:58
@yoshikawaa yoshikawaa changed the title redirect to context root using request context path. throw exception if URL does not include context path in context relative. May 18, 2020
@eleftherias eleftherias added type: enhancement A general enhancement type: breaks-passivity A change that breaks passivity with the previous release labels May 19, 2020
@eleftherias eleftherias added this to the 5.4.0-M2 milestone May 19, 2020
Copy link
Contributor

@eleftherias eleftherias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates @yoshikawaa!

All of the code looks good.
My one note is to format your commit message to follow our conventions https://github.com/spring-projects/spring-security/blob/master/CONTRIBUTING.adoc#format-commit-messages.

Here is a suggestion, but feel free to update it as you see fit

Throw exception if context path not in redirect

Issue: gh-8399

@yoshikawaa yoshikawaa force-pushed the redirect-context-root branch from adf1901 to 94d36ee Compare May 20, 2020 01:12
@yoshikawaa yoshikawaa changed the title throw exception if URL does not include context path in context relative. Throw exception if URL does not include context path when context relative May 20, 2020
@yoshikawaa
Copy link
Contributor Author

@eleftherias
Thanks for your review & advice.
I've kept the message a bit long in order to convey the commit as accurately as possible.

@eleftherias eleftherias merged commit f08ca4e into spring-projects:master May 20, 2020
@eleftherias
Copy link
Contributor

Thanks for the PR @yoshikawaa!
This is now merged into master.

I am curious if we have the same issue one the reactive side.
Would you be interested in investigating if DefaultServerRedirectStrategy has the same issue, and if it does, submitting a fix for it?

@yoshikawaa
Copy link
Contributor Author

Sorry for the late response, @eleftherias .

When using spring-boot-starter-tomcat, reactive's response.getHeaders().setLocation("") produced similar results as servlet's response.sendRedirect("").

private URI createLocation(ServerWebExchange exchange, URI location) {
if (!this.contextRelative) {
return location;
}
String url = location.toASCIIString();
if (url.startsWith("/")) {
String context = exchange.getRequest().getPath().contextPath().value();
return URI.create(context + url);
}
return location;
}

The DefaultServerRedirectStrategy#createLocation method does not perform the process of calculating the redirect destination URL by removing the scheme and context path from the URL.
As a result, It will be response.getHeaders().setLocation("") only when the developer intentionally sets the empty redirect URL (eg URI.create("")).

Since behavior when intentionally specifying an empty URL is as requested by the developer and it is not a trouble of Spring Security, I think that it is no need to fix this.

Regards.

@eleftherias
Copy link
Contributor

Thank you for looking into that @yoshikawaa.
I agree with your assessment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web An issue in web modules (web, webmvc) type: breaks-passivity A change that breaks passivity with the previous release type: enhancement A general enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants