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 dj...@apache.org on 2006/11/09 00:51:46 UTC

svn commit: r472704 - in /db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang: DatabaseClassLoadingTest.java _Suite.java

Author: djd
Date: Wed Nov  8 15:51:46 2006
New Revision: 472704

URL: http://svn.apache.org/viewvc?view=rev&rev=472704
Log:
DERBY-2033 (partial) All of the test cases from dcl.sql are converted to DatabaseClassLoadingTest
except those related to jarring up the database and runing tests against that read-only database.
Add DatabaseClassLoadingTest into lang._Suite.

Modified:
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/DatabaseClassLoadingTest.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/DatabaseClassLoadingTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/DatabaseClassLoadingTest.java?view=diff&rev=472704&r1=472703&r2=472704
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/DatabaseClassLoadingTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/DatabaseClassLoadingTest.java Wed Nov  8 15:51:46 2006
@@ -18,7 +18,8 @@
 
 /**
  * Test database class loading, executing routines from the
- * installed jars including accessing resources.
+ * installed jars including accessing resources. Replacing
+ * jars and handling signed jars is also tested.
  *
  */
 public class DatabaseClassLoadingTest extends BaseJDBCTestCase {
@@ -61,12 +62,33 @@
            
            suite.addTest(SecurityManagerSetup.noSecurityManager(
                    new DatabaseClassLoadingTest("testAlterTable")));
-        }
+
+           suite.addTest(SecurityManagerSetup.noSecurityManager(
+                   new DatabaseClassLoadingTest("testClassPathRollback")));
+           
+           suite.addTest(SecurityManagerSetup.noSecurityManager(
+                   new DatabaseClassLoadingTest("testReplaceJar")));        
+           
+           suite.addTest(SecurityManagerSetup.noSecurityManager(
+                   new DatabaseClassLoadingTest("testReplacedClass")));
+           suite.addTest(SecurityManagerSetup.noSecurityManager(
+                   new DatabaseClassLoadingTest("testSecondJar")));
+           suite.addTest(SecurityManagerSetup.noSecurityManager(
+                   new DatabaseClassLoadingTest("testSignedJar")));
+           
+           suite.addTest(SecurityManagerSetup.noSecurityManager(
+                   new DatabaseClassLoadingTest("testHackedJarReplacedClass")));
+           suite.addTest(SecurityManagerSetup.noSecurityManager(
+                   new DatabaseClassLoadingTest("testInvalidJar")));           
+           suite.addTest(SecurityManagerSetup.noSecurityManager(
+                   new DatabaseClassLoadingTest("testRemoveJar")));           
+           }
         
         return new CleanDatabaseTestSetup(suite) {
             protected void decorateSQL(Statement s) throws SQLException
             {
                 s.executeUpdate("create schema emc");
+                s.executeUpdate("create schema \"emcAddOn\"");
                 s.executeUpdate("create table emc.contacts " +
                         "(id int primary key, e_mail varchar(30))");
                 s.executeUpdate(
@@ -81,6 +103,17 @@
                   "NO SQL " +
                   "external name 'org.apache.derbyTesting.databaseclassloader.emc.getArticle' " +
                   "language java parameter style java");
+                
+                // function that gets the signers of the class (loaded from the jar)
+                s.executeUpdate("CREATE FUNCTION EMC.GETSIGNERS(" +
+                  "CLASS_NAME VARCHAR(256)) RETURNS VARCHAR(60) "+
+                  "NO SQL LANGUAGE JAVA PARAMETER STYLE JAVA " +
+                  "EXTERNAL NAME 'org.apache.derbyTesting.databaseclassloader.emc.getSigners'");
+                
+                s.executeUpdate("CREATE FUNCTION \"emcAddOn\".VALIDCONTACT(E_MAIL VARCHAR(30)) "+
+                  "RETURNS SMALLINT "+
+                  "READS SQL DATA LANGUAGE JAVA PARAMETER STYLE JAVA " +
+                  "EXTERNAL NAME 'org.apache.derbyTesting.databaseclassloader.addon.vendor.util.valid'");
                 }
         };
     }
@@ -111,16 +144,7 @@
      */
     public void testWithNoClasspath() throws SQLException
     {       
-        URL jar =
-            getTestResource("org/apache/derbyTesting/functionTests/tests/lang/dcl_emc1.jar");
-        
-        assertNotNull(jar);
-        CallableStatement cs = prepareCall("CALL SQLJ.INSTALL_JAR(?, ?, 0)");
-        
-        cs.setString(1, jar.toExternalForm());
-        cs.setString(2, "EMC.MAIL_APP");
-        cs.executeUpdate();
-        cs.close();
+        installJar("dcl_emc1.jar", "EMC.MAIL_APP");
 
         testWithNoInstalledJars();
     }
@@ -247,6 +271,260 @@
                     });
       
         s.close();
+    }
+    
+    /**
+     * check the roll back of class loading.
+     * install a new jar in a transaction, see
+     * that the new class is used and then rollback
+     * the old class should be used after the rollback.
+     * @throws SQLException
+     */
+    public void testClassPathRollback() throws SQLException
+    {        
+        getConnection().setAutoCommit(false);
+        replaceJar("dcl_emc2.jar", "EMC.MAIL_APP");
+
+        
+        // This version checks the e-mail address.
+        CallableStatement cs = prepareCall("CALL EMC.ADDCONTACT(?, ?)");
+        cs.setInt(1, 99);
+        cs.setString(2, "wormspam@soil.com");
+        cs.executeUpdate();
+        
+        Statement s = createStatement();
+        
+        JDBC.assertFullResultSet(
+                s.executeQuery("SELECT id, e_mail, ok from EMC.CONTACTS WHERE ID = 99"),
+                new String[][] {
+                    {"99", "wormspam@soil.com", "0"},
+                    });
+        
+        rollback();
+        getConnection().setAutoCommit(true);
+        
+        // execute again but reverted to the version that does not
+        // check the email address.
+        cs.executeUpdate();
+        cs.close();
+
+         JDBC.assertFullResultSet(
+                s.executeQuery("SELECT id, e_mail, ok from EMC.CONTACTS WHERE ID = 99"),
+                new String[][] {
+                    {"99", "wormspam@soil.com", null},
+                    });
+         
+         s.executeUpdate("DELETE FROM EMC.CONTACTS WHERE ID = 99");
+         s.close();
+    }
+    
+    /**
+     * Replace the jar to later test the prepare from a different
+     * connection picks up the new version.
+     * @throws SQLException
+     */
+    public void testReplaceJar() throws SQLException
+    {
+        replaceJar("dcl_emc2.jar", "EMC.MAIL_APP");
+    }
+    
+    /**
+     * Change of class due to testReplaceJar that
+     * changes the application to run checks on the e-mail
+     * to ensure it is valid (in this case by seeing if
+     *  it simply includes 'spam' in the title).
+     * @throws SQLException
+     */
+    public void testReplacedClass() throws SQLException {
+        // This version checks the e-mail address.
+        CallableStatement cs = prepareCall("CALL EMC.ADDCONTACT(?, ?)");
+        cs.setInt(1, 4);
+        cs.setString(2, "spammer@ripoff.com");
+        cs.executeUpdate();
+        cs.setInt(1, 5);
+        cs.setString(2, "open@source.org");
+        cs.executeUpdate();
+        
+        Statement s = createStatement();
+        JDBC.assertFullResultSet(
+                s.executeQuery("SELECT id, e_mail, ok from EMC.CONTACTS ORDER BY 1"),
+                new String[][] {
+                    {"0", "now@classpathchange.com", null},
+                    {"1", "bill@ruletheworld.com", null},
+                    {"2", "penguin@antartic.com", null},
+                    {"3", "big@blue.com", null},
+                    {"4", "spammer@ripoff.com", "0"},
+                    {"5", "open@source.org", "1"},
+                    });
+      
+        s.close();
+    }
+    
+    /**
+     * now add another jar in to test two jars and
+     * a quoted identifer for the jar names.
+     */
+    public void testSecondJar() throws SQLException {
+        
+        installJar("dcl_emcaddon.jar", "\"emcAddOn\".\"MailAddOn\"");
+
+        setDBClasspath("EMC.MAIL_APP:\"emcAddOn\".\"MailAddOn\"");
+        Statement s = createStatement();
+        JDBC.assertFullResultSet(
+                s.executeQuery("SELECT E_MAIL, \"emcAddOn\".VALIDCONTACT(E_MAIL) FROM EMC.CONTACTS ORDER BY 1"),
+                new String[][] {
+                    {"big@blue.com", "0"},
+                    {"bill@ruletheworld.com", "0"},
+                    {"now@classpathchange.com", "0"},
+                    {"open@source.org", "1"},
+                    {"penguin@antartic.com", "0"},
+                    {"spammer@ripoff.com", "0"},
+                    });
+      
+        s.close();
+    }
+    
+    /**
+     * Test to see if the jar signatures can be obtained from the jar file.
+     * The jar was signed with a self signed certificate
+     * <code>
+        keytool -delete -alias emccto -keystore emcks -storepass ab987c
+        keytool -genkey -dname "cn=EMC CTO, ou=EMC APP, o=Easy Mail Company, c=US" -alias emccto -keypass kpi135 -keystore emcks -storepass ab987c
+        keytool -selfcert -alias emccto -keypass kpi135 -validity 36500 -keystore emcks -storepass ab987c
+        keytool -keystore emcks -storepass ab987c -list -v
+        jarsigner -keystore emcks -storepass ab987c -keypass kpi135 -signedjar dcl_emc2s.jar dcl_emc2.jar emccto
+        keytool -delete -alias emccto -keystore emcks -storepass ab987c
+        </code>
+     * @throws SQLException
+     */
+    public void testSignedJar() throws SQLException
+    {
+        // Statement to get the signers for a class loaded from a jar file
+        PreparedStatement ps = prepareStatement("VALUES EMC.GETSIGNERS(?)");
+        
+        // current jar is unsigned.
+        ps.setString(1, "org.apache.derbyTesting.databaseclassloader.emc");      
+        JDBC.assertSingleValueResultSet(ps.executeQuery(), null);
+        
+        // replace with a signed jar
+        replaceJar("dcl_emc2s.jar", "EMC.MAIL_APP");
+        
+        ps.close();
+        ps = prepareStatement("VALUES EMC.GETSIGNERS(?)");
+        ps.setString(1, "org.apache.derbyTesting.databaseclassloader.emc");    
+        
+        // now class is signed
+        JDBC.assertSingleValueResultSet(ps.executeQuery(),
+                "CN=EMC CTO, OU=EMC APP, O=Easy Mail Company, C=US");
+        
+        // verify the other jar is still not signed
+        ps.setString(1, "org.apache.derbyTesting.databaseclassloader.addon.vendor.util");
+        JDBC.assertSingleValueResultSet(ps.executeQuery(), null);
+
+        ps.close();
+    }
+    
+    /**
+     * Replace the signed jar with a hacked jar. emc.class modified to diable
+     * valid e-mail address check but using same signatures within jar.
+     * Class loader should reject.
+     * 
+     * rejects it.
+     * @throws SQLException
+     */
+    public void testHackedJarReplacedClass() throws SQLException {
+
+        replaceJar("dcl_emc2sm.jar", "EMC.MAIL_APP");
+        
+        try {
+            CallableStatement cs = prepareCall("CALL EMC.ADDCONTACT(?, ?)");
+            cs.setInt(1, 99);
+            cs.setString(2, "spamking@cracker.org");
+            cs.executeUpdate();
+            cs.close();
+            fail("procedure call worked on hacked jar");
+        } catch (SQLException e) {
+            assertSQLState("Class load should fail due to invalid signature", "42X51", e);
+        }
+    }
+    
+    /**
+     * replace with a hacked jar file, emc.class modified to 
+     be an invalid class (no signing on this jar).
+     */
+    public void testInvalidJar() throws SQLException
+    {
+        replaceJar("dcl_emc2l.jar", "EMC.MAIL_APP");
+        
+        try {
+            CallableStatement cs = prepareCall("CALL EMC.ADDCONTACT(?, ?)");
+            cs.setInt(1, 999);
+            cs.setString(2, "spamking2@cracker.org");
+            cs.executeUpdate();
+            cs.close();
+            fail("procedure call worked on invalid jar");
+        } catch (SQLException e) {
+            assertSQLState("Class load should fail due to invalid jar", "42X51", e);
+
+        }        
+    }
+    
+    public void testRemoveJar() throws SQLException
+    {
+        CallableStatement cs = prepareCall("CALL SQLJ.REMOVE_JAR(?, 0)");
+        
+        cs.setString(1, "EMC.MAIL_APP");
+        
+        // fail if jar is on classpath
+        try {
+            cs.executeUpdate();
+            fail("REMOVE_JAR on jar in derby.database.classpath worked");
+        } catch (SQLException e) {
+            assertSQLState("X0X07", e);
+        }
+        
+        // remove from classpath 
+        setDBClasspath("\"emcAddOn\".\"MailAddOn\"");
+        testWithNoInstalledJars();
+        cs.executeUpdate();      
+        testWithNoInstalledJars();
+        
+        // remove the second jar
+        setDBClasspath(null);
+        cs.setString(1, "\"emcAddOn\".\"MailAddOn\"");
+        cs.executeUpdate();
+        
+        cs.close();
+    }
+  
+    private void installJar(String resource, String jarName) throws SQLException
+    {
+        URL jar =
+            getTestResource(
+               "org/apache/derbyTesting/functionTests/tests/lang/" + resource);
+        
+        assertNotNull(resource, jar);
+        
+        CallableStatement cs = prepareCall("CALL SQLJ.INSTALL_JAR(?, ?, 0)");
+        cs.setString(1, jar.toExternalForm());
+        cs.setString(2, jarName);
+        cs.executeUpdate();
+        cs.close();
+    }
+    
+    private void replaceJar(String resource, String jarName) throws SQLException
+    {
+        URL jar =
+            getTestResource(
+               "org/apache/derbyTesting/functionTests/tests/lang/" + resource);
+        
+        assertNotNull(resource, jar);
+        
+        CallableStatement cs = prepareCall("CALL SQLJ.REPLACE_JAR(?, ?)");
+        cs.setString(1, jar.toExternalForm());
+        cs.setString(2, jarName);
+        cs.executeUpdate();
+        cs.close();
     }
     
     private void setDBClasspath(String cp) throws SQLException

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java?view=diff&rev=472704&r1=472703&r2=472704
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java Wed Nov  8 15:51:46 2006
@@ -59,7 +59,7 @@
         // suite.addTest(largeCodeGen.suite());
 
 
-        //suite.addTest(DatabaseClassLoadingTest.suite());
+        suite.addTest(DatabaseClassLoadingTest.suite());
         suite.addTest(GroupByExpressionTest.suite());
 		suite.addTest(LangScripts.suite());
         suite.addTest(MathTrigFunctionsTest.suite());