3.26. Signaturen - Unterschriebenes PDF

Überblick

Wenn im Zeitalter der elektronischen Kommunikation vertraglich relevante Informationen in Form von PDF-Dokumenten ausgetauscht werden, muss irgendwie sichergestellt werden, dass die Daten auch wirklich von demjenigen stammen, von dem sie vorgeben, zu sein. Für diesen Zweck gibt es Zertifikate. Sie bestätigen - unabhängig von PDF-Dokumenten - die Echtheit von Personen- oder Unternehmensdaten. Mit einem Zertifikat kann der Inhalt von Dokumenten unterschrieben (signiert) werden. Dafür bietet PDF ein spezielles Signaturfeld an.

PDFUnit stellt für Signaturen zahlreiche Testmethoden zur Verfügung:

// Simple methods for signatures:
.isSigned()
.isSignedBy(..)
.hasNumberOfSignatures(..) 
.hasSignatureField(..)
.hasSignatureFields()

// Detailed tests for one signature:
.hasSignatureField(..).withSignature(..).coveringWholeDocument()
.hasSignatureField(..).withSignature(..).signedBy(name)
.hasSignatureField(..).withSignature(..).signedOn(date)
.hasSignatureField(..).withSignature(..).withReason(..)
.hasSignatureField(..).withoutSignature(..)

// Tests covering all signature fields:
.hasSignatureFields().allSigned()
.hasSignatureFields().allUnSigned()

// Other tests with signatures:
.hasField(..).ofType(SIGNATURE)
.hasField(..).withProperty().signed()

Ein signiertes PDF darf nicht mit einem zertifizierten PDF verwechselt werden. Ein zertifiziertes PDF garantiert die Einhaltung bestimmter Eigenschaften, die für eine Verarbeitung benötigt werden. Tests für zertifizierte PDF-Dokumente sind im Kapitel 3.38: „Zertifiziertes PDF“ beschrieben.

Existenz

Der einfachste Test ist, zu prüfen, ob ein Testdokument überhaupt signiert ist:

@Test
public void isSigned() throws Exception {
  String filename = "sampleSignedPDFDocument.pdf";

  AssertThat.document(filename)
            .isSigned()
  ;
}

Wenn es mehrere Unterschriftsfelder gibt, kann auch geprüft werden, ob alle Felder signiert sind:

@Test
public void allFieldsSigned() throws Exception {
  String filename = "documentUnderTest.pdf";
  AssertThat.document(filename)
            .hasSignatureFields()
            .allSigned()
  ;
}

Die Methode .allUnsigned() prüft genau das Gegenteil.

Ein spezielles Unterschriftsfeld kann auf folgende Weise validiert werden:

@Test
public void hasField_Signed() throws Exception {
  String filename = "sampleSignedPDFDocument.pdf";
  String fieldnameSignedField = "Signature2"; 
  
  AssertThat.document(filename)
            .hasField(fieldnameSignedField) 
            .withProperty()
            .signed()
  ;
}

Weiterhin kann die Existenz von Unterschriftsfeldern geprüft werden:

@Test
public void hasSignatureFields() throws Exception {
  String filename = "sampleSignedPDFDocument.pdf";

  AssertThat.document(filename)
            .hasSignatureField("Signature of Seller")
            .hasSignatureField("Signature of Buyer")
  ;
}

Und führt man die Intention der vorhergehende Tests weiter fort, muss die Frage gestellt werden, ob bestimmte Unterschriftsfelder unterschrieben sind. Die Antwort liefert der folgende Test:

@Test
public void hasSignatureFieldsWithSignature() throws Exception {
  String filename = "sampleSignedPDFDocument.pdf";

  AssertThat.document(filename)
            .hasSignatureField("Signature of Seller").withSignature()
            .hasSignatureField("Signature of Buyer").withSignature()
  ;
}

Der umgekehrte Fall, dass ein Unterschriftsfeld keine Unterschrift enthält, kann mit der Funktion .hasSignatureField("name").withoutSignature() überprüft werden.

Anzahl der Unterschriften

Da ein PDF-Dokument mehrere Unterschriften enthalten kann, gibt es auch einen Test, der lediglich die Anzahl der Signaturen überprüft:

@Test
public void hasNumberOfSignatures() throws Exception {
  String filename = "sampleSignedPDFDocument.pdf";

  AssertThat.document(filename)
            .hasNumberOfSignatures(1)
  ;
}

Unterschriftsdatum

Es ist manchmal interessant, festzustellen, wann ein PDF-Dokument unterschrieben wurde:

@Test 
public void hasSignature_WithSigningDate() throws Exception {
  String filename = "sampleSignedPDFDocument.pdf";
  Calendar signingDate = DateHelper.getCalendar("2009-07-16", "yyyy-MM-dd");

  AssertThat.document(filename)
            .hasSignatureField("Signature2")
            .signedOn(signingDate)  1
  ;
}

1

Der Vergleich findet immer auf der Basis von Jahr-Monat-Tag statt.

Grund einer Unterschrift

Möglicherweise ist es für Tests nicht so interessant, den Grund einer Unterschrift zu überprüfen. Falls ein solcher Test aber notwendig sein sollte, dann sieht er folgendermaßen aus:

@Test
public void hasSignature_WithReason() throws Exception {
  String filename = "sampleSignedPDFDocument.pdf";
  
  AssertThat.document(filename)
            .hasSignatureField("Signature2")
            .withSignature()
            .withReason("I am the author of this document")
  ;
}

Vor dem Vergleich werden die Whitespaces normalisiert.

Name des Unterzeichner

Auch der Name dessen, der ein PDF-Dokument unterschrieben hat, ist für Testzwecke weniger interessant, als für die produktive Verarbeitung von PDF-Dokumenten. Dennoch gibt es dafür eine Testmethode:

@Test
public void hasSignature_WithSigningName() throws Exception {
  String filename = "sampleSignedPDFDocument.pdf";

  AssertThat.document(filename)
            .hasSignatureField("Signature2")
            .withSigningName("John B Harris")
  ;
}

Mit dem folgenden Test kann eine erwartete Unterschrift auch unabhängig von einem bestimmten Feld getestet werden:

@Test
public void isSignedBy() throws Exception {
  String filename = "sampleSignedPDFDocument.pdf";

  AssertThat.document(filename)
            .isSignedBy("John B Harris")
  ;
}

Umfang der Unterschrift

Eine Unterschrift kann sich laut PDF Standard auch auf Teile eines Dokumentes beziehen. Deshalb ist es möglich, zu testen, ob eine Unterschrift das komplette Dokument abdeckt:

@Test
public void hasSignature_CoveringWholeDocument() throws Exception {
  String filename = "sampleSignedPDFDocument.pdf";

  AssertThat.document(filename)
            .hasSignatureField("Signature2")
            .coveringWholeDocument()
  ;
}

Zusammenhängend testen

Mehrere Tests, die sich auf ein Unterschriftsfeld beziehen, können verkettet werden:

@Test
public void differentAspectsAroundSignature() throws Exception {
  String filename = "helloWorld_signed.pdf";
  Calendar signingDate = DateHelper.getCalendar("2007-10-14", "yyyy-MM-dd");
  
  AssertThat.document(filename)
            .hasSignatureField("sign_rbl")
            .signedBy("Raymond Berthou")
            .signedOn(signingDate)
            .coveringWholeDocument()
  ;
}

Überlegen Sie sich aber einen besseren Namen für diesen Test!