From 3209899172c03bb7c2610eeb17d748f9f6d1b54d Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 11 Jan 2019 19:21:47 -0800 Subject: [PATCH] authorization framework --- src/remote/codec.cpp | 3 ++ src/remote/pv/security.h | 36 ++++++++++++++++++++++++ src/remote/security.cpp | 60 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) diff --git a/src/remote/codec.cpp b/src/remote/codec.cpp index 110fcc7..33755b8 100644 --- a/src/remote/codec.cpp +++ b/src/remote/codec.cpp @@ -1619,6 +1619,9 @@ void BlockingServerTCPTransportCodec::authenticationCompleted(epics::pvData::Sta LOG(logLevelDebug, "Authentication completed with status '%s' for PVA client: %s.", Status::StatusTypeName[status.getType()], _socketName.c_str()); } + if(peer) + AuthorizationRegistry::plugins().run(peer); + bool isVerified; { Guard G(_mutex); diff --git a/src/remote/pv/security.h b/src/remote/pv/security.h index 1af1d7b..68f2e5b 100644 --- a/src/remote/pv/security.h +++ b/src/remote/pv/security.h @@ -263,6 +263,42 @@ public: AuthenticationPlugin::shared_pointer lookup(const std::string& name) const; }; +//! I modify PeerInfo after authentication is complete. +//! Usually to update PeerInfo::roles +class epicsShareClass AuthorizationPlugin +{ +public: + POINTER_DEFINITIONS(AuthorizationPlugin); + + virtual ~AuthorizationPlugin(); + + //! Hook to modify PeerInfo + virtual void authorize(const std::tr1::shared_ptr& peer) =0; +}; + +class epicsShareClass AuthorizationRegistry +{ + EPICS_NOT_COPYABLE(AuthorizationRegistry) +public: + POINTER_DEFINITIONS(AuthenticationRegistry); + + static AuthorizationRegistry &plugins(); + + AuthorizationRegistry(); + ~AuthorizationRegistry(); + +private: + typedef std::map map_t; + map_t map; + void *busy; + mutable epicsMutex mutex; +public: + + void add(int prio, const AuthorizationPlugin::shared_pointer& plugin); + bool remove(const AuthorizationPlugin::shared_pointer& plugin); + void run(const std::tr1::shared_ptr& peer); +}; + } } diff --git a/src/remote/security.cpp b/src/remote/security.cpp index abb268d..45c0201 100644 --- a/src/remote/security.cpp +++ b/src/remote/security.cpp @@ -132,10 +132,15 @@ AuthenticationPlugin::~AuthenticationPlugin() {} AuthenticationRegistry::~AuthenticationRegistry() {} +AuthorizationPlugin::~AuthorizationPlugin() {} + +AuthorizationRegistry::~AuthorizationRegistry() {} + namespace { struct authGbl_t { mutable epicsMutex mutex; AuthenticationRegistry servers, clients; + AuthorizationRegistry authorizers; } *authGbl; void authGblInit(void *) @@ -223,6 +228,61 @@ AuthenticationPlugin::shared_pointer AuthenticationRegistry::lookup(const std::s } +AuthorizationRegistry::AuthorizationRegistry() + :busy(0) +{} + +AuthorizationRegistry& AuthorizationRegistry::plugins() +{ + epicsThreadOnce(&authGblOnce, &authGblInit, 0); + assert(authGbl); + return authGbl->authorizers; +} + +void AuthorizationRegistry::add(int prio, const AuthorizationPlugin::shared_pointer& plugin) +{ + Guard G(mutex); + // we don't expect changes after server start + if(busy) + throw std::runtime_error("AuthorizationRegistry busy"); + if(map.find(prio)!=map.end()) + THROW_EXCEPTION2(std::logic_error, "Authorization plugin already registered with this priority"); + map[prio] = plugin; +} + +bool AuthorizationRegistry::remove(const AuthorizationPlugin::shared_pointer& plugin) +{ + Guard G(mutex); + if(busy) + throw std::runtime_error("AuthorizationRegistry busy"); + for(map_t::iterator it(map.begin()), end(map.end()); it!=end; ++it) { + if(it->second==plugin) { + map.erase(it); + return true; + } + } + return false; +} + +void AuthorizationRegistry::run(const std::tr1::shared_ptr& peer) +{ + int marker; + { + Guard G(mutex); + if(busy) + throw std::runtime_error("AuthorizationRegistry busy"); + busy = ▮ + } + for(map_t::iterator it(map.begin()), end(map.end()); it!=end; ++it) + { + (it->second)->authorize(peer); + } + { + Guard G(mutex); + assert(busy==&marker); + busy = 0; + } +} void AuthNZHandler::handleResponse(osiSockAddr* responseFrom, Transport::shared_pointer const & transport,