at.gv.egovernment.moa.id.auth.servlet.AuthServlet.java Source code

Java tutorial

Introduction

Here is the source code for at.gv.egovernment.moa.id.auth.servlet.AuthServlet.java

Source

/*******************************************************************************
 * Copyright 2014 Federal Chancellery Austria
 * MOA-ID has been developed in a cooperation between BRZ, the Federal
 * Chancellery Austria - ICT staff unit, and Graz University of Technology.
 * 
 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
 * the European Commission - subsequent versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at:
 * http://www.osor.eu/eupl/
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the Licence is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Licence for the specific language governing permissions and
 * limitations under the Licence.
 * 
 * This product combines work with different licenses. See the "NOTICE" text
 * file for details on the various modules and licenses.
 * The "NOTICE" text file is part of the distribution. Any derivative works
 * that you distribute must include a readable copy of the "NOTICE" text file.
 ******************************************************************************/
/*
 * Copyright 2003 Federal Chancellery Austria
 * MOA-ID has been developed in a cooperation between BRZ, the Federal
 * Chancellery Austria - ICT staff unit, and Graz University of Technology.
 *
 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
 * the European Commission - subsequent versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at:
 * http://www.osor.eu/eupl/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the Licence is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Licence for the specific language governing permissions and
 * limitations under the Licence.
 *
 * This product combines work with different licenses. See the "NOTICE" text
 * file for details on the various modules and licenses.
 * The "NOTICE" text file is part of the distribution. Any derivative works
 * that you distribute must include a readable copy of the "NOTICE" text file.
 */

package at.gv.egovernment.moa.id.auth.servlet;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import at.gv.egovernment.moa.id.advancedlogging.StatisticLogger;
import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants;
import at.gv.egovernment.moa.id.auth.exception.AuthenticationException;
import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
import at.gv.egovernment.moa.id.auth.exception.WrongParametersException;
import at.gv.egovernment.moa.id.config.ConfigurationException;
import at.gv.egovernment.moa.id.entrypoints.DispatcherServlet;
import at.gv.egovernment.moa.id.process.ProcessEngine;
import at.gv.egovernment.moa.id.storage.DBExceptionStoreImpl;
import at.gv.egovernment.moa.id.storage.IExceptionStore;
import at.gv.egovernment.moa.id.util.ServletUtils;
import at.gv.egovernment.moa.logging.Logger;
import at.gv.egovernment.moa.util.MiscUtil;
import at.gv.egovernment.moa.util.URLDecoder;

/**
 * Base class for MOA-ID Auth Servlets, providing standard error handling and
 * constant names.
 * 
 * @author Paul Ivancsics
 * @version $Id$
 */
public class AuthServlet extends HttpServlet implements MOAIDAuthConstants {

    /**
     * 
     */
    private static final long serialVersionUID = -6929905344382283738L;

    protected static final String ERROR_CODE_PARAM = "errorid";

    /**
     * The process engine.
     */
    private ProcessEngine processEngine;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Logger.debug("GET " + this.getServletName());

        this.setNoCachingHeadersInHttpRespone(req, resp);
    }

    protected void handleErrorNoRedirect(String errorMessage, Throwable exceptionThrown, HttpServletRequest req,
            HttpServletResponse resp) {

        if (null != errorMessage) {
            Logger.error(errorMessage);
            req.setAttribute("ErrorMessage", errorMessage);
        }

        if (null != exceptionThrown) {
            if (null == errorMessage)
                errorMessage = exceptionThrown.getMessage();
            Logger.error(errorMessage, exceptionThrown);
            req.setAttribute("ExceptionThrown", exceptionThrown);
        }

        if (Logger.isDebugEnabled()) {
            req.setAttribute("LogLevel", "debug");
        }

        StatisticLogger logger = StatisticLogger.getInstance();
        logger.logErrorOperation(exceptionThrown);

        // forward this to errorpage-auth.jsp where the HTML error page is
        // generated
        ServletContext context = getServletContext();
        RequestDispatcher dispatcher = context.getRequestDispatcher("/errorpage-auth.jsp");
        try {

            resp.setHeader(MOAIDAuthConstants.HEADER_EXPIRES, MOAIDAuthConstants.HEADER_VALUE_EXPIRES);
            resp.setHeader(MOAIDAuthConstants.HEADER_PRAGMA, MOAIDAuthConstants.HEADER_VALUE_PRAGMA);
            resp.setHeader(MOAIDAuthConstants.HEADER_CACHE_CONTROL, MOAIDAuthConstants.HEADER_VALUE_CACHE_CONTROL);
            resp.addHeader(MOAIDAuthConstants.HEADER_CACHE_CONTROL,
                    MOAIDAuthConstants.HEADER_VALUE_CACHE_CONTROL_IE);

            dispatcher.forward(req, resp);
        } catch (ServletException e) {
            Logger.error(e);
        } catch (IOException e) {
            Logger.error(e);
        }
    }

    /**
     * Handles an error. <br>>
     * <ul>
     * <li>Logs the error</li>
     * <li>Places error message and exception thrown into the request as request
     * attributes (to be used by <code>"/errorpage-auth.jsp"</code>)</li>
     * <li>Sets HTTP status 500 (internal server error)</li>
     * </ul>
     * 
     * @param errorMessage
     *            error message
     * @param exceptionThrown
     *            exception thrown
     * @param req
     *            servlet request
     * @param resp
     *            servlet response
     */
    protected void handleError(String errorMessage, Throwable exceptionThrown, HttpServletRequest req,
            HttpServletResponse resp, String pendingRequestID) {

        if (null != errorMessage) {
            Logger.error(errorMessage);
            req.setAttribute("ErrorMessage", errorMessage);
        }

        if (null != exceptionThrown) {
            if (null == errorMessage)
                errorMessage = exceptionThrown.getMessage();
            Logger.error(errorMessage, exceptionThrown);
            req.setAttribute("ExceptionThrown", exceptionThrown);
        }

        if (Logger.isDebugEnabled()) {
            req.setAttribute("LogLevel", "debug");
        }

        if (!(exceptionThrown instanceof MOAIDException)) {
            Logger.error("Receive an internal error: Message=" + exceptionThrown.getMessage(), exceptionThrown);

        }

        IExceptionStore store = DBExceptionStoreImpl.getStore();
        String id = store.storeException(exceptionThrown);

        if (id != null && MiscUtil.isNotEmpty(pendingRequestID)) {

            String redirectURL = null;

            redirectURL = ServletUtils.getBaseUrl(req);
            redirectURL += "/dispatcher?" + ERROR_CODE_PARAM + "=" + id + "&"
                    + DispatcherServlet.PARAM_TARGET_PENDINGREQUESTID + "=" + pendingRequestID;

            resp.setContentType("text/html");
            resp.setStatus(302);

            resp.addHeader("Location", redirectURL);
            Logger.debug("REDIRECT TO: " + redirectURL);

            return;

        } else {

            //Exception can not be stored in database
            handleErrorNoRedirect(errorMessage, exceptionThrown, req, resp);
        }
    }

    /**
     * Handles a <code>WrongParametersException</code>.
     * 
     * @param req
     *            servlet request
     * @param resp
     *            servlet response
     */
    protected void handleWrongParameters(WrongParametersException ex, HttpServletRequest req,
            HttpServletResponse resp) {
        Logger.error(ex.toString());
        req.setAttribute("WrongParameters", ex.getMessage());

        // forward this to errorpage-auth.jsp where the HTML error page is
        // generated
        ServletContext context = getServletContext();
        RequestDispatcher dispatcher = context.getRequestDispatcher("/errorpage-auth.jsp");
        try {
            resp.setHeader(MOAIDAuthConstants.HEADER_EXPIRES, MOAIDAuthConstants.HEADER_VALUE_EXPIRES);
            resp.setHeader(MOAIDAuthConstants.HEADER_PRAGMA, MOAIDAuthConstants.HEADER_VALUE_PRAGMA);
            resp.setHeader(MOAIDAuthConstants.HEADER_CACHE_CONTROL, MOAIDAuthConstants.HEADER_VALUE_CACHE_CONTROL);
            resp.addHeader(MOAIDAuthConstants.HEADER_CACHE_CONTROL,
                    MOAIDAuthConstants.HEADER_VALUE_CACHE_CONTROL_IE);

            dispatcher.forward(req, resp);
        } catch (ServletException e) {
            Logger.error(e);
        } catch (IOException e) {
            Logger.error(e);
        }
    }

    /**
     * Logs all servlet parameters for debugging purposes.
     */
    protected void logParameters(HttpServletRequest req) {
        for (Enumeration params = req.getParameterNames(); params.hasMoreElements();) {
            String parname = (String) params.nextElement();
            Logger.debug("Parameter " + parname + req.getParameter(parname));
        }
    }

    /**
     * Parses the request input stream for parameters, assuming parameters are
     * encoded UTF-8 (no standard exists how browsers should encode them).
     * 
     * @param req
     *            servlet request
     * 
     * @return mapping parameter name -> value
     * 
     * @throws IOException
     *             if parsing request parameters fails.
     * 
     * @throws FileUploadException
     *             if parsing request parameters fails.
     */
    protected Map<String, String> getParameters(HttpServletRequest req) throws IOException, FileUploadException {

        Map<String, String> parameters = new HashMap<String, String>();

        if (ServletFileUpload.isMultipartContent(req)) {
            // request is encoded as mulitpart/form-data
            FileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload upload = null;
            upload = new ServletFileUpload(factory);
            List items = null;
            items = upload.parseRequest(req);
            for (int i = 0; i < items.size(); i++) {
                FileItem item = (FileItem) items.get(i);
                if (item.isFormField()) {
                    // Process only form fields - no file upload items
                    String logString = item.getString("UTF-8");

                    // TODO use RegExp
                    String startS = "<pr:Identification><pr:Value>";
                    String endS = "</pr:Value><pr:Type>urn:publicid:gv.at:baseid</pr:Type>";
                    String logWithMaskedBaseid = logString;
                    int start = logString.indexOf(startS);
                    if (start > -1) {
                        int end = logString.indexOf(endS);
                        if (end > -1) {
                            logWithMaskedBaseid = logString.substring(0, start);
                            logWithMaskedBaseid += startS;
                            logWithMaskedBaseid += "xxxxxxxxxxxxxxxxxxxxxxxx";
                            logWithMaskedBaseid += logString.substring(end, logString.length());
                        }
                    }
                    parameters.put(item.getFieldName(), item.getString("UTF-8"));
                    Logger.debug("Processed multipart/form-data request parameter: \nName: " + item.getFieldName()
                            + "\nValue: " + logWithMaskedBaseid);
                }
            }
        }

        else {
            // request is encoded as application/x-www-urlencoded
            InputStream in = req.getInputStream();

            String paramName;
            String paramValueURLEncoded;
            do {
                paramName = new String(readBytesUpTo(in, '='));
                if (paramName.length() > 0) {
                    paramValueURLEncoded = readBytesUpTo(in, '&');
                    String paramValue = URLDecoder.decode(paramValueURLEncoded, "UTF-8");
                    parameters.put(paramName, paramValue);
                }
            } while (paramName.length() > 0);
            in.close();
        }

        return parameters;
    }

    /**
     * Reads bytes up to a delimiter, consuming the delimiter.
     * 
     * @param in
     *            input stream
     * @param delimiter
     *            delimiter character
     * @return String constructed from the read bytes
     * @throws IOException
     */
    protected String readBytesUpTo(InputStream in, char delimiter) throws IOException {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        boolean done = false;
        int b;
        while (!done && (b = in.read()) >= 0) {
            if (b == delimiter)
                done = true;
            else
                bout.write(b);
        }
        return bout.toString();
    }

    /**
     * Calls the web application initializer.
     * 
     * @see javax.servlet.Servlet#init(ServletConfig)
     */
    public void init(ServletConfig servletConfig) throws ServletException {
        super.init(servletConfig);
    }

    //   public void contextDestroyed(ServletContextEvent arg0) {
    //      Security.removeProvider((new IAIK()).getName());
    //      Security.removeProvider((new ECCProvider()).getName());
    //   }

    /**
     * Set response headers to avoid caching
     * 
     * @param request
     *            HttpServletRequest
     * @param response
     *            HttpServletResponse
     */
    protected void setNoCachingHeadersInHttpRespone(HttpServletRequest request, HttpServletResponse response) {
        response.setHeader(MOAIDAuthConstants.HEADER_EXPIRES, MOAIDAuthConstants.HEADER_VALUE_EXPIRES);
        response.setHeader(MOAIDAuthConstants.HEADER_PRAGMA, MOAIDAuthConstants.HEADER_VALUE_PRAGMA);
        response.setHeader(MOAIDAuthConstants.HEADER_CACHE_CONTROL, MOAIDAuthConstants.HEADER_VALUE_CACHE_CONTROL);
        response.addHeader(MOAIDAuthConstants.HEADER_CACHE_CONTROL,
                MOAIDAuthConstants.HEADER_VALUE_CACHE_CONTROL_IE);

    }

    /**
     * Adds a parameter to a URL.
     * 
     * @param url
     *            the URL
     * @param paramname
     *            parameter name
     * @param paramvalue
     *            parameter value
     * @return the URL with parameter added
     */
    protected static String addURLParameter(String url, String paramname, String paramvalue) {
        String param = paramname + "=" + paramvalue;
        if (url.indexOf("?") < 0)
            return url + "?" + param;
        else
            return url + "&" + param;
    }

    /**
     * Checks if HTTP requests are allowed
     * 
     * @param authURL
     *            requestURL
     * @throws AuthenticationException
     *             if HTTP requests are not allowed
     * @throws ConfigurationException
     */
    protected void checkIfHTTPisAllowed(String authURL) throws AuthenticationException, ConfigurationException {
        // check if HTTP Connection may be allowed (through
        // FRONTEND_SERVLETS_ENABLE_HTTP_CONNECTION_PROPERTY)

        //Removed from MOA-ID 2.0 config
        //      String boolStr = AuthConfigurationProvider
        //            .getInstance()
        //            .getGenericConfigurationParameter(
        //                  AuthConfigurationProvider.FRONTEND_SERVLETS_ENABLE_HTTP_CONNECTION_PROPERTY);
        if ((!authURL.startsWith("https:"))
        //&& (false == BoolUtils.valueOf(boolStr))
        )
            throw new AuthenticationException("auth.07", new Object[] { authURL + "*" });

    }

    /**
     * Returns the underlying process engine instance.
     * 
     * @return The process engine (never {@code null}).
     * @throws NoSuchBeanDefinitionException
     *             if no {@link ProcessEngine} bean was found.
     * @throws NoUniqueBeanDefinitionException
     *             if more than one {@link ProcessEngine} bean was found.
     * @throws BeansException
     *             if a problem getting the {@link ProcessEngine} bean occurred.
     * @throws IllegalStateException
     *             if the Spring WebApplicationContext was not found, which means that the servlet is used outside a
     *             Spring web environment.
     */
    public synchronized ProcessEngine getProcessEngine() {
        if (processEngine == null) {
            WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
            if (ctx == null) {
                throw new IllegalStateException(
                        "Unable to find Spring WebApplicationContext. Servlet needs to be executed within a Spring web environment.");
            }
            processEngine = ctx.getBean(ProcessEngine.class);
        }
        return processEngine;
    }

}