[cpp-sp] branch master updated: SSPCPP-799 - Listener remoting map needs to be synchronized SSPCPP-350 - Better modulariziation in vhosted environments
Scott Cantor
cantor.2 at osu.edu
Wed May 9 16:07:29 EDT 2018
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch master
in repository cpp-sp.
View the commit online:
http://git.shibboleth.net/view/?p=cpp-sp.git;a=commit;h=7b43f446464aa631fc16d72e313f47286a37561f
The following commit(s) were added to refs/heads/master by this push:
new 7b43f44 SSPCPP-799 - Listener remoting map needs to be synchronized SSPCPP-350 - Better modulariziation in vhosted environments
7b43f44 is described below
commit 7b43f446464aa631fc16d72e313f47286a37561f
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed May 9 15:51:55 2018 -0400
SSPCPP-799 - Listener remoting map needs to be synchronized
SSPCPP-350 - Better modulariziation in vhosted environments
Add locking to address maps.
Fix problem with dereg for failed Application loads.
Add a dynamic override lookup feature using external files.
Fix some handlers registering non-app-specific addresses.
---
schemas/shibboleth-3.0-native-sp-config.xsd | 13 +-
shibsp/ServiceProvider.cpp | 31 -----
shibsp/ServiceProvider.h | 18 +--
shibsp/handler/impl/AssertionLookup.cpp | 9 +-
shibsp/handler/impl/ExternalAuthHandler.cpp | 31 +++--
shibsp/handler/impl/RemotedHandler.cpp | 14 +-
shibsp/impl/XMLApplication.cpp | 26 ++--
shibsp/impl/XMLApplication.h | 8 +-
shibsp/impl/XMLServiceProvider.cpp | 191 ++++++++++++++++++++++++++--
shibsp/impl/XMLServiceProvider.h | 27 +++-
shibsp/remoting/ListenerService.h | 9 +-
shibsp/remoting/impl/ListenerService.cpp | 23 ++--
12 files changed, 288 insertions(+), 112 deletions(-)
diff --git a/schemas/shibboleth-3.0-native-sp-config.xsd b/schemas/shibboleth-3.0-native-sp-config.xsd
index 77c2073..79a237a 100644
--- a/schemas/shibboleth-3.0-native-sp-config.xsd
+++ b/schemas/shibboleth-3.0-native-sp-config.xsd
@@ -428,7 +428,8 @@
<element name="AttributeResolver" type="conf:PluggableType"/>
<element name="AttributeFilter" type="conf:PluggableType"/>
<element name="CredentialResolver" type="conf:PluggableType"/>
- <element name="ApplicationOverride" type="conf:ApplicationOverrideType"/>
+ <element ref="conf:ApplicationOverride"/>
+ <element name="ExternalApplicationOverrides" type="conf:ExternalApplicationOverridesType"/>
</choice>
</sequence>
<attribute name="id" type="conf:string" fixed="default"/>
@@ -438,6 +439,8 @@
<anyAttribute namespace="##other" processContents="lax"/>
</complexType>
+ <element name="ApplicationOverride" type="conf:ApplicationOverrideType"/>
+
<complexType name="ApplicationOverrideType">
<annotation>
<documentation>Container for application-specific overrides</documentation>
@@ -463,6 +466,14 @@
<anyAttribute namespace="##other" processContents="lax"/>
</complexType>
+ <complexType name="ExternalApplicationOverridesType">
+ <annotation>
+ <documentation>Externalized application overrides.</documentation>
+ </annotation>
+ <sequence/>
+ <attribute name="path" type="conf:string" use="required" />
+ </complexType>
+
<attributeGroup name="ApplicationGroup">
<attribute name="homeURL" type="anyURI"/>
<attribute name="policyId" type="conf:string"/>
diff --git a/shibsp/ServiceProvider.cpp b/shibsp/ServiceProvider.cpp
index ec13bfe..aacbba1 100644
--- a/shibsp/ServiceProvider.cpp
+++ b/shibsp/ServiceProvider.cpp
@@ -283,37 +283,6 @@ ServiceProvider::~ServiceProvider()
{
}
-Remoted* ServiceProvider::regListener(const char* address, Remoted* listener)
-{
- Remoted* ret = nullptr;
- map<string,Remoted*>::const_iterator i = m_listenerMap.find(address);
- if (i != m_listenerMap.end())
- ret = i->second;
- m_listenerMap[address] = listener;
- Category::getInstance(SHIBSP_LOGCAT ".ServiceProvider").info("registered remoted message endpoint (%s)",address);
- return ret;
-}
-
-bool ServiceProvider::unregListener(const char* address, Remoted* current, Remoted* restore)
-{
- map<string,Remoted*>::const_iterator i = m_listenerMap.find(address);
- if (i != m_listenerMap.end() && i->second == current) {
- if (restore)
- m_listenerMap[address] = restore;
- else
- m_listenerMap.erase(address);
- Category::getInstance(SHIBSP_LOGCAT ".ServiceProvider").info("unregistered remoted message endpoint (%s)",address);
- return true;
- }
- return false;
-}
-
-Remoted* ServiceProvider::lookupListener(const char *address) const
-{
- map<string,Remoted*>::const_iterator i = m_listenerMap.find(address);
- return (i == m_listenerMap.end()) ? nullptr : i->second;
-}
-
pair<bool,long> ServiceProvider::doAuthentication(SPRequest& request, bool handler) const
{
#ifdef _DEBUG
diff --git a/shibsp/ServiceProvider.h b/shibsp/ServiceProvider.h
index d386c88..2aca228 100644
--- a/shibsp/ServiceProvider.h
+++ b/shibsp/ServiceProvider.h
@@ -30,7 +30,6 @@
#include <shibsp/util/PropertySet.h>
#include <set>
-#include <vector>
#include <xmltooling/Lockable.h>
namespace xmltooling {
@@ -210,23 +209,21 @@ namespace shibsp {
virtual std::pair<bool,long> doHandler(SPRequest& request) const;
/**
- * Register for a message. Returns existing remote service, allowing message hooking.
+ * Register for a message.
*
- * @param address message address to register
- * @param svc pointer to remote service
- * @return previous service registered for message, if any
+ * @param address message address to register
+ * @param svc pointer to remote service
*/
- virtual Remoted* regListener(const char* address, Remoted* svc);
+ virtual void regListener(const char* address, Remoted* svc)=0;
/**
* Unregisters service from an address, possibly restoring an original.
*
* @param address message address to modify
* @param current pointer to unregistering service
- * @param restore service to "restore" registration for
* @return true iff the current service was still registered
*/
- virtual bool unregListener(const char* address, Remoted* current, Remoted* restore=nullptr);
+ virtual bool unregListener(const char* address, Remoted* current)=0;
/**
* Returns current service registered at an address, if any.
@@ -234,14 +231,11 @@ namespace shibsp {
* @param address message address to access
* @return registered service, or nullptr
*/
- virtual Remoted* lookupListener(const char* address) const;
+ virtual Remoted* lookupListener(const char* address) const=0;
protected:
/** The AuthTypes to "recognize" (defaults to "shibboleth"). */
std::set<std::string> m_authTypes;
-
- private:
- std::map<std::string,Remoted*> m_listenerMap;
};
#if defined (_MSC_VER)
diff --git a/shibsp/handler/impl/AssertionLookup.cpp b/shibsp/handler/impl/AssertionLookup.cpp
index 9c58b73..e1a02e4 100644
--- a/shibsp/handler/impl/AssertionLookup.cpp
+++ b/shibsp/handler/impl/AssertionLookup.cpp
@@ -86,7 +86,14 @@ namespace shibsp {
AssertionLookup::AssertionLookup(const DOMElement* e, const char* appId)
: SecuredHandler(e, Category::getInstance(SHIBSP_LOGCAT ".Handler.AssertionLookup"), "exportACL", "127.0.0.1 ::1")
{
- setAddress("run::AssertionLookup");
+ pair<bool,const char*> prop = getString("Location");
+ if (!prop.first)
+ throw ConfigurationException("AssertionLookup handler requires Location property.");
+ string address(appId);
+ if (*prop.second != '/')
+ address += '/';
+ address += prop.second;
+ setAddress(address.c_str());
}
pair<bool,long> AssertionLookup::run(SPRequest& request, bool isHandler) const
diff --git a/shibsp/handler/impl/ExternalAuthHandler.cpp b/shibsp/handler/impl/ExternalAuthHandler.cpp
index 30e2519..d3204d9 100644
--- a/shibsp/handler/impl/ExternalAuthHandler.cpp
+++ b/shibsp/handler/impl/ExternalAuthHandler.cpp
@@ -165,7 +165,12 @@ namespace {
ExternalAuth::ExternalAuth(const DOMElement* e, const char* appId)
: SecuredHandler(e, Category::getInstance(SHIBSP_LOGCAT ".Handler.ExternalAuth"), "acl", "127.0.0.1 ::1")
{
- setAddress("run::ExternalAuth");
+ pair<bool,const char*> prop = getString("Location");
+ if (!prop.first)
+ throw ConfigurationException("ExternalAuth handler requires Location property.");
+ string address(appId);
+ address += prop.second;
+ setAddress(address.c_str());
}
pair<bool,long> ExternalAuth::run(SPRequest& request, bool isHandler) const
@@ -202,7 +207,7 @@ pair<bool,long> ExternalAuth::run(SPRequest& request, bool isHandler) const
return unwrap(request, out);
}
}
- catch (std::exception& ex) {
+ catch (const std::exception& ex) {
m_log.error("error while processing request: %s", ex.what());
istringstream msg("External Authentication Failed");
return make_pair(true, request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_ERROR));
@@ -234,7 +239,7 @@ void ExternalAuth::receive(DDF& in, ostream& out)
try {
processMessage(*app, *req, *resp, in, &ret);
}
- catch (std::exception& ex) {
+ catch (const std::exception& ex) {
m_log.error("raising exception: %s", ex.what());
throw;
}
@@ -489,7 +494,7 @@ pair<bool,long> ExternalAuth::processMessage(
}
}
}
- catch (std::exception&) {
+ catch (const std::exception&) {
for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
throw;
}
@@ -561,7 +566,7 @@ pair<bool,long> ExternalAuth::processMessage(
try {
recoverRelayState(application, httpRequest, httpResponse, target);
}
- catch (std::exception& ex) {
+ catch (const std::exception& ex) {
m_log.error("error recovering relay state: %s", ex.what());
target.erase();
}
@@ -701,7 +706,7 @@ ResolutionContext* ExternalAuth::resolveAttributes(
*id = mprefix.second + *id;
}
}
- catch (std::exception& ex) {
+ catch (const std::exception& ex) {
m_log.error("caught exception extracting attributes: %s", ex.what());
}
}
@@ -713,7 +718,7 @@ ResolutionContext* ExternalAuth::resolveAttributes(
try {
extractor->extractAttributes(application, request, issuer, *nameid, resolvedAttributes);
}
- catch (std::exception& ex) {
+ catch (const std::exception& ex) {
m_log.error("caught exception extracting attributes: %s", ex.what());
}
}
@@ -722,7 +727,7 @@ ResolutionContext* ExternalAuth::resolveAttributes(
try {
extractor->extractAttributes(application, request, issuer, *statement, resolvedAttributes);
}
- catch (std::exception& ex) {
+ catch (const std::exception& ex) {
m_log.error("caught exception extracting attributes: %s", ex.what());
}
}
@@ -733,7 +738,7 @@ ResolutionContext* ExternalAuth::resolveAttributes(
try {
extractor->extractAttributes(application, request, issuer, *t, resolvedAttributes);
}
- catch (std::exception& ex) {
+ catch (const std::exception& ex) {
m_log.error("caught exception extracting attributes: %s", ex.what());
}
}
@@ -746,7 +751,7 @@ ResolutionContext* ExternalAuth::resolveAttributes(
try {
filter->filterAttributes(fc, resolvedAttributes);
}
- catch (std::exception& ex) {
+ catch (const std::exception& ex) {
m_log.error("caught exception filtering attributes: %s", ex.what());
m_log.error("dumping extracted attributes due to filtering exception");
for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
@@ -786,7 +791,7 @@ ResolutionContext* ExternalAuth::resolveAttributes(
return ctx.release();
}
}
- catch (std::exception& ex) {
+ catch (const std::exception& ex) {
m_log.error("attribute resolution failed: %s", ex.what());
}
@@ -794,7 +799,7 @@ ResolutionContext* ExternalAuth::resolveAttributes(
try {
return new DummyContext(resolvedAttributes);
}
- catch (bad_alloc&) {
+ catch (const bad_alloc&) {
for_each(resolvedAttributes.begin(), resolvedAttributes.end(), xmltooling::cleanup<shibsp::Attribute>());
}
}
@@ -819,7 +824,7 @@ LoginEvent* ExternalAuth::newLoginEvent(const Application& application, const HT
m_log.warn("unable to audit event, log event object was of an incorrect type");
}
}
- catch (std::exception& ex) {
+ catch (const std::exception& ex) {
m_log.warn("exception auditing event: %s", ex.what());
}
return nullptr;
diff --git a/shibsp/handler/impl/RemotedHandler.cpp b/shibsp/handler/impl/RemotedHandler.cpp
index 9d5556a..348d0c4 100644
--- a/shibsp/handler/impl/RemotedHandler.cpp
+++ b/shibsp/handler/impl/RemotedHandler.cpp
@@ -334,13 +334,8 @@ void RemotedHandler::setAddress(const char* address)
throw ConfigurationException("Cannot register a remoting address twice for the same Handler.");
m_address = address;
SPConfig& conf = SPConfig::getConfig();
- if (!conf.isEnabled(SPConfig::InProcess)) {
- ListenerService* listener = conf.getServiceProvider()->getListenerService(false);
- if (listener)
- listener->regListener(m_address.c_str(), this);
- else
- Category::getInstance(SHIBSP_LOGCAT ".Handler").info("no ListenerService available, handler remoting disabled");
- }
+ if (conf.isEnabled(SPConfig::OutOfProcess) && !conf.isEnabled(SPConfig::InProcess))
+ conf.getServiceProvider()->regListener(address, this);
}
set<string> RemotedHandler::m_remotedHeaders;
@@ -352,9 +347,8 @@ RemotedHandler::RemotedHandler()
RemotedHandler::~RemotedHandler()
{
SPConfig& conf = SPConfig::getConfig();
- ListenerService* listener=conf.getServiceProvider()->getListenerService(false);
- if (listener && conf.isEnabled(SPConfig::OutOfProcess) && !conf.isEnabled(SPConfig::InProcess))
- listener->unregListener(m_address.c_str(),this);
+ if (conf.isEnabled(SPConfig::OutOfProcess) && !conf.isEnabled(SPConfig::InProcess))
+ conf.getServiceProvider()->unregListener(m_address.c_str(), this);
}
void RemotedHandler::addRemotedHeader(const char* header)
diff --git a/shibsp/impl/XMLApplication.cpp b/shibsp/impl/XMLApplication.cpp
index 944f0fb..58c9e05 100644
--- a/shibsp/impl/XMLApplication.cpp
+++ b/shibsp/impl/XMLApplication.cpp
@@ -84,6 +84,7 @@ namespace {
static const XMLCh Channel[]= UNICODE_LITERAL_7(C,h,a,n,n,e,l);
static const XMLCh _CredentialResolver[] = UNICODE_LITERAL_18(C,r,e,d,e,n,t,i,a,l,R,e,s,o,l,v,e,r);
static const XMLCh _default[] = UNICODE_LITERAL_7(d,e,f,a,u,l,t);
+ static const XMLCh ExternalApplicationOverrides[] = UNICODE_LITERAL_28(E,x,t,e,r,n,a,l,A,p,p,l,i,c,a,t,i,o,n,O,v,e,r,r,i,d,e,s);
static const XMLCh _Handler[] = UNICODE_LITERAL_7(H,a,n,d,l,e,r);
static const XMLCh _id[] = UNICODE_LITERAL_2(i,d);
static const XMLCh _index[] = UNICODE_LITERAL_5(i,n,d,e,x);
@@ -107,8 +108,9 @@ XMLApplication::XMLApplication(
const ServiceProvider* sp,
const ProtocolProvider* pp,
DOMElement* e,
- const XMLApplication* base
- ) : Application(sp), m_base(base), m_acsDefault(nullptr), m_sessionInitDefault(nullptr), m_artifactResolutionDefault(nullptr)
+ const XMLApplication* base,
+ DOMDocument* doc
+ ) : Application(sp), m_base(base), m_acsDefault(nullptr), m_sessionInitDefault(nullptr), m_artifactResolutionDefault(nullptr), m_doc(doc)
{
#ifdef _DEBUG
xmltooling::NDC ndc("XMLApplication");
@@ -326,24 +328,19 @@ XMLApplication::XMLApplication(
// Out of process only, we register a listener endpoint.
if (!conf.isEnabled(SPConfig::InProcess)) {
- ListenerService* listener = sp->getListenerService(false);
- if (listener) {
- string addr=string(getId()) + "::getHeaders::Application";
- listener->regListener(addr.c_str(), this);
- }
- else {
- log.info("no ListenerService available, Application remoting disabled");
- }
+ string addr=string(getId()) + "::getHeaders::Application";
+ const_cast<ServiceProvider*>(sp)->regListener(addr.c_str(), this);
}
}
XMLApplication::~XMLApplication()
{
- ListenerService* listener=getServiceProvider().getListenerService(false);
- if (listener && SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess) && !SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
+ if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess) && !SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
string addr=string(getId()) + "::getHeaders::Application";
- listener->unregListener(addr.c_str(), this);
+ const_cast<ServiceProvider&>(getServiceProvider()).unregListener(addr.c_str(), this);
}
+ if (m_doc)
+ m_doc->release();
}
template <class T> T* XMLApplication::doChainedPlugins(
@@ -1140,7 +1137,8 @@ DOMNodeFilter::FilterAction XMLApplication::acceptNode(const DOMNode* node) cons
XMLString::equals(name, _CredentialResolver) ||
XMLString::equals(name, _AttributeFilter) ||
XMLString::equals(name, _AttributeExtractor) ||
- XMLString::equals(name, _AttributeResolver)) {
+ XMLString::equals(name, _AttributeResolver) ||
+ XMLString::equals(name, ExternalApplicationOverrides)) {
return FILTER_REJECT;
}
diff --git a/shibsp/impl/XMLApplication.h b/shibsp/impl/XMLApplication.h
index 043f405..57edeae 100644
--- a/shibsp/impl/XMLApplication.h
+++ b/shibsp/impl/XMLApplication.h
@@ -77,7 +77,12 @@ namespace shibsp {
: public Application, public Remoted, public DOMPropertySet, public xercesc::DOMNodeFilter
{
public:
- XMLApplication(const ServiceProvider*, const ProtocolProvider*, xercesc::DOMElement*, const XMLApplication* base=nullptr);
+ XMLApplication(
+ const ServiceProvider*,
+ const ProtocolProvider*,
+ xercesc::DOMElement*,
+ const XMLApplication* base=nullptr,
+ xercesc::DOMDocument* doc=nullptr);
virtual ~XMLApplication();
const char* getHash() const {
@@ -221,6 +226,7 @@ namespace shibsp {
} m_redirectLimit;
std::vector<std::string> m_redirectWhitelist;
+ xercesc::DOMDocument* m_doc;
};
#if defined (_MSC_VER)
diff --git a/shibsp/impl/XMLServiceProvider.cpp b/shibsp/impl/XMLServiceProvider.cpp
index 6ef74b3..7661001 100644
--- a/shibsp/impl/XMLServiceProvider.cpp
+++ b/shibsp/impl/XMLServiceProvider.cpp
@@ -41,11 +41,14 @@
#else
# error "Supported logging library not available."
#endif
+#include <fstream>
#include <boost/algorithm/string.hpp>
#include <boost/tuple/tuple.hpp>
#include <xmltooling/XMLToolingConfig.h>
#include <xmltooling/version.h>
#include <xmltooling/util/NDC.h>
+#include <xmltooling/util/ParserPool.h>
+#include <xmltooling/util/PathResolver.h>
#include <xmltooling/util/TemplateEngine.h>
#include <xmltooling/util/Threads.h>
#include <xmltooling/util/XMLHelper.h>
@@ -88,6 +91,7 @@ namespace {
static const XMLCh _DataSealer[] = UNICODE_LITERAL_10(D,a,t,a,S,e,a,l,e,r);
static const XMLCh _default[] = UNICODE_LITERAL_7(d,e,f,a,u,l,t);
static const XMLCh _Extensions[] = UNICODE_LITERAL_10(E,x,t,e,n,s,i,o,n,s);
+ static const XMLCh ExternalApplicationOverrides[] = UNICODE_LITERAL_28(E,x,t,e,r,n,a,l,A,p,p,l,i,c,a,t,i,o,n,O,v,e,r,r,i,d,e,s);
static const XMLCh _fatal[] = UNICODE_LITERAL_5(f,a,t,a,l);
static const XMLCh _id[] = UNICODE_LITERAL_2(i,d);
static const XMLCh InProcess[] = UNICODE_LITERAL_9(I,n,P,r,o,c,e,s,s);
@@ -304,7 +308,7 @@ void XMLConfigImpl::doCaching(const DOMElement* e, XMLConfig* conf, Category& lo
}
}
-XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, XMLConfig* outer, Category& log) : m_document(nullptr)
+XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, XMLConfig* outer, Category& log) : m_document(nullptr), m_defaultApplication(nullptr)
{
#ifdef _DEBUG
xmltooling::NDC ndc("XMLConfigImpl");
@@ -531,17 +535,16 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, XMLConfig* outer,
}
#endif
- scoped_ptr<ProtocolProvider> pp;
if (conf.isEnabled(SPConfig::Handlers)) {
if (child = XMLHelper::getLastChildElement(e, _ProtocolProvider)) {
string t(XMLHelper::getAttrString(child, nullptr, _type));
if (!t.empty()) {
log.info("building ProtocolProvider of type %s...", t.c_str());
- pp.reset(conf.ProtocolProviderManager.newPlugin(t.c_str(), child));
+ m_protocolProvider.reset(conf.ProtocolProviderManager.newPlugin(t.c_str(), child));
}
}
}
- Locker pplocker(pp.get());
+ Locker pplocker(m_protocolProvider.get());
// Load the default application.
child = XMLHelper::getLastChildElement(e, ApplicationDefaults);
@@ -549,21 +552,38 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, XMLConfig* outer,
log.fatal("can't build default Application object, missing conf:ApplicationDefaults element?");
throw ConfigurationException("can't build default Application object, missing conf:ApplicationDefaults element?");
}
- boost::shared_ptr<XMLApplication> defapp(new XMLApplication(outer, pp.get(), child));
+ boost::shared_ptr<XMLApplication> defapp(new XMLApplication(outer, m_protocolProvider.get(), child));
m_appmap[defapp->getId()] = defapp;
+ m_defaultApplication = defapp.get();
// Load any overrides.
- child = XMLHelper::getFirstChildElement(child, ApplicationOverride);
- while (child) {
- boost::shared_ptr<XMLApplication> iapp(new XMLApplication(outer, pp.get(), child, defapp.get()));
+ DOMElement* override = XMLHelper::getFirstChildElement(child, ApplicationOverride);
+ while (override) {
+ boost::shared_ptr<XMLApplication> iapp(new XMLApplication(outer, m_protocolProvider.get(), override, defapp.get()));
if (m_appmap.count(iapp->getId()))
log.crit("found conf:ApplicationOverride element with duplicate id attribute (%s), skipping it", iapp->getId());
else
m_appmap[iapp->getId()] = iapp;
- child = XMLHelper::getNextSiblingElement(child, ApplicationOverride);
+ override = XMLHelper::getNextSiblingElement(override, ApplicationOverride);
+ }
+
+ // Save off any external override paths.
+ override = XMLHelper::getFirstChildElement(child, ExternalApplicationOverrides);
+ while (override) {
+ string extoverridepath(XMLHelper::getAttrString(override, nullptr, _path));
+ XMLToolingConfig::getConfig().getPathResolver()->resolve(extoverridepath, PathResolver::XMLTOOLING_CFG_FILE);
+ if (!extoverridepath.empty()) {
+ log.info("adding external ApplicationOverride search path: %s", extoverridepath.c_str());
+ m_externalAppPaths.push_back(extoverridepath);
+ }
+
+ override = XMLHelper::getNextSiblingElement(override, ApplicationOverride);
}
+ if (!m_externalAppPaths.empty())
+ m_appMapLock.reset(Mutex::create());
+
// Check for extra AuthTypes to recognize.
if (conf.isEnabled(SPConfig::InProcess)) {
const PropertySet* inprocs = getPropertySet("InProcess");
@@ -579,6 +599,64 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, XMLConfig* outer,
}
}
+boost::shared_ptr<Application> XMLConfigImpl::findExternalOverride(const char* id, const XMLConfig* config)
+{
+ Locker pplocker(m_protocolProvider.get());
+
+ for (vector<string>::const_iterator i = m_externalAppPaths.begin(); i != m_externalAppPaths.end(); ++i) {
+ string path(*i);
+ if (!ends_with(path, "/"))
+ path += '/';
+ path = path + id + "-override.xml";
+ try {
+ ifstream in(path.c_str());
+ if (in) {
+ DOMDocument* doc = XMLToolingConfig::getConfig().getValidatingParser().parse(in);
+ if (!XMLHelper::isNodeNamed(doc->getDocumentElement(), shibspconstants::SHIB3SPCONFIG_NS, ApplicationOverride)) {
+ throw ConfigurationException("External override not rooted in conf:ApplicationOverride element.");
+ }
+
+ string id2(XMLHelper::getAttrString(doc->getDocumentElement(), nullptr, _id));
+ if (id2 != id)
+ throw ConfigurationException("External override's id ($1) did not match the expected value", params(1, id2.c_str()));
+
+ boost::shared_ptr<XMLApplication> iapp(
+ new XMLApplication(config, m_protocolProvider.get(), doc->getDocumentElement(), m_defaultApplication, doc)
+ );
+ return iapp;
+ }
+ }
+ catch (const std::exception& ex) {
+ config->m_log.error("Exception creating ApplicationOverride: %s", ex.what());
+ }
+ }
+
+ return nullptr;
+}
+
+const Application* XMLConfig::getApplication(const char* applicationId) const
+{
+ Lock locker(m_impl->m_appMapLock);
+
+ map< string, boost::shared_ptr<Application> >::const_iterator i = m_impl->m_appmap.find(applicationId ? applicationId : "default");
+ Application* ret = (i != m_impl->m_appmap.end()) ? i->second.get() : nullptr;
+
+ if (!ret && m_impl->m_appMapLock && applicationId) {
+ m_log.info("application override (%s) not found, searching external sources", applicationId);
+ boost::shared_ptr<Application> newapp = m_impl->findExternalOverride(applicationId, this);
+ if (newapp) {
+ m_log.info("storing externally defined application override (%s)", applicationId);
+ ret = newapp.get();
+ m_impl->m_appmap[applicationId] = newapp;
+ }
+ else {
+ m_log.warn("application override (%s) not found in external sources", applicationId);
+ }
+ }
+
+ return ret;
+}
+
#ifndef SHIBSP_LITE
StorageService* XMLConfig::getStorageService(const char* id) const
@@ -721,6 +799,101 @@ void XMLConfig::receive(DDF& in, ostream& out)
#endif
+void XMLConfig::regListener(const char* address, Remoted* listener)
+{
+ m_listenerLock->wrlock();
+ SharedLock locker(m_listenerLock, false);
+
+ map< string,pair<Remoted*,Remoted*> >::iterator i = m_listenerMap.find(address);
+ if (i != m_listenerMap.end()) {
+ if (!i->second.first) {
+ // First slot is null. Look for second slot and move up if needed.
+ if (i->second.second) {
+ i->second.first = i->second.second;
+ i->second.second = listener;
+ Category::getInstance(SHIBSP_LOGCAT ".ServiceProvider").debug("registered second remoted message endpoint (%s)",address);
+ }
+ else {
+ // Both slots null, so put into first slot.
+ i->second.first = listener;
+ Category::getInstance(SHIBSP_LOGCAT ".ServiceProvider").debug("registered remoted message endpoint (%s)",address);
+ }
+ }
+ else if (!i->second.second) {
+ // First slot occupied, so put into empty second slot.
+ i->second.second = listener;
+ Category::getInstance(SHIBSP_LOGCAT ".ServiceProvider").debug("registered second remoted message endpoint (%s)",address);
+ }
+ else {
+ // This should never happen...?
+ throw new ConfigurationException("Attempted to register more than two endpoints for a single listener address.");
+ }
+ }
+ else {
+ // Stick it in the first slot.
+ m_listenerMap[address] = pair<Remoted*, Remoted*>(listener, nullptr);
+ Category::getInstance(SHIBSP_LOGCAT ".ServiceProvider").debug("registered remoted message endpoint (%s)",address);
+ }
+}
+
+bool XMLConfig::unregListener(const char* address, Remoted* current)
+{
+ m_listenerLock->wrlock();
+ SharedLock locker(m_listenerLock, false);
+
+ map< string,pair<Remoted*,Remoted*> >::iterator i = m_listenerMap.find(address);
+ if (i != m_listenerMap.end()) {
+ if (i->second.first == current) {
+ if (i->second.second) {
+ // Promote second slot to first.
+ i->second.first = i->second.second;
+ i->second.second = nullptr;
+ }
+ else {
+ // Remove entirely.
+ m_listenerMap.erase(address);
+ }
+ }
+ else if (i->second.second = current) {
+ if (!i->second.first)
+ m_listenerMap.erase(address);
+ else
+ i->second.second = nullptr;
+ }
+ else {
+ return false;
+ }
+ Category::getInstance(SHIBSP_LOGCAT ".ServiceProvider").debug("unregistered remoted message endpoint (%s)", address);
+ return true;
+ }
+ return false;
+}
+
+Remoted* XMLConfig::lookupListener(const char* address) const
+{
+ SharedLock locker(m_listenerLock, true);
+ map< string,pair<Remoted*,Remoted*> >::const_iterator i = m_listenerMap.find(address);
+ if (i != m_listenerMap.end())
+ return i->second.first ? i->second.first : i->second.second;
+
+ const char* colons = strstr(address, "::");
+ if (colons) {
+ string appId(address, colons - address);
+ locker.release()->unlock(); // free up the listener map
+ getApplication(appId.c_str());
+ SharedLock sublocker(m_listenerLock, true); // relock and check again
+ i = m_listenerMap.find(address);
+ if (i != m_listenerMap.end())
+ return i->second.first ? i->second.first : i->second.second;
+ }
+ return nullptr;
+}
+
+XMLConfig::XMLConfig(const DOMElement* e)
+ : ReloadableXMLFile(e, xmltooling::logging::Category::getInstance(SHIBSP_LOGCAT ".Config")), m_listenerLock(RWLock::create())
+{
+}
+
XMLConfig::~XMLConfig()
{
shutdown();
diff --git a/shibsp/impl/XMLServiceProvider.h b/shibsp/impl/XMLServiceProvider.h
index cfb1554..0b5e22b 100644
--- a/shibsp/impl/XMLServiceProvider.h
+++ b/shibsp/impl/XMLServiceProvider.h
@@ -44,6 +44,11 @@
# include <boost/tuple/tuple.hpp>
#endif
+namespace xmltooling {
+ class Mutex;
+ class RWLock;
+}
+
namespace shibsp {
#if defined (_MSC_VER)
@@ -66,8 +71,14 @@ namespace shibsp {
boost::scoped_ptr<SecurityPolicyProvider> m_policy;
std::vector< boost::tuple<std::string, std::string, std::string> > m_transportOptions;
#endif
+ std::map<std::string,Remoted*> m_listenerMap;
boost::scoped_ptr<RequestMapper> m_requestMapper;
+ boost::scoped_ptr<ProtocolProvider> m_protocolProvider;
+ boost::scoped_ptr<xmltooling::Mutex> m_appMapLock;
std::map< std::string, boost::shared_ptr<Application> > m_appmap;
+ std::vector<std::string> m_externalAppPaths;
+
+ boost::shared_ptr<Application> findExternalOverride(const char*, const XMLConfig*);
// Provides filter to exclude special config elements.
xercesc::DOMNodeFilter::FilterAction acceptNode(const xercesc::DOMNode* node) const;
@@ -82,6 +93,7 @@ namespace shibsp {
void doCaching(const xercesc::DOMElement*, XMLConfig*, xmltooling::logging::Category&);
xercesc::DOMDocument* m_document;
+ const XMLApplication* m_defaultApplication;
};
class SHIBSP_DLLLOCAL XMLConfig : public ServiceProvider, public xmltooling::ReloadableXMLFile
@@ -90,7 +102,7 @@ namespace shibsp {
#endif
{
public:
- XMLConfig(const xercesc::DOMElement* e) : ReloadableXMLFile(e, xmltooling::logging::Category::getInstance(SHIBSP_LOGCAT ".Config")) {}
+ XMLConfig(const xercesc::DOMElement* e);
virtual ~XMLConfig();
void init() {
@@ -150,10 +162,7 @@ namespace shibsp {
return m_impl->m_requestMapper.get();
}
- const Application* getApplication(const char* applicationId) const {
- std::map< std::string, boost::shared_ptr<Application> >::const_iterator i = m_impl->m_appmap.find(applicationId ? applicationId : "default");
- return (i != m_impl->m_appmap.end()) ? i->second.get() : nullptr;
- }
+ const Application* getApplication(const char* applicationId) const;
#ifndef SHIBSP_LITE
SecurityPolicyProvider* getSecurityPolicyProvider(bool required=true) const {
@@ -165,11 +174,19 @@ namespace shibsp {
bool setTransportOptions(xmltooling::SOAPTransport& transport) const;
#endif
+ void regListener(const char* address, Remoted* svc);
+ bool unregListener(const char* address, Remoted* current);
+ Remoted* lookupListener(const char* address) const;
+
protected:
std::pair<bool,xercesc::DOMElement*> background_load();
private:
friend class XMLConfigImpl;
+
+ boost::scoped_ptr<xmltooling::RWLock> m_listenerLock;
+ std::map< std::string,std::pair<Remoted*,Remoted*> > m_listenerMap;
+
// The order of these members actually matters. If we want to rely on auto-destruction, then
// anything dependent on anything else has to come later in the object so it will pop first.
// Storage is the lowest, then remoting, then the cache, and finally the rest.
diff --git a/shibsp/remoting/ListenerService.h b/shibsp/remoting/ListenerService.h
index 8f5b2ef..8e115b3 100644
--- a/shibsp/remoting/ListenerService.h
+++ b/shibsp/remoting/ListenerService.h
@@ -33,6 +33,7 @@
#include <boost/scoped_ptr.hpp>
namespace xmltooling {
+ class RWLock;
class ThreadKey;
}
@@ -111,26 +112,23 @@ namespace shibsp {
DDF* getInput() const;
// Remoted classes register and unregister for messages using these methods.
- // Registration returns any existing listeners, allowing message hooking.
/**
* Register for a message. Returns existing remote service, allowing message hooking.
*
* @param address message address to register
* @param svc pointer to remote service
- * @return previous service registered for message, if any
*/
- virtual Remoted* regListener(const char* address, Remoted* svc);
+ virtual void regListener(const char* address, Remoted* svc);
/**
* Unregisters service from an address, possibly restoring an original.
*
* @param address message address to modify
* @param current pointer to unregistering service
- * @param restore service to "restore" registration for
* @return true iff the current service was still registered
*/
- virtual bool unregListener(const char* address, Remoted* current, Remoted* restore=nullptr);
+ virtual bool unregListener(const char* address, Remoted* current);
/**
* Returns current service registered at an address, if any.
@@ -169,6 +167,7 @@ namespace shibsp {
private:
std::map<std::string,Remoted*> m_listenerMap;
+ boost::scoped_ptr<xmltooling::RWLock> m_listenerLock;
boost::scoped_ptr<xmltooling::ThreadKey> m_threadLocalKey;
};
diff --git a/shibsp/remoting/impl/ListenerService.cpp b/shibsp/remoting/impl/ListenerService.cpp
index 386943e..f70b1a6 100644
--- a/shibsp/remoting/impl/ListenerService.cpp
+++ b/shibsp/remoting/impl/ListenerService.cpp
@@ -62,7 +62,7 @@ Remoted::~Remoted()
{
}
-ListenerService::ListenerService() : m_threadLocalKey(ThreadKey::create(nullptr))
+ListenerService::ListenerService() : m_listenerLock(RWLock::create()), m_threadLocalKey(ThreadKey::create(nullptr))
{
}
@@ -70,26 +70,28 @@ ListenerService::~ListenerService()
{
}
-Remoted* ListenerService::regListener(const char* address, Remoted* listener)
+void ListenerService::regListener(const char* address, Remoted* listener)
{
+ m_listenerLock->wrlock();
+ SharedLock locker(m_listenerLock, false);
+
Remoted* ret=nullptr;
map<string,Remoted*>::const_iterator i=m_listenerMap.find(address);
if (i!=m_listenerMap.end())
ret=i->second;
m_listenerMap[address]=listener;
- Category::getInstance(SHIBSP_LOGCAT ".Listener").info("registered remoted message endpoint (%s)",address);
- return ret;
+ Category::getInstance(SHIBSP_LOGCAT ".Listener").debug("registered remoted message endpoint (%s)",address);
}
-bool ListenerService::unregListener(const char* address, Remoted* current, Remoted* restore)
+bool ListenerService::unregListener(const char* address, Remoted* current)
{
+ m_listenerLock->wrlock();
+ SharedLock locker(m_listenerLock, false);
+
map<string,Remoted*>::const_iterator i=m_listenerMap.find(address);
if (i!=m_listenerMap.end() && i->second==current) {
- if (restore)
- m_listenerMap[address]=restore;
- else
- m_listenerMap.erase(address);
- Category::getInstance(SHIBSP_LOGCAT ".Listener").info("unregistered remoted message endpoint (%s)",address);
+ m_listenerMap.erase(address);
+ Category::getInstance(SHIBSP_LOGCAT ".Listener").debug("unregistered remoted message endpoint (%s)",address);
return true;
}
return false;
@@ -97,6 +99,7 @@ bool ListenerService::unregListener(const char* address, Remoted* current, Remot
Remoted* ListenerService::lookup(const char *address) const
{
+ SharedLock locker(m_listenerLock, true);
map<string,Remoted*>::const_iterator i=m_listenerMap.find(address);
return (i==m_listenerMap.end()) ? nullptr : i->second;
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list