Author: kiwiwings
Date: Thu Sep 4 22:50:28 2014
New Revision: 1622577
URL: http://svn.apache.org/r1622577
Log:
Bug 51483 - XSSF locking of specific features not working
Added some documentation to the crypto functions and adapted xor1verifier code
to the OFFCrypto-Docs
Added:
poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPaswordHelper.java
poi/trunk/test-data/spreadsheet/workbookProtection-sheet_password-2013.xlsx
(with props)
poi/trunk/test-data/spreadsheet/workbookProtection-workbook_password-2013.xlsx
(with props)
poi/trunk/test-data/spreadsheet/workbookProtection-workbook_password_user_range-2010.xlsx
(with props)
Modified:
poi/site/src/documentation/content/xdocs/status.xml
poi/trunk/src/java/org/apache/poi/hssf/record/PasswordRecord.java
poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/WorksheetProtectionBlock.java
poi/trunk/src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java
poi/trunk/src/java/org/apache/poi/poifs/crypt/HashAlgorithm.java
poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/TestSheetProtection.java
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/TestWorkbookProtection.java
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
Modified: poi/site/src/documentation/content/xdocs/status.xml
URL:
http://svn.apache.org/viewvc/poi/site/src/documentation/content/xdocs/status.xml?rev=1622577&r1=1622576&r2=1622577&view=diff
==============================================================================
--- poi/site/src/documentation/content/xdocs/status.xml (original)
+++ poi/site/src/documentation/content/xdocs/status.xml Thu Sep 4 22:50:28 2014
@@ -38,6 +38,7 @@
</devs>
<release version="3.11-beta3" date="2014-??-??">
+ <action dev="PD" type="fix" fixes-bug="51483">XSSF locking of specific
features not working</action>
<action dev="PD" type="fix" fixes-bug="48195">Formulas: Fix incorrect
evaluation of IF() with ROW()/COLUMN() as else-result.</action>
<action dev="PD" type="fix" fixes-bug="55280">XSSF: Greatly improve
performance of shifting rows in sheets with many merged regions.</action>
<action dev="PD" type="fix" fixes-bug="51222">XSSFColor.getARGBHex()
returns wrong color for Excel 2007 xlsx file</action>
Modified: poi/trunk/src/java/org/apache/poi/hssf/record/PasswordRecord.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/PasswordRecord.java?rev=1622577&r1=1622576&r2=1622577&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/PasswordRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/PasswordRecord.java Thu Sep
4 22:50:28 2014
@@ -17,6 +17,7 @@
package org.apache.poi.hssf.record;
+import org.apache.poi.poifs.crypt.CryptoFunctions;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;
@@ -39,23 +40,13 @@ public final class PasswordRecord extend
field_1_password = in.readShort();
}
- //this is the world's lamest "security". thanks to Wouter van Vugt for
making me
- //not have to try real hard. -ACO
+ /**
+ * Return the password hash
+ *
+ * @deprecated use {@link CryptoFunctions#createXorVerifier1(String)}
+ */
public static short hashPassword(String password) {
- byte[] passwordCharacters = password.getBytes();
- int hash = 0;
- if (passwordCharacters.length > 0) {
- int charIndex = passwordCharacters.length;
- while (charIndex-- > 0) {
- hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
- hash ^= passwordCharacters[charIndex];
- }
- // also hash with charcount
- hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
- hash ^= passwordCharacters.length;
- hash ^= (0x8000 | ('N' << 8) | 'K');
- }
- return (short)hash;
+ return (short)CryptoFunctions.createXorVerifier1(password);
}
/**
Modified:
poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/WorksheetProtectionBlock.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/WorksheetProtectionBlock.java?rev=1622577&r1=1622576&r2=1622577&view=diff
==============================================================================
---
poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/WorksheetProtectionBlock.java
(original)
+++
poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/WorksheetProtectionBlock.java
Thu Sep 4 22:50:28 2014
@@ -24,6 +24,7 @@ import org.apache.poi.hssf.record.Protec
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.hssf.record.ScenarioProtectRecord;
+import org.apache.poi.poifs.crypt.CryptoFunctions;
/**
* Groups the sheet protection records for a worksheet.
@@ -186,7 +187,7 @@ public final class WorksheetProtectionBl
ProtectRecord prec = getProtect();
PasswordRecord pass = getPassword();
prec.setProtect(true);
- pass.setPassword(PasswordRecord.hashPassword(password));
+
pass.setPassword((short)CryptoFunctions.createXorVerifier1(password));
if (_objectProtectRecord == null && shouldProtectObjects) {
ObjectProtectRecord rec = createObjectProtect();
rec.setProtect(true);
Modified: poi/trunk/src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java?rev=1622577&r1=1622576&r2=1622577&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java
(original)
+++ poi/trunk/src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java Thu Sep
4 22:50:28 2014
@@ -180,14 +180,20 @@ public class CryptoFunctions {
}
/**
- *
+ * Initialize a new cipher object with the given cipher properties
+ * If the given algorithm is not implemented in the JCE, it will try to
load it from the bouncy castle
+ * provider.
*
- * @param key
- * @param chain
- * @param vec
+ * @param key the secrect key
+ * @param cipherAlgorithm the cipher algorithm
+ * @param chain the chaining mode
+ * @param vec the initialization vector (IV), can be null
* @param cipherMode Cipher.DECRYPT_MODE or Cipher.ENCRYPT_MODE
+ * @param padding
* @return the requested cipher
* @throws GeneralSecurityException
+ * @throws EncryptedDocumentException if the initialization failed or if
an algorithm was specified,
+ * which depends on a missing bouncy castle provider
*/
public static Cipher getCipher(SecretKey key, CipherAlgorithm
cipherAlgorithm, ChainingMode chain, byte[] vec, int cipherMode, String
padding) {
int keySizeInBytes = key.getEncoded().length;
@@ -226,10 +232,26 @@ public class CryptoFunctions {
}
}
+ /**
+ * Returns a new byte array with a truncated to the given size.
+ * If the hash has less then size bytes, it will be filled with 0x36-bytes
+ *
+ * @param hash the to be truncated/filled hash byte array
+ * @param size the size of the returned byte array
+ * @return the padded hash
+ */
public static byte[] getBlock36(byte[] hash, int size) {
return getBlockX(hash, size, (byte)0x36);
}
+ /**
+ * Returns a new byte array with a truncated to the given size.
+ * If the hash has less then size bytes, it will be filled with 0-bytes
+ *
+ * @param hash the to be truncated/filled hash byte array
+ * @param size the size of the returned byte array
+ * @return the padded hash
+ */
public static byte[] getBlock0(byte[] hash, int size) {
return getBlockX(hash, size, (byte)0);
}
@@ -331,11 +353,11 @@ public class CryptoFunctions {
byte[] generatedKey = new byte[4];
//Maximum length of the password is 15 chars.
- final int intMaxPasswordLength = 15;
+ final int maxPasswordLength = 15;
if (!"".equals(password)) {
// Truncate the password to 15 characters
- password = password.substring(0, Math.min(password.length(),
intMaxPasswordLength));
+ password = password.substring(0, Math.min(password.length(),
maxPasswordLength));
// Construct a new NULL-terminated string consisting of
single-byte characters:
// -- > Get the single-byte values by iterating through the
Unicode characters of the truncated Password.
@@ -359,7 +381,7 @@ public class CryptoFunctions {
// the most significant, if the bit is set, XOR the keys
high-order word with the corresponding word from
// the Encryption Matrix
for (int i = 0; i < arrByteChars.length; i++) {
- int tmp = intMaxPasswordLength - arrByteChars.length + i;
+ int tmp = maxPasswordLength - arrByteChars.length + i;
for (int intBit = 0; intBit < 7; intBit++) {
if ((arrByteChars[i] & (0x0001 << intBit)) != 0) {
highOrderWord ^= EncryptionMatrix[tmp][intBit];
@@ -369,22 +391,28 @@ public class CryptoFunctions {
// Compute the low-order word of the new key:
- // Initialize with 0
- int lowOrderWord = 0;
+ // SET Verifier TO 0x0000
+ short verifier = 0;
- // For each character in the password, going backwards
- for (int i = arrByteChars.length - 1; i >= 0; i--) {
- // low-order word = (((low-order word SHR 14) AND 0x0001) OR
(low-order word SHL 1) AND 0x7FFF)) XOR character
- lowOrderWord = (((lowOrderWord >> 14) & 0x0001) |
((lowOrderWord << 1) & 0x7FFF)) ^ arrByteChars[i];
+ // FOR EACH PasswordByte IN PasswordArray IN REVERSE ORDER
+ for (int i = arrByteChars.length-1; i >= 0; i--) {
+ // SET Verifier TO Intermediate3 BITWISE XOR PasswordByte
+ verifier = rotateLeftBase15Bit(verifier);
+ verifier ^= arrByteChars[i];
}
- // Lastly,low-order word = (((low-order word SHR 14) AND 0x0001)
OR (low-order word SHL 1) AND 0x7FFF)) XOR password length XOR 0xCE4B.
- lowOrderWord = (((lowOrderWord >> 14) & 0x0001) | ((lowOrderWord
<< 1) & 0x7FFF)) ^ arrByteChars.length ^ 0xCE4B;
+ // as we haven't prepended the password length into the input array
+ // we need to do it now separately ...
+ verifier = rotateLeftBase15Bit(verifier);
+ verifier ^= arrByteChars.length;
+
+ // RETURN Verifier BITWISE XOR 0xCE4B
+ verifier ^= 0xCE4B; // (0x8000 | ('N' << 8) | 'K')
// The byte order of the result shall be reversed [password
"Example": 0x64CEED7E becomes 7EEDCE64],
// and that value shall be hashed as defined by the attribute
values.
- LittleEndian.putShort(generatedKey, 0, (short)lowOrderWord);
+ LittleEndian.putShort(generatedKey, 0, verifier);
LittleEndian.putShort(generatedKey, 2, (short)highOrderWord);
}
@@ -421,7 +449,7 @@ public class CryptoFunctions {
* @see <a
href="http://msdn.microsoft.com/en-us/library/dd905229.aspx">2.3.7.4 Binary
Document Password Verifier Derivation Method 2</a>
*
* @param password the password
- * @return the verifier
+ * @return the verifier (actually a short value)
*/
public static int createXorVerifier1(String password) {
// the verifier for method 1 is part of the verifier for method 2
@@ -480,4 +508,25 @@ public class CryptoFunctions {
private static byte rotateLeft(byte bits, int shift) {
return (byte)(((bits & 0xff) << shift) | ((bits & 0xff) >>> (8 -
shift)));
}
+
+ private static short rotateLeftBase15Bit(short verifier) {
+ /*
+ * IF (Verifier BITWISE AND 0x4000) is 0x0000
+ * SET Intermediate1 TO 0
+ * ELSE
+ * SET Intermediate1 TO 1
+ * ENDIF
+ */
+ short intermediate1 = (short)(((verifier & 0x4000) == 0) ? 0 : 1);
+ /*
+ * SET Intermediate2 TO Verifier MULTIPLED BY 2
+ * SET most significant bit of Intermediate2 TO 0
+ */
+ short intermediate2 = (short)((verifier<<1) & 0x7FFF);
+ /*
+ * SET Intermediate3 TO Intermediate1 BITWISE OR Intermediate2
+ */
+ short intermediate3 = (short)(intermediate1 | intermediate2);
+ return intermediate3;
+ }
}
Modified: poi/trunk/src/java/org/apache/poi/poifs/crypt/HashAlgorithm.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/crypt/HashAlgorithm.java?rev=1622577&r1=1622576&r2=1622577&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/crypt/HashAlgorithm.java (original)
+++ poi/trunk/src/java/org/apache/poi/poifs/crypt/HashAlgorithm.java Thu Sep 4
22:50:28 2014
@@ -64,4 +64,11 @@ public enum HashAlgorithm {
}
throw new EncryptedDocumentException("hash algorithm not found");
}
+
+ public static HashAlgorithm fromString(String string) {
+ for (HashAlgorithm ha : values()) {
+ if (ha.ecmaString.equalsIgnoreCase(string) ||
ha.jceId.equalsIgnoreCase(string)) return ha;
+ }
+ throw new EncryptedDocumentException("hash algorithm not found");
+ }
}
\ No newline at end of file
Modified: poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java?rev=1622577&r1=1622576&r2=1622577&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
(original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java Thu
Sep 4 22:50:28 2014
@@ -17,6 +17,9 @@
package org.apache.poi.xssf.usermodel;
+import static
org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.setPassword;
+import static
org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.validatePassword;
+
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -33,7 +36,6 @@ import javax.xml.namespace.QName;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLException;
-import org.apache.poi.hssf.record.PasswordRecord;
import org.apache.poi.hssf.util.PaneInformation;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.PartAlreadyExistsException;
@@ -41,6 +43,7 @@ import org.apache.poi.openxml4j.opc.Pack
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
import org.apache.poi.openxml4j.opc.TargetMode;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.formula.FormulaShifter;
import org.apache.poi.ss.formula.SheetNameFormatter;
@@ -52,7 +55,6 @@ import org.apache.poi.ss.util.CellRefere
import org.apache.poi.ss.util.SSCellRange;
import org.apache.poi.ss.util.SheetUtil;
import org.apache.poi.util.Beta;
-import org.apache.poi.util.HexDump;
import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
@@ -1056,7 +1058,7 @@ public class XSSFSheet extends POIXMLDoc
*/
@Override
public boolean getProtect() {
- return worksheet.isSetSheetProtection() && sheetProtectionEnabled();
+ return isSheetLocked();
}
/**
@@ -1068,10 +1070,9 @@ public class XSSFSheet extends POIXMLDoc
*/
@Override
public void protectSheet(String password) {
-
- if(password != null) {
- CTSheetProtection sheetProtection =
worksheet.addNewSheetProtection();
- sheetProtection.xsetPassword(stringToExcelPassword(password));
+ if (password != null) {
+ CTSheetProtection sheetProtection = safeGetProtectionField();
+ setSheetPassword(password, null); // defaults to xor password
sheetProtection.setSheet(true);
sheetProtection.setScenarios(true);
sheetProtection.setObjects(true);
@@ -1081,19 +1082,28 @@ public class XSSFSheet extends POIXMLDoc
}
/**
- * Converts a String to a {@link STUnsignedShortHex} value that contains
the {@link PasswordRecord#hashPassword(String)}
- * value in hexadecimal format
- *
- * @param password the password string you wish convert to an {@link
STUnsignedShortHex}
- * @return {@link STUnsignedShortHex} that contains Excel hashed password
in Hex format
+ * Sets the sheet password.
+ *
+ * @param password if null, the password will be removed
+ * @param hashAlgo if null, the password will be set as XOR password
(Excel 2010 and earlier)
+ * otherwise the given algorithm is used for calculating the hash
password (Excel 2013)
*/
- private STUnsignedShortHex stringToExcelPassword(String password) {
- STUnsignedShortHex hexPassword =
STUnsignedShortHex.Factory.newInstance();
-
hexPassword.setStringValue(String.valueOf(HexDump.shortToHex(PasswordRecord.hashPassword(password))).substring(2));
- return hexPassword;
+ public void setSheetPassword(String password, HashAlgorithm hashAlgo) {
+ if (password == null && !isSheetProtectionEnabled()) return;
+ setPassword(safeGetProtectionField(), password, hashAlgo, null);
}
/**
+ * Validate the password against the stored hash, the hashing method will
be determined
+ * by the existing password attributes
+ * @return true, if the hashes match (... though original password may
differ ...)
+ */
+ public boolean validateSheetPassword(String password) {
+ if (!isSheetProtectionEnabled()) return (password == null);
+ return validatePassword(safeGetProtectionField(), password, null);
+ }
+
+ /**
* Returns the logical row ( 0-based). If you ask for a row that is not
* defined you get a null. This is to say row 4 represents the fifth row
on a sheet.
*
@@ -1546,7 +1556,7 @@ public class XSSFSheet extends POIXMLDoc
worksheet.unsetMergeCells();
}
}
-
+
/**
* Removes a number of merged regions of cells (hence letting them free)
*
@@ -2910,304 +2920,440 @@ public class XSSFSheet extends POIXMLDoc
* @return true when Autofilters are locked and the sheet is protected.
*/
public boolean isAutoFilterLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() &&
worksheet.getSheetProtection().getAutoFilter();
+ if (isSheetLocked()) {
+ return safeGetProtectionField().getAutoFilter();
+ }
+ return false;
}
/**
* @return true when Deleting columns is locked and the sheet is protected.
*/
public boolean isDeleteColumnsLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() &&
worksheet.getSheetProtection().getDeleteColumns();
+ if (isSheetLocked()) {
+ return safeGetProtectionField().getDeleteColumns();
+ }
+ return false;
}
/**
* @return true when Deleting rows is locked and the sheet is protected.
*/
public boolean isDeleteRowsLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() &&
worksheet.getSheetProtection().getDeleteRows();
+ if (isSheetLocked()) {
+ return safeGetProtectionField().getDeleteRows();
+ }
+ return false;
}
/**
* @return true when Formatting cells is locked and the sheet is protected.
*/
public boolean isFormatCellsLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() &&
worksheet.getSheetProtection().getFormatCells();
+ if (isSheetLocked()) {
+ return safeGetProtectionField().getFormatCells();
+ }
+ return false;
}
/**
* @return true when Formatting columns is locked and the sheet is
protected.
*/
public boolean isFormatColumnsLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() &&
worksheet.getSheetProtection().getFormatColumns();
+ if (isSheetLocked()) {
+ return safeGetProtectionField().getFormatColumns();
+ }
+ return false;
}
/**
* @return true when Formatting rows is locked and the sheet is protected.
*/
public boolean isFormatRowsLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() &&
worksheet.getSheetProtection().getFormatRows();
+ if (isSheetLocked()) {
+ return safeGetProtectionField().getFormatRows();
+ }
+ return false;
}
/**
* @return true when Inserting columns is locked and the sheet is
protected.
*/
public boolean isInsertColumnsLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() &&
worksheet.getSheetProtection().getInsertColumns();
+ if (isSheetLocked()) {
+ return safeGetProtectionField().getInsertColumns();
+ }
+ return false;
}
/**
* @return true when Inserting hyperlinks is locked and the sheet is
protected.
*/
public boolean isInsertHyperlinksLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() &&
worksheet.getSheetProtection().getInsertHyperlinks();
+ if (isSheetLocked()) {
+ return safeGetProtectionField().getInsertHyperlinks();
+ }
+ return false;
}
/**
* @return true when Inserting rows is locked and the sheet is protected.
*/
public boolean isInsertRowsLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() &&
worksheet.getSheetProtection().getInsertRows();
+ if (isSheetLocked()) {
+ return safeGetProtectionField().getInsertRows();
+ }
+ return false;
}
/**
* @return true when Pivot tables are locked and the sheet is protected.
*/
public boolean isPivotTablesLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() &&
worksheet.getSheetProtection().getPivotTables();
+ if (isSheetLocked()) {
+ return safeGetProtectionField().getPivotTables();
+ }
+ return false;
}
/**
* @return true when Sorting is locked and the sheet is protected.
*/
public boolean isSortLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() &&
worksheet.getSheetProtection().getSort();
+ if (isSheetLocked()) {
+ return safeGetProtectionField().getSort();
+ }
+ return false;
}
/**
* @return true when Objects are locked and the sheet is protected.
*/
public boolean isObjectsLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() &&
worksheet.getSheetProtection().getObjects();
+ if (isSheetLocked()) {
+ return safeGetProtectionField().getObjects();
+ }
+ return false;
}
/**
* @return true when Scenarios are locked and the sheet is protected.
*/
public boolean isScenariosLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() &&
worksheet.getSheetProtection().getScenarios();
+ if (isSheetLocked()) {
+ return safeGetProtectionField().getScenarios();
+ }
+ return false;
}
/**
* @return true when Selection of locked cells is locked and the sheet is
protected.
*/
public boolean isSelectLockedCellsLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() &&
worksheet.getSheetProtection().getSelectLockedCells();
+ if (isSheetLocked()) {
+ return safeGetProtectionField().getSelectLockedCells();
+ }
+ return false;
}
/**
* @return true when Selection of unlocked cells is locked and the sheet
is protected.
*/
public boolean isSelectUnlockedCellsLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() &&
worksheet.getSheetProtection().getSelectUnlockedCells();
+ if (isSheetLocked()) {
+ return safeGetProtectionField().getSelectUnlockedCells();
+ }
+ return false;
}
/**
* @return true when Sheet is Protected.
*/
public boolean isSheetLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() &&
worksheet.getSheetProtection().getSheet();
+ if (worksheet.isSetSheetProtection()) {
+ return safeGetProtectionField().getSheet();
+ }
+ return false;
}
/**
* Enable sheet protection
*/
public void enableLocking() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setSheet(true);
+ safeGetProtectionField().setSheet(true);
}
/**
* Disable sheet protection
*/
public void disableLocking() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setSheet(false);
+ safeGetProtectionField().setSheet(false);
}
/**
* Enable Autofilters locking.
- * This does not modify sheet protection status.
- * To enforce this locking, call {@link #enableLocking()}
+ * @deprecated use {@link #lockAutoFilter(boolean)}
*/
public void lockAutoFilter() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setAutoFilter(true);
+ lockAutoFilter(true);
}
/**
- * Enable Deleting columns locking.
+ * Enable or disable Autofilters locking.
* This does not modify sheet protection status.
- * To enforce this locking, call {@link #enableLocking()}
+ * To enforce this un-/locking, call {@link #disableLocking()} or {@link
#enableLocking()}
+ */
+ public void lockAutoFilter(boolean enabled) {
+ safeGetProtectionField().setAutoFilter(enabled);
+ }
+
+ /**
+ * Enable Deleting columns locking.
+ * @deprecated use {@link #lockDeleteColumns(boolean)}
*/
public void lockDeleteColumns() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setDeleteColumns(true);
+ lockDeleteColumns(true);
}
/**
- * Enable Deleting rows locking.
+ * Enable or disable Deleting columns locking.
* This does not modify sheet protection status.
- * To enforce this locking, call {@link #enableLocking()}
+ * To enforce this un-/locking, call {@link #disableLocking()} or {@link
#enableLocking()}
+ */
+ public void lockDeleteColumns(boolean enabled) {
+ safeGetProtectionField().setDeleteColumns(enabled);
+ }
+
+ /**
+ * Enable Deleting rows locking.
+ * @deprecated use {@link #lockDeleteRows(boolean)}
*/
public void lockDeleteRows() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setDeleteRows(true);
+ lockDeleteRows(true);
}
/**
- * Enable Formatting cells locking.
+ * Enable or disable Deleting rows locking.
* This does not modify sheet protection status.
- * To enforce this locking, call {@link #enableLocking()}
+ * To enforce this un-/locking, call {@link #disableLocking()} or {@link
#enableLocking()}
+ */
+ public void lockDeleteRows(boolean enabled) {
+ safeGetProtectionField().setDeleteRows(enabled);
+ }
+
+ /**
+ * Enable Formatting cells locking.
+ * @deprecated use {@link #lockFormatCells(boolean)}
*/
public void lockFormatCells() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setDeleteColumns(true);
+ lockFormatCells(true);
}
/**
- * Enable Formatting columns locking.
+ * Enable or disable Formatting cells locking.
* This does not modify sheet protection status.
- * To enforce this locking, call {@link #enableLocking()}
+ * To enforce this un-/locking, call {@link #disableLocking()} or {@link
#enableLocking()}
+ */
+ public void lockFormatCells(boolean enabled) {
+ safeGetProtectionField().setFormatCells(enabled);
+ }
+
+ /**
+ * Enable Formatting columns locking.
+ * @deprecated use {@link #lockFormatColumns(boolean)}
*/
public void lockFormatColumns() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setFormatColumns(true);
+ lockFormatColumns(true);
}
/**
- * Enable Formatting rows locking.
+ * Enable or disable Formatting columns locking.
* This does not modify sheet protection status.
- * To enforce this locking, call {@link #enableLocking()}
+ * To enforce this un-/locking, call {@link #disableLocking()} or {@link
#enableLocking()}
+ */
+ public void lockFormatColumns(boolean enabled) {
+ safeGetProtectionField().setFormatColumns(enabled);
+ }
+
+ /**
+ * Enable Formatting rows locking.
+ * @deprecated use {@link #lockFormatRows(boolean)}
*/
public void lockFormatRows() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setFormatRows(true);
+ lockFormatRows(true);
}
/**
- * Enable Inserting columns locking.
+ * Enable or disable Formatting rows locking.
* This does not modify sheet protection status.
- * To enforce this locking, call {@link #enableLocking()}
+ * To enforce this un-/locking, call {@link #disableLocking()} or {@link
#enableLocking()}
+ */
+ public void lockFormatRows(boolean enabled) {
+ safeGetProtectionField().setFormatRows(enabled);
+ }
+
+ /**
+ * Enable Inserting columns locking.
+ * @deprecated use {@link #lockInsertColumns(boolean)}
*/
public void lockInsertColumns() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setInsertColumns(true);
+ lockInsertColumns(true);
}
/**
- * Enable Inserting hyperlinks locking.
+ * Enable or disable Inserting columns locking.
* This does not modify sheet protection status.
- * To enforce this locking, call {@link #enableLocking()}
+ * To enforce this un-/locking, call {@link #disableLocking()} or {@link
#enableLocking()}
+ */
+ public void lockInsertColumns(boolean enabled) {
+ safeGetProtectionField().setInsertColumns(enabled);
+ }
+
+ /**
+ * Enable Inserting hyperlinks locking.
+ * @deprecated use {@link #lockInsertHyperlinks(boolean)}
*/
public void lockInsertHyperlinks() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setInsertHyperlinks(true);
+ lockInsertHyperlinks(true);
}
/**
- * Enable Inserting rows locking.
+ * Enable or disable Inserting hyperlinks locking.
* This does not modify sheet protection status.
- * To enforce this locking, call {@link #enableLocking()}
+ * To enforce this un-/locking, call {@link #disableLocking()} or {@link
#enableLocking()}
+ */
+ public void lockInsertHyperlinks(boolean enabled) {
+ safeGetProtectionField().setInsertHyperlinks(enabled);
+ }
+
+ /**
+ * Enable Inserting rows locking.
+ * @deprecated use {@link #lockInsertRows(boolean)}
*/
public void lockInsertRows() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setInsertRows(true);
+ lockInsertRows(true);
}
/**
- * Enable Pivot Tables locking.
+ * Enable or disable Inserting rows locking.
* This does not modify sheet protection status.
- * To enforce this locking, call {@link #enableLocking()}
+ * To enforce this un-/locking, call {@link #disableLocking()} or {@link
#enableLocking()}
+ */
+ public void lockInsertRows(boolean enabled) {
+ safeGetProtectionField().setInsertRows(enabled);
+ }
+
+ /**
+ * Enable Pivot Tables locking.
+ * @deprecated use {@link #lockPivotTables(boolean)}
*/
public void lockPivotTables() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setPivotTables(true);
+ lockPivotTables(true);
}
/**
- * Enable Sort locking.
+ * Enable or disable Pivot Tables locking.
* This does not modify sheet protection status.
- * To enforce this locking, call {@link #enableLocking()}
+ * To enforce this un-/locking, call {@link #disableLocking()} or {@link
#enableLocking()}
+ */
+ public void lockPivotTables(boolean enabled) {
+ safeGetProtectionField().setPivotTables(enabled);
+ }
+
+ /**
+ * Enable Sort locking.
+ * @deprecated use {@link #lockSort(boolean)}
*/
public void lockSort() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setSort(true);
+ lockSort(true);
}
/**
- * Enable Objects locking.
+ * Enable or disable Sort locking.
* This does not modify sheet protection status.
- * To enforce this locking, call {@link #enableLocking()}
+ * To enforce this un-/locking, call {@link #disableLocking()} or {@link
#enableLocking()}
+ */
+ public void lockSort(boolean enabled) {
+ safeGetProtectionField().setSort(enabled);
+ }
+
+ /**
+ * Enable Objects locking.
+ * @deprecated use {@link #lockObjects(boolean)}
*/
public void lockObjects() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setObjects(true);
+ lockObjects(true);
}
/**
- * Enable Scenarios locking.
+ * Enable or disable Objects locking.
* This does not modify sheet protection status.
- * To enforce this locking, call {@link #enableLocking()}
+ * To enforce this un-/locking, call {@link #disableLocking()} or {@link
#enableLocking()}
+ */
+ public void lockObjects(boolean enabled) {
+ safeGetProtectionField().setObjects(enabled);
+ }
+
+ /**
+ * Enable Scenarios locking.
+ * @deprecated use {@link #lockScenarios(boolean)}
*/
public void lockScenarios() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setScenarios(true);
+ lockScenarios(true);
}
/**
- * Enable Selection of locked cells locking.
+ * Enable or disable Scenarios locking.
* This does not modify sheet protection status.
- * To enforce this locking, call {@link #enableLocking()}
+ * To enforce this un-/locking, call {@link #disableLocking()} or {@link
#enableLocking()}
+ */
+ public void lockScenarios(boolean enabled) {
+ safeGetProtectionField().setScenarios(enabled);
+ }
+
+ /**
+ * Enable Selection of locked cells locking.
+ * @deprecated use {@link #lockSelectLockedCells(boolean)}
*/
public void lockSelectLockedCells() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setSelectLockedCells(true);
+ lockSelectLockedCells(true);
}
/**
- * Enable Selection of unlocked cells locking.
+ * Enable or disable Selection of locked cells locking.
* This does not modify sheet protection status.
- * To enforce this locking, call {@link #enableLocking()}
+ * To enforce this un-/locking, call {@link #disableLocking()} or {@link
#enableLocking()}
+ */
+ public void lockSelectLockedCells(boolean enabled) {
+ safeGetProtectionField().setSelectLockedCells(enabled);
+ }
+
+ /**
+ * Enable Selection of unlocked cells locking.
+ * @deprecated use {@link #lockSelectUnlockedCells(boolean)}
*/
public void lockSelectUnlockedCells() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setSelectUnlockedCells(true);
+ lockSelectUnlockedCells(true);
+ }
+
+ /**
+ * Enable or disable Selection of unlocked cells locking.
+ * This does not modify sheet protection status.
+ * To enforce this un-/locking, call {@link #disableLocking()} or {@link
#enableLocking()}
+ */
+ public void lockSelectUnlockedCells(boolean enabled) {
+ safeGetProtectionField().setSelectUnlockedCells(enabled);
}
- private void createProtectionFieldIfNotPresent() {
- if (worksheet.getSheetProtection() == null) {
-
worksheet.setSheetProtection(CTSheetProtection.Factory.newInstance());
+ private CTSheetProtection safeGetProtectionField() {
+ if (!isSheetProtectionEnabled()) {
+ return worksheet.addNewSheetProtection();
}
+ return worksheet.getSheetProtection();
}
- private boolean sheetProtectionEnabled() {
- return worksheet.getSheetProtection().getSheet();
+ /* package */ boolean isSheetProtectionEnabled() {
+ return (worksheet.isSetSheetProtection());
}
/* package */ boolean isCellInArrayFormulaContext(XSSFCell cell) {
Modified:
poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java?rev=1622577&r1=1622576&r2=1622577&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
(original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
Thu Sep 4 22:50:28 2014
@@ -17,6 +17,9 @@
package org.apache.poi.xssf.usermodel;
+import static
org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.setPassword;
+import static
org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.validatePassword;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -47,6 +50,7 @@ import org.apache.poi.openxml4j.opc.Pack
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.openxml4j.opc.TargetMode;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.ss.formula.SheetNameFormatter;
import org.apache.poi.ss.formula.udf.IndexedUDFFinder;
import org.apache.poi.ss.formula.udf.UDFFinder;
@@ -1736,60 +1740,108 @@ public class XSSFWorkbook extends POIXML
* Locks the structure of workbook.
*/
public void lockStructure() {
- createProtectionFieldIfNotPresent();
- workbook.getWorkbookProtection().setLockStructure(true);
+ safeGetWorkbookProtection().setLockStructure(true);
}
/**
* Unlocks the structure of workbook.
*/
public void unLockStructure() {
- createProtectionFieldIfNotPresent();
- workbook.getWorkbookProtection().setLockStructure(false);
+ safeGetWorkbookProtection().setLockStructure(false);
}
/**
* Locks the windows that comprise the workbook.
*/
public void lockWindows() {
- createProtectionFieldIfNotPresent();
- workbook.getWorkbookProtection().setLockWindows(true);
+ safeGetWorkbookProtection().setLockWindows(true);
}
/**
* Unlocks the windows that comprise the workbook.
*/
public void unLockWindows() {
- createProtectionFieldIfNotPresent();
- workbook.getWorkbookProtection().setLockWindows(false);
+ safeGetWorkbookProtection().setLockWindows(false);
}
/**
* Locks the workbook for revisions.
*/
public void lockRevision() {
- createProtectionFieldIfNotPresent();
- workbook.getWorkbookProtection().setLockRevision(true);
+ safeGetWorkbookProtection().setLockRevision(true);
}
/**
* Unlocks the workbook for revisions.
*/
public void unLockRevision() {
- createProtectionFieldIfNotPresent();
- workbook.getWorkbookProtection().setLockRevision(false);
+ safeGetWorkbookProtection().setLockRevision(false);
}
- private boolean workbookProtectionPresent() {
- return workbook.getWorkbookProtection() != null;
+ /**
+ * Sets the workbook password.
+ *
+ * @param password if null, the password will be removed
+ * @param hashAlgo if null, the password will be set as XOR password
(Excel 2010 and earlier)
+ * otherwise the given algorithm is used for calculating the hash
password (Excel 2013)
+ */
+ public void setWorkbookPassword(String password, HashAlgorithm
hashAlgo) {
+ if (password == null && !workbookProtectionPresent()) return;
+ setPassword(safeGetWorkbookProtection(), password, hashAlgo,
"workbook");
}
- private void createProtectionFieldIfNotPresent() {
- if (workbook.getWorkbookProtection() == null){
-
workbook.setWorkbookProtection(CTWorkbookProtection.Factory.newInstance());
- }
+ /**
+ * Validate the password against the stored hash, the hashing method will
be determined
+ * by the existing password attributes
+ * @return true, if the hashes match (... though original password may
differ ...)
+ */
+ public boolean validateWorkbookPassword(String password) {
+ if (!workbookProtectionPresent()) return (password == null);
+ return validatePassword(safeGetWorkbookProtection(), password,
"workbook");
+ }
+
+ /**
+ * Sets the revisions password.
+ *
+ * @param password if null, the password will be removed
+ * @param hashAlgo if null, the password will be set as XOR password
(Excel 2010 and earlier)
+ * otherwise the given algorithm is used for calculating the hash
password (Excel 2013)
+ */
+ public void setRevisionsPassword(String password, HashAlgorithm hashAlgo) {
+ if (password == null && !workbookProtectionPresent()) return;
+ setPassword(safeGetWorkbookProtection(), password, hashAlgo,
"revisions");
+ }
+
+ /**
+ * Validate the password against the stored hash, the hashing method will
be determined
+ * by the existing password attributes
+ * @return true if the hashes match (... though original password may
differ ...)
+ */
+ public boolean validateRevisionsPassword(String password) {
+ if (!workbookProtectionPresent()) return (password == null);
+ return validatePassword(safeGetWorkbookProtection(), password,
"revisions");
+ }
+
+ /**
+ * Removes the workbook protection settings
+ */
+ public void unLock() {
+ if (workbookProtectionPresent()) {
+ workbook.unsetWorkbookProtection();
+ }
+ }
+
+ private boolean workbookProtectionPresent() {
+ return workbook.isSetWorkbookProtection();
}
+ private CTWorkbookProtection safeGetWorkbookProtection() {
+ if (!workbookProtectionPresent()){
+ return workbook.addNewWorkbookProtection();
+ }
+ return workbook.getWorkbookProtection();
+ }
+
/**
*
* Returns the locator of user-defined functions.
Added:
poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPaswordHelper.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPaswordHelper.java?rev=1622577&view=auto
==============================================================================
---
poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPaswordHelper.java
(added)
+++
poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPaswordHelper.java
Thu Sep 4 22:50:28 2014
@@ -0,0 +1,128 @@
+/*
+ * ====================================================================
+ * 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.usermodel.helpers;
+
+import java.security.SecureRandom;
+import java.util.Arrays;
+
+import javax.xml.bind.DatatypeConverter;
+import javax.xml.namespace.QName;
+
+import org.apache.poi.poifs.crypt.CryptoFunctions;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.apache.xmlbeans.XmlCursor;
+import org.apache.xmlbeans.XmlObject;
+
+public class XSSFPaswordHelper {
+ /**
+ * Sets the XORed or hashed password
+ *
+ * @param xobj the xmlbeans object which contains the password attributes
+ * @param password the password, if null, the password attributes will be
removed
+ * @param hashAlgo the hash algorithm, if null the password will be XORed
+ * @param prefix the prefix of the password attributes, may be null
+ */
+ public static void setPassword(XmlObject xobj, String password,
HashAlgorithm hashAlgo, String prefix) {
+ XmlCursor cur = xobj.newCursor();
+
+ if (password == null) {
+ cur.removeAttribute(getAttrName(prefix, "password"));
+ cur.removeAttribute(getAttrName(prefix, "algorithmName"));
+ cur.removeAttribute(getAttrName(prefix, "hashValue"));
+ cur.removeAttribute(getAttrName(prefix, "saltValue"));
+ cur.removeAttribute(getAttrName(prefix, "spinCount"));
+ return;
+ }
+
+ cur.toFirstContentToken();
+ if (hashAlgo == null) {
+ int hash = CryptoFunctions.createXorVerifier1(password);
+ cur.insertAttributeWithValue(getAttrName(prefix, "password"),
Integer.toHexString(hash).toUpperCase());
+ } else {
+ SecureRandom random = new SecureRandom();
+ byte salt[] = random.generateSeed(16);
+
+ // Iterations specifies the number of times the hashing function
shall be iteratively run (using each
+ // iteration's result as the input for the next iteration).
+ int spinCount = 100000;
+
+ // Implementation Notes List:
+ // --> In this third stage, the reversed byte order legacy hash
from the second stage shall
+ // be converted to Unicode hex string representation
+ byte hash[] = CryptoFunctions.hashPassword(password, hashAlgo,
salt, spinCount, false);
+
+ cur.insertAttributeWithValue(getAttrName(prefix, "algorithmName"),
hashAlgo.jceId);
+ cur.insertAttributeWithValue(getAttrName(prefix, "hashValue"),
DatatypeConverter.printBase64Binary(hash));
+ cur.insertAttributeWithValue(getAttrName(prefix, "saltValue"),
DatatypeConverter.printBase64Binary(salt));
+ cur.insertAttributeWithValue(getAttrName(prefix, "spinCount"),
""+spinCount);
+ }
+ cur.dispose();
+ }
+
+ /**
+ * Validates the password, i.e.
+ * calculates the hash of the given password and compares it against the
stored hash
+ *
+ * @param xobj the xmlbeans object which contains the password attributes
+ * @param password the password, if null the method will always return
false,
+ * even if there's no password set
+ * @param prefix the prefix of the password attributes, may be null
+ *
+ * @return true, if the hashes match
+ */
+ public static boolean validatePassword(XmlObject xobj, String password,
String prefix) {
+ // TODO: is "velvetSweatshop" the default password?
+ if (password == null) return false;
+
+ XmlCursor cur = xobj.newCursor();
+ String xorHashVal = cur.getAttributeText(getAttrName(prefix,
"password"));
+ String algoName = cur.getAttributeText(getAttrName(prefix,
"algorithmName"));
+ String hashVal = cur.getAttributeText(getAttrName(prefix,
"hashValue"));
+ String saltVal = cur.getAttributeText(getAttrName(prefix,
"saltValue"));
+ String spinCount = cur.getAttributeText(getAttrName(prefix,
"spinCount"));
+ cur.dispose();
+
+ if (xorHashVal != null) {
+ int hash1 = Integer.parseInt(xorHashVal, 16);
+ int hash2 = CryptoFunctions.createXorVerifier1(password);
+ return hash1 == hash2;
+ } else {
+ if (hashVal == null || algoName == null || saltVal == null ||
spinCount == null) {
+ return false;
+ }
+
+ byte hash1[] = DatatypeConverter.parseBase64Binary(hashVal);
+ HashAlgorithm hashAlgo = HashAlgorithm.fromString(algoName);
+ byte salt[] = DatatypeConverter.parseBase64Binary(saltVal);
+ int spinCnt = Integer.parseInt(spinCount);
+ byte hash2[] = CryptoFunctions.hashPassword(password, hashAlgo,
salt, spinCnt, false);
+ return Arrays.equals(hash1, hash2);
+ }
+ }
+
+
+ private static QName getAttrName(String prefix, String name) {
+ if (prefix == null || "".equals(prefix)) {
+ return new QName(name);
+ } else {
+ return new
QName(prefix+Character.toUpperCase(name.charAt(0))+name.substring(1));
+ }
+ }
+}
Modified:
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/TestSheetProtection.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/TestSheetProtection.java?rev=1622577&r1=1622576&r2=1622577&view=diff
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/TestSheetProtection.java
(original)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/TestSheetProtection.java
Thu Sep 4 22:50:28 2014
@@ -16,12 +16,11 @@
==================================================================== */
package org.apache.poi.xssf;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
+import junit.framework.TestCase;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import junit.framework.TestCase;
-
public class TestSheetProtection extends TestCase {
private XSSFSheet sheet;
@@ -75,6 +74,8 @@ public class TestSheetProtection extends
assertFalse(sheet.isAutoFilterLocked());
sheet.enableLocking();
assertTrue(sheet.isAutoFilterLocked());
+ sheet.lockAutoFilter(false);
+ assertFalse(sheet.isAutoFilterLocked());
}
public void testWriteDeleteColumns() throws Exception {
@@ -83,6 +84,8 @@ public class TestSheetProtection extends
assertFalse(sheet.isDeleteColumnsLocked());
sheet.enableLocking();
assertTrue(sheet.isDeleteColumnsLocked());
+ sheet.lockDeleteColumns(false);
+ assertFalse(sheet.isDeleteColumnsLocked());
}
public void testWriteDeleteRows() throws Exception {
@@ -91,6 +94,8 @@ public class TestSheetProtection extends
assertFalse(sheet.isDeleteRowsLocked());
sheet.enableLocking();
assertTrue(sheet.isDeleteRowsLocked());
+ sheet.lockDeleteRows(false);
+ assertFalse(sheet.isDeleteRowsLocked());
}
public void testWriteFormatCells() throws Exception {
@@ -99,6 +104,8 @@ public class TestSheetProtection extends
assertFalse(sheet.isFormatCellsLocked());
sheet.enableLocking();
assertTrue(sheet.isFormatCellsLocked());
+ sheet.lockFormatCells(false);
+ assertFalse(sheet.isFormatCellsLocked());
}
public void testWriteFormatColumns() throws Exception {
@@ -107,6 +114,8 @@ public class TestSheetProtection extends
assertFalse(sheet.isFormatColumnsLocked());
sheet.enableLocking();
assertTrue(sheet.isFormatColumnsLocked());
+ sheet.lockFormatColumns(false);
+ assertFalse(sheet.isFormatColumnsLocked());
}
public void testWriteFormatRows() throws Exception {
@@ -115,6 +124,8 @@ public class TestSheetProtection extends
assertFalse(sheet.isFormatRowsLocked());
sheet.enableLocking();
assertTrue(sheet.isFormatRowsLocked());
+ sheet.lockFormatRows(false);
+ assertFalse(sheet.isFormatRowsLocked());
}
public void testWriteInsertColumns() throws Exception {
@@ -123,6 +134,8 @@ public class TestSheetProtection extends
assertFalse(sheet.isInsertColumnsLocked());
sheet.enableLocking();
assertTrue(sheet.isInsertColumnsLocked());
+ sheet.lockInsertColumns(false);
+ assertFalse(sheet.isInsertColumnsLocked());
}
public void testWriteInsertHyperlinks() throws Exception {
@@ -131,6 +144,8 @@ public class TestSheetProtection extends
assertFalse(sheet.isInsertHyperlinksLocked());
sheet.enableLocking();
assertTrue(sheet.isInsertHyperlinksLocked());
+ sheet.lockInsertHyperlinks(false);
+ assertFalse(sheet.isInsertHyperlinksLocked());
}
public void testWriteInsertRows() throws Exception {
@@ -139,6 +154,8 @@ public class TestSheetProtection extends
assertFalse(sheet.isInsertRowsLocked());
sheet.enableLocking();
assertTrue(sheet.isInsertRowsLocked());
+ sheet.lockInsertRows(false);
+ assertFalse(sheet.isInsertRowsLocked());
}
public void testWritePivotTables() throws Exception {
@@ -147,6 +164,8 @@ public class TestSheetProtection extends
assertFalse(sheet.isPivotTablesLocked());
sheet.enableLocking();
assertTrue(sheet.isPivotTablesLocked());
+ sheet.lockPivotTables(false);
+ assertFalse(sheet.isPivotTablesLocked());
}
public void testWriteSort() throws Exception {
@@ -155,6 +174,8 @@ public class TestSheetProtection extends
assertFalse(sheet.isSortLocked());
sheet.enableLocking();
assertTrue(sheet.isSortLocked());
+ sheet.lockSort(false);
+ assertFalse(sheet.isSortLocked());
}
public void testWriteObjects() throws Exception {
@@ -163,6 +184,8 @@ public class TestSheetProtection extends
assertFalse(sheet.isObjectsLocked());
sheet.enableLocking();
assertTrue(sheet.isObjectsLocked());
+ sheet.lockObjects(false);
+ assertFalse(sheet.isObjectsLocked());
}
public void testWriteScenarios() throws Exception {
@@ -171,6 +194,8 @@ public class TestSheetProtection extends
assertFalse(sheet.isScenariosLocked());
sheet.enableLocking();
assertTrue(sheet.isScenariosLocked());
+ sheet.lockScenarios(false);
+ assertFalse(sheet.isScenariosLocked());
}
public void testWriteSelectLockedCells() throws Exception {
@@ -179,6 +204,8 @@ public class TestSheetProtection extends
assertFalse(sheet.isSelectLockedCellsLocked());
sheet.enableLocking();
assertTrue(sheet.isSelectLockedCellsLocked());
+ sheet.lockSelectLockedCells(false);
+ assertFalse(sheet.isSelectLockedCellsLocked());
}
public void testWriteSelectUnlockedCells() throws Exception {
@@ -187,6 +214,8 @@ public class TestSheetProtection extends
assertFalse(sheet.isSelectUnlockedCellsLocked());
sheet.enableLocking();
assertTrue(sheet.isSelectUnlockedCellsLocked());
+ sheet.lockSelectUnlockedCells(false);
+ assertFalse(sheet.isSelectUnlockedCellsLocked());
}
public void testWriteSelectEnableLocking() throws Exception {
Modified:
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/TestWorkbookProtection.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/TestWorkbookProtection.java?rev=1622577&r1=1622576&r2=1622577&view=diff
==============================================================================
---
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/TestWorkbookProtection.java
(original)
+++
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/TestWorkbookProtection.java
Thu Sep 4 22:50:28 2014
@@ -16,42 +16,94 @@
==================================================================== */
package org.apache.poi.xssf;
-import java.io.File;
+import static org.apache.poi.xssf.XSSFTestDataSamples.openSampleWorkbook;
+import static org.apache.poi.xssf.XSSFTestDataSamples.writeOutAndReadBack;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-
-import junit.framework.TestCase;
-
-import org.apache.poi.util.TempFile;
+import org.apache.poi.poifs.crypt.CryptoFunctions;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.junit.Test;
-public class TestWorkbookProtection extends TestCase {
+public class TestWorkbookProtection {
- public void testShouldReadWorkbookProtection() throws Exception {
- XSSFWorkbook workbook =
XSSFTestDataSamples.openSampleWorkbook("workbookProtection_not_protected.xlsx");
+ @Test
+ public void workbookAndRevisionPassword() throws Exception {
+ XSSFWorkbook workbook;
+ String password = "test";
+
+ // validate password with an actual office file (Excel 2010)
+ workbook =
openSampleWorkbook("workbookProtection-workbook_password_user_range-2010.xlsx");
+ assertTrue(workbook.validateWorkbookPassword(password));
+
+ // validate with another office file (Excel 2013)
+ workbook =
openSampleWorkbook("workbookProtection-workbook_password-2013.xlsx");
+ assertTrue(workbook.validateWorkbookPassword(password));
+
+
+ workbook = openSampleWorkbook("workbookProtection_not_protected.xlsx");
+
+ // setting a null password shouldn't introduce the protection element
+ workbook.setWorkbookPassword(null, null);
+ assertNull(workbook.getCTWorkbook().getWorkbookProtection());
+
+ // compare the hashes
+ workbook.setWorkbookPassword(password, null);
+ int hashVal = CryptoFunctions.createXorVerifier1(password);
+ int actualVal =
Integer.parseInt(workbook.getCTWorkbook().getWorkbookProtection().xgetWorkbookPassword().getStringValue(),16);
+ assertEquals(hashVal, actualVal);
+ assertTrue(workbook.validateWorkbookPassword(password));
+
+ // removing the password again
+ workbook.setWorkbookPassword(null, null);
+
assertFalse(workbook.getCTWorkbook().getWorkbookProtection().isSetWorkbookPassword());
+
+ // removing the whole protection structure
+ workbook.unLock();
+ assertNull(workbook.getCTWorkbook().getWorkbookProtection());
+
+ // setting a null password shouldn't introduce the protection element
+ workbook.setRevisionsPassword(null, null);
+ assertNull(workbook.getCTWorkbook().getWorkbookProtection());
+
+ // compare the hashes
+ password = "T\u0400ST\u0100passwordWhichIsLongerThan15Chars";
+ workbook.setRevisionsPassword(password, null);
+ hashVal = CryptoFunctions.createXorVerifier1(password);
+ actualVal =
Integer.parseInt(workbook.getCTWorkbook().getWorkbookProtection().xgetRevisionsPassword().getStringValue(),16);
+ assertEquals(hashVal, actualVal);
+ assertTrue(workbook.validateRevisionsPassword(password));
+ }
+
+ @Test
+ public void shouldReadWorkbookProtection() throws Exception {
+ XSSFWorkbook workbook =
openSampleWorkbook("workbookProtection_not_protected.xlsx");
assertFalse(workbook.isStructureLocked());
assertFalse(workbook.isWindowsLocked());
assertFalse(workbook.isRevisionLocked());
- workbook =
XSSFTestDataSamples.openSampleWorkbook("workbookProtection_workbook_structure_protected.xlsx");
+ workbook =
openSampleWorkbook("workbookProtection_workbook_structure_protected.xlsx");
assertTrue(workbook.isStructureLocked());
assertFalse(workbook.isWindowsLocked());
assertFalse(workbook.isRevisionLocked());
- workbook =
XSSFTestDataSamples.openSampleWorkbook("workbookProtection_workbook_windows_protected.xlsx");
+ workbook =
openSampleWorkbook("workbookProtection_workbook_windows_protected.xlsx");
assertTrue(workbook.isWindowsLocked());
assertFalse(workbook.isStructureLocked());
assertFalse(workbook.isRevisionLocked());
- workbook =
XSSFTestDataSamples.openSampleWorkbook("workbookProtection_workbook_revision_protected.xlsx");
+ workbook =
openSampleWorkbook("workbookProtection_workbook_revision_protected.xlsx");
assertTrue(workbook.isRevisionLocked());
assertFalse(workbook.isWindowsLocked());
assertFalse(workbook.isStructureLocked());
}
- public void testShouldWriteStructureLock() throws Exception {
- XSSFWorkbook workbook =
XSSFTestDataSamples.openSampleWorkbook("workbookProtection_not_protected.xlsx");
+ @Test
+ public void shouldWriteStructureLock() throws Exception {
+ XSSFWorkbook workbook =
openSampleWorkbook("workbookProtection_not_protected.xlsx");
assertFalse(workbook.isStructureLocked());
workbook.lockStructure();
@@ -63,8 +115,9 @@ public class TestWorkbookProtection exte
assertFalse(workbook.isStructureLocked());
}
- public void testShouldWriteWindowsLock() throws Exception {
- XSSFWorkbook workbook =
XSSFTestDataSamples.openSampleWorkbook("workbookProtection_not_protected.xlsx");
+ @Test
+ public void shouldWriteWindowsLock() throws Exception {
+ XSSFWorkbook workbook =
openSampleWorkbook("workbookProtection_not_protected.xlsx");
assertFalse(workbook.isWindowsLocked());
workbook.lockWindows();
@@ -76,8 +129,9 @@ public class TestWorkbookProtection exte
assertFalse(workbook.isWindowsLocked());
}
- public void testShouldWriteRevisionLock() throws Exception {
- XSSFWorkbook workbook =
XSSFTestDataSamples.openSampleWorkbook("workbookProtection_not_protected.xlsx");
+ @Test
+ public void shouldWriteRevisionLock() throws Exception {
+ XSSFWorkbook workbook =
openSampleWorkbook("workbookProtection_not_protected.xlsx");
assertFalse(workbook.isRevisionLocked());
workbook.lockRevision();
@@ -89,22 +143,32 @@ public class TestWorkbookProtection exte
assertFalse(workbook.isRevisionLocked());
}
+ @SuppressWarnings("resource")
+ @Test
+ public void testHashPassword() throws Exception {
+ XSSFWorkbook wb = new XSSFWorkbook();
+ wb.lockRevision();
+ wb.setRevisionsPassword("test", HashAlgorithm.sha1);
+
+ wb = writeOutAndReadBack(wb);
+
+ assertTrue(wb.isRevisionLocked());
+ assertTrue(wb.validateRevisionsPassword("test"));
+ }
+
+ @SuppressWarnings("resource")
+ @Test
public void testIntegration() throws Exception {
XSSFWorkbook wb = new XSSFWorkbook();
wb.createSheet("Testing purpose sheet");
assertFalse(wb.isRevisionLocked());
wb.lockRevision();
+ wb.setRevisionsPassword("test", null);
- File tempFile = TempFile.createTempFile("workbookProtection",
".xlsx");
- FileOutputStream out = new FileOutputStream(tempFile);
- wb.write(out);
- out.close();
-
- FileInputStream inputStream = new FileInputStream(tempFile);
- XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
- inputStream.close();
-
- assertTrue(workbook.isRevisionLocked());
+ wb = writeOutAndReadBack(wb);
+
+ assertTrue(wb.isRevisionLocked());
+ assertTrue(wb.validateRevisionsPassword("test"));
}
}
Modified:
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java?rev=1622577&r1=1622576&r2=1622577&view=diff
==============================================================================
---
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
(original)
+++
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
Thu Sep 4 22:50:28 2014
@@ -19,6 +19,8 @@ package org.apache.poi.xssf.usermodel;
import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertTrue;
+import static org.apache.poi.xssf.XSSFTestDataSamples.openSampleWorkbook;
+import static org.apache.poi.xssf.XSSFTestDataSamples.writeOutAndReadBack;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
@@ -29,7 +31,8 @@ import static org.junit.Assert.fail;
import java.util.List;
import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.hssf.record.PasswordRecord;
+import org.apache.poi.poifs.crypt.CryptoFunctions;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.ss.usermodel.AutoFilter;
import org.apache.poi.ss.usermodel.BaseTestSheet;
import org.apache.poi.ss.usermodel.Cell;
@@ -41,7 +44,6 @@ import org.apache.poi.ss.usermodel.Workb
import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.util.HexDump;
import org.apache.poi.xssf.SXSSFITestDataProvider;
import org.apache.poi.xssf.XSSFITestDataProvider;
import org.apache.poi.xssf.XSSFTestDataSamples;
@@ -1068,13 +1070,27 @@ public final class TestXSSFSheet extends
assertTrue("sheet protection should be on", pr.isSetSheet());
assertTrue("object protection should be on", pr.isSetObjects());
assertTrue("scenario protection should be on", pr.isSetScenarios());
- String hash =
String.valueOf(HexDump.shortToHex(PasswordRecord.hashPassword(password))).substring(2);
- assertEquals("well known value for top secret hash should be "+ hash,
hash, pr.xgetPassword().getStringValue());
+ int hashVal = CryptoFunctions.createXorVerifier1(password);
+ int actualVal =
Integer.parseInt(pr.xgetPassword().getStringValue(),16);
+ assertEquals("well known value for top secret hash should match",
hashVal, actualVal);
sheet.protectSheet(null);
assertNull("protectSheet(null) should unset CTSheetProtection",
sheet.getCTWorksheet().getSheetProtection());
}
+ @Test
+ public void protectSheet_lowlevel_2013() {
+ String password = "test";
+ XSSFWorkbook wb = new XSSFWorkbook();
+ XSSFSheet xs = wb.createSheet();
+ xs.setSheetPassword(password, HashAlgorithm.sha384);
+ wb = writeOutAndReadBack(wb);
+ assertTrue(wb.getSheetAt(0).validateSheetPassword(password));
+
+ wb = openSampleWorkbook("workbookProtection-sheet_password-2013.xlsx");
+ assertTrue(wb.getSheetAt(0).validateSheetPassword("pwd"));
+ }
+
@Test
public void bug49966() {
Added:
poi/trunk/test-data/spreadsheet/workbookProtection-sheet_password-2013.xlsx
URL:
http://svn.apache.org/viewvc/poi/trunk/test-data/spreadsheet/workbookProtection-sheet_password-2013.xlsx?rev=1622577&view=auto
==============================================================================
Binary file - no diff available.
Propchange:
poi/trunk/test-data/spreadsheet/workbookProtection-sheet_password-2013.xlsx
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added:
poi/trunk/test-data/spreadsheet/workbookProtection-workbook_password-2013.xlsx
URL:
http://svn.apache.org/viewvc/poi/trunk/test-data/spreadsheet/workbookProtection-workbook_password-2013.xlsx?rev=1622577&view=auto
==============================================================================
Binary file - no diff available.
Propchange:
poi/trunk/test-data/spreadsheet/workbookProtection-workbook_password-2013.xlsx
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added:
poi/trunk/test-data/spreadsheet/workbookProtection-workbook_password_user_range-2010.xlsx
URL:
http://svn.apache.org/viewvc/poi/trunk/test-data/spreadsheet/workbookProtection-workbook_password_user_range-2010.xlsx?rev=1622577&view=auto
==============================================================================
Binary file - no diff available.
Propchange:
poi/trunk/test-data/spreadsheet/workbookProtection-workbook_password_user_range-2010.xlsx
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]