You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by kr...@apache.org on 2007/05/08 12:43:52 UTC

svn commit: r536156 - in /db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests: suites/ tests/store/

Author: kristwaa
Date: Tue May  8 03:43:50 2007
New Revision: 536156

URL: http://svn.apache.org/viewvc?view=rev&rev=536156
Log:
DERBY-1001: Rewrite 'store/encryptionKey.sql' to a JUnit test.
Patch file: derby-1001-2a.diff

Added:
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyAESTest.java   (with props)
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyBlowfishTest.java   (with props)
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyDESTest.java   (with props)
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyTest.java   (with props)
Modified:
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/encryptionAll.runall
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/_Suite.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/encryptionKey.sql
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/encryptionKey_app.properties

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/encryptionAll.runall
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/encryptionAll.runall?view=diff&rev=536156&r1=536155&r2=536156
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/encryptionAll.runall (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/encryptionAll.runall Tue May  8 03:43:50 2007
@@ -1,6 +1,5 @@
 store/aes.sql
 store/encryptParams.sql
-store/encryptionKey.sql
 store/encryptDatabaseTest1.sql
 store/encryptDatabaseTest2.sql
 store/encryptDatabaseTest3.sql

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyAESTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyAESTest.java?view=auto&rev=536156
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyAESTest.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyAESTest.java Tue May  8 03:43:50 2007
@@ -0,0 +1,48 @@
+/*
+ *
+ * Derby - Class org.apache.derbyTesting.functionTests.tests.store.EncryptionKeyAESTest
+ *
+ * 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.derbyTesting.functionTests.tests.store;
+
+import org.apache.derbyTesting.junit.*;
+import junit.framework.*;
+
+/**
+ * Test basic functionality on a database encrypted with the AES algorithm.
+ *
+ * @see EncryptionKeyTest
+ */
+public class EncryptionKeyAESTest
+    extends EncryptionKeyTest {
+
+    public EncryptionKeyAESTest(String name) {
+        super(name,
+              "AES/CBC/NoPadding",
+              "616263646666768661626364666676AF",
+              "919293949999798991929394999979CA",
+              "616263646666768999616263646666768",
+              "X1X2X3X4XXXX7X8XX1X2X3X4XXXX7X8X");
+    }
+
+    public static Test suite() {
+        // This test runs only in embedded due to the use of external files.
+        TestSuite suite = new TestSuite(EncryptionKeyAESTest.class,
+                                        "EncryptionKey AES suite");
+        return new SupportFilesSetup(suite);
+    }
+} // End class EncryptionKeyAESTest

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyAESTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyBlowfishTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyBlowfishTest.java?view=auto&rev=536156
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyBlowfishTest.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyBlowfishTest.java Tue May  8 03:43:50 2007
@@ -0,0 +1,49 @@
+/*
+ *
+ * Derby - Class org.apache.derbyTesting.functionTests.tests.store.EncryptionKeyBlowfishTest
+ *
+ * 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.derbyTesting.functionTests.tests.store;
+
+import org.apache.derbyTesting.junit.*;
+import junit.framework.*;
+
+/**
+ * Test basic functionality on a database encrypted with the Blowfish
+ * algorithm.
+ *
+ * @see EncryptionKeyTest
+ */
+public class EncryptionKeyBlowfishTest
+    extends EncryptionKeyTest {
+
+    public EncryptionKeyBlowfishTest(String name) {
+        super(name,
+              "Blowfish/OFB/NoPadding",
+              "6162636466667686",
+              "9192939499997989",
+              "6162636466667689979",
+              "X1X2X3X4XXXX7X8X");
+    }
+
+    public static Test suite() {
+        // This test runs only in embedded due to the use of external files.
+        Test suite =
+            TestConfiguration.embeddedSuite(EncryptionKeyBlowfishTest.class);
+        return new SupportFilesSetup(suite);
+    }
+} // End class EncryptionKeyBlowfishTest

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyBlowfishTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyDESTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyDESTest.java?view=auto&rev=536156
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyDESTest.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyDESTest.java Tue May  8 03:43:50 2007
@@ -0,0 +1,48 @@
+/*
+ *
+ * Derby - Class org.apache.derbyTesting.functionTests.tests.store.EncryptionKeyDESTest
+ *
+ * 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.derbyTesting.functionTests.tests.store;
+
+import org.apache.derbyTesting.junit.*;
+import junit.framework.*;
+
+/**
+ * Test basic functionality on a database encrypted with the DES algorithm.
+ *
+ * @see EncryptionKeyTest
+ */
+public class EncryptionKeyDESTest
+    extends EncryptionKeyTest {
+
+    public EncryptionKeyDESTest(String name) {
+        super(name,
+              "DES/CBC/NoPadding",
+              "6162636466667686",
+              "9192939499997989",
+              "6162636466667689979",
+              "X1X2X3X4XXXX7X8X");
+    }
+
+    public static Test suite() {
+        // This test runs only in embedded due to the use of external files.
+        Test suite =
+            TestConfiguration.embeddedSuite(EncryptionKeyDESTest.class);
+        return new SupportFilesSetup(suite);
+    }
+} // End class EncryptionKeyDESTest

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyDESTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyTest.java?view=auto&rev=536156
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyTest.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyTest.java Tue May  8 03:43:50 2007
@@ -0,0 +1,703 @@
+/*
+ *
+ * Derby - Class org.apache.derbyTesting.functionTests.tests.store.EncryptionKeyTest
+ *
+ * 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.derbyTesting.functionTests.tests.store;
+
+import java.io.File;
+
+import java.sql.Connection;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+
+import javax.sql.DataSource;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+
+import org.apache.derbyTesting.junit.BaseJDBCTestCase;
+import org.apache.derbyTesting.junit.JDBCDataSource;
+import org.apache.derbyTesting.junit.SupportFilesSetup;
+
+/**
+ * Tests various connection sequences to encrypted databases.
+ * Four kinds of external keys are used:
+ *  <ol><li>the correct key
+ *      <li>an incorrect key
+ *      <li>a key with odd length (in hex representation)
+ *      <li>a key containing invalid characters
+ *  </ol>
+ * <p>
+ * The algorithms used for en-/decryption is determined by the subclasses,
+ * where a single algorithm and a set of keys are associated with each
+ * subclass.
+ * <p>
+ * Databases are created in the <tt>EXTINOUT</tt> directory. Backups are made
+ * to <tt>EXTINOUT/backups</tt> and restored databases are put into
+ * <tt>EXTINOUT/restored</tt> <b>if and only if</b> the databases need to be
+ * both written and read. Otherwise backups are placed in <tt>EXTOUT</tt>.
+ * Testsuites generated from this class must be wrapped in a
+ * <code>SupportFileSetup</code> decorator.
+ */
+ //@NotThreadSafe
+public abstract class EncryptionKeyTest
+    extends BaseJDBCTestCase {
+
+    /** Correct key constant. */
+    protected static final int CORRECT_KEY = 0;
+    /** Wrong key constant. */
+    protected static final int WRONG_KEY = 1;
+    /** Odd length key constant. */
+    protected static final int ODD_LENGTH_KEY = 2;
+    /** Invalid char key constant. */
+    protected static final int INVALID_CHAR_KEY = 3;
+
+    /** Table holding the test data. */
+    private static final String TABLE = "encryptionkeytestdata";
+    /** Test data inserted into database and used for verification. */
+    private static final int[] DATA = {9,4,2,34,6543,3,123,434,5436,-123,0,123};
+
+    /** The algorithm used by the fixture. */
+    private final String algorithm;
+
+    /** The correct key. */
+    private final String keyCorrect;
+    /** An incorrect key. */
+    private final String keyWrong;
+    /** A key with odd length. */
+    private final String keyOddLength;
+    /** A key with an invalid char in it. */
+    private final String keyInvalidChar;
+
+    /**
+     * Variable to hold the various connections.
+     * No guarantee is made about the state of this connection, but it is
+     * closed at tear-down.
+     */
+    private Connection con = null;
+
+    /**
+     * Configures a new setup by specifying the encryption properties.
+     *
+     * @param name name of the fixture
+     * @param algorithm encryption algorithm to use
+     * @param correctKey the correct encryption key
+     * @param wrongKey an incorrect encryption key
+     * @param oddLengthKey a key of odd length
+     * @param invalidCharKey a key with invalid characters
+     */
+    public EncryptionKeyTest(String name,
+                             String algorithm,
+                             String correctKey,
+                             String wrongKey,
+                             String oddLengthKey,
+                             String invalidCharKey) {
+        super(name);
+        this.algorithm = algorithm;
+        this.keyCorrect = correctKey;
+        this.keyWrong = wrongKey;
+        this.keyOddLength = oddLengthKey;
+        this.keyInvalidChar = invalidCharKey;
+    }
+
+    /**
+     * Clean up the connection maintained by this test.
+     */
+    protected void tearDown()
+            throws java.lang.Exception {
+        if (con != null && !con.isClosed()) {
+            con.rollback();
+            con.close();
+            con = null;
+        }
+        super.tearDown();
+    }
+
+    /**
+     * Test a sequence of connections and connection attempts.
+     * Sequence: Create database, connect to database using correct key,
+     * try to connect using incorrect key, connect using correct key.
+     */
+    public void testConnectionSequence1()
+            throws SQLException {
+        String dbName = "encryptedDB_ConnectionSequence1";
+        // Create database.
+        con = createAndPopulateDB(dbName);
+        validateDBContents(con);
+        // Shutdown the database.
+        con.close();
+        shutdown(dbName);
+        // Connect using correct key.
+        con = getConnection(dbName, CORRECT_KEY);
+        validateDBContents(con);
+        con.close();
+        // Shutdown the database.
+        shutdown(dbName);
+        // Try to connect using wrong key.
+        try {
+            getConnection(dbName, WRONG_KEY);
+            fail("Booting with an incorrect encryption key should fail.");
+        } catch (SQLException sqle) {
+            assertSQLState("XJ040", sqle);
+            assertSQLState("XBCXK", getLastSQLException(sqle));
+        }
+        // Connect using correct key.
+        con = getConnection(dbName, CORRECT_KEY);
+        validateDBContents(con);
+        con.close();
+        // Shutdown the database.
+        shutdown(dbName);
+    }
+
+    /**
+     * Test a sequence of connections and connection attempts.
+     * Sequence: Create database, connect to database using odd length key,
+     * try to connect using incorrect key, connect using correct key.
+     */
+    public void testConnectionSequence2()
+            throws SQLException {
+        String dbName = "encryptedDB_ConnectionSequence2";
+        // Create database.
+        con = createAndPopulateDB(dbName);
+        validateDBContents(con);
+        // Shutdown the database.
+        con.close();
+        shutdown(dbName);
+        // Connect using odd length key.
+        try {
+            con = getConnection(dbName, ODD_LENGTH_KEY);
+            fail("Connected with an odd length key.");
+        } catch (SQLException sqle) {
+            assertSQLState("XJ040", sqle);
+            SQLException lastSQLE = getLastSQLException(sqle);
+            String sqlState = lastSQLE.getSQLState();
+            // The state of this exception varies with the security provider
+            // the test is run with.
+            // Briefly stated, the deciding factor is whether the error is
+            // caught by checks in the Derby code, or by the checks in the
+            // security provider. For instance, the (current Sun JCE) DES
+            // key implementation does not verify the key length, whereas the
+            // AES key implementation does. For other providers, the situation
+            // might be different.
+            // XBCX0 : A general crypto exception, wraps the exception from the
+            //         security provider.
+            // XBCXM : A specific Derby exception for external keys of invalid
+            //         lengths.
+            if (!sqlState.equals("XBCX0") && !sqlState.equals("XBCXM")) {
+                throw lastSQLE;
+            }
+        }
+        confirmNonBootedDB(dbName);
+        // Try to connect using wrong key.
+        try {
+            getConnection(dbName, WRONG_KEY);
+            fail("Booting with an incorrect encryption key should fail.");
+        } catch (SQLException sqle) {
+            assertSQLState("XJ040", sqle);
+            assertSQLState("XBCXK", getLastSQLException(sqle));
+        }
+        // Connect using correct key.
+        con = getConnection(dbName, CORRECT_KEY);
+        validateDBContents(con);
+        con.close();
+        // Shutdown the database.
+        shutdown(dbName);
+    }
+
+    /**
+     * Backup an encrypted database.
+     */
+    public void testBackupEncryptedDatabase()
+            throws SQLException {
+        String dbName = "encryptionKeyDBToBackup";
+        // Create the database.
+        con = createAndPopulateDB(dbName);
+        validateDBContents(con);
+        CallableStatement cs = con.prepareCall(
+                "CALL SYSCS_UTIL.SYSCS_BACKUP_DATABASE(?)");
+        cs.setString(1, SupportFilesSetup.EXTOUT);
+        // Perform backup.
+        cs.execute();
+        cs.close();
+        con.close();
+        shutdown(dbName);
+        // Connect to original database after backup.
+        con = getConnection(dbName, CORRECT_KEY);
+        validateDBContents(con);
+        con.close();
+        shutdown(dbName);
+    }
+
+    /**
+     * Create a new database from a backup image.
+     */
+    public void testCreateDbFromBackup()
+            throws SQLException {
+        // No ordering imposed by JUnit, so we create our own db and backup.
+        // Setup paths and names.
+        final String dbName = "encryptionKeyDBToCreateFrom";
+        final String backupDbLocation =
+            SupportFilesSetup.getReadWrite(
+                    new File("backups", "encryptionKeyDBToCreateFrom").getPath()
+                ).getPath();
+        // Create the database.
+        con = createAndPopulateDB(dbName);
+        validateDBContents(con);
+        CallableStatement cs = con.prepareCall(
+                "CALL SYSCS_UTIL.SYSCS_BACKUP_DATABASE(?)");
+        cs.setString(1, 
+                     new File(SupportFilesSetup.EXTINOUT, "backups").getPath());
+        // Perform backup.
+        cs.execute();
+        cs.close();
+        con.close();
+        shutdown(dbName);
+        // Create a new database from backup.
+        String dbNameRestored = dbName + "Restored";
+        con = getPrivilegedConnection(dbNameRestored, CORRECT_KEY,
+                "createFrom=" + backupDbLocation);
+        validateDBContents(con);
+        con.close();
+        shutdown(dbNameRestored, "restored");
+        // Try to create a new database from backup with the wrong key.
+        dbNameRestored = dbName + "RestoreAttemptedWrongKey";
+        try {
+            con = getPrivilegedConnection(dbNameRestored, WRONG_KEY,
+                    "createFrom=" + backupDbLocation);
+            fail("Created database from encrypted backup with wrong key.");
+        } catch (SQLException sqle) {
+            assertSQLState("XJ040", sqle);
+            assertSQLState("XBCXK", getLastSQLException(sqle));
+        }
+        assertTrue(con.isClosed());
+        // Try to create a new database from backup with an invalid key.
+        dbNameRestored = dbName + "RestoreAttemptedInvalidKey";
+        try {
+            con = getPrivilegedConnection(dbNameRestored, INVALID_CHAR_KEY,
+                    "createFrom=" + backupDbLocation);
+            fail("Created database from encrypted backup with an invalid key.");
+        } catch (SQLException sqle) {
+            assertSQLState("XJ040", sqle);
+            assertSQLState("XBCXN", getLastSQLException(sqle));
+        }
+        assertTrue(con.isClosed());
+        // Try to create a new database from backup with an odd length key.
+        dbNameRestored = dbName + "RestoreAttemptedOddLengthKey";
+        try {
+            con = getPrivilegedConnection(dbNameRestored, ODD_LENGTH_KEY,
+                    "createFrom=" + backupDbLocation);
+            fail("Created db from encrypted backup with an odd length key.");
+        } catch (SQLException sqle) {
+            assertSQLState("XJ040", sqle);
+            SQLException lastSQLE = getLastSQLException(sqle);
+            String sqlState = lastSQLE.getSQLState();
+            // The state of this exception varies with the security provider
+            // the test is run with.
+            // Briefly stated, the deciding factor is whether the error is
+            // caught by checks in the Derby code, or by the checks in the
+            // security provider. For instance, the (current Sun JCE) DES
+            // key implementation does not verify the key length, whereas the
+            // AES key implementation does. For other providers, the situation
+            // might be different.
+            // XBCX0 : A general crypto exception, wraps the exception from the
+            //         security provider.
+            // XBCXM : A specific Derby exception for external keys of invalid
+            //         lengths.
+            if (!sqlState.equals("XBCX0") && !sqlState.equals("XBCXM")) {
+                throw lastSQLE;
+            }
+        }
+        assertTrue(con.isClosed());
+        // Create a new database from backup again.
+        dbNameRestored = dbName + "RestoredOnceMore";
+        con = getPrivilegedConnection(dbNameRestored, CORRECT_KEY,
+                "createFrom=" + backupDbLocation);
+        validateDBContents(con);
+        con.close();
+        shutdown(dbNameRestored, "restored");
+    }
+
+    /**
+     * Recover the database using <tt>restoreFrom</tt>.
+     */
+    public void testRestoreFrom()
+            throws SQLException {
+        // No ordering imposed by JUnit, so we create our own db and backup.
+        String dbName = "encryptionKeyDBToRestoreFrom";
+        String dbNameRestored = dbName + "Restored";
+        createBackupRestore(dbName, dbNameRestored);
+        shutdown(dbNameRestored, "restored");
+    }
+
+    /**
+     * Try to recover database with an invalid key.
+     * <p>
+     * It should be noted that the existing database, which has been previously
+     * recovered from the same backup image, is deleted/overwritten even though
+     * Derby is unable to boot the backup image.
+     */
+    public void testInvalidRestoreFrom()
+            throws SQLException {
+        // No ordering imposed by JUnit, so we create our own db and backup.
+        String dbName = "encryptionKeyDBToInvalidRestoreFrom";
+        String dbNameRestored = dbName + "Restored";
+        createBackupRestore(dbName, dbNameRestored);
+        shutdown(dbNameRestored, "restored");
+        // Check that the database is not booted.
+        confirmNonBootedDB("restored/" + dbNameRestored);
+        // Validate the existing database.
+        con = getConnection("restored/" + dbNameRestored, CORRECT_KEY);
+        validateDBContents(con);
+        con.close();
+        shutdown(dbNameRestored, "restored");
+        // Confirm that trying a restore with an invalid key will overwrite
+        // the existing database we are trying to restore to/into. This is
+        // expected behavior currently, but should maybe change?
+        try {
+            con = getPrivilegedConnection(dbNameRestored, INVALID_CHAR_KEY,
+                    ";restoreFrom=" + obtainDbName(dbName, null));
+            fail("Restored database with an invalid key.");
+        } catch (SQLException sqle) {
+            assertSQLState("XBCXN", sqle);
+        }
+        // The database should no longer exist.
+        try {
+            // The "" is a hack to avoid using "create=true".
+            con = getConnection("restored/" + dbNameRestored, CORRECT_KEY, "");
+            fail("Expected connection to fail due to non-existent database.");
+        } catch (SQLException sqle) {
+            assertSQLState("XJ004", sqle);
+        }
+    }
+
+    /**
+     * Try to create database with a key of odd length.
+     */
+    public void testCreateWithOddEncryptionKeyLength()
+            throws SQLException {
+        try {
+            getConnection("encryptedDB_oddKeyLength", ODD_LENGTH_KEY);
+            fail("Database creation with odd key length should fail.");
+        } catch (SQLException sqle) {
+            assertSQLState("XJ041", sqle);
+            SQLException lastSQLE = getLastSQLException(sqle);
+            String sqlState = lastSQLE.getSQLState();
+            // The state of this exception varies with the security provider
+            // the test is run with. In general, it depends on whether it is
+            // Derby code or the security provider code that detects the
+            // problem with the encryption key.
+            if (!sqlState.equals("XBCXM") && !sqlState.equals("XJ001")) {
+                throw lastSQLE;
+            }
+        }
+    }
+
+    /**
+     * Try to create database with a key containing one or more invalid chars.
+     */
+    public void testCreateWithInvalidEncryptionKey() {
+        try {
+            getConnection("encryptedDB_invkeyChar", INVALID_CHAR_KEY);
+            fail("Database creation with invalid key should fail.");
+        } catch (SQLException sqle)  {
+            assertSQLState("XJ041", sqle);
+            assertSQLState("XBCXN", getLastSQLException(sqle));
+        }
+    }
+
+    /* ********************************************************************* *
+     *                     H E L P E R  M E T H O D S                        *
+     * ********************************************************************* */
+
+    /**
+     * Obtain absolute path for the specified database name.
+     * <p>
+     * This absolute path is the name of the database (specified) prefixed with
+     * the absolute path to the EXTINOUT directory. The latter is determined by
+     * consulting <code>SupportFilesSetup</code>.
+     *
+     * @param dbName name of the database
+     * @param subdirectory directory to prefix the database name with (can be
+     *      <code>null</code>). Note that the database name will be prefixed
+     *      with the path to the EXTINOUT directory even if this parameter is
+     *      <code>null</code>.
+     * @return A string with the absolute path to the database.
+     * @see SupportFilesSetup
+     */
+    private String obtainDbName(String dbName, String subdirectory) {
+        File tmp = new File(dbName);
+        if (subdirectory != null) {
+            tmp = new File(subdirectory, dbName);
+        }
+        final File db = tmp;
+        return (String)AccessController.doPrivileged(
+                    new PrivilegedAction() {
+                        public Object run() {
+                            return new File(SupportFilesSetup.EXTINOUT,
+                                            db.getPath()).getAbsolutePath();
+                        }
+                    }
+                );
+    }
+
+    /**
+     * Create encrypted database, validate it, backup, restore and validate
+     * recovered database.
+     * <p>
+     * The source db is shutdown, the recovered db is left booted.
+     *
+     * @param sourceDb the original database to create
+     * @param targetDb the database to recover to
+     */
+    private void createBackupRestore(String sourceDb, String targetDb)
+            throws SQLException {
+        // Create the database.
+        con = createAndPopulateDB(sourceDb);
+        validateDBContents(con);
+        CallableStatement cs = con.prepareCall(
+                "CALL SYSCS_UTIL.SYSCS_BACKUP_DATABASE(?)");
+        cs.setString(1,
+                     new File(SupportFilesSetup.EXTINOUT, "backups").getPath());
+        // Perform backup.
+        cs.execute();
+        con.close();
+        shutdown(sourceDb);
+        confirmNonBootedDB(sourceDb);
+        // Use the restoreFrom attribute.
+        con = getPrivilegedConnection(targetDb, CORRECT_KEY,
+                ";restoreFrom=" + obtainDbName(sourceDb, "backups"));
+        validateDBContents(con);
+        con.close();
+    }
+
+    /**
+     * Confirm that the specified encrypted database has not been booted.
+     *
+     * @param dbName name of an encrypted database
+     * @throws junit.framework.AssertionFailedError if the database has been
+     *      booted (connection may or may not be established)
+     */
+    private void confirmNonBootedDB(String dbName) {
+        DataSource ds = JDBCDataSource.getDataSource(obtainDbName(dbName, null));
+        try {
+            ds.getConnection();
+        } catch (SQLException sqle) {
+            assertSQLState("Database booted? <state:" + sqle.getSQLState() +
+                    ", msg:" + sqle.getMessage() + ">", "XJ040", sqle);
+        }
+    }
+
+    /**
+     * Try to establish a connection to the named database with the
+     * specified type of key.
+     *
+     * @param dbName name of the database
+     * @param keyMode what kind of key to use (correct, wrong, invalid, odd)
+     * @return A connection to the database.
+     * @throws SQLException if connection fails
+     */
+    private Connection getConnection(String dbName, int keyMode)
+            throws SQLException {
+        return getConnection(dbName, keyMode, null);
+    }
+
+    /**
+     * Try to establish a connection to the named database with the
+     * specified type of key and recovery mode.
+     * <p>
+     * The connection is made in a privileged block of code to allow Derby to
+     * read the database backup used for recovery.
+     *
+     * @param dbName name of the database
+     * @param keyMode what kind of key to use (correct, wrong, invalid, odd)
+     * @param recoveryAttribute attribute to recover a database from a backup,
+     *      for instance <code>createFrom</code> or <code>restoreFrom</code>.
+     *      Both the attribute and its value is expected.
+     * @return A connection to the database.
+     * @throws SQLException if connection fails
+     */
+    private Connection getPrivilegedConnection(final String dbName,
+                                               final int keyMode,
+                                               final String recoveryAttribute)
+            throws SQLException {
+        try {
+            return (Connection)AccessController.doPrivileged(
+                new PrivilegedExceptionAction() {
+                    public Object run()
+                            throws SQLException {
+                        return getConnection(dbName, keyMode,
+                            recoveryAttribute);
+                    }
+                });
+        } catch (PrivilegedActionException pae) {
+            throw (SQLException)pae.getException();
+        }
+    }
+
+    /**
+     * Create a new connection to the specified database, using the given
+     * connection attributes.
+     *
+     * @param dbName name of the database
+     * @param keyMode what kind of key to use (correct, wrong, invalid, odd)
+     * @param recoveryAttribute attribute to recover a database from a backup,
+     *      for instance <code>createFrom</code> or <code>restoreFrom</code>.
+     *      Both the attribute and its value is expected.
+     * @return A connection to the database.
+     * @throws SQLException if connection fails
+     */
+    private Connection getConnection(String dbName,
+                                     int keyMode,
+                                     String recoveryAttribute)
+            throws SQLException {
+        DataSource ds = JDBCDataSource.getDataSource(
+                obtainDbName(dbName, 
+                             recoveryAttribute == null ? null : "restored"));
+        StringBuffer str = new StringBuffer(75);
+        if (recoveryAttribute == null) {
+            // Enable data encryption is this database is being created.
+            JDBCDataSource.setBeanProperty(ds, "CreateDatabase", "create");
+            str.append("dataEncryption=true;");
+        } else {
+            str.append(recoveryAttribute);
+            str.append(";");
+        }
+        // Add the encryption algorithm.
+        str.append("encryptionAlgorithm=");
+        str.append(algorithm);
+        str.append(";");
+        // Add the key.
+        str.append("encryptionKey=");
+        switch (keyMode) {
+            case CORRECT_KEY:
+                str.append(keyCorrect);
+                break;
+            case WRONG_KEY:
+                str.append(keyWrong);
+                break;
+            case ODD_LENGTH_KEY:
+                str.append(keyOddLength);
+                break;
+            case INVALID_CHAR_KEY:
+                str.append(keyInvalidChar);
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Invalid key mode specified: " + keyMode);
+        }
+        str.append(";");
+        JDBCDataSource.setBeanProperty(
+                ds, "connectionAttributes", str.toString());
+        return ds.getConnection();
+    }
+
+    /**
+     * Shutdown the specified database.
+     *
+     * @param databaseName the name of the database
+     */
+    protected void shutdown(String databaseName)
+            throws SQLException {
+        shutdown(databaseName, null);
+    }
+
+    /**
+     * Shutdown the database, specified by the database name and prefix.
+     *
+     * @param databaseName the name of the database
+     * @param dir sub-directory prefix for the database
+     */
+    protected void shutdown(String databaseName, String dir)
+            throws SQLException {
+        DataSource ds = JDBCDataSource.getDataSource(
+                obtainDbName(databaseName, dir));
+        JDBCDataSource.shutdownDatabase(ds);
+    }
+
+    /**
+     * Create a new database and populate it.
+     * <p>
+     * The method fails with an exception if the database already exists.
+     * This is because it is the creation process that is to be tested.
+     *
+     * @param dbName name of the database to create
+     * @return A connection the to the newly created database.
+     * @throws SQLException if the database already exist, or
+     *      a general error happens during database interaction
+     */
+    protected Connection createAndPopulateDB(String dbName)
+            throws SQLException {
+        Connection con = getConnection(dbName, CORRECT_KEY);
+        SQLWarning warning = con.getWarnings();
+        // If the database already exists, fail the test.
+        if (warning != null) {
+            if ("01J01".equals(warning.getSQLState())) {
+                fail("Refusing to continue, database already exists <" +
+                        warning.getMessage() + ">");
+            }
+        }
+        Statement stmt = con.createStatement();
+        stmt.executeUpdate("CREATE TABLE " + TABLE + " (id int NOT NULL, " +
+                "val int NOT NULL, PRIMARY KEY(id))");
+        stmt.close();
+        PreparedStatement ps = con.prepareStatement("INSERT INTO " + TABLE +
+                " (id, val) VALUES (?,?)");
+        for (int i=0; i < DATA.length; i++) {
+            ps.setInt(1, i);
+            ps.setInt(2, DATA[i]);
+            ps.executeUpdate();
+        }
+        ps.close();
+        return con;
+    }
+
+    /**
+     * Validate the data in the database against the data model.
+     *
+     * @param con the database to validate the contents of
+     * @throws junit.framework.AssertionFailedError if there is a mismatch
+     *      between the data in the database and the model
+     */
+    protected void validateDBContents(Connection con)
+            throws SQLException {
+        Statement stmt = con.createStatement();
+        ResultSet rs = stmt.executeQuery("SELECT id, val FROM " + TABLE +
+                                            " ORDER BY id");
+        int id, val;
+        while (rs.next()) {
+            id = rs.getInt(1);
+            val = rs.getInt(2);
+            if (id >= DATA.length) {
+                fail("Id in database out of bounds for data model; " +
+                        id + " >= " + DATA.length);
+            }
+            if (val != DATA[id]) {
+                fail("Mismatch between db and model for id " + id + ";" +
+                        val + " != " + DATA[id]);
+            }
+        }
+        rs.close();
+        stmt.close();
+    }
+} // End EncryptionKeyTest

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/EncryptionKeyTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/_Suite.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/_Suite.java?view=diff&rev=536156&r1=536155&r2=536156
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/_Suite.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/_Suite.java Tue May  8 03:43:50 2007
@@ -22,6 +22,8 @@
 package org.apache.derbyTesting.functionTests.tests.store;
 
 import org.apache.derbyTesting.junit.BaseTestCase;
+import org.apache.derbyTesting.junit.JDBC;
+
 import junit.framework.Test; 
 import junit.framework.TestSuite;
 
@@ -50,7 +52,16 @@
         TestSuite suite = new TestSuite("store");
         
         suite.addTest(BootAllTest.suite());
+
+        // Encryption only supported for Derby in J2SE/J2EE environments.
+        // J2ME (JSR169) does not support encryption.
+        if (JDBC.vmSupportsJDBC3()) {
+            // Add tests of basic functionality on encrypted databases.
+            suite.addTest(EncryptionKeyAESTest.suite());
+            suite.addTest(EncryptionKeyBlowfishTest.suite());
+            suite.addTest(EncryptionKeyDESTest.suite());
+        }
         
         return suite;
     }
-}
\ No newline at end of file
+}

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/encryptionKey.sql
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/encryptionKey.sql?view=diff&rev=536156&r1=536155&r2=536156
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/encryptionKey.sql (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/encryptionKey.sql Tue May  8 03:43:50 2007
@@ -1,112 +0,0 @@
---
---   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.
---
-------------------------------------------------------------------------------------
--- This test file contains test cases for testing encryptionKey  property in the connection
--- url 
--- 
--- Case 1: use external encryption key and create
--- 	   connect using correct key
---	   connect using wrong key ( different length, different key)
---	   connect again using correct key
--- Case 2: backup database
---	   connect to original db after backup
--- Case 3: createFrom backedup database
---	   with wrong key
---	   with right key
---	   with wrong key
---	   with right key
---	   test restoreFrom
--- Case 4: use invalid key when trying to create
---     key length not even
---     key contains invalid character(s)
---	   
-------------------------------------------------------------------------------------
--- case1:	give external encryptionKey instead of bootpassword
-connect 'jdbc:derby:encdbcbc_key;create=true;dataEncryption=true;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=6162636465666768';
-
-create table t1(i1 int);
-insert into t1 values(1);
-select * from t1;
-commit;
-connect 'jdbc:derby:encdbcbc_key;shutdown=true';
-
--- case 1.1 - right key
-
-connect 'jdbc:derby:encdbcbc_key;create=true;dataEncryption=true;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=6162636465666768';
-select * from t1;
-
-connect 'jdbc:derby:encdbcbc_key;shutdown=true';
--- (-ve case) connect without the encryptionKey 
---  connect with encryptionKey and keylength ( will ignore the keylength value)
-
---  wrong length
-connect 'jdbc:derby:encdbcbc_key;create=true;dataEncryption=true;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=6163646566676868';
--- wrong key
-connect 'jdbc:derby:encdbcbc_key;create=true;dataEncryption=true;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=6862636465666768';
-select * from t1;
-
--- correct key
-connect 'jdbc:derby:encdbcbc_key;create=true;dataEncryption=true;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=6162636465666768';
-select * from t1;
-
--- case 2 backup
-CALL SYSCS_UTIL.SYSCS_BACKUP_DATABASE('extinout/bkup1');
-connect 'jdbc:derby:encdbcbc_key;shutdown=true';
-
--- connect to original db after backup
-
-connect 'jdbc:derby:encdbcbc_key;create=true;dataEncryption=true;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=6162636465666768';
-select * from t1;
-
--- case 3 :create db from backup using correct key
-connect 'jdbc:derby:encdbcbc_key2;createFrom=extinout/bkup1/encdbcbc_key;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=6162636465666768';
-select * from t1;
-connect 'jdbc:derby:encdbcbc_key2;shutdown=true';
-
--- create db from backup using wrong key
-connect 'jdbc:derby:encdbcbc_key3;createFrom=extinout/bkup1/encdbcbc_key;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=6122636465666768';
-select * from t1;
-
-connect 'jdbc:derby:encdbcbc_key3;shutdown=true';
-
--- create db from backup using correct key
-connect 'jdbc:derby:encdbcbc_12;createFrom=extinout/bkup1/encdbcbc_key;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=6162636465666768';
-select * from t1;
-
-connect 'jdbc:derby:encdbcbc_key12;shutdown=true';
-
-connect 'jdbc:derby:encdb;create=true;dataEncryption=true;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=6162636465666768';
-create table t1(i1 int ,c2 char(20));
-insert into t1 values(1,'a');
-select * from t1;
-
-call SYSCS_UTIL.SYSCS_BACKUP_DATABASE('extinout/mybackup2');
-
-connect 'jdbc:derby:encdb;shutdown=true';
-disconnect;
-
-connect 'jdbc:derby:encdb;restoreFrom=extinout/mybackup2/encdb;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=6162636465666768';
-select * from t1;
-disconnect;
-
--- case 4 : invalid keys
--- key length not even
-connect 'jdbc:derby:encddbdb_invkey;create=true;dataEncryption=true;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=123456789';
-
--- key contains illegal character(s)
-connect 'jdbc:derby:encddbdb_invkey;create=true;dataEncryption=true;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=61626364656667XY';
-

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/encryptionKey_app.properties
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/encryptionKey_app.properties?view=diff&rev=536156&r1=536155&r2=536156
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/encryptionKey_app.properties (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/encryptionKey_app.properties Tue May  8 03:43:50 2007
@@ -1,9 +0,0 @@
-#database=jdbc:derby:wombat;create=true;dataEncryption=true;bootPassword=Thursday
-
-#
-derby.optimizer.noTimeout=true
-
-ij.showNoConnectionsAtStart=true
-ij.showNoCountForSelect=true
-runwithjdk13=false
-useextdirs=true