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 2006/08/09 15:51:33 UTC
svn commit: r430056 [1/4] - in /db/derby/code/trunk/java:
client/org/apache/derby/client/am/ client/org/apache/derby/client/net/
client/org/apache/derby/jdbc/ drda/org/apache/derby/impl/drda/
engine/org/apache/derby/iapi/reference/ engine/org/apache/de...
Author: rhillegas
Date: Wed Aug 9 06:51:30 2006
New Revision: 430056
URL: http://svn.apache.org/viewvc?rev=430056&view=rev
Log:
DERBY-528: Commit Francois' 528_diff_v5.txt patch, adding username/password substitution to our authentication options.
Modified:
db/derby/code/trunk/java/client/org/apache/derby/client/am/EncryptionManager.java
db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConfiguration.java
db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnection.java
db/derby/code/trunk/java/client/org/apache/derby/jdbc/ClientBaseDataSource.java
db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/AppRequester.java
db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/CodePoint.java
db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/Database.java
db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DecryptionManager.java
db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/NetworkServerControlImpl.java
db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Attribute.java
db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Property.java
db/derby/code/trunk/java/engine/org/apache/derby/iapi/util/StringUtil.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/BasicAuthenticationServiceImpl.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/ibm14/testSecMec.out
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/testSecMec.out
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/ibm14/testSecMec.out
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk14/testSecMec.out
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/testSecMec.out
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/protocol.tests
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/testSecMec.java
Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/EncryptionManager.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/EncryptionManager.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/EncryptionManager.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/EncryptionManager.java Wed Aug 9 06:51:30 2006
@@ -24,7 +24,7 @@
import java.security.Provider;
import java.security.Security;
import org.apache.derby.shared.common.reference.SQLState;
-
+import org.apache.derby.shared.common.sanity.SanityManager;
// This class is get used when using encrypted password and/or userid mechanism.
// The <b>EncryptionManager</b> classs uses Diffie_Hellman algorithm to get the publick key and
@@ -36,6 +36,8 @@
// obtainPublicKey(), calculateEncryptionToken(int, byte[]) and encryptData(byte[], int, byte[], byte[])
// The agreed public value for the Diffie-Hellman prime is 256 bits
// and hence the encrytion will work only if the jce provider supports a 256 bits prime
+//
+// This class also have methods for the SECMEC_USRSSBPWD security mechanism.
public class EncryptionManager {
transient Agent agent_; // for obtaining an exception log writer only
@@ -87,6 +89,22 @@
private String providerName; // security provider name
private Provider provider;
+ // Required for SECMEC_USRSSBPWD DRDA security mechanism
+ // NOTE: In a next incarnation, these constants are being moved
+ // to a dedicated/specialized SecMec_USRSSBPWD class implementing
+ // a SecurityMechanism interface.
+ private java.security.MessageDigest messageDigest = null;
+ private java.security.SecureRandom secureRandom = null;
+ private final static int SECMEC_USRSSBPWD_SEED_LEN = 8; // Seed length
+ // PWSEQs's 8-byte value constant - See DRDA Vol 3
+ private static final byte SECMEC_USRSSBPWD_PWDSEQS[] = {
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01
+ };
+ // Random Number Generator (PRNG) Algorithm
+ private final static String SHA_1_PRNG_ALGORITHM = "SHA1PRNG";
+ public final static String SHA_1_DIGEST_ALGORITHM = "SHA-1";
+
// EncryptionManager constructor. In this constructor,DHParameterSpec,
// KeyPairGenerator, KeyPair, and KeyAgreement are initialized.
public EncryptionManager(Agent agent) throws SqlException {
@@ -111,6 +129,36 @@
}
}
+ // Retrieve a particular instance of the Encryption manager for a given
+ // (Messsage Digest) algorithm. This is currently required for the
+ // SECMEC_USRSSBPWD (strong password substitute) security mechanism.
+ //
+ // NOTE: This is temporary logic as the encryption manager is being
+ // rewritten into a DRDASecurityManager and have some of the
+ // client/engine common logic moved to the Derby 'shared' package.
+ public EncryptionManager(Agent agent, String algorithm) throws SqlException {
+ agent_ = agent;
+ try {
+ // Instantiate the encryption manager for the passed-in security
+ // algorithm and this from the default provider
+ // NOTE: We're only dealing with Message Digest algorithms for now.
+ messageDigest = java.security.MessageDigest.getInstance(algorithm);
+ // We're also verifying that we can instantiate a randon number
+ // generator (PRNG).
+ secureRandom =
+ java.security.SecureRandom.getInstance(SHA_1_PRNG_ALGORITHM);
+ } catch (java.security.NoSuchAlgorithmException nsae) {
+ // The following exception should not be raised for SHA-1 type of
+ // message digest as we've already verified during boot-up that this
+ // algorithm was available as part of the JRE (since BUILT-IN
+ // authentication requires it); but we still raise the exception if
+ // a client were to request a different algorithm.
+ throw new SqlException(agent_.logWriter_,
+ new ClientMessageId(SQLState.SECURITY_EXCEPTION_ENCOUNTERED),
+ nsae);
+ }
+ }
+
// This method generates the public key and returns it. This
// shared public key is the application requester's connection key and will
// be exchanged with the application server's connection key. This connection
@@ -457,5 +505,187 @@
secKey_ = null;
}
-}
+ /****************************************************************
+ * Below are methods for the SECMEC_USRSSBPWD security mechanism.
+ ****************************************************************/
+
+ /**
+ * This method generates an 8-Byte random seed for the client (source).
+ *
+ * @return a random 8-Byte seed.
+ */
+ public byte[] generateSeed() {
+ byte randomSeedBytes[] = new byte[SECMEC_USRSSBPWD_SEED_LEN];
+ secureRandom.setSeed(secureRandom.generateSeed(
+ SECMEC_USRSSBPWD_SEED_LEN));
+ secureRandom.nextBytes(randomSeedBytes);
+ return randomSeedBytes;
+ }
+ /**
+ * Strong Password Substitution (USRSSBPWD).
+ *
+ * This method generate a password subtitute to send to the target
+ * server.
+ *
+ * Substitution algorithm works as follow:
+ *
+ * PW_TOKEN = SHA-1(PW, ID)
+ * The password (PW) and user name (ID) can be of any length greater
+ * than or equal to 1 byte.
+ * The client generates a 20-byte password substitute (PW_SUB) as follows:
+ * PW_SUB = SHA-1(PW_TOKEN, RDr, RDs, ID, PWSEQs)
+ *
+ * w/ (RDs) as the random client seed and (RDr) as the server one.
+ *
+ * See PWDSSB - Strong Password Substitution Security Mechanism
+ * (DRDA Vol.3 - P.650)
+ *
+ * @param userName The user's name
+ * @param password The user's password
+ * @param sourceSeed_ random client seed (RDs)
+ * @param targetSeed_ random server seed (RDr)
+ *
+ * @return a password substitute.
+ */
+ public byte[] substitutePassword(
+ String userName,
+ String password,
+ byte[] sourceSeed_,
+ byte[] targetSeed_) throws SqlException {
+
+ // Pattern that is prefixed to the BUILTIN encrypted password
+ String ID_PATTERN_NEW_SCHEME = "3b60";
+
+ // Generated password substitute
+ byte[] passwordSubstitute;
+
+ // Assert we have a SHA-1 Message Digest already instantiated
+ if (SanityManager.DEBUG) {
+ SanityManager.ASSERT((messageDigest != null) &&
+ (SHA_1_DIGEST_ALGORITHM.equals(
+ messageDigest.getAlgorithm())));
+ }
+
+ // IMPORTANT NOTE: As the password is stored single-hashed in the
+ // database on the target side, it is impossible for the target to
+ // decrypt the password and recompute a substitute to compare with
+ // one generated on the source side - Hence, for now we have to
+ // single-hash and encrypt the password the same way the target is
+ // doing it and we will still generate a substitute obviously - The
+ // password, even pre-hashed will never make it across the wire as
+ // a substitute is generated. In other words, if the target cannot
+ // figure what the original password is (because of not being able
+ // to decrypt it or not being able to retrieve it (i.e. LDAP), then
+ // It may be problematic - so in a way, Strong Password Substitution
+ // (USRSSBPWD) cannot be supported for targets which can't access or
+ // decrypt some password on their side.
+ //
+ // So in short, SECMEC_USRSSBPWD is only supported if the
+ // authentication provider on the target side is NONE or Derby's
+ // BUILTIN one and if using Derby's Client Network driver (for now).
+ //
+ // Encrypt the password as it is done by the derby engine - Note that
+ // this code (logic) is not shared yet - will be in next revision.
+ messageDigest.reset();
+
+ messageDigest.update(this.toHexByte(password, 0, password.length()));
+ byte[] encryptVal = messageDigest.digest();
+ String hexString = ID_PATTERN_NEW_SCHEME +
+ this.toHexString(encryptVal, 0, encryptVal.length);
+
+ // Generate some 20-byte password token
+ byte[] userBytes = this.toHexByte(userName, 0, userName.length());
+ messageDigest.update(userBytes);
+ messageDigest.update(this.toHexByte(hexString, 0, hexString.length()));
+ byte[] passwordToken = messageDigest.digest();
+
+ // Now we generate the 20-byte password substitute
+ messageDigest.update(passwordToken);
+ messageDigest.update(targetSeed_);
+ messageDigest.update(sourceSeed_);
+ messageDigest.update(userBytes);
+ messageDigest.update(SECMEC_USRSSBPWD_PWDSEQS);
+
+ passwordSubstitute = messageDigest.digest();
+
+ return passwordSubstitute;
+ }
+
+ /*********************************************************************
+ * RESOLVE: *
+ * The methods and static vars below should go into some 'shared' *
+ * package when the capability is put back in (StringUtil.java). *
+ *********************************************************************/
+
+ private static char[] hex_table = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+
+ /**
+ Convert a byte array to a String with a hexidecimal format.
+ The String may be converted back to a byte array using fromHexString.
+ <BR>
+ For each byte (b) two characaters are generated, the first character
+ represents the high nibble (4 bits) in hexidecimal (<code>b & 0xf0</code>),
+ the second character represents the low nibble (<code>b & 0x0f</code>).
+ <BR>
+ The byte at <code>data[offset]</code> is represented by the first two
+ characters in the returned String.
+
+ @param data byte array
+ @param offset starting byte (zero based) to convert.
+ @param length number of bytes to convert.
+
+ @return the String (with hexidecimal format) form of the byte array
+ */
+ private String toHexString(byte[] data, int offset, int length)
+ {
+ StringBuffer s = new StringBuffer(length*2);
+ int end = offset+length;
+
+ for (int i = offset; i < end; i++)
+ {
+ int high_nibble = (data[i] & 0xf0) >>> 4;
+ int low_nibble = (data[i] & 0x0f);
+ s.append(hex_table[high_nibble]);
+ s.append(hex_table[low_nibble]);
+ }
+
+ return s.toString();
+ }
+
+ /**
+
+ Convert a string into a byte array in hex format.
+ <BR>
+ For each character (b) two bytes are generated, the first byte
+ represents the high nibble (4 bits) in hexidecimal (<code>b & 0xf0</code>),
+ the second byte represents the low nibble (<code>b & 0x0f</code>).
+ <BR>
+ The character at <code>str.charAt(0)</code> is represented by the first two bytes
+ in the returned String.
+
+ @param str string
+ @param offset starting character (zero based) to convert.
+ @param length number of characters to convert.
+
+ @return the byte[] (with hexidecimal format) form of the string (str)
+ */
+ private byte[] toHexByte(String str, int offset, int length)
+ {
+ byte[] data = new byte[(length - offset) * 2];
+ int end = offset+length;
+
+ for (int i = offset; i < end; i++)
+ {
+ char ch = str.charAt(i);
+ int high_nibble = (ch & 0xf0) >>> 4;
+ int low_nibble = (ch & 0x0f);
+ data[i] = (byte)high_nibble;
+ data[i+1] = (byte)low_nibble;
+ }
+ return data;
+ }
+}
Modified: db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConfiguration.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConfiguration.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConfiguration.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConfiguration.java Wed Aug 9 06:51:30 2006
@@ -156,20 +156,23 @@
// Indicates userid/password security mechanism.
public static final int SECMEC_USRIDPWD = 0x03;
-
//Indicates Encrypted userid and Encrypted Security-sensitive Data security mechanism
public static final int SECMEC_EUSRIDDTA = 0x0C;
//Indicates Encrypted userid,Encrypted password and Encrypted Security-sensitive Data security mechanism
public static final int SECMEC_EUSRPWDDTA = 0x0D;
+ // Indicates userid with strong password substitute security mechanism.
+ public static final int SECMEC_USRSSBPWD = 0x08;
+
// list of security mechanisms supported by this driver
static final int[] SECMGR_SECMECS = {NetConfiguration.SECMEC_EUSRIDPWD,
NetConfiguration.SECMEC_USRENCPWD,
NetConfiguration.SECMEC_USRIDPWD,
NetConfiguration.SECMEC_USRIDONL,
NetConfiguration.SECMEC_EUSRIDDTA,
- NetConfiguration.SECMEC_EUSRPWDDTA};
+ NetConfiguration.SECMEC_EUSRPWDDTA,
+ NetConfiguration.SECMEC_USRSSBPWD};
// IEEE ASCII constant.
Modified: db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnection.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnection.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnection.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/net/NetConnection.java Wed Aug 9 06:51:30 2006
@@ -120,6 +120,10 @@
transient byte[] publicKey_;
transient byte[] targetPublicKey_;
+ // Seeds used for strong password substitute generation (USRSSBPWD)
+ transient byte[] sourceSeed_; // Client seed
+ transient byte[] targetSeed_; // Server seed
+
// Product-Specific Data (prddta) sent to the server in the accrdb command.
// The prddta has a specified format. It is saved in case it is needed again
// since it takes a little effort to compute. Saving this information is
@@ -313,6 +317,8 @@
targetSrvrlslv_ = null;
publicKey_ = null;
targetPublicKey_ = null;
+ sourceSeed_ = null;
+ targetSeed_ = null;
targetSecmec_ = 0;
if (ds != null && securityMechanism_ == 0) {
securityMechanism_ = ds.getSecurityMechanism(password);
@@ -363,6 +369,8 @@
targetSrvrlslv_ = null;
publicKey_ = null;
targetPublicKey_ = null;
+ sourceSeed_ = null;
+ targetSeed_ = null;
targetSecmec_ = 0;
if (ds != null && securityMechanism_ == 0) {
securityMechanism_ = ds.getSecurityMechanism();
@@ -446,6 +454,10 @@
checkUserPassword(user_, password);
flowEUSRPWDDTAconnect(password);
break;
+ case NetConfiguration.SECMEC_USRSSBPWD: // Clear text user, strong password substitute
+ checkUserPassword(user_, password);
+ flowUSRSSBPWDconnect(password);
+ break;
default:
throw new SqlException(agent_.logWriter_,
@@ -565,6 +577,11 @@
resetConnectionAtFirstSql_ = true;
setDeferredResetPassword(password);
return true;
+ case NetConfiguration.SECMEC_USRSSBPWD: // Clear text user, strong password substitute
+ checkUserPassword(user_, password);
+ resetConnectionAtFirstSql_ = true;
+ setDeferredResetPassword(password);
+ return true;
default:
throw new SqlException(agent_.logWriter_,
new ClientMessageId(SQLState.SECMECH_NOT_SUPPORTED),
@@ -679,6 +696,39 @@
encryptedPasswordForEUSRIDPWD(password));
}
+ /**
+ * The User ID and Strong Password Substitute mechanism (USRSSBPWD)
+ * authenticates the user like the user ID and password mechanism, but
+ * the password does not flow. A password substitute is generated instead
+ * using the SHA-1 algorithm, and is sent to the application server.
+ *
+ * The application server generates a password substitute using the same
+ * algorithm and compares it with the application requesterÂ’s password
+ * substitute. If equal, the user is authenticated.
+ *
+ * The SECTKN parameter is used to flow the client and server encryption
+ * seeds on the ACCSEC and ACCSECRD commands.
+ *
+ * More information in DRDA, V3, Volume 3 standard - PWDSSB (page 650)
+ */
+ private void flowUSRSSBPWDconnect(String password) throws SqlException {
+ flowServerAttributes();
+
+ checkSecmgrForSecmecSupport(NetConfiguration.SECMEC_USRSSBPWD);
+ // Generate a random client seed to send to the target server - in
+ // response we will also get a generated seed from this last one.
+ // Seeds are used on both sides to generate the password substitute.
+ initializeClientSeed();
+
+ flowSeedExchange(NetConfiguration.SECMEC_USRSSBPWD, sourceSeed_);
+
+ flowSecurityCheckAndAccessRdb(targetSecmec_, //securityMechanism
+ user_,
+ null,
+ null,
+ passwordSubstituteForUSRSSBPWD(password)); // PWD Substitute
+ }
+
private void flowServerAttributes() throws SqlException {
agent_.beginWriteChainOutsideUOW();
netAgent_.netConnectionRequest_.writeExchangeServerAttributes(extnam_, //externalName
@@ -706,6 +756,16 @@
agent_.endReadChain();
}
+ private void flowSeedExchange(int securityMechanism, byte[] sourceSeed) throws SqlException {
+ agent_.beginWriteChainOutsideUOW();
+ netAgent_.netConnectionRequest_.writeAccessSecurity(securityMechanism,
+ databaseName_,
+ sourceSeed);
+ agent_.flowOutsideUOW();
+ netAgent_.netConnectionReply_.readAccessSecurity(this, securityMechanism);
+ agent_.endReadChain();
+ }
+
private void flowServerAttributesAndKeyExchange(int securityMechanism,
byte[] publicKey) throws SqlException {
agent_.beginWriteChainOutsideUOW();
@@ -715,6 +775,15 @@
agent_.endReadChain();
}
+ private void flowServerAttributesAndSeedExchange(int securityMechanism,
+ byte[] sourceSeed) throws SqlException {
+ agent_.beginWriteChainOutsideUOW();
+ writeServerAttributesAndSeedExchange(sourceSeed);
+ agent_.flowOutsideUOW();
+ readServerAttributesAndSeedExchange();
+ agent_.endReadChain();
+ }
+
private void flowSecurityCheckAndAccessRdb(int securityMechanism,
String user,
String password,
@@ -765,11 +834,24 @@
publicKey);
}
+ private void writeServerAttributesAndSeedExchange(byte[] sourceSeed)
+ throws SqlException {
+
+ // For now, we're just calling our cousin method to do the job
+ writeServerAttributesAndKeyExchange(NetConfiguration.SECMEC_USRSSBPWD,
+ sourceSeed);
+ }
+
private void readServerAttributesAndKeyExchange(int securityMechanism) throws SqlException {
netAgent_.netConnectionReply_.readExchangeServerAttributes(this);
netAgent_.netConnectionReply_.readAccessSecurity(this, securityMechanism);
}
+ private void readServerAttributesAndSeedExchange() throws SqlException {
+ // For now, we're just calling our cousin method to do the job
+ readServerAttributesAndKeyExchange(NetConfiguration.SECMEC_USRSSBPWD);
+ }
+
private void writeSecurityCheckAndAccessRdb(int securityMechanism,
String user,
String password,
@@ -830,21 +912,33 @@
endOffset = netAgent_.netConnectionRequest_.offset_;
cacheConnectBytes(beginOffset, endOffset);
}
- // either NetConfiguration.SECMEC_USRENCPWD or NetConfiguration.SECMEC_EUSRIDPWD
+ // Either NetConfiguration.SECMEC_USRENCPWD,
+ // NetConfiguration.SECMEC_EUSRIDPWD or
+ // NetConfiguration.SECMEC_USRSSBPWD
else {
- initializePublicKeyForEncryption();
+ if (securityMechanism_ == NetConfiguration.SECMEC_USRSSBPWD)
+ initializeClientSeed();
+ else // SECMEC_USRENCPWD, SECMEC_EUSRIDPWD
+ initializePublicKeyForEncryption();
+
// Set the resetConnectionAtFirstSql_ to false to avoid going in an
// infinite loop, since all the flow methods call beginWriteChain which then
// calls writeDeferredResetConnection where the check for resetConnectionAtFirstSql_
// is done. By setting the resetConnectionAtFirstSql_ to false will avoid calling the
// writeDeferredReset method again.
resetConnectionAtFirstSql_ = false;
- flowServerAttributesAndKeyExchange(securityMechanism_, publicKey_);
+
+ if (securityMechanism_ == NetConfiguration.SECMEC_USRSSBPWD)
+ flowSeedExchange(securityMechanism_, sourceSeed_);
+ else // SECMEC_USRENCPWD, SECMEC_EUSRIDPWD
+ flowServerAttributesAndKeyExchange(securityMechanism_, publicKey_);
+
agent_.beginWriteChainOutsideUOW();
// Reset the resetConnectionAtFirstSql_ to true since we are done
// with the flow method.
resetConnectionAtFirstSql_ = true;
+
// NetConfiguration.SECMEC_USRENCPWD
if (securityMechanism_ == NetConfiguration.SECMEC_USRENCPWD) {
writeSecurityCheckAndAccessRdb(NetConfiguration.SECMEC_USRENCPWD,
@@ -853,8 +947,15 @@
null, //encryptedUserid
encryptedPasswordForUSRENCPWD(getDeferredResetPassword()));
}
- // NetConfiguration.SECMEC_EUSRIDPWD
- else {
+ // NetConfiguration.SECMEC_USRSSBPWD
+ else if (securityMechanism_ == NetConfiguration.SECMEC_USRSSBPWD) {
+ writeSecurityCheckAndAccessRdb(NetConfiguration.SECMEC_USRSSBPWD,
+ user_,
+ null,
+ null,
+ passwordSubstituteForUSRSSBPWD(getDeferredResetPassword()));
+ }
+ else { // NetConfiguration.SECMEC_EUSRIDPWD
writeSecurityCheckAndAccessRdb(NetConfiguration.SECMEC_EUSRIDPWD,
null, //user
null, //password
@@ -924,6 +1025,7 @@
if ((targetSecmec_ == NetConfiguration.SECMEC_USRENCPWD) ||
(targetSecmec_ == NetConfiguration.SECMEC_EUSRIDPWD) ||
+ (targetSecmec_ == NetConfiguration.SECMEC_USRSSBPWD) ||
(targetSecmec_ == NetConfiguration.SECMEC_EUSRIDDTA) ||
(targetSecmec_ == NetConfiguration.SECMEC_EUSRPWDDTA)) {
@@ -933,7 +1035,10 @@
new DisconnectException(agent_,
new ClientMessageId(SQLState.NET_SECTKN_NOT_RETURNED)));
} else {
- targetPublicKey_ = sectkn;
+ if (targetSecmec_ == NetConfiguration.SECMEC_USRSSBPWD)
+ targetSeed_ = sectkn;
+ else
+ targetPublicKey_ = sectkn;
if (encryptionManager_ != null) {
encryptionManager_.resetSecurityKeys();
}
@@ -1309,11 +1414,21 @@
private void initializePublicKeyForEncryption() throws SqlException {
if (encryptionManager_ == null) {
- encryptionManager_ = new org.apache.derby.client.am.EncryptionManager(agent_);
+ encryptionManager_ = new EncryptionManager(agent_);
}
publicKey_ = encryptionManager_.obtainPublicKey();
}
+ // SECMEC_USRSSBPWD security mechanism - Generate a source (client) seed
+ // to send to the target (application) server.
+ private void initializeClientSeed() throws SqlException {
+ if (encryptionManager_ == null) {
+ encryptionManager_ = new EncryptionManager(
+ agent_,
+ EncryptionManager.SHA_1_DIGEST_ALGORITHM);
+ }
+ sourceSeed_ = encryptionManager_.generateSeed();
+ }
private byte[] encryptedPasswordForUSRENCPWD(String password) throws SqlException {
return encryptionManager_.encryptData(netAgent_.sourceCcsidManager_.convertFromUCS2(password, netAgent_),
@@ -1334,6 +1449,35 @@
NetConfiguration.SECMEC_EUSRIDPWD,
targetPublicKey_,
targetPublicKey_);
+ }
+
+ private byte[] passwordSubstituteForUSRSSBPWD(String password) throws SqlException {
+ String userName = user_;
+
+ // Define which userName takes precedence - If we have a dataSource
+ // available here, it is posible that the userName has been
+ // overriden by some defined as part of the connection attributes
+ // (see ClientBaseDataSource.updateDataSourceValues().
+ // We need to use the right userName as strong password
+ // substitution depends on the userName when the substitute
+ // password is generated; if we were not using the right userName
+ // then authentication would fail when regenerating the substitute
+ // password on the engine server side, where userName as part of the
+ // connection attributes would get used to authenticate the user.
+ if (dataSource_ != null)
+ {
+ String dataSourceUserName = dataSource_.getUser();
+ if (!dataSourceUserName.equals("") &&
+ userName.equalsIgnoreCase(
+ dataSource_.propertyDefault_user) &&
+ !dataSourceUserName.equalsIgnoreCase(
+ dataSource_.propertyDefault_user))
+ {
+ userName = dataSourceUserName;
+ }
+ }
+ return encryptionManager_.substitutePassword(
+ userName, password, sourceSeed_, targetSeed_);
}
// Methods to get the manager levels for Regression harness only.
Modified: db/derby/code/trunk/java/client/org/apache/derby/jdbc/ClientBaseDataSource.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/jdbc/ClientBaseDataSource.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/jdbc/ClientBaseDataSource.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/jdbc/ClientBaseDataSource.java Wed Aug 9 06:51:30 2006
@@ -201,6 +201,7 @@
// <li> CLEAR_TEXT_PASSWORD_SECURITY
// <li> ENCRYPTED_PASSWORD_SECURITY
// <li> ENCRYPTED_USER_AND_PASSWORD_SECURITY - both password and user are encrypted
+ // <li> STRONG_PASSWORD_SUBSTITUTE_SECURITY
// </ul>
// The default security mechanism is USER_ONLY_SECURITY.
// <p>
@@ -209,7 +210,7 @@
// If the specified security mechanism is not supported by the conversation
// then an exception will be thrown and there will be no additional retries.
// <p>
- // This property is currently only available for the DNC driver.
+ // This property is currently only available for the DNC driver.
// <p>
// Both user and password need to be set for all security mechanism except USER_ONLY_SECURITY
// When using USER_ONLY_SECURITY, only the user property needs to be specified.
@@ -229,13 +230,12 @@
// If the security mechanism is not explicitly set as mentioned above, in that case
// the Client will try to upgrade the security mechanism to a more secure one, if possible.
// @see #getUpgradedSecurityMechanism
- // Therefore, need to keep track if the seurityMechanism has been explicitly set
+ // Therefore, need to keep track if the securityMechanism has been explicitly set
protected short securityMechanism = SECMEC_HAS_NOT_EXPLICITLY_SET;
- // TODO default should be USER_ONLY_SECURITY. Change when working on
- // Network Server
- // public final static short propertyDefault_securityMechanism = (short)
- // org.apache.derby.client.net.NetConfiguration.SECMEC_USRIDONL;
- public final static short propertyDefault_securityMechanism = (short) NetConfiguration.SECMEC_USRIDONL;
+
+ // Default security mechanism is USER_ONLY_SECURITY.
+ public final static short propertyDefault_securityMechanism =
+ (short) NetConfiguration.SECMEC_USRIDONL;
// We use the NET layer constants to avoid a mapping for the NET driver.
@@ -248,7 +248,9 @@
*/
public static short getSecurityMechanism(Properties properties) {
short secmec;
- String securityMechanismString = properties.getProperty(Attribute.CLIENT_SECURITY_MECHANISM);
+ String securityMechanismString =
+ properties.getProperty(Attribute.CLIENT_SECURITY_MECHANISM);
+
if ( securityMechanismString != null )
{
// security mechanism has been set, do not override, but instead return
@@ -269,16 +271,17 @@
}
/**
- * This method has logic to upgrade security mechanism to a better (more secure) one
- * if it is possible. Currently derby server only has support for USRIDPWD,USRIDONL,
- * EUSRIDPWD and this method only considers these possibilities.
- * USRIDPWD, EUSRIDPWD require a password, USRIDONL is the only security mechanism
- * which does not require password.
+ * This method has logic to upgrade security mechanism to a better (more secure)
+ * one if it is possible. Currently derby server only has support for USRIDPWD,
+ * USRIDONL, EUSRIDPWD and USRSSBPWD (10.2+) - this method only considers these
+ * possibilities. USRIDPWD, EUSRIDPWD and USRSSBPWD require a password, USRIDONL
+ * is the only security mechanism which does not require password.
* 1. if password is not available, then security mechanism possible is USRIDONL
* 2. if password is available, if client supports EUSRIDPWD, then EUSRIDPWD is
* returned
- * 3. if password is available, if client does not support EUSRIDPWD, then USRIDPWD
- * is returned.
+ * 3. if password is available, if client does not support EUSRIDPWD, then
+ * USRIDPWD is returned.
+ *
* @param password password argument
* @return upgraded security mechanism if possible
*/
@@ -288,8 +291,8 @@
if ( password == null )
return propertyDefault_securityMechanism;
- // if password is available, then a security mechanism is picked in following
- // order if support is available
+ // if password is available, then a security mechanism is picked in
+ // following order if support is available.
// 1. EUSRIDPWD
// 2. USRIDPWD
// when we have support for more security mechanisms on server
@@ -299,7 +302,18 @@
if (SUPPORTS_EUSRIDPWD)
return (short)NetConfiguration.SECMEC_EUSRIDPWD;
else
+ // IMPORTANT NOTE:
+ // --------------
+ // If DERBY-1517 can be fixed, we should default to
+ // SECMEC_USRSSBPWD (strong password substitute).
+ // Until then, connecting with a 10.2+ client to
+ // a derby server < 10.2, and hence does not support
+ // SECMEC_USRSSBPWD as a SECMEC, will cause a DRDA protocol
+ // exception, as described in DERBY-926).
+ //
+ // return (short)NetConfiguration.SECMEC_USRSSBPWD;
return (short)NetConfiguration.SECMEC_USRIDPWD;
+
}
// ---------------------------- getServerMessageTextOnGetMessage -----------------------------------
@@ -716,8 +730,12 @@
/**
* The source security mechanism to use when connecting to this data source.
* <p/>
- * Security mechanism options are: <ul> <li> USER_ONLY_SECURITY <li> CLEAR_TEXT_PASSWORD_SECURITY <li>
- * ENCRYPTED_PASSWORD_SECURITY <li> ENCRYPTED_USER_AND_PASSWORD_SECURITY - both password and user are encrypted
+ * Security mechanism options are: <ul>
+ * <li> USER_ONLY_SECURITY
+ * <li> CLEAR_TEXT_PASSWORD_SECURITY
+ * <li> ENCRYPTED_PASSWORD_SECURITY
+ * <li> ENCRYPTED_USER_AND_PASSWORD_SECURITY - both password and user are encrypted
+ * <li> STRONG_PASSWORD_SUBSTITUTE_SECURITY
* </ul> The default security mechanism is USER_ONLY SECURITY
* <p/>
* If the application specifies a security mechanism then it will be the only one attempted. If the specified
@@ -733,6 +751,7 @@
public final static short CLEAR_TEXT_PASSWORD_SECURITY = (short) NetConfiguration.SECMEC_USRIDPWD;
public final static short ENCRYPTED_PASSWORD_SECURITY = (short) NetConfiguration.SECMEC_USRENCPWD;
public final static short ENCRYPTED_USER_AND_PASSWORD_SECURITY = (short) NetConfiguration.SECMEC_EUSRIDPWD;
+ public final static short STRONG_PASSWORD_SUBSTITUTE_SECURITY = (short) NetConfiguration.SECMEC_USRSSBPWD;
/**
* sets the security mechanism
@@ -859,8 +878,6 @@
}
-
-
// --- private helper methods
@@ -888,15 +905,8 @@
if (prop.containsKey(Attribute.CLIENT_TRACE_APPEND)) {
setTraceFileAppend(getTraceFileAppend(prop));
}
- if (prop.containsKey(Attribute.CLIENT_SECURITY_MECHANISM)) {
- setSecurityMechanism(getSecurityMechanism(prop));
- }
if (prop.containsKey(Attribute.CLIENT_RETIEVE_MESSAGE_TEXT)) {
setRetrieveMessageText(getRetrieveMessageText(prop));
}
}
-
-
}
-
-
Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/AppRequester.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/AppRequester.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/AppRequester.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/AppRequester.java Wed Aug 9 06:51:30 2006
@@ -121,6 +121,19 @@
}
/**
+ * Returns true if Derby's client driver supports SECMEC_USRSSBPWD
+ * DRDA security mechanism.
+ */
+ protected boolean supportsSecMecUSRSSBPWD()
+ {
+ return
+ (
+ ( clientType == DNC_CLIENT ) &&
+ ( greaterThanOrEqualTo( 10, 2, 0 ) )
+ );
+ }
+
+ /**
* Check if the client expects QRYCLSIMP to be supported when the
* protocol is LMTBLKPRC.
*
Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/CodePoint.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/CodePoint.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/CodePoint.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/CodePoint.java Wed Aug 9 06:51:30 2006
@@ -719,6 +719,7 @@
static final int SECMEC_USRIDNWPWD = 5; // Userid, Password, and new Password
static final int SECMEC_USRSBSPWD = 6; // Userid with substitute password
static final int SECMEC_USRENCPWD = 7; // Userid with encrypted password
+ static final int SECMEC_USRSSBPWD = 8; // Userid with Strong password substitute
static final int SECMEC_EUSRIDPWD = 9; // Encrpyted userid and password
static final int SECMEC_EUSRIDNWPWD = 10; // Encrpyted userid and password
Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java Wed Aug 9 06:51:30 2006
@@ -34,6 +34,7 @@
import java.math.BigDecimal;
import java.sql.CallableStatement;
import java.sql.Connection;
+import java.sql.Driver;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
@@ -51,15 +52,18 @@
import org.apache.derby.iapi.reference.Attribute;
import org.apache.derby.iapi.reference.DRDAConstants;
import org.apache.derby.iapi.reference.JDBC30Translation;
+import org.apache.derby.iapi.reference.Property;
import org.apache.derby.iapi.reference.SQLState;
import org.apache.derby.iapi.services.info.JVMInfo;
import org.apache.derby.iapi.services.monitor.Monitor;
import org.apache.derby.iapi.services.sanity.SanityManager;
import org.apache.derby.iapi.services.stream.HeaderPrintWriter;
import org.apache.derby.iapi.tools.i18n.LocalizedResource;
+import org.apache.derby.iapi.jdbc.AuthenticationService;
import org.apache.derby.iapi.jdbc.EngineParameterMetaData;
import org.apache.derby.impl.jdbc.EmbedSQLException;
import org.apache.derby.impl.jdbc.Util;
+import org.apache.derby.jdbc.InternalDriver;
class DRDAConnThread extends Thread {
@@ -161,10 +165,15 @@
// for decryption
private static DecryptionManager decryptionManager;
+
// public key generated by Deffie-Hellman algorithm, to be passed to the encrypter,
// as well as used to initialize the cipher
private byte[] myPublicKey;
+ // generated target seed to be used to generate the password substitute
+ // as part of SECMEC_USRSSBPWD security mechanism
+ private byte[] myTargetSeed;
+
// Some byte[] constants that are frequently written into messages. It is more efficient to
// use these constants than to convert from a String each time
// (This replaces the qryscraft_ and notQryscraft_ static exception objects.)
@@ -174,6 +183,12 @@
private static final byte[] errD4_D6 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // 12x0
private static final byte[] warn0_warnA = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }; // 11x ' '
+ private final static String AUTHENTICATION_PROVIDER_BUILTIN_CLASS =
+ "org.apache.derby.impl.jdbc.authentication.BasicAuthenticationServiceImpl";
+
+ private final static String AUTHENTICATION_PROVIDER_NONE_CLASS =
+ "org.apache.derby.impl.jdbc.authentication.NoneAuthenticationServiceImpl";
+
// Work around a classloader bug involving interrupt handling during
// class loading. If the first request to load the
// DRDAProtocolExceptionInfo class occurs during shutdown, the
@@ -1161,7 +1176,6 @@
databaseAccessException = null;
int retSecChkCode = 0;
-
String realName = database.dbName; //first strip off properties
int endOfName = realName.indexOf(';');
if (endOfName != -1)
@@ -1187,6 +1201,34 @@
if (session.drdaID == null)
session.drdaID = leftBrace + session.connNum + rightBrace;
p.put(Attribute.DRDAID_ATTR, session.drdaID);
+
+ // We pass extra property information for the authentication provider
+ // to successfully re-compute the substitute (hashed) password and
+ // compare it with what we've got from the requester (source).
+ //
+ // If a password attribute appears as part of the connection URL
+ // attributes, we then don't use the substitute hashed password
+ // to authenticate with the engine _as_ the one (if any) as part
+ // of the connection URL attributes, will be used to authenticate
+ // against Derby's BUILT-IN authentication provider - As a reminder,
+ // Derby allows password to be mentioned as part of the connection
+ // URL attributes, as this extra capability could be useful to pass
+ // passwords to external authentication providers for Derby; hence
+ // a password defined as part of the connection URL attributes cannot
+ // be substituted (single-hashed) as it is not recoverable.
+ if ((database.securityMechanism == CodePoint.SECMEC_USRSSBPWD) &&
+ (database.dbName.indexOf(Attribute.PASSWORD_ATTR) == -1))
+ {
+ p.put(Attribute.CLIENT_SECURITY_MECHANISM,
+ String.valueOf(database.securityMechanism));
+ p.put(Attribute.DRDA_SECTKN_IN,
+ DecryptionManager.toHexString(database.secTokenIn, 0,
+ database.secTokenIn.length));
+ p.put(Attribute.DRDA_SECTKN_OUT,
+ DecryptionManager.toHexString(database.secTokenOut, 0,
+ database.secTokenOut.length));
+ }
+
try {
database.makeConnection(p);
} catch (SQLException se) {
@@ -1206,7 +1248,6 @@
return CodePoint.SECCHKCD_USERIDINVALID;
return 0;
-
}
catch (Exception e)
{
@@ -1576,26 +1617,28 @@
*
* If the target server supports the SECMEC requested by the application requester
* then a single value is returned and it is identical to the SECMEC value
- * in the ACCSEC command. If the target server does not support the SECMEC
+ * in the ACCSEC command. If the target server does not support the SECMEC
* requested, then one or more values are returned and the application requester
* must choose one of these values for the security mechanism.
* We currently support
* - user id and password (default for JCC)
* - encrypted user id and password
+ * - strong password substitute (USRSSBPWD w/
+ * Derby network client only)
*
* Instance variables
* SECMGRNM - security manager name - optional
* SECMEC - security mechanism - required
* RDBNAM - relational database name - optional
* SECTKN - security token - optional, (required if sec mech. needs it)
- *
+ *
* @return security check code - 0 if everything O.K.
*/
private int parseACCSEC() throws DRDAProtocolException
{
int securityCheckCode = 0;
int securityMechanism = 0;
- byte [] publicKeyIn = null;
+ byte [] secTokenIn = null;
reader.markCollection();
int codePoint = reader.getCodePoint();
@@ -1614,7 +1657,7 @@
checkLength(CodePoint.SECMEC, 2);
securityMechanism = reader.readNetworkShort();
if (SanityManager.DEBUG)
- trace("Security mechanism = " + securityMechanism);
+ trace("parseACCSEC - Security mechanism = " + securityMechanism);
// if Property.DRDA_PROP_SECURITYMECHANISM has been set, then
// network server only accepts connections which use that
@@ -1628,7 +1671,14 @@
if ( (server.getSecurityMechanism() !=
NetworkServerControlImpl.INVALID_OR_NOTSET_SECURITYMECHANISM)
&& securityMechanism != server.getSecurityMechanism())
+ {
securityCheckCode = CodePoint.SECCHKCD_NOTSUPPORTED;
+ if (SanityManager.DEBUG) {
+ trace("parseACCSEC - SECCHKCD_NOTSUPPORTED [1] - " +
+ securityMechanism + " <> " +
+ server.getSecurityMechanism() + "\n");
+ }
+ }
else
{
// for plain text userid,password USRIDPWD, and USRIDONL
@@ -1636,11 +1686,33 @@
if (securityMechanism != CodePoint.SECMEC_USRIDPWD &&
securityMechanism != CodePoint.SECMEC_USRIDONL)
{
- //this is the only other one we understand
- if (securityMechanism != CodePoint.SECMEC_EUSRIDPWD)
- securityCheckCode = CodePoint.SECCHKCD_NOTSUPPORTED;
+ // These are the only other mechanisms we understand
+ if ((securityMechanism !=
+ CodePoint.SECMEC_EUSRIDPWD) &&
+ (securityMechanism !=
+ CodePoint.SECMEC_USRSSBPWD))
+ //securityCheckCode = CodePoint.SECCHKCD_NOTSUPPORTED;
+ {
+ securityCheckCode = CodePoint.SECCHKCD_NOTSUPPORTED;
+ if (SanityManager.DEBUG) {
+ trace("parseACCSEC - SECCHKCD_NOTSUPPORTED [2]\n");
+ }
+ }
else
{
+ // We delay the initialization and required
+ // processing for SECMEC_USRSSBPWD as we need
+ // to ensure the database is booted so that
+ // we can verify that the current auth scheme
+ // is set to BUILT-IN or NONE. For this we need
+ // to have the RDBNAM codepoint available.
+ //
+ // See validateSecMecUSRSSBPWD() call below
+ if (securityMechanism ==
+ CodePoint.SECMEC_USRSSBPWD)
+ break;
+
+ // SECMEC_EUSRIDPWD initialization
try {
if (decryptionManager == null)
decryptionManager = new DecryptionManager();
@@ -1654,7 +1726,8 @@
}
}
break;
- //optional (currently required for Cloudscape - may need to revisit)
+ //optional (currently required for Cloudscape - needed for
+ // DERBY-528 as well)
case CodePoint.RDBNAM:
String dbname = parseRDBNAM();
Database d = session.getDatabase(dbname);
@@ -1662,7 +1735,6 @@
addDatabase(dbname);
else
{
-
// reset database for connection re-use
d.reset();
database = d;
@@ -1670,13 +1742,14 @@
break;
//optional - depending on security Mechanism
case CodePoint.SECTKN:
- publicKeyIn = reader.readBytes();
+ secTokenIn = reader.readBytes();
break;
default:
invalidCodePoint(codePoint);
}
codePoint = reader.getCodePoint();
}
+
// check for required CodePoint's
if (securityMechanism == 0)
missingCodePoint(CodePoint.SECMEC);
@@ -1690,22 +1763,38 @@
missingCodePoint(CodePoint.RDBNAM);
database.securityMechanism = securityMechanism;
- database.publicKeyIn = publicKeyIn;
+ database.secTokenIn = secTokenIn;
+
+ // If security mechanism is SECMEC_USRSSBPWD, then ensure it can be
+ // used for the database or system based on the client's connection
+ // URL and its identity.
+ if (securityCheckCode == 0 &&
+ (database.securityMechanism == CodePoint.SECMEC_USRSSBPWD))
+ {
+ if (SanityManager.DEBUG)
+ SanityManager.ASSERT((securityCheckCode == 0),
+ "SECMEC_USRSSBPWD: securityCheckCode should not " +
+ "already be set, found it initialized with " +
+ "a value of '" + securityCheckCode + "'.");
+ securityCheckCode = validateSecMecUSRSSBPWD();
+ }
// need security token
if (securityCheckCode == 0 &&
- database.securityMechanism == CodePoint.SECMEC_EUSRIDPWD &&
- database.publicKeyIn == null)
+ (database.securityMechanism == CodePoint.SECMEC_EUSRIDPWD ||
+ database.securityMechanism == CodePoint.SECMEC_USRSSBPWD) &&
+ database.secTokenIn == null)
securityCheckCode = CodePoint.SECCHKCD_SECTKNMISSING_OR_INVALID;
// shouldn't have security token
if (securityCheckCode == 0 &&
(database.securityMechanism == CodePoint.SECMEC_USRIDPWD ||
database.securityMechanism == CodePoint.SECMEC_USRIDONL) &&
- database.publicKeyIn != null)
+ database.secTokenIn != null)
securityCheckCode = CodePoint.SECCHKCD_SECTKNMISSING_OR_INVALID;
+
if (SanityManager.DEBUG)
- trace("** ACCSECRD securityCheckCode is: "+securityCheckCode);
+ trace("** ACCSECRD securityCheckCode is: " + securityCheckCode);
// If the security check was successful set the session state to
// security accesseed. Otherwise go back to attributes exchanged so we
@@ -1716,7 +1805,6 @@
session.setState(session.ATTEXC);
return securityCheckCode;
-
}
/**
@@ -2539,6 +2627,7 @@
trace("RdbName " + name);
return name;
}
+
/**
* Write ACCSECRD
* If the security mechanism is known, we just send it back along with
@@ -2560,6 +2649,7 @@
{
writer.createDssReply();
writer.startDdm(CodePoint.ACCSECRD);
+
if (securityCheckCode != CodePoint.SECCHKCD_NOTSUPPORTED)
writer.writeScalar2Bytes(CodePoint.SECMEC, database.securityMechanism);
else
@@ -2571,7 +2661,7 @@
// security mechanism, if so send only the security mechanism that the
// server will accept, to the client
if ( server.getSecurityMechanism() != NetworkServerControlImpl.INVALID_OR_NOTSET_SECURITYMECHANISM )
- writer.writeScalar2Bytes(CodePoint.SECMEC,server.getSecurityMechanism());
+ writer.writeScalar2Bytes(CodePoint.SECMEC, server.getSecurityMechanism());
else
{
// note: per the DDM manual , ACCSECRD response is of
@@ -2582,8 +2672,10 @@
writer.writeScalar2Bytes(CodePoint.SECMEC, CodePoint.SECMEC_USRIDPWD);
writer.writeScalar2Bytes(CodePoint.SECMEC, CodePoint.SECMEC_EUSRIDPWD);
writer.writeScalar2Bytes(CodePoint.SECMEC, CodePoint.SECMEC_USRIDONL);
+ writer.writeScalar2Bytes(CodePoint.SECMEC, CodePoint.SECMEC_USRSSBPWD);
}
}
+
if (securityCheckCode != 0)
{
writer.writeScalar1Byte(CodePoint.SECCHKCD, securityCheckCode);
@@ -2593,6 +2685,8 @@
// we need to send back the key if encryption is being used
if (database.securityMechanism == CodePoint.SECMEC_EUSRIDPWD)
writer.writeScalarBytes(CodePoint.SECTKN, myPublicKey);
+ else if (database.securityMechanism == CodePoint.SECMEC_USRSSBPWD)
+ writer.writeScalarBytes(CodePoint.SECTKN, myTargetSeed);
}
writer.endDdmAndDss ();
@@ -2603,8 +2697,8 @@
}
finalizeChain();
-
}
+
/**
* Parse security check
* Instance Variables
@@ -2640,7 +2734,7 @@
checkLength(CodePoint.SECMEC, 2);
securityMechanism = reader.readNetworkShort();
if (SanityManager.DEBUG)
- trace("Security mechanism = " + securityMechanism);
+ trace("parseSECCHK - Security mechanism = " + securityMechanism);
//RESOLVE - spec is not clear on what should happen
//in this case
if (securityMechanism != database.securityMechanism)
@@ -2648,37 +2742,76 @@
break;
//optional - depending on security Mechanism
case CodePoint.SECTKN:
- if (database.securityMechanism != CodePoint.SECMEC_EUSRIDPWD)
+ if ((database.securityMechanism !=
+ CodePoint.SECMEC_EUSRIDPWD) &&
+ (database.securityMechanism !=
+ CodePoint.SECMEC_USRSSBPWD))
{
securityCheckCode = CodePoint.SECCHKCD_SECTKNMISSING_OR_INVALID;
reader.skipBytes();
}
- else if (database.decryptedUserId == null) {
- try {
- database.decryptedUserId = reader.readEncryptedString(decryptionManager,
- database.securityMechanism, myPublicKey, database.publicKeyIn);
- } catch (SQLException se)
- {
- println2Log(database.dbName, session.drdaID, se.getMessage());
- if (securityCheckCode == 0)
- securityCheckCode = CodePoint.SECCHKCD_13; //userid invalid
- }
- database.userId = database.decryptedUserId;
- if (SanityManager.DEBUG) trace("**decrypted userid is: "+database.userId);
- }
- else if (database.decryptedPassword == null) {
- try {
- database.decryptedPassword = reader.readEncryptedString(decryptionManager,
- database.securityMechanism, myPublicKey, database.publicKeyIn);
- } catch (SQLException se)
- {
- println2Log(database.dbName, session.drdaID, se.getMessage());
- if (securityCheckCode == 0)
- securityCheckCode = CodePoint.SECCHKCD_0F; //password invalid
- }
- database.password = database.decryptedPassword;
- if (SanityManager.DEBUG) trace("**decrypted password is: "+database.password);
- }
+ else if (database.securityMechanism ==
+ CodePoint.SECMEC_EUSRIDPWD)
+ {
+ if (database.decryptedUserId == null)
+ {
+ try {
+ database.decryptedUserId =
+ reader.readEncryptedString(
+ decryptionManager,
+ database.securityMechanism,
+ myPublicKey,
+ database.secTokenIn);
+ } catch (SQLException se) {
+ println2Log(database.dbName, session.drdaID,
+ se.getMessage());
+ if (securityCheckCode == 0)
+ //userid invalid
+ securityCheckCode = CodePoint.SECCHKCD_13;
+ }
+ database.userId = database.decryptedUserId;
+ if (SanityManager.DEBUG)
+ trace("**decrypted userid is: "+database.userId);
+ }
+ else if (database.decryptedPassword == null)
+ {
+ try {
+ database.decryptedPassword =
+ reader.readEncryptedString(
+ decryptionManager,
+ database.securityMechanism,
+ myPublicKey,
+ database.secTokenIn);
+ } catch (SQLException se) {
+ println2Log(database.dbName, session.drdaID,
+ se.getMessage());
+ if (securityCheckCode == 0)
+ //password invalid
+ securityCheckCode = CodePoint.SECCHKCD_0F;
+ }
+ database.password = database.decryptedPassword;
+ if (SanityManager.DEBUG)
+ trace("**decrypted password is: " +
+ database.password);
+ }
+ }
+ else if (database.securityMechanism ==
+ CodePoint.SECMEC_USRSSBPWD)
+ {
+ if (database.passwordSubstitute == null)
+ {
+ database.passwordSubstitute = reader.readBytes();
+ if (SanityManager.DEBUG)
+ trace("** Substitute Password is:" +
+ DecryptionManager.toHexString(
+ database.passwordSubstitute, 0,
+ database.passwordSubstitute.length));
+ database.password =
+ DecryptionManager.toHexString(
+ database.passwordSubstitute, 0,
+ database.passwordSubstitute.length);
+ }
+ }
else
{
tooMany(CodePoint.SECTKN);
@@ -2732,7 +2865,7 @@
{
if (database.userId == null)
securityCheckCode = CodePoint.SECCHKCD_USERIDMISSING;
- else if ( database.securityMechanism == CodePoint.SECMEC_USRIDPWD)
+ else if (database.securityMechanism == CodePoint.SECMEC_USRIDPWD)
{
if (database.password == null)
securityCheckCode = CodePoint.SECCHKCD_PASSWORDMISSING;
@@ -2740,6 +2873,16 @@
//Note, we'll ignore encryptedUserId and encryptedPassword if they
//are also set
}
+
+ if (securityCheckCode == 0 &&
+ database.securityMechanism == CodePoint.SECMEC_USRSSBPWD)
+ {
+ if (database.userId == null)
+ securityCheckCode = CodePoint.SECCHKCD_USERIDMISSING;
+ else if (database.passwordSubstitute == null)
+ securityCheckCode = CodePoint.SECCHKCD_PASSWORDMISSING;
+ }
+
if (securityCheckCode == 0 &&
database.securityMechanism == CodePoint.SECMEC_EUSRIDPWD)
{
@@ -2747,7 +2890,6 @@
securityCheckCode = CodePoint.SECCHKCD_USERIDMISSING;
else if (database.decryptedPassword == null)
securityCheckCode = CodePoint.SECCHKCD_PASSWORDMISSING;
-
}
// RESOLVE - when we do security we need to decrypt encrypted userid & password
// before proceeding
@@ -7703,6 +7845,135 @@
}
+ /**
+ * Validate SECMEC_USRSSBPWD (Strong Password Substitute) can be used as
+ * DRDA security mechanism.
+ *
+ * Here we check that the target server can support SECMEC_USRSSBPWD
+ * security mechanism based on the environment, application
+ * requester's identity (PRDID) and connection URL.
+ *
+ * IMPORTANT NOTE:
+ * --------------
+ * SECMEC_USRSSBPWD is ONLY supported by the target server if:
+ * - current authentication provider is Derby BUILTIN or
+ * NONE. (database / system level) (Phase I)
+ * - Application requester is 'DNC' (Derby Network Client)
+ * (Phase I)
+ *
+ * @return security check code - 0 if everything O.K.
+ */
+ private int validateSecMecUSRSSBPWD() throws DRDAProtocolException
+ {
+ String dbName = null;
+ AuthenticationService authenticationService = null;
+ org.apache.derby.iapi.db.Database databaseObj = null;
+ String srvrlslv = appRequester.srvrlslv;
+
+ // Check if application requester is the Derby Network Client (DNC)
+ //
+ // We use a trick here - as the product ID is not yet available
+ // since ACCRDB message is only coming later, we check the server
+ // release level field sent as part of the initial EXCSAT message;
+ // indeed, the product ID (PRDID) is prefixed to in the field.
+ // Derby always sets it as part of the EXCSAT message so if it is
+ // not available, we stop here and inform the requester that
+ // SECMEC_USRSSBPWD cannot be supported for this connection.
+ if ((srvrlslv == null) || (srvrlslv.length() == 0) ||
+ (srvrlslv.length() < CodePoint.PRDID_MAX) ||
+ (srvrlslv.indexOf(DRDAConstants.DERBY_DRDA_CLIENT_ID)
+ == -1))
+ return CodePoint.SECCHKCD_NOTSUPPORTED; // Not Supported
+
+
+ // Client product version is extracted from the srvrlslv field.
+ // srvrlslv has the format <PRDID>/<ALTERNATE VERSION FORMAT>
+ // typically, a known Derby client has a four part version number
+ // with a pattern such as DNC10020/10.2.0.3 alpha. If the alternate
+ // version format is not specified, clientProductVersion_ will just
+ // be set to the srvrlslvl. Final fallback will be the product id.
+ //
+ // SECMEC_USRSSBPWD is only supported by the Derby engine and network
+ // server code starting at version major '10' and minor '02'. Hence,
+ // as this is the same for the derby client driver, we need to ensure
+ // our DNC client is at version and release level of 10.2 at least.
+ // We set the client version in the application requester and check
+ // if it is at the level we require at a minimum.
+ appRequester.setClientVersion(
+ srvrlslv.substring(0, (int) CodePoint.PRDID_MAX));
+
+ if (appRequester.supportsSecMecUSRSSBPWD() == false)
+ return CodePoint.SECCHKCD_NOTSUPPORTED; // Not Supported
+
+ dbName = database.shortDbName;
+ // Check if the database is available (booted)
+ //
+ // First we need to have the database name available and it should
+ // have been set as part of the ACCSEC request (in the case of a Derby
+ // 'DNC' client)
+ if ((dbName == null) || (dbName.length() == 0))
+ {
+ // No database specified in the connection URL attributes
+ //
+ // In this case, we get the authentication service handle from the
+ // local driver, as the requester may simply be trying to shutdown
+ // the engine.
+ authenticationService = ((InternalDriver)
+ NetworkServerControlImpl.getDriver()).getAuthenticationService();
+ }
+ else
+ {
+ // We get the authentication service from the database as this
+ // last one might have specified its own auth provider (at the
+ // database level).
+ //
+ // if monitor is never setup by any ModuleControl, getMonitor
+ // returns null and no cloudscape database has been booted.
+ if (Monitor.getMonitor() != null)
+ databaseObj = (org.apache.derby.iapi.db.Database)
+ Monitor.findService(Property.DATABASE_MODULE, dbName);
+
+ if (databaseObj == null)
+ {
+ // If database is not found, try connecting to it.
+ database.makeDummyConnection();
+
+ // now try to find it again
+ databaseObj = (org.apache.derby.iapi.db.Database)
+ Monitor.findService(Property.DATABASE_MODULE, dbName);
+ }
+
+ // If database still could not be found, it means the database
+ // does not exist - we just return security mechanism not
+ // supported down below as we could not verify we can handle
+ // it.
+ if (databaseObj != null)
+ authenticationService =
+ databaseObj.getAuthenticationService();
+ }
+
+ // Now we check if the authentication provider is NONE or BUILTIN
+ if (authenticationService != null)
+ {
+ String authClassName = authenticationService.getClass().getName();
+
+ if (!authClassName.equals(AUTHENTICATION_PROVIDER_BUILTIN_CLASS) &&
+ !authClassName.equals(AUTHENTICATION_PROVIDER_NONE_CLASS))
+ return CodePoint.SECCHKCD_NOTSUPPORTED; // Not Supported
+ }
+
+ // SECMEC_USRSSBPWD target initialization
+ try {
+ myTargetSeed = decryptionManager.generateSeed();
+ database.secTokenOut = myTargetSeed;
+ } catch (SQLException se) {
+ println2Log(null, session.drdaID, se.getMessage());
+ // Local security service non-retryable error.
+ return CodePoint.SECCHKCD_0A;
+ }
+
+ return 0; // SECMEC_USRSSBPWD is supported
+ }
private static int peekStream(EXTDTAInputStream is) throws IOException{
@@ -7730,6 +8001,4 @@
}
}
-
-
}
Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/Database.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/Database.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/Database.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/Database.java Wed Aug 9 06:51:30 2006
@@ -35,6 +35,7 @@
import org.apache.derby.iapi.reference.Attribute;
import org.apache.derby.iapi.tools.i18n.LocalizedResource;
import org.apache.derby.iapi.services.sanity.SanityManager;
+
/**
Database stores information about the current database
It is used so that a session may have more than one database
@@ -50,12 +51,13 @@
protected String password; // password
protected String decryptedUserId; // Decrypted User id
protected String decryptedPassword; // Decrypted password
+ protected byte[] passwordSubstitute;// password substitute - SECMEC_USRSSBPWD
protected boolean rdbAllowUpdates = true; // Database allows updates -default is true
protected int accessCount; // Number of times we have tried to
// set up access to this database (only 1
// allowed)
- protected byte[] publicKeyIn; // Security token from app requester
- protected byte[] publicKeyOut; // Security token sent to app requester
+ protected byte[] secTokenIn; // Security token from app requester
+ protected byte[] secTokenOut; // Security token sent to app requester
protected byte[] crrtkn; // Correlation token
protected String typDefNam; // Type definition name
protected int byteOrder; //deduced from typDefNam, save String comparisons
@@ -223,8 +225,8 @@
{
p.put(Attribute.USERNAME_ATTR, userId);
- // take care of case of SECMEC_USRIDONL
- if(password != null)
+ // take care of case of SECMEC_USRIDONL
+ if (password != null)
p.put(Attribute.PASSWORD_ATTR, password);
// Contract between network server and embedded engine
@@ -232,12 +234,37 @@
EngineConnection conn = (EngineConnection)
NetworkServerControlImpl.getDriver().connect(Attribute.PROTOCOL
+ shortDbName + attrString, p);
- if(conn != null){
+ if (conn != null) {
conn.setAutoCommit(false);
}
setConnection(conn);
}
+ /**
+ * This makes a dummy connection to the database in order to
+ * boot and/or create this last one. If database cannot
+ * be found or authentication does not succeed, this will throw
+ * a SQLException which we catch and do nothing. We don't pass a
+ * userid and password here as we don't need to for the purpose
+ * of this method - main goal is to cause the database to be
+ * booted via a dummy connection.
+ */
+ void makeDummyConnection()
+ {
+ try {
+ // Contract between network server and embedded engine
+ // is that any connection returned implements EngineConnection.
+ EngineConnection conn = (EngineConnection)
+ NetworkServerControlImpl.getDriver().connect(Attribute.PROTOCOL
+ + shortDbName + attrString, new Properties());
+
+ // If we succeeded in getting a connection, well just close it
+ if (conn != null) {
+ conn.close();
+ }
+ } catch (SQLException se) {} // Simply do nothing
+ }
+
// Create string to pass to DataSource.setConnectionAttributes
String appendAttrString(Properties p)
{
@@ -248,7 +275,7 @@
while (pKeys.hasMoreElements())
{
String key = (String) pKeys.nextElement();
- attrString +=";" + key +"=" + p.getProperty(key);
+ attrString +=";" + key + "=" + p.getProperty(key);
}
return attrString;
@@ -386,28 +413,15 @@
public void reset()
{
// Reset variables for connection re-use. Currently only takes care
- // of reset the variables that affect EUSRIDPWD security mechanism. (DERBY-1080)
+ // of reset the variables that affect EUSRIDPWD and USRSSBPWD
+ // security mechanisms. (DERBY-1080)
decryptedUserId = null;
decryptedPassword = null;
- publicKeyIn = null;
- publicKeyOut = null;
+ passwordSubstitute = null;
+ secTokenIn = null;
+ secTokenOut = null;
userId = null;
password = null;
securityMechanism = 0;
}
-
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DecryptionManager.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DecryptionManager.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DecryptionManager.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DecryptionManager.java Wed Aug 9 06:51:30 2006
@@ -35,6 +35,7 @@
import java.security.PublicKey;
import java.sql.SQLException;
import java.math.BigInteger;
+import org.apache.derby.shared.common.sanity.SanityManager;
/**
* This class is used to decrypt password and/or userid.
@@ -89,6 +90,10 @@
private KeyAgreement keyAgreement_;
private DHParameterSpec paramSpec_;
+ // Random Number Generator (PRNG) Algorithm
+ private final static String SHA_1_PRNG_ALGORITHM = "SHA1PRNG";
+ private final static int SECMEC_USRSSBPWD_SEED_LEN = 8; // Seed length
+
/**
* EncryptionManager constructor. In this constructor,DHParameterSpec,
* KeyPairGenerator, KeyPair, and KeyAgreement are initialized.
@@ -381,4 +386,109 @@
}
return plainText;
}
+
+ /**
+ * This method generates an 8-Byte random seed.
+ *
+ * Required for the SECMEC_USRSSBPWD security mechanism
+ *
+ * @return a random 8-Byte seed.
+ */
+ protected static byte[] generateSeed() throws SQLException {
+ java.security.SecureRandom secureRandom = null;
+ try {
+ // We're verifying that we can instantiate a randon number
+ // generator (PRNG).
+ secureRandom =
+ java.security.SecureRandom.getInstance(SHA_1_PRNG_ALGORITHM);
+ } catch (java.security.NoSuchAlgorithmException nsae) {
+ throw new SQLException(
+ "java.security.NoSuchAlgorithmException is caught" +
+ " when initializing DecryptionManager '" +
+ nsae.getMessage() + "'");
+ }
+ byte randomSeedBytes[] = new byte[SECMEC_USRSSBPWD_SEED_LEN];
+ secureRandom.setSeed(secureRandom.generateSeed(
+ SECMEC_USRSSBPWD_SEED_LEN));
+ secureRandom.nextBytes(randomSeedBytes);
+ // Return the 8-byte generated random seed
+ return randomSeedBytes;
+ }
+
+ /*********************************************************************
+ * RESOLVE: *
+ * The methods and static vars below should go into some 'shared' *
+ * package when the capability is put back in (StringUtil.java). *
+ *********************************************************************/
+
+ private static char[] hex_table = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+
+ /**
+ Convert a byte array to a String with a hexidecimal format.
+ The String may be converted back to a byte array using fromHexString.
+ <BR>
+ For each byte (b) two characaters are generated, the first character
+ represents the high nibble (4 bits) in hexidecimal (<code>b & 0xf0</code>),
+ the second character represents the low nibble (<code>b & 0x0f</code>).
+ <BR>
+ The byte at <code>data[offset]</code> is represented by the first two characters in the returned String.
+
+ @param data byte array
+ @param offset starting byte (zero based) to convert.
+ @param length number of bytes to convert.
+
+ @return the String (with hexidecimal format) form of the byte array
+ */
+ protected static String toHexString(byte[] data, int offset, int length)
+ {
+ StringBuffer s = new StringBuffer(length*2);
+ int end = offset+length;
+
+ for (int i = offset; i < end; i++)
+ {
+ int high_nibble = (data[i] & 0xf0) >>> 4;
+ int low_nibble = (data[i] & 0x0f);
+ s.append(hex_table[high_nibble]);
+ s.append(hex_table[low_nibble]);
+ }
+
+ return s.toString();
+ }
+
+ /**
+
+ Convert a string into a byte array in hex format.
+ <BR>
+ For each character (b) two bytes are generated, the first byte
+ represents the high nibble (4 bits) in hexidecimal (<code>b & 0xf0</code>),
+ the second byte
+ represents the low nibble (<code>b & 0x0f</code>).
+ <BR>
+ The character at <code>str.charAt(0)</code> is represented by the first two bytes
+ in the returned String.
+
+ @param str string
+ @param offset starting character (zero based) to convert.
+ @param length number of characters to convert.
+
+ @return the byte[] (with hexidecimal format) form of the string (str)
+ */
+ protected static byte[] toHexByte(String str, int offset, int length)
+ {
+ byte[] data = new byte[(length - offset) * 2];
+ int end = offset+length;
+
+ for (int i = offset; i < end; i++)
+ {
+ char ch = str.charAt(i);
+ int high_nibble = (ch & 0xf0) >>> 4;
+ int low_nibble = (ch & 0x0f);
+ data[i] = (byte)high_nibble;
+ data[i+1] = (byte)low_nibble;
+ }
+ return data;
+ }
}
Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/NetworkServerControlImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/NetworkServerControlImpl.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/NetworkServerControlImpl.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/NetworkServerControlImpl.java Wed Aug 9 06:51:30 2006
@@ -2534,12 +2534,15 @@
private int getSecMecValue(String s)
{
int secmec = INVALID_OR_NOTSET_SECURITYMECHANISM;
+
if( StringUtil.SQLEqualsIgnoreCase(s,"USER_ONLY_SECURITY"))
secmec = CodePoint.SECMEC_USRIDONL;
else if( StringUtil.SQLEqualsIgnoreCase(s,"CLEAR_TEXT_PASSWORD_SECURITY"))
secmec = CodePoint.SECMEC_USRIDPWD;
else if( StringUtil.SQLEqualsIgnoreCase(s,"ENCRYPTED_USER_AND_PASSWORD_SECURITY"))
secmec = CodePoint.SECMEC_EUSRIDPWD;
+ else if( StringUtil.SQLEqualsIgnoreCase(s,"STRONG_PASSWORD_SUBSTITUTE_SECURITY"))
+ secmec = CodePoint.SECMEC_USRSSBPWD;
return secmec;
}
@@ -2563,6 +2566,9 @@
case CodePoint.SECMEC_EUSRIDPWD:
return "ENCRYPTED_USER_AND_PASSWORD_SECURITY";
+
+ case CodePoint.SECMEC_USRSSBPWD:
+ return "STRONG_PASSWORD_SUBSTITUTE_SECURITY";
}
return null;
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Attribute.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Attribute.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Attribute.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Attribute.java Wed Aug 9 06:51:30 2006
@@ -222,13 +222,25 @@
*/
String RESTORE_FROM = "restoreFrom";
-
/**
The attribute that is used to request a roll-forward recovery of the database.
*/
String ROLL_FORWARD_RECOVERY_FROM = "rollForwardRecoveryFrom";
+ /**
+ * securityMechanism sets the DRDA mechanism in-use for the client.
+ * Internal only.
+ */
+ String CLIENT_SECURITY_MECHANISM = "securityMechanism";
+ /**
+ * Internal attributes. Mainly used by DRDA and Derby BUILTIN
+ * authentication provider in some security mechanism context
+ * (SECMEC_USRSSBPWD).
+ *
+ * DRDA_SECTKN_IN is the random client seed (RDs)
+ * DRDA_SECTKN_OUT is the random server seed (RDr)
+ */
+ String DRDA_SECTKN_IN = "drdaSecTokenIn";
+ String DRDA_SECTKN_OUT = "drdaSecTokenOut";
}
-
-
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=430056&r1=430055&r2=430056&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 Wed Aug 9 06:51:30 2006
@@ -774,6 +774,7 @@
* USER_ONLY_SECURITY
* CLEAR_TEXT_PASSWORD_SECURITY
* ENCRYPTED_USER_AND_PASSWORD_SECURITY
+ * STRONG_PASSWORD_SUBSTITUTE_SECURITY
* <BR>
* if derby.drda.securityMechanism is set to a valid mechanism, then
* the Network Server accepts only connections which use that
Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/util/StringUtil.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/util/StringUtil.java?rev=430056&r1=430055&r2=430056&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/util/StringUtil.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/util/StringUtil.java Wed Aug 9 06:51:30 2006
@@ -191,6 +191,39 @@
return s.toString();
}
+
+ /**
+
+ Convert a string into a byte array in hex format.
+ <BR>
+ For each character (b) two bytes are generated, the first byte
+ represents the high nibble (4 bits) in hexidecimal (<code>b & 0xf0</code>),
+ the second byte represents the low nibble (<code>b & 0x0f</code>).
+ <BR>
+ The character at <code>str.charAt(0)</code> is represented by the first two bytes
+ in the returned String.
+
+ @param str string
+ @param offset starting character (zero based) to convert.
+ @param length number of characters to convert.
+
+ @return the byte[] (with hexidecimal format) form of the string (str)
+ */
+ public static byte[] toHexByte(String str, int offset, int length)
+ {
+ byte[] data = new byte[(length - offset) * 2];
+ int end = offset+length;
+
+ for (int i = offset; i < end; i++)
+ {
+ char ch = str.charAt(i);
+ int high_nibble = (ch & 0xf0) >>> 4;
+ int low_nibble = (ch & 0x0f);
+ data[i] = (byte)high_nibble;
+ data[i+1] = (byte)low_nibble;
+ }
+ return data;
+ }
/**
Convert a hexidecimal string generated by toHexString() back