]> source.dussan.org Git - poi.git/commitdiff
Handle encrypted files with known password in integration tests
authorAndreas Beeker <kiwiwings@apache.org>
Tue, 6 Jun 2017 22:21:46 +0000 (22:21 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Tue, 6 Jun 2017 22:21:46 +0000 (22:21 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1797839 13f79535-47bb-0310-9956-ffa450edef68

src/integrationtest/org/apache/poi/TestAllFiles.java
src/integrationtest/org/apache/poi/stress/AbstractFileHandler.java
src/integrationtest/org/apache/poi/stress/XSSFFileHandler.java
src/java/org/apache/poi/extractor/OLE2ExtractorFactory.java
src/java/org/apache/poi/sl/usermodel/SlideShowFactory.java
src/ooxml/java/org/apache/poi/extractor/ExtractorFactory.java
src/ooxml/java/org/apache/poi/ss/usermodel/WorkbookFactory.java

index 9a589bbe94047815c608eed3c7b8bbc1210dd75b..3dafca29157798b48c55de7e9f0fc819d8a81010 100644 (file)
@@ -34,6 +34,8 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
+import org.apache.poi.poifs.crypt.Decryptor;
 import org.apache.poi.stress.AbstractFileHandler;
 import org.apache.poi.stress.FileHandler;
 import org.apache.poi.stress.HDGFFileHandler;
@@ -53,6 +55,7 @@ import org.apache.poi.stress.XSSFFileHandler;
 import org.apache.poi.stress.XWPFFileHandler;
 import org.apache.tools.ant.DirectoryScanner;
 import org.junit.AssumptionViolatedException;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -88,6 +91,9 @@ public class TestAllFiles {
     private static final File ROOT_DIR = new File("test-data");
 
     static final String[] SCAN_EXCLUDES = new String[] { "**/.svn/**", "lost+found" };
+
+    private static final Map<String,String> FILE_PASSWORD;
+
     
     // map file extensions to the actual mappers
     static final Map<String, FileHandler> HANDLERS = new HashMap<String, FileHandler>();
@@ -200,6 +206,28 @@ public class TestAllFiles {
         HANDLERS.put("spreadsheet/BigSSTRecord2CR7", new NullFileHandler());
         HANDLERS.put("spreadsheet/BigSSTRecordCR", new NullFileHandler());
         HANDLERS.put("spreadsheet/test_properties1", new NullFileHandler());
+        
+        Map<String,String> passmap = new HashMap<String,String>();
+        passmap.put("slideshow/Password_Protected-hello.ppt", "hello");
+        passmap.put("slideshow/Password_Protected-56-hello.ppt", "hello");
+        passmap.put("slideshow/Password_Protected-np-hello.ppt", "hello");
+        passmap.put("slideshow/cryptoapi-proc2356.ppt", "crypto");
+        passmap.put("spreadsheet/xor-encryption-abc.xls", "abc");
+        passmap.put("spreadsheet/35897-type4.xls", "freedom");
+        passmap.put("spreadsheet/58616.xlsx", Decryptor.DEFAULT_PASSWORD);
+        passmap.put("spreadsheet/password.xls", "password");
+        passmap.put("spreadsheet/protected_passtika.xlsx", "tika");
+        passmap.put("document/bug53475-password-is-pass.docx", "pass");
+        passmap.put("document/bug53475-password-is-solrcell.docx", "solrcell");
+        passmap.put("document/password_password_cryptoapi.doc", "password");
+        passmap.put("document/password_tika_binaryrc4.doc", "tika");
+        passmap.put("poifs/protect.xlsx", Decryptor.DEFAULT_PASSWORD);
+        passmap.put("poifs/extenxls_pwd123.xlsx", "pwd123");
+        passmap.put("poifs/protected_agile.docx", Decryptor.DEFAULT_PASSWORD);
+        passmap.put("poifs/60320-protected.xlsx", "Test001!!");
+        passmap.put("poifs/protected_sha512.xlsx", "this is a test");
+        
+        FILE_PASSWORD = Collections.unmodifiableMap(passmap);
     }
 
     private static final Set<String> unmodifiableHashSet(String... a) {
@@ -228,25 +256,9 @@ public class TestAllFiles {
     );
 
     private static final Set<String> EXPECTED_FAILURES = unmodifiableHashSet(
-        // password protected files
-        "spreadsheet/password.xls",
-        "spreadsheet/protected_passtika.xlsx",
+        // password protected files without known password
         "spreadsheet/51832.xls",
         "document/PasswordProtected.doc",
-        "slideshow/Password_Protected-hello.ppt",
-        "slideshow/Password_Protected-56-hello.ppt",
-        "slideshow/Password_Protected-np-hello.ppt",
-        "slideshow/cryptoapi-proc2356.ppt",
-        //"document/bug53475-password-is-pass.docx",
-        //"document/bug53475-password-is-solrcell.docx",
-        "spreadsheet/xor-encryption-abc.xls",
-        "spreadsheet/35897-type4.xls",
-        //"poifs/protect.xlsx",
-        //"poifs/protected_sha512.xlsx",
-        //"poifs/extenxls_pwd123.xlsx",
-        //"poifs/protected_agile.docx",
-        "spreadsheet/58616.xlsx",
-        "poifs/60320-protected.xlsx",
 
         // TODO: fails XMLExportTest, is this ok?
         "spreadsheet/CustomXMLMapping-singleattributenamespace.xlsx",
@@ -368,6 +380,13 @@ public class TestAllFiles {
 
     @Parameter(value=1)
     public FileHandler handler;
+
+    @Before
+    public void setPassword() {
+        // this also removes the password for non encrypted files
+        String pass = TestAllFiles.FILE_PASSWORD.get(file);
+        Biff8EncryptionKey.setCurrentUserPassword(pass);
+    }
     
     @Test
     public void testAllFiles() throws Exception {
@@ -381,7 +400,6 @@ public class TestAllFiles {
                 handler instanceof OPCFileHandler;
         boolean ignoreHPSF = (handler instanceof HPSFFileHandler);
         
-        
         try {
             InputStream stream = new BufferedInputStream(new FileInputStream(inputFile), 64*1024);
             try {
index 8bd34acdaed3cb4e439d7f820bfd95721ea36018..cf606c05cdcc359e4028fbc6662fd26a0e7476f1 100644 (file)
@@ -37,12 +37,8 @@ import org.apache.xmlbeans.XmlException;
 public abstract class AbstractFileHandler implements FileHandler {
     public static final Set<String> EXPECTED_EXTRACTOR_FAILURES = new HashSet<String>();
     static {
-        // password protected files
-        EXPECTED_EXTRACTOR_FAILURES.add("document/bug53475-password-is-pass.docx");
-        EXPECTED_EXTRACTOR_FAILURES.add("poifs/extenxls_pwd123.xlsx");
-        EXPECTED_EXTRACTOR_FAILURES.add("poifs/protect.xlsx");
-        EXPECTED_EXTRACTOR_FAILURES.add("poifs/protected_agile.docx");
-        EXPECTED_EXTRACTOR_FAILURES.add("poifs/protected_sha512.xlsx");
+        // password protected files without password
+       // ... currently none ...
         
         // unsupported file-types, no supported OLE2 parts
         EXPECTED_EXTRACTOR_FAILURES.add("hmef/quick-winmail.dat");
index ec325b9551634f10c83a89ceb6bb3264a02a21fa..477f8aa64212c5ec997544be563affdaf7b11196 100644 (file)
@@ -16,8 +16,9 @@
 ==================================================================== */
 package org.apache.poi.stress;
 
-import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.*;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assume.assumeFalse;
 
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
@@ -37,10 +38,14 @@ import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.transform.TransformerException;
 
 import org.apache.poi.POIXMLException;
+import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.exceptions.OLE2NotOfficeXmlFileException;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
 import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.poifs.crypt.Decryptor;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.xssf.eventusermodel.XLSX2CSV;
 import org.apache.poi.xssf.eventusermodel.XSSFReader;
@@ -54,8 +59,9 @@ import org.xml.sax.SAXException;
 public class XSSFFileHandler extends SpreadsheetHandler {
     @Override
     public void handleFile(InputStream stream, String path) throws Exception {
-        // ignore password protected files
-        if (POIXMLDocumentHandler.isEncrypted(stream)) return;
+        // ignore password protected files if password is unknown
+        String pass = Biff8EncryptionKey.getCurrentUserPassword();
+        assumeFalse(pass == null && POIXMLDocumentHandler.isEncrypted(stream));
 
         final XSSFWorkbook wb;
 
@@ -63,11 +69,24 @@ public class XSSFFileHandler extends SpreadsheetHandler {
         {
             ByteArrayOutputStream out = new ByteArrayOutputStream();
             IOUtils.copy(stream, out);
-            final byte[] bytes = out.toByteArray();
+            ByteArrayInputStream bytes = new ByteArrayInputStream(out.toByteArray());
 
-            checkXSSFReader(OPCPackage.open(new ByteArrayInputStream(bytes)));
-
-            wb = new XSSFWorkbook(new ByteArrayInputStream(bytes));
+            if (pass != null) {
+                POIFSFileSystem poifs = new POIFSFileSystem(bytes);
+                EncryptionInfo ei = new EncryptionInfo(poifs);
+                Decryptor dec = ei.getDecryptor();
+                boolean b = dec.verifyPassword(pass);
+                assertTrue("password mismatch", b);
+                InputStream is = dec.getDataStream(poifs);
+                out.reset();
+                IOUtils.copy(is, out);
+                is.close();
+                poifs.close();
+                bytes = new ByteArrayInputStream(out.toByteArray());
+            }
+            checkXSSFReader(OPCPackage.open(bytes));
+            bytes.reset();
+            wb = new XSSFWorkbook(bytes);
         }
 
         // use the combined handler for HSSF/XSSF
index 737e9e35102c450695afe85288b0ea1a94f0ad5c..6c96181e5f85862e30cd11954d516015c54fbdc8 100644 (file)
@@ -26,17 +26,22 @@ import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 
+import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.POIOLE2TextExtractor;
 import org.apache.poi.POITextExtractor;
 import org.apache.poi.hssf.OldExcelFormatException;
 import org.apache.poi.hssf.extractor.EventBasedExcelExtractor;
 import org.apache.poi.hssf.extractor.ExcelExtractor;
+import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
+import org.apache.poi.poifs.crypt.Decryptor;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
 import org.apache.poi.poifs.filesystem.DirectoryEntry;
 import org.apache.poi.poifs.filesystem.DirectoryNode;
 import org.apache.poi.poifs.filesystem.Entry;
 import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
 import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
 
@@ -167,9 +172,7 @@ public class OLE2ExtractorFactory {
      * Note that this won't check for embedded OOXML resources either, use
      *  {@link org.apache.poi.extractor.ExtractorFactory} for that.
      */
-    public static POITextExtractor createExtractor(DirectoryNode poifsDir)
-            throws IOException
-    {
+    public static POITextExtractor createExtractor(DirectoryNode poifsDir) throws IOException {
         // Look for certain entries in the stream, to figure it
         // out from
         for (String workbookName : WORKBOOK_DIR_ENTRY_NAMES) {
@@ -267,4 +270,29 @@ public class OLE2ExtractorFactory {
         }
         return e.toArray(new POITextExtractor[e.size()]);
     }
+
+    private static POITextExtractor createEncyptedOOXMLExtractor(DirectoryNode poifsDir)
+    throws IOException {
+        String pass = Biff8EncryptionKey.getCurrentUserPassword();
+        if (pass == null) {
+            pass = Decryptor.DEFAULT_PASSWORD;
+        }
+        
+        EncryptionInfo ei = new EncryptionInfo(poifsDir);
+        Decryptor dec = ei.getDecryptor();
+        InputStream is = null;
+        try {
+            if (!dec.verifyPassword(pass)) {
+                throw new EncryptedDocumentException("Invalid password specified - use Biff8EncryptionKey.setCurrentUserPassword() before calling extractor");
+            }
+            is = dec.getDataStream(poifsDir);
+            return createExtractor(is);
+        } catch (IOException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new IOException(e);
+        } finally {
+            IOUtils.closeQuietly(is);
+        }
+    }
 }
index 92575d1d6bdd076599b54ee2d02ce705c24054ba..97d9466173e5f7954e88c4a90747df48ef3caf01 100644 (file)
@@ -76,13 +76,17 @@ public class SlideShowFactory {
 
         // If we get here, it isn't an encrypted PPTX file
         // So, treat it as a regular HSLF PPT one
+        boolean passwordSet = false;
         if (password != null) {
             Biff8EncryptionKey.setCurrentUserPassword(password);
+            passwordSet = true;
         }
         try {
             return createHSLFSlideShow(fs);
         } finally {
-            Biff8EncryptionKey.setCurrentUserPassword(null);
+            if (passwordSet) {
+                Biff8EncryptionKey.setCurrentUserPassword(null);
+            }
         }
     }
 
index faae5bacbdfea740ae956e5012c6d8bc56504260..94a3fc023dd2be02a12be6acd9bc6e13c95f743c 100644 (file)
@@ -25,6 +25,7 @@ import java.io.PushbackInputStream;
 import java.util.ArrayList;
 import java.util.Iterator;
 
+import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.POIOLE2TextExtractor;
 import org.apache.poi.POITextExtractor;
 import org.apache.poi.POIXMLTextExtractor;
@@ -32,6 +33,7 @@ import org.apache.poi.hsmf.MAPIMessage;
 import org.apache.poi.hsmf.datatypes.AttachmentChunks;
 import org.apache.poi.hsmf.extractor.OutlookTextExtactor;
 import org.apache.poi.hssf.extractor.ExcelExtractor;
+import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
 import org.apache.poi.hwpf.extractor.WordExtractor;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
 import org.apache.poi.openxml4j.opc.OPCPackage;
@@ -39,6 +41,8 @@ import org.apache.poi.openxml4j.opc.PackageAccess;
 import org.apache.poi.openxml4j.opc.PackagePart;
 import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
 import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
+import org.apache.poi.poifs.crypt.Decryptor;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
 import org.apache.poi.poifs.filesystem.DirectoryEntry;
 import org.apache.poi.poifs.filesystem.DirectoryNode;
 import org.apache.poi.poifs.filesystem.DocumentFactoryHelper;
@@ -127,6 +131,9 @@ public class ExtractorFactory {
         NPOIFSFileSystem fs = null;
         try {
             fs = new NPOIFSFileSystem(f);
+            if (fs.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) {
+                return createEncyptedOOXMLExtractor(fs);
+            }
             POIOLE2TextExtractor extractor = createExtractor(fs);
             extractor.setFilesystem(fs);
             return extractor;
@@ -171,7 +178,9 @@ public class ExtractorFactory {
         }
 
         if (NPOIFSFileSystem.hasPOIFSHeader(inp)) {
-            return createExtractor(new NPOIFSFileSystem(inp));
+            NPOIFSFileSystem fs = new NPOIFSFileSystem(inp);
+            boolean isEncrypted = fs.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY); 
+            return isEncrypted ? createEncyptedOOXMLExtractor(fs) : createExtractor(fs);
         }
         if (DocumentFactoryHelper.hasOOXMLHeader(inp)) {
             return createExtractor(OPCPackage.open(inp));
@@ -397,4 +406,29 @@ public class ExtractorFactory {
     public static POITextExtractor[] getEmbededDocsTextExtractors(POIXMLTextExtractor ext) {
         throw new IllegalStateException("Not yet supported");
     }
+    
+    private static POIXMLTextExtractor createEncyptedOOXMLExtractor(NPOIFSFileSystem fs)
+    throws IOException {
+        String pass = Biff8EncryptionKey.getCurrentUserPassword();
+        if (pass == null) {
+            pass = Decryptor.DEFAULT_PASSWORD;
+        }
+        
+        EncryptionInfo ei = new EncryptionInfo(fs);
+        Decryptor dec = ei.getDecryptor();
+        InputStream is = null;
+        try {
+            if (!dec.verifyPassword(pass)) {
+                throw new EncryptedDocumentException("Invalid password specified - use Biff8EncryptionKey.setCurrentUserPassword() before calling extractor");
+            }
+            is = dec.getDataStream(fs);
+            return createExtractor(OPCPackage.open(is));
+        } catch (IOException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new EncryptedDocumentException(e);
+        } finally {
+            IOUtils.closeQuietly(is);
+        }
+    }
 }
index 312642ffe22d6af599545194afa3c3e697a1248a..cb97ad252a4c9e42cfbac4050e6f37869cc2cf9d 100644 (file)
@@ -92,13 +92,17 @@ public class WorkbookFactory {
 
         // If we get here, it isn't an encrypted XLSX file
         // So, treat it as a regular HSSF XLS one
+        boolean passwordSet = false;
         if (password != null) {
             Biff8EncryptionKey.setCurrentUserPassword(password);
+            passwordSet = true;
         }
         try {
             return new HSSFWorkbook(root, true);
         } finally {
-            Biff8EncryptionKey.setCurrentUserPassword(null);
+            if (passwordSet) {
+                Biff8EncryptionKey.setCurrentUserPassword(null);
+            }
         }
     }