ODFTOOLKIT-446 - Receiving encrypted file without password should be not NULL
git-svn-id: https://svn.apache.org/repos/asf/incubator/odf/trunk@1786663 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/CHANGES.txt b/CHANGES.txt
index a244a9e..da20204 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -3,6 +3,9 @@
======= Release 0.6.2 =======
+The most notable changes in ODF Toolkit 0.6.2 incubating over previous release:
+* Supply signature and manifest features to ODFDOM
+
Release wiki page: https://cwiki.apache.org/confluence/display/ODFTOOLKIT/0.6.2-incubating
Versions of major components
@@ -19,6 +22,7 @@
* ODFTOOLKIT-200 Supply signature and manifest features to ODFDOM
* ODFTOOLKIT-294 Adding the XSL stylesheet for extracting default values to XSLT_RUNNER XSL sample folder
* ODFTOOLKIT-374 Set the field "Last Modified By" in the metadata file
+* ODFTOOLKIT-410 Set table:error-message for content-validation to activate actual validation
* ODFTOOLKIT-417 Missing methods for set and get background-color, subscripted and superscripted for a paragraph
* ODFTOOLKIT-418 missing method to find an embedded section
* ODFTOOLKIT-420 missing functions in TextProperties set/get background color
@@ -32,14 +36,13 @@
---------
* ODFTOOLKIT-300 Memory Leak in ODF Simple API
* ODFTOOLKIT-323 Remove old references to odftoolkit.org site
+* ODFTOOLKIT-367 Paragraph.getTextContent throws NullPointerException with exactly 2 spaces between words Improvement ODFTOOLKIT-365 Improve Release Process to easily publish releases with maven
* ODFTOOLKIT-368 Column.setWidth wrong size
-* ODFTOOLKIT-379 NullPointerException in Paragraph.getTextContent()
* ODFTOOLKIT-386 Project doesn't build with JDK 8
* ODFTOOLKIT-388 Test hangs when iterating over a spreadsheet created with LibreOffice 4.0.0
* ODFTOOLKIT-391 Publish ODF Toolkit artifacts to Maven Central + tag release version in SVN
* ODFTOOLKIT-395 [PATCH] validator applies ODF 1.1 rules to ODF 1.2 documents when checking character content in foreign elements
* ODFTOOLKIT-396 SpreadsheetDocument.appendSheet fails because of buggy alien element cloning
-* ODFTOOLKIT-397 DataSet cannot set values from spreadsheet if there are repeated rows before data rows
* ODFTOOLKIT-398 crash when calling getCellBackgroundColor from the org.odftoolkit.simple.table.Cell
* ODFTOOLKIT-401 NullPointerException from typo hides all ZIP exceptions
* ODFTOOLKIT-404 Obsolete Jena dependency at ODF Toolkit
diff --git a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/OdfPackage.java b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/OdfPackage.java
index b60fdc7..82d8dc9 100644
--- a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/OdfPackage.java
+++ b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/OdfPackage.java
@@ -139,8 +139,8 @@
private ErrorHandler mErrorHandler;
private String mManifestVersion;
private OdfManifestDom mManifestDom;
- private String oldPwd;
- private String newPwd;
+ private String mOldPwd;
+ private String mNewPwd;
/* Commonly used files within the ODF Package */
public enum OdfFile {
@@ -247,8 +247,8 @@
this();
mBaseURI = getBaseURLFromFile(pkgFile);
mErrorHandler = errorHandler;
- oldPwd = password;
- newPwd = oldPwd;
+ mOldPwd = password;
+ mNewPwd = mOldPwd;
mBaseURI = baseURI;
InputStream packageStream = new FileInputStream(pkgFile);
@@ -280,8 +280,8 @@
this(); // calling private constructor
mErrorHandler = errorHandler;
mBaseURI = baseURI;
- oldPwd = password;
- newPwd = oldPwd;
+ mOldPwd = password;
+ mNewPwd = mOldPwd;
initializeZip(packageStream);
}
@@ -382,6 +382,23 @@
*
* @param pkgFile - the ODF Package. A baseURL is being generated based on its location.
* @param password - the ODF Package password.
+ * @throws SAXException if there's an XML- or validation-related error while loading the package
+ * @throws IOException if there's an I/O error while loading the package
+ * @see #getErrorHandler
+ */
+ public static OdfPackage loadPackage(File pkgFile, String password) throws SAXException, IOException {
+ return OdfPackage.loadPackage(pkgFile, password, null);
+ }
+
+ /**
+ * Loads an OdfPackage from the given File.
+ * <p>
+ * OdfPackage relies on the file being available for read access over the whole lifecycle of
+ * OdfPackage.
+ * </p>
+ *
+ * @param pkgFile - the ODF Package. A baseURL is being generated based on its location.
+ * @param password - the ODF Package password.
* @param errorHandler - SAX ErrorHandler used for ODF validation.
* @throws SAXException if there's an XML- or validation-related error while loading the package
* @throws IOException if there's an I/O error while loading the package
@@ -804,9 +821,14 @@
return mPkgDocuments.keySet();
}
- public OdfPackageDocument getRootDocument() {
- return mPkgDocuments.get(OdfPackageDocument.ROOT_DOCUMENT_PATH);
- }
+ public OdfPackageDocument getRootDocument() {
+ OdfPackageDocument odfPackageDocument = null;
+ odfPackageDocument = mPkgDocuments.get(OdfPackageDocument.ROOT_DOCUMENT_PATH);
+ if (odfPackageDocument == null) {
+ odfPackageDocument = this.loadDocument(OdfPackageDocument.ROOT_DOCUMENT_PATH);
+ }
+ return odfPackageDocument;
+ }
public OdfManifestDom getManifestDom() {
return mManifestDom;
@@ -943,7 +965,7 @@
* @since 0.8.9
*/
public void setPassword(String password) {
- newPwd = password;
+ mNewPwd = password;
}
/**
@@ -1064,7 +1086,7 @@
* @return true if the file needs encrypted, false, otherwise
*/
private boolean fileNeedsEncryption(String internalPath) {
- if (newPwd != null) {
+ if (mNewPwd != null) {
// ODF spec does not allow encrytion of "./mimetype" file
if (internalPath.endsWith(SLASH) || OdfFile.MANIFEST.getPath().equals(internalPath) || OdfPackage.OdfFile.MEDIA_TYPE.getPath().equals(internalPath)) {
return false;
@@ -1688,7 +1710,12 @@
OdfFileEntry manifestEntry = getManifestEntries().get(internalPath);
EncryptionDataElement encryptionDataElement = manifestEntry.getEncryptionData();
if (encryptionDataElement != null) {
- data = decryptData(data, manifestEntry, encryptionDataElement);
+ byte[] newData = decryptData(data, manifestEntry, encryptionDataElement);
+ if(newData != null){
+ data = newData;
+ }else{
+ Logger.getLogger(OdfPackage.class.getName()).log(Level.SEVERE, null, "Wrong password being used for decryption!");
+ }
}
}
// store for further usage; do not care about manifest:
@@ -1730,7 +1757,7 @@
// 3. The start key is generated: the byte sequence
// representing the password in UTF-8 is used to
// generate a 20-byte SHA1 digest.
- byte[] passBytes = newPwd.getBytes("UTF-8");
+ byte[] passBytes = mNewPwd.getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("SHA1");
passBytes = md.digest(passBytes);
// 4. Checksum specifies a digest in BASE64 encoding
@@ -1838,7 +1865,7 @@
String checksum = encryptionDataElement.getChecksumAttribute();
byte[] salt = Base64Binary.valueOf(saltStr).getBytes();
byte[] iv = Base64Binary.valueOf(ivStr).getBytes();
- byte[] passBytes = oldPwd.getBytes("UTF-8");
+ byte[] passBytes = mOldPwd.getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("SHA-1");
passBytes = md.digest(passBytes);
/*
diff --git a/odfdom/src/test/java/org/odftoolkit/odfdom/pkg/PackageTest.java b/odfdom/src/test/java/org/odftoolkit/odfdom/pkg/PackageTest.java
index 58be527..479d24e 100644
--- a/odfdom/src/test/java/org/odftoolkit/odfdom/pkg/PackageTest.java
+++ b/odfdom/src/test/java/org/odftoolkit/odfdom/pkg/PackageTest.java
@@ -1,20 +1,20 @@
/************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
- *
+ *
* Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
- *
+ *
* Use is subject to license terms.
- *
+ *
* Licensed 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. You can also
* obtain a copy of the License at http://odftoolkit.org/docs/license.txt
- *
+ *
* 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.
*
@@ -35,14 +35,12 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
-
import javax.xml.transform.Templates;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
-
import junit.framework.Assert;
-
+import static org.junit.Assert.fail;
import org.junit.Test;
import org.odftoolkit.odfdom.doc.OdfDocument;
import org.odftoolkit.odfdom.doc.OdfPresentationDocument;
@@ -60,7 +58,7 @@
import org.xml.sax.helpers.DefaultHandler;
public class PackageTest {
-
+
private static final Logger LOG = Logger.getLogger(PackageTest.class.getName());
private static final String mImagePath = "src/main/javadoc/doc-files/";
private static final String mImageName = "ODFDOM-Layered-Model.png";
@@ -77,10 +75,10 @@
private static final String TARGET_STEP_1 = "PackageLoadTestStep1.ods";
private static final String TARGET_STEP_2 = "PackageLoadTestStep2.ods";
private static final String TARGET_STEP_3 = "PackageLoadTestStep3.ods";
-
+
public PackageTest() {
}
-
+
@Test
public void testNotCompressImages() throws Exception {
// create test presentation
@@ -91,7 +89,7 @@
OdfDrawImage image = (OdfDrawImage) frame.newDrawImageElement();
image.newImage(ResourceUtilities.getURI(IMAGE_TEST_FILE));
odp.save(ResourceUtilities.newTestOutputFile(IMAGE_PRESENTATION));
-
+
// test if the image is not compressed
ZipInputStream zinput = new ZipInputStream(ResourceUtilities.getTestResourceAsStream(IMAGE_PRESENTATION));
ZipEntry entry = zinput.getNextEntry();
@@ -105,16 +103,16 @@
entry = zinput.getNextEntry();
}
}
-
+
@Test
public void loadPackage() {
try {
-
+
// LOAD PACKAGE FORMULA
LOG.info("Loading an unsupported ODF Formula document as an ODF Package!");
OdfPackage formulaPackage = OdfPackage.loadPackage(ResourceUtilities.getAbsolutePath(ODF_FORMULAR_TEST_FILE));
Assert.assertNotNull(formulaPackage);
-
+
// LOAD PACKAGE IMAGE
LOG.info("Loading an unsupported image file as an ODF Package!");
try {
@@ -128,7 +126,7 @@
Assert.fail();
}
}
-
+
// LOAD PACKAGE IMAGE (WITH ERROR HANDLER)
LOG.info("Loading an unsupported image file as an ODF Package (with error handler)!");
try {
@@ -147,7 +145,7 @@
Assert.fail(e.getMessage());
}
}
-
+
@Test
public void testPackage() {
File tmpFile1 = ResourceUtilities.newTestOutputFile(TARGET_STEP_1);
@@ -162,18 +160,18 @@
LOG.log(Level.SEVERE, mImagePath, ex);
Assert.fail();
}
-
+
long lengthBefore = tmpFile1.length();
try {
// not allowed to change the document simply by open and save
OdfPackage odfPackage = OdfPackage.loadPackage(tmpFile1);
-
+
URI imageURI = new URI(mImagePath + mImageName);
// testing encoded none ASCII in URL path
String pkgRef1 = AnyURI.encodePath("Pictures/a&b.jpg");
LOG.log(Level.INFO, "Attempt to write graphic to package path: {0}", pkgRef1);
odfPackage.insert(uri2ByteArray(imageURI), pkgRef1, mImageMediaType);
-
+
// testing allowed none-ASCII in URL path (see rfc1808.txt)
String pkgRef2 = "Pictures/a&%" + "\u00ea" + "\u00f1" + "\u00fc" + "b.jpg";
LOG.log(Level.INFO, "Attempt to write graphic to package path: {0}", pkgRef2);
@@ -188,16 +186,16 @@
odfPackage.save(tmpFile3);
long lengthAfter3 = tmpFile3.length();
odfPackage.close();
-
+
// the package without the images should be as long as before
Assert.assertTrue("The files \n\t" + tmpFile1.getAbsolutePath() + " and \n\t" + tmpFile3.getAbsolutePath() + " differ!", lengthBefore == lengthAfter3);
-
+
} catch (Exception ex) {
LOG.log(Level.SEVERE, mImagePath, ex);
Assert.fail();
}
}
-
+
private static byte[] uri2ByteArray(URI uri) {
byte[] fileBytes = null;
try {
@@ -222,7 +220,7 @@
}
return fileBytes;
}
-
+
/**
* Testing the XML helper and the OdfPackage to handle two files at the same
* time (have them open)
@@ -247,9 +245,9 @@
Logger.getLogger(PackageTest.class.getName()).log(Level.SEVERE, t.getMessage(), t);
Assert.fail();
}
-
+
}
-
+
@Test
public void validationTestDefault() {
try {
@@ -260,7 +258,7 @@
LOG.log(Level.SEVERE, null, ex);
Assert.fail();
}
-
+
// default no error handler: fatal errors are reported
try {
OdfPackage.loadPackage(ResourceUtilities.getAbsolutePath("testA.jpg"));
@@ -272,7 +270,7 @@
}
}
}
-
+
@Test
public void loadPackageWithoutManifest() {
try {
@@ -284,7 +282,7 @@
ZipEntry entry = new ZipEntry("someentry");
zipped.putNextEntry(entry);
zipped.close();
-
+
byte[] data = out.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(data);
OdfPackage pkg = OdfPackage.loadPackage(in);
@@ -294,14 +292,14 @@
Assert.fail();
}
}
-
+
@Test
public void validationTest() {
-
+
// TESTDOC1: Expected ODF Warnings
Map expectedWarning1 = new HashMap();
expectedWarning1.put(OdfPackageConstraint.MANIFEST_LISTS_DIRECTORY, 10);
-
+
// TESTDOC1: Expected ODF Errors
Map expectedErrors1 = new HashMap();
expectedErrors1.put(OdfPackageConstraint.MIMETYPE_NOT_FIRST_IN_PACKAGE, 1);
@@ -311,19 +309,19 @@
expectedErrors1.put(OdfPackageConstraint.MANIFEST_LISTS_NONEXISTENT_FILE, 1);
ErrorHandlerStub handler1 = new ErrorHandlerStub(expectedWarning1, expectedErrors1, null);
handler1.setTestFilePath("testInvalidPkg1.odt");
-
+
// TESTDOC2: Expected ODF Warnings
Map expectedWarning2 = new HashMap();
expectedWarning2.put(OdfPackageConstraint.MIMETYPE_NOT_IN_PACKAGE, 1);
expectedWarning2.put(OdfPackageConstraint.MANIFEST_LISTS_DIRECTORY, 10);
-
+
// TESTDOC2: Expected ODF Errors
Map expectedErrors2 = new HashMap();
expectedErrors2.put(OdfPackageConstraint.MANIFEST_DOES_NOT_LIST_FILE, 1);
expectedErrors2.put(OdfPackageConstraint.MANIFEST_LISTS_NONEXISTENT_FILE, 3);
ErrorHandlerStub handler2 = new ErrorHandlerStub(expectedWarning2, expectedErrors2, null);
handler2.setTestFilePath("testInvalidPkg2.odt");
-
+
// TESTDOC3 DESCRIPTION - only mimetype file in package
// TESTDOC3: Expected ODF Errors
Map expectedErrors3 = new HashMap();
@@ -331,13 +329,13 @@
expectedErrors3.put(OdfPackageConstraint.MIMETYPE_WITHOUT_MANIFEST_MEDIATYPE, 1);
ErrorHandlerStub handler3 = new ErrorHandlerStub(null, expectedErrors3, null);
handler3.setTestFilePath("testInvalidPkg3.odt");
-
+
// TESTDOC4: Expected ODF FatalErrors
Map<ValidationConstraint, Integer> expectedFatalErrors4 = new HashMap<ValidationConstraint, Integer>();
// loading a graphic instead an ODF document
expectedFatalErrors4.put(OdfPackageConstraint.PACKAGE_IS_NO_ZIP, 1);
ErrorHandlerStub handler4 = new ErrorHandlerStub(null, null, expectedFatalErrors4);
-
+
try {
OdfPackage pkg1 = OdfPackage.loadPackage(new File(ResourceUtilities.getAbsolutePath(handler1.getTestFilePath())), null, handler1);
Assert.assertNotNull(pkg1);
@@ -363,19 +361,37 @@
handler3.validate();
handler4.validate();
}
-
+
@Test
public void testPackagePassword() {
File tmpFile = ResourceUtilities.newTestOutputFile("PackagePassword.ods");
OdfDocument doc = null;
try {
doc = OdfSpreadsheetDocument.newSpreadsheetDocument();
- doc.getPackage().setPassword("password");
+ OdfPackage odfPackage = doc.getPackage();
+ LOG.info("Unencrypted content.xml" + odfPackage.getRootDocument().getFileDom("content.xml").toString());
+ odfPackage.setPassword("password");
doc.save(tmpFile);
doc.close();
- OdfPackage odfPackage = OdfPackage.loadPackage(tmpFile, "password", null);
+ // using wrong password
+ odfPackage = OdfPackage.loadPackage(tmpFile, "passwordx");
byte[] contentBytes = odfPackage.getBytes("content.xml");
+ // some encrypted XML
Assert.assertNotNull(contentBytes);
+ try{
+ odfPackage.getRootDocument().getFileDom("content.xml").toString();
+ fail("NullPointerException missing!");
+ }catch(NullPointerException e){
+ // as expected
+ }
+ // using correct password
+ OdfPackage odfPackage2 = OdfPackage.loadPackage(tmpFile, "password");
+ byte[] contentBytes2 = odfPackage2.getBytes("content.xml");
+ // some encrypted XML
+ Assert.assertNotNull(contentBytes2);
+ // due to XML parse errors null
+ LOG.info("Decrypted content.xml" + odfPackage2.getRootDocument().getFileDom("content.xml").toString());
+
} catch (Exception ex) {
LOG.log(Level.SEVERE, "password test failed.", ex);
Assert.fail();