summaryrefslogtreecommitdiff
path: root/qpid/cpp/src/qpid/broker/amqp/Sasl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/cpp/src/qpid/broker/amqp/Sasl.cpp')
-rw-r--r--qpid/cpp/src/qpid/broker/amqp/Sasl.cpp167
1 files changed, 167 insertions, 0 deletions
diff --git a/qpid/cpp/src/qpid/broker/amqp/Sasl.cpp b/qpid/cpp/src/qpid/broker/amqp/Sasl.cpp
new file mode 100644
index 0000000000..907e04f5ed
--- /dev/null
+++ b/qpid/cpp/src/qpid/broker/amqp/Sasl.cpp
@@ -0,0 +1,167 @@
+/*
+ *
+ * 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 "qpid/broker/amqp/Sasl.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/log/Statement.h"
+#include "qpid/framing/ProtocolInitiation.h"
+#include "qpid/sys/OutputControl.h"
+#include "qpid/sys/SecurityLayer.h"
+#include <boost/format.hpp>
+#include <vector>
+
+namespace qpid {
+namespace broker {
+namespace amqp {
+
+Sasl::Sasl(qpid::sys::OutputControl& o, const std::string& id, BrokerContext& context, std::auto_ptr<qpid::SaslServer> auth)
+ : qpid::amqp::SaslServer(id), out(o), connection(out, id, context, true, false),
+ authenticator(auth),
+ state(INCOMPLETE), writeHeader(true), haveOutput(true)
+{
+ out.activateOutput();
+ mechanisms(authenticator->getMechanisms());
+}
+
+Sasl::~Sasl() {}
+
+size_t Sasl::decode(const char* buffer, size_t size)
+{
+ if (state == AUTHENTICATED) {
+ if (securityLayer.get()) return securityLayer->decode(buffer, size);
+ else return connection.decode(buffer, size);
+ } else if (state == INCOMPLETE && size) {
+ size_t decoded = read(buffer, size);
+ QPID_LOG(trace, id << " Sasl::decode(" << size << "): " << decoded);
+ return decoded;
+ } else {
+ return 0;
+ }
+}
+
+size_t Sasl::encode(char* buffer, size_t size)
+{
+ if (state == AUTHENTICATED) {
+ if (securityLayer.get()) return securityLayer->encode(buffer, size);
+ else return connection.encode(buffer, size);
+ } else {
+ size_t encoded = 0;
+ if (writeHeader) {
+ encoded += writeProtocolHeader(buffer, size);
+ if (!encoded) return 0;
+ writeHeader = false;
+ }
+ if (encoded < size) {
+ encoded += write(buffer + encoded, size - encoded);
+ }
+ if (state == SUCCESS_PENDING) {
+ state = AUTHENTICATED;
+ } else if (state == FAILURE_PENDING) {
+ state = FAILED;
+ } else {
+ haveOutput = (encoded == size);
+ }
+ QPID_LOG(trace, id << " Sasl::encode(" << size << "): " << encoded);
+ return encoded;
+ }
+}
+
+bool Sasl::canEncode()
+{
+ if (state == AUTHENTICATED) {
+ if (securityLayer.get()) return securityLayer->canEncode();
+ else return connection.canEncode();
+ } else {
+ return haveOutput;
+ }
+}
+
+void Sasl::closed()
+{
+ if (state == AUTHENTICATED) {
+ connection.closed();
+ } else {
+ QPID_LOG(info, id << " Connection closed prior to authentication completing");
+ state = FAILED;
+ }
+}
+bool Sasl::isClosed() const
+{
+ if (state == AUTHENTICATED) {
+ return connection.isClosed();
+ } else {
+ return state == FAILED;
+ }
+}
+
+framing::ProtocolVersion Sasl::getVersion() const
+{
+ return connection.getVersion();
+}
+namespace {
+const std::string EMPTY;
+}
+
+void Sasl::init(const std::string& mechanism, const std::string* response, const std::string* /*hostname*/)
+{
+ QPID_LOG_CAT(debug, protocol, id << " Received SASL-INIT(" << mechanism << ", " << (response ? *response : EMPTY) << ")");
+ //TODO: what should we do with hostname here?
+ std::string c;
+ respond(authenticator->start(mechanism, response, c), c);
+ connection.setSaslMechanism(mechanism);
+}
+
+void Sasl::response(const std::string* r)
+{
+ QPID_LOG_CAT(debug, protocol, id << " Received SASL-RESPONSE(" << (r ? *r : EMPTY) << ")");
+ std::string c;
+ respond(authenticator->step(r, c), c);
+}
+
+void Sasl::respond(qpid::SaslServer::Status status, const std::string& chllnge)
+{
+ switch (status) {
+ case qpid::SaslServer::OK:
+ connection.setUserId(authenticator->getUserid());
+ completed(true);
+ //can't set authenticated & failed until we have actually sent the outcome
+ state = SUCCESS_PENDING;
+ securityLayer = authenticator->getSecurityLayer(65535);
+ if (securityLayer.get()) {
+ QPID_LOG_CAT(info, security, id << " Security layer installed");
+ securityLayer->init(&connection);
+ connection.setSaslSsf(securityLayer->getSsf());
+ }
+ QPID_LOG_CAT(info, security, id << " Authenticated as " << authenticator->getUserid());
+ break;
+ case qpid::SaslServer::FAIL:
+ completed(false);
+ state = FAILURE_PENDING;
+ QPID_LOG_CAT(info, security, id << " Failed to authenticate");
+ break;
+ case qpid::SaslServer::CHALLENGE:
+ challenge(&chllnge);
+ QPID_LOG_CAT(info, security, id << " Challenge issued");
+ break;
+ }
+ haveOutput = true;
+ out.activateOutput();
+}
+}}} // namespace qpid::broker::amqp