summaryrefslogtreecommitdiff
path: root/cpp/src/qpid/amqp/SaslClient.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/qpid/amqp/SaslClient.cpp')
-rw-r--r--cpp/src/qpid/amqp/SaslClient.cpp154
1 files changed, 154 insertions, 0 deletions
diff --git a/cpp/src/qpid/amqp/SaslClient.cpp b/cpp/src/qpid/amqp/SaslClient.cpp
new file mode 100644
index 0000000000..69660e9294
--- /dev/null
+++ b/cpp/src/qpid/amqp/SaslClient.cpp
@@ -0,0 +1,154 @@
+/*
+ *
+ * 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/SaslClient.h"
+#include "qpid/amqp/Decoder.h"
+#include "qpid/amqp/Descriptor.h"
+#include "qpid/amqp/descriptors.h"
+#include "qpid/amqp/Encoder.h"
+#include "qpid/log/Statement.h"
+
+using namespace qpid::amqp::sasl;
+
+namespace qpid {
+namespace amqp {
+
+SaslClient::SaslClient(const std::string& id) : Sasl(id) {}
+SaslClient::~SaslClient() {}
+void SaslClient::init(const std::string& mechanism, const std::string* response, const std::string* hostname)
+{
+ void* frame = startFrame();
+
+ void* token = encoder.startList32(&SASL_INIT);
+ encoder.writeSymbol(mechanism);
+ if (response) encoder.writeBinary(*response);
+ else encoder.writeNull();
+ if (hostname) encoder.writeString(*hostname);
+ else encoder.writeNull();
+ encoder.endList32(3, token);
+
+ endFrame(frame);
+ QPID_LOG_CAT(debug, protocol, id << " Sent SASL-INIT(" << mechanism << ", " << (response ? *response : "null") << ", " << (hostname ? *hostname : "null") << ")");
+}
+void SaslClient::response(const std::string* r)
+{
+ void* frame = startFrame();
+
+ void* token = encoder.startList32(&SASL_RESPONSE);
+ if (r) encoder.writeBinary(*r);
+ else encoder.writeNull();
+ encoder.endList32(1, token);
+
+ endFrame(frame);
+ QPID_LOG_CAT(debug, protocol, id << " Sent SASL-RESPONSE(" << (r ? *r : "null") << ")");
+}
+
+
+namespace {
+const std::string SPACE(" ");
+class SaslMechanismsReader : public Reader
+{
+ public:
+ SaslMechanismsReader(SaslClient& c) : client(c), expected(0) {}
+ void onSymbol(const CharSequence& mechanism, const Descriptor*)
+ {
+ if (expected) {
+ mechanisms << mechanism.str() << SPACE;
+ } else {
+ client.mechanisms(mechanism.str());
+ }
+ }
+ bool onStartArray(uint32_t count, const CharSequence&, const Constructor&, const Descriptor*)
+ {
+ expected = count;
+ return true;
+ }
+ void onEndArray(uint32_t, const Descriptor*)
+ {
+ client.mechanisms(mechanisms.str());
+ }
+ private:
+ SaslClient& client;
+ uint32_t expected;
+ std::stringstream mechanisms;
+};
+class SaslChallengeReader : public Reader
+{
+ public:
+ SaslChallengeReader(SaslClient& c) : client(c) {}
+ void onNull(const Descriptor*) { client.challenge(); }
+ void onBinary(const CharSequence& c, const Descriptor*) { client.challenge(c.str()); }
+ private:
+ SaslClient& client;
+};
+class SaslOutcomeReader : public Reader
+{
+ public:
+ SaslOutcomeReader(SaslClient& c, bool e) : client(c), expectExtraData(e) {}
+ void onUByte(uint8_t c, const Descriptor*)
+ {
+ if (expectExtraData) code = c;
+ else client.outcome(c);
+ }
+ void onBinary(const CharSequence& extra, const Descriptor*) { client.outcome(code, extra.str()); }
+ void onNull(const Descriptor*) { client.outcome(code); }
+ private:
+ SaslClient& client;
+ bool expectExtraData;
+ uint8_t code;
+};
+}
+
+bool SaslClient::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_MECHANISMS_SYMBOL, SASL_MECHANISMS_CODE)) {
+ QPID_LOG(trace, "Reading SASL-MECHANISMS");
+ Decoder decoder(arguments.data, arguments.size);
+ if (count != 1) QPID_LOG(error, "Invalid SASL-MECHANISMS frame; exactly one field expected, got " << count);
+ SaslMechanismsReader reader(*this);
+ decoder.read(reader);
+ } else if (descriptor->match(SASL_CHALLENGE_SYMBOL, SASL_CHALLENGE_CODE)) {
+ QPID_LOG(trace, "Reading SASL-CHALLENGE");
+ Decoder decoder(arguments.data, arguments.size);
+ if (count != 1) QPID_LOG(error, "Invalid SASL-CHALLENGE frame; exactly one field expected, got " << count);
+ SaslChallengeReader reader(*this);
+ decoder.read(reader);
+ } else if (descriptor->match(SASL_OUTCOME_SYMBOL, SASL_OUTCOME_CODE)) {
+ QPID_LOG(trace, "Reading SASL-OUTCOME");
+ Decoder decoder(arguments.data, arguments.size);
+ if (count == 1) {
+ SaslOutcomeReader reader(*this, false);
+ decoder.read(reader);
+ } else if (count == 2) {
+ SaslOutcomeReader reader(*this, true);
+ decoder.read(reader);
+ } else {
+ QPID_LOG(error, "Invalid SASL-OUTCOME frame; got " << count << " fields");
+ }
+ } else {
+ QPID_LOG(error, "Unexpected descriptor in SASL negotiation: " << *descriptor);
+ }
+ return false;
+}
+
+
+}} // namespace qpid::amqp