Following up on my thread from yesterday, I've finished work on the SSL 
Interceptor, which can be added to the default stack and works as follows:

- If the associated action class is marked with the (custom) @SSLProtected 
annotation and it's an HTTP (non-SSL) GET request, then the interceptor will 
redirect to the https 
(SSL) version of the page.
- Likewise, if it's an HTTPS (SSL) GET request and the action class does not 
have the annotation, then it 
will redirect to the http (non-SSL) version of the page.

I've tested it with both browsers, with and without cookies, and it seems to 
work well, so I'll offer it to those interested.  I'm not a regular contributor 
to the source code base, but if someone wants to submit this into the 
repository, feel free.


/**
 * @name SSLProtected
 * @description Simple marker annotation indicating access to an action class 
should be protected 
 *  under SSL (Secure Sockets Layer) HTTP tunneling. 
 * @version $Revision:  $
 * @author <a href="mailto:[EMAIL PROTECTED]">Shahak Nagiel</a>
 * $Id:  $
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface SSLProtected { }


/**
 * @name SSLInterceptor
 * @description <p>This interceptor performs two functions:
 * <ul><li>If the associated action class is marked with the @SSLProtected 
annotation 
 *     and it's an HTTP (non-SSL) GET request, then the interceptor will 
redirect to the https 
(SSL) version of the page.</li>
 *     <li>Likewise, if it's an HTTPS (SSL) GET request and the action class 
does not have the annotation, then it 

 *    will redirect to the http (non-SSL) version of the page.</li></ul>
 * @version $Revision: $
 * @author <a href="mailto:[EMAIL PROTECTED]">Shahak Nagiel</a>
 * $Id: $
 */
public class SSLInterceptor extends AbstractInterceptor {
    
    /** Creates a new instance of SSLInterceptor */
    public SSLInterceptor() {
        super();
    }
    
    /**
     * Defaults for HTTP and HTTPS ports.  Can be overridden in web.xml with 
context parameters of the same name.
     */
    final static int HTTP_PORT = 8080;
    final static int HTTPS_PORT = 8443;

    final static String HTTP_PORT_PARAM = "HTTP_PORT";
    final static String HTTPS_PORT_PARAM = "HTTPS_PORT";
    final static String HTTP_GET = "GET";
    final static String SCHEME_HTTP = "http";
    final static String SCHEME_HTTPS = "https";

    /**
     * Redirect to SSL or non-SSL version of page as indicated by the presence 
(or absence) of the
     *  @SSLProtected annotation on the action class.
     */
    public String intercept(ActionInvocation invocation) throws Exception {
        
        // initialize request and response
        final ActionContext context = invocation.getInvocationContext ();
        final HttpServletRequest request = 
            (HttpServletRequest) context.get(StrutsStatics.HTTP_REQUEST);
        final HttpServletResponse response = 
            (HttpServletResponse) context.get(StrutsStatics.HTTP_RESPONSE);

        // check scheme
        String scheme = request.getScheme().toLowerCase();

        // check method
        String method = request.getMethod().toUpperCase();
        
        // If the action class uses the SSLProtected marker annotation, then 
see if we need to 
        //  redirect to the SSL protected version of this page
        if 
(invocation.getAction().getClass().isAnnotationPresent(SSLProtected.class)){
            
            if (HTTP_GET.equals(method) && SCHEME_HTTP.equals(scheme)){

                // initialize https port
                String httpsPortParam = 
                    
request.getSession().getServletContext().getInitParameter(HTTP_PORT_PARAM);
                int httpsPort = httpsPortParam == null? HTTPS_PORT : 
Integer.parseInt(httpsPortParam);

                URI uri = new URI(SCHEME_HTTPS, null, request.getServerName(), 
                    httpsPort, 
response.encodeRedirectURL(request.getRequestURI()), 
                    request.getQueryString(), null);

                log.debug("Going to SSL mode, redirecting to " + 
uri.toString());

                response.sendRedirect(uri.toString());
                return null;
            }
        }
        // Otherwise, check to see if we need to redirect to the non-SSL 
version of this page
        else{
            
            if (HTTP_GET.equals(method) && SCHEME_HTTPS.equals(scheme)){
                
                // initialize http port
                String httpPortParam = 
                    
request.getSession().getServletContext().getInitParameter(HTTPS_PORT_PARAM);
                int httpPort = httpPortParam == null? HTTP_PORT : 
Integer.parseInt(httpPortParam);
                
                URI uri = new URI(SCHEME_HTTP, null, request.getServerName(), 
                    httpPort, 
response.encodeRedirectURL(request.getRequestURI()), 
                    request.getQueryString(), null);
                
                log.debug("Going to non-SSL mode, redirecting to " + 
uri.toString());

                response.sendRedirect(uri.toString());
                return null;
            }
        }
        
        return invocation.invoke();
    }
    
    // configure the logger for this class
    private static Log log = LogFactory.getLog(SSLInterceptor.class);
}

Reply via email to