com.meltmedia.cadmium.servlets.AbstractSecureRedirectStrategy.java Source code

Java tutorial

Introduction

Here is the source code for com.meltmedia.cadmium.servlets.AbstractSecureRedirectStrategy.java

Source

/**
 *    Copyright 2012 meltmedia
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package com.meltmedia.cadmium.servlets;

import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;

/**
 * Provides an abstract base class for SecureRedirectStrategy implementations.
 * 
 * @author Christian Trimble
 */
public abstract class AbstractSecureRedirectStrategy implements SecureRedirectStrategy {

    /** The default port for HTTP */
    public static final int DEFAULT_HTTP_PORT = 80;

    public static final String HTTP_PROTOCOL = "http";

    /** The default port for HTTPS */
    public static final int DEFAULT_HTTPS_PORT = 443;

    public static final String HTTPS_PROTOCOL = "https";

    /** A mapping from common insecure ports to secure ports. */
    private static final Map<Integer, Integer> TO_SECURE_PORT_MAP = new HashMap<Integer, Integer>();

    /** A mapping from common secure ports to insecure ports. */
    private static final Map<Integer, Integer> TO_INSECURE_PORT_MAP = new HashMap<Integer, Integer>();

    /** Adds an entry to the secure and insecure port map. */
    private static void addPortMapping(Integer insecurePort, Integer securePort) {
        TO_SECURE_PORT_MAP.put(insecurePort, securePort);
        TO_INSECURE_PORT_MAP.put(securePort, insecurePort);
    }

    static {
        addPortMapping(DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT);
        addPortMapping(8080, 8443);
    }

    /**
     * Returns the default port for the specified protocol.
     * 
     * @param protocol the protocol name.
     * @return the default port for the specifed protocol.
     */
    public static int getDefaultPort(String protocol) {
        if (HTTP_PROTOCOL.equals(protocol)) {
            return DEFAULT_HTTP_PORT;
        } else if (HTTPS_PROTOCOL.equals(protocol)) {
            return DEFAULT_HTTPS_PORT;
        } else {
            throw new IllegalArgumentException("No known default for " + protocol);
        }
    }

    /**
     * Looks up a corresponding port number from a port mapping.
     * @param mapping the port mapping
     * @param port the key in the port map.
     * @return the corresponding port number from the port mapping.
     * @throws RuntimeException if a value could not be found.
     */
    public static int mapPort(Map<Integer, Integer> mapping, int port) {
        Integer mappedPort = mapping.get(port);
        if (mappedPort == null)
            throw new RuntimeException("Could not map port " + port);
        return mappedPort;
    }

    /**
     * Gets the original protocol for the specified request.
     * @param request the request made by the user.
     * @return the original protocol for the request.
     */
    public abstract String getProtocol(HttpServletRequest request);

    /**
     * Gets the original port for the specified request.
     * @param request the request made by the user.
     * @return the original protocol for the request.
     */
    public abstract int getPort(HttpServletRequest request);

    /**
     * Returns the secure version of the original URL for the request.
     * 
     * @param request the insecure request that was made.
     * @param response the response for the request.
     * @return the secure version of the original URL for the request.
     * @throws IOException if the url could not be created.
     */
    public String secureUrl(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String protocol = getProtocol(request);
        if (protocol.equalsIgnoreCase(HTTP_PROTOCOL)) {
            int port = mapPort(TO_SECURE_PORT_MAP, getPort(request));
            try {
                URI newUri = changeProtocolAndPort(HTTPS_PROTOCOL, port == DEFAULT_HTTPS_PORT ? -1 : port, request);
                return newUri.toString();
            } catch (URISyntaxException e) {
                throw new IllegalStateException("Failed to create URI.", e);
            }
        } else {
            throw new UnsupportedProtocolException("Cannot build secure url for " + protocol);
        }
    }

    /**
     * Returns the insecure version of the original URL for the request.
     * 
     * @param request the secure request that was made.
     * @param response the response for the request.
     * @return the insecure version of the original URL for the request.
     * @throws IOException if the url could not be created.
     */
    public String insecureUrl(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String protocol = getProtocol(request);
        if (protocol.equalsIgnoreCase(HTTPS_PROTOCOL)) {
            int port = mapPort(TO_INSECURE_PORT_MAP, getPort(request));
            try {
                return changeProtocolAndPort(HTTP_PROTOCOL, port == DEFAULT_HTTP_PORT ? -1 : port, request)
                        .toString();
            } catch (URISyntaxException e) {
                throw new IllegalStateException("Failed to create URI.", e);
            }
        } else {
            throw new UnsupportedProtocolException("Cannot build insecure url for " + protocol);
        }
    }

    /**
     * Sends a moved perminately redirect to the secure form of the request URL.
     * 
     * @request the request to make secure.
     * @response the response for the request.
     */
    @Override
    public void makeSecure(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
        response.setHeader("Location", secureUrl(request, response));
        response.getOutputStream().flush();
        response.getOutputStream().close();
    }

    /**
     * Sends a moved perminately redirect to the insecure form of the request URL.
     * 
     * @request the request to make secure.
     * @response the response for the request.
     */
    @Override
    public void makeInsecure(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
        response.setHeader("Location", insecureUrl(request, response));
        response.getOutputStream().flush();
        response.getOutputStream().close();
    }

    /**
     * Constructs a URI for request and calls changeProtocolAndPort(String, int, URI).
     * 
     * @param protocol the new protocol (scheme) in the resulting URI.
     * @param port the new port in the resulting URI, or the default port if -1 is provided.
     * @param request the request to use as the URI template.
     * @return a new URI object with the updated protocol and port.
     * @throws URISyntaxException 
      */
    public static URI changeProtocolAndPort(String protocol, int port, HttpServletRequest request)
            throws URISyntaxException {
        return changeProtocolAndPort(protocol, port,
                URI.create(request.getRequestURL().append(
                        (StringUtils.isEmpty(request.getQueryString()) ? "" : "?" + request.getQueryString()))
                        .toString()));
    }

    /**
     * Returns a new URI object, based on the specified URI template, with an updated port (scheme) and port.  If the port
     * number is -1, then the default port is used in the resulting URI. 
     * 
     * @param protocol the new protocol (scheme) in the resulting URI.
     * @param port the new port in the resulting URI, or the default port if -1 is provided.
     * @param template the source of all other values for the new URI.
     * @return a new URI object with the updated protocol and port.
     * @throws URISyntaxException 
     */
    public static URI changeProtocolAndPort(String protocol, int port, URI template) throws URISyntaxException {
        return new URI(protocol, template.getUserInfo(), template.getHost(), port, template.getPath(),
                template.getQuery(), null);
    }

}