/* * This action receives the form submission from the page for the final step of the signature process. We'll call * REST PKI to complete the signature. */ @RequestMapping( value = "/xml-signature-complete", method = {RequestMethod.POST}) public String complete( @RequestParam(value = "token", required = true) String token, @RequestParam(value = "signature", required = true) String signature, Model model) throws IOException, RestException { // Instantiate the FullXmlSignatureFinisher class, responsible for completing the signature // process. For more // information, see: // https://pki.rest/Content/docs/java-client/index.html?com/lacunasoftware/restpki/XmlSignatureFinisher.html XmlSignatureFinisher signatureFinisher = new XmlSignatureFinisher(Util.getRestPkiClient()); // Set the token for this signature (rendered in a hidden input field, see file // templates/xml-full-signature.html) signatureFinisher.setToken(token); // Set the result of the signature operation signatureFinisher.setSignature(signature); // Call the finish() method, which finalizes the signature process and returns the signed XML's // bytes byte[] signedXml; try { signedXml = signatureFinisher.finish(); } catch (ValidationException e) { // The call above may throw a ValidationException if any validation errors occur (for // instance, if the // certificate is revoked). If so, we'll render a page showing what went wrong. model.addAttribute("title", "Validation of the signature failed"); // The toString() method of the ValidationResults object can be used to obtain the checks // performed, but the // string contains tabs and new line characters for formatting. Therefore, we call the method // Util.getValidationResultsHtml() to convert these characters to <br>'s and 's. model.addAttribute("vrHtml", Util.getValidationResultsHtml(e.getValidationResults())); return "validation-failed"; } // Get information about the certificate used by the user to sign the file. This method must // only be called after // calling the finish() method. PKCertificate signerCert = signatureFinisher.getCertificateInfo(); // At this point, you'd typically store the signed XML on your database. For demonstration // purposes, we'll // store the XML on a temporary folder and return to the page an identifier that can be used to // download it. String filename = UUID.randomUUID() + ".xml"; Files.write(Application.getTempFolderPath().resolve(filename), signedXml); model.addAttribute("signerCert", signerCert); model.addAttribute("filename", filename); return "xml-signature-info"; }
/* * This action receives the encoding of the certificate chosen by the user, uses it to initiate a XML signature * using REST PKI and renders the page for the final step of the signature process. */ @RequestMapping( value = "/xml-full-signature", method = {RequestMethod.POST}) public String postFull( @RequestParam(value = "selectedCertThumb", required = true) String selectedCertThumb, @RequestParam(value = "certificate", required = true) String certificate, Model model, HttpServletResponse response) throws IOException, RestException { // Instantiate the FullXmlSignatureStarter class, responsible for receiving the signature // elements and start the // signature process. For more information, see: // https://pki.rest/Content/docs/java-client/index.html?com/lacunasoftware/restpki/FullXmlSignatureStarter.html FullXmlSignatureStarter signatureStarter = new FullXmlSignatureStarter(Util.getRestPkiClient()); // Set the XML to be signed, a sample XML Document signatureStarter.setXml(Util.getSampleXml()); // Set the location on which to insert the signature node. If the location is not specified, the // signature will appended // to the root element (which is most usual with enveloped signatures). XmlNamespaceManager nsm = new XmlNamespaceManager(); nsm.addNamespace("ls", "http://www.lacunasoftware.com/sample"); signatureStarter.setSignatureElementLocation( "//ls:signaturePlaceholder", nsm, XmlInsertionOptions.AppendChild); // Set the certificate's encoding in base64 encoding (which is what the Web PKI component // yields) signatureStarter.setSignerCertificate(certificate); // Set the signature policy signatureStarter.setSignaturePolicy(SignaturePolicy.XadesBasic); // Set a SecurityContext to be used to determine trust in the certificate chain signatureStarter.setSecurityContext(SecurityContext.pkiBrazil); // Note: By changing the SecurityContext above you can accept only certificates from a certain // PKI, // for instance, ICP-Brasil (SecurityContext.pkiBrazil). // Call the start() method, which initiates the signature on REST PKI. This yields the // parameters for the // client-side signature, which we'll use to render the page for the final step, where the // actual signature will // be performed. ClientSideSignatureInstructions signatureInstructions; try { signatureInstructions = signatureStarter.start(); } catch (ValidationException e) { // The call above may throw a ValidationException if the certificate fails the initial // validations (for // instance, if it is expired). If so, we'll render a page showing what went wrong. model.addAttribute("title", "Validation of the certificate failed"); // The toString() method of the ValidationResults object can be used to obtain the checks // performed, but the // string contains tabs and new line characters for formatting. Therefore, we call the method // Util.getValidationResultsHtml() to convert these characters to <br>'s and 's. model.addAttribute("vrHtml", Util.getValidationResultsHtml(e.getValidationResults())); String retryUrl = "/xml-full-signature"; model.addAttribute("retryUrl", retryUrl); return "validation-failed"; } // Among the data returned by the start() method is the token, a string which identifies this // signature process. // This token can only be used for a single signature attempt. In order to retry the signature // it is // necessary to get a new token. This can be a problem if the user uses the back button of the // browser, since the // browser might show a cached page that we rendered previously, with a now stale token. To // prevent this from // happening, we call the method Util.setNoCacheHeaders(), which sets HTTP headers to prevent // caching of the page. Util.setNoCacheHeaders(response); // Render the page for the final step of the signature process, on which the actual signature // will be performed // (templates/xml-full-signature-step2.html) model.addAttribute("selectedCertThumb", selectedCertThumb); model.addAttribute("token", signatureInstructions.getToken()); model.addAttribute("toSignHash", signatureInstructions.getToSignHash()); model.addAttribute("digestAlg", signatureInstructions.getDigestAlgorithmOid()); return "xml-full-signature-step2"; }