459 lines
16 KiB
C++
459 lines
16 KiB
C++
/**
|
|
* 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 <pv/status.h>
|
|
#include <pv/pvData.h>
|
|
#include <pv/sharedPtr.h>
|
|
|
|
#ifdef securityEpicsExportSharedSymbols
|
|
# define epicsExportSharedSymbols
|
|
# undef securityEpicsExportSharedSymbols
|
|
#endif
|
|
|
|
#include <pv/pvaDefs.h>
|
|
#include <pv/pvaConstants.h>
|
|
#include <pv/serializationHelper.h>
|
|
#include <pv/logger.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 epicsShareClass 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::shared_pointer 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::shared_pointer 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::shared_pointer 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::shared_pointer 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::shared_pointer 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::shared_pointer 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::shared_pointer 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);
|
|
|
|
virtual ~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) = 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) = 0;
|
|
};
|
|
|
|
|
|
|
|
class epicsShareClass NoSecurityPlugin :
|
|
public SecurityPlugin,
|
|
public SecuritySession,
|
|
public ChannelSecuritySession,
|
|
public std::tr1::enable_shared_from_this<NoSecurityPlugin> {
|
|
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 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*/)
|
|
{
|
|
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*/) {
|
|
control->authenticationCompleted(epics::pvData::Status::Ok);
|
|
return 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::shared_pointer 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::shared_pointer 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::shared_pointer 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::shared_pointer 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::shared_pointer 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::shared_pointer 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::shared_pointer 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 CAClientSecurityPlugin :
|
|
public NoSecurityPlugin {
|
|
protected:
|
|
epics::pvData::PVStructure::shared_pointer m_userAndHost;
|
|
|
|
CAClientSecurityPlugin();
|
|
|
|
|
|
public:
|
|
POINTER_DEFINITIONS(CAClientSecurityPlugin);
|
|
|
|
static CAClientSecurityPlugin::shared_pointer INSTANCE;
|
|
|
|
virtual epics::pvData::PVField::shared_pointer initializationData() {
|
|
return m_userAndHost;
|
|
}
|
|
|
|
virtual std::string getId() const {
|
|
return "ca";
|
|
}
|
|
|
|
virtual std::string getDescription() const {
|
|
return "CA client security plug-in";
|
|
}
|
|
};
|
|
|
|
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;
|
|
LOG(epics::pvAccess::logLevelDebug, "Client security plug-in '%s' installed.", plugin->getId().c_str());
|
|
}
|
|
|
|
void installServerSecurityPlugin(std::tr1::shared_ptr<SecurityPlugin> plugin)
|
|
{
|
|
m_serverSecurityPlugins[plugin->getId()] = plugin;
|
|
LOG(epics::pvAccess::logLevelDebug, "Server security plug-in '%s' installed.", plugin->getId().c_str());
|
|
}
|
|
|
|
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
|