summaryrefslogtreecommitdiff
path: root/cpp/src/qpid/amqp/SaslServer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/qpid/amqp/SaslServer.cpp')
-rw-r--r--cpp/src/qpid/amqp/SaslServer.cpp183
1 files changed, 183 insertions, 0 deletions
diff --git a/cpp/src/qpid/amqp/SaslServer.cpp b/cpp/src/qpid/amqp/SaslServer.cpp
new file mode 100644
index 0000000000..403730ad69
--- /dev/null
+++ b/cpp/src/qpid/amqp/SaslServer.cpp
@@ -0,0 +1,183 @@
+/*
+ *
+ * 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/amqp/SaslServer.h"
+#include "qpid/amqp/Constructor.h"
+#include "qpid/amqp/Decoder.h"
+#include "qpid/amqp/Descriptor.h"
+#include "qpid/amqp/descriptors.h"
+#include "qpid/amqp/Encoder.h"
+#include "qpid/amqp/typecodes.h"
+#include "qpid/log/Statement.h"
+#include "qpid/StringUtils.h"
+#include <limits>
+#include <vector>
+
+using namespace qpid::amqp::sasl;
+using namespace qpid::amqp::typecodes;
+
+namespace qpid {
+namespace amqp {
+namespace {
+const std::string SPACE(" ");
+const std::string NULL_("NULL");
+}
+
+SaslServer::SaslServer(const std::string& id) : Sasl(id) {}
+SaslServer::~SaslServer() {}
+
+void SaslServer::mechanisms(const std::string& mechanisms)
+{
+ void* frameToken = startFrame();
+
+ std::vector<std::string> parts = split(mechanisms, SPACE);
+ void* listToken = encoder.startList32(&SASL_MECHANISMS);
+ if (parts.size() > 1) {
+ void* arrayToken = encoder.startArray8(Constructor(SYMBOL8));
+ for (std::vector<std::string>::const_iterator i = parts.begin();i != parts.end(); ++i) {
+ uint8_t size = i->size() > std::numeric_limits<uint8_t>::max() ? std::numeric_limits<uint8_t>::max() : i->size();
+ encoder.write(size);
+ encoder.writeBytes(i->data(), size);
+ }
+ encoder.endArray8(parts.size(), arrayToken);
+ } else {
+ encoder.writeSymbol(mechanisms);
+ }
+ encoder.endList32(1, listToken);
+
+ endFrame(frameToken);
+ QPID_LOG_CAT(debug, protocol, id << " Sent SASL-MECHANISMS(" << mechanisms << ") " << encoder.getPosition());
+}
+void SaslServer::challenge(const std::string* c)
+{
+ void* frameToken = startFrame();
+
+ void* listToken = encoder.startList32(&SASL_CHALLENGE);
+ if (c) encoder.writeBinary(*c);
+ else encoder.writeNull();
+ encoder.endList32(1, listToken);
+
+ endFrame(frameToken);
+ QPID_LOG_CAT(debug, protocol, id << " Sent SASL-CHALLENGE(" << (c ? *c : NULL_) << ") " << encoder.getPosition());
+}
+void SaslServer::completed(bool succeeded)
+{
+ void* frameToken = startFrame();
+
+ void* listToken = encoder.startList8(&SASL_OUTCOME);
+ encoder.writeUByte(succeeded ? 0 : 1);
+ encoder.endList8(1, listToken);
+
+ endFrame(frameToken);
+ QPID_LOG_CAT(debug, protocol, id << " Sent SASL-OUTCOME(" << (succeeded ? 0 : 1) << ") " << encoder.getPosition());
+}
+
+namespace {
+class SaslInitReader : public Reader
+{
+ public:
+ SaslInitReader(SaslServer& s, uint32_t e) : server(s), expected(e), hasResponse(false), index(0) {}
+ void onNull(const Descriptor*)
+ {
+ ++index;
+ if (index == 2) {
+ if (--expected == 0) {
+ server.init(mechanism, 0, 0);
+ }
+ } else if (index == 3) {
+ server.init(mechanism, hasResponse ? &response : 0, 0);
+ } else {
+ QPID_LOG(warning, "Unexpected sequence of fields for SASL-INIT: got null for field " << index);
+ }
+ }
+ void onBinary(const CharSequence& r, const Descriptor*)
+ {
+ if (++index != 2) QPID_LOG(warning, "Unexpected sequence of fields for SASL-INIT: got binary for field " << index);
+ response = r.str();
+ hasResponse = true;
+ if (--expected == 0) {
+ server.init(mechanism, &response, 0);
+ }
+ }
+ void onString(const CharSequence& h, const Descriptor*)
+ {
+ if (--expected || ++index != 3) {
+ QPID_LOG(warning, "Unexpected sequence of fields for SASL-INIT: got string for field " << index);
+ } else {
+ std::string hostname = h.str();
+ server.init(mechanism, hasResponse ? &response : 0, &hostname);
+ }
+ }
+ void onSymbol(const CharSequence& m, const Descriptor*)
+ {
+ if (++index != 1) QPID_LOG(warning, "Unexpected sequence of fields for SASL-INIT: got symbol for field " << index);
+ if (--expected) {
+ mechanism = m.str();
+ } else {
+ server.init(m.str(), 0, 0);
+ }
+ }
+ private:
+ SaslServer& server;
+ uint32_t expected;
+ std::string mechanism;
+ std::string response;
+ bool hasResponse;
+ uint32_t index;
+};
+
+class SaslResponseReader : public Reader
+{
+ public:
+ SaslResponseReader(SaslServer& s) : server(s) {}
+ void onNull(const Descriptor*) { server.response(0); }
+ void onBinary(const CharSequence& r, const Descriptor*)
+ {
+ std::string s = r.str();
+ server.response(&s);
+ }
+ private:
+ SaslServer& server;
+};
+}
+
+bool SaslServer::onStartList(uint32_t count, const CharSequence& arguments, const Descriptor* descriptor)
+{
+ if (!descriptor) {
+ QPID_LOG(error, "Expected described type in SASL negotiation but got no descriptor");
+ } else if (descriptor->match(SASL_INIT_SYMBOL, SASL_INIT_CODE)) {
+ QPID_LOG(trace, "Reading SASL-INIT");
+ Decoder decoder(arguments.data, arguments.size);
+ if (count < 1 || count > 3) QPID_LOG(error, "Invalid SASL-INIT frame; got " << count << " fields");
+ SaslInitReader reader(*this, count);
+ decoder.read(reader);
+ } else if (descriptor->match(SASL_RESPONSE_SYMBOL, SASL_RESPONSE_CODE)) {
+ QPID_LOG(trace, "Reading SASL-RESPONSE (" << std::string(arguments.data, arguments.size) << ") " << count << " elements");
+ Decoder decoder(arguments.data, arguments.size);
+ if (count != 1) QPID_LOG(error, "Invalid SASL-RESPONSE frame; exactly one field expected, got " << count);
+ SaslResponseReader reader(*this);
+ decoder.read(reader);
+ } else {
+ QPID_LOG(error, "Unexpected descriptor in SASL negotiation: " << *descriptor);
+ }
+ return false;
+}
+
+}} // namespace qpid::amqp