Skip to content

Commit 2057d95

Browse files
author
Eugene Bochilo
committed
Refactor preClose method in PdfSigner
DEVSIX-5219
1 parent 3106077 commit 2057d95

File tree

2 files changed

+241
-59
lines changed

2 files changed

+241
-59
lines changed

sign/src/main/java/com/itextpdf/signatures/PdfSigner.java

Lines changed: 102 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -887,66 +887,9 @@ protected void preClose(Map<PdfName, Integer> exclusionSizes) throws IOException
887887
cryptoDictionary.getPdfObject().makeIndirect(document);
888888

889889
if (fieldExist) {
890-
PdfSignatureFormField sigField = (PdfSignatureFormField) acroForm.getField(fieldName);
891-
sigField.put(PdfName.V, cryptoDictionary.getPdfObject());
892-
893-
fieldLock = sigField.getSigFieldLockDictionary();
894-
895-
if (fieldLock == null && this.fieldLock != null) {
896-
this.fieldLock.getPdfObject().makeIndirect(document);
897-
sigField.put(PdfName.Lock, this.fieldLock.getPdfObject());
898-
fieldLock = this.fieldLock;
899-
}
900-
901-
sigField.put(PdfName.P, document.getPage(appearance.getPageNumber()).getPdfObject());
902-
sigField.put(PdfName.V, cryptoDictionary.getPdfObject());
903-
PdfObject obj = sigField.getPdfObject().get(PdfName.F);
904-
int flags = 0;
905-
906-
if (obj != null && obj.isNumber()) {
907-
flags = ((PdfNumber) obj).intValue();
908-
}
909-
910-
flags |= PdfAnnotation.LOCKED;
911-
sigField.put(PdfName.F, new PdfNumber(flags));
912-
PdfDictionary ap = new PdfDictionary();
913-
ap.put(PdfName.N, appearance.getAppearance().getPdfObject());
914-
sigField.put(PdfName.AP, ap);
915-
sigField.setModified();
890+
fieldLock = populateExistingSignatureFormField(acroForm);
916891
} else {
917-
PdfWidgetAnnotation widget = new PdfWidgetAnnotation(appearance.getPageRect());
918-
widget.setFlags(PdfAnnotation.PRINT | PdfAnnotation.LOCKED);
919-
920-
PdfSignatureFormField sigField = PdfFormField.createSignature(document);
921-
sigField.setFieldName(name);
922-
sigField.put(PdfName.V, cryptoDictionary.getPdfObject());
923-
sigField.addKid(widget);
924-
925-
if (this.fieldLock != null) {
926-
this.fieldLock.getPdfObject().makeIndirect(document);
927-
sigField.put(PdfName.Lock, this.fieldLock.getPdfObject());
928-
fieldLock = this.fieldLock;
929-
}
930-
931-
int pagen = appearance.getPageNumber();
932-
widget.setPage(document.getPage(pagen));
933-
PdfDictionary ap = widget.getAppearanceDictionary();
934-
935-
if (ap == null) {
936-
ap = new PdfDictionary();
937-
widget.put(PdfName.AP, ap);
938-
}
939-
940-
ap.put(PdfName.N, appearance.getAppearance().getPdfObject());
941-
acroForm.addField(sigField, document.getPage(pagen));
942-
943-
if (acroForm.getPdfObject().isIndirect()) {
944-
acroForm.setModified();
945-
} else {
946-
//Acroform dictionary is a Direct dictionary,
947-
//for proper flushing, catalog needs to be marked as modified
948-
document.getCatalog().setModified();
949-
}
892+
fieldLock = createNewSignatureFormField(acroForm, name);
950893
}
951894

952895
exclusionLocations = new HashMap<>();
@@ -1032,6 +975,106 @@ protected void preClose(Map<PdfName, Integer> exclusionSizes) throws IOException
1032975
}
1033976
}
1034977

978+
/**
979+
* Populates already existing signature form field in the acroForm object.
980+
* This method is called during the {@link PdfSigner#preClose(Map)} method if the signature field already exists.
981+
*
982+
* @param acroForm {@link PdfAcroForm} object in which the signature field will be populated
983+
* @return signature field lock dictionary
984+
* @throws IOException if font for the appearance dictionary cannot be created
985+
*/
986+
protected PdfSigFieldLock populateExistingSignatureFormField(PdfAcroForm acroForm) throws IOException {
987+
PdfSignatureFormField sigField = (PdfSignatureFormField) acroForm.getField(fieldName);
988+
sigField.put(PdfName.V, cryptoDictionary.getPdfObject());
989+
990+
PdfSigFieldLock sigFieldLock = sigField.getSigFieldLockDictionary();
991+
992+
if (sigFieldLock == null && this.fieldLock != null) {
993+
this.fieldLock.getPdfObject().makeIndirect(document);
994+
sigField.put(PdfName.Lock, this.fieldLock.getPdfObject());
995+
sigFieldLock = this.fieldLock;
996+
}
997+
998+
sigField.put(PdfName.P, document.getPage(appearance.getPageNumber()).getPdfObject());
999+
sigField.put(PdfName.V, cryptoDictionary.getPdfObject());
1000+
PdfObject obj = sigField.getPdfObject().get(PdfName.F);
1001+
int flags = 0;
1002+
1003+
if (obj != null && obj.isNumber()) {
1004+
flags = ((PdfNumber) obj).intValue();
1005+
}
1006+
1007+
flags |= PdfAnnotation.LOCKED;
1008+
sigField.put(PdfName.F, new PdfNumber(flags));
1009+
1010+
if (appearance.isInvisible()) {
1011+
// According to the spec, appearance stream is not required if the width and height of the rectangle are 0
1012+
sigField.remove(PdfName.AP);
1013+
} else {
1014+
PdfDictionary ap = new PdfDictionary();
1015+
ap.put(PdfName.N, appearance.getAppearance().getPdfObject());
1016+
sigField.put(PdfName.AP, ap);
1017+
}
1018+
1019+
sigField.setModified();
1020+
1021+
return sigFieldLock;
1022+
}
1023+
1024+
/**
1025+
* Creates new signature form field and adds it to the acroForm object.
1026+
* This method is called during the {@link PdfSigner#preClose(Map)} method if the signature field doesn't exist.
1027+
*
1028+
* @param acroForm {@link PdfAcroForm} object in which new signature field will be added
1029+
* @param name the name of the field
1030+
* @return signature field lock dictionary
1031+
* @throws IOException if font for the appearance dictionary cannot be created
1032+
*/
1033+
protected PdfSigFieldLock createNewSignatureFormField(PdfAcroForm acroForm, String name) throws IOException {
1034+
PdfWidgetAnnotation widget = new PdfWidgetAnnotation(appearance.getPageRect());
1035+
widget.setFlags(PdfAnnotation.PRINT | PdfAnnotation.LOCKED);
1036+
1037+
PdfSignatureFormField sigField = PdfFormField.createSignature(document);
1038+
sigField.setFieldName(name);
1039+
sigField.put(PdfName.V, cryptoDictionary.getPdfObject());
1040+
sigField.addKid(widget);
1041+
1042+
PdfSigFieldLock sigFieldLock = sigField.getSigFieldLockDictionary();
1043+
1044+
if (this.fieldLock != null) {
1045+
this.fieldLock.getPdfObject().makeIndirect(document);
1046+
sigField.put(PdfName.Lock, this.fieldLock.getPdfObject());
1047+
sigFieldLock = this.fieldLock;
1048+
}
1049+
1050+
int pagen = appearance.getPageNumber();
1051+
widget.setPage(document.getPage(pagen));
1052+
1053+
if (appearance.isInvisible()) {
1054+
// According to the spec, appearance stream is not required if the width and height of the rectangle are 0
1055+
widget.remove(PdfName.AP);
1056+
} else {
1057+
PdfDictionary ap = widget.getAppearanceDictionary();
1058+
if (ap == null) {
1059+
ap = new PdfDictionary();
1060+
widget.put(PdfName.AP, ap);
1061+
}
1062+
ap.put(PdfName.N, appearance.getAppearance().getPdfObject());
1063+
}
1064+
1065+
acroForm.addField(sigField, document.getPage(pagen));
1066+
1067+
if (acroForm.getPdfObject().isIndirect()) {
1068+
acroForm.setModified();
1069+
} else {
1070+
//Acroform dictionary is a Direct dictionary,
1071+
//for proper flushing, catalog needs to be marked as modified
1072+
document.getCatalog().setModified();
1073+
}
1074+
1075+
return sigFieldLock;
1076+
}
1077+
10351078
/**
10361079
* Gets the document bytes that are hashable when using external signatures.
10371080
* The general sequence is:
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package com.itextpdf.signatures;
2+
3+
import com.itextpdf.forms.PdfAcroForm;
4+
import com.itextpdf.forms.PdfSigFieldLock;
5+
import com.itextpdf.forms.fields.PdfFormField;
6+
import com.itextpdf.forms.fields.PdfSignatureFormField;
7+
import com.itextpdf.io.source.ByteArrayOutputStream;
8+
import com.itextpdf.kernel.geom.Rectangle;
9+
import com.itextpdf.kernel.pdf.EncryptionConstants;
10+
import com.itextpdf.kernel.pdf.PdfDictionary;
11+
import com.itextpdf.kernel.pdf.PdfDocument;
12+
import com.itextpdf.kernel.pdf.PdfName;
13+
import com.itextpdf.kernel.pdf.PdfReader;
14+
import com.itextpdf.kernel.pdf.PdfWriter;
15+
import com.itextpdf.kernel.pdf.ReaderProperties;
16+
import com.itextpdf.kernel.pdf.StampingProperties;
17+
import com.itextpdf.kernel.pdf.WriterProperties;
18+
import com.itextpdf.kernel.pdf.annot.PdfWidgetAnnotation;
19+
import com.itextpdf.test.ExtendedITextTest;
20+
import com.itextpdf.test.annotations.type.UnitTest;
21+
import org.junit.Assert;
22+
import org.junit.Test;
23+
import org.junit.experimental.categories.Category;
24+
25+
import java.io.ByteArrayInputStream;
26+
import java.io.IOException;
27+
28+
@Category(UnitTest.class)
29+
public class PdfSignerUnitTest extends ExtendedITextTest {
30+
31+
@Test
32+
public void createNewSignatureFormFieldInvisibleAnnotationTest() throws IOException {
33+
PdfSigner signer = new PdfSigner(
34+
new PdfReader(new ByteArrayInputStream(createDocumentWithoutWidgetAnnotation()),
35+
new ReaderProperties().setPassword("owner".getBytes())), new ByteArrayOutputStream(), new StampingProperties());
36+
signer.cryptoDictionary = new PdfSignature();
37+
signer.appearance.setPageRect(new Rectangle(100, 100, 0, 0));
38+
39+
PdfAcroForm acroForm = PdfAcroForm.getAcroForm(signer.document, true);
40+
signer.createNewSignatureFormField(acroForm, signer.fieldName);
41+
PdfFormField formField = acroForm.getField(signer.fieldName);
42+
43+
PdfDictionary formFieldDictionary = formField.getPdfObject();
44+
Assert.assertNotNull(formFieldDictionary);
45+
Assert.assertFalse(formFieldDictionary.containsKey(PdfName.AP));
46+
}
47+
48+
@Test
49+
public void createNewSignatureFormFieldNotInvisibleAnnotationTest() throws IOException {
50+
PdfSigner signer = new PdfSigner(
51+
new PdfReader(new ByteArrayInputStream(createDocumentWithoutWidgetAnnotation()),
52+
new ReaderProperties().setPassword("owner".getBytes())), new ByteArrayOutputStream(), new StampingProperties());
53+
signer.cryptoDictionary = new PdfSignature();
54+
signer.appearance.setPageRect(new Rectangle(100, 100, 10, 10));
55+
PdfSigFieldLock fieldLock = new PdfSigFieldLock();
56+
signer.fieldLock = fieldLock;
57+
58+
PdfAcroForm acroForm = PdfAcroForm.getAcroForm(signer.document, true);
59+
Assert.assertEquals(fieldLock, signer.createNewSignatureFormField(acroForm, signer.fieldName));
60+
PdfFormField formField = acroForm.getField(signer.fieldName);
61+
62+
PdfDictionary formFieldDictionary = formField.getPdfObject();
63+
Assert.assertNotNull(formFieldDictionary);
64+
Assert.assertTrue(formFieldDictionary.containsKey(PdfName.AP));
65+
}
66+
67+
@Test
68+
public void populateExistingSignatureFormFieldInvisibleAnnotationTest() throws IOException {
69+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
70+
PdfDocument document = new PdfDocument(new PdfWriter(outputStream,
71+
new WriterProperties().setStandardEncryption("user".getBytes(), "owner".getBytes(), 0, EncryptionConstants.STANDARD_ENCRYPTION_128)));
72+
document.addNewPage();
73+
PdfWidgetAnnotation widgetAnnotation = new PdfWidgetAnnotation(new Rectangle(100, 100, 0, 0));
74+
document.getPage(1).addAnnotation(widgetAnnotation);
75+
document.close();
76+
PdfSigner signer = new PdfSigner(
77+
new PdfReader(new ByteArrayInputStream(outputStream.toByteArray()), new ReaderProperties().setPassword("owner".getBytes())),
78+
new ByteArrayOutputStream(), new StampingProperties());
79+
signer.cryptoDictionary = new PdfSignature();
80+
signer.appearance.setPageRect(new Rectangle(100, 100, 0, 0));
81+
82+
widgetAnnotation = (PdfWidgetAnnotation) signer.document.getPage(1).getAnnotations().get(0);
83+
PdfAcroForm acroForm = PdfAcroForm.getAcroForm(signer.document, true);
84+
PdfFormField formField = new ExtendedPdfSignatureFormField(widgetAnnotation, signer.document);
85+
formField.setFieldName(signer.fieldName);
86+
acroForm.addField(formField);
87+
signer.populateExistingSignatureFormField(acroForm);
88+
formField = acroForm.getField(signer.fieldName);
89+
90+
PdfDictionary formFieldDictionary = formField.getPdfObject();
91+
Assert.assertNotNull(formFieldDictionary);
92+
Assert.assertFalse(formFieldDictionary.containsKey(PdfName.AP));
93+
}
94+
95+
@Test
96+
public void populateExistingSignatureFormFieldNotInvisibleAnnotationTest() throws IOException {
97+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
98+
PdfDocument document = new PdfDocument(new PdfWriter(outputStream,
99+
new WriterProperties().setStandardEncryption("user".getBytes(), "owner".getBytes(), 0, EncryptionConstants.STANDARD_ENCRYPTION_128)));
100+
document.addNewPage();
101+
PdfWidgetAnnotation widgetAnnotation = new PdfWidgetAnnotation(new Rectangle(100, 100, 0, 0));
102+
document.getPage(1).addAnnotation(widgetAnnotation);
103+
document.close();
104+
PdfSigner signer = new PdfSigner(
105+
new PdfReader(new ByteArrayInputStream(outputStream.toByteArray()), new ReaderProperties().setPassword("owner".getBytes())),
106+
new ByteArrayOutputStream(), new StampingProperties());
107+
signer.cryptoDictionary = new PdfSignature();
108+
PdfSigFieldLock fieldLock = new PdfSigFieldLock();
109+
signer.fieldLock = fieldLock;
110+
signer.appearance.setPageRect(new Rectangle(100, 100, 10, 10));
111+
112+
widgetAnnotation = (PdfWidgetAnnotation) signer.document.getPage(1).getAnnotations().get(0);
113+
PdfAcroForm acroForm = PdfAcroForm.getAcroForm(signer.document, true);
114+
PdfFormField formField = new ExtendedPdfSignatureFormField(widgetAnnotation, signer.document);
115+
formField.setFieldName(signer.fieldName);
116+
acroForm.addField(formField);
117+
Assert.assertEquals(signer.populateExistingSignatureFormField(acroForm), fieldLock);
118+
formField = acroForm.getField(signer.fieldName);
119+
120+
PdfDictionary formFieldDictionary = formField.getPdfObject();
121+
Assert.assertNotNull(formFieldDictionary);
122+
Assert.assertTrue(formFieldDictionary.containsKey(PdfName.AP));
123+
}
124+
125+
private static byte[] createDocumentWithoutWidgetAnnotation() {
126+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
127+
PdfDocument document = new PdfDocument(new PdfWriter(outputStream,
128+
new WriterProperties().setStandardEncryption("user".getBytes(), "owner".getBytes(), 0, EncryptionConstants.STANDARD_ENCRYPTION_128)));
129+
document.addNewPage();
130+
document.close();
131+
return outputStream.toByteArray();
132+
}
133+
134+
static class ExtendedPdfSignatureFormField extends PdfSignatureFormField {
135+
public ExtendedPdfSignatureFormField(PdfWidgetAnnotation widgetAnnotation, PdfDocument document) {
136+
super(widgetAnnotation, document);
137+
}
138+
}
139+
}

0 commit comments

Comments
 (0)