/* * * 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