By jluehe on Dec 08, 2008
How to downshift from HTTPS to HTTP in your web application
Web applications will normally protect any of their web resources that process security-sensitive information (e.g., the login page used by FORM authentication) with SSL, to ensure that the information submitted by the user (e.g., username and password security credentials) will not be transmitted in the clear.
Some web applications will only protect web resources that process security-sensitive information in this manner, while allowing requests for other resources to travel in the clear.
Imagine a user accessing some of the unprotected resources of a web application (over HTTP) before accessing a resource that requires FORM
authentication, where the FORM login page is guarded by a transport guarantee of
CONFIDENTIAL according to the web application's
deployment descriptor. In this case, the protocol will change from HTTP to HTTPS (to satisfy the transport guarantee of the login page), and will remain HTTPS even after the user has authenticated successfully and continues accessing any of the unprotected resources.
The fact that the protocol remains HTTPS once it has been changed to HTTPS, even though HTTPS may no longer be required, can be a problem for performance sensitive applications that do not want to incur the overhead of SSL unless required.
This blog explains how a web application can be written so that the protocol changes back to HTTP when HTTPS is no longer needed.
Imagine a very simple web application containing two servlets
UseHttps.java, which are mapped to
/useHttps, respectively. Further assume that the web application must satisfy the following requirements:
- REQ_1: Access to "/useHttps" must be over HTTPS (otherwise, the servlet will throw an exception). This means that if the current protocol is HTTP, it must be upgraded to HTTPS.
- REQ_2: Access to "/useHttp" must be over HTTP (otherwise, the servlet will throw an exception). This means that if the current protocol is HTTPS, it must be downshifted to HTTP.
REQ_1 will be handled automatically by the container, by declaring the following security constraint in the web application's
REQ_2 cannot be handled automatically by the container, and must be implemented by the application itself. In order to address REQ_2, we are going to implement a filter that intercepts every request and determines programmtically whether the target resource is guarded by a transport guarantee of
CONFIDENTIAL. If it is not, and the request came in over HTTPS, the filter will issue a redirect to the target resource over HTTP.
In order to determine if a requested resource is guarded by HTTPS, the filter leverages the JavaTM Authorization Contract for Containers (Java ACC), which defines new
java.security.Permission classes to satisfy the authorization model of the Java Platform, Enterprise Edition. In our particular case, the filter creates and uses an instance of
javax.security.jacc.WebUserDataPermission to check if the target resource of a request is guarded by HTTPS.
The complete source code of the filter and the two servlets, as well as the
web.xml, are provided as part of the sample application's WAR file and may be downloaded from this link.
For the sake of simplicity, we assume the default GlassFish configuration of three HTTP listeners: one listener reserved for any admin requests, a second listener for user traffic over HTTP (on port 8080), and a third listener for user traffic over HTTPS (on port 8181). (Notice that when you are using GlassFish v3 Prelude, you must enable the HTTPS listener on port 8181, which is disabled by default.)
The port number of the HTTP port for user requests is fed into the filter via an init parameter in
This is necessary so that the filter will know which port number to use when redirecting from HTTPS to HTTP.
To see the upshift from HTTP to HTTPS, and downshift from HTTPS to HTTP in action, follow these simple steps:
- Download and install GlassFish v2 UR2 or GlassFish v3 Prelude.
- Download the sample web application
sample.war, and deploy it to GlassFish.
- Access this URL:
http://leah:8080/sample/useHttps. Notice how the request gets redirected to the HTTPS port, and how the protocol changes from HTTP to HTTPS:
- Now edit the above HTTPS URL in your browser's address window by removing the trailing s from useHttps, so that the URL reads:
https://localhost:8181/sample/useHttp, and hit return. Notice how the browser displays this warning message: You are about to leave an encrypted page. Information you send or receive from now on could easily be read by a third party, before issuing a redirect to the HTTP port and downshifting the protocol from HTTPS to HTTP:
I hope you found this blog useful. Please send any questions or comments you may have to the GlassFish webtier alias, or post them to the GlassFish webtier forum. I also would like to thank GlassFish security architect Ron Monzillo for his Java ACC related contribution to the idea behind this blog and to the filter code of the sample web application.