[
https://issues.apache.org/jira/browse/TAP5-2577?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Geoff Callender updated TAP5-2577:
----------------------------------
Description:
I have a secured application, meaning it insists on HTTPS, so it should return
HTTPS URLs for everything, but it doesn't. When an event handler returns a page
class or an injected page, Tapestry returns an HTTP URL.
{code}
public class Page1 {
@InjectPage
private Page2 page2;
Object onToPage2InjectPage() {
return page2;
}
Object onToPage2Class() {
return Page2.class;
}
}
{code}
The problem started when I switched handling of HTTPS to a load balancer (AWS
Application Load Balancer). It forwards the request as HTTP, along with the
HTTPS headers intact. Normally Tapestry recognises the request is secure and
returns a secure URL, but not in the 2 cases above.
I've narrowed the problem down to a method in RequestSecurityManagerImpl:
{code}
public LinkSecurity checkPageSecurity(String pageName)
{
if (!securityEnabled)
{
return request.isSecure() ? LinkSecurity.SECURE :
LinkSecurity.INSECURE;
}
boolean securePage = isSecure(pageName);
if (request.isSecure() == securePage)
{
return securePage ? LinkSecurity.SECURE : LinkSecurity.INSECURE;
}
// Return a value that will, ultimately, force an absolute URL.
return securePage ? LinkSecurity.FORCE_SECURE :
LinkSecurity.FORCE_INSECURE;
}
{code}
It assumes that a secure page is HTTPS and therefore it returns
LinkSecurity.SECURE instead of LinkSecurity.FORCE_SECURE . Consequently,
Tapestry returns a relative URL instead of an absolute URL specifying
"https://".
I see 3 possible solutions:
(1) Always return absolute URLs.
(2) Instead of relative URLs, return a protocol-relative URL (i.e. "//" instead
of "https://" or "http://").
(3) Modify the code to handle the possibility that protocol and isSecure()
disagree. For example (this code snippet has been tested and is running live):
{code}
if (request.isSecure() == securePage)
{
if (request.isSecure() &&
request.getAttribute("servletAPI.scheme").equals("https")
|| !request.isSecure() &&
request.getAttribute("servletAPI.scheme").equals("http"))
{
return securePage ? LinkSecurity.SECURE :
LinkSecurity.INSECURE;
}
else
{
return securePage ? LinkSecurity.FORCE_SECURE :
LinkSecurity.FORCE_INSECURE;
}
}
{code}
Is possibility 1 a bad idea? Are longer URLs really a big deal?
Some people suggest possibility 2 has downsides such as page URLs not standing
on their own if copied and pasted. Maybe that's an issue.
I used possibility 3 to solved my problem. It works.
was:
I have a secured application, meaning it insists on HTTPS, so it should return
HTTPS URLs for everything, but it doesn't. When an event handler returns a page
class or an injected page, Tapestry returns an HTTP URL.
public class Page1 {
@InjectPage
private Page2 page2;
Object onToPage2InjectPage() {
return page2;
}
Object onToPage2Class() {
return Page2.class;
}
}
The problem started when I switched handling of HTTPS to a load balancer (AWS
Application Load Balancer). It forwards the request as HTTP, along with the
HTTPS headers intact. Normally Tapestry recognises the request is secure and
returns a secure URL, but not in the 2 cases above.
I've narrowed the problem down to a method in RequestSecurityManagerImpl:
public LinkSecurity checkPageSecurity(String pageName)
{
if (!securityEnabled)
{
return request.isSecure() ? LinkSecurity.SECURE :
LinkSecurity.INSECURE;
}
boolean securePage = isSecure(pageName);
if (request.isSecure() == securePage)
{
return securePage ? LinkSecurity.SECURE : LinkSecurity.INSECURE;
}
// Return a value that will, ultimately, force an absolute URL.
return securePage ? LinkSecurity.FORCE_SECURE :
LinkSecurity.FORCE_INSECURE;
}
It assumes that a secure page is HTTPS and therefore it returns
LinkSecurity.SECURE instead of LinkSecurity.FORCE_SECURE . Consequently,
Tapestry returns a relative URL instead of an absolute URL specifying
"https://".
I see 3 possible solutions:
(1) Always return absolute URLs.
(2) Instead of relative URLs, return a protocol-relative URL (i.e. "//" instead
of "https://" or "http://").
(3) Modify the code to handle the possibility that protocol and isSecure()
disagree. For example (this code snippet has been tested and is running live):
if (request.isSecure() == securePage)
{
if (request.isSecure() &&
request.getAttribute("servletAPI.scheme").equals("https")
|| !request.isSecure() &&
request.getAttribute("servletAPI.scheme").equals("http"))
{
return securePage ? LinkSecurity.SECURE :
LinkSecurity.INSECURE;
}
else
{
return securePage ? LinkSecurity.FORCE_SECURE :
LinkSecurity.FORCE_INSECURE;
}
}
Is possibility 1 a bad idea? Are longer URLs really a big deal?
Some people suggest possibility 2 has downsides such as page URLs not standing
on their own if copied and pasted. Maybe that's an issue.
I used possibility 3 to solved my problem. It works.
> HTTPS + Load balancer not working with InjectPage or Class
> ----------------------------------------------------------
>
> Key: TAP5-2577
> URL: https://issues.apache.org/jira/browse/TAP5-2577
> Project: Tapestry 5
> Issue Type: Bug
> Components: tapestry-core
> Affects Versions: 5.4.1, 5.4.2
> Reporter: Geoff Callender
> Labels: easyfix, security
>
> I have a secured application, meaning it insists on HTTPS, so it should
> return HTTPS URLs for everything, but it doesn't. When an event handler
> returns a page class or an injected page, Tapestry returns an HTTP URL.
> {code}
> public class Page1 {
> @InjectPage
> private Page2 page2;
> Object onToPage2InjectPage() {
> return page2;
> }
> Object onToPage2Class() {
> return Page2.class;
> }
> }
> {code}
> The problem started when I switched handling of HTTPS to a load balancer (AWS
> Application Load Balancer). It forwards the request as HTTP, along with the
> HTTPS headers intact. Normally Tapestry recognises the request is secure and
> returns a secure URL, but not in the 2 cases above.
> I've narrowed the problem down to a method in RequestSecurityManagerImpl:
> {code}
> public LinkSecurity checkPageSecurity(String pageName)
> {
> if (!securityEnabled)
> {
> return request.isSecure() ? LinkSecurity.SECURE :
> LinkSecurity.INSECURE;
> }
> boolean securePage = isSecure(pageName);
> if (request.isSecure() == securePage)
> {
> return securePage ? LinkSecurity.SECURE : LinkSecurity.INSECURE;
> }
> // Return a value that will, ultimately, force an absolute URL.
> return securePage ? LinkSecurity.FORCE_SECURE :
> LinkSecurity.FORCE_INSECURE;
> }
> {code}
> It assumes that a secure page is HTTPS and therefore it returns
> LinkSecurity.SECURE instead of LinkSecurity.FORCE_SECURE . Consequently,
> Tapestry returns a relative URL instead of an absolute URL specifying
> "https://".
> I see 3 possible solutions:
> (1) Always return absolute URLs.
> (2) Instead of relative URLs, return a protocol-relative URL (i.e. "//"
> instead of "https://" or "http://").
> (3) Modify the code to handle the possibility that protocol and isSecure()
> disagree. For example (this code snippet has been tested and is running
> live):
> {code}
> if (request.isSecure() == securePage)
> {
> if (request.isSecure() &&
> request.getAttribute("servletAPI.scheme").equals("https")
> || !request.isSecure() &&
> request.getAttribute("servletAPI.scheme").equals("http"))
> {
> return securePage ? LinkSecurity.SECURE :
> LinkSecurity.INSECURE;
> }
> else
> {
> return securePage ? LinkSecurity.FORCE_SECURE :
> LinkSecurity.FORCE_INSECURE;
> }
> }
> {code}
> Is possibility 1 a bad idea? Are longer URLs really a big deal?
> Some people suggest possibility 2 has downsides such as page URLs not
> standing on their own if copied and pasted. Maybe that's an issue.
> I used possibility 3 to solved my problem. It works.
--
This message was sent by Atlassian JIRA
(v6.3.15#6346)