Break up monolithic SecurityPlugin API into three parts. 1. Authentication. 2. Authorization. 3. Access Control decision. Left to ChannelProviders
270 lines
9.5 KiB
C++
270 lines
9.5 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
|
|
|
|
/** @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
|
|
# define securityEpicsExportSharedSymbols
|
|
# undef epicsExportSharedSymbols
|
|
#endif
|
|
|
|
#include <string>
|
|
#include <osiSock.h>
|
|
#include <epicsMutex.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 {
|
|
|
|
/** @brief Information provded by a client to a server-type ChannelProvider.
|
|
*
|
|
* 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;
|
|
|
|
std::string peer; //!< network address of remote peer. eg. "192.168.1.1:5075".
|
|
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;
|
|
|
|
typedef std::set<std::string> roles_t;
|
|
//! Set of strings which may be used to modify access control decisions.
|
|
roles_t roles;
|
|
|
|
unsigned transportVersion; //!< If applicable, the protocol minor version number
|
|
|
|
// attributes for programatic consumption
|
|
bool local; //!< Short-hand for transport=="local"
|
|
bool identified; //!< Short-hand for authority!="anonymous"
|
|
|
|
PeerInfo();
|
|
virtual ~PeerInfo();
|
|
};
|
|
|
|
/** A particular authentication exchange. See AuthenticationPlugin::createSession()
|
|
*
|
|
* @note Must not hold a strong reference to AuthenticationPluginControl
|
|
*/
|
|
class epicsShareClass AuthenticationSession
|
|
{
|
|
public:
|
|
POINTER_DEFINITIONS(AuthenticationSession);
|
|
|
|
virtual ~AuthenticationSession();
|
|
|
|
//! 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(); }
|
|
|
|
//! Called when an AUTHZ message is recieved from the peer.
|
|
//! See AuthenticationPluginControl::sendSecurityPluginMessage().
|
|
//! callee accepts ownership of data, which will not be modified.
|
|
virtual void messageReceived(epics::pvData::PVStructure::const_shared_pointer const & data) {}
|
|
|
|
/** For client plugins only. Notification that server has declared the exchange complete.
|
|
* @param status Check Status::isSuccess()
|
|
* @param peer Final information about pe
|
|
*/
|
|
virtual void authenticationComplete(const epics::pvData::Status& status) {}
|
|
};
|
|
|
|
//! Callbacks for use by AuthenticationSession
|
|
class epicsShareClass AuthenticationPluginControl
|
|
{
|
|
public:
|
|
POINTER_DEFINITIONS(AuthenticationPluginControl);
|
|
virtual ~AuthenticationPluginControl();
|
|
|
|
//! Send AUTHZ to peer with payload.
|
|
//! caller gives up ownership of data, which must not be modified.
|
|
virtual void sendSecurityPluginMessage(epics::pvData::PVStructure::const_shared_pointer const & data) = 0;
|
|
|
|
/** 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:
|
|
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;
|
|
|
|
//! The client side of the conversation
|
|
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;
|
|
};
|
|
|
|
}
|
|
}
|
|
|
|
#endif // SECURITY_H
|