You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ro...@apache.org on 2011/05/26 16:27:08 UTC

svn commit: r1127939 - in /qpid/trunk/qpid/java/client/src: main/java/org/apache/qpid/client/ main/java/org/apache/qpid/client/handler/ main/java/org/apache/qpid/client/protocol/ main/java/org/apache/qpid/client/security/ test/java/org/apache/qpid/clie...

Author: robbie
Date: Thu May 26 14:27:07 2011
New Revision: 1127939

URL: http://svn.apache.org/viewvc?rev=1127939&view=rev
Log:
QPID-3277: AMQCallbackHandler improvements. Refactor AMQCallbackHandler to accept ConnectionURL in place of AMQProtocolSession (improved information hiding, ease ability to write good unit tests). Remove unused protected constructor from AMQConnection and MockAMQConnection.

Applied patch from  Keith Wall <ke...@gmail.com>

Added:
    qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/security/
    qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandlerTest.java
    qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandlerTest.java
Modified:
    qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java
    qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java
    qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java
    qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/security/AMQCallbackHandler.java
    qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java
    qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandler.java
    qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java

Modified: qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java?rev=1127939&r1=1127938&r2=1127939&view=diff
==============================================================================
--- qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java (original)
+++ qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java Thu May 26 14:27:07 2011
@@ -111,7 +111,7 @@ public class AMQConnection extends Close
     /** Maps from session id (Integer) to AMQSession instance */
     private final ChannelToSessionMap _sessions = new ChannelToSessionMap();
 
-    private String _clientName;
+    private final String _clientName;
 
     /** The user name to use for authentication */
     private String _username;
@@ -126,7 +126,7 @@ public class AMQConnection extends Close
 
     private ConnectionListener _connectionListener;
 
-    private ConnectionURL _connectionURL;
+    private final ConnectionURL _connectionURL;
 
     /**
      * Whether this connection is started, i.e. whether messages are flowing to consumers. It has no meaning for message
@@ -257,6 +257,11 @@ public class AMQConnection extends Close
      */
     public AMQConnection(ConnectionURL connectionURL, SSLConfiguration sslConfig) throws AMQException
     {
+        if (connectionURL == null)
+        {
+            throw new IllegalArgumentException("Connection must be specified");
+        }
+        
         // set this connection maxPrefetch
         if (connectionURL.getOption(ConnectionURL.OPTIONS_MAXPREFETCH) != null)
         {
@@ -264,7 +269,7 @@ public class AMQConnection extends Close
         }
         else
         {
-            // use the defaul value set for all connections
+            // use the default value set for all connections
             _maxPrefetch = Integer.parseInt(System.getProperties().getProperty(ClientProperties.MAX_PREFETCH_PROP_NAME,
                     ClientProperties.MAX_PREFETCH_DEFAULT));
         }
@@ -278,7 +283,7 @@ public class AMQConnection extends Close
         }
         else
         {
-            // use the defaul value set for all connections
+            // use the default value set for all connections
             _syncPersistence = Boolean.getBoolean(ClientProperties.SYNC_PERSISTENT_PROP_NAME);
             if (_syncPersistence)
             {
@@ -293,7 +298,7 @@ public class AMQConnection extends Close
         }
         else
         {
-            // use the defaul value set for all connections
+            // use the default value set for all connections
             _syncAck = Boolean.getBoolean(ClientProperties.SYNC_ACK_PROP_NAME);
         }
 
@@ -346,11 +351,6 @@ public class AMQConnection extends Close
         }
 
         _sslConfiguration = sslConfig;
-        if (connectionURL == null)
-        {
-            throw new IllegalArgumentException("Connection must be specified");
-        }
-
         _connectionURL = connectionURL;
 
         _clientName = connectionURL.getClientName();
@@ -535,14 +535,6 @@ public class AMQConnection extends Close
         }
     }
 
-    protected AMQConnection(String username, String password, String clientName, String virtualHost)
-    {
-        _clientName = clientName;
-        _username = username;
-        _password = password;
-        setVirtualHost(virtualHost);
-    }
-
     private void setVirtualHost(String virtualHost)
     {
         if (virtualHost != null && virtualHost.startsWith("/"))
@@ -696,20 +688,6 @@ public class AMQConnection extends Close
         }
     }
 
-    private void reopenChannel(int channelId, int prefetchHigh, int prefetchLow, boolean transacted)
-            throws AMQException, FailoverException
-    {
-        try
-        {
-            createChannelOverWire(channelId, prefetchHigh, prefetchLow, transacted);
-        }
-        catch (AMQException e)
-        {
-            deregisterSession(channelId);
-            throw new AMQException(null, "Error reopening channel " + channelId + " after failover: " + e, e);
-        }
-    }
-
     public void setFailoverPolicy(FailoverPolicy policy)
     {
         _failoverPolicy = policy;
@@ -1372,6 +1350,20 @@ public class AMQConnection extends Close
         return buf.toString();
     }
 
+    /**
+     * Returns connection url. 
+     * @return connection url
+     */
+    public ConnectionURL getConnectionURL()
+    {
+        return _connectionURL;
+    }
+    
+    /**
+     * Returns stringified connection url.   This url is suitable only for display
+     * as {@link AMQConnectionURL#toString()} converts any password to asterisks. 
+     * @return connection url
+     */
     public String toURL()
     {
         return _connectionURL.toString();

Modified: qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java?rev=1127939&r1=1127938&r2=1127939&view=diff
==============================================================================
--- qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java (original)
+++ qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java Thu May 26 14:27:07 2011
@@ -226,7 +226,7 @@ public class ConnectionStartMethodHandle
         {
             Object instance = mechanismClass.newInstance();
             AMQCallbackHandler cbh = (AMQCallbackHandler) instance;
-            cbh.initialise(protocolSession);
+            cbh.initialise(protocolSession.getAMQConnection().getConnectionURL());
 
             return cbh;
         }

Modified: qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java?rev=1127939&r1=1127938&r2=1127939&view=diff
==============================================================================
--- qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java (original)
+++ qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java Thu May 26 14:27:07 2011
@@ -148,16 +148,6 @@ public class AMQProtocolSession implemen
         return getAMQConnection().getVirtualHost();
     }
 
-    public String getUsername()
-    {
-        return getAMQConnection().getUsername();
-    }
-
-    public String getPassword()
-    {
-        return getAMQConnection().getPassword();
-    }
-
     public SaslClient getSaslClient()
     {
         return _saslClient;

Modified: qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/security/AMQCallbackHandler.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/security/AMQCallbackHandler.java?rev=1127939&r1=1127938&r2=1127939&view=diff
==============================================================================
--- qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/security/AMQCallbackHandler.java (original)
+++ qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/security/AMQCallbackHandler.java Thu May 26 14:27:07 2011
@@ -22,9 +22,9 @@ package org.apache.qpid.client.security;
 
 import javax.security.auth.callback.CallbackHandler;
 
-import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.jms.ConnectionURL;
 
 public interface AMQCallbackHandler extends CallbackHandler
 {
-    void initialise(AMQProtocolSession protocolSession);    
+    void initialise(ConnectionURL connectionURL);    
 }

Modified: qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java?rev=1127939&r1=1127938&r2=1127939&view=diff
==============================================================================
--- qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java (original)
+++ qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java Thu May 26 14:27:07 2011
@@ -20,30 +20,29 @@
  */
 package org.apache.qpid.client.security;
 
-import org.apache.qpid.client.protocol.AMQProtocolSession;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 
 import javax.security.auth.callback.Callback;
 import javax.security.auth.callback.NameCallback;
 import javax.security.auth.callback.PasswordCallback;
 import javax.security.auth.callback.UnsupportedCallbackException;
 
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
+import org.apache.qpid.jms.ConnectionURL;
 
 public class UsernameHashedPasswordCallbackHandler implements AMQCallbackHandler
 {
-    private static final Logger _logger = LoggerFactory.getLogger(UsernameHashedPasswordCallbackHandler.class);
+    private ConnectionURL _connectionURL;
 
-    private AMQProtocolSession _protocolSession;
-
-    public void initialise(AMQProtocolSession protocolSession)
+    /**
+     * @see org.apache.qpid.client.security.AMQCallbackHandler#initialise(org.apache.qpid.jms.ConnectionURL)
+     */
+    @Override
+    public void initialise(ConnectionURL connectionURL)
     {
-        _protocolSession = protocolSession;
+        _connectionURL = connectionURL;
     }
 
     public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
@@ -53,13 +52,13 @@ public class UsernameHashedPasswordCallb
             Callback cb = callbacks[i];
             if (cb instanceof NameCallback)
             {
-                ((NameCallback) cb).setName(_protocolSession.getUsername());
+                ((NameCallback) cb).setName(_connectionURL.getUsername());
             }
             else if (cb instanceof PasswordCallback)
             {
                 try
                 {
-                    ((PasswordCallback) cb).setPassword(getHash(_protocolSession.getPassword()));
+                    ((PasswordCallback) cb).setPassword(getHash(_connectionURL.getPassword()));
                 }
                 catch (NoSuchAlgorithmException e)
                 {
@@ -99,4 +98,5 @@ public class UsernameHashedPasswordCallb
 
         return hash;
     }
+
 }

Modified: qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandler.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandler.java?rev=1127939&r1=1127938&r2=1127939&view=diff
==============================================================================
--- qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandler.java (original)
+++ qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandler.java Thu May 26 14:27:07 2011
@@ -27,15 +27,19 @@ import javax.security.auth.callback.Name
 import javax.security.auth.callback.PasswordCallback;
 import javax.security.auth.callback.UnsupportedCallbackException;
 
-import org.apache.qpid.client.protocol.AMQProtocolSession;
+import org.apache.qpid.jms.ConnectionURL;
 
 public class UsernamePasswordCallbackHandler implements AMQCallbackHandler
 {
-    private AMQProtocolSession _protocolSession;
+    private ConnectionURL _connectionURL;
 
-    public void initialise(AMQProtocolSession protocolSession)
+    /**
+     * @see org.apache.qpid.client.security.AMQCallbackHandler#initialise(org.apache.qpid.jms.ConnectionURL)
+     */
+    @Override
+    public void initialise(final ConnectionURL connectionURL)
     {
-        _protocolSession = protocolSession;
+        _connectionURL = connectionURL;
     }
 
     public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
@@ -45,11 +49,11 @@ public class UsernamePasswordCallbackHan
             Callback cb = callbacks[i];
             if (cb instanceof NameCallback)
             {
-                ((NameCallback)cb).setName(_protocolSession.getUsername());
+                ((NameCallback)cb).setName(_connectionURL.getUsername());
             }
             else if (cb instanceof PasswordCallback)
             {
-                ((PasswordCallback)cb).setPassword(_protocolSession.getPassword().toCharArray());
+                ((PasswordCallback)cb).setPassword(_connectionURL.getPassword().toCharArray());
             }
             else
             {
@@ -57,4 +61,5 @@ public class UsernamePasswordCallbackHan
             }
         }
     }
+
 }

Modified: qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java?rev=1127939&r1=1127938&r2=1127939&view=diff
==============================================================================
--- qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java (original)
+++ qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/MockAMQConnection.java Thu May 26 14:27:07 2011
@@ -79,11 +79,6 @@ public class MockAMQConnection extends A
         super(connectionURL, sslConfig);
     }
 
-    protected MockAMQConnection(String username, String password, String clientName, String virtualHost)
-    {
-        super(username, password, clientName, virtualHost);
-    }
-
     @Override
     public ProtocolVersion makeBrokerConnection(BrokerDetails brokerDetail) throws IOException
     {

Added: qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandlerTest.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandlerTest.java?rev=1127939&view=auto
==============================================================================
--- qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandlerTest.java (added)
+++ qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandlerTest.java Thu May 26 14:27:07 2011
@@ -0,0 +1,99 @@
+/*
+ *
+ * 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.client.security;
+
+import java.security.MessageDigest;
+import java.util.Arrays;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQConnectionURL;
+import org.apache.qpid.client.MockAMQConnection;
+import org.apache.qpid.client.protocol.AMQProtocolHandler;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+
+/**
+ * Unit tests for the UsernameHashPasswordCallbackHandler.  This callback handler is
+ * used by the CRAM-MD5-HASHED SASL mechanism.
+ *
+ */
+public class UsernameHashedPasswordCallbackHandlerTest extends TestCase
+{
+    private AMQCallbackHandler _callbackHandler = new UsernameHashedPasswordCallbackHandler(); // Class under test
+    private static final String PROMPT_UNUSED = "unused";
+
+    @Override
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+
+        final String url = "amqp://username:password@client/test?brokerlist='vm://:1'";
+        _callbackHandler.initialise(new AMQConnectionURL(url));
+    }
+
+    /**
+     *  Tests that the callback handler can correctly retrieve the username from the connection url.
+     */
+    public void testNameCallback() throws Exception
+    {
+        final String expectedName = "username";
+        NameCallback nameCallback = new NameCallback(PROMPT_UNUSED);
+
+        assertNull("Unexpected name before test", nameCallback.getName());
+        _callbackHandler.handle(new Callback[] {nameCallback});
+        assertEquals("Unexpected name", expectedName, nameCallback.getName());
+    }
+
+    /**
+     *  Tests that the callback handler can correctly retrieve the password from the connection url
+     *  and calculate a MD5.
+     */
+    public void testDigestedPasswordCallback() throws Exception
+    {
+        final char[] expectedPasswordDigested = getHashPassword("password");
+        
+        PasswordCallback passwordCallback = new PasswordCallback(PROMPT_UNUSED, false);
+        assertNull("Unexpected password before test", passwordCallback.getPassword());
+        _callbackHandler.handle(new Callback[] {passwordCallback});
+        assertTrue("Unexpected password", Arrays.equals(expectedPasswordDigested, passwordCallback.getPassword()));
+    }
+
+    private char[] getHashPassword(final String password) throws Exception
+    {
+        MessageDigest md5Digester = MessageDigest.getInstance("MD5");
+        final byte[] digest = md5Digester.digest(password.getBytes("UTF-8"));
+
+        char[] hash = new char[digest.length];
+
+        int index = 0;
+        for (byte b : digest)
+        {
+            hash[index++] = (char) b;
+        }
+
+        return hash;
+    }
+}

Added: qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandlerTest.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandlerTest.java?rev=1127939&view=auto
==============================================================================
--- qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandlerTest.java (added)
+++ qpid/trunk/qpid/java/client/src/test/java/org/apache/qpid/client/security/UsernamePasswordCallbackHandlerTest.java Thu May 26 14:27:07 2011
@@ -0,0 +1,78 @@
+/*
+ *
+ * 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.client.security;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQConnectionURL;
+import org.apache.qpid.client.MockAMQConnection;
+import org.apache.qpid.client.protocol.AMQProtocolHandler;
+import org.apache.qpid.client.protocol.AMQProtocolSession;
+
+/**
+ * Unit tests for the UsernamePasswordCallbackHandler.
+ *
+ */
+public class UsernamePasswordCallbackHandlerTest extends TestCase
+{
+    private AMQCallbackHandler _callbackHandler = new UsernamePasswordCallbackHandler(); // Class under test
+    private static final String PROMPT_UNUSED = "unused";
+
+    @Override
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+
+        final String url = "amqp://username:password@client/test?brokerlist='vm://:1'";
+
+        _callbackHandler.initialise(new AMQConnectionURL(url));
+    }
+
+    /**
+     *  Tests that the callback handler can correctly retrieve the username from the connection url.
+     */
+    public void testNameCallback() throws Exception
+    {
+        final String expectedName = "username";
+        NameCallback nameCallback = new NameCallback(PROMPT_UNUSED);
+
+        assertNull("Unexpected name before test", nameCallback.getName());
+        _callbackHandler.handle(new Callback[] {nameCallback});
+        assertEquals("Unexpected name", expectedName, nameCallback.getName());
+    }
+
+    /**
+     *  Tests that the callback handler can correctly retrieve the password from the connection url.
+     */
+    public void testPasswordCallback() throws Exception
+    {
+        final String expectedPassword = "password";
+        PasswordCallback passwordCallback = new PasswordCallback(PROMPT_UNUSED, false);
+        assertNull("Unexpected password before test", passwordCallback.getPassword());
+        _callbackHandler.handle(new Callback[] {passwordCallback});
+        assertEquals("Unexpected password", expectedPassword, new String(passwordCallback.getPassword()));
+    }    
+}



---------------------------------------------------------------------
Apache Qpid - AMQP Messaging Implementation
Project:      http://qpid.apache.org
Use/Interact: mailto:commits-subscribe@qpid.apache.org