[ 
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)

Reply via email to