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 rh...@apache.org on 2007/03/14 17:49:37 UTC
svn commit: r518214 - 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/
testing/org/apache/derbyTe...
Author: rhillegas
Date: Wed Mar 14 09:49:35 2007
New Revision: 518214
URL: http://svn.apache.org/viewvc?view=rev&rev=518214
Log:
DERBY-2264: Commit Dag's patch DERBY-2264.5.diff, which restricts encryption powers to the DBA.
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
db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/DatabasePropertyTestSetup.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/DropDatabaseSetup.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/TestConfiguration.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=518214&r1=518213&r2=518214
==============================================================================
--- 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 Wed Mar 14 09:49:35 2007
@@ -119,7 +119,7 @@
//////////////////////////////////////////////////////////
DatabaseMetaData dbMetadata;
- final TransactionResourceImpl tr; // always access tr thru getTR()
+ TransactionResourceImpl tr; // always access tr thru getTR()
private HashMap lobHashMap = null;
private int lobHMKey = 0;
@@ -215,16 +215,37 @@
// See if user wants to create a new database.
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.
+ boolean isTwoPhaseEncryptionBoot = (!createBoot &&
+ isEncryptionBoot(info));
+
+ // Save original properties if we modified them for
+ // isTwoPhaseEncryptionBoot.
+ Properties savedInfo = null;
+
if (database != null)
{
// database already booted by someone else
tr.setDatabase(database);
+ isTwoPhaseEncryptionBoot = false;
}
else if (!shutdown)
{
- // Return false iff the monitor cannot handle a service of the type
- // indicated by the proptocol within the name. If that's the case
- // then we are the wrong driver.
+ if (isTwoPhaseEncryptionBoot) {
+ savedInfo = info;
+ info = removeEncryptionProps((Properties)info.clone());
+ }
+
+ // Return false iff the monitor cannot handle a service of the
+ // type indicated by the proptocol within the name. If that's
+ // the case then we are the wrong driver.
+
if (!bootDatabase(info))
{
tr.clearContextInError();
@@ -236,7 +257,8 @@
if (createBoot && !shutdown)
{
- // if we are shutting down don't attempt to boot or create the database
+ // if we are shutting down don't attempt to boot or create the
+ // database
if (tr.getDatabase() != null) {
addWarning(EmbedSQLWarning.newEmbedSQLWarning(SQLState.DATABASE_EXISTS, getDBName()));
@@ -276,12 +298,47 @@
// the rest.
tr.startTransaction();
+ if (isTwoPhaseEncryptionBoot) {
+ // DERBY-2264: shutdown and boot again with encryption
+ // 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);
+ }
+
+ // shutdown and reboot using saved properties which
+ // include the (re)encyption attributes
+ info = savedInfo;
+ handleException(tr.shutdownDatabaseException());
+ restoreContextStack();
+ tr = new TransactionResourceImpl(driver, url, info);
+ active = true;
+ setupContextStack();
+
+ if (!bootDatabase(info))
+ {
+ if (SanityManager.DEBUG) {
+ SanityManager.THROWASSERT(
+ "bootDatabase failed after initial plain boot " +
+ "for (re)encryption");
+ }
+ tr.clearContextInError();
+ setInactive();
+ return;
+ }
+ // don't need to check user credentials again, did
+ // that on first plain boot, so just start
+ tr.startTransaction();
+ }
+
// now we have the database connection, we can shut down
if (shutdown) {
if (!usingNoneAuth) {
- // DERBY-2264: Only allow db owner to shut down if
+ // DERBY-2264: Only allow database owner to shut down if
// authentication is on.
- checkIsDBOwner();
+ checkIsDBOwner(OP_SHUTDOWN);
}
throw tr.shutdownDatabaseException();
}
@@ -354,14 +411,8 @@
// combination with createFrom/restoreFrom/rollForwardRecoveryFrom
// attributes. Re-encryption is not
// allowed when restoring from backup.
- if (restoreCount != 0 &&
- (Boolean.valueOf(p.getProperty(
- Attribute.DATA_ENCRYPTION)).booleanValue() ||
- p.getProperty(Attribute.NEW_BOOT_PASSWORD) != null ||
- p.getProperty(Attribute.NEW_CRYPTO_EXTERNAL_KEY) != null
- ))
- {
- throw newSQLException(SQLState.CONFLICTING_RESTORE_ATTRIBUTES);
+ if (restoreCount != 0 && isEncryptionBoot(p)) {
+ throw newSQLException(SQLState.CONFLICTING_RESTORE_ATTRIBUTES);
}
@@ -377,6 +428,37 @@
}
/**
+ * Examine boot properties and determine if a boot with the given
+ * attributes would entail an encryption operation.
+ *
+ * @param p the attribute set
+ * @return true if a boot will encrypt or re-encrypt the database
+ */
+ private boolean isEncryptionBoot(Properties p)
+ {
+ return ((Boolean.valueOf(
+ p.getProperty(Attribute.DATA_ENCRYPTION)).booleanValue()) ||
+ (p.getProperty(Attribute.NEW_BOOT_PASSWORD) != null) ||
+ (p.getProperty(Attribute.NEW_CRYPTO_EXTERNAL_KEY) != null));
+ }
+
+
+ /**
+ * Remove any encryption properties from the given properties
+ *
+ * @param p the attribute set
+ * @return clone sans encryption properties
+ */
+ private Properties removeEncryptionProps(Properties p)
+ {
+ p.remove(Attribute.DATA_ENCRYPTION);
+ p.remove(Attribute.NEW_BOOT_PASSWORD);
+ p.remove(Attribute.NEW_CRYPTO_EXTERNAL_KEY);
+ return p;
+ }
+
+
+ /**
* Create a new connection based off of the
* connection passed in. Initializes state
* based on input connection, and copies
@@ -482,21 +564,38 @@
usingNoneAuth = true;
}
+ /* Enumerate operations controlled by database owner powers */
+ private static final int OP_ENCRYPT = 0;
+ private static final int OP_SHUTDOWN = 1;
/**
* Check if actual authenticationId is equal to the database owner's.
*
+ * @param operation attempted operation which needs database owner powers
* @throws SQLException if actual authenticationId is different
* from authenticationId of database owner.
*/
- private void checkIsDBOwner() throws SQLException
+ private void checkIsDBOwner(int operation) throws SQLException
{
final LanguageConnectionContext lcc = getLanguageConnection();
final String actualId = lcc.getAuthorizationId();
final String dbOwnerId = lcc.getDataDictionary().
getAuthorizationDatabaseOwner();
if (!actualId.equals(dbOwnerId)) {
- throw newSQLException(SQLState.AUTH_NOT_DB_OWNER,
- actualId, tr.getDBName());
+ switch (operation) {
+ case OP_ENCRYPT:
+ throw newSQLException(SQLState.AUTH_ENCRYPT_NOT_DB_OWNER,
+ actualId, tr.getDBName());
+ case OP_SHUTDOWN:
+ throw newSQLException(SQLState.AUTH_SHUTDOWN_NOT_DB_OWNER,
+ actualId, tr.getDBName());
+ default:
+ if (SanityManager.DEBUG) {
+ SanityManager.THROWASSERT(
+ "illegal checkIsDBOwner operation");
+ }
+ throw newSQLException(
+ SQLState.AUTH_DATABASE_CONNECTION_REFUSED);
+ }
}
}
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=518214&r1=518213&r2=518214
==============================================================================
--- 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 Wed Mar 14 09:49:35 2007
@@ -851,6 +851,13 @@
<arg>databaseName</arg>
</msg>
+ <msg>
+ <name>2850I.C</name>
+ <text>User '{0}' cannot (re)encrypt 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=518214&r1=518213&r2=518214
==============================================================================
--- 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 Wed Mar 14 09:49:35 2007
@@ -1379,7 +1379,8 @@
String AUTH_NOT_DATABASE_OWNER = "2850E";
String AUTH_GRANT_REVOKE_NOT_ALLOWED = "2850F";
String AUTH_NO_OBJECT_PERMISSION = "2850G";
- String AUTH_NOT_DB_OWNER = "2850H.C";
+ String AUTH_SHUTDOWN_NOT_DB_OWNER = "2850H.C";
+ String AUTH_ENCRYPT_NOT_DB_OWNER = "2850I.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=518214&r1=518213&r2=518214
==============================================================================
--- 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 Wed Mar 14 09:49:35 2007
@@ -36,7 +36,7 @@
*
* The tests are run in the cross product (cardinality 10) of contexts:
*
- * {client/server, embedded} x
+ * {client/server, embedded} x
* {no authentication, authentication and authentication/sqlAuthorization} x
* {data base owner, other user }
*
@@ -46,24 +46,54 @@
*/
public class DboPowersTest extends BaseJDBCTestCase
{
+ /* internal state */
+ final private int _authLevel;
+ final private String _dbo;
+ final private String _dboPassword;
+
/* test execution security context: one of three below */
- final private int authLevel;
final private static int NOAUTHENTICATION=0;
final private static int AUTHENTICATION=1;
final private static int SQLAUTHORIZATION=2;
-
+
+ final private static String[] secLevelNames = {
+ "noAuthentication",
+ "authentication",
+ "authentication + sqlAuthorization"};
+
+ /**
+ * Create a new instance of DboPowersTest (for shutdown test)
+ *
+ * @param name Fixture name
+ * @param authLevel authentication level with which test is run
+ */
+ public DboPowersTest(String name, int authLevel)
+ {
+ super(name);
+ this._authLevel = authLevel;
+ this._dbo = null;
+ this._dboPassword = null;
+ }
+
/**
- * Create a new instance of DboPowersTest
+ * Create a new instance of DboPowersTest (for encryption tests)
*
* @param name Fixture name
* @param authLevel authentication level with which test is run
+ * @param dbo Database owner
+ * @param dboPassword Database owner's password
*/
- public DboPowersTest(String name, int authLevel)
- {
- super(name);
- this.authLevel = authLevel;
+
+ public DboPowersTest(String name, int authLevel,
+ String dbo, String dboPassword)
+ {
+ super(name);
+ this._authLevel = authLevel;
+ this._dbo = dbo;
+ this._dboPassword = dboPassword;
}
+
/**
* Construct top level suite in this JUnit test
*
@@ -72,67 +102,73 @@
public static Test suite()
{
TestSuite suite = new TestSuite("DboPowersTest");
- suite.addTest(dboSuite("embedded"));
- suite.addTest(TestConfiguration.clientServerDecorator(
- dboSuite("client")));
+
+ suite.addTest(dboShutdownSuite("suite: shutdown powers, embedded"));
+ suite.addTest(
+ TestConfiguration.clientServerDecorator(
+ dboShutdownSuite("suite: shutdown powers, client")));
+
+ suite.addTest(dboEncryptionSuite("suite: encryption powers, embedded"));
+ suite.addTest(
+ TestConfiguration.clientServerDecorator(
+ dboEncryptionSuite("suite: encryption powers, client")));
+
return suite;
}
-
+
+ /**
+ * Users used by both dboShutdownSuite and dboEncryptionSuite
+ */
+ final static String[][] users = {
+ /* authLevel == AUTHENTICATION: dbo is APP/APP for db 'wombat',
+ * so use that as first user. Otherwise,
+ * builtinAuthentication decorator's db shutdown fails to
+ * work after DERBY-2264(!).
+ */
+ {"APP", "U1"},
+ /* authLevel == SQLAUTHORIZATION: sqlAuthorizationDecorator
+ * decorator presumes TEST_DBO as dbo, so add it to set of
+ * valid users. Uses a fresh db 'dbsqlauth', not 'wombat'.
+ */
+ {"TEST_DBO", "U1"}};
+
+ final static String pwSuffix = "pwSuffix";
+
+
/**
*
- * Construct default suite of tests
+ * Construct suite of tests for shutdown database action
*
- * @param framework Derby framework
- * @return A suite containing the test cases 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,
- * in all five incarnations of tests.
- */
- private static Test dboSuite(String framework)
- {
- final String[][] users = {
- /* authLevel == AUTHENTICATION: dbo is APP/APP for db 'wombat',
- * so use that as first user. Otherwise,
- * builtinAuthentication decorator's db shutdown fails to
- * work after DERBY-2264(!).
- */
- {"APP", "U1"},
- /* authLevel == SQLAUTHORIZATION: sqlAuthorizationDecorator
- * decorator presumes TEST_DBO as dbo, so add it to set of
- * valid users. Uses a fresh db 'dbsqlauth', not 'wombat'.
- */
- {"TEST_DBO", "U1"}};
-
- final String pwSuffix = "pwSuffix";
-
+ * @param framework Derby framework name
+ * @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,
+ * so there are in all five incarnations of tests.
+ */
+ private static Test dboShutdownSuite(String framework)
+ {
Test tests[] = new Test[SQLAUTHORIZATION+1]; // one per authLevel
- tests[NOAUTHENTICATION] = collectFixtures(NOAUTHENTICATION);
+ /* Tests without any authorization active (level ==
+ * NOAUTHENTICATION).
+ */
+ TestSuite noauthSuite =
+ new TestSuite("suite: security level=" +
+ secLevelNames[NOAUTHENTICATION]);
+ noauthSuite.addTest(new DboPowersTest("testShutDown",
+ NOAUTHENTICATION));;
+ tests[NOAUTHENTICATION] = noauthSuite;
/* First decorate with users, then with authentication. Do this
* twice, once for authentication only, and once for
- * authentication and sqlAuthorization (see extra decorator
+ * authentication + sqlAuthorization (see extra decorator
* added below).
*/
- for (int autLev = AUTHENTICATION;
+ for (int autLev = AUTHENTICATION;
autLev <= SQLAUTHORIZATION ; autLev++) {
- // add decorator for different users authenticated
- TestSuite userSuite = new TestSuite(
- "userSuite:"+ (autLev == AUTHENTICATION ? "authentication"
- : "sqlAuthorization"));
-
- for (int userNo = 0; userNo < users.length; userNo++) {
- userSuite.addTest
- (TestConfiguration.changeUserDecorator
- (collectFixtures(autLev),
- users[autLev-1][userNo],
- users[autLev-1][userNo].concat(pwSuffix)));
- }
-
- tests[autLev] = DatabasePropertyTestSetup.
- builtinAuthentication(userSuite, users[autLev-1], pwSuffix);
+ tests[autLev] = wrapShutdownUserTests(autLev);
}
TestSuite suite = new TestSuite("dboPowers:"+framework);
@@ -149,23 +185,39 @@
suite.addTest(
TestConfiguration.
sqlAuthorizationDecorator(tests[SQLAUTHORIZATION]));
-
+
return suite;
}
+
/**
- * Pick up individual test fixtures explicitly, since we need to
- * provide the context.
+ * Wraps the shutdown fixture in decorators to run with data
+ * base owner and other valid user.
*
- * @param authLevel tests to be run with this security level
+ * @param autLev security context to use
*/
- private static TestSuite collectFixtures(int authLevel)
+
+ private static Test wrapShutdownUserTests(int autLev)
{
- TestSuite suite = new TestSuite("dboPowersTests");
- suite.addTest(new DboPowersTest("testShutDown", authLevel));
- return suite;
+ // 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("testShutDown", autLev),
+ users[autLev-1][userNo],
+ users[autLev-1][userNo].concat(pwSuffix)));
+ }
+
+ return DatabasePropertyTestSetup.
+ builtinAuthentication(usersSuite, users[autLev-1], pwSuffix);
}
+
/**
* Test database shutdown power enforcement
*
@@ -173,6 +225,9 @@
*/
public void testShutDown() throws SQLException
{
+ println("testShutDown: auth=" + this._authLevel +
+ " user="+getTestConfiguration().getUserName());
+
// make sure db is booted
getConnection().close();
@@ -202,22 +257,22 @@
* Decide if the result of trying to shut down the database is
* compliant with the semantics introduced by DERBY-2264.
*
- * @throws SQLException
*/
private void vetShutdownException (String user, SQLException e)
{
- switch (authLevel) {
+ switch (_authLevel) {
case NOAUTHENTICATION:
- assertSQLState("database shutdown, no authentication",
+ assertSQLState("database shutdown, no authentication",
"08006", e);
break;
case AUTHENTICATION:
if ("APP".equals(user)) {
- assertSQLState("database shutdown, authentication, db owner",
+ assertSQLState("database shutdown, authentication, db owner",
"08006", e);
} else {
- assertSQLState("database shutdown restriction, authentication," +
- " not db owner", "2850H", e);
+ assertSQLState("database shutdown restriction, " +
+ "authentication, not db owner",
+ "2850H", e);
}
break;
case SQLAUTHORIZATION:
@@ -225,13 +280,304 @@
assertSQLState("database shutdown, SQL authorization, db owner",
"08006", e);
} else {
- assertSQLState("database shutdown restriction, " +
+ assertSQLState("database shutdown restriction, " +
"SQL authorization, not db owner",
"2850H", e);
}
break;
default:
- fail("test error");
+ fail("test error: invalid authLevel: " + _authLevel);
+ break;
+ }
+ }
+
+ /**
+ *
+ * Construct suite of tests for database encryption action
+ *
+ * @param framework Derby framework name
+ * @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,
+ * so there are in all five incarnations of tests.
+ */
+ private static Test dboEncryptionSuite(String framework)
+ {
+ Test tests[] = new Test[SQLAUTHORIZATION+1]; // one per authLevel
+
+ /* Tests without any authorization active (level ==
+ * NOAUTHENTICATION). Note use of no shutdown decorator
+ * variants: Necessary since framework doesn't know
+ * bootPassword.
+ */
+ TestSuite noauthSuite =
+ new TestSuite("suite: security level=" +
+ secLevelNames[NOAUTHENTICATION]);
+
+ for (int tNo = 0; tNo < encryptionTests.length; tNo++) {
+ noauthSuite.addTest(
+ TestConfiguration.singleUseDatabaseDecoratorNoShutdown(
+ new DboPowersTest(encryptionTests[tNo], NOAUTHENTICATION,
+ "foo", "bar")));
+ }
+
+ tests[NOAUTHENTICATION] = noauthSuite;
+
+ /* Tests with authentication and sql authorization
+ */
+ for (int autLev = AUTHENTICATION;
+ autLev <= SQLAUTHORIZATION ; autLev++) {
+
+ tests[autLev] = wrapEncryptionUserTests(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(tests[SQLAUTHORIZATION]);
+
+ return suite;
+ }
+
+ /**
+ * Wraps the encryption fixtures in decorators to run with data
+ * base owner and other valid user.
+ *
+ * @param autLev security context to use
+ */
+
+ private static Test wrapEncryptionUserTests(int autLev)
+ {
+ // add decorator for different users authenticated
+ TestSuite usersSuite =
+ new TestSuite("usersSuite: security level=" +
+ secLevelNames[autLev]);
+
+ // First decorate with users, then with authentication. Note
+ // use of no teardown / no shutdown decorator variants:
+ // Necessary since framework doesnt know bootPassword
+ for (int userNo = 0; userNo < users.length; userNo++) {
+ for (int tNo = 0; tNo < encryptionTests.length; tNo++) {
+ Test test = TestConfiguration.changeUserDecorator
+ (new DboPowersTest(encryptionTests[tNo],
+ autLev,
+ users[autLev-1][0], // dbo
+ users[autLev-1][0].concat(pwSuffix)),
+ users[autLev-1][userNo],
+ users[autLev-1][userNo].concat(pwSuffix));
+ test = DatabasePropertyTestSetup.builtinAuthenticationNoTeardown
+ (test, users[autLev-1], pwSuffix);
+ if (autLev == AUTHENTICATION) {
+ test = TestConfiguration.
+ singleUseDatabaseDecoratorNoShutdown(test);
+ } else {
+ test = TestConfiguration.
+ sqlAuthorizationDecoratorSingleUse(test);
+ }
+ usersSuite.addTest(test);
+ }
+ }
+ return usersSuite;
+ }
+
+ /**
+ * Enumerates the encryption tests
+ */
+ final static String[] encryptionTests = { "testEncrypt", "testReEncrypt" };
+
+ /**
+ * Test database encryption for an already created
+ * database. Note: The test needs to shut down the database for
+ * the single use decorators to work.
+ *
+ * @throws SQLException
+ */
+ public void testEncrypt() throws SQLException
+ {
+ println("testEncrypt: auth=" + this._authLevel +
+ " user="+getTestConfiguration().getUserName());
+
+ // make sure db is created
+ getConnection().close();
+
+ // shut down database in preparation for encryption
+ bringDbDown();
+
+ // make encryption attempt
+ String user = getTestConfiguration().getUserName();
+ String password = getTestConfiguration().getUserPassword();
+ String bootPassword="12345678";
+ DataSource ds = JDBCDataSource.getDataSource();
+
+ JDBCDataSource.setBeanProperty(ds, "connectionAttributes",
+ "dataEncryption=true;bootPassword=" +
+ bootPassword);
+ JDBCDataSource.setBeanProperty(ds, "user", user);
+ JDBCDataSource.setBeanProperty(ds, "password", password);
+
+ try {
+ ds.getConnection();
+ vetEncryptionAttempt(user, null);
+ } catch (SQLException e) {
+ vetEncryptionAttempt(user, e);
+ bringDbDown();
+ return;
+ }
+
+ // we managed to encrypt: bring db down and up again to verify
+ bringDbDown();
+ bringDbUp(bootPassword);
+ bringDbDown();
+ }
+
+
+ /**
+ * Test database re-encryption for an already encrypted
+ * database. Note: The test needs to shut down database for the
+ * single use decorators to work.
+ *
+ * @throws SQLException
+ */
+ public void testReEncrypt() throws SQLException
+ {
+ println("testReEncrypt: auth=" + this._authLevel +
+ " user="+getTestConfiguration().getUserName());
+
+ // make sure db is created
+ getConnection().close();
+
+ // shut down database in preparation for encryption
+ bringDbDown();
+
+ String bootPassword="12345678";
+ doEncrypt(bootPassword);
+ bringDbDown();
+
+ // make re-encryption attempt
+ String user = getTestConfiguration().getUserName();
+ String password = getTestConfiguration().getUserPassword();
+ String newBootPassword="87654321";
+ DataSource ds = JDBCDataSource.getDataSource();
+
+ JDBCDataSource.setBeanProperty(ds, "connectionAttributes",
+ "bootPassword=" + bootPassword +
+ ";newBootPassword=" + newBootPassword);
+ JDBCDataSource.setBeanProperty(ds, "user", user);
+ JDBCDataSource.setBeanProperty(ds, "password", password);
+
+ try {
+ ds.getConnection();
+ vetEncryptionAttempt(user, null);
+ } catch (SQLException e) {
+ vetEncryptionAttempt(user, e);
+ bringDbDown();
+ return;
+ }
+
+ // we managed to encrypt: bring db down and up again to verify
+ bringDbDown();
+ bringDbUp(newBootPassword);
+ bringDbDown();
+ }
+
+
+ /**
+ * Encrypt database, as owner (not testing encryption power here)
+ * @param bootPassword
+ * @throws SQLException
+ */
+ private void doEncrypt(String bootPassword) throws SQLException
+ {
+ DataSource ds = JDBCDataSource.getDataSource();
+ JDBCDataSource.setBeanProperty(ds, "connectionAttributes",
+ "dataEncryption=true;bootPassword=" +
+ bootPassword);
+ JDBCDataSource.setBeanProperty(ds, "user", _dbo);
+ JDBCDataSource.setBeanProperty(ds, "password", _dboPassword);
+ ds.getConnection();
+ }
+
+
+ /**
+ * Shut down database, as db owner (not testing that power here)
+ */
+ private void bringDbDown()
+ {
+ DataSource ds = JDBCDataSource.getDataSource();
+ JDBCDataSource.setBeanProperty(
+ ds, "connectionAttributes", "shutdown=true");
+ JDBCDataSource.setBeanProperty(ds, "user", _dbo);
+ JDBCDataSource.setBeanProperty(ds, "password", _dboPassword);
+ try {
+ ds.getConnection();
+ fail("shutdown failed: expected exception");
+ } catch (SQLException e) {
+ assertSQLState("database shutdown", "08006", e);
+ }
+ }
+
+
+ /**
+ * Boot database back up after encryption using current user,
+ * should succeed
+ *
+ * @param bootPassword Boot using this bootPassword
+ * @throws SQLException
+ */
+ private void bringDbUp(String bootPassword) throws SQLException
+ {
+ String user = getTestConfiguration().getUserName();
+ String password = getTestConfiguration().getUserPassword();
+ DataSource ds = JDBCDataSource.getDataSource();
+ JDBCDataSource.setBeanProperty(
+ ds, "connectionAttributes", "bootPassword=" + bootPassword);
+ JDBCDataSource.setBeanProperty(ds, "user", user);
+ JDBCDataSource.setBeanProperty(ds, "password", password);
+ ds.getConnection().close();
+ }
+
+ /**
+ * Decide if the result of trying to (re)encrypt the database is
+ * compliant with the semantics introduced by DERBY-2264.
+ *
+ * @param user The db user under which we tried to encrypt
+ * @param e Exception caught during attempt, if any
+ */
+ private void vetEncryptionAttempt (String user, SQLException e)
+ {
+ switch (_authLevel) {
+ case NOAUTHENTICATION:
+ assertEquals("encryption, no authentication", null, e);
+ break;
+ case AUTHENTICATION:
+ if ("APP".equals(user)) {
+ assertEquals("encryption, authentication, db owner", null, e);
+ } else {
+ assertSQLState("database encryption restriction, " +
+ "authentication, not db owner", "2850I", e);
+ }
+ break;
+ case SQLAUTHORIZATION:
+ if ("TEST_DBO".equals(user)) {
+ assertEquals("encryption, SQL authorization, db owner",
+ null, e);
+ } else {
+ assertSQLState("encryption restriction, " +
+ "SQL authorization, not db owner",
+ "2850I", e);
+ }
+ break;
+ default:
+ fail("test error: invalid authLevel: " + _authLevel);
break;
}
}
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/DatabasePropertyTestSetup.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/DatabasePropertyTestSetup.java?view=diff&rev=518214&r1=518213&r2=518214
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/DatabasePropertyTestSetup.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/DatabasePropertyTestSetup.java Wed Mar 14 09:49:35 2007
@@ -132,6 +132,60 @@
}
/**
+ * Decorate a test so that the database has authentication enabled
+ * using the BUILTIN provider and the set of users passed in.
+ * The password for each user is set to the user's name with
+ * the value of passwordToken appended.
+ * <BR>
+ * The decorated test can use BaseJDBCTestCase.openUserConnection(String user)
+ * method to simplify using authentication.
+ * <P>
+ * Assumption is that no authentication was enabled upon entry.
+ * <P>
+ * Current user is set to the first user in the list users[0].
+ * <P>
+ * In contrast to plain builtinAuthentication, here the
+ * authentication nor users are *NOT* removed by the decorator's
+ * tearDown method.
+ * @param test Test to be decorated.
+ * @param users Set of users for authentication.
+ * @return Decorated test.
+ */
+ public static Test builtinAuthenticationNoTeardown(Test test, String[] users,
+ String passwordToken)
+ {
+ final Properties userProps = new Properties();
+ final Properties authProps = new Properties();
+
+ authProps.setProperty("derby.connection.requireAuthentication", "true");
+ authProps.setProperty("derby.authentication.provider", "BUILTIN");
+
+ for (int i = 0; i < users.length; i++)
+ {
+ String user = users[i];
+ userProps.setProperty("derby.user." + user,
+ TestConfiguration.getPassword(user, passwordToken));
+ }
+
+ test = getNoTeardownInstance(test, authProps, true);
+ test = new ChangeUserSetup(test, users[0],
+ TestConfiguration.getPassword(users[0], passwordToken),
+ passwordToken);
+ test = getNoTeardownInstance(test, userProps, false);
+ return test;
+ }
+
+ private static DatabasePropertyTestSetup getNoTeardownInstance(
+ Test test, Properties p, boolean staticp)
+ {
+ return new DatabasePropertyTestSetup(test, p, staticp) {
+ protected void tearDown()
+ throws java.lang.Exception {
+ }
+ };
+ }
+
+ /**
* Decorate a test so that it sets a single database property
* at setUp and resets it at tearDown. Shorthand for
* using DatabasePropertyTestSetup when only a single property is needed.
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/DropDatabaseSetup.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/DropDatabaseSetup.java?view=diff&rev=518214&r1=518213&r2=518214
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/DropDatabaseSetup.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/DropDatabaseSetup.java Wed Mar 14 09:49:35 2007
@@ -37,7 +37,7 @@
*/
class DropDatabaseSetup extends TestSetup {
- private final String logicalDBName;
+ final String logicalDBName;
DropDatabaseSetup(Test test, String logicalDBName) {
super(test);
this.logicalDBName = logicalDBName;
@@ -56,18 +56,25 @@
String dbName = config.getPhysicalDatabaseName(logicalDBName);
DataSource ds = JDBCDataSource.getDataSource(dbName);
JDBCDataSource.shutdownDatabase(ds);
-
+
+ removeDatabase();
+ }
+
+ void removeDatabase()
+ {
+ TestConfiguration config = TestConfiguration.getCurrent();
+ String dbName = config.getPhysicalDatabaseName(logicalDBName);
dbName = dbName.replace('/', File.separatorChar);
-
String dsh = BaseTestCase.getSystemProperty("derby.system.home");
- if (dsh == null)
+ if (dsh == null) {
fail("not implemented");
- else
+ } else {
dbName = dsh + File.separator + dbName;
-
+ }
removeDirectory(dbName);
- }
-
+ }
+
+
static void removeDirectory(String path)
{
final File dir = new File(path);
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/TestConfiguration.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/TestConfiguration.java?view=diff&rev=518214&r1=518213&r2=518214
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/TestConfiguration.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/TestConfiguration.java Wed Mar 14 09:49:35 2007
@@ -314,7 +314,37 @@
return new DatabaseChangeSetup(new DropDatabaseSetup(test, dbName), dbName, dbName, true);
}
-
+
+ /**
+ * Decorate a test to use a new database that is created upon the
+ * first connection request to the database and deleted at
+ * tearDown. In contrast to plain singleUseDatabaseDecorator, the
+ * database is expected to be shutdown by the test. The
+ * configuration differs only from the current configuration by
+ * the list of used databases. The new database name is generated
+ * automatically as 'singleUse/oneuseXX' where 'XX' is the unique
+ * number. The generated database name is added at the end of
+ * <code>usedDbNames</code> and assigned as a default database
+ * name. This decorator expects the database file to be local so
+ * it can be removed.
+ * @param test Test to be decorated
+ * @return decorated test.
+ */
+ public static TestSetup singleUseDatabaseDecoratorNoShutdown(Test test)
+ {
+ String dbName = generateUniqueDatabaseName();
+
+ return new DatabaseChangeSetup(
+ new DropDatabaseSetup(test, dbName)
+ {
+ protected void tearDown() throws Exception {
+ // test responsible for shutdown
+ removeDatabase();
+ }
+ },
+ dbName, dbName, true);
+ }
+
/**
* Decorate a test to use a new database that is created upon the
* first connection request to the database and shutdown & deleted at
@@ -404,7 +434,45 @@
new DatabaseChangeSetup(setSQLAuthMode, DEFAULT_DBNAME_SQL, DEFAULT_DBNAME_SQL, true),
"TEST_DBO", "dummy"); // DRDA doesn't like empty pw
}
+
+
+ /**
+ * Same as sqlAuthorizationDecorator, except that the database is dropped
+ * at teardown and the test is responsible for shutting down the database.
+ *
+ * @param test Test to be decorated
+ * @return decorated test.
+ *
+ * @see TestConfiguration#sqlAuthorizationDecorator(Test test)
+ */
+ public static Test sqlAuthorizationDecoratorSingleUse(Test test)
+ {
+ // Set the SQL authorization mode as a database property
+ // with a modified DatabasePropertyTestSetup that does not
+ // reset it.
+ final Properties sqlAuth = new Properties();
+ sqlAuth.setProperty("derby.database.sqlAuthorization", "true");
+ Test setSQLAuthMode = new DatabasePropertyTestSetup(test,
+ sqlAuth, true) {
+ protected void tearDown() { }
+ };
+
+
+ setSQLAuthMode = new DatabaseChangeSetup(
+ new DropDatabaseSetup(setSQLAuthMode, DEFAULT_DBNAME_SQL) {
+ protected void tearDown() throws Exception {
+ // test responsible for shutdown
+ removeDatabase();
+ }
+ },
+ DEFAULT_DBNAME_SQL, DEFAULT_DBNAME_SQL, true);
+
+ return changeUserDecorator(setSQLAuthMode,
+ "TEST_DBO",
+ "dummy"); // DRDA doesn't like empty pw
+ }
+
/**
* Utility version of sqlAuthorizationDecorator that also sets
* up authentication. A combination of