summaryrefslogtreecommitdiff
path: root/cpp/src/qpid/broker/SaslAuthenticator.cpp
diff options
context:
space:
mode:
authorGordon Sim <gsim@apache.org>2008-04-22 10:33:12 +0000
committerGordon Sim <gsim@apache.org>2008-04-22 10:33:12 +0000
commit2b8e82875776feb8393c7791975acc9cf9fdb5e1 (patch)
tree1dda91e21db631a53fc796ffe6a12190895ba0db /cpp/src/qpid/broker/SaslAuthenticator.cpp
parenta00e277846fb1ad432988e582506c7a4223e7d67 (diff)
downloadqpid-python-2b8e82875776feb8393c7791975acc9cf9fdb5e1.tar.gz
QPID-648: (based on patch from mfarrellee@redhat.com)
* apply authentication to final 0-10 codepath * consolidate conditional compilation of sasl-related code * improved handling of connection close during connection establishment in client git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@650439 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp/src/qpid/broker/SaslAuthenticator.cpp')
-rw-r--r--cpp/src/qpid/broker/SaslAuthenticator.cpp242
1 files changed, 242 insertions, 0 deletions
diff --git a/cpp/src/qpid/broker/SaslAuthenticator.cpp b/cpp/src/qpid/broker/SaslAuthenticator.cpp
new file mode 100644
index 0000000000..9ca4069a12
--- /dev/null
+++ b/cpp/src/qpid/broker/SaslAuthenticator.cpp
@@ -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
+
+}}