redo security (aka. access control)

Break up monolithic SecurityPlugin API into three parts.

1. Authentication.
2. Authorization.
3. Access Control decision.  Left to ChannelProviders
This commit is contained in:
Michael Davidsaver
2019-01-12 11:48:52 -08:00
parent 13cac5f4cc
commit fa484a883a
19 changed files with 665 additions and 670 deletions

View File

@ -773,6 +773,7 @@ INPUT = ../src/client/pv \
../src/rpcService/pv \ ../src/rpcService/pv \
../src/utils/pv \ ../src/utils/pv \
../src/pva/pv \ ../src/pva/pv \
../src/remote/pv \
. .
# This tag can be used to specify the character encoding of the source files # This tag can be used to specify the character encoding of the source files

View File

@ -819,6 +819,7 @@ public:
}; };
struct PeerInfo; // see pv/security.h
class ChannelRequester; class ChannelRequester;
@ -1133,6 +1134,26 @@ public:
* @param connectionState The new connection state. * @param connectionState The new connection state.
*/ */
virtual void channelStateChange(Channel::shared_pointer const & channel, Channel::ConnectionState connectionState) = 0; virtual void channelStateChange(Channel::shared_pointer const & channel, Channel::ConnectionState connectionState) = 0;
/**
* @brief Return information on connected peer if applicable.
*
* A server-type ChannelProvider will use this method to discover if a remote client
* has provided credentials which may be used in access control decisions.
*
* Default implementation returns NULL.
*
* isConnected()==true and getPeerInfo()==NULL when the ChannelProvider does not provide
* information about the peer. This should be treated as an unauthenticated, anonymous,
* peer.
*
* The returned instance must not change, and a different instance should be returned
* if/when peer information changes (eg. after reconnect).
*
* May return !NULL when !isConnected(). getPeerInfo() must be called _before_
* testing isConnected() in situations where connection state is being polled.
*/
virtual std::tr1::shared_ptr<const PeerInfo> getPeerInfo();
}; };
//! Used when ChannelProvider::createChannel() is passed a NULL ChannelRequester //! Used when ChannelProvider::createChannel() is passed a NULL ChannelRequester

View File

@ -8,9 +8,11 @@
#include <epicsGuard.h> #include <epicsGuard.h>
#include <pv/reftrack.h> #include <pv/reftrack.h>
#include <pv/valueBuilder.h> #include <pv/valueBuilder.h>
#include <pv/epicsException.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include <pv/pvAccess.h> #include <pv/pvAccess.h>
#include <pv/security.h>
namespace pvd = epics::pvData; namespace pvd = epics::pvData;
@ -418,6 +420,11 @@ ChannelRequester::~ChannelRequester()
REFTRACE_DECREMENT(num_instances); REFTRACE_DECREMENT(num_instances);
} }
PeerInfo::const_shared_pointer ChannelRequester::getPeerInfo()
{
return PeerInfo::const_shared_pointer();
}
std::string DefaultChannelRequester::getRequesterName() { return "DefaultChannelRequester"; } std::string DefaultChannelRequester::getRequesterName() { return "DefaultChannelRequester"; }
void DefaultChannelRequester::channelCreated(const epics::pvData::Status& status, Channel::shared_pointer const & channel) void DefaultChannelRequester::channelCreated(const epics::pvData::Status& status, Channel::shared_pointer const & channel)

View File

@ -40,6 +40,8 @@ using namespace std;
using namespace epics::pvData; using namespace epics::pvData;
using namespace epics::pvAccess; using namespace epics::pvAccess;
typedef epicsGuard<epicsMutex> Guard;
namespace { namespace {
struct BreakTransport : TransportSender struct BreakTransport : TransportSender
{ {
@ -1087,15 +1089,11 @@ void BlockingTCPTransportCodec::internalClose()
Transport::shared_pointer thisSharedPtr = this->shared_from_this(); Transport::shared_pointer thisSharedPtr = this->shared_from_this();
_context->getTransportRegistry()->remove(thisSharedPtr); _context->getTransportRegistry()->remove(thisSharedPtr);
// TODO sync
if (_securitySession)
_securitySession->close();
if (IS_LOGGABLE(logLevelDebug)) if (IS_LOGGABLE(logLevelDebug))
{ {
LOG(logLevelDebug, LOG(logLevelDebug,
"TCP socket to %s is to be closed.", "TCP socket to %s is to be closed.",
inetAddressToString(_socketAddress).c_str()); _socketName.c_str());
} }
} }
@ -1244,7 +1242,6 @@ BlockingTCPTransportCodec::BlockingTCPTransportCodec(bool serverFlag, const Cont
ipAddrToDottedIP(&_socketAddress.ia, ipAddrStr, sizeof(ipAddrStr)); ipAddrToDottedIP(&_socketAddress.ia, ipAddrStr, sizeof(ipAddrStr));
_socketName = ipAddrStr; _socketName = ipAddrStr;
} }
} }
@ -1361,24 +1358,28 @@ bool BlockingTCPTransportCodec::verify(epics::pvData::int32 timeoutMs) {
} }
void BlockingTCPTransportCodec::verified(epics::pvData::Status const & status) { void BlockingTCPTransportCodec::verified(epics::pvData::Status const & status) {
epics::pvData::Lock lock(_verifiedMutex); epics::pvData::Lock lock(_mutex);
if (IS_LOGGABLE(logLevelDebug) && !status.isOK()) if (IS_LOGGABLE(logLevelDebug) && !status.isOK())
{ {
char ipAddrStr[48]; LOG(logLevelDebug, "Failed to verify connection to %s: %s.", _socketName.c_str(), status.getMessage().c_str());
ipAddrToDottedIP(&_socketAddress.ia, ipAddrStr, sizeof(ipAddrStr));
LOG(logLevelDebug, "Failed to verify connection to %s: %s.", ipAddrStr, status.getMessage().c_str());
// TODO stack dump
} }
_verified = status.isSuccess(); {
Guard G(_mutex);
_verified = status.isSuccess();
}
_verifiedEvent.signal(); _verifiedEvent.signal();
} }
void BlockingTCPTransportCodec::authNZMessage(epics::pvData::PVField::shared_pointer const & data) { void BlockingTCPTransportCodec::authNZMessage(epics::pvData::PVStructure::shared_pointer const & data) {
// TODO sync AuthenticationSession::shared_pointer sess;
if (_securitySession) {
_securitySession->messageReceived(data); Guard G(_mutex);
sess = _authSession;
}
if (sess)
sess->messageReceived(data);
else else
{ {
char ipAddrStr[48]; char ipAddrStr[48];
@ -1392,7 +1393,7 @@ class SecurityPluginMessageTransportSender : public TransportSender {
public: public:
POINTER_DEFINITIONS(SecurityPluginMessageTransportSender); POINTER_DEFINITIONS(SecurityPluginMessageTransportSender);
SecurityPluginMessageTransportSender(PVField::shared_pointer const & data) : SecurityPluginMessageTransportSender(PVStructure::const_shared_pointer const & data) :
_data(data) _data(data)
{ {
} }
@ -1405,11 +1406,10 @@ public:
} }
private: private:
PVField::shared_pointer _data; PVStructure::const_shared_pointer _data;
}; };
void BlockingTCPTransportCodec::sendSecurityPluginMessage(epics::pvData::PVField::shared_pointer const & data) { void BlockingTCPTransportCodec::sendSecurityPluginMessage(epics::pvData::PVStructure::const_shared_pointer const & data) {
// TODO not optimal since it allocates a new object every time
SecurityPluginMessageTransportSender::shared_pointer spmts(new SecurityPluginMessageTransportSender(data)); SecurityPluginMessageTransportSender::shared_pointer spmts(new SecurityPluginMessageTransportSender(data));
enqueueSendRequest(spmts); enqueueSendRequest(spmts);
} }
@ -1426,7 +1426,7 @@ BlockingServerTCPTransportCodec::BlockingServerTCPTransportCodec(
int32_t receiveBufferSize) : int32_t receiveBufferSize) :
BlockingTCPTransportCodec(true, context, channel, responseHandler, BlockingTCPTransportCodec(true, context, channel, responseHandler,
sendBufferSize, receiveBufferSize, PVA_DEFAULT_PRIORITY), sendBufferSize, receiveBufferSize, PVA_DEFAULT_PRIORITY),
_lastChannelSID(0), _verifyOrVerified(false), _securityRequired(false) _lastChannelSID(0), _verifyOrVerified(false)
{ {
// NOTE: priority not yet known, default priority is used to // NOTE: priority not yet known, default priority is used to
//register/unregister //register/unregister
@ -1530,29 +1530,38 @@ void BlockingServerTCPTransportCodec::send(ByteBuffer* buffer,
// TODO // TODO
buffer->putShort(0x7FFF); buffer->putShort(0x7FFF);
// list of authNZ plugin names // list of authNZ plugin names advertised to this client
const Context::securityPlugins_t& securityPlugins = _context->getSecurityPlugins();
vector<string> validSPNames;
validSPNames.reserve(securityPlugins.size());
for (Context::securityPlugins_t::const_iterator iter(securityPlugins.begin()); AuthenticationRegistry::list_t plugins;
iter != securityPlugins.end(); iter++) AuthenticationRegistry::servers().snapshot(plugins); // copy
std::vector<std::string> validSPNames;
validSPNames.reserve(plugins.size()); // assume all will be valid
PeerInfo info;
info.transport = "pva";
info.peer = _socketName;
info.transportVersion = this->getRevision();
// filter plugins which may be used by this peer
for(AuthenticationRegistry::list_t::iterator it(plugins.begin()), end(plugins.end());
it!=end; ++it)
{ {
SecurityPlugin::shared_pointer securityPlugin = iter->second; info.authority = it->first;
if (securityPlugin->isValidFor(_socketAddress)) if(it->second->isValidFor(info))
validSPNames.push_back(securityPlugin->getId()); validSPNames.push_back(it->first);
} }
size_t validSPCount = validSPNames.size(); SerializeHelper::writeSize(validSPNames.size(), buffer, this);
for (vector<string>::const_iterator iter(validSPNames.begin()), end(validSPNames.end());
SerializeHelper::writeSize(validSPCount, buffer, this); iter != end; iter++)
for (vector<string>::const_iterator iter = {
validSPNames.begin();
iter != validSPNames.end(); iter++)
SerializeHelper::serializeString(*iter, buffer, this); SerializeHelper::serializeString(*iter, buffer, this);
}
// TODO sync {
_securityRequired = (validSPCount > 0); Guard G(_mutex);
advertisedAuthPlugins.swap(validSPNames);
}
// send immediately // send immediately
control->flush(true); control->flush(true);
@ -1564,10 +1573,12 @@ void BlockingServerTCPTransportCodec::send(ByteBuffer* buffer,
// //
control->startMessage(CMD_CONNECTION_VALIDATED, 0); control->startMessage(CMD_CONNECTION_VALIDATED, 0);
pvData::Status sts;
{ {
Lock lock(_verificationStatusMutex); Lock lock(_mutex);
_verificationStatus.serialize(buffer, control); sts = _verificationStatus;
} }
sts.serialize(buffer, control);
// send immediately // send immediately
control->flush(true); control->flush(true);
@ -1600,14 +1611,25 @@ void BlockingServerTCPTransportCodec::internalClose() {
destroyAllChannels(); destroyAllChannels();
} }
void BlockingServerTCPTransportCodec::authenticationCompleted(epics::pvData::Status const & status) void BlockingServerTCPTransportCodec::authenticationCompleted(epics::pvData::Status const & status,
const std::tr1::shared_ptr<PeerInfo>& peer)
{ {
if (IS_LOGGABLE(logLevelDebug)) if (IS_LOGGABLE(logLevelDebug))
{ {
LOG(logLevelDebug, "Authentication completed with status '%s' for PVA client: %s.", Status::StatusTypeName[status.getType()], _socketName.c_str()); LOG(logLevelDebug, "Authentication completed with status '%s' for PVA client: %s.", Status::StatusTypeName[status.getType()], _socketName.c_str());
} }
if (!isVerified()) // TODO sync bool isVerified;
{
Guard G(_mutex);
isVerified = _verified;
if(status.isSuccess())
_peerInfo = peer;
else
_peerInfo.reset();
}
if (!isVerified)
verified(status); verified(status);
else if (!status.isSuccess()) else if (!status.isSuccess())
{ {
@ -1620,59 +1642,35 @@ void BlockingServerTCPTransportCodec::authenticationCompleted(epics::pvData::Sta
} }
} }
epics::pvData::Status BlockingServerTCPTransportCodec::invalidSecurityPluginNameStatus(Status::STATUSTYPE_ERROR, "invalid security plug-in name");
void BlockingServerTCPTransportCodec::authNZInitialize(const std::string& securityPluginName, void BlockingServerTCPTransportCodec::authNZInitialize(const std::string& securityPluginName,
const epics::pvData::PVField::shared_pointer& data) const epics::pvData::PVStructure::shared_pointer& data)
{ {
// check if plug-in name is valid AuthenticationPlugin::shared_pointer plugin(AuthenticationRegistry::servers().lookup(securityPluginName));
SecurityPlugin::shared_pointer securityPlugin; // attempting the force use of an un-advertised/non-existant plugin is treated as a protocol error.
// We cheat here by assuming the the registry doesn't often change after server start,
// and don't test if securityPluginName is in advertisedAuthPlugins
if(!plugin)
throw std::runtime_error(_socketName+" failing attempt to select non-existant auth. plugin "+securityPluginName);
Context::securityPlugins_t::const_iterator spIter(_context->getSecurityPlugins().find(securityPluginName)); PeerInfo::shared_pointer info(new PeerInfo);
if (spIter != _context->getSecurityPlugins().end()) info->peer = _socketName;
securityPlugin = spIter->second; info->transport = "pva";
if (!securityPlugin) info->transportVersion = getRevision();
{ info->authority = securityPluginName;
if (_securityRequired)
{
verified(invalidSecurityPluginNameStatus);
return;
}
else
{
securityPlugin = NoSecurityPlugin::INSTANCE;
if (IS_LOGGABLE(logLevelDebug)) if (!plugin->isValidFor(*info))
{ verified(pvData::Status::error("invalid security plug-in name"));
LOG(logLevelDebug, "No security plug-in installed, selecting default plug-in '%s' for PVA client: %s.", securityPlugin->getId().c_str(), _socketName.c_str());
}
}
}
if (!securityPlugin->isValidFor(_socketAddress))
verified(invalidSecurityPluginNameStatus);
if (IS_LOGGABLE(logLevelDebug)) if (IS_LOGGABLE(logLevelDebug))
{ {
char ipAddrStr[48]; LOG(logLevelDebug, "Accepted security plug-in '%s' for PVA client: %s.", securityPluginName.c_str(), _socketName.c_str());
ipAddrToDottedIP(&_socketAddress.ia, ipAddrStr, sizeof(ipAddrStr));
LOG(logLevelDebug, "Accepted security plug-in '%s' for PVA client: %s.", securityPluginName.c_str(), ipAddrStr);
} }
try AuthenticationSession::shared_pointer sess(plugin->createSession(info, shared_from_this(), data));
{
// create session Guard G(_mutex);
SecurityPluginControl::shared_pointer spc = std::tr1::dynamic_pointer_cast<SecurityPluginControl>(shared_from_this()); _authSessionName = securityPluginName;
// TODO sync _authSession.swap(sess);
_securitySession = securityPlugin->createSession(_socketAddress, spc, data);
} catch (SecurityException &se) {
if (IS_LOGGABLE(logLevelDebug))
{
LOG(logLevelDebug, "Security plug-in '%s' failed to create a session for PVA client: %s.", securityPluginName.c_str(), _socketName.c_str());
}
Status status(Status::STATUSTYPE_ERROR, se.what());
verified(status);
}
} }
@ -1894,17 +1892,25 @@ void BlockingClientTCPTransportCodec::send(ByteBuffer* buffer,
// QoS (aka connection priority) // QoS (aka connection priority)
buffer->putShort(getPriority()); buffer->putShort(getPriority());
// TODO sync std::string pluginName;
if (_securitySession) AuthenticationSession::shared_pointer session;
{
Guard G(_mutex);
pluginName = _authSessionName;
session = _authSession;
}
if (session)
{ {
// selected authNZ plug-in name // selected authNZ plug-in name
SerializeHelper::serializeString(_securitySession->getSecurityPlugin()->getId(), buffer, control); SerializeHelper::serializeString(_authSessionName, buffer, control);
// optional authNZ plug-in initialization data // optional authNZ plug-in initialization data
SerializationHelper::serializeFull(buffer, control, _securitySession->initializationData()); SerializationHelper::serializeFull(buffer, control, session->initializationData());
} }
else else
{ {
//TODO: allowed?
// emptry authNZ plug-in name // emptry authNZ plug-in name
SerializeHelper::serializeString("", buffer, control); SerializeHelper::serializeString("", buffer, control);
@ -1926,38 +1932,68 @@ void BlockingClientTCPTransportCodec::send(ByteBuffer* buffer,
void BlockingClientTCPTransportCodec::authNZInitialize(const std::vector<std::string>& offeredSecurityPlugins) void BlockingClientTCPTransportCodec::authNZInitialize(const std::vector<std::string>& offeredSecurityPlugins)
{ {
if (!offeredSecurityPlugins.empty()) AuthenticationRegistry& plugins = AuthenticationRegistry::clients();
std::string selectedName;
AuthenticationPlugin::shared_pointer plugin;
// because of a missing break; the original SecurityPlugin effectively treated the offered list as being
// in order of increasing preference (last is preferred).
// we continue with this because, hey isn't compatibility fun...
for(std::vector<std::string>::const_reverse_iterator it(offeredSecurityPlugins.rbegin()), end(offeredSecurityPlugins.rend());
it!=end; ++it)
{ {
const Context::securityPlugins_t& availableSecurityPlugins(_context->getSecurityPlugins()); plugin = plugins.lookup(*it);
if(plugin) {
for (vector<string>::const_iterator offeredSP = offeredSecurityPlugins.begin(); selectedName = *it;
offeredSP != offeredSecurityPlugins.end(); offeredSP++) break;
{
Context::securityPlugins_t::const_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());
}
}
} }
} }
if(!plugin) {
// mis-match and legacy. some early servers (java?) don't advertise any plugins.
// treat this as anonymous
selectedName = "anonymous";
plugin = plugins.lookup(selectedName);
assert(plugin); // fallback required
}
{
PeerInfo::shared_pointer info(new PeerInfo);
info->peer = _socketName; // this is the server name
info->transport = "pva";
info->transportVersion = getRevision();
info->authority = selectedName;
AuthenticationSession::shared_pointer sess(plugin->createSession(info, shared_from_this(), pvData::PVStructure::shared_pointer()));
Guard G(_mutex);
_authSessionName = selectedName;
_authSession = sess;
}
TransportSender::shared_pointer transportSender = std::tr1::dynamic_pointer_cast<TransportSender>(shared_from_this()); TransportSender::shared_pointer transportSender = std::tr1::dynamic_pointer_cast<TransportSender>(shared_from_this());
enqueueSendRequest(transportSender); enqueueSendRequest(transportSender);
} }
void BlockingClientTCPTransportCodec::authenticationCompleted(epics::pvData::Status const & status) void BlockingClientTCPTransportCodec::authenticationCompleted(epics::pvData::Status const & status,
const std::tr1::shared_ptr<PeerInfo>& peer)
{ {
// noop for client side (server will send ConnectionValidation message) // noop for client side (server will send ConnectionValidation message)
} }
void BlockingClientTCPTransportCodec::verified(epics::pvData::Status const & status)
{
AuthenticationSession::shared_pointer sess;
{
Guard G(_mutex);
sess = _authSession;
}
if(sess)
sess->authenticationComplete(status);
this->BlockingTCPTransportCodec::verified(status);
}
} }
} }
} }

View File

@ -124,14 +124,10 @@ public:
// noop // noop
} }
virtual void authNZMessage(epics::pvData::PVField::shared_pointer const & data) OVERRIDE FINAL { virtual void authNZMessage(epics::pvData::PVStructure::shared_pointer const & data) OVERRIDE FINAL {
// noop // noop
} }
virtual std::tr1::shared_ptr<SecuritySession> getSecuritySession() const OVERRIDE FINAL {
return std::tr1::shared_ptr<SecuritySession>();
}
// NOTE: this is not yet used for UDP // NOTE: this is not yet used for UDP
virtual void setByteOrder(int byteOrder) OVERRIDE FINAL { virtual void setByteOrder(int byteOrder) OVERRIDE FINAL {
// called from receive thread... or before processing // called from receive thread... or before processing

View File

@ -296,7 +296,7 @@ private:
class BlockingTCPTransportCodec: class BlockingTCPTransportCodec:
public AbstractCodec, public AbstractCodec,
public SecurityPluginControl, public AuthenticationPluginControl,
public std::tr1::enable_shared_from_this<BlockingTCPTransportCodec> public std::tr1::enable_shared_from_this<BlockingTCPTransportCodec>
{ {
@ -428,18 +428,9 @@ public:
virtual void verified(epics::pvData::Status const & status) OVERRIDE; virtual void verified(epics::pvData::Status const & status) OVERRIDE;
bool isVerified() const { virtual void authNZMessage(epics::pvData::PVStructure::shared_pointer const & data) OVERRIDE FINAL;
return _verified; // TODO sync
}
virtual std::tr1::shared_ptr<SecuritySession> getSecuritySession() const OVERRIDE FINAL { virtual void sendSecurityPluginMessage(epics::pvData::PVStructure::const_shared_pointer const & data) OVERRIDE FINAL;
// TODO sync
return _securitySession;
}
virtual void authNZMessage(epics::pvData::PVField::shared_pointer const & data) OVERRIDE FINAL;
virtual void sendSecurityPluginMessage(epics::pvData::PVField::shared_pointer const & data) OVERRIDE FINAL;
private: private:
void receiveThread(); void receiveThread();
@ -467,7 +458,12 @@ protected:
IntrospectionRegistry _incomingIR; IntrospectionRegistry _incomingIR;
IntrospectionRegistry _outgoingIR; IntrospectionRegistry _outgoingIR;
SecuritySession::shared_pointer _securitySession; // active authentication exchange, if any
std::string _authSessionName;
AuthenticationSession::shared_pointer _authSession;
public:
// final info, after authentication complete.
PeerInfo::const_shared_pointer _peerInfo;
private: private:
@ -476,9 +472,12 @@ private:
epics::pvData::int8 _remoteTransportRevision; epics::pvData::int8 _remoteTransportRevision;
epics::pvData::int16 _priority; epics::pvData::int16 _priority;
protected:
bool _verified; bool _verified;
epics::pvData::Mutex _verifiedMutex;
epics::pvData::Event _verifiedEvent; epics::pvData::Event _verifiedEvent;
public:
mutable epics::pvData::Mutex _mutex;
}; };
class BlockingServerTCPTransportCodec : class BlockingServerTCPTransportCodec :
@ -554,9 +553,10 @@ public:
} }
virtual void verified(epics::pvData::Status const & status) OVERRIDE FINAL { virtual void verified(epics::pvData::Status const & status) OVERRIDE FINAL {
_verificationStatusMutex.lock(); {
_verificationStatus = status; epicsGuard<epicsMutex> G(_mutex);
_verificationStatusMutex.unlock(); _verificationStatus = status;
}
BlockingTCPTransportCodec::verified(status); BlockingTCPTransportCodec::verified(status);
} }
@ -565,9 +565,10 @@ public:
} }
void authNZInitialize(const std::string& securityPluginName, void authNZInitialize(const std::string& securityPluginName,
const epics::pvData::PVField::shared_pointer& data); const epics::pvData::PVStructure::shared_pointer& data);
virtual void authenticationCompleted(epics::pvData::Status const & status) OVERRIDE FINAL; virtual void authenticationCompleted(epics::pvData::Status const & status,
const std::tr1::shared_ptr<PeerInfo>& peer) OVERRIDE FINAL;
virtual void send(epics::pvData::ByteBuffer* buffer, virtual void send(epics::pvData::ByteBuffer* buffer,
TransportSendControl* control) OVERRIDE FINAL; TransportSendControl* control) OVERRIDE FINAL;
@ -595,13 +596,10 @@ private:
mutable epics::pvData::Mutex _channelsMutex; mutable epics::pvData::Mutex _channelsMutex;
epics::pvData::Status _verificationStatus; epics::pvData::Status _verificationStatus;
epics::pvData::Mutex _verificationStatusMutex;
bool _verifyOrVerified; bool _verifyOrVerified;
bool _securityRequired; std::vector<std::string> advertisedAuthPlugins;
static epics::pvData::Status invalidSecurityPluginNameStatus;
}; };
@ -673,8 +671,10 @@ public:
void authNZInitialize(const std::vector<std::string>& offeredSecurityPlugins); void authNZInitialize(const std::vector<std::string>& offeredSecurityPlugins);
virtual void authenticationCompleted(epics::pvData::Status const & status) OVERRIDE FINAL; virtual void authenticationCompleted(epics::pvData::Status const & status,
const std::tr1::shared_ptr<PeerInfo>& peer) OVERRIDE FINAL;
virtual void verified(epics::pvData::Status const & status) OVERRIDE FINAL;
protected: protected:
virtual void internalClose() OVERRIDE FINAL; virtual void internalClose() OVERRIDE FINAL;
@ -719,8 +719,6 @@ private:
* Responsive transport notify. * Responsive transport notify.
*/ */
void responsiveTransport(); void responsiveTransport();
epics::pvData::Mutex _mutex;
}; };
} }

View File

@ -291,13 +291,12 @@ public:
* Pass data to the active security plug-in session. * Pass data to the active security plug-in session.
* @param data the data (any data), can be <code>null</code>. * @param data the data (any data), can be <code>null</code>.
*/ */
virtual void authNZMessage(epics::pvData::PVField::shared_pointer const & data) = 0; virtual void authNZMessage(epics::pvData::PVStructure::shared_pointer const & data) = 0;
virtual std::tr1::shared_ptr<SecuritySession> getSecuritySession() const = 0;
}; };
class Channel; class Channel;
class SecurityPlugin; class SecurityPlugin;
class AuthenticationRegistry;
/** /**
* Not public IF, used by Transports, etc. * Not public IF, used by Transports, etc.
@ -317,14 +316,6 @@ public:
virtual Configuration::const_shared_pointer getConfiguration() = 0; virtual Configuration::const_shared_pointer getConfiguration() = 0;
typedef std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> > securityPlugins_t;
/**
* Get map of available security plug-ins.
* @return the map of available security plug-ins
*/
virtual const securityPlugins_t& getSecurityPlugins() = 0;
/// ///
/// due to ClientContextImpl /// due to ClientContextImpl
/// ///

View File

@ -7,6 +7,72 @@
#ifndef SECURITY_H #ifndef SECURITY_H
#define SECURITY_H #define SECURITY_H
/** @page pva_security PVA Security
*
* Summary of PVA auth. process.
*
@msc
arcgradient = 8;
CP [label="Client Plugin"], CS [label="Client Session"], C [label="Client"], S [label="Server"], SS [label="Server Session"], SP [label="Server Plugin"];
C:>S [label="Opens TCP connection"];
S box SP [label="Server lists plugins"];
S=>SP [label="isValidFor()"];
C<:S [label="CONNECTION_VALIDATION"];
CP box C [label="Client lists plugins"];
CP box C [label="Client select plugin"];
CP<=C [label="createSession()"];
CP>>C [label="Returns Session"];
CS<=C [label="initializationData()"];
CS>>C [label="Initial payload"];
C:>S [label="CONNECTION_VALIDATION"];
S=>SP [label="createSession()"];
S<<SP [label="Returns Session"];
--- [label="Optional (Repeatable)"];
S<=SS [label="sendSecurityPluginMessage()"];
C<:S [label="AUTHZ"];
CS<=C [label="messageReceived()"];
...;
CS=>C [label="sendSecurityPluginMessage()"];
C:>S [label="AUTHZ"];
S=>SS [label="messageReceived()"];
...;
--- [label="Completion"];
S<=SS [label="authenticationCompleted()"];
C<:S [label="CONNECTION_VALIDATED"];
CS<=C [label="authenticationComplete()"];
@endmsc
*
* Ownership
*
@dot
digraph authplugin {
External;
AuthenticationRegistry [shape=box];
AuthenticationPlugin [shape=box];
AuthenticationPluginControl [shape=box];
AuthenticationSession [shape=box];
External -> AuthenticationRegistry;
AuthenticationRegistry -> AuthenticationPlugin;
External -> AuthenticationSession;
AuthenticationSession -> AuthenticationPluginControl [color=green, style=dashed];
External -> AuthenticationPluginControl;
AuthenticationPluginControl -> AuthenticationSession;
AuthenticationPlugin -> AuthenticationSession [style=dashed];
}
@enddot
*
* Locking
*
* All methods of AuthenticationSession are called from a single thread.
* Methods of AuthenticationPlugin and AuthenticationPluginControl can be called
* from any threads.
*
* AuthenticationPluginControl is an Operation, AuthenticationSession is a Requester.
* @see provider_roles_requester_locking
*/
#ifdef epicsExportSharedSymbols #ifdef epicsExportSharedSymbols
# define securityEpicsExportSharedSymbols # define securityEpicsExportSharedSymbols
# undef epicsExportSharedSymbols # undef epicsExportSharedSymbols
@ -14,6 +80,7 @@
#include <string> #include <string>
#include <osiSock.h> #include <osiSock.h>
#include <epicsMutex.h>
#include <pv/status.h> #include <pv/status.h>
#include <pv/pvData.h> #include <pv/pvData.h>
@ -34,426 +101,166 @@
namespace epics { namespace epics {
namespace pvAccess { namespace pvAccess {
// notify client only on demand, configurable via pvRequest /** @brief Information provded by a client to a server-type ChannelProvider.
// add the following method to ChannelRequest: *
// void credentialsChanged(std::vector<BitSet> credentials); * All peers must be identified by a peer name, which may be a network address (IP+port#) and transport.
* Peer names must be unique for a given transport.
*
* Transport names include:
*
* # "local" in-process client. Peer name is optional and arbitrary. Must set local flag.
* # "pva" PVA over TCP. Used by PVA client provider. Peer name is IP address and TCP port number as "XXX.XXX.XXX.XXX:YYYYY".
*
* Authority names include:
*
* "anonymous" - No credentials provided. Must not set identified flag.
* "plain" - Unauthenticated credential.
*/
struct epicsShareClass PeerInfo {
POINTER_DEFINITIONS(PeerInfo);
static size_t num_instances;
// pvAccess message: channel client id, ioid (if invalid then it's for channel) and array of bitSets std::string peer; //!< network address of remote peer. eg. "192.168.1.1:5075".
// or leave to the plugin? std::string transport; //!< transport protocol used eg. "pva". Must not be empty.
std::string authority; //!< authentication mechanism used. eg. "anonymous" or "gssapi". Must not be empty.
std::string realm; //!< scope of authority. eg. "mylab.gov"
std::string account; //!< aka. user name
//! NULL or extra authority specific information.
pvData::PVStructure::const_shared_pointer aux;
// when clients gets initial credentialsChanged call before create is called typedef std::set<std::string> roles_t;
// and then on each change //! Set of strings which may be used to modify access control decisions.
roles_t roles;
class epicsShareClass ChannelSecuritySession { unsigned transportVersion; //!< If applicable, the protocol minor version number
public:
POINTER_DEFINITIONS(ChannelSecuritySession);
virtual ~ChannelSecuritySession() {} // attributes for programatic consumption
bool local; //!< Short-hand for transport=="local"
bool identified; //!< Short-hand for authority!="anonymous"
/// closes this session PeerInfo();
virtual void close() = 0; virtual ~PeerInfo();
// 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; /** A particular authentication exchange. See AuthenticationPlugin::createSession()
*
class SecurityException: public std::runtime_error { * @note Must not hold a strong reference to AuthenticationPluginControl
public: */
explicit SecurityException(std::string const & what): std::runtime_error(what) {} class epicsShareClass AuthenticationSession
};
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
*
* @warning a Ref. loop is created if the SecuritySession stores a pointer to 'control'
*/
// 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
{ {
EPICS_NOT_COPYABLE(SecurityPluginRegistry)
public: public:
POINTER_DEFINITIONS(AuthenticationSession);
static SecurityPluginRegistry& instance() virtual ~AuthenticationSession();
{
static SecurityPluginRegistry thisInstance;
return thisInstance;
}
typedef std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> > securityPlugins_t; //! For client plugins only, call to find the payload returned with CONNECTION_VALIDATION.
//! May return NULL.
virtual epics::pvData::PVStructure::const_shared_pointer initializationData()
{ return epics::pvData::PVStructure::const_shared_pointer(); }
securityPlugins_t& getClientSecurityPlugins() //! Called when an AUTHZ message is recieved from the peer.
{ //! See AuthenticationPluginControl::sendSecurityPluginMessage().
return m_clientSecurityPlugins; //! callee accepts ownership of data, which will not be modified.
} virtual void messageReceived(epics::pvData::PVStructure::const_shared_pointer const & data) {}
securityPlugins_t& getServerSecurityPlugins() /** For client plugins only. Notification that server has declared the exchange complete.
{ * @param status Check Status::isSuccess()
return m_serverSecurityPlugins; * @param peer Final information about pe
} */
virtual void authenticationComplete(const epics::pvData::Status& status) {}
};
void installClientSecurityPlugin(std::tr1::shared_ptr<SecurityPlugin> plugin) //! Callbacks for use by AuthenticationSession
{ class epicsShareClass AuthenticationPluginControl
m_clientSecurityPlugins[plugin->getId()] = plugin; {
LOG(epics::pvAccess::logLevelDebug, "Client security plug-in '%s' installed.", plugin->getId().c_str()); public:
} POINTER_DEFINITIONS(AuthenticationPluginControl);
virtual ~AuthenticationPluginControl();
void installServerSecurityPlugin(std::tr1::shared_ptr<SecurityPlugin> plugin) //! Send AUTHZ to peer with payload.
{ //! caller gives up ownership of data, which must not be modified.
m_serverSecurityPlugins[plugin->getId()] = plugin; virtual void sendSecurityPluginMessage(epics::pvData::PVStructure::const_shared_pointer const & data) = 0;
LOG(epics::pvAccess::logLevelDebug, "Server security plug-in '%s' installed.", plugin->getId().c_str());
} /** Called by server plugin to indicate the the exchange has completed.
*
* @param status If !status.isSuccess() then the connection will be closed without being used.
* @param peer Partially initialized PeerInfo. See AuthenticationPlugin::createSession().
* PeerInfo::realm and/or PeerInfo::account will now be considered valid.
* Caller transfers ownership to callee, which may modify.
*/
virtual void authenticationCompleted(const epics::pvData::Status& status,
const std::tr1::shared_ptr<PeerInfo>& peer) = 0;
};
//! Actor through which authentication exchanges are initiated.
class epicsShareClass AuthenticationPlugin
{
public:
POINTER_DEFINITIONS(AuthenticationPlugin);
virtual ~AuthenticationPlugin();
/** Allow this plugin to be advertised to a particular peer.
*
* At this point the PeerInfo has only been partially initialized with
* transport/protocol specific information: PeerInfo::peer, PeerInfo::transport, and PeerInfo::transportVersion.
*/
virtual bool isValidFor(const PeerInfo& peer) const { return true; }
/** Begin a new session with a peer.
*
* @param peer Partially initialized PeerInfo. See isValidFor().
* PeerInfo::authority is also set.
* Caller transfers ownership to callee, which may modify.
* @param control callee uses to asynchronously continue, and complete the session.
* @param data Always NULL for client-type plugins. For server-type plugins,
* the result of initializationData() from the peer
*/
virtual std::tr1::shared_ptr<AuthenticationSession> createSession(
const std::tr1::shared_ptr<PeerInfo>& peer,
std::tr1::shared_ptr<AuthenticationPluginControl> const & control,
epics::pvData::PVStructure::shared_pointer const & data) = 0;
};
/** Registry(s) for plugins
*/
class epicsShareClass AuthenticationRegistry
{
EPICS_NOT_COPYABLE(AuthenticationRegistry) // would need locking
public:
POINTER_DEFINITIONS(AuthenticationRegistry);
private: private:
SecurityPluginRegistry(); typedef std::map<int, std::pair<std::string, AuthenticationPlugin::shared_pointer> > map_t;
map_t map;
mutable epicsMutex mutex;
public:
typedef std::vector<map_t::mapped_type> list_t;
securityPlugins_t m_clientSecurityPlugins; //! The client side of the conversation
securityPlugins_t m_serverSecurityPlugins; static AuthenticationRegistry& clients();
//! The server side of the conversation
static AuthenticationRegistry& servers();
AuthenticationRegistry() {}
~AuthenticationRegistry();
//! Save a copy of the current registry in order of increasing priority
void snapshot(list_t& plugmap) const;
/** @brief Add a new plugin to this registry.
*
@param prio Order in which plugins are considered. highest is preferred.
@param name Name under which this plugin will be known
@param plugin Plugin instance
*/
void add(int prio, const std::string& name, const AuthenticationPlugin::shared_pointer& plugin);
//! Remove an existing entry. Remove true if the entry was actually removed.
bool remove(const AuthenticationPlugin::shared_pointer& plugin);
//! Fetch a single plugin explicitly by name.
//! @returns NULL if no entry for this name is available.
AuthenticationPlugin::shared_pointer lookup(const std::string& name) const;
}; };
} }

View File

@ -82,7 +82,7 @@ public:
* Serialize optional PVField. * Serialize optional PVField.
* @param buffer data buffer. * @param buffer data buffer.
*/ */
static void serializeFull(epics::pvData::ByteBuffer* buffer, epics::pvData::SerializableControl* control, epics::pvData::PVField::shared_pointer const & pvField); static void serializeFull(epics::pvData::ByteBuffer* buffer, epics::pvData::SerializableControl* control, const epics::pvData::PVField::const_shared_pointer &pvField);
}; };

View File

@ -6,51 +6,223 @@
#include <osiProcess.h> #include <osiProcess.h>
#include <epicsThread.h>
#include <epicsGuard.h>
#include <pv/epicsException.h>
#include <pv/reftrack.h>
#define epicsExportSharedSymbols #define epicsExportSharedSymbols
#include <pv/securityImpl.h> #include <pv/securityImpl.h>
using namespace epics::pvData; typedef epicsGuard<epicsMutex> Guard;
using namespace epics::pvAccess;
NoSecurityPlugin::shared_pointer NoSecurityPlugin::INSTANCE(new NoSecurityPlugin()); namespace {
namespace pvd = epics::pvData;
namespace pva = epics::pvAccess;
CAClientSecurityPlugin::shared_pointer CAClientSecurityPlugin::INSTANCE(new CAClientSecurityPlugin());
CAClientSecurityPlugin::CAClientSecurityPlugin() pvd::StructureConstPtr userAndHostStructure(
pvd::FieldBuilder::begin()->
add("user", pvd::pvString)->
add("host", pvd::pvString)->
createStructure()
);
struct SimpleSession : public pva::AuthenticationSession
{ {
StructureConstPtr userAndHostStructure = const pvd::PVStructure::const_shared_pointer initdata;
getFieldCreate()->createFieldBuilder()->
add("user", pvString)->
add("host", pvString)->
createStructure();
m_userAndHost = getPVDataCreate()->createPVStructure(userAndHostStructure); SimpleSession(const pvd::PVStructure::const_shared_pointer& data) :initdata(data) {}
virtual ~SimpleSession() {}
// virtual epics::pvData::PVStructure::const_shared_pointer initializationData() OVERRIDE FINAL
// user name { return initdata; }
// };
char buffer[256]; struct AnonPlugin : public pva::AuthenticationPlugin
{
const bool server;
std::string userName; AnonPlugin(bool server) :server(server) {}
if (osiGetUserName(buffer, sizeof(buffer)) == osiGetUserNameSuccess) virtual ~AnonPlugin() {}
userName = buffer;
// TODO more error handling
m_userAndHost->getSubFieldT<PVString>("user")->put(userName); virtual std::tr1::shared_ptr<pva::AuthenticationSession> createSession(
const std::tr1::shared_ptr<pva::PeerInfo>& peer,
std::tr1::shared_ptr<pva::AuthenticationPluginControl> const & control,
epics::pvData::PVStructure::shared_pointer const & data) OVERRIDE FINAL
{
std::tr1::shared_ptr<SimpleSession> sess(new SimpleSession(pvd::PVStructure::const_shared_pointer())); // no init data
if(server) {
peer->identified = false;
peer->account = "anonymous";
control->authenticationCompleted(pvd::Status::Ok, peer);
}
return sess;
}
};
// struct CAPlugin : public pva::AuthenticationPlugin
// host name {
// const bool server;
// fully const after ctor
const pvd::PVStructurePtr user;
std::string hostName; CAPlugin(bool server)
if (gethostname(buffer, sizeof(buffer)) == 0) :server(server)
hostName = buffer; ,user(userAndHostStructure->build())
// TODO more error handling {
std::vector<char> buffer(256u);
if(osiGetUserName(&buffer[0], buffer.size()) != osiGetUserNameSuccess)
throw std::runtime_error("Unable to determine user account name");
m_userAndHost->getSubFieldT<PVString>("host")->put(buffer); buffer[buffer.size()-1] = '\0';
user->getSubFieldT<pvd::PVString>("user")->put(&buffer[0]);
// use of unverified host name is considered deprecated.
// use PeerInfo::peer instead.
if (gethostname(&buffer[0], buffer.size()) != 0)
throw std::runtime_error("Unable to determine host name");
buffer[buffer.size()-1] = '\0';
user->getSubFieldT<pvd::PVString>("host")->put(&buffer[0]);
}
virtual ~CAPlugin() {}
virtual std::tr1::shared_ptr<pva::AuthenticationSession> createSession(
const std::tr1::shared_ptr<pva::PeerInfo>& peer,
std::tr1::shared_ptr<pva::AuthenticationPluginControl> const & control,
epics::pvData::PVStructure::shared_pointer const & data) OVERRIDE FINAL
{
std::tr1::shared_ptr<SimpleSession> sess(new SimpleSession(user)); // no init data
if(server) {
peer->identified = true;
peer->account = data->getSubFieldT<pvd::PVString>("user")->get();
peer->aux = pvd::getPVDataCreate()->createPVStructure(data); // clone to ensure it won't be modified
control->authenticationCompleted(pvd::Status::Ok, peer);
}
return sess;
}
};
} // namespace
namespace epics {
namespace pvAccess {
size_t PeerInfo::num_instances;
PeerInfo::PeerInfo()
:transportVersion(0u)
,local(false)
,identified(false)
{
REFTRACE_INCREMENT(num_instances);
} }
PeerInfo::~PeerInfo()
{
REFTRACE_DECREMENT(num_instances);
}
AuthenticationSession::~AuthenticationSession() {}
AuthenticationPluginControl::~AuthenticationPluginControl() {}
AuthenticationPlugin::~AuthenticationPlugin() {}
AuthenticationRegistry::~AuthenticationRegistry() {}
namespace {
struct authGbl_t {
mutable epicsMutex mutex;
AuthenticationRegistry servers, clients;
} *authGbl;
void authGblInit(void *)
{
authGbl = new authGbl_t;
{
AnonPlugin::shared_pointer plugin(new AnonPlugin(true));
authGbl->servers.add(-1024, "anonymous", plugin);
}
{
AnonPlugin::shared_pointer plugin(new AnonPlugin(false));
authGbl->clients.add(-1024, "anonymous", plugin);
}
{
CAPlugin::shared_pointer plugin(new CAPlugin(true));
authGbl->servers.add(0, "ca", plugin);
}
{
CAPlugin::shared_pointer plugin(new CAPlugin(false));
authGbl->clients.add(0, "ca", plugin);
}
epics::registerRefCounter("PeerInfo", &PeerInfo::num_instances);
}
epicsThreadOnceId authGblOnce = EPICS_THREAD_ONCE_INIT;
} // namespace
AuthenticationRegistry& AuthenticationRegistry::clients()
{
epicsThreadOnce(&authGblOnce, &authGblInit, 0);
assert(authGbl);
return authGbl->clients;
}
AuthenticationRegistry& AuthenticationRegistry::servers()
{
epicsThreadOnce(&authGblOnce, &authGblInit, 0);
assert(authGbl);
return authGbl->servers;
}
void AuthenticationRegistry::snapshot(list_t &plugmap) const
{
plugmap.clear();
Guard G(mutex);
plugmap.reserve(map.size());
for(map_t::const_iterator it(map.begin()), end(map.end()); it!=end; ++it) {
plugmap.push_back(it->second);
}
}
void AuthenticationRegistry::add(int prio, const std::string& name,
const AuthenticationPlugin::shared_pointer& plugin)
{
Guard G(mutex);
if(map.find(prio)!=map.end())
THROW_EXCEPTION2(std::logic_error, "Authentication plugin already registered with this priority");
map[prio] = std::make_pair(name, plugin);
}
bool AuthenticationRegistry::remove(const AuthenticationPlugin::shared_pointer& plugin)
{
Guard G(mutex);
for(map_t::iterator it(map.begin()), end(map.end()); it!=end; ++it) {
if(it->second.second==plugin) {
map.erase(it);
return true;
}
}
return false;
}
AuthenticationPlugin::shared_pointer AuthenticationRegistry::lookup(const std::string& name) const
{
Guard G(mutex);
// assuming the number of plugins is small, we don't index by name.
for(map_t::const_iterator it(map.begin()), end(map.end()); it!=end; ++it) {
if(it->second.first==name)
return it->second.second;
}
return AuthenticationPlugin::shared_pointer();
}
void AuthNZHandler::handleResponse(osiSockAddr* responseFrom, void AuthNZHandler::handleResponse(osiSockAddr* responseFrom,
Transport::shared_pointer const & transport, Transport::shared_pointer const & transport,
@ -61,15 +233,17 @@ void AuthNZHandler::handleResponse(osiSockAddr* responseFrom,
{ {
ResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); ResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer);
epics::pvData::PVField::shared_pointer data = pvd::PVStructure::shared_pointer data;
SerializationHelper::deserializeFull(payloadBuffer, transport.get()); {
pvd::PVField::shared_pointer raw(SerializationHelper::deserializeFull(payloadBuffer, transport.get()));
if(raw->getField()->getType()==pvd::structure) {
data = std::tr1::static_pointer_cast<pvd::PVStructure>(raw);
} else {
// was originally possible, but never used
}
}
transport->authNZMessage(data); transport->authNZMessage(data);
} }
SecurityPluginRegistry::SecurityPluginRegistry() { }} // namespace epics::pvAccess
// install CA client security plugin by default
installClientSecurityPlugin(CAClientSecurityPlugin::INSTANCE);
}

View File

@ -81,7 +81,7 @@ void SerializationHelper::serializeStructureFull(ByteBuffer* buffer, Serializabl
serializeFull(buffer, control, pvStructure); serializeFull(buffer, control, pvStructure);
} }
void SerializationHelper::serializeFull(ByteBuffer* buffer, SerializableControl* control, PVField::shared_pointer const & pvField) void SerializationHelper::serializeFull(ByteBuffer* buffer, SerializableControl* control, PVField::const_shared_pointer const & pvField)
{ {
if (!pvField) if (!pvField)
{ {

View File

@ -4164,9 +4164,6 @@ private:
m_channelSearchManager.reset(new ChannelSearchManager(thisPointer)); m_channelSearchManager.reset(new ChannelSearchManager(thisPointer));
// preinitialize security plugins
SecurityPluginRegistry::instance();
// TODO put memory barrier here... (if not already called within a lock?) // TODO put memory barrier here... (if not already called within a lock?)
// setup UDP transport // setup UDP transport
@ -4448,11 +4445,6 @@ private:
} }
} }
const securityPlugins_t& getSecurityPlugins() OVERRIDE FINAL
{
return SecurityPluginRegistry::instance().getClientSecurityPlugins();
}
/** /**
* Get channel search manager. * Get channel search manager.
* @return channel search manager. * @return channel search manager.

View File

@ -201,14 +201,15 @@ public:
protected: protected:
ServerChannelRequesterImpl(Transport::shared_pointer const & transport, ServerChannelRequesterImpl(Transport::shared_pointer const & transport,
const std::string channelName, const std::string channelName,
const pvAccessID cid, ChannelSecuritySession::shared_pointer const & css); const pvAccessID cid);
public: public:
virtual ~ServerChannelRequesterImpl() {} virtual ~ServerChannelRequesterImpl() {}
static ChannelRequester::shared_pointer create(ChannelProvider::shared_pointer const & provider, static ChannelRequester::shared_pointer create(ChannelProvider::shared_pointer const & provider,
Transport::shared_pointer const & transport, const std::string channelName, Transport::shared_pointer const & transport, const std::string channelName,
const pvAccessID cid, ChannelSecuritySession::shared_pointer const & css); const pvAccessID cid);
virtual void channelCreated(const epics::pvData::Status& status, Channel::shared_pointer const & channel) OVERRIDE FINAL; virtual void channelCreated(const epics::pvData::Status& status, Channel::shared_pointer const & channel) OVERRIDE FINAL;
virtual void channelStateChange(Channel::shared_pointer const & c, const Channel::ConnectionState isConnected) OVERRIDE FINAL; virtual void channelStateChange(Channel::shared_pointer const & c, const Channel::ConnectionState isConnected) OVERRIDE FINAL;
virtual std::tr1::shared_ptr<const PeerInfo> getPeerInfo() OVERRIDE FINAL;
virtual std::string getRequesterName() OVERRIDE FINAL; virtual std::string getRequesterName() OVERRIDE FINAL;
virtual void message(std::string const & message, epics::pvData::MessageType messageType) OVERRIDE FINAL; virtual void message(std::string const & message, epics::pvData::MessageType messageType) OVERRIDE FINAL;
virtual void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) OVERRIDE FINAL; virtual void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) OVERRIDE FINAL;
@ -217,7 +218,6 @@ private:
std::tr1::weak_ptr<detail::BlockingServerTCPTransportCodec> _transport; std::tr1::weak_ptr<detail::BlockingServerTCPTransportCodec> _transport;
const std::string _channelName; const std::string _channelName;
const pvAccessID _cid; const pvAccessID _cid;
ChannelSecuritySession::shared_pointer const & _css;
epics::pvData::Status _status; epics::pvData::Status _status;
epics::pvData::Mutex _mutex; epics::pvData::Mutex _mutex;
}; };

View File

@ -33,8 +33,7 @@ public:
*/ */
ServerChannel(Channel::shared_pointer const & channel, ServerChannel(Channel::shared_pointer const & channel,
const ChannelRequester::shared_pointer& requester, const ChannelRequester::shared_pointer& requester,
pvAccessID cid, pvAccessID sid, pvAccessID cid, pvAccessID sid);
ChannelSecuritySession::shared_pointer const & css);
~ServerChannel(); ~ServerChannel();
const Channel::shared_pointer& getChannel() const { return _channel; } const Channel::shared_pointer& getChannel() const { return _channel; }
@ -43,9 +42,6 @@ public:
pvAccessID getSID() const { return _sid; } pvAccessID getSID() const { return _sid; }
ChannelSecuritySession::shared_pointer getChannelSecuritySession() const
{ return _channelSecuritySession; }
void registerRequest(pvAccessID id, const std::tr1::shared_ptr<BaseChannelRequester>& request); void registerRequest(pvAccessID id, const std::tr1::shared_ptr<BaseChannelRequester>& request);
void unregisterRequest(pvAccessID id); void unregisterRequest(pvAccessID id);
@ -77,8 +73,6 @@ private:
bool _destroyed; bool _destroyed;
mutable epics::pvData::Mutex _mutex; mutable epics::pvData::Mutex _mutex;
const ChannelSecuritySession::shared_pointer _channelSecuritySession;
}; };
} }

View File

@ -51,7 +51,6 @@ public:
Transport::shared_pointer getSearchTransport() OVERRIDE FINAL; Transport::shared_pointer getSearchTransport() OVERRIDE FINAL;
Configuration::const_shared_pointer getConfiguration() OVERRIDE FINAL; Configuration::const_shared_pointer getConfiguration() OVERRIDE FINAL;
TransportRegistry* getTransportRegistry() OVERRIDE FINAL; TransportRegistry* getTransportRegistry() OVERRIDE FINAL;
const securityPlugins_t& getSecurityPlugins() OVERRIDE FINAL;
virtual void newServerDetected() OVERRIDE FINAL; virtual void newServerDetected() OVERRIDE FINAL;

View File

@ -194,15 +194,30 @@ void ServerConnectionValidationHandler::handleResponse(
std::string securityPluginName = SerializeHelper::deserializeString(payloadBuffer, transport.get()); std::string securityPluginName = SerializeHelper::deserializeString(payloadBuffer, transport.get());
// optional authNZ plug-in initialization data // optional authNZ plug-in initialization data
PVField::shared_pointer data; PVStructure::shared_pointer data;
if (payloadBuffer->getRemaining()) if (payloadBuffer->getRemaining()) {
data = SerializationHelper::deserializeFull(payloadBuffer, transport.get()); PVField::shared_pointer raw(SerializationHelper::deserializeFull(payloadBuffer, transport.get()));
if(raw && raw->getField()->getType()==structure) {
data = std::tr1::static_pointer_cast<PVStructure>(raw);
} else {
// was originally allowed, but never used
}
}
detail::BlockingServerTCPTransportCodec* casTransport(static_cast<detail::BlockingServerTCPTransportCodec*>(transport.get())); detail::BlockingServerTCPTransportCodec* casTransport(static_cast<detail::BlockingServerTCPTransportCodec*>(transport.get()));
//TODO: simplify byzantine class heirarchy... //TODO: simplify byzantine class heirarchy...
assert(casTransport); assert(casTransport);
casTransport->authNZInitialize(securityPluginName, data); try {
casTransport->authNZInitialize(securityPluginName, data);
}catch(std::exception& e){
if (IS_LOGGABLE(logLevelDebug))
{
LOG(logLevelDebug, "Security plug-in '%s' failed to create a session for PVA client: %s.", securityPluginName.c_str(), casTransport->getRemoteName().c_str());
}
casTransport->verified(pvData::Status::error(e.what()));
throw;
}
} }
@ -732,30 +747,13 @@ void ServerCreateChannelHandler::handleResponse(osiSockAddr* responseFrom,
return; return;
} }
SecuritySession::shared_pointer securitySession = transport->getSecuritySession();
ChannelSecuritySession::shared_pointer css;
try {
css = securitySession->createChannelSession(channelName);
if (!css)
throw SecurityException("null channelSecuritySession");
} catch (SecurityException& se) {
// TODO use std::make_shared
std::tr1::shared_ptr<ServerChannelRequesterImpl> tp(new ServerChannelRequesterImpl(transport, channelName, cid, css));
ChannelRequester::shared_pointer cr = tp;
Status asStatus(Status::STATUSTYPE_ERROR,
string("Insufficient rights to create a channel: ") + se.what());
cr->channelCreated(asStatus, Channel::shared_pointer());
return;
}
if (channelName == SERVER_CHANNEL_NAME) if (channelName == SERVER_CHANNEL_NAME)
{ {
// TODO singleton!!! // TODO singleton!!!
ServerRPCService::shared_pointer serverRPCService(new ServerRPCService(_context)); ServerRPCService::shared_pointer serverRPCService(new ServerRPCService(_context));
// TODO use std::make_shared // TODO use std::make_shared
std::tr1::shared_ptr<ServerChannelRequesterImpl> tp(new ServerChannelRequesterImpl(transport, channelName, cid, css)); std::tr1::shared_ptr<ServerChannelRequesterImpl> tp(new ServerChannelRequesterImpl(transport, channelName, cid));
ChannelRequester::shared_pointer cr = tp; ChannelRequester::shared_pointer cr = tp;
Channel::shared_pointer serverChannel = createRPCChannel(ChannelProvider::shared_pointer(), channelName, cr, serverRPCService); Channel::shared_pointer serverChannel = createRPCChannel(ChannelProvider::shared_pointer(), channelName, cr, serverRPCService);
cr->channelCreated(Status::Ok, serverChannel); cr->channelCreated(Status::Ok, serverChannel);
@ -766,7 +764,7 @@ void ServerCreateChannelHandler::handleResponse(osiSockAddr* responseFrom,
ServerContextImpl::s_channelNameToProvider_t::const_iterator it; ServerContextImpl::s_channelNameToProvider_t::const_iterator it;
if (_providers.size() == 1) if (_providers.size() == 1)
ServerChannelRequesterImpl::create(_providers[0], transport, channelName, cid, css); ServerChannelRequesterImpl::create(_providers[0], transport, channelName, cid);
else { else {
ChannelProvider::shared_pointer prov; ChannelProvider::shared_pointer prov;
{ {
@ -775,7 +773,7 @@ void ServerCreateChannelHandler::handleResponse(osiSockAddr* responseFrom,
prov = it->second.lock(); prov = it->second.lock();
} }
if(prov) if(prov)
ServerChannelRequesterImpl::create(prov, transport, channelName, cid, css); ServerChannelRequesterImpl::create(prov, transport, channelName, cid);
} }
} }
} }
@ -786,12 +784,11 @@ void ServerCreateChannelHandler::disconnect(Transport::shared_pointer const & tr
} }
ServerChannelRequesterImpl::ServerChannelRequesterImpl(const Transport::shared_pointer &transport, ServerChannelRequesterImpl::ServerChannelRequesterImpl(const Transport::shared_pointer &transport,
const string channelName, const pvAccessID cid, ChannelSecuritySession::shared_pointer const & css) : const string channelName, const pvAccessID cid) :
_serverChannel(), _serverChannel(),
_transport(std::tr1::static_pointer_cast<detail::BlockingServerTCPTransportCodec>(transport)), _transport(std::tr1::static_pointer_cast<detail::BlockingServerTCPTransportCodec>(transport)),
_channelName(channelName), _channelName(channelName),
_cid(cid), _cid(cid),
_css(css),
_status(), _status(),
_mutex() _mutex()
{ {
@ -799,10 +796,10 @@ ServerChannelRequesterImpl::ServerChannelRequesterImpl(const Transport::shared_p
ChannelRequester::shared_pointer ServerChannelRequesterImpl::create( ChannelRequester::shared_pointer ServerChannelRequesterImpl::create(
ChannelProvider::shared_pointer const & provider, Transport::shared_pointer const & transport, ChannelProvider::shared_pointer const & provider, Transport::shared_pointer const & transport,
const string channelName, const pvAccessID cid, ChannelSecuritySession::shared_pointer const & css) const string channelName, const pvAccessID cid)
{ {
// TODO use std::make_shared // TODO use std::make_shared
std::tr1::shared_ptr<ServerChannelRequesterImpl> tp(new ServerChannelRequesterImpl(transport, channelName, cid, css)); std::tr1::shared_ptr<ServerChannelRequesterImpl> tp(new ServerChannelRequesterImpl(transport, channelName, cid));
ChannelRequester::shared_pointer cr = tp; ChannelRequester::shared_pointer cr = tp;
// TODO exception guard and report error back // TODO exception guard and report error back
provider->createChannel(channelName, cr, transport->getPriority()); provider->createChannel(channelName, cr, transport->getPriority());
@ -824,7 +821,7 @@ void ServerChannelRequesterImpl::channelCreated(const Status& status, Channel::s
pvAccessID sid = transport->preallocateChannelSID(); pvAccessID sid = transport->preallocateChannelSID();
try try
{ {
serverChannel.reset(new ServerChannel(channel, shared_from_this(), _cid, sid, _css)); serverChannel.reset(new ServerChannel(channel, shared_from_this(), _cid, sid));
// ack allocation and register // ack allocation and register
transport->registerChannel(sid, serverChannel); transport->registerChannel(sid, serverChannel);
@ -836,11 +833,6 @@ void ServerChannelRequesterImpl::channelCreated(const Status& status, Channel::s
throw; throw;
} }
} }
else
{
if (_css)
_css->close();
}
{ {
@ -861,9 +853,6 @@ void ServerChannelRequesterImpl::channelCreated(const Status& status, Channel::s
} }
TransportSender::shared_pointer thisSender = shared_from_this(); TransportSender::shared_pointer thisSender = shared_from_this();
transport->enqueueSendRequest(thisSender); transport->enqueueSendRequest(thisSender);
// TODO make sure that serverChannel gets destroyed
if (_css)
_css->close();
} }
catch (...) catch (...)
{ {
@ -874,9 +863,6 @@ void ServerChannelRequesterImpl::channelCreated(const Status& status, Channel::s
} }
TransportSender::shared_pointer thisSender = shared_from_this(); TransportSender::shared_pointer thisSender = shared_from_this();
transport->enqueueSendRequest(thisSender); transport->enqueueSendRequest(thisSender);
// TODO make sure that serverChannel gets destroyed
if (_css)
_css->close();
} }
} }
} }
@ -909,6 +895,17 @@ void ServerChannelRequesterImpl::channelStateChange(Channel::shared_pointer cons
} }
} }
std::tr1::shared_ptr<const PeerInfo> ServerChannelRequesterImpl::getPeerInfo()
{
if(detail::BlockingServerTCPTransportCodec::shared_pointer transport = _transport.lock()) {
epicsGuard<epicsMutex> G(transport->_mutex);
return transport->_peerInfo;
} else {
return std::tr1::shared_ptr<const PeerInfo>();
}
}
string ServerChannelRequesterImpl::getRequesterName() string ServerChannelRequesterImpl::getRequesterName()
{ {
detail::BlockingServerTCPTransportCodec::shared_pointer transport = _transport.lock(); detail::BlockingServerTCPTransportCodec::shared_pointer transport = _transport.lock();

View File

@ -18,14 +18,12 @@ size_t ServerChannel::num_instances;
ServerChannel::ServerChannel(Channel::shared_pointer const & channel, ServerChannel::ServerChannel(Channel::shared_pointer const & channel,
const ChannelRequester::shared_pointer &requester, const ChannelRequester::shared_pointer &requester,
pvAccessID cid, pvAccessID sid, pvAccessID cid, pvAccessID sid):
ChannelSecuritySession::shared_pointer const & css):
_channel(channel), _channel(channel),
_requester(requester), _requester(requester),
_cid(cid), _cid(cid),
_sid(sid), _sid(sid),
_destroyed(false), _destroyed(false)
_channelSecuritySession(css)
{ {
REFTRACE_INCREMENT(num_instances); REFTRACE_INCREMENT(num_instances);
if (!channel.get()) if (!channel.get())
@ -76,10 +74,6 @@ void ServerChannel::destroy()
// removal via unregisterRequest() during iteration // removal via unregisterRequest() during iteration
_requests.swap(reqs); _requests.swap(reqs);
// close channel security session
// TODO try catch
_channelSecuritySession->close();
// ... and the channel // ... and the channel
// TODO try catch // TODO try catch
_channel->destroy(); _channel->destroy();

View File

@ -533,12 +533,6 @@ epicsTimeStamp& ServerContextImpl::getStartTime()
return _startTime; return _startTime;
} }
const Context::securityPlugins_t& ServerContextImpl::getSecurityPlugins()
{
return SecurityPluginRegistry::instance().getServerSecurityPlugins();
}
ServerContext::shared_pointer startPVAServer(std::string const & providerNames, int timeToRun, bool runInSeparateThread, bool printInfo) ServerContext::shared_pointer startPVAServer(std::string const & providerNames, int timeToRun, bool runInSeparateThread, bool printInfo)
{ {
ServerContext::shared_pointer ret(ServerContext::create(ServerContext::Config() ServerContext::shared_pointer ret(ServerContext::create(ServerContext::Config()

View File

@ -396,13 +396,7 @@ public:
void aliveNotification() {} void aliveNotification() {}
void authNZMessage(epics::pvData::PVField::shared_pointer const & data) {} void authNZMessage(epics::pvData::PVStructure::shared_pointer const & data) {}
virtual std::tr1::shared_ptr<SecuritySession> getSecuritySession() const
{
return std::tr1::shared_ptr<SecuritySession>();
}
bool isClosed() { bool isClosed() {