access security
This commit is contained in:
@@ -235,3 +235,5 @@ testApp/utils/testAtomicBoolean.cpp
|
||||
testApp/utils/testHexDump.cpp
|
||||
testApp/utils/testInetAddressUtils.cpp
|
||||
testApp/utils/transportRegistryTest.cpp
|
||||
src/remote/security.h
|
||||
src/remote/security.cpp
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace pvAccess {
|
||||
const epics::pvData::int16 PVA_MESSAGE_HEADER_SIZE = 8;
|
||||
|
||||
/** All messages must be aligned to 8-bytes (64-bit). */
|
||||
const epics::pvData::int32 PVA_ALIGNMENT = 1;
|
||||
const epics::pvData::int32 PVA_ALIGNMENT = 1; //8;
|
||||
|
||||
/**
|
||||
* UDP maximum send message size.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
SRC_DIRS += $(PVACCESS_SRC)/remote
|
||||
|
||||
INC += remote.h
|
||||
INC += security.h
|
||||
INC += blockingUDP.h
|
||||
INC += beaconHandler.h
|
||||
INC += blockingTCP.h
|
||||
@@ -22,3 +23,4 @@ LIBSRCS += blockingTCPAcceptor.cpp
|
||||
LIBSRCS += transportRegistry.cpp
|
||||
LIBSRCS += serializationHelper.cpp
|
||||
LIBSRCS += codec.cpp
|
||||
LIBSRCS += security.cpp
|
||||
|
||||
@@ -166,8 +166,6 @@ namespace epics {
|
||||
THROW_BASE_EXCEPTION(temp.str().c_str());
|
||||
}
|
||||
|
||||
// TODO send security token
|
||||
|
||||
LOG(logLevelDebug, "Connected to PVA server: %s.", ipAddrStr);
|
||||
|
||||
_namedLocker.releaseSynchronizationObject(&address);
|
||||
|
||||
@@ -121,6 +121,18 @@ namespace epics {
|
||||
// noop
|
||||
}
|
||||
|
||||
virtual void authNZInitialize(void*) {
|
||||
// noop
|
||||
}
|
||||
|
||||
virtual void authNZMessage(epics::pvData::PVField::shared_pointer const & data) {
|
||||
// noop
|
||||
}
|
||||
|
||||
virtual std::tr1::shared_ptr<SecuritySession> getSecuritySession() const {
|
||||
return std::tr1::shared_ptr<SecuritySession>();
|
||||
}
|
||||
|
||||
// NOTE: this is not yet used for UDP
|
||||
virtual void setByteOrder(int byteOrder) {
|
||||
// called from receive thread... or before processing
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/blockingTCP.h>
|
||||
@@ -23,7 +26,9 @@
|
||||
#include <pv/hexDump.h>
|
||||
#include <pv/logger.h>
|
||||
#include <pv/codec.h>
|
||||
#include <pv/serializationHelper.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
|
||||
@@ -1433,6 +1438,11 @@ namespace epics {
|
||||
|
||||
void BlockingTCPTransportCodec::internalClose(bool force) {
|
||||
BlockingSocketAbstractCodec::internalClose(force);
|
||||
|
||||
// TODO sync
|
||||
if (_securitySession)
|
||||
_securitySession->close();
|
||||
|
||||
if (IS_LOGGABLE(logLevelDebug))
|
||||
{
|
||||
LOG(logLevelDebug,
|
||||
@@ -1461,9 +1471,47 @@ namespace epics {
|
||||
_verifiedEvent.signal();
|
||||
}
|
||||
|
||||
void BlockingTCPTransportCodec::authNZMessage(epics::pvData::PVField::shared_pointer const & data) {
|
||||
// TODO sync
|
||||
if (_securitySession)
|
||||
_securitySession->messageReceived(data);
|
||||
else
|
||||
{
|
||||
char ipAddrStr[48];
|
||||
ipAddrToDottedIP(&_socketAddress.ia, ipAddrStr, sizeof(ipAddrStr));
|
||||
LOG(logLevelWarn, "authNZ message received from '%s' but no security plug-in session active.", ipAddrStr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SecurityPluginMessageTransportSender : public TransportSender {
|
||||
public:
|
||||
POINTER_DEFINITIONS(SecurityPluginMessageTransportSender);
|
||||
|
||||
SecurityPluginMessageTransportSender(PVField::shared_pointer const & data) :
|
||||
m_data(data)
|
||||
{
|
||||
}
|
||||
|
||||
void send(ByteBuffer* buffer, TransportSendControl* control) {
|
||||
control->startMessage((int8)5, 0);
|
||||
SerializationHelper::serializeFull(buffer, control, m_data);
|
||||
// send immediately
|
||||
control->flush(true);
|
||||
}
|
||||
|
||||
void lock() {}
|
||||
void unlock() {}
|
||||
|
||||
private:
|
||||
PVField::shared_pointer m_data;
|
||||
};
|
||||
|
||||
void BlockingTCPTransportCodec::sendSecurityPluginMessage(epics::pvData::PVField::shared_pointer const & data) {
|
||||
// TODO not optimal since it allocates a new object every time
|
||||
SecurityPluginMessageTransportSender::shared_pointer spmts(new SecurityPluginMessageTransportSender(data));
|
||||
enqueueSendRequest(spmts);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1477,7 +1525,7 @@ namespace epics {
|
||||
int32_t receiveBufferSize) :
|
||||
BlockingTCPTransportCodec(true, context, channel, responseHandler,
|
||||
sendBufferSize, receiveBufferSize, PVA_DEFAULT_PRIORITY),
|
||||
_lastChannelSID(0), _verifyOrVerified(false)
|
||||
_lastChannelSID(0), _verifyOrVerified(false), _securityRequired(false)
|
||||
{
|
||||
|
||||
// NOTE: priority not yet known, default priority is used to
|
||||
@@ -1574,8 +1622,29 @@ namespace epics {
|
||||
buffer->putShort(0x7FFF);
|
||||
|
||||
// list of authNZ plugin names
|
||||
// TODO
|
||||
buffer->putByte(0);
|
||||
map<string, SecurityPlugin::shared_pointer> securityPlugins;
|
||||
vector<string> validSPNames;
|
||||
validSPNames.reserve(securityPlugins.size());
|
||||
|
||||
for (map<string, SecurityPlugin::shared_pointer>::const_iterator iter =
|
||||
securityPlugins.begin();
|
||||
iter != securityPlugins.end(); iter++)
|
||||
{
|
||||
SecurityPlugin::shared_pointer securityPlugin = iter->second;
|
||||
if (securityPlugin->isValidFor(_socketAddress))
|
||||
validSPNames.push_back(securityPlugin->getId());
|
||||
}
|
||||
|
||||
size_t validSPCount = validSPNames.size();
|
||||
|
||||
SerializeHelper::writeSize(validSPCount, buffer, this);
|
||||
for (vector<string>::const_iterator iter =
|
||||
validSPNames.begin();
|
||||
iter != validSPNames.end(); iter++)
|
||||
SerializeHelper::serializeString(*iter, buffer, this);
|
||||
|
||||
// TODO sync
|
||||
_securityRequired = (validSPCount > 0);
|
||||
|
||||
// send immediately
|
||||
control->flush(true);
|
||||
@@ -1625,7 +1694,82 @@ namespace epics {
|
||||
destroyAllChannels();
|
||||
}
|
||||
|
||||
void BlockingServerTCPTransportCodec::authenticationCompleted(epics::pvData::Status const & status)
|
||||
{
|
||||
if (IS_LOGGABLE(logLevelDebug))
|
||||
{
|
||||
char ipAddrStr[48];
|
||||
ipAddrToDottedIP(&_socketAddress.ia, ipAddrStr, sizeof(ipAddrStr));
|
||||
LOG(logLevelDebug, "Authentication completed with status '%s' for PVA client: %s.", Status::StatusTypeName[status.getType()], ipAddrStr);
|
||||
}
|
||||
|
||||
if (!isVerified()) // TODO sync
|
||||
verified(status);
|
||||
else if (!status.isSuccess())
|
||||
{
|
||||
string errorMessage = "Re-authentication failed: " + status.getMessage();
|
||||
if (!status.getStackDump().empty())
|
||||
errorMessage += "\n" + status.getStackDump();
|
||||
LOG(logLevelInfo, errorMessage.c_str());
|
||||
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
epics::pvData::Status BlockingServerTCPTransportCodec::invalidSecurityPluginNameStatus(Status::STATUSTYPE_ERROR, "invalid security plug-in name");
|
||||
|
||||
void BlockingServerTCPTransportCodec::authNZInitialize(void *arg)
|
||||
{
|
||||
struct InitData {
|
||||
std::string securityPluginName;
|
||||
PVField::shared_pointer data;
|
||||
};
|
||||
|
||||
InitData* initData = static_cast<InitData*>(arg);
|
||||
|
||||
// check if plug-in name is valid
|
||||
SecurityPlugin::shared_pointer securityPlugin;
|
||||
|
||||
map<string, SecurityPlugin::shared_pointer>::iterator spIter =
|
||||
_context->getSecurityPlugins().find(initData->securityPluginName);
|
||||
if (spIter != _context->getSecurityPlugins().end())
|
||||
securityPlugin = spIter->second;
|
||||
if (!securityPlugin)
|
||||
{
|
||||
if (_securityRequired)
|
||||
{
|
||||
verified(invalidSecurityPluginNameStatus);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
securityPlugin = NoSecurityPlugin::INSTANCE;
|
||||
|
||||
if (IS_LOGGABLE(logLevelDebug))
|
||||
{
|
||||
char ipAddrStr[48];
|
||||
ipAddrToDottedIP(&_socketAddress.ia, ipAddrStr, sizeof(ipAddrStr));
|
||||
LOG(logLevelDebug, "No security plug-in installed, selecting default plug-in '%s' for PVA client: %s.", securityPlugin->getId().c_str(), ipAddrStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!securityPlugin->isValidFor(_socketAddress))
|
||||
verified(invalidSecurityPluginNameStatus);
|
||||
|
||||
if (IS_LOGGABLE(logLevelDebug))
|
||||
{
|
||||
char ipAddrStr[48];
|
||||
ipAddrToDottedIP(&_socketAddress.ia, ipAddrStr, sizeof(ipAddrStr));
|
||||
LOG(logLevelDebug, "Accepted security plug-in '%s' for PVA client: %s.", initData->securityPluginName.c_str(), ipAddrStr);
|
||||
}
|
||||
|
||||
// create session
|
||||
SecurityPluginControl::shared_pointer spc = std::tr1::dynamic_pointer_cast<SecurityPluginControl>(shared_from_this());
|
||||
|
||||
// TODO sync
|
||||
_securitySession = securityPlugin->createSession(_socketAddress, spc, initData->data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1858,9 +2002,23 @@ namespace epics {
|
||||
// QoS (aka connection priority)
|
||||
buffer->putShort(getPriority());
|
||||
|
||||
// authNZ plugin name
|
||||
// TODO
|
||||
SerializeHelper::serializeString("", buffer, control);
|
||||
// TODO sync
|
||||
if (_securitySession)
|
||||
{
|
||||
// selected authNZ plug-in name
|
||||
SerializeHelper::serializeString(_securitySession->getSecurityPlugin()->getId(), buffer, control);
|
||||
|
||||
// optional authNZ plug-in initialization data
|
||||
SerializationHelper::serializeFull(buffer, control, _securitySession->initializationData());
|
||||
}
|
||||
else
|
||||
{
|
||||
// emptry authNZ plug-in name
|
||||
SerializeHelper::serializeString("", buffer, control);
|
||||
|
||||
// no authNZ plug-in initialization data
|
||||
SerializationHelper::serializeNullField(buffer, control);
|
||||
}
|
||||
|
||||
// send immediately
|
||||
control->flush(true);
|
||||
@@ -1872,8 +2030,44 @@ namespace epics {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void BlockingClientTCPTransportCodec::authNZInitialize(void *arg)
|
||||
{
|
||||
vector<string>* offeredSecurityPlugins = static_cast< vector<string>* >(arg);
|
||||
if (!offeredSecurityPlugins->empty())
|
||||
{
|
||||
map<string, SecurityPlugin::shared_pointer>& availableSecurityPlugins =
|
||||
_context->getSecurityPlugins();
|
||||
|
||||
for (vector<string>::const_iterator offeredSP = offeredSecurityPlugins->begin();
|
||||
offeredSP != offeredSecurityPlugins->end(); offeredSP++)
|
||||
{
|
||||
map<string, SecurityPlugin::shared_pointer>::iterator spi = availableSecurityPlugins.find(*offeredSP);
|
||||
if (spi != availableSecurityPlugins.end())
|
||||
{
|
||||
SecurityPlugin::shared_pointer securityPlugin = spi->second;
|
||||
if (securityPlugin->isValidFor(_socketAddress))
|
||||
{
|
||||
// create session
|
||||
SecurityPluginControl::shared_pointer spc = std::tr1::dynamic_pointer_cast<SecurityPluginControl>(shared_from_this());
|
||||
|
||||
// TODO sync
|
||||
_securitySession = securityPlugin->createSession(_socketAddress, spc, PVField::shared_pointer());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TransportSender::shared_pointer transportSender = std::tr1::dynamic_pointer_cast<TransportSender>(shared_from_this());
|
||||
enqueueSendRequest(transportSender);
|
||||
}
|
||||
|
||||
void BlockingClientTCPTransportCodec::authenticationCompleted(epics::pvData::Status const & status)
|
||||
{
|
||||
// noop for client side (server will send ConnectionValidation message)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
#include <pv/pvaConstants.h>
|
||||
#include <pv/remote.h>
|
||||
#include <pv/security.h>
|
||||
#include <pv/transportRegistry.h>
|
||||
#include <pv/introspectionRegistry.h>
|
||||
#include <pv/namedLockPattern.h>
|
||||
@@ -415,7 +416,8 @@ namespace epics {
|
||||
|
||||
|
||||
class BlockingTCPTransportCodec :
|
||||
public BlockingSocketAbstractCodec
|
||||
public BlockingSocketAbstractCodec,
|
||||
public SecurityPluginControl
|
||||
|
||||
{
|
||||
|
||||
@@ -522,6 +524,17 @@ namespace epics {
|
||||
|
||||
void verified(epics::pvData::Status const & status);
|
||||
|
||||
bool isVerified() const { return _verified; } // TODO sync
|
||||
|
||||
std::tr1::shared_ptr<SecuritySession> getSecuritySession() const {
|
||||
// TODO sync
|
||||
return _securitySession;
|
||||
}
|
||||
|
||||
void authNZMessage(epics::pvData::PVField::shared_pointer const & data);
|
||||
|
||||
void sendSecurityPluginMessage(epics::pvData::PVField::shared_pointer const & data);
|
||||
|
||||
protected:
|
||||
|
||||
BlockingTCPTransportCodec(
|
||||
@@ -548,6 +561,8 @@ namespace epics {
|
||||
IntrospectionRegistry _incomingIR;
|
||||
IntrospectionRegistry _outgoingIR;
|
||||
|
||||
SecuritySession::shared_pointer _securitySession;
|
||||
|
||||
private:
|
||||
|
||||
std::auto_ptr<ResponseHandler> _responseHandler;
|
||||
@@ -558,6 +573,7 @@ namespace epics {
|
||||
bool _verified;
|
||||
epics::pvData::Mutex _verifiedMutex;
|
||||
epics::pvData::Event _verifiedEvent;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -619,10 +635,6 @@ namespace epics {
|
||||
|
||||
int getChannelCount();
|
||||
|
||||
epics::pvData::PVField::shared_pointer getSecurityToken() {
|
||||
return epics::pvData::PVField::shared_pointer();
|
||||
}
|
||||
|
||||
void lock() {
|
||||
// noop
|
||||
}
|
||||
@@ -655,6 +667,10 @@ namespace epics {
|
||||
// noop on server-side
|
||||
}
|
||||
|
||||
void authNZInitialize(void *);
|
||||
|
||||
void authenticationCompleted(epics::pvData::Status const & status);
|
||||
|
||||
void send(epics::pvData::ByteBuffer* buffer,
|
||||
TransportSendControl* control);
|
||||
|
||||
@@ -684,6 +700,10 @@ namespace epics {
|
||||
|
||||
bool _verifyOrVerified;
|
||||
|
||||
bool _securityRequired;
|
||||
|
||||
static epics::pvData::Status invalidSecurityPluginNameStatus;
|
||||
|
||||
};
|
||||
|
||||
class epicsShareClass BlockingClientTCPTransportCodec :
|
||||
@@ -759,7 +779,11 @@ namespace epics {
|
||||
|
||||
void send(epics::pvData::ByteBuffer* buffer,
|
||||
TransportSendControl* control);
|
||||
|
||||
|
||||
void authNZInitialize(void *);
|
||||
|
||||
void authenticationCompleted(epics::pvData::Status const & status);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void internalClose(bool force);
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <osiSock.h>
|
||||
#include <osdSock.h>
|
||||
|
||||
@@ -157,6 +160,7 @@ namespace epics {
|
||||
};
|
||||
|
||||
class TransportClient;
|
||||
class SecuritySession;
|
||||
|
||||
/**
|
||||
* Interface defining transport (connection).
|
||||
@@ -288,9 +292,24 @@ namespace epics {
|
||||
* @return <code>true</code> if connected.
|
||||
*/
|
||||
virtual bool isClosed() = 0;
|
||||
|
||||
/**
|
||||
* Used to initialize authNZ (select security plug-in).
|
||||
* @param data
|
||||
*/
|
||||
virtual void authNZInitialize(void*) = 0;
|
||||
|
||||
/**
|
||||
* Pass data to the active security plug-in session.
|
||||
* @param data the data (any data), can be <code>null</code>.
|
||||
*/
|
||||
virtual void authNZMessage(epics::pvData::PVField::shared_pointer const & data) = 0;
|
||||
|
||||
virtual std::tr1::shared_ptr<SecuritySession> getSecuritySession() const = 0;
|
||||
};
|
||||
|
||||
class Channel;
|
||||
class SecurityPlugin;
|
||||
|
||||
/**
|
||||
* Not public IF, used by Transports, etc.
|
||||
@@ -311,6 +330,11 @@ namespace epics {
|
||||
|
||||
virtual Configuration::shared_pointer getConfiguration() = 0;
|
||||
|
||||
/**
|
||||
* Get map of available security plug-ins.
|
||||
* @return the map of available security plug-ins
|
||||
*/
|
||||
virtual std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> >& getSecurityPlugins() = 0;
|
||||
|
||||
|
||||
///
|
||||
@@ -465,12 +489,6 @@ namespace epics {
|
||||
|
||||
virtual ~ChannelHostingTransport() {}
|
||||
|
||||
/**
|
||||
* Get security token.
|
||||
* @return security token, can be <code>null</code>.
|
||||
*/
|
||||
virtual epics::pvData::PVField::shared_pointer getSecurityToken() = 0;
|
||||
|
||||
/**
|
||||
* Preallocate new channel SID.
|
||||
* @return new channel server id (SID).
|
||||
|
||||
13
src/remote/security.cpp
Normal file
13
src/remote/security.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* pvAccessCPP is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/security.h>
|
||||
|
||||
using namespace epics::pvAccess;
|
||||
|
||||
NoSecurityPlugin::shared_pointer NoSecurityPlugin::INSTANCE(new NoSecurityPlugin());
|
||||
|
||||
458
src/remote/security.h
Normal file
458
src/remote/security.h
Normal file
@@ -0,0 +1,458 @@
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* pvAccessCPP is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#ifndef SECURITY_H
|
||||
#define SECURITY_H
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define securityEpicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <osiSock.h>
|
||||
#include <osdSock.h>
|
||||
|
||||
#include <pv/status.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/sharedPtr.h>
|
||||
|
||||
#ifdef securityEpicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# undef securityEpicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <pv/remote.h>
|
||||
#include <pv/serializationHelper.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics {
|
||||
namespace pvAccess {
|
||||
|
||||
// notify client only on demand, configurable via pvRequest
|
||||
// add the following method to ChannelRequest:
|
||||
// void credentialsChanged(std::vector<BitSet> credentials);
|
||||
|
||||
|
||||
// pvAccess message: channel client id, ioid (if invalid then it's for channel) and array of bitSets
|
||||
// or leave to the plugin?
|
||||
|
||||
|
||||
// when clients gets initial credentialsChanged call before create is called
|
||||
// and then on each change
|
||||
|
||||
class ChannelSecuritySession {
|
||||
public:
|
||||
POINTER_DEFINITIONS(ChannelSecuritySession);
|
||||
|
||||
virtual ~ChannelSecuritySession() {}
|
||||
|
||||
/// closes this session
|
||||
virtual void close() = 0;
|
||||
|
||||
// for every authroizeCreate... a release() must be called
|
||||
virtual void release(pvAccessID ioid) = 0;
|
||||
|
||||
// bitSet w/ one bit
|
||||
virtual epics::pvData::Status authorizeCreateChannelProcess(
|
||||
pvAccessID ioid, epics::pvData::PVStructure const & pvRequest) = 0;
|
||||
virtual epics::pvData::Status authorizeProcess(pvAccessID ioid) = 0;
|
||||
|
||||
// bitSet w/ one bit (allowed, not allowed) and rest of the bit per field
|
||||
virtual epics::pvData::Status authorizeCreateChannelGet(
|
||||
pvAccessID ioid, epics::pvData::PVStructure const & pvRequest) = 0;
|
||||
virtual epics::pvData::Status authorizeGet(pvAccessID ioid) = 0;
|
||||
|
||||
// read: bitSet w/ one bit (allowed, not allowed) and rest of the bit per field
|
||||
// write: bitSet w/ one bit (allowed, not allowed) and rest of the bit per field
|
||||
virtual epics::pvData::Status authorizeCreateChannelPut(
|
||||
pvAccessID ioid, epics::pvData::PVStructure const & pvRequest) = 0;
|
||||
virtual epics::pvData::Status authorizePut(
|
||||
pvAccessID ioid,
|
||||
epics::pvData::PVStructure::shared_pointer const & dataToPut,
|
||||
epics::pvData::BitSet::shared_pointer const & fieldsToPut) = 0;
|
||||
|
||||
// read: bitSet w/ one bit (allowed, not allowed) and rest of the bit per field
|
||||
// write: bitSet w/ one bit (allowed, not allowed) and rest of the bit per field
|
||||
// process: bitSet w/ one bit (allowed, not allowed)
|
||||
virtual epics::pvData::Status authorizeCreateChannelPutGet(
|
||||
pvAccessID ioid, epics::pvData::PVStructure const & pvRequest) = 0;
|
||||
virtual epics::pvData::Status authorizePutGet(
|
||||
pvAccessID ioid,
|
||||
epics::pvData::PVStructure::shared_pointer const & dataToPut,
|
||||
epics::pvData::BitSet::shared_pointer const & fieldsToPut) = 0;
|
||||
|
||||
// bitSet w/ one bit
|
||||
virtual epics::pvData::Status authorizeCreateChannelRPC(
|
||||
pvAccessID ioid, epics::pvData::PVStructure const & pvRequest) = 0;
|
||||
// one could authorize per operation basis
|
||||
virtual epics::pvData::Status authorizeRPC(
|
||||
pvAccessID ioid, epics::pvData::PVStructure::shared_pointer const & arguments) = 0;
|
||||
|
||||
// read: bitSet w/ one bit (allowed, not allowed) and rest of the bit per field
|
||||
virtual epics::pvData::Status authorizeCreateMonitor(
|
||||
pvAccessID ioid, epics::pvData::PVStructure const & pvRequest) = 0;
|
||||
virtual epics::pvData::Status authorizeMonitor(pvAccessID ioid) = 0;
|
||||
|
||||
// read: bitSet w/ one bit (allowed, not allowed) and rest put/get/set length
|
||||
virtual epics::pvData::Status authorizeCreateChannelArray(
|
||||
pvAccessID ioid, epics::pvData::PVStructure const & pvRequest) = 0;
|
||||
// use authorizeGet
|
||||
virtual epics::pvData::Status authorizePut(pvAccessID ioid, epics::pvData::PVArray::shared_pointer const & dataToPut) = 0;
|
||||
virtual epics::pvData::Status authorizeSetLength(pvAccessID ioid) = 0;
|
||||
|
||||
|
||||
// introspection authorization
|
||||
virtual epics::pvData::Status authorizeGetField(pvAccessID ioid, std::string const & subField) = 0;
|
||||
};
|
||||
|
||||
class SecurityPlugin;
|
||||
|
||||
class epicsShareClass SecurityException: public std::runtime_error {
|
||||
public:
|
||||
explicit SecurityException(std::string const & what): std::runtime_error(what) {}
|
||||
};
|
||||
|
||||
class epicsShareClass SecuritySession {
|
||||
public:
|
||||
POINTER_DEFINITIONS(SecuritySession);
|
||||
|
||||
// optional (can be null) initialization data for the remote party
|
||||
// client to server
|
||||
virtual epics::pvData::PVField::shared_pointer initializationData() = 0;
|
||||
|
||||
// get parent
|
||||
virtual std::tr1::shared_ptr<SecurityPlugin> getSecurityPlugin() = 0;
|
||||
|
||||
// can be called any time, for any reason
|
||||
virtual void messageReceived(epics::pvData::PVField::shared_pointer const & data) = 0;
|
||||
|
||||
/// closes this session
|
||||
virtual void close() = 0;
|
||||
|
||||
// notification to the client on allowed requests (bitSet, a bit per request)
|
||||
virtual ChannelSecuritySession::shared_pointer createChannelSession(std::string const & channelName)
|
||||
throw (SecurityException) = 0;
|
||||
};
|
||||
|
||||
class epicsShareClass SecurityPluginControl {
|
||||
public:
|
||||
POINTER_DEFINITIONS(SecurityPluginControl);
|
||||
|
||||
virtual ~SecurityPluginControl() {}
|
||||
|
||||
// can be called any time, for any reason
|
||||
virtual void sendSecurityPluginMessage(epics::pvData::PVField::shared_pointer const & data) = 0;
|
||||
|
||||
// if Status.isSuccess() == false,
|
||||
// pvAccess will send status to the client and close the connection
|
||||
// can be called more then once (in case of re-authentication process)
|
||||
virtual void authenticationCompleted(epics::pvData::Status const & status) = 0;
|
||||
};
|
||||
|
||||
|
||||
class epicsShareClass SecurityPlugin {
|
||||
public:
|
||||
POINTER_DEFINITIONS(SecurityPlugin);
|
||||
|
||||
virtual ~SecurityPlugin() {}
|
||||
|
||||
/**
|
||||
* Short, unique name for the plug-in, used to identify the plugin.
|
||||
* @return the ID.
|
||||
*/
|
||||
virtual std::string getId() const = 0;
|
||||
|
||||
/**
|
||||
* Description of the security plug-in.
|
||||
* @return the description string.
|
||||
*/
|
||||
virtual std::string getDescription() const = 0;
|
||||
|
||||
/**
|
||||
* Check whether the remote instance with given network address is
|
||||
* valid to use this security plug-in to authNZ.
|
||||
* @param remoteAddress
|
||||
* @return <code>true</code> if this security plugin can be used for remote instance.
|
||||
*/
|
||||
virtual bool isValidFor(osiSockAddr const & remoteAddress) const = 0;
|
||||
|
||||
/**
|
||||
* Create a security session (usually one per transport).
|
||||
* @param remoteAddress
|
||||
* @return a new session.
|
||||
* @throws SecurityException
|
||||
*/
|
||||
// authentication must be done immediately when connection is established (timeout 3seconds),
|
||||
// later on authentication process can be repeated
|
||||
// the server and the client can exchange (arbitrary number) of messages using SecurityPluginControl.sendMessage()
|
||||
// the process completion must be notified by calling AuthenticationControl.completed()
|
||||
virtual SecuritySession::shared_pointer createSession(
|
||||
osiSockAddr const & remoteAddress,
|
||||
SecurityPluginControl::shared_pointer const & control,
|
||||
epics::pvData::PVField::shared_pointer const & data) throw (SecurityException) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class epicsShareClass NoSecurityPlugin :
|
||||
public SecurityPlugin,
|
||||
public SecuritySession,
|
||||
public ChannelSecuritySession,
|
||||
public std::tr1::enable_shared_from_this<ChannelSecuritySession> {
|
||||
protected:
|
||||
NoSecurityPlugin() {}
|
||||
|
||||
public:
|
||||
POINTER_DEFINITIONS(NoSecurityPlugin);
|
||||
|
||||
static NoSecurityPlugin::shared_pointer INSTANCE;
|
||||
|
||||
virtual ~NoSecurityPlugin() {}
|
||||
|
||||
// optional (can be null) initialization data for the remote party
|
||||
// client to server
|
||||
virtual epics::pvData::PVField::shared_pointer initializationData() {
|
||||
return epics::pvData::PVField::shared_pointer();
|
||||
}
|
||||
|
||||
// get parent
|
||||
virtual std::tr1::shared_ptr<SecurityPlugin> getSecurityPlugin() {
|
||||
return std::tr1::dynamic_pointer_cast<SecurityPlugin>(shared_from_this());
|
||||
}
|
||||
|
||||
// can be called any time, for any reason
|
||||
virtual void messageReceived(epics::pvData::PVField::shared_pointer const & data) {
|
||||
// noop
|
||||
}
|
||||
|
||||
/// closes this session
|
||||
virtual void close() {
|
||||
// noop
|
||||
}
|
||||
|
||||
// notification to the client on allowed requests (bitSet, a bit per request)
|
||||
virtual ChannelSecuritySession::shared_pointer createChannelSession(std::string const & /*channelName*/)
|
||||
throw (SecurityException)
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
/**
|
||||
* Short, unique name for the plug-in, used to identify the plugin.
|
||||
* @return the ID.
|
||||
*/
|
||||
virtual std::string getId() const {
|
||||
return "none";
|
||||
}
|
||||
|
||||
/**
|
||||
* Description of the security plug-in.
|
||||
* @return the description string.
|
||||
*/
|
||||
virtual std::string getDescription() const {
|
||||
return "No security plug-in";
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the remote instance with given network address is
|
||||
* valid to use this security plug-in to authNZ.
|
||||
* @param remoteAddress
|
||||
* @return <code>true</code> if this security plugin can be used for remote instance.
|
||||
*/
|
||||
virtual bool isValidFor(osiSockAddr const & /*remoteAddress*/) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a security session (usually one per transport).
|
||||
* @param remoteAddress
|
||||
* @return a new session.
|
||||
* @throws SecurityException
|
||||
*/
|
||||
// authentication must be done immediately when connection is established (timeout 3seconds),
|
||||
// later on authentication process can be repeated
|
||||
// the server and the client can exchange (arbitrary number) of messages using SecurityPluginControl.sendMessage()
|
||||
// the process completion must be notified by calling AuthenticationControl.completed()
|
||||
virtual SecuritySession::shared_pointer createSession(
|
||||
osiSockAddr const & /*remoteAddress*/,
|
||||
SecurityPluginControl::shared_pointer const & control,
|
||||
epics::pvData::PVField::shared_pointer const & /*data*/) throw (SecurityException) {
|
||||
control->authenticationCompleted(epics::pvData::Status::Ok);
|
||||
return std::tr1::dynamic_pointer_cast<SecuritySession>(shared_from_this());
|
||||
}
|
||||
|
||||
// for every authroizeCreate... a release() must be called
|
||||
virtual void release(pvAccessID ioid) {
|
||||
// noop
|
||||
}
|
||||
|
||||
// bitSet w/ one bit
|
||||
virtual epics::pvData::Status authorizeCreateChannelProcess(
|
||||
pvAccessID ioid, epics::pvData::PVStructure const & /*pvRequest*/) {
|
||||
return epics::pvData::Status::Ok;
|
||||
}
|
||||
|
||||
virtual epics::pvData::Status authorizeProcess(pvAccessID /*ioid*/) {
|
||||
return epics::pvData::Status::Ok;
|
||||
}
|
||||
|
||||
// bitSet w/ one bit (allowed, not allowed) and rest of the bit per field
|
||||
virtual epics::pvData::Status authorizeCreateChannelGet(
|
||||
pvAccessID /*ioid*/, epics::pvData::PVStructure const & /*pvRequest*/) {
|
||||
return epics::pvData::Status::Ok;
|
||||
}
|
||||
|
||||
virtual epics::pvData::Status authorizeGet(pvAccessID /*ioid*/) {
|
||||
return epics::pvData::Status::Ok;
|
||||
}
|
||||
|
||||
// read: bitSet w/ one bit (allowed, not allowed) and rest of the bit per field
|
||||
// write: bitSet w/ one bit (allowed, not allowed) and rest of the bit per field
|
||||
virtual epics::pvData::Status authorizeCreateChannelPut(
|
||||
pvAccessID /*ioid*/, epics::pvData::PVStructure const & /*pvRequest*/) {
|
||||
return epics::pvData::Status::Ok;
|
||||
}
|
||||
|
||||
virtual epics::pvData::Status authorizePut(
|
||||
pvAccessID /*ioid*/,
|
||||
epics::pvData::PVStructure::shared_pointer const & /*dataToPut*/,
|
||||
epics::pvData::BitSet::shared_pointer const & /*fieldsToPut*/) {
|
||||
return epics::pvData::Status::Ok;
|
||||
}
|
||||
|
||||
// read: bitSet w/ one bit (allowed, not allowed) and rest of the bit per field
|
||||
// write: bitSet w/ one bit (allowed, not allowed) and rest of the bit per field
|
||||
// process: bitSet w/ one bit (allowed, not allowed)
|
||||
virtual epics::pvData::Status authorizeCreateChannelPutGet(
|
||||
pvAccessID /*ioid*/, epics::pvData::PVStructure const & /*pvRequest*/) {
|
||||
return epics::pvData::Status::Ok;
|
||||
}
|
||||
|
||||
virtual epics::pvData::Status authorizePutGet(
|
||||
pvAccessID /*ioid*/,
|
||||
epics::pvData::PVStructure::shared_pointer const & /*dataToPut*/,
|
||||
epics::pvData::BitSet::shared_pointer const & /*fieldsToPut*/) {
|
||||
return epics::pvData::Status::Ok;
|
||||
}
|
||||
|
||||
// bitSet w/ one bit
|
||||
virtual epics::pvData::Status authorizeCreateChannelRPC(
|
||||
pvAccessID /*ioid*/, epics::pvData::PVStructure const & /*pvRequest*/) {
|
||||
return epics::pvData::Status::Ok;
|
||||
}
|
||||
|
||||
// one could authorize per operation basis
|
||||
virtual epics::pvData::Status authorizeRPC(
|
||||
pvAccessID /*ioid*/, epics::pvData::PVStructure::shared_pointer const & /*arguments*/) {
|
||||
return epics::pvData::Status::Ok;
|
||||
}
|
||||
|
||||
// read: bitSet w/ one bit (allowed, not allowed) and rest of the bit per field
|
||||
virtual epics::pvData::Status authorizeCreateMonitor(
|
||||
pvAccessID /*ioid*/, epics::pvData::PVStructure const & /*pvRequest*/) {
|
||||
return epics::pvData::Status::Ok;
|
||||
}
|
||||
|
||||
virtual epics::pvData::Status authorizeMonitor(pvAccessID /*ioid*/) {
|
||||
return epics::pvData::Status::Ok;
|
||||
}
|
||||
|
||||
// read: bitSet w/ one bit (allowed, not allowed) and rest put/get/set length
|
||||
virtual epics::pvData::Status authorizeCreateChannelArray(
|
||||
pvAccessID /*ioid*/, epics::pvData::PVStructure const & /*pvRequest*/) {
|
||||
return epics::pvData::Status::Ok;
|
||||
}
|
||||
|
||||
// use authorizeGet
|
||||
virtual epics::pvData::Status authorizePut(
|
||||
pvAccessID /*ioid*/, epics::pvData::PVArray::shared_pointer const & /*dataToPut*/) {
|
||||
return epics::pvData::Status::Ok;
|
||||
}
|
||||
|
||||
virtual epics::pvData::Status authorizeSetLength(pvAccessID /*ioid*/) {
|
||||
return epics::pvData::Status::Ok;
|
||||
}
|
||||
|
||||
// introspection authorization
|
||||
virtual epics::pvData::Status authorizeGetField(pvAccessID /*ioid*/, std::string const & /*subField*/) {
|
||||
return epics::pvData::Status::Ok;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class epicsShareClass AuthNZHandler :
|
||||
public AbstractResponseHandler,
|
||||
private epics::pvData::NoDefaultMethods
|
||||
{
|
||||
public:
|
||||
AuthNZHandler(Context* context) :
|
||||
AbstractResponseHandler(context, "authNZ message")
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~AuthNZHandler() {}
|
||||
|
||||
virtual void handleResponse(osiSockAddr* responseFrom,
|
||||
Transport::shared_pointer const & transport,
|
||||
epics::pvData::int8 version,
|
||||
epics::pvData::int8 command,
|
||||
size_t payloadSize,
|
||||
epics::pvData::ByteBuffer* payloadBuffer)
|
||||
{
|
||||
AbstractResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer);
|
||||
|
||||
epics::pvData::PVField::shared_pointer data =
|
||||
SerializationHelper::deserializeFull(payloadBuffer, transport.get());
|
||||
|
||||
transport->authNZMessage(data);
|
||||
}
|
||||
};
|
||||
|
||||
class epicsShareClass SecurityPluginRegistry :
|
||||
private epics::pvData::NoDefaultMethods
|
||||
{
|
||||
public:
|
||||
|
||||
static SecurityPluginRegistry& instance()
|
||||
{
|
||||
static SecurityPluginRegistry thisInstance;
|
||||
return thisInstance;
|
||||
}
|
||||
|
||||
std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> >& getClientSecurityPlugins()
|
||||
{
|
||||
return m_clientSecurityPlugins;
|
||||
}
|
||||
|
||||
std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> >& getServerSecurityPlugins()
|
||||
{
|
||||
return m_serverSecurityPlugins;
|
||||
}
|
||||
|
||||
void installClientSecurityPlugin(std::tr1::shared_ptr<SecurityPlugin> plugin)
|
||||
{
|
||||
m_clientSecurityPlugins[plugin->getId()] = plugin;
|
||||
}
|
||||
|
||||
void installServerSecurityPlugin(std::tr1::shared_ptr<SecurityPlugin> plugin)
|
||||
{
|
||||
m_serverSecurityPlugins[plugin->getId()] = plugin;
|
||||
}
|
||||
|
||||
private:
|
||||
SecurityPluginRegistry() {}
|
||||
|
||||
std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> > m_clientSecurityPlugins;
|
||||
std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> > m_serverSecurityPlugins;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SECURITY_H
|
||||
@@ -40,14 +40,19 @@ PVStructure::shared_pointer SerializationHelper::deserializeStructureAndCreatePV
|
||||
|
||||
PVStructure::shared_pointer SerializationHelper::deserializeStructureFull(ByteBuffer* buffer, DeserializableControl* control)
|
||||
{
|
||||
PVStructure::shared_pointer pvStructure;
|
||||
FieldConstPtr structureField = control->cachedDeserialize(buffer);
|
||||
if (structureField.get() != 0)
|
||||
return std::tr1::static_pointer_cast<PVStructure>(deserializeFull(buffer, control));
|
||||
}
|
||||
|
||||
PVField::shared_pointer SerializationHelper::deserializeFull(ByteBuffer* buffer, DeserializableControl* control)
|
||||
{
|
||||
PVField::shared_pointer pvField;
|
||||
FieldConstPtr field = control->cachedDeserialize(buffer);
|
||||
if (field.get() != 0)
|
||||
{
|
||||
pvStructure = _pvDataCreate->createPVStructure(std::tr1::static_pointer_cast<const Structure>(structureField));
|
||||
pvStructure->deserialize(buffer, control);
|
||||
pvField = _pvDataCreate->createPVField(field);
|
||||
pvField->deserialize(buffer, control);
|
||||
}
|
||||
return pvStructure;
|
||||
return pvField;
|
||||
}
|
||||
|
||||
void SerializationHelper::serializeNullField(ByteBuffer* buffer, SerializableControl* control)
|
||||
@@ -64,15 +69,20 @@ void SerializationHelper::serializePVRequest(ByteBuffer* buffer, SerializableCon
|
||||
|
||||
void SerializationHelper::serializeStructureFull(ByteBuffer* buffer, SerializableControl* control, PVStructure::shared_pointer const & pvStructure)
|
||||
{
|
||||
if (pvStructure.get() == 0)
|
||||
{
|
||||
serializeNullField(buffer, control);
|
||||
}
|
||||
else
|
||||
{
|
||||
control->cachedSerialize(pvStructure->getField(), buffer);
|
||||
pvStructure->serialize(buffer, control);
|
||||
}
|
||||
serializeFull(buffer, control, pvStructure);
|
||||
}
|
||||
|
||||
void SerializationHelper::serializeFull(ByteBuffer* buffer, SerializableControl* control, PVField::shared_pointer const & pvField)
|
||||
{
|
||||
if (pvField.get() == 0)
|
||||
{
|
||||
serializeNullField(buffer, control);
|
||||
}
|
||||
else
|
||||
{
|
||||
control->cachedSerialize(pvField->getField(), buffer);
|
||||
pvField->serialize(buffer, control);
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -67,7 +67,19 @@ namespace epics {
|
||||
*/
|
||||
static epics::pvData::PVStructure::shared_pointer deserializeStructureFull(epics::pvData::ByteBuffer* payloadBuffer, epics::pvData::DeserializableControl* control);
|
||||
|
||||
static void serializeNullField(epics::pvData::ByteBuffer* buffer, epics::pvData::SerializableControl* control);
|
||||
/**
|
||||
* Deserialize optional PVField.
|
||||
* @param payloadBuffer data buffer.
|
||||
* @return deserialized PVField, can be <code>null</code>.
|
||||
*/
|
||||
static epics::pvData::PVField::shared_pointer deserializeFull(epics::pvData::ByteBuffer* payloadBuffer, epics::pvData::DeserializableControl* control);
|
||||
|
||||
/**
|
||||
* Serialize <code>null</code> PVField.
|
||||
* @param buffer
|
||||
* @param control
|
||||
*/
|
||||
static void serializeNullField(epics::pvData::ByteBuffer* buffer, epics::pvData::SerializableControl* control);
|
||||
|
||||
/**
|
||||
* Serialize PVRequest.
|
||||
@@ -81,6 +93,11 @@ namespace epics {
|
||||
*/
|
||||
static void serializeStructureFull(epics::pvData::ByteBuffer* buffer, epics::pvData::SerializableControl* control, epics::pvData::PVStructure::shared_pointer const & pvStructure);
|
||||
|
||||
/**
|
||||
* Serialize optional PVField.
|
||||
* @param buffer data buffer.
|
||||
*/
|
||||
static void serializeFull(epics::pvData::ByteBuffer* buffer, epics::pvData::SerializableControl* control, epics::pvData::PVField::shared_pointer const & pvField);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <pv/configuration.h>
|
||||
#include <pv/beaconHandler.h>
|
||||
#include <pv/logger.h>
|
||||
#include <pv/security.h>
|
||||
|
||||
#include <pv/pvAccessMB.h>
|
||||
|
||||
@@ -47,9 +48,9 @@ namespace epics {
|
||||
namespace pvAccess {
|
||||
|
||||
string ClientContextImpl::PROVIDER_NAME = "pva";
|
||||
Status ChannelImpl::channelDestroyed = Status(
|
||||
Status ChannelImpl::channelDestroyed(
|
||||
Status::STATUSTYPE_WARNING, "channel destroyed");
|
||||
Status ChannelImpl::channelDisconnected = Status(
|
||||
Status ChannelImpl::channelDisconnected(
|
||||
Status::STATUSTYPE_WARNING, "channel disconnected");
|
||||
string emptyString;
|
||||
ConvertPtr convert = getConvert();
|
||||
@@ -389,15 +390,15 @@ namespace epics {
|
||||
|
||||
PVDataCreatePtr BaseRequestImpl::pvDataCreate = getPVDataCreate();
|
||||
|
||||
Status BaseRequestImpl::notInitializedStatus = Status(Status::STATUSTYPE_ERROR, "request not initialized");
|
||||
Status BaseRequestImpl::destroyedStatus = Status(Status::STATUSTYPE_ERROR, "request destroyed");
|
||||
Status BaseRequestImpl::channelNotConnected = Status(Status::STATUSTYPE_ERROR, "channel not connected");
|
||||
Status BaseRequestImpl::channelDestroyed = Status(Status::STATUSTYPE_ERROR, "channel destroyed");
|
||||
Status BaseRequestImpl::otherRequestPendingStatus = Status(Status::STATUSTYPE_ERROR, "other request pending");
|
||||
Status BaseRequestImpl::invalidPutStructureStatus = Status(Status::STATUSTYPE_ERROR, "incompatible put structure");
|
||||
Status BaseRequestImpl::invalidPutArrayStatus = Status(Status::STATUSTYPE_ERROR, "incompatible put array");
|
||||
Status BaseRequestImpl::invalidBitSetLengthStatus = Status(Status::STATUSTYPE_ERROR, "invalid bit-set length");
|
||||
Status BaseRequestImpl::pvRequestNull = Status(Status::STATUSTYPE_ERROR, "pvRequest == 0");
|
||||
Status BaseRequestImpl::notInitializedStatus(Status::STATUSTYPE_ERROR, "request not initialized");
|
||||
Status BaseRequestImpl::destroyedStatus(Status::STATUSTYPE_ERROR, "request destroyed");
|
||||
Status BaseRequestImpl::channelNotConnected(Status::STATUSTYPE_ERROR, "channel not connected");
|
||||
Status BaseRequestImpl::channelDestroyed(Status::STATUSTYPE_ERROR, "channel destroyed");
|
||||
Status BaseRequestImpl::otherRequestPendingStatus(Status::STATUSTYPE_ERROR, "other request pending");
|
||||
Status BaseRequestImpl::invalidPutStructureStatus(Status::STATUSTYPE_ERROR, "incompatible put structure");
|
||||
Status BaseRequestImpl::invalidPutArrayStatus(Status::STATUSTYPE_ERROR, "incompatible put array");
|
||||
Status BaseRequestImpl::invalidBitSetLengthStatus(Status::STATUSTYPE_ERROR, "invalid bit-set length");
|
||||
Status BaseRequestImpl::pvRequestNull(Status::STATUSTYPE_ERROR, "pvRequest == 0");
|
||||
|
||||
PVStructure::shared_pointer BaseRequestImpl::nullPVStructure;
|
||||
Structure::const_shared_pointer BaseRequestImpl::nullStructure;
|
||||
@@ -2821,14 +2822,17 @@ namespace epics {
|
||||
// TODO
|
||||
// TODO serverIntrospectionRegistryMaxSize
|
||||
/*int serverIntrospectionRegistryMaxSize = */ payloadBuffer->getShort();
|
||||
// TODO authNZ
|
||||
size_t size = SerializeHelper::readSize(payloadBuffer, transport.get());
|
||||
for (size_t i = 0; i < size; i++)
|
||||
SerializeHelper::deserializeString(payloadBuffer, transport.get());
|
||||
|
||||
TransportSender::shared_pointer sender = dynamic_pointer_cast<TransportSender>(transport);
|
||||
if (sender.get())
|
||||
transport->enqueueSendRequest(sender);
|
||||
// authNZ
|
||||
size_t size = SerializeHelper::readSize(payloadBuffer, transport.get());
|
||||
vector<string> offeredSecurityPlugins;
|
||||
offeredSecurityPlugins.reserve(size);
|
||||
for (size_t i = 0; i < size; i++)
|
||||
offeredSecurityPlugins.push_back(
|
||||
SerializeHelper::deserializeString(payloadBuffer, transport.get())
|
||||
);
|
||||
|
||||
transport->authNZInitialize(&offeredSecurityPlugins);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2965,8 +2969,8 @@ namespace epics {
|
||||
m_handlerTable[CMD_ECHO].reset(new NoopResponse(context, "Echo")); /* 2 */
|
||||
m_handlerTable[CMD_SEARCH].reset(new NoopResponse(context, "Search")); /* 3 */
|
||||
m_handlerTable[CMD_SEARCH_RESPONSE].reset(new SearchResponseHandler(context)); /* 4 */
|
||||
m_handlerTable[CMD_AUTHNZ].reset(new NoopResponse(context, "Introspection search")); /* 5 */
|
||||
m_handlerTable[CMD_ACL_CHANGE] = dataResponse; /* 6 */
|
||||
m_handlerTable[CMD_AUTHNZ].reset(new AuthNZHandler(context.get())); /* 5 */
|
||||
m_handlerTable[CMD_ACL_CHANGE].reset(new NoopResponse(context, "Access rights change")); /* 6 */
|
||||
m_handlerTable[CMD_CREATE_CHANNEL].reset(new CreateChannelHandler(context)); /* 7 */
|
||||
m_handlerTable[CMD_DESTROY_CHANNEL].reset(new NoopResponse(context, "Destroy channel")); /* 8 */ // TODO it might be useful to implement this...
|
||||
m_handlerTable[CMD_CONNECTION_VALIDATED].reset(new ClientConnectionValidatedHandler(context)); /* 9 */
|
||||
@@ -4631,6 +4635,11 @@ TODO
|
||||
// TODO
|
||||
}
|
||||
|
||||
std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> >& getSecurityPlugins()
|
||||
{
|
||||
return SecurityPluginRegistry::instance().getClientSecurityPlugins();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get channel search manager.
|
||||
* @return channel search manager.
|
||||
|
||||
@@ -13,13 +13,13 @@ namespace epics {
|
||||
namespace pvAccess {
|
||||
|
||||
const Status BaseChannelRequester::okStatus = Status();
|
||||
const Status BaseChannelRequester::badCIDStatus = Status(Status::STATUSTYPE_ERROR, "bad channel id");
|
||||
const Status BaseChannelRequester::badIOIDStatus = Status(Status::STATUSTYPE_ERROR, "bad request id");
|
||||
const Status BaseChannelRequester::noReadACLStatus = Status(Status::STATUSTYPE_ERROR, "no read access");
|
||||
const Status BaseChannelRequester::noWriteACLStatus = Status(Status::STATUSTYPE_ERROR, "no write access");
|
||||
const Status BaseChannelRequester::noProcessACLStatus = Status(Status::STATUSTYPE_ERROR, "no process access");
|
||||
const Status BaseChannelRequester::otherRequestPendingStatus = Status(Status::STATUSTYPE_ERROR, "other request pending");
|
||||
const Status BaseChannelRequester::notAChannelRequestStatus = Status(Status::STATUSTYPE_ERROR, "not a channel request");
|
||||
const Status BaseChannelRequester::badCIDStatus(Status::STATUSTYPE_ERROR, "bad channel id");
|
||||
const Status BaseChannelRequester::badIOIDStatus(Status::STATUSTYPE_ERROR, "bad request id");
|
||||
const Status BaseChannelRequester::noReadACLStatus(Status::STATUSTYPE_ERROR, "no read access");
|
||||
const Status BaseChannelRequester::noWriteACLStatus(Status::STATUSTYPE_ERROR, "no write access");
|
||||
const Status BaseChannelRequester::noProcessACLStatus(Status::STATUSTYPE_ERROR, "no process access");
|
||||
const Status BaseChannelRequester::otherRequestPendingStatus(Status::STATUSTYPE_ERROR, "other request pending");
|
||||
const Status BaseChannelRequester::notAChannelRequestStatus(Status::STATUSTYPE_ERROR, "not a channel request");
|
||||
|
||||
const int32 BaseChannelRequester::NULL_REQUEST = -1;
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <pv/pvAccessMB.h>
|
||||
#include <pv/rpcServer.h>
|
||||
#include <pv/security.h>
|
||||
|
||||
using std::string;
|
||||
using std::ostringstream;
|
||||
@@ -92,8 +93,8 @@ ServerResponseHandler::ServerResponseHandler(ServerContextImpl::shared_pointer c
|
||||
m_handlerTable[CMD_ECHO].reset(new ServerEchoHandler(context)); /* 2 */
|
||||
m_handlerTable[CMD_SEARCH].reset(new ServerSearchHandler(context)); /* 3 */
|
||||
m_handlerTable[CMD_SEARCH_RESPONSE] = badResponse;
|
||||
m_handlerTable[CMD_AUTHNZ] = badResponse; /* 5 */
|
||||
m_handlerTable[CMD_ACL_CHANGE] = badResponse; /* 6 - introspection search */
|
||||
m_handlerTable[CMD_AUTHNZ].reset(new AuthNZHandler(context.get())); /* 5 */
|
||||
m_handlerTable[CMD_ACL_CHANGE] = badResponse; /* 6 - access right change */
|
||||
m_handlerTable[CMD_CREATE_CHANNEL].reset(new ServerCreateChannelHandler(context)); /* 7 */
|
||||
m_handlerTable[CMD_DESTROY_CHANNEL].reset(new ServerDestroyChannelHandler(context)); /* 8 */
|
||||
m_handlerTable[CMD_CONNECTION_VALIDATED] = badResponse; /* 9 */
|
||||
@@ -152,13 +153,28 @@ void ServerConnectionValidationHandler::handleResponse(
|
||||
/* int clientIntrospectionRegistryMaxSize = */ payloadBuffer->getShort();
|
||||
// TODO connectionQoS
|
||||
/* int16 connectionQoS = */ payloadBuffer->getShort();
|
||||
// TODO authNZ
|
||||
/*std::string authNZ = */ SerializeHelper::deserializeString(payloadBuffer, transport.get());
|
||||
|
||||
// TODO call this after authNZ has done their work
|
||||
transport->verified(Status::Ok);
|
||||
// authNZ
|
||||
std::string securityPluginName = SerializeHelper::deserializeString(payloadBuffer, transport.get());
|
||||
|
||||
// optional authNZ plug-in initialization data
|
||||
PVField::shared_pointer data;
|
||||
if (payloadBuffer->getRemaining())
|
||||
SerializationHelper::deserializeFull(payloadBuffer, transport.get());
|
||||
|
||||
struct {
|
||||
std::string securityPluginName;
|
||||
PVField::shared_pointer data;
|
||||
} initData = { securityPluginName, data };
|
||||
|
||||
transport->authNZInitialize(&initData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void ServerEchoHandler::handleResponse(osiSockAddr* responseFrom,
|
||||
Transport::shared_pointer const & transport, int8 version, int8 command,
|
||||
size_t payloadSize, ByteBuffer* payloadBuffer)
|
||||
@@ -630,7 +646,7 @@ void ServerChannelRequesterImpl::channelCreated(const Status& status, Channel::s
|
||||
pvAccessID sid = casTransport->preallocateChannelSID();
|
||||
try
|
||||
{
|
||||
epics::pvData::PVField::shared_pointer securityToken = casTransport->getSecurityToken();
|
||||
epics::pvData::PVField::shared_pointer securityToken; // TODO replace with security session
|
||||
serverChannel.reset(new ServerChannelImpl(channel, _cid, sid, securityToken));
|
||||
|
||||
// ack allocation and register
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <pv/responseHandlers.h>
|
||||
#include <pv/logger.h>
|
||||
#include <pv/serverContext.h>
|
||||
#include <pv/security.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace epics::pvData;
|
||||
@@ -673,6 +674,11 @@ void ServerContextImpl::newServerDetected()
|
||||
// not used
|
||||
}
|
||||
|
||||
std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> >& ServerContextImpl::getSecurityPlugins()
|
||||
{
|
||||
return SecurityPluginRegistry::instance().getServerSecurityPlugins();
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct ThreadRunnerParam {
|
||||
|
||||
@@ -138,6 +138,7 @@ public:
|
||||
Transport::shared_pointer getSearchTransport();
|
||||
Configuration::shared_pointer getConfiguration();
|
||||
TransportRegistry::shared_pointer getTransportRegistry();
|
||||
std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> >& getSecurityPlugins();
|
||||
|
||||
std::auto_ptr<ResponseHandler> createResponseHandler();
|
||||
virtual void newServerDetected();
|
||||
|
||||
@@ -357,6 +357,16 @@ namespace epics {
|
||||
|
||||
void aliveNotification() {}
|
||||
|
||||
void authNZMessage(epics::pvData::PVField::shared_pointer const & data) {}
|
||||
void authNZInitialize(void*) {}
|
||||
|
||||
virtual std::tr1::shared_ptr<SecuritySession> getSecuritySession() const
|
||||
{
|
||||
return std::tr1::shared_ptr<SecuritySession>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool isClosed() { return false; }
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user