in src/qpid/management/ManagementAgent.cpp [2144:2297]
bool ManagementAgent::authorizeAgentMessage(Message& msg)
{
sys::Mutex::ScopedLock lock(userLock);
ResizableBuffer inBuffer (qmfV1BufferSize);
uint32_t sequence = 0;
bool methodReq = false;
bool mapMsg = false;
string packageName;
string className;
string methodName;
string cid;
boost::intrusive_ptr<const qpid::broker::amqp_0_10::MessageTransfer> transfer = protocols->translate(msg);
//
// If the message is larger than our working buffer size (or if it
// could not be converted to an 0-10 messgae-transfer), we can't
// determine if it's authorized or not. In this case, return true
// (authorized) if there is no ACL in place, otherwise return
// false;
//
if (!transfer || transfer->getContentSize() > qmfV1BufferSize)
return broker->getAcl() == 0;
inBuffer.putRawData(transfer->getContent());
uint32_t bufferLen = inBuffer.getPosition();
inBuffer.reset();
const framing::MessageProperties* p =
transfer ? transfer->getFrames().getHeaders()->get<framing::MessageProperties>() : 0;
const framing::FieldTable *headers = p ? &p->getApplicationHeaders() : 0;
if (headers && p->getAppId() == "qmf2")
{
mapMsg = true;
if (p && p->hasCorrelationId()) {
cid = p->getCorrelationId();
}
if (headers->getAsString("qmf.opcode") == "_method_request")
{
methodReq = true;
// extract object id and method name
string body;
inBuffer.getRawData(body, bufferLen);
Variant::Map inMap;
MapCodec::decode(body, inMap);
Variant::Map::const_iterator oid, mid;
ObjectId objId;
if ((oid = inMap.find("_object_id")) == inMap.end() ||
(mid = inMap.find("_method_name")) == inMap.end()) {
QPID_LOG(warning,
"Missing fields in QMF authorize req received.");
return false;
}
try {
// coversions will throw if input is invalid.
objId = ObjectId(oid->second.asMap());
methodName = mid->second.getString();
} catch(exception& /*e*/) {
QPID_LOG(warning,
"Badly formatted QMF authorize req received.");
return false;
}
// look up schema for object to get package and class name
sys::Mutex::ScopedLock lock(objectLock);
ManagementObjectMap::iterator iter = managementObjects.find(objId);
if (iter == managementObjects.end() || iter->second->isDeleted()) {
QPID_LOG(debug, "ManagementAgent::authorizeAgentMessage: stale object id " <<
objId);
return false;
}
packageName = iter->second->getPackageName();
className = iter->second->getClassName();
}
} else { // old style binary message format
uint8_t opcode;
if (!checkHeader(inBuffer, &opcode, &sequence))
return false;
if (opcode == 'M') {
methodReq = true;
// extract method name & schema package and class name
uint8_t hash[16];
inBuffer.getLongLong(); // skip over object id
inBuffer.getLongLong();
inBuffer.getShortString(packageName);
inBuffer.getShortString(className);
inBuffer.getBin128(hash);
inBuffer.getShortString(methodName);
}
}
if (methodReq) {
map<acl::Property, string> params;
AclModule* acl = broker->getAcl();
if (acl == 0)
return true;
string userId = msg.getUserId();
params[acl::PROP_SCHEMAPACKAGE] = packageName;
params[acl::PROP_SCHEMACLASS] = className;
if (acl->authorise(userId, acl::ACT_ACCESS, acl::OBJ_METHOD, methodName, ¶ms))
return true;
// authorization failed, send reply if replyTo present
boost::intrusive_ptr<const qpid::broker::amqp_0_10::MessageTransfer> transfer = protocols->translate(msg);
const framing::MessageProperties* p =
transfer ? transfer->getFrames().getHeaders()->get<framing::MessageProperties>() : 0;
if (p && p->hasReplyTo()) {
const framing::ReplyTo& rt = p->getReplyTo();
string rte = rt.getExchange();
string rtk = rt.getRoutingKey();
string cid;
if (p && p->hasCorrelationId())
cid = p->getCorrelationId();
if (mapMsg) {
sendException(rte, rtk, cid, Manageable::StatusText(Manageable::STATUS_FORBIDDEN),
Manageable::STATUS_FORBIDDEN, false);
} else {
ResizableBuffer outBuffer(qmfV1BufferSize);
encodeHeader(outBuffer, 'm', sequence);
outBuffer.putLong(Manageable::STATUS_FORBIDDEN);
outBuffer.putMediumString(Manageable::StatusText(Manageable::STATUS_FORBIDDEN));
sendBuffer(outBuffer, rte, rtk);
}
QPID_LOG(debug, "SEND MethodResponse status=FORBIDDEN" << " seq=" << sequence);
}
return false;
}
return true;
}