package at.gv.egovernment.moa.id.auth.modules;
import static at.gv.egovernment.moa.id.auth.MOAIDAuthConstants.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
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.apache.commons.lang3.ArrayUtils;
import at.gv.egovernment.moa.id.advancedlogging.StatisticLogger;
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.auth.servlet.AuthServlet;
import at.gv.egovernment.moa.id.config.ConfigurationException;
import at.gv.egovernment.moa.id.entrypoints.DispatcherServlet;
import at.gv.egovernment.moa.id.process.springweb.MoaIdTask;
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;
/**
* Task based counterpart to {@link AuthServlet}, providing the same utility methods (error handling, parameter parsing
* etc.).
The code has been taken from {@link AuthServlet}.
*/
public abstract class AbstractAuthServletTask extends MoaIdTask {
protected static final String ERROR_CODE_PARAM = "errorid";
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 = req.getServletContext();
RequestDispatcher dispatcher = context
.getRequestDispatcher("/errorpage-auth.jsp");
try {
resp.setHeader(HEADER_EXPIRES, HEADER_VALUE_EXPIRES);
resp.setHeader(HEADER_PRAGMA, HEADER_VALUE_PRAGMA);
resp.setHeader(HEADER_CACHE_CONTROL, HEADER_VALUE_CACHE_CONTROL);
resp.addHeader(HEADER_CACHE_CONTROL, HEADER_VALUE_CACHE_CONTROL_IE);
dispatcher.forward(req, resp);
} catch (ServletException e) {
Logger.error(e);
} catch (IOException e) {
Logger.error(e);
}
}
/**
* Handles an error.
>
*
* - Logs the error
* - Places error message and exception thrown into the request as request
* attributes (to be used by
"/errorpage-auth.jsp"
)
* - Sets HTTP status 500 (internal server error)
*
*
* @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 WrongParametersException
.
*
* @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 = req.getServletContext();
RequestDispatcher dispatcher = context
.getRequestDispatcher("/errorpage-auth.jsp");
try {
setNoCachingHeaders(resp);
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 getParameters(HttpServletRequest req) throws IOException,
FileUploadException {
Map parameters = new HashMap();
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 = "";
String endS = "urn:publicid:gv.at:baseid";
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
// [tknall]: we must not consume request body input stream once servlet-api request parameters have been accessed
/*
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();
*/
Iterator> requestParamIt = req.getParameterMap().entrySet().iterator();
while (requestParamIt.hasNext()) {
Entry entry = requestParamIt.next();
String key = entry.getKey();
String[] values = entry.getValue();
// take the last value from the value array since the legacy code above also does it this way
parameters.put(key, ArrayUtils.isEmpty(values) ? null : values[values.length-1]);
}
}
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();
}
/**
* Sets response headers that prevent caching (code taken from {@link AuthServlet}).
*
* @param resp
* The HttpServletResponse.
*/
public void setNoCachingHeaders(HttpServletResponse resp) {
resp.setHeader(HEADER_EXPIRES, HEADER_VALUE_EXPIRES);
resp.setHeader(HEADER_PRAGMA, HEADER_VALUE_PRAGMA);
resp.setHeader(HEADER_CACHE_CONTROL, HEADER_VALUE_CACHE_CONTROL);
resp.addHeader(HEADER_CACHE_CONTROL, 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
+ "*" });
}
}