/**
* Copyright 2006 by Know-Center, Graz, Austria
* PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a
* joint initiative of the Federal Chancellery Austria 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.egiz.pdfas.web.servlets;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
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.logging.Log;
import org.apache.commons.logging.LogFactory;
import at.gv.egiz.pdfas.api.PdfAs;
import at.gv.egiz.pdfas.api.commons.Constants;
import at.gv.egiz.pdfas.api.commons.SignatureInformation;
import at.gv.egiz.pdfas.api.exceptions.PdfAsException;
import at.gv.egiz.pdfas.api.internal.LocalBKUParams;
import at.gv.egiz.pdfas.api.internal.PdfAsInternal;
import at.gv.egiz.pdfas.api.verify.VerifyResult;
import at.gv.egiz.pdfas.api.verify.VerifyResults;
import at.gv.egiz.pdfas.web.LocalRequest;
import at.gv.egiz.pdfas.web.helper.ApiHelper;
import at.gv.egiz.pdfas.web.helper.LocalRequestHelper;
import at.gv.egiz.pdfas.web.helper.SessionHelper;
import at.gv.egiz.pdfas.web.helper.SignServletHelper;
import at.gv.egiz.pdfas.web.helper.SigningTimeHelper;
import at.gv.egiz.pdfas.web.session.SessionAttributes;
import at.gv.egiz.pdfas.web.session.SignSessionInformation;
import at.gv.egiz.pdfas.web.session.VerifySessionInformation;
import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException;
import at.knowcenter.wag.egov.egiz.exceptions.SignatureException;
/**
* @author wprinz
*
*/
public class DataURLServlet extends HttpServlet
{
/**
* SVUID.
*/
private static final long serialVersionUID = -5846618335843762752L;
/**
* The log.
*/
private static Log log = LogFactory.getLog(DataURLServlet.class);
protected void dispatch(HttpServletRequest request,
HttpServletResponse response, String resource) throws ServletException, IOException
{
dispatch(request, response, resource, getServletContext());
}
protected static void dispatch(HttpServletRequest request,
HttpServletResponse response, String resource, ServletContext context) throws ServletException, IOException
{
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
RequestDispatcher disp = context.getRequestDispatcher(resource);
disp.forward(request, response);
}
protected void dispatchToResults(VerifyResults results, HttpServletRequest request,
HttpServletResponse response, String backToListURL) throws ServletException, IOException
{
request.setAttribute("results", results);
request.setAttribute("btlurl", backToListURL);
dispatch(request, response, "/jsp/results.jsp");
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
private static void temporaryRedirect(String redirectURL, HttpServletResponse response) throws IOException {
String encodedRedirect = response.encodeRedirectURL(redirectURL);
response.addHeader("Location", encodedRedirect);
response.setContentType("text/xml");
response.setStatus(HttpServletResponse.SC_TEMPORARY_REDIRECT);
String nop = "";
PrintWriter pw = response.getWriter();
response.setCharacterEncoding("UTF-8");
response.setContentLength(nop.getBytes("UTF-8").length);
log.debug("Redirecting via NullOperationRequest to " + encodedRedirect + ".");
pw.println(nop);
pw.flush();
pw.close();
}
/**
* @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
log.debug("Data URL is accessed."); //$NON-NLS-1$
try
{
Object sessionObject = SessionHelper.getSession(request);
// obsolete since EncodingFilter is set in web.xml
checkRequestCharacterEncoding(request);
if (sessionObject instanceof SignSessionInformation)
{
SignSessionInformation si = (SignSessionInformation)sessionObject;
processSign(request, response, si);
}
else
{
VerifySessionInformation si = (VerifySessionInformation) sessionObject;
processVerify(request, response, si);
}
}
catch (PdfAsException e)
{
log.error(e.getMessage(), e);
SignServlet.prepareDispatchToErrorPage(e, request);
dispatch(request, response, "/jsp/error.jsp");
}
log.debug("DataURL access finished."); //$NON-NLS-1$
}
protected void checkRequestCharacterEncoding(HttpServletRequest request) throws UnsupportedEncodingException
{
if (request.getCharacterEncoding() == null || request.getCharacterEncoding().length() <= 0) //$NON-NLS-1$
{
log.info("The BKU didn't set a character encoding for the request."); //$NON-NLS-1$
log.info("Manually setting character encoding to UTF-8"); //$NON-NLS-1$
request.setCharacterEncoding("UTF-8"); //$NON-NLS-1$
}
}
protected boolean isNullResponse(String xml_response)
{
return xml_response != null && xml_response.indexOf("NullOperationResponse") != -1;
}
private static String retrieveXMLResponse(HttpServletRequest request) throws ServletException {
log.debug("Trying to fetch XMLResponse...");
String xml_response = null;
if (ServletFileUpload.isMultipartContent(request)) {
log.debug("Response is multipart.");
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
try {
List items = upload.parseRequest(request);
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (item.isFormField() && "XMLResponse".equals(item.getFieldName())) {
log.debug("XMLResponse part found.");
xml_response = item.getString();
break;
}
}
} catch (FileUploadException e) {
throw new ServletException(e);
}
} else {
xml_response = request.getParameter("XMLResponse");
}
log.debug("XMLResponse = " + xml_response);
return xml_response;
}
protected void processSign(HttpServletRequest request, HttpServletResponse response, SignSessionInformation si) throws ServletException, IOException, PdfAsException
{
log.trace("processSign");
String xml_response = retrieveXMLResponse(request);
PdfAsInternal pdfAsInternal = ApiHelper.getPdfAsInternalFromContext(getServletContext());
String server = request.getHeader("server");
String userAgent = request.getHeader("user-agent");
String signatureLayout = request.getHeader(Constants.BKU_HEADER_SIGNATURE_LAYOUT);
LocalBKUParams bkuParams = new LocalBKUParams(server, userAgent, signatureLayout);
si.localBKUParams = bkuParams;
pdfAsInternal.verifyBKUSupport(bkuParams);
if (isNullResponse(xml_response))
{
log.debug("Received a NullOperationResponse -> answering with the first request."); //$NON-NLS-1$
assert si.outputAvailable == false;
assert si.xmlResponse == null;
log.debug("There are still requests to be performed -> answering with request."); //$NON-NLS-1$
LocalRequest local_request = si.localRequest;
String request_string = local_request.getRequestString();
log.debug("request = " + request_string);
response.setContentType("text/xml");
response.setCharacterEncoding("UTF-8");
response.getWriter().println(request_string);
}
else if (xml_response != null)
{
log.debug("Received a normal response -> storing the response."); //$NON-NLS-1$
si.xmlResponse = xml_response;
log.debug("All requests have been processed -> processing the responses."); //$NON-NLS-1$
// Sign
if (!si.outputAvailable)
{
PdfAs pdfAs = ApiHelper.getPdfAsFromContext(getServletContext());
SignServletHelper.finishLocalSign(pdfAs, pdfAsInternal, si);
SigningTimeHelper.checkSigningTimeAgainstHostTime(si.sdi.getSignDate());
si.outputAvailable = true;
}
if (si.output.getMimeType().equals("text/xml") && si.outputAvailable)
{
// For "detached" signatures, the return value (data sink) is the response xml,
// but when passed through the BKU it is interpreted as another request
// which will generate a return code 1501
// Then PDF-AS would answer with the response as well generating
// another 1501 and so forth.
// Therefor return it as TXT.
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
response.getWriter().println("Das detached XML kann nicht direkt durch die BKU geschliffen werden, weil diese es als Request interpretieren würde. Daher das XML als Text:");
response.getWriter().println(new String(si.signedPdf, "UTF-8"));
}
else
{
// tzefferer: If PDF-AS has been called by an external web-application, we do not
// redirect to download.jsp but return the sign-response immediately
if (si.exappinf != null) {
log.debug("Entering external application interface mode. Skipping redirection to download page.");
SignServletHelper.returnSignResponse(si, request, response);
// Not needed due to redirection of returnSignResponse.
// Just to clarify that there must not be any code after returnSignResponse.
return;
} else {
log.debug("Preparing download page.");
HttpSession session = request.getSession(true);
log.debug("Putting signed document into session (" + session.getId() + ").");
session.setAttribute(SessionAttributes.SIGNED_PDF_DOCUMENT, si);
String downloadURL = response.encodeRedirectURL(LocalRequestHelper.getLocalContextAddress(request, response) + "/ProvidePDF");
log.debug("Creating download URL \"" + downloadURL + "\".");
session.setAttribute(SessionAttributes.DOWNLOAD_URL_FOR_SIGNED_PDF_DOCUMENT, downloadURL);
temporaryRedirect(response.encodeRedirectURL(LocalRequestHelper.getLocalContextAddress(request, response) + "/jsp/download.jsp") , response);
// Not needed due to temporaryRedirect.
// Just to clarify that there must not be any code after temporaryRedirect.
return;
}
// do not insert any code within this else block !
}
} else {
log.debug("No XMLResponse found. Do nothing.");
}
}
protected void processVerify(HttpServletRequest request, HttpServletResponse response, VerifySessionInformation si) throws ServletException, IOException, ConnectorException, SignatureException
{
log.trace("processVerify");
String xml_response = request.getParameter("XMLResponse"); //$NON-NLS-1$
log.debug("xml_response = " + xml_response); //$NON-NLS-1$
if (isNullResponse(xml_response))
{
log.debug("Received a NullOperationResponse -> answering with the first request."); //$NON-NLS-1$
assert si.currentLocalOperation.current_operation == 0;
}
else
{
log.debug("Recieved a normal response -> storing the response."); //$NON-NLS-1$
si.currentLocalOperation.finishCurrentOperation(xml_response);
}
if (!si.currentLocalOperation.isFinished())
{
log.debug("There are still requests to be performed -> answering with request #" + si.currentLocalOperation.current_operation); //$NON-NLS-1$
LocalRequest local_request = si.currentLocalOperation.getCurrentLocalRequest();
String request_string = local_request.getRequestString();
response.setContentType("text/xml");
response.setCharacterEncoding("UTF-8");
response.getWriter().println(request_string);
}
else
{
log.debug("All requests have been processed -> processing the responses."); //$NON-NLS-1$
PdfAsInternal pdfAsInternal = ApiHelper.getPdfAsInternalFromContext(getServletContext());
final ArrayList resList = new ArrayList();
for (int i = 0; i < si.currentLocalOperation.response_xmls.length; i++)
{
SignatureInformation sigInfo = (SignatureInformation) si.currentLocalOperation.signaturesToBeverified.get(i);
VerifyResult result = pdfAsInternal.finishLocalVerify(sigInfo, si.connector, si.type, "loc ref content not needed here", si.currentLocalOperation.response_xmls[i]);
resList.add(result);
}
si.currentLocalOperation = null;
URL btlURL = new URL(LocalRequestHelper.getLocalContextAddress(request, response) + "/jsp/verifylist.jsp");
String backToListURL = response.encodeURL(btlURL.toString());
VerifyResults results = new VerifyResults() {
public List getResults() {
return resList;
}
};
dispatchToResults(results, request, response, backToListURL);
}
}
}