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 2012/01/31 19:14:41 UTC
svn commit: r1238727 - in /db/derby/code/trunk/java:
engine/org/apache/derby/iapi/reference/ engine/org/apache/derby/impl/jdbc/
engine/org/apache/derby/impl/jdbc/authentication/
engine/org/apache/derby/loc/ shared/org/apache/derby/shared/common/referen...
Author: rhillegas
Date: Tue Jan 31 18:14:41 2012
New Revision: 1238727
URL: http://svn.apache.org/viewvc?rev=1238727&view=rev
Log:
DERBY-866: Add expiration limits for NATIVE passwords.
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Property.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/authentication/AuthenticationServiceBase.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/authentication/NativeAuthenticationServiceImpl.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/lang/NativeAuthenticationServiceTest.java
Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Property.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Property.java?rev=1238727&r1=1238726&r2=1238727&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Property.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Property.java Tue Jan 31 18:14:41 2012
@@ -818,6 +818,21 @@ public interface Property {
public static final String AUTHENTICATION_PROVIDER_NATIVE_LOCAL =
AUTHENTICATION_PROVIDER_NATIVE + AUTHENTICATION_PROVIDER_LOCAL_SUFFIX;
+ // lifetime (in milliseconds) of a NATIVE password. if <= 0, then the password never expires
+ public static final String AUTHENTICATION_NATIVE_PASSWORD_LIFETIME =
+ "derby.authentication.native.passwordLifetimeMillis";
+
+ // default lifetime (in milliseconds) of a NATIVE password. 31 days.
+ public static final long MILLISECONDS_IN_DAY = 1000L * 60L * 60L * 24L;
+ public static final long AUTHENTICATION_NATIVE_PASSWORD_LIFETIME_DEFAULT = MILLISECONDS_IN_DAY * 31L;
+
+ // threshhold for raising a warning that a password is about to expire.
+ // raise a warning if the remaining password lifetime is less than this proportion of the max lifetime.
+ public static final String AUTHENTICATION_PASSWORD_EXPIRATION_THRESHOLD =
+ "derby.authentication.native.passwordLifetimeThreshold";
+ public static final double AUTHENTICATION_PASSWORD_EXPIRATION_THRESHOLD_DEFAULT = 0.125;
+
+
/**
* Property that specifies the name of the hash algorithm to use with
* the configurable hash authentication scheme.
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?rev=1238727&r1=1238726&r2=1238727&view=diff
==============================================================================
--- 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 Tue Jan 31 18:14:41 2012
@@ -1240,15 +1240,24 @@ public abstract class EmbedConnection im
}
// Let's authenticate now
-
- if (!authenticationService.authenticate(
- dbname,
- userInfo
- )) {
+ boolean authenticationSucceeded = true;
+
+ try {
+ authenticationSucceeded = authenticationService.authenticate( dbname, userInfo );
+ }
+ catch (SQLWarning warnings)
+ {
+ //
+ // Let the user handle the warning that her password is about to expire.
+ //
+ addWarning( warnings );
+ }
+
+ if ( !authenticationSucceeded )
+ {
throw newSQLException(SQLState.NET_CONNECT_AUTH_FAILED,
MessageService.getTextMessage(MessageId.AUTH_INVALID));
-
}
// If authentication is not on, we have to raise a warning if sqlAuthorization is ON
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/authentication/AuthenticationServiceBase.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/authentication/AuthenticationServiceBase.java?rev=1238727&r1=1238726&r2=1238727&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/authentication/AuthenticationServiceBase.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/authentication/AuthenticationServiceBase.java Tue Jan 31 18:14:41 2012
@@ -407,12 +407,51 @@ public abstract class AuthenticationServ
}
}
+ if ( Property.AUTHENTICATION_NATIVE_PASSWORD_LIFETIME.equals( key ) )
+ {
+ if ( parsePasswordLifetime( stringValue ) == null )
+ {
+ throw StandardException.newException
+ ( SQLState.BAD_PASSWORD_LIFETIME, Property.AUTHENTICATION_NATIVE_PASSWORD_LIFETIME );
+ }
+ }
+
+ if ( Property.AUTHENTICATION_PASSWORD_EXPIRATION_THRESHOLD.equals( key ) )
+ {
+ if ( parsePasswordThreshold( stringValue ) == null )
+ {
+ throw StandardException.newException
+ ( SQLState.BAD_PASSWORD_LIFETIME, Property.AUTHENTICATION_PASSWORD_EXPIRATION_THRESHOLD );
+ }
+ }
+
return false;
}
private StandardException badNativeAuthenticationChange()
{
return StandardException.newException( SQLState.PROPERTY_BAD_NATIVE_CHANGE );
}
+ /** Parse the value of the password lifetime property. Return null if it is bad. */
+ protected Long parsePasswordLifetime( String passwordLifetimeString )
+ {
+ try {
+ long passwordLifetime = Long.parseLong( passwordLifetimeString );
+
+ if ( passwordLifetime < 0L ) { passwordLifetime = 0L; }
+
+ return new Long( passwordLifetime );
+ } catch (Exception e) { return null; }
+ }
+ /** Parse the value of the password expiration threshold property. Return null if it is bad. */
+ protected Double parsePasswordThreshold( String expirationThresholdString )
+ {
+ try {
+ double expirationThreshold = Double.parseDouble( expirationThresholdString );
+
+ if ( expirationThreshold <= 0L ) { return null; }
+ else { return new Double( expirationThreshold ); }
+ } catch (Exception e) { return null; }
+ }
/**
@see PropertySetCallback#validate
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/authentication/NativeAuthenticationServiceImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/authentication/NativeAuthenticationServiceImpl.java?rev=1238727&r1=1238726&r2=1238727&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/authentication/NativeAuthenticationServiceImpl.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/authentication/NativeAuthenticationServiceImpl.java Tue Jan 31 18:14:41 2012
@@ -26,6 +26,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Connection;
import java.sql.SQLException;
+import java.sql.SQLWarning;
import java.util.Arrays;
import javax.sql.DataSource;
@@ -39,6 +40,7 @@ import org.apache.derby.iapi.sql.diction
import org.apache.derby.iapi.reference.Attribute;
import org.apache.derby.iapi.reference.SQLState;
import org.apache.derby.authentication.UserAuthenticator;
+import org.apache.derby.iapi.error.SQLWarningFactory;
import org.apache.derby.iapi.error.StandardException;
import org.apache.derby.iapi.services.monitor.Monitor;
import org.apache.derby.iapi.services.property.PropertyUtil;
@@ -87,6 +89,9 @@ public final class NativeAuthenticationS
private String _credentialsDB;
private boolean _authenticateDatabaseOperationsLocally;
+ private long _passwordLifetimeMillis = Property.AUTHENTICATION_NATIVE_PASSWORD_LIFETIME_DEFAULT;
+ private double _passwordExpirationThreshold = Property.AUTHENTICATION_PASSWORD_EXPIRATION_THRESHOLD_DEFAULT;
+ private String _badlyFormattedPasswordProperty;
///////////////////////////////////////////////////////////////////////////////////
//
@@ -149,6 +154,39 @@ public final class NativeAuthenticationS
if ( _credentialsDB.length() == 0 ) { _credentialsDB = null; }
}
+
+ //
+ // Let the application override password lifespans.
+ //
+ _badlyFormattedPasswordProperty = null;
+ String passwordLifetimeString = PropertyUtil.getPropertyFromSet
+ (
+ properties,
+ Property.AUTHENTICATION_NATIVE_PASSWORD_LIFETIME
+ );
+ if ( passwordLifetimeString != null )
+ {
+ Long passwordLifetime = parsePasswordLifetime( passwordLifetimeString );
+
+ if ( passwordLifetime != null ) { _passwordLifetimeMillis = passwordLifetime.longValue(); }
+ else
+ { _badlyFormattedPasswordProperty = Property.AUTHENTICATION_NATIVE_PASSWORD_LIFETIME; }
+ }
+
+ String expirationThresholdString = PropertyUtil.getPropertyFromSet
+ (
+ properties,
+ Property.AUTHENTICATION_PASSWORD_EXPIRATION_THRESHOLD
+ );
+ if ( expirationThresholdString != null )
+ {
+ Double expirationThreshold = parsePasswordThreshold( expirationThresholdString );
+
+ if ( expirationThreshold != null ) { _passwordExpirationThreshold = expirationThreshold.doubleValue(); }
+ else
+ { _badlyFormattedPasswordProperty = Property.AUTHENTICATION_PASSWORD_EXPIRATION_THRESHOLD; }
+ }
+
}
/**
@@ -178,6 +216,12 @@ public final class NativeAuthenticationS
throw StandardException.newException( SQLState.BAD_NATIVE_AUTH_SPEC );
}
+ if ( _badlyFormattedPasswordProperty != null )
+ {
+ throw StandardException.newException
+ ( SQLState.BAD_PASSWORD_LIFETIME, _badlyFormattedPasswordProperty );
+ }
+
// Initialize the MessageDigest class engine here
// (we don't need to do that ideally, but there is some
// overhead the first time it is instantiated.
@@ -340,7 +384,7 @@ public final class NativeAuthenticationS
String userPassword,
String databaseName
)
- throws StandardException
+ throws StandardException, SQLWarning
{
// this catches the case when someone specifies derby.authentication.provider=NATIVE::LOCAL
// at the system level
@@ -353,6 +397,8 @@ public final class NativeAuthenticationS
"org.apache.derby.jdbc.EmbeddedSimpleDataSource" :
"org.apache.derby.jdbc.EmbeddedDataSource";
+ SQLWarning warnings = null;
+
try {
DataSource dataSource = (DataSource) Class.forName( dataSourceName ).newInstance();
@@ -361,6 +407,8 @@ public final class NativeAuthenticationS
callDataSourceSetter( dataSource, "setPassword", userPassword );
Connection conn = dataSource.getConnection();
+
+ warnings = conn.getWarnings();
conn.close();
}
catch (ClassNotFoundException cnfe) { throw wrap( cnfe ); }
@@ -378,6 +426,10 @@ public final class NativeAuthenticationS
else { throw wrap( se ); }
}
+ // let warnings percolate up so that EmbedConnection can handle notifications
+ // about expiring passwords
+ if ( warnings != null ) { throw warnings; }
+
// If we get here, then we successfully connected to the credentials database. Hooray.
return true;
}
@@ -445,17 +497,48 @@ public final class NativeAuthenticationS
PasswordHasher hasher = new PasswordHasher( userDescriptor.getHashingScheme() );
char[] candidatePassword = hasher.hashPasswordIntoString( userName, userPassword ).toCharArray();
char[] actualPassword = userDescriptor.getAndZeroPassword();
+
+ try {
+ if ( (candidatePassword == null) || (actualPassword == null)) { return false; }
+ if ( candidatePassword.length != actualPassword.length ) { return false; }
- if ( (candidatePassword == null) || (actualPassword == null)) { return false; }
- if ( candidatePassword.length != actualPassword.length ) { return false; }
-
- for ( int i = 0; i < candidatePassword.length; i++ )
+ for ( int i = 0; i < candidatePassword.length; i++ )
+ {
+ if ( candidatePassword[ i ] != actualPassword[ i ] ) { return false; }
+ }
+ } finally
{
- if ( candidatePassword[ i ] != actualPassword[ i ] ) { return false; }
+ Arrays.fill( candidatePassword, (char) 0 );
+ Arrays.fill( actualPassword, (char) 0 );
+ }
+
+ //
+ // Password is good. Check whether the password has expired or will expire soon.
+ //
+ if ( _passwordLifetimeMillis > 0 )
+ {
+ long passwordAge = System.currentTimeMillis() - userDescriptor.getLastModified().getTime();
+ long remainingLifetime = _passwordLifetimeMillis - passwordAge;
+
+ //
+ // Oops, the password has expired. Fail the authentication. Say nothing more
+ // so that we give password crackers as little information as possible.
+ //
+ if ( remainingLifetime <= 0L )
+ {
+ // The DBO's password never expires.
+ if ( !dd.getAuthorizationDatabaseOwner().equals( userName ) ) { return false; }
+ else { remainingLifetime = 0L; }
+ }
+
+ long expirationThreshold = (long) ( _passwordLifetimeMillis * _passwordExpirationThreshold );
+
+ if ( remainingLifetime <= expirationThreshold )
+ {
+ long daysRemaining = remainingLifetime / Property.MILLISECONDS_IN_DAY;
+ throw SQLWarningFactory.newSQLWarning( SQLState.PASSWORD_EXPIRES_SOON, Long.toString( daysRemaining ) );
+ }
}
-
- Arrays.fill( candidatePassword, (char) 0 );
- Arrays.fill( actualPassword, (char) 0 );
return true;
}
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?rev=1238727&r1=1238726&r2=1238727&view=diff
==============================================================================
--- 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 Tue Jan 31 18:14:41 2012
@@ -211,6 +211,12 @@ Guide.
<text>SQL authorization is being used without first enabling authentication.</text>
</msg>
+ <msg>
+ <name>01J15</name>
+ <text>Your password will expire in {0} day(s). Please use the SYSCS_UTIL.SYSCS_MODIFY_PASSWORD procedure to change your password.</text>
+ <arg>remainingDays</arg>
+ </msg>
+
</family>
<family>
@@ -1250,6 +1256,12 @@ Guide.
</msg>
<msg>
+ <name>4251J</name>
+ <text>The value for the property '{0}' is formatted badly.</text>
+ <arg>propertyName</arg>
+ </msg>
+
+ <msg>
<name>42601</name>
<text>In an ALTER TABLE statement, the column '{0}' has been specified as NOT NULL and either the DEFAULT clause was not specified or was specified as DEFAULT NULL.</text>
<arg>columnName</arg>
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?rev=1238727&r1=1238726&r2=1238727&view=diff
==============================================================================
--- 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 Tue Jan 31 18:14:41 2012
@@ -783,6 +783,7 @@ public interface SQLState {
String WEAK_AUTHENTICATION = "4251G";
String BAD_NATIVE_AUTH_SPEC = "4251H";
String MISSING_CREDENTIALS_DB = "4251I";
+ String BAD_PASSWORD_LIFETIME = "4251J";
String LANG_DB2_NOT_NULL_COLUMN_INVALID_DEFAULT = "42601";
String LANG_DB2_INVALID_HEXADECIMAL_CONSTANT = "42606";
@@ -1742,6 +1743,7 @@ public interface SQLState {
String UNABLE_TO_OBTAIN_MESSAGE_TEXT_FROM_SERVER = "01J12";
String NUMBER_OF_ROWS_TOO_LARGE_FOR_INT = "01J13";
String SQL_AUTHORIZATION_WITH_NO_AUTHENTICATION = "01J14";
+ String PASSWORD_EXPIRES_SOON = "01J15";
String CURSOR_OPERATION_CONFLICT = "01001";
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NativeAuthenticationServiceTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NativeAuthenticationServiceTest.java?rev=1238727&r1=1238726&r2=1238727&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NativeAuthenticationServiceTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NativeAuthenticationServiceTest.java Tue Jan 31 18:14:41 2012
@@ -23,6 +23,7 @@ package org.apache.derbyTesting.function
import java.sql.Connection;
import java.sql.SQLException;
+import java.sql.SQLWarning;
import java.util.Properties;
import junit.extensions.TestSetup;
@@ -58,6 +59,7 @@ public class NativeAuthenticationService
private static final String SECOND_DB = "secondDB";
private static final String THIRD_DB = "thirdDB";
private static final String FOURTH_DB = "fourthDB";
+ private static final String FIFTH_DB = "fifthDB";
private static final String PROVIDER_PROPERTY = "derby.authentication.provider";
@@ -67,6 +69,8 @@ public class NativeAuthenticationService
private static final String INVALID_PROVIDER_CHANGE = "XCY05";
private static final String CANT_DROP_DBO = "4251F";
private static final String NO_COLUMN_PERMISSION = "42502";
+ private static final String PASSWORD_EXPIRING = "01J15";
+ private static final String BAD_PASSWORD_PROPERTY = "4251J";
///////////////////////////////////////////////////////////////////////////////////
//
@@ -78,6 +82,7 @@ public class NativeAuthenticationService
private final boolean _localAuthentication;
private DatabaseChangeSetup _fourthDBSetup;
+ private DatabaseChangeSetup _fifthDBSetup;
///////////////////////////////////////////////////////////////////////////////////
//
@@ -132,11 +137,17 @@ public class NativeAuthenticationService
"NATIVE authentication on, " :
"Authentication off, ";
String local = _localAuthentication ?
- "LOCAL authentication ON" :
- "LOCAL authentication OFF";
+ "LOCAL authentication ON, " :
+ "LOCAL authentication OFF, ";
+ String embedded = isEmbedded() ?
+ "Embedded" :
+ "Client/Server";
- return "[ " + authType + local + " ]";
+ return "[ " + authType + local + embedded + " ]";
}
+
+ /** Return true if the test is running embedded */
+ public boolean isEmbedded() { return getTestConfiguration().getJDBCClient().isEmbedded(); }
///////////////////////////////////////////////////////////////////////////////////
//
@@ -228,6 +239,7 @@ public class NativeAuthenticationService
result = TestConfiguration.additionalDatabaseDecoratorNoShutdown( result, SECOND_DB );
result = TestConfiguration.additionalDatabaseDecoratorNoShutdown( result, THIRD_DB );
result = _fourthDBSetup = TestConfiguration.additionalDatabaseDecoratorNoShutdown( result, FOURTH_DB, true );
+ result = _fifthDBSetup = TestConfiguration.additionalDatabaseDecoratorNoShutdown( result, FIFTH_DB, true );
result = TestConfiguration.changeUserDecorator( result, DBO, getPassword( DBO ) );
@@ -249,17 +261,23 @@ public class NativeAuthenticationService
{
println( nameOfTest() );
- vetForAllConfigurations();
+ vetCoreBehavior();
+
+ if ( !_nativeAuthentication ) { vetProviderChanges(); }
- if ( !_nativeAuthentication ) { vetUnauthenticatedConfiguration(); }
+ // only run this for local authentication so that we don't have to shutdown
+ // the system-wide credentials db. also only run this embedded so that we
+ // don't have to deal with the problems of shutting down a database
+ // across the network.
+ if ( _localAuthentication && isEmbedded() ) { vetPasswordLifetime(); }
}
/**
* <p>
- * These tests are run for all configurations.
+ * Verify the core behavior of NATIVE authentication.
* </p>
*/
- private void vetForAllConfigurations() throws Exception
+ private void vetCoreBehavior() throws Exception
{
// can't create any database until the credentials db has been created
Connection secondDBConn = getConnection
@@ -370,10 +388,11 @@ public class NativeAuthenticationService
/**
* <p>
+ * Try changing the value of the provider property on disk.
* These tests are run only if authentication is turned off.
* </p>
*/
- private void vetUnauthenticatedConfiguration() throws Exception
+ private void vetProviderChanges() throws Exception
{
// create an empty database without authentication turned on
String dbo = ORANGE_USER;
@@ -471,6 +490,68 @@ public class NativeAuthenticationService
}
+ /**
+ * <p>
+ * Verify that password lifetimes are checked.
+ * </p>
+ */
+ private void vetPasswordLifetime() throws Exception
+ {
+ // create another database
+ Connection dboConn = openConnection( FIFTH_DB, DBO );
+
+ // add another legal user
+ addUser( dboConn, APPLE_USER );
+
+ Connection appleConn = passwordExpiring( false, FIFTH_DB, APPLE_USER );
+
+ // setup so that passwords are expiring after the db is rebooted.
+ // shutdown the database in this test so that the new property settings take effect.
+ goodStatement
+ ( dboConn, "call syscs_util.syscs_set_database_property( 'derby.authentication.native.passwordLifetimeMillis', '86400000' )" );
+ goodStatement
+ ( dboConn, "call syscs_util.syscs_set_database_property( 'derby.authentication.native.passwordLifetimeThreshold', '2.0' )" );
+ _fifthDBSetup.getTestConfiguration().shutdownDatabase();
+
+ // password should be expiring
+ dboConn = passwordExpiring( true, FIFTH_DB, DBO );
+ appleConn = passwordExpiring( true, FIFTH_DB, APPLE_USER );
+
+ // setup so that passwords have expired after we reboot the database.
+ // shutdown the database so that the new property settings take effect.
+ goodStatement
+ ( dboConn, "call syscs_util.syscs_set_database_property( 'derby.authentication.native.passwordLifetimeMillis', '1' )" );
+ _fifthDBSetup.getTestConfiguration().shutdownDatabase();
+
+ // the DBO's password does not expire
+ dboConn = openConnection( FIFTH_DB, DBO );
+
+ // but the other user's password has expired
+ appleConn = getConnection( true, FIFTH_DB, APPLE_USER, INVALID_AUTHENTICATION );
+
+ // setup so that passwords don't expire after we reboot the database.
+ // shutdown the database so that the new property settings take effect.
+ goodStatement
+ ( dboConn, "call syscs_util.syscs_set_database_property( 'derby.authentication.native.passwordLifetimeMillis', '0' )" );
+ _fifthDBSetup.getTestConfiguration().shutdownDatabase();
+
+ // passwords should NOT be expiring or expired
+ dboConn = passwordExpiring( false, FIFTH_DB, DBO );
+ appleConn = passwordExpiring( false, FIFTH_DB, APPLE_USER );
+
+ // check that invalid property settings are caught
+ expectExecutionError
+ (
+ dboConn, BAD_PASSWORD_PROPERTY,
+ "call syscs_util.syscs_set_database_property( 'derby.authentication.native.passwordLifetimeMillis', 'rabbit' )"
+ );
+ expectExecutionError
+ (
+ dboConn, BAD_PASSWORD_PROPERTY,
+ "call syscs_util.syscs_set_database_property( 'derby.authentication.native.passwordLifetimeThreshold', '-1' )"
+ );
+ }
+
private void vetSQLAuthorizationOn() throws Exception
{
Connection nonDBOConn = openConnection( CREDENTIALS_DB, APPLE_USER );
@@ -515,6 +596,32 @@ public class NativeAuthenticationService
return conn;
}
+ // connect but expect a warning that the password is about to expire
+ private Connection passwordExpiring( boolean expiring, String dbName, String user )
+ throws Exception
+ {
+ Connection conn = null;
+
+ println( user + " attempting to get connection to database " + dbName );
+
+ conn = openConnection( dbName, user );
+
+ SQLWarning warning = conn.getWarnings();
+
+ if ( expiring )
+ {
+ assertNotNull( tagError( "Should have seen a warning" ), warning );
+ assertSQLState( PASSWORD_EXPIRING, warning );
+ }
+ else
+ {
+ assertNull( tagError( "Should not have seen a warning" ), warning );
+ }
+
+
+ return conn;
+ }
+
private void addUser( Connection conn, String user ) throws Exception
{
String password = getPassword( user );