Files
pvAccess/src/remote/pv/security.h
2017-07-19 15:22:16 +02:00

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