diff options
Diffstat (limited to 'cpp/src/qpid/amqp/SaslClient.cpp')
-rw-r--r-- | cpp/src/qpid/amqp/SaslClient.cpp | 154 |
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 |