blob: d8a38750c537e0552bf2ba67199fcb6a51d64cf8 [file]
/*
*
* 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 CharSequence& /*full raw data*/, 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