Author: gsim
Date: Tue Apr 22 03:33:12 2008
New Revision: 650439

URL: http://svn.apache.org/viewvc?rev=650439&view=rev
Log:
QPID-648: (based on patch from [EMAIL PROTECTED]) 

* apply authentication to final 0-10 codepath
* consolidate conditional compilation of sasl-related code
* improved handling of connection close during connection establishment in 
client


Added:
    incubator/qpid/trunk/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp   (with 
props)
    incubator/qpid/trunk/qpid/cpp/src/qpid/broker/SaslAuthenticator.h   (with 
props)
Modified:
    incubator/qpid/trunk/qpid/cpp/src/Makefile.am
    incubator/qpid/trunk/qpid/cpp/src/qpid/broker/Broker.cpp
    incubator/qpid/trunk/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp
    incubator/qpid/trunk/qpid/cpp/src/qpid/broker/ConnectionHandler.h
    incubator/qpid/trunk/qpid/cpp/src/qpid/client/ConnectionHandler.cpp
    incubator/qpid/trunk/qpid/cpp/src/qpid/client/ConnectionHandler.h

Modified: incubator/qpid/trunk/qpid/cpp/src/Makefile.am
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/Makefile.am?rev=650439&r1=650438&r2=650439&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/Makefile.am (original)
+++ incubator/qpid/trunk/qpid/cpp/src/Makefile.am Tue Apr 22 03:33:12 2008
@@ -238,6 +238,7 @@
   qpid/broker/RecoveryManagerImpl.cpp \
   qpid/broker/RecoveredEnqueue.cpp \
   qpid/broker/RecoveredDequeue.cpp \
+  qpid/broker/SaslAuthenticator.cpp \
   qpid/broker/SemanticState.h \
   qpid/broker/SemanticState.cpp \
   qpid/broker/SessionState.h \
@@ -372,6 +373,7 @@
   qpid/broker/RecoveryManager.h \
   qpid/broker/RecoveryManagerImpl.h \
   qpid/broker/SemanticHandler.h \
+  qpid/broker/SaslAuthenticator.h \
   qpid/broker/SessionManager.h \
   qpid/broker/System.h \
   qpid/broker/Timer.h \

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/broker/Broker.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/broker/Broker.cpp?rev=650439&r1=650438&r2=650439&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/broker/Broker.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/broker/Broker.cpp Tue Apr 22 
03:33:12 2008
@@ -21,7 +21,6 @@
 
 #include "config.h"
 #include "Broker.h"
-#include "Connection.h"
 #include "DirectExchange.h"
 #include "FanOutExchange.h"
 #include "HeadersExchange.h"

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp?rev=650439&r1=650438&r2=650439&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp 
(original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp Tue Apr 
22 03:33:12 2008
@@ -20,6 +20,8 @@
  *
  */
 
+#include "config.h"
+
 #include "ConnectionHandler.h"
 #include "Connection.h"
 #include "qpid/framing/ClientInvoker.h"
@@ -63,42 +65,41 @@
     }
 }
 
-ConnectionHandler::ConnectionHandler(Connection& connection)  : handler(new 
Handler(connection)) {
+ConnectionHandler::ConnectionHandler(Connection& connection)  : handler(new 
Handler(connection)) {}
+
+ConnectionHandler::Handler::Handler(Connection& c) :
+    client(c.getOutput()), server(c.getOutput()), 
+    connection(c), serverMode(false)
+{
     FieldTable properties;
     Array mechanisms(0x95);
-    boost::shared_ptr<FieldValue> m(new Str16Value(PLAIN));
-    mechanisms.add(m);
+
+    authenticator = SaslAuthenticator::createAuthenticator(c);
+    authenticator->getMechanisms(mechanisms);
+
     Array locales(0x95);
     boost::shared_ptr<FieldValue> l(new Str16Value(en_US));
     locales.add(l);
-    handler->serverMode = true;
-    handler->client.start(properties, mechanisms, locales);
+    serverMode = true;
+    client.start(properties, mechanisms, locales);
 }
 
 
+ConnectionHandler::Handler::~Handler() {}
 
-ConnectionHandler::Handler:: Handler(Connection& c) : client(c.getOutput()), 
server(c.getOutput()), 
-                                                      connection(c), 
serverMode(false) {}
 
 void ConnectionHandler::Handler::startOk(const framing::FieldTable& 
/*clientProperties*/,
-    const string& mechanism, 
-    const string& response, const string& /*locale*/)
+                                         const string& mechanism, 
+                                         const string& response,
+                                         const string& /*locale*/)
 {
-    //TODO: handle SASL mechanisms more cleverly
-    if (mechanism == PLAIN) {
-        if (response.size() > 0 && response[0] == (char) 0) {
-            string temp = response.substr(1);
-            string::size_type i = temp.find((char)0);
-            string uid = temp.substr(0, i);
-            string pwd = temp.substr(i + 1);
-            //TODO: authentication
-            connection.setUserId(uid);
-        }
-    }
-    client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), 0, 0);
+    authenticator->start(mechanism, response);
 }
         
-void ConnectionHandler::Handler::secureOk(const string& /*response*/){}
+void ConnectionHandler::Handler::secureOk(const string& response)
+{
+    authenticator->step(response);
+}
         
 void ConnectionHandler::Handler::tuneOk(uint16_t /*channelmax*/,
     uint16_t framemax, uint16_t heartbeat)

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/broker/ConnectionHandler.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/broker/ConnectionHandler.h?rev=650439&r1=650438&r2=650439&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/broker/ConnectionHandler.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/broker/ConnectionHandler.h Tue Apr 
22 03:33:12 2008
@@ -22,6 +22,7 @@
 #define _ConnectionAdapter_
 
 #include <memory>
+#include "SaslAuthenticator.h"
 #include "qpid/framing/amqp_types.h"
 #include "qpid/framing/AMQFrame.h"
 #include "qpid/framing/AMQP_ClientOperations.h"
@@ -47,8 +48,10 @@
         framing::AMQP_ServerProxy::Connection010 server;
         Connection& connection;
         bool serverMode;
+        std::auto_ptr<SaslAuthenticator> authenticator;
     
         Handler(Connection& connection);
+        ~Handler();
         void startOk(const qpid::framing::FieldTable& clientProperties,
                      const std::string& mechanism, const std::string& response,
                      const std::string& locale); 

Added: incubator/qpid/trunk/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp?rev=650439&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp (added)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp Tue Apr 
22 03:33:12 2008
@@ -0,0 +1,242 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "config.h"
+
+#include "Connection.h"
+#include "qpid/log/Statement.h"
+
+#if HAVE_SASL
+#include <sasl/sasl.h>
+#endif
+
+using namespace qpid::framing;
+
+namespace qpid {
+namespace broker {
+
+
+class NullAuthenticator : public SaslAuthenticator
+{
+    Connection& connection;
+    framing::AMQP_ClientProxy::Connection010 client;
+public:
+    NullAuthenticator(Connection& connection);
+    ~NullAuthenticator();
+    void getMechanisms(framing::Array& mechanisms);
+    void start(const std::string& mechanism, const std::string& response);
+    void step(const std::string&) {}
+};
+
+#if HAVE_SASL
+
+class CyrusAuthenticator : public SaslAuthenticator
+{
+    sasl_conn_t *sasl_conn;
+    Connection& connection;
+    framing::AMQP_ClientProxy::Connection010 client;
+
+    void processAuthenticationStep(int code, const char *challenge, unsigned 
int challenge_len);
+
+public:
+    CyrusAuthenticator(Connection& connection);
+    ~CyrusAuthenticator();
+    void init();
+    void getMechanisms(framing::Array& mechanisms);
+    void start(const std::string& mechanism, const std::string& response);
+    void step(const std::string& response);
+};
+
+#else
+
+typedef NullAuthenticator CyrusAuthenticator;
+
+#endif
+
+std::auto_ptr<SaslAuthenticator> 
SaslAuthenticator::createAuthenticator(Connection& c)
+{
+    if (c.getBroker().getOptions().auth) {
+        return std::auto_ptr<SaslAuthenticator>(new CyrusAuthenticator(c));
+    } else {
+        return std::auto_ptr<SaslAuthenticator>(new NullAuthenticator(c));
+    }
+}
+
+NullAuthenticator::NullAuthenticator(Connection& c) : connection(c), 
client(c.getOutput()) {}
+NullAuthenticator::~NullAuthenticator() {}
+
+void NullAuthenticator::getMechanisms(Array& mechanisms)
+{
+    mechanisms.add(boost::shared_ptr<FieldValue>(new Str16Value("ANONYMOUS")));
+}
+
+void NullAuthenticator::start(const string& /*mechanism*/, const string& 
/*response*/)
+{
+    QPID_LOG(warning, "SASL: No Authentication Performed");
+    
+    // TODO: Figure out what should actually be set in this case
+    connection.setUserId("anonymous");
+    
+    client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), 0, 0);
+}
+
+
+#if HAVE_SASL
+
+CyrusAuthenticator::CyrusAuthenticator(Connection& c) : sasl_conn(0), 
connection(c), client(c.getOutput()) 
+{
+    init();
+}
+
+void CyrusAuthenticator::init()
+{
+    int code = sasl_server_new(BROKER_SASL_NAME,
+                               NULL, NULL, NULL, NULL, NULL, 0,
+                               &sasl_conn);
+    
+    if (SASL_OK != code) {
+        QPID_LOG(info, "SASL: Connection creation failed: [" << code << "] " 
<< sasl_errdetail(sasl_conn));
+        
+        // TODO: Change this to an exception signaling
+        // server error, when one is available
+        throw CommandInvalidException("Unable to perform authentication");
+    }
+}
+
+CyrusAuthenticator::~CyrusAuthenticator()
+{
+    if (sasl_conn) {
+        sasl_dispose(&sasl_conn);
+        sasl_conn = 0;
+    }
+}
+
+void CyrusAuthenticator::getMechanisms(Array& mechanisms)
+{
+    const char *separator = " ";
+    const char *list;
+    unsigned int list_len;
+    int count;
+
+    int code = sasl_listmech(sasl_conn, NULL,
+                             "", separator, "",
+                             &list, &list_len,
+                             &count);
+    
+    if (SASL_OK != code) {
+        QPID_LOG(info, "SASL: Mechanism listing failed: " << 
sasl_errdetail(sasl_conn));
+        
+        // TODO: Change this to an exception signaling
+        // server error, when one is available
+        throw CommandInvalidException("Mechanism listing failed");
+    } else {
+        string mechanism;
+        unsigned int start;
+        unsigned int end;
+        
+        QPID_LOG(info, "SASL: Mechanism list: " << list);
+        
+        end = 0;
+        do {
+            start = end;
+            
+            // Seek to end of next mechanism
+            while (end < list_len && separator[0] != list[end])
+                end++;
+            
+            // Record the mechanism
+            mechanisms.add(boost::shared_ptr<FieldValue>(new 
Str16Value(string(list, start, end - start))));
+            end++;
+        } while (end < list_len);
+    }
+}
+
+void CyrusAuthenticator::start(const string& mechanism, const string& response)
+{
+    const char *challenge;
+    unsigned int challenge_len;
+    
+    QPID_LOG(info, "SASL: Starting authentication with mechanism: " << 
mechanism);
+    int code = sasl_server_start(sasl_conn,
+                                 mechanism.c_str(),
+                                 response.c_str(), response.length(),
+                                 &challenge, &challenge_len);
+    
+    processAuthenticationStep(code, challenge, challenge_len);
+}
+        
+void CyrusAuthenticator::step(const string& response)
+{
+    const char *challenge;
+    unsigned int challenge_len;
+
+    int code = sasl_server_step(sasl_conn,
+                            response.c_str(), response.length(),
+                            &challenge, &challenge_len);
+
+    processAuthenticationStep(code, challenge, challenge_len);
+}
+
+void CyrusAuthenticator::processAuthenticationStep(int code, const char 
*challenge, unsigned int challenge_len)
+{
+    if (SASL_OK == code) {
+        const void *uid;
+
+        code = sasl_getprop(sasl_conn, SASL_USERNAME, &uid);
+        if (SASL_OK != code) {
+            QPID_LOG(info, "SASL: Authentication succeeded, username 
unavailable");
+            // TODO: Change this to an exception signaling
+            // authentication failure, when one is available
+            throw ConnectionForcedException("Authenticated username 
unavailable");
+        }
+
+        QPID_LOG(info, "SASL: Authentication succeeded for: " << (char *)uid);
+
+        connection.setUserId((char *)uid);
+
+        client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), 0, 0);
+    } else if (SASL_CONTINUE == code) {
+        string challenge_str(challenge, challenge_len);
+
+        QPID_LOG(debug, "SASL: sending challenge to client");
+
+        client.secure(challenge_str);
+    } else {
+        QPID_LOG(info, "SASL: Authentication failed: " << 
sasl_errdetail(sasl_conn));
+
+        // TODO: Change to more specific exceptions, when they are
+        // available
+        switch (code) {
+        case SASL_NOMECH:
+            throw ConnectionForcedException("Unsupported mechanism");
+            break;
+        case SASL_TRYAGAIN:
+            throw ConnectionForcedException("Transient failure, try again");
+            break;
+        default:
+            throw ConnectionForcedException("Authentication failed");
+            break;
+        }
+    }
+}
+#endif
+
+}}

Propchange: incubator/qpid/trunk/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/qpid/trunk/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: incubator/qpid/trunk/qpid/cpp/src/qpid/broker/SaslAuthenticator.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/broker/SaslAuthenticator.h?rev=650439&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/broker/SaslAuthenticator.h (added)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/broker/SaslAuthenticator.h Tue Apr 
22 03:33:12 2008
@@ -0,0 +1,47 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _SaslAuthenticator_
+#define _SaslAuthenticator_
+
+#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/AMQP_ClientProxy.h"
+#include "qpid/Exception.h"
+#include <memory>
+
+namespace qpid {
+namespace broker {
+
+class Connection;
+
+class SaslAuthenticator
+{
+public:
+    virtual ~SaslAuthenticator() {}
+    virtual void getMechanisms(framing::Array& mechanisms) = 0;
+    virtual void start(const std::string& mechanism, const std::string& 
response) = 0;
+    virtual void step(const std::string& response) = 0;
+
+    static std::auto_ptr<SaslAuthenticator> createAuthenticator(Connection& 
connection);
+};
+
+}}
+
+#endif

Propchange: incubator/qpid/trunk/qpid/cpp/src/qpid/broker/SaslAuthenticator.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/qpid/trunk/qpid/cpp/src/qpid/broker/SaslAuthenticator.h
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/client/ConnectionHandler.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/client/ConnectionHandler.cpp?rev=650439&r1=650438&r2=650439&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/client/ConnectionHandler.cpp 
(original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/client/ConnectionHandler.cpp Tue Apr 
22 03:33:12 2008
@@ -42,7 +42,7 @@
 }
 
 ConnectionHandler::ConnectionHandler() 
-    : StateManager(NOT_STARTED), outHandler(*this), proxy(outHandler) 
+    : StateManager(NOT_STARTED), outHandler(*this), proxy(outHandler), 
errorCode(200)
 {
 
     mechanism = PLAIN;
@@ -54,6 +54,7 @@
     version = framing::highestProtocolVersion;
 
     ESTABLISHED.insert(FAILED);
+    ESTABLISHED.insert(CLOSED);
     ESTABLISHED.insert(OPEN);
 } 
 
@@ -98,8 +99,8 @@
 void ConnectionHandler::waitForOpen()
 {
     waitFor(ESTABLISHED);
-    if (getState() == FAILED) {
-        throw Exception("Failed to establish connection.");
+    if (getState() == FAILED || getState() == CLOSED) {
+        throw ConnectionException(errorCode, errorText);
     }
 }
 
@@ -108,7 +109,7 @@
     switch (getState()) {
       case NEGOTIATING:
       case OPENING:
-        setState(FAILED);
+        fail("Connection closed before it was established");
         break;
       case OPEN:
         setState(CLOSING);
@@ -128,6 +129,8 @@
 
 void ConnectionHandler::fail(const std::string& message)
 {
+    errorCode = 502;
+    errorText = message;
     QPID_LOG(warning, message);
     setState(FAILED);
 }
@@ -172,6 +175,8 @@
 {
     proxy.closeOk();
     setState(CLOSED);
+    errorCode = replyCode;
+    errorText = replyText;
     QPID_LOG(warning, "Broker closed connection: " << replyCode << ", " << 
replyText);
     if (onError) {
         onError(replyCode, replyText);

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/client/ConnectionHandler.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/client/ConnectionHandler.h?rev=650439&r1=650438&r2=650439&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/client/ConnectionHandler.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/client/ConnectionHandler.h Tue Apr 
22 03:33:12 2008
@@ -70,7 +70,9 @@
     }; 
 
     Adapter outHandler;
-    framing::AMQP_ServerProxy::Connection010 proxy;    
+    framing::AMQP_ServerProxy::Connection010 proxy;
+    uint16_t errorCode;
+    std::string errorText;
 
     void checkState(STATES s, const std::string& msg);
 


Reply via email to