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 da...@apache.org on 2007/04/13 00:54:20 UTC

svn commit: r528274 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/jdbc/ engine/org/apache/derby/loc/ shared/org/apache/derby/shared/common/reference/ testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/

Author: dag
Date: Thu Apr 12 15:54:20 2007
New Revision: 528274

URL: http://svn.apache.org/viewvc?view=rev&rev=528274
Log:
DERBY-2264 Patch DERBY-2264-7.diff, which restricts database hard upgrade to the database owner.

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java
    db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml
    db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DboPowersTest.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java?view=diff&rev=528274&r1=528273&r2=528274
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java Thu Apr 12 15:54:20 2007
@@ -217,16 +217,19 @@
 			boolean	createBoot = createBoot(info);	
 
 			// DERBY-2264: keeps track of whether we do a plain boot before an
-			// (re)encryption boot to (possibly) authenticate first. We can not
-			// authenticate before we have booted, so in order to enforce data
-			// base owner powers over encryption, we need a plain boot, then
-			// authenticate, then, if all is well, boot with (re)encryption.
-			// Encryption at create time is not checked.
+			// (re)encryption or hard upgrade boot to (possibly) authenticate
+			// first. We can not authenticate before we have booted, so in
+			// order to enforce data base owner powers over encryption or
+			// upgrade, we need a plain boot, then authenticate, then, if all
+			// is well, boot with (re)encryption or upgrade.  Encryption at
+			// create time is not checked.
 			boolean isTwoPhaseEncryptionBoot = (!createBoot &&
 												isEncryptionBoot(info));
+			boolean isTwoPhaseUpgradeBoot = (!createBoot &&
+											 isHardUpgradeBoot(info));
 
 			// Save original properties if we modified them for
-			// isTwoPhaseEncryptionBoot.
+			// two phase encryption or upgrade boot.
 			Properties savedInfo = null;
 
 			if (database != null)
@@ -234,12 +237,13 @@
 				// database already booted by someone else
 				tr.setDatabase(database);
 				isTwoPhaseEncryptionBoot = false;
+				isTwoPhaseUpgradeBoot = false;
 			}
 			else if (!shutdown)
 			{
-				if (isTwoPhaseEncryptionBoot) {
+				if (isTwoPhaseEncryptionBoot || isTwoPhaseUpgradeBoot) {
 					savedInfo = info;
-					info = removeEncryptionProps((Properties)info.clone());
+					info = removePhaseTwoProps((Properties)info.clone());
 				}
 
 				// Return false iff the monitor cannot handle a service of the
@@ -298,18 +302,20 @@
 			// the rest.
 			tr.startTransaction();
 
-			if (isTwoPhaseEncryptionBoot) {
-				// DERBY-2264: shutdown and boot again with encryption
-				// attributes active. This is restricted to the database owner.
+			if (isTwoPhaseEncryptionBoot || isTwoPhaseUpgradeBoot) {
+				// DERBY-2264: shutdown and boot again with encryption or
+				// upgrade attributes active. This is restricted to the
+				// database owner.
 				if (!usingNoneAuth) {
 					// a failure here leaves database booted, but no
 					// (re)encryption has taken place and the connection is
 					// rejected.
-					checkIsDBOwner(OP_ENCRYPT);
+					checkIsDBOwner(isTwoPhaseEncryptionBoot? OP_ENCRYPT :
+								   OP_HARD_UPGRADE);
 				}
 
 				// shutdown and reboot using saved properties which
-				// include the (re)encyption attributes
+				// include the (re)encyption or upgrade attribute(s)
 				info = savedInfo;
 				handleException(tr.shutdownDatabaseException());
 				restoreContextStack();
@@ -322,7 +328,7 @@
 					if (SanityManager.DEBUG) {
 						SanityManager.THROWASSERT(
 							"bootDatabase failed after initial plain boot " +
-							"for (re)encryption");
+							"for (re)encryption or upgrade");
 					}
 					tr.clearContextInError();
 					setInactive();
@@ -442,18 +448,31 @@
 				(p.getProperty(Attribute.NEW_CRYPTO_EXTERNAL_KEY) != null));
 	}
 
+	/**
+	 * Examine boot properties and determine if a boot with the given
+	 * attributes would entail a hard upgrade.
+	 *
+	 * @param p the attribute set
+	 * @return true if a boot will hard upgrade the database
+	 */
+	private boolean isHardUpgradeBoot(Properties p)
+	{
+		return Boolean.valueOf(
+			p.getProperty(Attribute.UPGRADE_ATTR)).booleanValue();
+	}
 
 	/**
-	 * Remove any encryption properties from the given properties
+	 * Remove any encryption or upgarde properties from the given properties
 	 *
 	 * @param p the attribute set
 	 * @return clone sans encryption properties
 	 */
-	private Properties removeEncryptionProps(Properties p)
+	private Properties removePhaseTwoProps(Properties p)
 	{
 		p.remove(Attribute.DATA_ENCRYPTION);
 		p.remove(Attribute.NEW_BOOT_PASSWORD);
 		p.remove(Attribute.NEW_CRYPTO_EXTERNAL_KEY);
+		p.remove(Attribute.UPGRADE_ATTR);
 		return p;
 	}
 
@@ -567,6 +586,7 @@
 	/* Enumerate operations controlled by database owner powers */
 	private static final int OP_ENCRYPT = 0;
 	private static final int OP_SHUTDOWN = 1;
+	private static final int OP_HARD_UPGRADE = 2;
 	/**
 	 * Check if actual authenticationId is equal to the database owner's.
 	 *
@@ -587,6 +607,9 @@
 									  actualId, tr.getDBName());
 			case OP_SHUTDOWN:
 				throw newSQLException(SQLState.AUTH_SHUTDOWN_NOT_DB_OWNER,
+									  actualId, tr.getDBName());
+			case OP_HARD_UPGRADE:
+				throw newSQLException(SQLState.AUTH_HARD_UPGRADE_NOT_DB_OWNER,
 									  actualId, tr.getDBName());
 			default:
 				if (SanityManager.DEBUG) {

Modified: db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml?view=diff&rev=528274&r1=528273&r2=528274
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml Thu Apr 12 15:54:20 2007
@@ -858,6 +858,13 @@
                 <arg>databaseName</arg>
             </msg>
 
+            <msg>
+                <name>2850J.C</name>
+                <text>User '{0}' cannot hard upgrade database '{1}'. Only the database owner can perform this operation.</text>
+                <arg>authorizationID</arg>
+                <arg>databaseName</arg>
+            </msg>
+
         </family>
 
 

Modified: db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java?view=diff&rev=528274&r1=528273&r2=528274
==============================================================================
--- db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java (original)
+++ db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java Thu Apr 12 15:54:20 2007
@@ -1388,6 +1388,7 @@
 	String AUTH_NO_OBJECT_PERMISSION                                   = "2850G";
 	String AUTH_SHUTDOWN_NOT_DB_OWNER                                  = "2850H.C";
 	String AUTH_ENCRYPT_NOT_DB_OWNER                                   = "2850I.C";
+	String AUTH_HARD_UPGRADE_NOT_DB_OWNER                              = "2850J.C";
 
 	/*
 	** Dependency manager

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DboPowersTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DboPowersTest.java?view=diff&rev=528274&r1=528273&r2=528274
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DboPowersTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DboPowersTest.java Thu Apr 12 15:54:20 2007
@@ -41,7 +41,7 @@
  *    {no authentication, authentication and authentication/sqlAuthorization} x
  *    {data base owner, other user }
  *
- * One could consider removing the client/server suite to speed up
+ * One could consider removing the client/server suites to speed up
  * this test as it does not add much value given the nature of the changes.
  *
  */
@@ -77,7 +77,11 @@
     }
 
     /**
-     * Create a new instance of DboPowersTest (for encryption tests)
+     * Create a new instance of DboPowersTest (for encryption and hard
+     * upgrade tests). The database owner credentials is needed to
+     * always be able to perform the restricted operations (when they
+     * are not under test, but used as part of a test fixture for
+     * another operation).
      *
      * @param name Fixture name
      * @param authLevel authentication level with which test is run
@@ -125,6 +129,14 @@
                     dboEncryptionSuite("suite: encryption powers, client")));
         }
 
+        /* Database hard upgrade powers */
+
+        suite.addTest(
+            dboHardUpgradeSuite("suite: hard upgrade powers, embedded"));
+        suite.addTest(
+            TestConfiguration.clientServerDecorator(
+                dboHardUpgradeSuite("suite: hard upgrade powers, client")));
+
         return suite;
     }
 
@@ -155,7 +167,7 @@
      * @return A suite containing the test case for shutdown
      * incarnated for the three security levels no authentication,
      * authentication, and authentication plus sqlAuthorization, The
-     * latter two has an instance for dbo, and one for ordinary user,
+     * latter two has an instance for dbo, and one for an ordinary user,
      * so there are in all five incarnations of tests.
      */
     private static Test dboShutdownSuite(String framework)
@@ -169,7 +181,7 @@
             new TestSuite("suite: security level=" +
                           secLevelNames[NOAUTHENTICATION]);
         noauthSuite.addTest(new DboPowersTest("testShutDown",
-                                                    NOAUTHENTICATION));;
+                                              NOAUTHENTICATION));
         tests[NOAUTHENTICATION] = noauthSuite;
 
         /* First decorate with users, then with authentication. Do this
@@ -204,7 +216,7 @@
 
     /**
      * Wraps the shutdown fixture in decorators to run with data
-     * base owner and other valid user.
+     * base owner and one other valid user.
      *
      * @param autLev security context to use
      */
@@ -311,7 +323,7 @@
      * @return A suite containing the test case for encryption
      * incarnated for the three security levels no authentication,
      * authentication, and authentication plus sqlAuthorization, The
-     * latter two has an instance for dbo, and one for ordinary user,
+     * latter two has an instance for dbo, and one for an ordinary user,
      * so there are in all five incarnations of tests.
      */
     private static Test dboEncryptionSuite(String framework)
@@ -362,7 +374,7 @@
 
     /**
      * Wraps the encryption fixtures in decorators to run with data
-     * base owner and other valid user.
+     * base owner and one other valid user.
      *
      * @param autLev security context to use
      */
@@ -566,26 +578,177 @@
      */
     private void vetEncryptionAttempt (String user, SQLException e)
     {
+        vetAttempt(user, e, "2850I", "(re)encryption");
+    }
+
+    /**
+     *
+     * Construct suite of tests for hard upgrade database action
+     *
+     * NOTE: there is no real upgrade going on here since the
+     * database is created with the same version, but the checking
+     * is performed nonetheless, which is what we are testing
+     * here.  This saves us from having to create a database with
+     * an old version of Derby to test this power.
+     *
+     * @param framework Derby framework name
+     * @return A suite containing the test case for hard upgrade
+     * incarnated for the three security levels no authentication,
+     * authentication, and authentication plus sqlAuthorization, The
+     * latter two has an instance for dbo, and one for an ordinary user,
+     * so there are in all five incarnations of tests.
+     */
+    private static Test dboHardUpgradeSuite(String framework)
+    {
+        Test tests[] = new Test[SQLAUTHORIZATION+1]; // one per authLevel
+
+        /* Tests without any authorization active (level ==
+         * NOAUTHENTICATION).
+         */
+        TestSuite noauthSuite =
+            new TestSuite("suite: security level=" +
+                          secLevelNames[NOAUTHENTICATION]);
+        noauthSuite.addTest(new DboPowersTest("testHardUpgrade",
+                                              NOAUTHENTICATION,
+                                              "foo", "bar"));
+        tests[NOAUTHENTICATION] = noauthSuite;
+
+        /* First decorate with users, then with authentication. Do this
+         * twice, once for authentication only, and once for
+         * authentication + sqlAuthorization (see extra decorator
+         * added below).
+         */
+        for (int autLev = AUTHENTICATION;
+             autLev <= SQLAUTHORIZATION ; autLev++) {
+
+            tests[autLev] = wrapHardUpgradeUserTests(autLev);
+        }
+
+        TestSuite suite = new TestSuite("dboPowers:"+framework);
+
+        /* run tests with no authentication enabled */
+        suite.addTest(tests[NOAUTHENTICATION]);
+
+        /* run test for all users with only authentication enabled */
+        suite.addTest(tests[AUTHENTICATION]);
+
+        /* run test for all users with authentication and
+         * sqlAuthorization enabled
+         */
+        suite.addTest(
+            TestConfiguration.
+            sqlAuthorizationDecorator(tests[SQLAUTHORIZATION]));
+
+        return suite;
+    }
+
+    /**
+     * Wraps the shutdown fixture in decorators to run with data
+     * base owner and one other valid user.
+     *
+     * @param autLev security context to use
+     */
+
+    private static Test wrapHardUpgradeUserTests(int autLev)
+    {
+        // add decorator for different users authenticated
+        TestSuite usersSuite =
+            new TestSuite("usersSuite: security level=" +
+                          secLevelNames[autLev]);
+
+        // First decorate with users, then with
+        for (int userNo = 0; userNo < users.length; userNo++) {
+            usersSuite.addTest
+                (TestConfiguration.changeUserDecorator
+                 (new DboPowersTest("testHardUpgrade",
+                                    autLev,
+                                    users[autLev-1][0], // dbo
+                                    users[autLev-1][0].concat(pwSuffix)),
+                  users[autLev-1][userNo],
+                  users[autLev-1][userNo].concat(pwSuffix)));
+        }
+
+        return DatabasePropertyTestSetup.
+            builtinAuthentication(usersSuite, users[autLev-1], pwSuffix);
+    }
+
+    /**
+     * Test database upgrade power enforcement
+     *
+     * @throws SQLException
+     */
+    public void testHardUpgrade() throws SQLException
+    {
+        println("testHardUpgrade: auth=" + this._authLevel +
+                " user="+getTestConfiguration().getUserName());
+
+        // make sure db is created
+        getConnection().close();
+        // shut it down in preparation for upgrade boot
+        bringDbDown();
+
+        String user = getTestConfiguration().getUserName();
+        String password = getTestConfiguration().getUserPassword();
+
+        DataSource ds = JDBCDataSource.getDataSource();
+        JDBCDataSource.setBeanProperty(
+            ds, "connectionAttributes", "upgrade=true");
+        JDBCDataSource.setBeanProperty(ds, "user", user);
+        JDBCDataSource.setBeanProperty(ds, "password", password);
+        try {
+            ds.getConnection();
+            vetHardUpgradeAttempt(user, null);
+        } catch (SQLException e) {
+            vetHardUpgradeAttempt(user, e);
+        }
+
+        bringDbDown();
+    }
+
+
+    /**
+     * Decide if the result of trying to hard upgrade the database is
+     * compliant with the semantics introduced by DERBY-2264.
+     *
+     * @param user The db user under which we tried to upgrade
+     * @param e    Exception caught during attempt, if any
+     */
+    private void vetHardUpgradeAttempt (String user, SQLException e)
+    {
+        vetAttempt(user, e, "2850J", "hard upgrade");
+    }
+
+    /**
+     * Decide if the result of trying operation yields expected result.
+     *
+     * @param user The db user under which we tried to upgrade
+     * @param e    Exception caught during attempted operation, if any
+     * @param state The expected SQL state if this operation fails due to
+     *             insufficient power
+     * @param operation string describing the operation attempted
+     */
+    private void vetAttempt (String user, SQLException e,
+                             String state, String operation)
+    {
         switch (_authLevel) {
         case NOAUTHENTICATION:
-            assertEquals("encryption, no authentication", null, e);
+            assertEquals(operation + ", no authentication", null, e);
             break;
         case AUTHENTICATION:
             if ("APP".equals(user)) {
-                assertEquals("encryption, authentication, db owner", null, e);
+                assertEquals(operation + ", authentication, db owner", null, e);
             } else {
-                assertSQLState("database encryption restriction, " +
-                               "authentication, not db owner", "2850I", e);
+                assertSQLState(operation + ", authentication, not db owner",
+                               state, e);
             }
             break;
         case SQLAUTHORIZATION:
             if ("TEST_DBO".equals(user)) {
-                assertEquals("encryption, SQL authorization, db owner",
+                assertEquals(operation + ", SQL authorization, db owner",
                              null, e);
             } else {
-                assertSQLState("encryption restriction, " +
-                               "SQL authorization, not db owner",
-                               "2850I", e);
+                assertSQLState(operation +", SQL authorization, not db owner",
+                               state, e);
             }
             break;
         default: