Author: rgodfrey
Date: Wed Dec 30 14:46:43 2015
New Revision: 1722339

URL: http://svn.apache.org/viewvc?rev=1722339&view=rev
Log:
QPID-6967 : [Java Broker] Add SCRAM-SHA* SASL support to Plain database based 
authentication managers

Added:
    
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSource.java
   (with props)
    
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSourceAdapter.java
   (with props)
Modified:
    
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java
    
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/ScramSHA1AuthenticationManager.java
    
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA256AuthenticationManager.java
    
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServer.java

Modified: 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java
URL: 
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java?rev=1722339&r1=1722338&r2=1722339&view=diff
==============================================================================
--- 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java
 (original)
+++ 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java
 Wed Dec 30 14:46:43 2015
@@ -102,8 +102,7 @@ public abstract class AbstractPasswordFi
 
 
     /**
-     * Looks up the password for a specified user in the password file. Note 
this code is <b>not</b> secure since it
-     * creates strings of passwords. It should be modified to create only char 
arrays which get nulled out.
+     * Looks up the password for a specified user in the password file.
      *
      * @param name The principal name to lookup
      *

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=1722339&r1=1722338&r2=1722339&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
 Wed Dec 30 14:46:43 2015
@@ -36,9 +36,13 @@ import javax.security.sasl.SaslServer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import 
org.apache.qpid.server.security.auth.manager.ScramSHA1AuthenticationManager;
+import 
org.apache.qpid.server.security.auth.manager.ScramSHA256AuthenticationManager;
 import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser;
 import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser;
 import org.apache.qpid.server.security.auth.sasl.plain.PlainSaslServer;
+import org.apache.qpid.server.security.auth.sasl.scram.ScramSaslServer;
+import 
org.apache.qpid.server.security.auth.sasl.scram.ScramSaslServerSourceAdapter;
 
 /**
  * Represents a user database where the account information is stored in a 
simple flat file.
@@ -53,18 +57,40 @@ public class PlainPasswordFilePrincipalD
     private final Logger _logger = 
LoggerFactory.getLogger(PlainPasswordFilePrincipalDatabase.class);
     private final Map<String, CallbackHandler> _callbackHandlerMap = new 
HashMap<String, CallbackHandler>();
     private final List<String> _mechanisms = 
Collections.unmodifiableList(Arrays.asList(PlainSaslServer.MECHANISM,
-                                                                               
         CRAMMD5Initialiser.MECHANISM));
+                                                                               
         CRAMMD5Initialiser.MECHANISM,
+                                                                               
         ScramSHA1AuthenticationManager.MECHANISM,
+                                                                               
         ScramSHA256AuthenticationManager.MECHANISM));
+    private final ScramSaslServerSourceAdapter _scramSha1Adapter;
+    private final ScramSaslServerSourceAdapter _scramSha256Adapter;
+
 
     public PlainPasswordFilePrincipalDatabase()
     {
         PlainInitialiser plainInitialiser = new PlainInitialiser();
         plainInitialiser.initialise(this);
         _callbackHandlerMap.put(PlainSaslServer.MECHANISM, 
plainInitialiser.getCallbackHandler());
+        _callbackHandlerMap.put(ScramSHA1AuthenticationManager.MECHANISM, 
plainInitialiser.getCallbackHandler());
+        _callbackHandlerMap.put(ScramSHA256AuthenticationManager.MECHANISM, 
plainInitialiser.getCallbackHandler());
+
 
         CRAMMD5Initialiser crammd5Initialiser = new CRAMMD5Initialiser();
         crammd5Initialiser.initialise(this);
         _callbackHandlerMap.put(CRAMMD5Initialiser.MECHANISM, 
crammd5Initialiser.getCallbackHandler());
 
+        ScramSaslServerSourceAdapter.PasswordSource passwordSource =
+                new ScramSaslServerSourceAdapter.PasswordSource()
+                {
+                    @Override
+                    public char[] getPassword(final String username)
+                    {
+                        return lookupPassword(username);
+                    }
+                };
+
+        _scramSha1Adapter = new ScramSaslServerSourceAdapter(4096, "HmacSHA1", 
passwordSource);
+        _scramSha256Adapter = new ScramSaslServerSourceAdapter(4096, 
"HmacSHA256", passwordSource);
+
+
     }
 
 
@@ -120,7 +146,7 @@ public class PlainPasswordFilePrincipalD
     @Override
     public SaslServer createSaslServer(String mechanism, String localFQDN, 
Principal externalPrincipal) throws SaslException
     {
-        CallbackHandler callbackHandler = _callbackHandlerMap.get(mechanism);
+        final CallbackHandler callbackHandler = 
_callbackHandlerMap.get(mechanism);
         if(callbackHandler == null)
         {
             throw new SaslException("Unsupported mechanism: " + mechanism);
@@ -135,7 +161,16 @@ public class PlainPasswordFilePrincipalD
         {
             return new PlainSaslServer(callbackHandler);
         }
+        else if(ScramSHA1AuthenticationManager.MECHANISM.equals(mechanism))
+        {
+            return new ScramSaslServer(_scramSha1Adapter, mechanism, 
"HmacSHA1", "SHA-1");
+        }
+        else if(ScramSHA256AuthenticationManager.MECHANISM.equals(mechanism))
+        {
+            return new ScramSaslServer(_scramSha256Adapter, mechanism, 
"HmacSHA256", "SHA-256");
+        }
 
         throw new SaslException("Unsupported mechanism: " + mechanism);
     }
+
 }

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=1722339&r1=1722338&r2=1722339&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
 Wed Dec 30 14:46:43 2015
@@ -41,10 +41,11 @@ import org.apache.qpid.server.security.a
 import org.apache.qpid.server.security.auth.UsernamePrincipal;
 import org.apache.qpid.server.security.auth.sasl.plain.PlainAdapterSaslServer;
 import org.apache.qpid.server.security.auth.sasl.scram.ScramSaslServer;
+import org.apache.qpid.server.security.auth.sasl.scram.ScramSaslServerSource;
 
 public abstract class AbstractScramAuthenticationManager<X extends 
AbstractScramAuthenticationManager<X>>
         extends ConfigModelPasswordManagingAuthenticationProvider<X>
-        implements PasswordCredentialManagingAuthenticationProvider<X>
+        implements PasswordCredentialManagingAuthenticationProvider<X>, 
ScramSaslServerSource
 {
 
     public static final String PLAIN = "PLAIN";
@@ -213,4 +214,46 @@ public abstract class AbstractScramAuthe
             throw new IllegalArgumentException("User names are restricted to 
characters in the ASCII charset");
         }
     }
+
+    @Override
+    public SaltAndSaltedPassword getSaltAndSaltedPassword(final String 
username)
+    {
+        final byte[] salt = getSalt(username);
+        byte[] tmpPassword = null;
+        SaslException tmpException = null;
+
+        try
+        {
+            tmpPassword = getSaltedPassword(username);
+        }
+        catch (SaslException e)
+        {
+            tmpException = e;
+        }
+
+        final byte[] saltedPassword = tmpPassword;
+        final SaslException exception = tmpException;
+
+        return new SaltAndSaltedPassword()
+        {
+            @Override
+            public byte[] getSalt()
+            {
+                return salt;
+            }
+
+            @Override
+            public byte[] getSaltedPassword() throws SaslException
+            {
+                if(exception == null)
+                {
+                    return saltedPassword;
+                }
+                else
+                {
+                    throw exception;
+                }
+            }
+        };
+    }
 }

Modified: 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA1AuthenticationManager.java
URL: 
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA1AuthenticationManager.java?rev=1722339&r1=1722338&r2=1722339&view=diff
==============================================================================
--- 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA1AuthenticationManager.java
 (original)
+++ 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA1AuthenticationManager.java
 Wed Dec 30 14:46:43 2015
@@ -34,8 +34,7 @@ public class ScramSHA1AuthenticationMana
     public static final String PROVIDER_TYPE = "SCRAM-SHA-1";
     private static final String HMAC_NAME = "HmacSHA1";
 
-    static final Charset ASCII = Charset.forName("ASCII");
-    private static final String MECHANISM = "SCRAM-SHA-1";
+    public static final String MECHANISM = "SCRAM-SHA-1";
     private static final String DIGEST_NAME = "SHA-1";
 
 

Modified: 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA256AuthenticationManager.java
URL: 
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA256AuthenticationManager.java?rev=1722339&r1=1722338&r2=1722339&view=diff
==============================================================================
--- 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA256AuthenticationManager.java
 (original)
+++ 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramSHA256AuthenticationManager.java
 Wed Dec 30 14:46:43 2015
@@ -34,8 +34,7 @@ public class ScramSHA256AuthenticationMa
     public static final String PROVIDER_TYPE = "SCRAM-SHA-256";
     private static final String HMAC_NAME = "HmacSHA256";
 
-    static final Charset ASCII = Charset.forName("ASCII");
-    private static final String MECHANISM = "SCRAM-SHA-256";
+    public static final String MECHANISM = "SCRAM-SHA-256";
     private static final String DIGEST_NAME = "SHA-256";
 
 

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=1722339&r1=1722338&r2=1722339&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
 Wed Dec 30 14:46:43 2015
@@ -44,7 +44,7 @@ public class ScramSaslServer implements
 
     private static final Charset ASCII = Charset.forName("ASCII");
 
-    private final AbstractScramAuthenticationManager _authManager;
+    private final ScramSaslServerSource _authManager;
     private State _state = State.INITIAL;
     private String _nonce;
     private String _username;
@@ -52,8 +52,9 @@ public class ScramSaslServer implements
     private String _serverFirstMessage;
     private String _clientFirstMessageBare;
     private byte[] _serverSignature;
+    private ScramSaslServerSource.SaltAndSaltedPassword _saltAndPassword;
 
-    public ScramSaslServer(final AbstractScramAuthenticationManager 
authenticationManager,
+    public ScramSaslServer(final ScramSaslServerSource authenticationManager,
                            final String mechanism,
                            final String hmacName,
                            final String digestName)
@@ -130,8 +131,8 @@ public class ScramSaslServer implements
         _nonce = parts[3].substring(2) + UUID.randomUUID().toString();
 
         int count = _authManager.getIterationCount();
-        byte[] saltBytes = _authManager.getSalt(_username);
-        _serverFirstMessage = "r="+_nonce+",s="+ 
DatatypeConverter.printBase64Binary(saltBytes)+",i=" + count;
+        _saltAndPassword = _authManager.getSaltAndSaltedPassword(_username);
+        _serverFirstMessage = "r="+_nonce+",s="+ 
DatatypeConverter.printBase64Binary(_saltAndPassword.getSalt())+",i=" + count;
         return _serverFirstMessage.getBytes(ASCII);
     }
 
@@ -187,7 +188,7 @@ public class ScramSaslServer implements
 
             String authMessage = _clientFirstMessageBare + "," + 
_serverFirstMessage + "," + clientFinalMessageWithoutProof;
 
-            byte[] saltedPassword = _authManager.getSaltedPassword(_username);
+            byte[] saltedPassword = _saltAndPassword.getSaltedPassword();
 
             byte[] clientKey = computeHmac(saltedPassword, "Client Key");
 

Added: 
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=1722339&view=auto
==============================================================================
--- 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSource.java
 (added)
+++ 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSource.java
 Wed Dec 30 14:46:43 2015
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.auth.sasl.scram;
+
+import javax.security.sasl.SaslException;
+
+public interface ScramSaslServerSource
+{
+    int getIterationCount();
+
+    interface SaltAndSaltedPassword
+    {
+        byte[] getSalt();
+
+        byte[] getSaltedPassword() throws SaslException;
+    }
+
+    SaltAndSaltedPassword getSaltAndSaltedPassword(String username);
+
+}

Propchange: 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSource.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
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=1722339&view=auto
==============================================================================
--- 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSourceAdapter.java
 (added)
+++ 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSourceAdapter.java
 Wed Dec 30 14:46:43 2015
@@ -0,0 +1,127 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.auth.sasl.scram;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+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};
+
+    private final int _iterationCount;
+    private final String _hmacName;
+    private final SecureRandom _random = new SecureRandom();
+    private final PasswordSource _passwordSource;
+
+    public interface PasswordSource
+    {
+        char[] getPassword(String username);
+    }
+
+    public ScramSaslServerSourceAdapter(final int iterationCount,
+                                        final String hmacName,
+                                        final PasswordSource passwordSource)
+    {
+        _iterationCount = iterationCount;
+        _hmacName = hmacName;
+        _passwordSource = passwordSource;
+    }
+
+    @Override
+    public int getIterationCount()
+    {
+        return _iterationCount;
+    }
+
+    @Override
+    public SaltAndSaltedPassword getSaltAndSaltedPassword(final String 
username)
+    {
+        final char[] password = _passwordSource.getPassword(username);
+
+        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)
+                {
+                    throw new SaslException("Authentication Failed");
+                }
+                byte[] passwordAsBytes = new byte[password.length];
+                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[] previous = null;
+                for(int i = 1; i < getIterationCount(); i++)
+                {
+                    mac.update(previous != null? previous: result);
+                    previous = mac.doFinal();
+                    for(int x = 0; x < result.length; x++)
+                    {
+                        result[x] ^= previous[x];
+                    }
+                }
+
+                return result;
+
+            }
+
+            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);
+                }
+            }
+
+        };
+    }
+}

Propchange: 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/scram/ScramSaslServerSourceAdapter.java
------------------------------------------------------------------------------
    svn:eol-style = native



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to