You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by on...@apache.org on 2016/10/09 12:58:46 UTC
svn commit: r1763969 - in /poi/trunk/src/ooxml:
java/org/apache/poi/openxml4j/util/ testcases/org/apache/poi/poifs/crypt/
testcases/org/apache/poi/xssf/streaming/
Author: onealj
Date: Sun Oct 9 12:58:46 2016
New Revision: 1763969
URL: http://svn.apache.org/viewvc?rev=1763969&view=rev
Log:
bug 60153: patch from PJ Fanning to demonstrate that SXSSFWorkbook SheetDataWriter can write encrypted temporary files to disk and the workbook can be AES encrypted when written to disk for a fully secure disk environment
Added:
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/streaming/TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource.java (with props)
Modified:
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipEntrySource.java
poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/AesZipFileZipEntrySource.java
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbookWithCustomZipEntrySource.java
Modified: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipEntrySource.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipEntrySource.java?rev=1763969&r1=1763968&r2=1763969&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipEntrySource.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipEntrySource.java Sun Oct 9 12:58:46 2016
@@ -16,6 +16,7 @@
==================================================================== */
package org.apache.poi.openxml4j.util;
+import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
@@ -28,7 +29,7 @@ import java.util.zip.ZipEntry;
* needing to worry about ZipFile vs ZipInputStream
* being annoyingly very different.
*/
-public interface ZipEntrySource {
+public interface ZipEntrySource extends Closeable {
/**
* Returns an Enumeration of all the Entries
*/
@@ -44,6 +45,7 @@ public interface ZipEntrySource {
* Indicates we are done with reading, and
* resources may be freed
*/
+ @Override
public void close() throws IOException;
/**
Modified: poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/AesZipFileZipEntrySource.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/AesZipFileZipEntrySource.java?rev=1763969&r1=1763968&r2=1763969&view=diff
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/AesZipFileZipEntrySource.java (original)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/AesZipFileZipEntrySource.java Sun Oct 9 12:58:46 2016
@@ -69,8 +69,10 @@ public class AesZipFileZipEntrySource im
@Override
public void close() throws IOException {
- zipFile.close();
- tmpFile.delete();
+ if(!closed) {
+ zipFile.close();
+ tmpFile.delete();
+ }
closed = true;
}
Added: poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/streaming/TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/streaming/TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource.java?rev=1763969&view=auto
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/streaming/TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource.java (added)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/streaming/TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource.java Sun Oct 9 12:58:46 2016
@@ -0,0 +1,49 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.xssf.streaming;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.xssf.streaming.TestSXSSFWorkbookWithCustomZipEntrySource.SXSSFWorkbookWithCustomZipEntrySource;
+import org.apache.poi.xssf.streaming.TestSXSSFWorkbookWithCustomZipEntrySource.SheetDataWriterWithDecorator;
+
+// a class to record a list of temporary files that are written to disk
+// afterwards, a test function can check whether these files were encrypted or not
+public class TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource extends SXSSFWorkbookWithCustomZipEntrySource {
+
+ private final List<File> tempFiles = new ArrayList<File>();
+
+ List<File> getTempFiles() {
+ return new ArrayList<File>(tempFiles);
+ }
+
+ @Override
+ protected SheetDataWriter createSheetDataWriter() throws IOException {
+ return new TempFileRecordingSheetDataWriterWithDecorator();
+ }
+
+ class TempFileRecordingSheetDataWriterWithDecorator extends SheetDataWriterWithDecorator {
+
+ TempFileRecordingSheetDataWriterWithDecorator() throws IOException {
+ super();
+ tempFiles.add(getTempFile());
+ }
+ }
+}
\ No newline at end of file
Propchange: poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/streaming/TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbookWithCustomZipEntrySource.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbookWithCustomZipEntrySource.java?rev=1763969&r1=1763968&r2=1763969&view=diff
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbookWithCustomZipEntrySource.java (original)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbookWithCustomZipEntrySource.java Sun Oct 9 12:58:46 2016
@@ -19,10 +19,14 @@
package org.apache.poi.xssf.streaming;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -30,19 +34,25 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.SecretKeySpec;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.util.ZipEntrySource;
import org.apache.poi.poifs.crypt.AesZipFileZipEntrySource;
import org.apache.poi.poifs.crypt.ChainingMode;
import org.apache.poi.poifs.crypt.CipherAlgorithm;
import org.apache.poi.poifs.crypt.CryptoFunctions;
+import org.apache.poi.util.IOUtils;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
+import org.apache.poi.util.TempFile;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
@@ -54,11 +64,13 @@ import org.junit.Test;
* is encrypted, but the final saved workbook is not encrypted
*/
public final class TestSXSSFWorkbookWithCustomZipEntrySource {
-
+
+ final String sheetName = "TestSheet1";
+ final String cellValue = "customZipEntrySource";
+
+ // write an unencrypted workbook to disk, but any temporary files are encrypted
@Test
- public void customZipEntrySource() throws IOException, GeneralSecurityException {
- final String sheetName = "TestSheet1";
- final String cellValue = "customZipEntrySource";
+ public void customZipEntrySource() throws IOException {
SXSSFWorkbookWithCustomZipEntrySource workbook = new SXSSFWorkbookWithCustomZipEntrySource();
SXSSFSheet sheet1 = workbook.createSheet(sheetName);
SXSSFRow row1 = sheet1.createRow(1);
@@ -77,6 +89,54 @@ public final class TestSXSSFWorkbookWith
xwb.close();
}
+ // write an encrypted workbook to disk, and encrypt any temporary files as well
+ @Test
+ public void customZipEntrySourceForWriteAndRead() throws IOException, GeneralSecurityException, InvalidFormatException {
+ SXSSFWorkbookWithCustomZipEntrySource workbook = new SXSSFWorkbookWithCustomZipEntrySource();
+ SXSSFSheet sheet1 = workbook.createSheet(sheetName);
+ SXSSFRow row1 = sheet1.createRow(1);
+ SXSSFCell cell1 = row1.createCell(1);
+ cell1.setCellValue(cellValue);
+ EncryptedTempData tempData = new EncryptedTempData();
+ workbook.write(tempData.getOutputStream());
+ workbook.close();
+ workbook.dispose();
+ ZipEntrySource zipEntrySource = AesZipFileZipEntrySource.createZipEntrySource(tempData.getInputStream());
+ tempData.dispose();
+ OPCPackage opc = OPCPackage.open(zipEntrySource);
+ XSSFWorkbook xwb = new XSSFWorkbook(opc);
+ zipEntrySource.close();
+ XSSFSheet xs1 = xwb.getSheetAt(0);
+ assertEquals(sheetName, xs1.getSheetName());
+ XSSFRow xr1 = xs1.getRow(1);
+ XSSFCell xc1 = xr1.getCell(1);
+ assertEquals(cellValue, xc1.getStringCellValue());
+ xwb.close();
+ opc.close();
+ }
+
+ @Test
+ public void validateTempFilesAreEncrypted() throws IOException {
+ TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource workbook = new TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource();
+ SXSSFSheet sheet1 = workbook.createSheet(sheetName);
+ SXSSFRow row1 = sheet1.createRow(1);
+ SXSSFCell cell1 = row1.createCell(1);
+ cell1.setCellValue(cellValue);
+ ByteArrayOutputStream os = new ByteArrayOutputStream(8192);
+ workbook.write(os);
+ workbook.close();
+ List<File> tempFiles = workbook.getTempFiles();
+ assertEquals(1, tempFiles.size());
+ File tempFile = tempFiles.get(0);
+ assertTrue("tempFile exists?", tempFile.exists());
+ byte[] data = IOUtils.toByteArray(new FileInputStream(tempFile));
+ String text = new String(data, UTF_8);
+ assertFalse(text.contains(sheetName));
+ assertFalse(text.contains(cellValue));
+ workbook.dispose();
+ assertFalse("tempFile deleted after dispose?", tempFile.exists());
+ }
+
static class SXSSFWorkbookWithCustomZipEntrySource extends SXSSFWorkbook {
private static final POILogger logger = POILogFactory.getLogger(SXSSFWorkbookWithCustomZipEntrySource.class);
@@ -84,17 +144,19 @@ public final class TestSXSSFWorkbookWith
@Override
public void write(OutputStream stream) throws IOException {
flushSheets();
- ByteArrayOutputStream os = new ByteArrayOutputStream();
+ EncryptedTempData tempData = new EncryptedTempData();
+ OutputStream os = tempData.getOutputStream();
getXSSFWorkbook().write(os);
+ os.close();
ZipEntrySource source = null;
try {
// provide ZipEntrySource to poi which decrypts on the fly
- source = AesZipFileZipEntrySource.createZipEntrySource(new ByteArrayInputStream(os.toByteArray()));
+ source = AesZipFileZipEntrySource.createZipEntrySource(tempData.getInputStream());
injectData(source, stream);
} catch (GeneralSecurityException e) {
throw new IOException(e);
} finally {
- source.close();
+ IOUtils.closeQuietly(source);
}
}
@@ -107,6 +169,7 @@ public final class TestSXSSFWorkbookWith
}
}
+
static class SheetDataWriterWithDecorator extends SheetDataWriter {
final static CipherAlgorithm cipherAlgorithm = CipherAlgorithm.aes128;
SecretKeySpec skeySpec;
@@ -141,4 +204,37 @@ public final class TestSXSSFWorkbookWith
}
}
+
+ // a class to save and read an AES-encrypted workbook
+ static class EncryptedTempData {
+ final static CipherAlgorithm cipherAlgorithm = CipherAlgorithm.aes128;
+ final SecretKeySpec skeySpec;
+ final byte[] ivBytes;
+ final File tempFile;
+
+ EncryptedTempData() throws IOException {
+ SecureRandom sr = new SecureRandom();
+ ivBytes = new byte[16];
+ byte[] keyBytes = new byte[16];
+ sr.nextBytes(ivBytes);
+ sr.nextBytes(keyBytes);
+ skeySpec = new SecretKeySpec(keyBytes, cipherAlgorithm.jceId);
+ tempFile = TempFile.createTempFile("poi-temp-data", ".tmp");
+ }
+
+ OutputStream getOutputStream() throws IOException {
+ Cipher ciEnc = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, ChainingMode.cbc, ivBytes, Cipher.ENCRYPT_MODE, null);
+ return new CipherOutputStream(new FileOutputStream(tempFile), ciEnc);
+ }
+
+ InputStream getInputStream() throws IOException {
+ Cipher ciDec = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, ChainingMode.cbc, ivBytes, Cipher.DECRYPT_MODE, null);
+ return new CipherInputStream(new FileInputStream(tempFile), ciDec);
+ }
+
+ void dispose() {
+ tempFile.delete();
+ }
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org