Základní implementace podepisování PDF dokumentů. Podpis implementován pouze pro sestavu schválení služební cesty (natvrdo v kódu). Spouští se univerzální podepisovací aplikace, která čte certifikát ze souboru.
closes #224
This commit is contained in:
@@ -168,4 +168,7 @@ public class Constants {
|
||||
public final static int LEN_TEXT = 255;
|
||||
public final static int LEN_DESCRIPTION = 8192;
|
||||
public final static int LEN_RESULT_MESSAGE = 8192;
|
||||
|
||||
public final static String KEY_SIGN_DATA = "SIGN_DATA";
|
||||
public final static String KEY_SIGN_GUID = "SIGN_GUID";
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import info.bukova.isspst.data.User;
|
||||
import info.bukova.isspst.data.Workgroup;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -13,16 +14,18 @@ public class SessionData implements Serializable {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -764426911263559758L;
|
||||
private static final long serialVersionUID = -764426911263559759L;
|
||||
|
||||
private List<Workgroup> userCentres;
|
||||
private List<Workgroup> userWorkgroups;
|
||||
private User currentUser;
|
||||
private Map<Integer, List<Role>> workgroupRoles;
|
||||
private boolean loginFailed;
|
||||
|
||||
private Map<String, Object> properties;
|
||||
|
||||
public SessionData() {
|
||||
loginFailed = false;
|
||||
properties = new HashMap<String, Object>();
|
||||
}
|
||||
|
||||
public List<Workgroup> getUserCentres() {
|
||||
@@ -65,4 +68,11 @@ public class SessionData implements Serializable {
|
||||
this.loginFailed = loginFailed;
|
||||
}
|
||||
|
||||
public void setProperty(String key, Object value) {
|
||||
properties.put(key, value);
|
||||
}
|
||||
|
||||
public Object getProperty(String key) {
|
||||
return properties.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package info.bukova.isspst.reporting;
|
||||
|
||||
import com.lowagie.text.Rectangle;
|
||||
import com.lowagie.text.pdf.PdfAnnotation;
|
||||
import com.lowagie.text.pdf.PdfFormField;
|
||||
import com.lowagie.text.pdf.PdfName;
|
||||
import net.sf.jasperreports.engine.JRGenericPrintElement;
|
||||
import net.sf.jasperreports.engine.JRPropertiesMap;
|
||||
import net.sf.jasperreports.engine.export.GenericElementHandler;
|
||||
import net.sf.jasperreports.engine.export.GenericElementHandlerBundle;
|
||||
import net.sf.jasperreports.engine.export.GenericElementPdfHandler;
|
||||
import net.sf.jasperreports.engine.export.JRPdfExporter;
|
||||
import net.sf.jasperreports.engine.export.JRPdfExporterContext;
|
||||
import net.sf.jasperreports.extensions.ExtensionsRegistry;
|
||||
import net.sf.jasperreports.extensions.ExtensionsRegistryFactory;
|
||||
import net.sf.jasperreports.extensions.SingletonExtensionRegistry;
|
||||
|
||||
/**
|
||||
* @author Pepa Rokos
|
||||
*/
|
||||
public class SignaturePdfHandler implements GenericElementPdfHandler, GenericElementHandlerBundle, ExtensionsRegistryFactory {
|
||||
|
||||
@Override
|
||||
public ExtensionsRegistry createRegistry(String registryId, JRPropertiesMap properties) {
|
||||
return new SingletonExtensionRegistry<GenericElementHandlerBundle>(GenericElementHandlerBundle.class, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportElement(JRPdfExporterContext exporterContext, JRGenericPrintElement element) {
|
||||
PdfFormField field = PdfFormField.createSignature(exporterContext.getPdfWriter());
|
||||
field.setFieldName("signature");
|
||||
field.setFieldFlags(PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_LOCKED);
|
||||
field.setWidget(new Rectangle(element.getX(), element.getY(), element.getX() + element.getWidth(), element.getY() + element.getHeight()), PdfName.HIGHLIGHT);
|
||||
exporterContext.getPdfWriter().addAnnotation(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean toExport(JRGenericPrintElement element) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNamespace() {
|
||||
return "urn:sig:sig";
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericElementHandler getHandler(String elementName, String exporterKey) {
|
||||
if (elementName.equals("signature") && exporterKey.equals(JRPdfExporter.PDF_EXPORTER_KEY)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package info.bukova.isspst.signapi;
|
||||
|
||||
/**
|
||||
* @author Pepa Rokos
|
||||
*/
|
||||
public interface JnlpGenerator {
|
||||
|
||||
public byte[] generate();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package info.bukova.isspst.signapi;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* @author Pepa Rokos
|
||||
*/
|
||||
public class JnlpGeneratorImpl implements JnlpGenerator {
|
||||
|
||||
@Autowired
|
||||
private HttpServletRequest request;
|
||||
|
||||
@Override
|
||||
public byte[] generate() {
|
||||
String sessionId;
|
||||
|
||||
if (request.getParameter("id") != null && !request.getParameter("id").isEmpty()) {
|
||||
sessionId = request.getParameter("id");
|
||||
} else {
|
||||
sessionId = request.getSession().getId();
|
||||
}
|
||||
|
||||
try {
|
||||
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
|
||||
|
||||
Document document = docBuilder.newDocument();
|
||||
Element root = document.createElement("jnlp");
|
||||
root.setAttribute("spec", "1.0+");
|
||||
|
||||
String signerUrl = request.getRequestURL().toString();
|
||||
signerUrl = signerUrl.substring(0, signerUrl.indexOf(request.getServletPath())) + "/api/sign";
|
||||
|
||||
root.setAttribute("codebase", signerUrl);
|
||||
root.setAttribute("href", "signer.jnlp" + "?id=" + sessionId);
|
||||
document.appendChild(root);
|
||||
|
||||
Element info = document.createElement("information");
|
||||
Element title = document.createElement("title");
|
||||
title.appendChild(document.createTextNode("Signer component"));
|
||||
info.appendChild(title);
|
||||
Element vendor = document.createElement("vendor");
|
||||
vendor.appendChild(document.createTextNode("bukova.info"));
|
||||
info.appendChild(vendor);
|
||||
root.appendChild(info);
|
||||
|
||||
Element security = document.createElement("security");
|
||||
security.appendChild(document.createElement("all-permissions"));
|
||||
root.appendChild(security);
|
||||
|
||||
Element resources = document.createElement("resources");
|
||||
Element j2se = document.createElement("j2se");
|
||||
j2se.setAttribute("version", "1.8+");
|
||||
Element jar = document.createElement("jar");
|
||||
jar.setAttribute("href", "pdfsigner.jar");
|
||||
resources.appendChild(j2se);
|
||||
resources.appendChild(jar);
|
||||
root.appendChild(resources);
|
||||
|
||||
Element appDesc = document.createElement("application-desc");
|
||||
appDesc.setAttribute("main-class", "info.bukova.pdfsigner.Main");
|
||||
Element argUrl = document.createElement("argument");
|
||||
argUrl.appendChild(document.createTextNode(signerUrl + "/data"));
|
||||
appDesc.appendChild(argUrl);
|
||||
Element argSession = document.createElement("argument");
|
||||
argSession.appendChild(document.createTextNode(sessionId));
|
||||
appDesc.appendChild(argSession);
|
||||
root.appendChild(appDesc);
|
||||
|
||||
|
||||
System.out.println(signerUrl);
|
||||
System.out.println(request.getSession().getId());
|
||||
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
DOMSource source = new DOMSource(document);
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
StreamResult result = new StreamResult(bos);
|
||||
|
||||
transformer.transform(source, result);
|
||||
|
||||
return bos.toByteArray();
|
||||
|
||||
} catch (ParserConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (TransformerConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (TransformerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package info.bukova.isspst.signapi;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Pepa Rokos
|
||||
*/
|
||||
public class SignData implements Serializable {
|
||||
|
||||
private byte[] pdfData;
|
||||
private byte[] signImg;
|
||||
private int areaId;
|
||||
private Date signDate;
|
||||
private String description;
|
||||
private String numser;
|
||||
private boolean signed;
|
||||
private String signGuid;
|
||||
private boolean signSuccess;
|
||||
|
||||
public byte[] getPdfData() {
|
||||
return pdfData;
|
||||
}
|
||||
|
||||
public void setPdfData(byte[] pdfData) {
|
||||
this.pdfData = pdfData;
|
||||
}
|
||||
|
||||
public Date getSignDate() {
|
||||
return signDate;
|
||||
}
|
||||
|
||||
public void setSignDate(Date signDate) {
|
||||
this.signDate = signDate;
|
||||
}
|
||||
|
||||
public String getNumser() {
|
||||
return numser;
|
||||
}
|
||||
|
||||
public void setNumser(String numser) {
|
||||
this.numser = numser;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public boolean isSigned() {
|
||||
return signed;
|
||||
}
|
||||
|
||||
public void setSigned(boolean signed) {
|
||||
this.signed = signed;
|
||||
}
|
||||
|
||||
public String getSignGuid() {
|
||||
return signGuid;
|
||||
}
|
||||
|
||||
public void setSignGuid(String signGuid) {
|
||||
this.signGuid = signGuid;
|
||||
}
|
||||
|
||||
public boolean isSignSuccess() {
|
||||
return signSuccess;
|
||||
}
|
||||
|
||||
public void setSignSuccess(boolean signSuccess) {
|
||||
this.signSuccess = signSuccess;
|
||||
}
|
||||
|
||||
public byte[] getSignImg() {
|
||||
return signImg;
|
||||
}
|
||||
|
||||
public void setSignImg(byte[] signImg) {
|
||||
this.signImg = signImg;
|
||||
}
|
||||
|
||||
public int getAreaId() {
|
||||
return areaId;
|
||||
}
|
||||
|
||||
public void setAreaId(int areaId) {
|
||||
this.areaId = areaId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package info.bukova.isspst.signapi;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Pepa Rokos
|
||||
*/
|
||||
public class SignUploadResponse implements Serializable {
|
||||
|
||||
private boolean ok;
|
||||
private String errorMessage;
|
||||
|
||||
public boolean isOk() {
|
||||
return ok;
|
||||
}
|
||||
|
||||
public void setOk(boolean ok) {
|
||||
this.ok = ok;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
public void setErrorMessage(String errorMessage) {
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package info.bukova.isspst.signapi;
|
||||
|
||||
import info.bukova.isspst.Constants;
|
||||
import info.bukova.isspst.SessionData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
|
||||
/**
|
||||
* @author Pepa Rokos
|
||||
*/
|
||||
|
||||
@Controller
|
||||
public class SigningController {
|
||||
|
||||
@Autowired
|
||||
private SessionData sessionData;
|
||||
@Autowired
|
||||
private JnlpGenerator jnlpGenerator;
|
||||
@Autowired
|
||||
private ServletContext context;
|
||||
|
||||
@RequestMapping(value="/sign/data", method= RequestMethod.GET)
|
||||
public void dataForSign(HttpServletResponse response, HttpServletRequest request) {
|
||||
SignData data = (SignData) sessionData.getProperty(Constants.KEY_SIGN_DATA);
|
||||
ObjectOutputStream os = null;
|
||||
|
||||
try {
|
||||
os = new ObjectOutputStream(response.getOutputStream());
|
||||
response.setContentType("application/x-java-serialized-object");
|
||||
os.writeObject(data);
|
||||
os.flush();
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (os != null) {
|
||||
try {
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RequestMapping(value="/sign/data", method= RequestMethod.POST)
|
||||
public void signedData(HttpServletRequest request, HttpServletResponse response) {
|
||||
ObjectInputStream ois = null;
|
||||
ObjectOutputStream os = null;
|
||||
String error = null;
|
||||
|
||||
try {
|
||||
ois = new ObjectInputStream(request.getInputStream());
|
||||
SignData data = (SignData) ois.readObject();
|
||||
sessionData.setProperty(Constants.KEY_SIGN_DATA, data);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
error = "IO error";
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
error = "Loading error";
|
||||
}
|
||||
|
||||
try {
|
||||
SignUploadResponse resp = new SignUploadResponse();
|
||||
|
||||
if (error == null) {
|
||||
resp.setOk(true);
|
||||
} else {
|
||||
resp.setOk(false);
|
||||
resp.setErrorMessage(error);
|
||||
}
|
||||
|
||||
os = new ObjectOutputStream(response.getOutputStream());
|
||||
response.setContentType("application/x-java-serialized-object");
|
||||
os.writeObject(resp);
|
||||
os.flush();
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value="/sign/signer.jnlp", method= RequestMethod.GET)
|
||||
public void jnlp(HttpServletResponse response) {
|
||||
byte[] data = jnlpGenerator.generate();
|
||||
sendByte(response, data, "application/x-java-jnlp-file");
|
||||
}
|
||||
|
||||
@RequestMapping(value="/sign/pdfsigner.jar", method= RequestMethod.GET)
|
||||
public void pdfsigner(HttpServletResponse response) {
|
||||
File inputJar = new File(context.getRealPath("/WEB-INF/signer/PDFSigner.jar"));
|
||||
|
||||
try {
|
||||
byte[] data = new byte[(int) inputJar.length()];
|
||||
FileInputStream is = new FileInputStream(inputJar);
|
||||
is.read(data);
|
||||
sendByte(response, data, "application/java-archive");
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void sendByte(HttpServletResponse response, byte[] data, String contentType) {
|
||||
ServletOutputStream os = null;
|
||||
|
||||
try {
|
||||
os = response.getOutputStream();
|
||||
response.setContentType(contentType);
|
||||
response.setContentLength(data.length);
|
||||
os.write(data);
|
||||
os.flush();
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +1,32 @@
|
||||
package info.bukova.isspst.ui.main;
|
||||
|
||||
import info.bukova.isspst.Constants;
|
||||
import info.bukova.isspst.SessionData;
|
||||
import info.bukova.isspst.StringUtils;
|
||||
import info.bukova.isspst.data.RequirementBase;
|
||||
import info.bukova.isspst.reporting.Generator;
|
||||
import info.bukova.isspst.reporting.GeneratorFactory;
|
||||
import info.bukova.isspst.reporting.ParamFiller;
|
||||
import info.bukova.isspst.reporting.Report;
|
||||
import info.bukova.isspst.reporting.ReportDefinition;
|
||||
import info.bukova.isspst.services.Service;
|
||||
import info.bukova.isspst.services.requirement.ApproveException;
|
||||
import info.bukova.isspst.services.requirement.RequirementBaseService;
|
||||
import info.bukova.isspst.signapi.SignData;
|
||||
import info.bukova.isspst.ui.ListViewModel;
|
||||
import org.zkoss.bind.BindUtils;
|
||||
import org.zkoss.bind.annotation.BindingParam;
|
||||
import org.zkoss.bind.annotation.Command;
|
||||
import org.zkoss.bind.annotation.ExecutionArgParam;
|
||||
import org.zkoss.bind.annotation.Init;
|
||||
import org.zkoss.bind.annotation.NotifyChange;
|
||||
import org.zkoss.zk.ui.Executions;
|
||||
import org.zkoss.zk.ui.select.annotation.WireVariable;
|
||||
import org.zkoss.zul.Messagebox;
|
||||
import org.zkoss.zul.Window;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Pepa Rokos
|
||||
@@ -24,6 +37,16 @@ public class ApproveDialogVM {
|
||||
private RequirementBase requirement;
|
||||
private ListViewModel grid;
|
||||
private Date approveDate;
|
||||
@WireVariable
|
||||
private SessionData sessionData;
|
||||
@WireVariable
|
||||
private ReportDefinition reportDefinition;
|
||||
@WireVariable
|
||||
private GeneratorFactory genFactory;
|
||||
@WireVariable
|
||||
private ParamFiller paramFiller;
|
||||
private boolean signed;
|
||||
private boolean timer;
|
||||
|
||||
public Date getApproveDate() {
|
||||
return approveDate;
|
||||
@@ -41,6 +64,9 @@ public class ApproveDialogVM {
|
||||
this.requirement = requirement;
|
||||
this.grid = grid;
|
||||
this.approveDate = new Date();
|
||||
|
||||
this.signed = false;
|
||||
this.timer = false;
|
||||
}
|
||||
|
||||
@Command
|
||||
@@ -57,4 +83,51 @@ public class ApproveDialogVM {
|
||||
}
|
||||
}
|
||||
|
||||
@Command
|
||||
@NotifyChange("timer")
|
||||
public void signPdf() {
|
||||
SignData data = new SignData();
|
||||
sessionData.setProperty(Constants.KEY_SIGN_DATA, data);
|
||||
data.setSignGuid(UUID.randomUUID().toString());
|
||||
sessionData.setProperty(Constants.KEY_SIGN_GUID, data.getSignGuid());
|
||||
|
||||
// ToDo: Generovat report
|
||||
reportDefinition.clear();
|
||||
reportDefinition.setSingleObject(requirement);
|
||||
reportDefinition.setReport(new Report(0, true, "", "tripRequirementApp", false, true, true));
|
||||
reportDefinition.setService((Service) service);
|
||||
|
||||
paramFiller.fill();
|
||||
Generator gen = genFactory.createGenerator(reportDefinition);
|
||||
data.setPdfData(gen.generate());
|
||||
data.setDescription(requirement.getDescription());
|
||||
data.setNumser(requirement.getNumser());
|
||||
|
||||
timer = true;
|
||||
|
||||
Executions.getCurrent().sendRedirect("/api/sign/signer.jnlp", "signer");
|
||||
}
|
||||
|
||||
@Command
|
||||
@NotifyChange({"signed", "timer"})
|
||||
public void onTimer() {
|
||||
String guid = (String) sessionData.getProperty(Constants.KEY_SIGN_GUID);
|
||||
SignData data = (SignData) sessionData.getProperty(Constants.KEY_SIGN_DATA);
|
||||
|
||||
if (guid.equals(data.getSignGuid()) && data.isSignSuccess()) {
|
||||
signed = true;
|
||||
timer = false;
|
||||
} else {
|
||||
signed = false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSigned() {
|
||||
return signed;
|
||||
}
|
||||
|
||||
public boolean isTimer() {
|
||||
return timer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user