Author: rgodfrey
Date: Tue Jan 12 14:46:25 2016
New Revision: 1724251
URL: http://svn.apache.org/viewvc?rev=1724251&view=rev
Log:
QPID-6993 : Improve ScramSHA* authentication managers so they no longer store
the hashed salted password
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PlainAuthenticationProvider.java
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleAuthenticationManager.java
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServer.java
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSource.java
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSourceAdapter.java
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java?rev=1724251&r1=1724250&r2=1724251&view=diff
==============================================================================
---
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java
(original)
+++
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java
Tue Jan 12 14:46:25 2016
@@ -87,8 +87,8 @@ public class PlainPasswordFilePrincipalD
}
};
- _scramSha1Adapter = new ScramSaslServerSourceAdapter(4096, "HmacSHA1",
passwordSource);
- _scramSha256Adapter = new ScramSaslServerSourceAdapter(4096,
"HmacSHA256", passwordSource);
+ _scramSha1Adapter = new ScramSaslServerSourceAdapter(4096, "HmacSHA1",
"SHA-1", passwordSource);
+ _scramSha256Adapter = new ScramSaslServerSourceAdapter(4096,
"HmacSHA256", "SHA-256", passwordSource);
}
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java?rev=1724251&r1=1724250&r2=1724251&view=diff
==============================================================================
---
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java
(original)
+++
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java
Tue Jan 12 14:46:25 2016
@@ -20,7 +20,9 @@
*/
package org.apache.qpid.server.security.auth.manager;
+import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
+import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.SecureRandom;
@@ -35,8 +37,12 @@ import javax.security.sasl.SaslException
import javax.security.sasl.SaslServer;
import javax.xml.bind.DatatypeConverter;
+import com.google.common.util.concurrent.ListenableFuture;
+
import org.apache.qpid.server.model.Broker;
import
org.apache.qpid.server.model.PasswordCredentialManagingAuthenticationProvider;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.StateTransition;
import org.apache.qpid.server.security.auth.AuthenticationResult;
import org.apache.qpid.server.security.auth.UsernamePrincipal;
import org.apache.qpid.server.security.auth.sasl.plain.PlainAdapterSaslServer;
@@ -59,6 +65,16 @@ public abstract class AbstractScramAuthe
super(attributes, broker);
}
+ @StateTransition( currentState = { State.UNINITIALIZED, State.QUIESCED,
State.QUIESCED }, desiredState = State.ACTIVE )
+ protected ListenableFuture<Void> activate()
+ {
+ for(ManagedUser user : getUserMap().values())
+ {
+ updateStoredPasswordFormatIfNecessary(user);
+ }
+ return super.activate();
+ }
+
@Override
public List<String> getMechanisms()
{
@@ -95,17 +111,26 @@ public abstract class AbstractScramAuthe
ManagedUser user = getUser(username);
if(user != null)
{
- final String[] usernamePassword = user.getPassword().split(",");
+ updateStoredPasswordFormatIfNecessary(user);
+ String[] usernamePassword = user.getPassword().split(",");
byte[] salt =
DatatypeConverter.parseBase64Binary(usernamePassword[0]);
try
{
-
if(Arrays.equals(DatatypeConverter.parseBase64Binary(usernamePassword[1]),
- createSaltedPassword(salt, password)))
+ byte[] saltedPassword = createSaltedPassword(salt, password);
+ byte[] clientKey = computeHmac(saltedPassword, "Client Key");
+
+ byte[] storedKey =
MessageDigest.getInstance(getDigestName()).digest(clientKey);
+
+ byte[] serverKey = computeHmac(saltedPassword, "Server Key");
+
+
if(Arrays.equals(DatatypeConverter.parseBase64Binary(usernamePassword[2]),
storedKey)
+ &&
Arrays.equals(DatatypeConverter.parseBase64Binary(usernamePassword[3]),
serverKey))
+
{
return new AuthenticationResult(new
UsernamePrincipal(username));
}
}
- catch (IllegalArgumentException e)
+ catch (IllegalArgumentException | NoSuchAlgorithmException e)
{
return new
AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR,e);
}
@@ -144,7 +169,21 @@ public abstract class AbstractScramAuthe
private static final byte[] INT_1 = new byte[]{0, 0, 0, 1};
- public byte[] getSaltedPassword(final String username) throws SaslException
+ private byte[] getStoredKey(final String username) throws SaslException
+ {
+ ManagedUser user = getUser(username);
+ if(user == null)
+ {
+ throw new SaslException("Authentication Failed");
+ }
+ else
+ {
+ updateStoredPasswordFormatIfNecessary(user);
+ return
DatatypeConverter.parseBase64Binary(user.getPassword().split(",")[2]);
+ }
+ }
+
+ private byte[] getServerKey(final String username) throws SaslException
{
ManagedUser user = getUser(username);
if(user == null)
@@ -153,7 +192,36 @@ public abstract class AbstractScramAuthe
}
else
{
- return
DatatypeConverter.parseBase64Binary(user.getPassword().split(",")[1]);
+ updateStoredPasswordFormatIfNecessary(user);
+ return
DatatypeConverter.parseBase64Binary(user.getPassword().split(",")[2]);
+ }
+ }
+
+
+ private void updateStoredPasswordFormatIfNecessary(final ManagedUser user)
+ {
+ if(user.getPassword().split(",").length<4)
+ {
+ byte[] saltedPassword =
DatatypeConverter.parseBase64Binary(user.getPassword().split(",")[1]);
+
+ try
+ {
+ byte[] clientKey = computeHmac(saltedPassword, "Client Key");
+
+ byte[] storedKey =
MessageDigest.getInstance(getDigestName()).digest(clientKey);
+
+ byte[] serverKey = computeHmac(saltedPassword, "Server Key");
+
+ String password = user.getPassword().split(",")[0] + ",,"
+ +
DatatypeConverter.printBase64Binary(storedKey) + ","
+ +
DatatypeConverter.printBase64Binary(serverKey);
+
+ user.setPassword(password);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new IllegalArgumentException(e);
+ }
}
}
@@ -180,6 +248,13 @@ public abstract class AbstractScramAuthe
}
+ private byte[] computeHmac(final byte[] key, final String string)
+ {
+ Mac mac = createShaHmac(key);
+ mac.update(string.getBytes(StandardCharsets.US_ASCII));
+ return mac.doFinal();
+ }
+
private Mac createShaHmac(final byte[] keyBytes)
{
try
@@ -200,10 +275,24 @@ public abstract class AbstractScramAuthe
@Override
protected String createStoredPassword(final String password)
{
- byte[] salt = new byte[32];
- _random.nextBytes(salt);
- byte[] passwordBytes = createSaltedPassword(salt, password);
- return DatatypeConverter.printBase64Binary(salt) + "," +
DatatypeConverter.printBase64Binary(passwordBytes);
+ try
+ {
+ byte[] salt = new byte[32];
+ _random.nextBytes(salt);
+ byte[] saltedPassword = createSaltedPassword(salt, password);
+ byte[] clientKey = computeHmac(saltedPassword, "Client Key");
+
+ byte[] storedKey =
MessageDigest.getInstance(getDigestName()).digest(clientKey);
+ byte[] serverKey = computeHmac(saltedPassword, "Server Key");
+
+ return DatatypeConverter.printBase64Binary(salt) + ",,"
+ + DatatypeConverter.printBase64Binary(storedKey) + ","
+ + DatatypeConverter.printBase64Binary(serverKey);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new IllegalArgumentException(e);
+ }
}
@Override
@@ -219,19 +308,23 @@ public abstract class AbstractScramAuthe
public SaltAndSaltedPassword getSaltAndSaltedPassword(final String
username)
{
final byte[] salt = getSalt(username);
- byte[] tmpPassword = null;
SaslException tmpException = null;
+ byte[] tmpStoredKey = null;
+ byte[] tmpServerKey = null;
+
try
{
- tmpPassword = getSaltedPassword(username);
+ tmpStoredKey = getStoredKey(username);
+ tmpServerKey = getServerKey(username);
}
catch (SaslException e)
{
tmpException = e;
}
- final byte[] saltedPassword = tmpPassword;
+ final byte[] storedKey = tmpStoredKey;
+ final byte[] serverKey = tmpServerKey;
final SaslException exception = tmpException;
return new SaltAndSaltedPassword()
@@ -242,17 +335,25 @@ public abstract class AbstractScramAuthe
return salt;
}
+
@Override
- public byte[] getSaltedPassword() throws SaslException
+ public byte[] getStoredKey() throws SaslException
{
- if(exception == null)
+ if(storedKey == null)
{
- return saltedPassword;
+ throw exception;
}
- else
+ return storedKey;
+ }
+
+ @Override
+ public byte[] getServerKey() throws SaslException
+ {
+ if(serverKey == null)
{
throw exception;
}
+ return serverKey;
}
};
}
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PlainAuthenticationProvider.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PlainAuthenticationProvider.java?rev=1724251&r1=1724250&r2=1724251&view=diff
==============================================================================
---
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PlainAuthenticationProvider.java
(original)
+++
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PlainAuthenticationProvider.java
Tue Jan 12 14:46:25 2016
@@ -81,8 +81,8 @@ public class PlainAuthenticationProvider
- _scramSha1Adapter = new ScramSaslServerSourceAdapter(4096, "HmacSHA1",
passwordSource);
- _scramSha256Adapter = new ScramSaslServerSourceAdapter(4096,
"HmacSHA256", passwordSource);
+ _scramSha1Adapter = new ScramSaslServerSourceAdapter(4096, "HmacSHA1",
"SHA-1", passwordSource);
+ _scramSha256Adapter = new ScramSaslServerSourceAdapter(4096,
"HmacSHA256", "SHA-256", passwordSource);
}
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleAuthenticationManager.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleAuthenticationManager.java?rev=1724251&r1=1724250&r2=1724251&view=diff
==============================================================================
---
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleAuthenticationManager.java
(original)
+++
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleAuthenticationManager.java
Tue Jan 12 14:46:25 2016
@@ -80,8 +80,8 @@ public class SimpleAuthenticationManager
}
};
- _scramSha1Adapter = new ScramSaslServerSourceAdapter(4096, "HmacSHA1",
passwordSource);
- _scramSha256Adapter = new ScramSaslServerSourceAdapter(4096,
"HmacSHA256", passwordSource);
+ _scramSha1Adapter = new ScramSaslServerSourceAdapter(4096, "HmacSHA1",
"SHA-1", passwordSource);
+ _scramSha256Adapter = new ScramSaslServerSourceAdapter(4096,
"HmacSHA256", "SHA-256", passwordSource);
}
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServer.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServer.java?rev=1724251&r1=1724250&r2=1724251&view=diff
==============================================================================
---
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServer.java
(original)
+++
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServer.java
Tue Jan 12 14:46:25 2016
@@ -34,8 +34,6 @@ import javax.security.sasl.SaslException
import javax.security.sasl.SaslServer;
import javax.xml.bind.DatatypeConverter;
-import
org.apache.qpid.server.security.auth.manager.AbstractScramAuthenticationManager;
-
public class ScramSaslServer implements SaslServer
{
public final String _mechanism;
@@ -188,25 +186,24 @@ public class ScramSaslServer implements
String authMessage = _clientFirstMessageBare + "," +
_serverFirstMessage + "," + clientFinalMessageWithoutProof;
- byte[] saltedPassword = _saltAndPassword.getSaltedPassword();
-
- byte[] clientKey = computeHmac(saltedPassword, "Client Key");
- byte[] storedKey =
MessageDigest.getInstance(_digestName).digest(clientKey);
+ byte[] storedKey = _saltAndPassword.getStoredKey();
byte[] clientSignature = computeHmac(storedKey, authMessage);
- byte[] clientProof = clientKey.clone();
- for(int i = 0 ; i < clientProof.length; i++)
+ for(int i = 0 ; i < proofBytes.length; i++)
{
- clientProof[i] ^= clientSignature[i];
+ proofBytes[i] ^= clientSignature[i];
}
- if(!Arrays.equals(clientProof, proofBytes))
+ final byte[] storedKeyFromClient =
MessageDigest.getInstance(_digestName).digest(proofBytes);
+
+ if(!Arrays.equals(storedKeyFromClient, storedKey))
{
throw new SaslException("Authentication failed");
}
- byte[] serverKey = computeHmac(saltedPassword, "Server Key");
+
+ byte[] serverKey = _saltAndPassword.getServerKey();
String finalResponse = "v=" +
DatatypeConverter.printBase64Binary(computeHmac(serverKey, authMessage));
return finalResponse.getBytes(ASCII);
@@ -260,13 +257,13 @@ public class ScramSaslServer implements
private byte[] computeHmac(final byte[] key, final String string)
throws SaslException, UnsupportedEncodingException
{
- Mac mac = createSha1Hmac(key);
+ Mac mac = createShaHmac(key);
mac.update(string.getBytes(ASCII));
return mac.doFinal();
}
- private Mac createSha1Hmac(final byte[] keyBytes)
+ private Mac createShaHmac(final byte[] keyBytes)
throws SaslException
{
try
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSource.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSource.java?rev=1724251&r1=1724250&r2=1724251&view=diff
==============================================================================
---
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSource.java
(original)
+++
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSource.java
Tue Jan 12 14:46:25 2016
@@ -30,7 +30,9 @@ public interface ScramSaslServerSource
{
byte[] getSalt();
- byte[] getSaltedPassword() throws SaslException;
+ byte[] getStoredKey() throws SaslException;
+
+ byte[] getServerKey() throws SaslException;
}
SaltAndSaltedPassword getSaltAndSaltedPassword(String username);
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSourceAdapter.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSourceAdapter.java?rev=1724251&r1=1724250&r2=1724251&view=diff
==============================================================================
---
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSourceAdapter.java
(original)
+++
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSourceAdapter.java
Tue Jan 12 14:46:25 2016
@@ -20,7 +20,9 @@
*/
package org.apache.qpid.server.security.auth.sasl.scram;
+import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
+import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
@@ -28,8 +30,6 @@ import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.security.sasl.SaslException;
-import
org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase;
-
public class ScramSaslServerSourceAdapter implements ScramSaslServerSource
{
private static final byte[] INT_1 = new byte[]{0, 0, 0, 1};
@@ -38,6 +38,7 @@ public class ScramSaslServerSourceAdapte
private final String _hmacName;
private final SecureRandom _random = new SecureRandom();
private final PasswordSource _passwordSource;
+ private final String _digestName;
public interface PasswordSource
{
@@ -46,11 +47,13 @@ public class ScramSaslServerSourceAdapte
public ScramSaslServerSourceAdapter(final int iterationCount,
final String hmacName,
+ final String digestName,
final PasswordSource passwordSource)
{
_iterationCount = iterationCount;
_hmacName = hmacName;
_passwordSource = passwordSource;
+ _digestName = digestName;
}
@Override
@@ -59,69 +62,112 @@ public class ScramSaslServerSourceAdapte
return _iterationCount;
}
+ private Mac createShaHmac(final byte[] keyBytes)
+ {
+ try
+ {
+ SecretKeySpec key = new SecretKeySpec(keyBytes, _hmacName);
+ Mac mac = Mac.getInstance(_hmacName);
+ mac.init(key);
+ return mac;
+ }
+ catch (NoSuchAlgorithmException | InvalidKeyException e)
+ {
+ throw new IllegalArgumentException(e.getMessage(), e);
+ }
+ }
+
+ private byte[] computeHmac(final byte[] key, final String string)
+ {
+ Mac mac = createShaHmac(key);
+ mac.update(string.getBytes(StandardCharsets.US_ASCII));
+ return mac.doFinal();
+ }
+
@Override
public SaltAndSaltedPassword getSaltAndSaltedPassword(final String
username)
{
final char[] password = _passwordSource.getPassword(username);
-
+ final byte[] storedKey;
+ final byte[] serverKey;
final byte[] salt = new byte[32];
_random.nextBytes(salt);
- return new SaltAndSaltedPassword()
- {
- @Override
- public byte[] getSalt()
- {
- return salt;
- }
- @Override
- public byte[] getSaltedPassword() throws SaslException
+ if(password != null)
+ {
+ try
{
- if(password == null)
- {
- throw new SaslException("Authentication Failed");
- }
byte[] passwordAsBytes = new byte[password.length];
- for(int i = 0; i< password.length; i++)
+ for (int i = 0; i < password.length; i++)
{
passwordAsBytes[i] = (byte) password[i];
}
+
Mac mac = createShaHmac(passwordAsBytes);
mac.update(salt);
mac.update(INT_1);
- byte[] result = mac.doFinal();
+ byte[] saltedPassword = mac.doFinal();
byte[] previous = null;
- for(int i = 1; i < getIterationCount(); i++)
+ for (int i = 1; i < getIterationCount(); i++)
{
- mac.update(previous != null? previous: result);
+ mac.update(previous != null ? previous : saltedPassword);
previous = mac.doFinal();
- for(int x = 0; x < result.length; x++)
+ for (int x = 0; x < saltedPassword.length; x++)
{
- result[x] ^= previous[x];
+ saltedPassword[x] ^= previous[x];
}
}
- return result;
+ byte[] clientKey = computeHmac(saltedPassword, "Client Key");
+ storedKey =
MessageDigest.getInstance(_digestName).digest(clientKey);
+
+ serverKey = computeHmac(saltedPassword, "Server Key");
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new IllegalArgumentException(e);
+ }
+
+ }
+ else
+ {
+ storedKey = null;
+ serverKey = null;
+ }
+
+ return new SaltAndSaltedPassword()
+ {
+ @Override
+ public byte[] getSalt()
+ {
+ return salt;
}
- private Mac createShaHmac(final byte[] keyBytes)
+ @Override
+ public byte[] getStoredKey() throws SaslException
{
- try
+ if(storedKey == null)
{
- SecretKeySpec key = new SecretKeySpec(keyBytes, _hmacName);
- Mac mac = Mac.getInstance(_hmacName);
- mac.init(key);
- return mac;
+ throw new SaslException("Authentication Failed");
}
- catch (NoSuchAlgorithmException | InvalidKeyException e)
+ return storedKey;
+ }
+
+ @Override
+ public byte[] getServerKey() throws SaslException
+ {
+
+ if(serverKey == null)
{
- throw new IllegalArgumentException(e.getMessage(), e);
+ throw new SaslException("Authentication Failed");
}
+ return serverKey;
}
+
};
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]