Passwortgeschützte Dokumente laden mit dem jadice web toolkit

Passwortgeschützte Dokumente laden mit dem jadice web toolkit

Gültig ab jadice web toolkit 5.7.1.0

Dieser Artikel beschreibt, wie passwortgeschützte PDF-Dokumente mit dem jadice web toolkit geladen werden können



Die vorgestellte Lösung ist im Showcase des jadice web toolkit unter http://webtoolkit.jadice.com/showcase/index.html#!EncryptedDocumentExample abrufbar. Das Passwort für das dort verwendete Dokument lautet J4d1c3







Anforderung

Ein PDF-Dokument, zu dessen Anzeige ein Passwort benötigt wird, soll im jadice web toolkit dargestellt werden. Dazu wird beim Öffnen des Dokuments ein Passwort in einem Benutzerdialog abgefragt. Anschließend wird versucht, das Dokument mit diesen Passwort zu öffnen.







Grundlegendes Prinzip

In diesem Abschnitt werden die grundlegenden Prinzipien behandelt, um passwortgeschützte PDF-Dokumente im jadice web toolkit öffnen zu können.



Lesen eines passwortgeschützten Dokuments mit dem DocumentDataProvider

Um ein passwortgeschütztes Dokument mit Mitteln der jadice documentplatform öffnen zu können, muss in den PDFStandardSecurityHandlerSettings des Readers ein CryptoMaterialProvider gesetzt werden. Das vom CryptoMaterialProviders bereitgestellte PasswordMaterial enthält dann einen String,  mit dem versucht wird, das Dokument zu öffnen.

Das Setzen dieser Einstellung kann beispielsweise in der der read()- beziehungsweise der recovery()Methode des verwendeten DocumentDataProvider erfolgen. Es ist allerdings auch möglich, in diese Methoden eine Reader-Instanz zu übergeben, für die die PDFStandardSecurityHandlerSettings bereits zuvor gesetzt wurden.

Das folgende Code-Beispiel enthält einen Auszug der Implementierung eines DocumentDataProvider, bei der stets versucht wird, das DEFAULT_PASSWORD zum Öffnen des Dokuments zu verwenden. In der Praxis wird man das Passwort eher über einen Benutzerdialog abfragen und in Source beziehungsweise Handle hinterlegen.

DocumentDataProvider mit Standard-Passwort
@Override public void read(Reader reader, final S source) throws JadiceException, IOException { // Abfragen der PDFStandardSecurityHandlerSettings beim Reader. PDFStandardSecurityHandlerSettings pdfStandardSecurityHandlerSettings = reader.getSettings( PDFStandardSecurityHandlerSettings.class); // Definition des CryptoMaterialProviders CryptoMaterialProvider<PasswordMaterial> cryptoMaterialProvider = new CryptoMaterialProvider<PasswordMaterial>() { @Override // Der CryptoMaterialProvider wiederum stellt einem CryptoMaterialReceiver das // PasswordMaterial zur Verfügung. public void provide(CryptoMaterialReceiver<PasswordMaterial> receiver) { // Bereistellung des PasswordMaterial mit dem fixen Passwort DEFAULT_PASSWORD receiver.receive(new PasswordMaterial(DEFAULT_PASSWORD)); } }; // setzen des oben definierten cryptoMaterialProvider in den pdfStandardSecurityHandlerSettings // des Readers pdfStandardSecurityHandlerSettings.setCryptoMaterialProvider(cryptoMaterialProvider); // eigentlicher Lesevorgang im Reader Provider<InputStream, IOException> stream = getStream(source); reader.read(stream); } @Override public void recover(Reader reader, final SH handle) throws RecoverFailedException, JadiceException { // Abfragen der PDFStandardSecurityHandlerSettings beim Reader. PDFStandardSecurityHandlerSettings pdfStandardSecurityHandlerSettings = reader.getSettings(PDFStandardSecurityHandlerSettings.class); // Definition des CryptoMaterialProviders CryptoMaterialProvider<PasswordMaterial> cryptoMaterialProvider = new CryptoMaterialProvider<PasswordMaterial>() { // Der CryptoMaterialProvider wiederum stellt einem CryptoMaterialReceiver das // PasswordMaterial zur Verfügung. @Override public void provide(CryptoMaterialReceiver<PasswordMaterial> receiver) { // Bereistellung des PasswordMaterial mit dem fixen Passwort DEFAULT_PASSWORD receiver.receive(new PasswordMaterial(DEFAULT_PASSWORD)); } }; // setzen des oben definierten cryptoMaterialProvider in den pdfStandardSecurityHandlerSettings // des Readers pdfStandardSecurityHandlerSettings.setCryptoMaterialProvider(cryptoMaterialProvider); try { Provider<InputStream, IOException> stream = getRecoveryStream(handle); reader.read(stream); } catch (IOException e) { throw new RecoverFailedException("Can't recover " + handle, e); } }

Weitere Implementierungsbeispiele eines CryptoMaterialProvider finden sich in den weiterführenden Links am Ende dieses Artikels. In der dort verlinkten Dokumentation wird auch erklärt, wie ein CryptoMaterialProvider mit mehreren Standard-Passwörtern implementiert werden kann.

Der Vergleich des Passworts aus dem PasswordMaterial mit dem im Dokument gesetzten Wert erfolgt auf Basis eine byte-Array, nicht als String-Vergleich! Deswegen kann es bei Verwendung unterschiedlicher Encodings zu Fehlern kommen, auch wenn offenbar der korrekte String im PasswordMaterial gesetzt wurde. Ein Workaround für dieses Problem ist ebenfalls am Ende dieses Artikels dargestellt.







Anfordern des Passworts beim Benutzer

Ist beim Laden eines PDF-Dokuments das benötigte Passwort serverseitig nicht bekannt wird dort zunächst eine PDFSecurityDocumentCreationException geworfen.
Diese kann anschließend in Form eines MimicryThrowable an den Client propagiert werden. Dort kann dann durch einen Benutzerdialog das Passwort abgefragt und an den Server übertragen werden.

Ist das Passwort korrekt, wird das Dokument geladen und angezeigt. Kann das Dokument mit dem eingegebenen Passwort nicht geöffnet werden, wird erneut eine PDFSecurityDocumentCreationException geworfen und als MimicryThrowable an den Client gesendet.

Der serverseitige Ladevorgang kann durch den Client abgebrochen werden, beispielsweise wenn das Passwort dem Benutzer nicht bekannt ist.

Da das Passwort bei jedem Ladevorgang des Dokuments auf dem Server vorhanden sein muss, sollte sichergestellt sein dass das Passwort dort lange genug vorgehalten wird. Damit wird sichergestellt. dass das Dokument im Recovery-Fall nach der Entfernung aus dem Cache ohne Nutzerinteraktion neu geladen werden kann.







Beispielhafte Implementierung im Showcase

Eine beispielhafte Implementierung zur Anzeige passwortgeschützter PDF-Dateien wird im Showcase unter https://webtoolkit.jadice.com/showcase/index.html#!EncryptedDocumentExample vorgestellt.

Dort findet in Example.java der Ladevorgang des passwortgeschützten Dokuments encr.pdf statt. Dabei wird dem Reader im Aufruf von Reader#complete(...) ein AsyncCallback-Objekt übergeben, dessen onFailure-Methode bei Fehlern beim Dokumentenladevorgang aufgerufen wird.

Innerhalb der onFailure-Methode wird geprüft, ob der Fehler durch ein falsches oder fehlendes Passwort verursacht wurde. Ist dies der Fall wird ein PasswortDialog angezeigt.

Der PasswortDialog hinterlegt das Passwort bei Bestätigung der Eingabe in einem Source-Handle, das anschließend an den Reader übergeben wird.

Weitere Information zum Lesen von Dokumenten mit Source-Handles finden sich in Kapitel zwei des Tutorials "Getting Started" unter 2 - Laden eines Dokuments

-

Passwort-Dialog aus PasswortDialog.java





Erläuterungen zur Implementierung

In diesem Abschnitt soll anhand von Code-Auszügen die Implementierung des Showcase erläutert werden.