- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
正如 Adobe 文章 "Digital Signatures in a PDF" 所述:
PDF defines two types of signatures: approval and certification. The differences are as follows: Approval: There can be any number of approval signatures in a document. The field may optionally be associated with FieldMDP permissions. Certification: There can be only one certification signature and it must be the first one in a document. The field is always associated with DocMDP.
使用 PDFBox 示例,我能够成功地将多个签名应用于我的文档:https://github.com/apache/pdfbox/blob/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java为了应用多个签名,我只是使用不同的签名占位符和图像多次运行相同的代码。
但我的区别在于,即使我运行相同的代码,它也总是将第一个签名设置为已认证,而所有其他签名都设置为批准。
但在我的例子中,我不希望文件得到认证,我只需要所有签名都是 Apploval 类型,包括第一个。我知道我可以先不可见地验证签名,但我仍然根本不想验证文件。
我试图找到一种设置签名的方法,但无法弄清楚。
下面是我使用的示例代码(其他类在上面的 GitHub 链接中):
public class SignnerPDFBoxExample extends CreateSignatureBase {
private SignatureOptions signatureOptions;
private PDVisibleSignDesigner visibleSignDesigner;
private final PDVisibleSigProperties visibleSignatureProperties = new PDVisibleSigProperties();
private boolean lateExternalSigning = false;
public static void main(String[] args) throws Exception {
File ksFile = new File("keystore.jks");
KeyStore keystore = KeyStore.getInstance("JKS");
char[] pin = "123456".toCharArray();
keystore.load(new FileInputStream(ksFile), pin);
SignnerPDFBoxExample signer = new SignnerPDFBoxExample(keystore, pin.clone());
String inputFilename = "Four_Signature_template.pdf";
File documentFile = new File(inputFilename);
File signedDocumentFile;
int page = 1;
try (FileInputStream imageStream = new FileInputStream("client_signature.jpg"))
{
String name = documentFile.getName();
String substring = name.substring(0, name.lastIndexOf('.'));
signedDocumentFile = new File(documentFile.getParent(), substring + "_signed.pdf");
// page is 1-based here
signer.setVisibleSignDesigner(inputFilename, 0, 0, -50, imageStream, page);
}
signer.setVisibleSignatureProperties("name", "location", "Signed using PDFBox", 0, page, true);
signer.signPDF(documentFile, signedDocumentFile, null, "certifySignature");
}
public boolean isLateExternalSigning()
{
return lateExternalSigning;
}
/**
* Set late external signing. Enable this if you want to activate the demo code where the
* signature is kept and added in an extra step without using PDFBox methods. This is disabled
* by default.
*
* @param lateExternalSigning
*/
public void setLateExternalSigning(boolean lateExternalSigning)
{
this.lateExternalSigning = lateExternalSigning;
}
/**
* Set visible signature designer for a new signature field.
*
* @param filename
* @param x position of the signature field
* @param y position of the signature field
* @param zoomPercent
* @param imageStream
* @param page the signature should be placed on
* @throws IOException
*/
public void setVisibleSignDesigner(String filename, int x, int y, int zoomPercent,
FileInputStream imageStream, int page)
throws IOException
{
visibleSignDesigner = new PDVisibleSignDesigner(filename, imageStream, page);
visibleSignDesigner.xAxis(x).yAxis(y).zoom(zoomPercent).adjustForRotation();
}
/**
* Set visible signature designer for an existing signature field.
*
* @param zoomPercent
* @param imageStream
* @throws IOException
*/
public void setVisibleSignDesigner(int zoomPercent, FileInputStream imageStream)
throws IOException
{
visibleSignDesigner = new PDVisibleSignDesigner(imageStream);
visibleSignDesigner.zoom(zoomPercent);
}
/**
* Set visible signature properties for new signature fields.
*
* @param name
* @param location
* @param reason
* @param preferredSize
* @param page
* @param visualSignEnabled
* @throws IOException
*/
public void setVisibleSignatureProperties(String name, String location, String reason, int preferredSize,
int page, boolean visualSignEnabled) throws IOException
{
visibleSignatureProperties.signerName(name).signerLocation(location).signatureReason(reason).
preferredSize(preferredSize).page(page).visualSignEnabled(visualSignEnabled).
setPdVisibleSignature(visibleSignDesigner);
}
/**
* Set visible signature properties for existing signature fields.
*
* @param name
* @param location
* @param reason
* @param visualSignEnabled
* @throws IOException
*/
public void setVisibleSignatureProperties(String name, String location, String reason,
boolean visualSignEnabled) throws IOException
{
visibleSignatureProperties.signerName(name).signerLocation(location).signatureReason(reason).
visualSignEnabled(visualSignEnabled).setPdVisibleSignature(visibleSignDesigner);
}
/**
* Initialize the signature creator with a keystore (pkcs12) and pin that
* should be used for the signature.
*
* @param keystore is a pkcs12 keystore.
* @param pin is the pin for the keystore / private key
* @throws KeyStoreException if the keystore has not been initialized (loaded)
* @throws NoSuchAlgorithmException if the algorithm for recovering the key cannot be found
* @throws UnrecoverableKeyException if the given password is wrong
* @throws CertificateException if the certificate is not valid as signing time
* @throws IOException if no certificate could be found
*/
public SignnerPDFBoxExample(KeyStore keystore, char[] pin)
throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, IOException, CertificateException
{
super(keystore, pin);
}
/**
* Sign pdf file and create new file that ends with "_signed.pdf".
*
* @param inputFile The source pdf document file.
* @param signedFile The file to be signed.
* @param tsaClient optional TSA client
* @throws IOException
*/
public void signPDF(File inputFile, File signedFile, TSAClient tsaClient) throws IOException
{
this.signPDF(inputFile, signedFile, tsaClient, null);
}
/**
* Sign pdf file and create new file that ends with "_signed.pdf".
*
* @param inputFile The source pdf document file.
* @param signedFile The file to be signed.
* @param tsaClient optional TSA client
* @param signatureFieldName optional name of an existing (unsigned) signature field
* @throws IOException
*/
public void signPDF(File inputFile, File signedFile, TSAClient tsaClient, String signatureFieldName) throws IOException
{
setTsaClient(tsaClient);
if (inputFile == null || !inputFile.exists())
{
throw new IOException("Document for signing does not exist");
}
// creating output document and prepare the IO streams.
FileOutputStream fos = new FileOutputStream(signedFile);
try (PDDocument doc = PDDocument.load(inputFile))
{
int accessPermissions = SigUtils.getMDPPermission(doc);
if (accessPermissions == 1)
{
throw new IllegalStateException("No changes to the document are permitted due to DocMDP transform parameters dictionary");
}
// Note that PDFBox has a bug that visual signing on certified files with permission 2
// doesn't work properly, see PDFBOX-3699. As long as this issue is open, you may want to
// be careful with such files.
PDSignature signature;
// sign a PDF with an existing empty signature, as created by the CreateEmptySignatureForm example.
signature = findExistingSignature(doc, signatureFieldName);
if (signature == null)
{
// create signature dictionary
signature = new PDSignature();
}
// Optional: certify
// can be done only if version is at least 1.5 and if not already set
// doing this on a PDF/A-1b file fails validation by Adobe preflight (PDFBOX-3821)
// PDF/A-1b requires PDF version 1.4 max, so don't increase the version on such files.
if (doc.getVersion() >= 1.5f && accessPermissions == 0)
{
SigUtils.setMDPPermission(doc, signature, 2);
}
PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
if (acroForm != null && acroForm.getNeedAppearances())
{
// PDFBOX-3738 NeedAppearances true results in visible signature becoming invisible
// with Adobe Reader
if (acroForm.getFields().isEmpty())
{
// we can safely delete it if there are no fields
acroForm.getCOSObject().removeItem(COSName.NEED_APPEARANCES);
// note that if you've set MDP permissions, the removal of this item
// may result in Adobe Reader claiming that the document has been changed.
// and/or that field content won't be displayed properly.
// ==> decide what you prefer and adjust your code accordingly.
}
else
{
System.out.println("/NeedAppearances is set, signature may be ignored by Adobe Reader");
}
}
// default filter
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
// subfilter for basic and PAdES Part 2 signatures
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
if (visibleSignatureProperties != null)
{
// this builds the signature structures in a separate document
visibleSignatureProperties.buildSignature();
signature.setName(visibleSignatureProperties.getSignerName());
signature.setLocation(visibleSignatureProperties.getSignerLocation());
signature.setReason(visibleSignatureProperties.getSignatureReason());
}
// the signing date, needed for valid signature
signature.setSignDate(Calendar.getInstance());
// do not set SignatureInterface instance, if external signing used
SignatureInterface signatureInterface = isExternalSigning() ? null : this;
// register signature dictionary and sign interface
if (visibleSignatureProperties != null && visibleSignatureProperties.isVisualSignEnabled())
{
signatureOptions = new SignatureOptions();
signatureOptions.setVisualSignature(visibleSignatureProperties.getVisibleSignature());
signatureOptions.setPage(visibleSignatureProperties.getPage() - 1);
doc.addSignature(signature, signatureInterface, signatureOptions);
}
else
{
doc.addSignature(signature, signatureInterface);
}
if (isExternalSigning())
{
System.out.println("Signing externally " + signedFile.getName());
ExternalSigningSupport externalSigning = doc.saveIncrementalForExternalSigning(fos);
// invoke external signature service
byte[] cmsSignature = sign(externalSigning.getContent());
// Explanation of late external signing (off by default):
// If you want to add the signature in a separate step, then set an empty byte array
// and call signature.getByteRange() and remember the offset signature.getByteRange()[1]+1.
// you can write the ascii hex signature at a later time even if you don't have this
// PDDocument object anymore, with classic java file random access methods.
// If you can't remember the offset value from ByteRange because your context has changed,
// then open the file with PDFBox, find the field with findExistingSignature() or
// PODDocument.getLastSignatureDictionary() and get the ByteRange from there.
// Close the file and then write the signature as explained earlier in this comment.
if (isLateExternalSigning())
{
// this saves the file with a 0 signature
externalSigning.setSignature(new byte[0]);
// remember the offset (add 1 because of "<")
int offset = signature.getByteRange()[1] + 1;
// now write the signature at the correct offset without any PDFBox methods
try (RandomAccessFile raf = new RandomAccessFile(signedFile, "rw"))
{
raf.seek(offset);
raf.write(Hex.getBytes(cmsSignature));
}
}
else
{
// set signature bytes received from the service and save the file
externalSigning.setSignature(cmsSignature);
}
}
else
{
// write incremental (only for signing purpose)
doc.saveIncremental(fos);
}
}
// Do not close signatureOptions before saving, because some COSStream objects within
// are transferred to the signed document.
// Do not allow signatureOptions get out of scope before saving, because then the COSDocument
// in signature options might by closed by gc, which would close COSStream objects prematurely.
// See https://issues.apache.org/jira/browse/PDFBOX-3743
IOUtils.closeQuietly(signatureOptions);
}
// Find an existing signature (assumed to be empty). You will usually not need this.
private PDSignature findExistingSignature(PDDocument doc, String sigFieldName)
{
PDSignature signature = null;
PDSignatureField signatureField;
PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
if (acroForm != null)
{
signatureField = (PDSignatureField) acroForm.getField(sigFieldName);
if (signatureField != null)
{
// retrieve signature dictionary
signature = signatureField.getSignature();
if (signature == null)
{
signature = new PDSignature();
// after solving PDFBOX-3524
// signatureField.setValue(signature)
// until then:
signatureField.getCOSObject().setItem(COSName.V, signature);
}
else
{
throw new IllegalStateException("The signature field " + sigFieldName + " is already signed.");
}
}
}
return signature;
}
/**
* This will print the usage for this program.
*/
private static void usage()
{
System.err.println("Usage: java " + CreateVisibleSignature.class.getName()
+ " <pkcs12-keystore-file> <pin> <input-pdf> <sign-image>\n" + "" +
"options:\n" +
" -tsa <url> sign timestamp using the given TSA server\n"+
" -e sign using external signature creation scenario");
}
}
最佳答案
您的 signPDF
方法包含此代码:
// Optional: certify
// can be done only if version is at least 1.5 and if not already set
// doing this on a PDF/A-1b file fails validation by Adobe preflight (PDFBOX-3821)
// PDF/A-1b requires PDF version 1.4 max, so don't increase the version on such files.
if (doc.getVersion() >= 1.5f && accessPermissions == 0)
{
SigUtils.setMDPPermission(doc, signature, 2);
}
如果您不希望以认证签名开头,请删除此 setMDPPermission
调用。
关于java - PDFBox 可以签署所有 'Approval Signatures' 而不是总是将第一个签名设为 'Certified' 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47294044/
我正在努力扩展此处发布的工作流程脚本... James Ferreira Workflow video. 我已经扩展了脚本,并且关于电子邮件的一切工作正常,但我遇到了 doGet() 函数无法正常工作
这是当前的分支策略 并且还需要批准人。问题是当所需的批准者创建他自己的 PR 时,Azure dev-Ops 不允许并显示其中一名批准者需要批准 PR。 我们如何让所需的批准人批准他们自己的 PR 最
这是当前的分支策略 并且还需要批准人。问题是当所需的批准者创建他自己的 PR 时,Azure dev-Ops 不允许并显示其中一名批准者需要批准 PR。 我们如何让所需的批准人批准他们自己的 PR 最
我正在构建一个约会风格的应用程序,其中 User 可以批准其他用户。我使用 Approval 模型来跟踪这些关系。每个 Approval 都有一个 user_id 和一个 approved_id --
我正在使用 ApprovalTests.Net。我看到我可以指定各种报告。我想在运行单元测试时自动批准测试。我只需要临时执行此操作,或者在代码进行重大更改时执行此操作。这在使用 ApprovalRes
今天我的应用被拒绝了,我不明白问题。 被拒绝,因为: 10.6 - Apple and our customers place a high value on simple, refined, cre
有没有办法通过规则手动批准正在发布到 firebase 数据库的帖子? 目前的规则是这样的: { "rules": { ".read": true, ".write": true
我希望当有人点击销售订单上的批准按钮时生成采购订单。我将脚本部署到销售订单记录和单击批准按钮时触发的事件类型。但是,此代码不会创建采购订单,因为我的子列表项值的字段值无效。 我使用了项目的内部 ID
当 a PayPal subscription is created 时,批准 URL 在响应中可用。 看起来像这样,包括一个 token : https://www.sandbox.paypal.c
我在 TFS (Visual Studio 2017) 中使用 Scrum 工作流,当我期望 Approved 时,状态的唯一可用值是 New,已提交 和完成。 他们为什么不见了?我该如何解决这个问题
我正在为我制作的 iOS 应用制作网络应用程序。我想管理我制作的应用程序中的问题,但现在我还希望用户有机会向 Web 应用程序提交问题。但是,用户的问题不能直接添加到列表中,因为我想首先批准它是一个有
我使用了 PayPal api,首先我进行预批准,然后使用该批准 key 进行链式支付。在我的本地服务器上一切正常。但在现场直播时,它给我以下错误。 预先批准 错误 PreapprovalRespon
我是 GitLab 的新手,目前正在使用社区版。我需要为每个产品添加一个默认批准人,以及用户选择的人。 我正在考虑将默认帐户保存在存储库托管的 yaml 文件中。我发现这条评论与我的情况非常相似: h
本页描述https://learn.microsoft.com/en-us/azure/devops/repos/git/branch-policies?view=azure-devops#requi
在我正在开发的应用程序中,我们使用 PaperTrail 不仅可以跟上原始用户所做的更改,还可以跟上对有权更改授权配置文件的“贡献者”角色的用户所做的更改. 我不能放在一起的一件是不允许未经批准的 p
对环境进行预部署批准是有意义的,但什么是部署后批准,我为什么要使用它? Team Service 文档中没有定义 here 最佳答案 验证测试是我能想到的主要场景。想象一个部署链 Dev -> Tes
我正在尝试使用 mocha 对 Sails.js 项目的 Controller 进行单元测试。由于我有不同的安全策略,我无法使用 suptertest或类似的测试框架通过实际调用 url 来测试 Co
在下一个场景中,我想找到合适的分支策略: 在检查 PR 之前,审核者(而不是 PR 所有者)希望确保该分支在主分支上重新建立基础并运行它以确保它通过。 推送分支后,审核者无法批准它,因为: 除了最近的
我的 Spring Web 应用程序有问题。我想使用 web 应用程序访问 google(日历)api,因此我必须向 api 验证自己的身份并授予对日历的访问权限。 但实际的问题是我收到错误org.s
我们正在考虑将 Gerrit 用于大型项目。此时,了解人们如何处理已批准变更的合并冲突将会很有趣。 想象一下,许多不同规模的变更正在同时等待修订,并且正在逐步审查和验证。由于其中一些人可能会修改同一段
我是一名优秀的程序员,十分优秀!