From 860f19710435e3d23ce484b017e5291815320885 Mon Sep 17 00:00:00 2001 From: cantor Date: Tue, 21 Aug 2007 04:33:41 +0000 Subject: [PATCH] Move to a "prefixed" model for metadata attributes and separate from session. git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@2441 cb58f699-b61c-0410-a6fe-9272a202ed29 --- schemas/shibboleth-2.0-native-sp-config.xsd | 1 + shibsp/Application.cpp | 63 +++++++++++++++ shibsp/Application.h | 52 +++++++++++-- shibsp/ServiceProvider.cpp | 28 +++++++ shibsp/handler/impl/AssertionConsumerService.cpp | 13 +--- shibsp/impl/XMLServiceProvider.cpp | 98 +++++++++--------------- 6 files changed, 175 insertions(+), 80 deletions(-) diff --git a/schemas/shibboleth-2.0-native-sp-config.xsd b/schemas/shibboleth-2.0-native-sp-config.xsd index 2b7ee70..9341fc6 100644 --- a/schemas/shibboleth-2.0-native-sp-config.xsd +++ b/schemas/shibboleth-2.0-native-sp-config.xsd @@ -454,6 +454,7 @@ + diff --git a/shibsp/Application.cpp b/shibsp/Application.cpp index 2488c1d..3c21cfb 100644 --- a/shibsp/Application.cpp +++ b/shibsp/Application.cpp @@ -22,10 +22,28 @@ #include "internal.h" #include "Application.h" +#include "SPRequest.h" +#include "ServiceProvider.h" +#include "attribute/Attribute.h" +#include "remoting/ListenerService.h" + +#include using namespace shibsp; +using namespace xmltooling; using namespace std; +Application::Application(const ServiceProvider* sp) : m_sp(sp), m_lock(RWLock::create()) +{ +} + +Application::~Application() +{ + delete m_lock; + for (map< string,multimap >::iterator i = m_entityAttributes.begin(); i!=m_entityAttributes.end(); ++i) + for_each(i->second.begin(), i->second.end(), cleanup_const_pair()); +} + pair Application::getCookieNameProps(const char* prefix) const { static const char* defProps="; path=/"; @@ -44,3 +62,48 @@ pair Application::getCookieNameProps(const char* prefix) con // Shouldn't happen, but just in case.. return pair(prefix,defProps); } + +void Application::clearAttributeHeaders(SPRequest& request) const +{ + if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) { + for (vector< pair >::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i) + request.clearHeader(i->first.c_str(), i->second.c_str()); + return; + } + + m_lock->rdlock(); + if (m_unsetHeaders.empty()) { + // No headers yet, so we have to request them from the remote half. + m_lock->unlock(); + m_lock->wrlock(); + if (m_unsetHeaders.empty()) { + SharedLock wrlock(m_lock, false); + string addr=string(getId()) + "::getHeaders::Application"; + DDF out,in = DDF(addr.c_str()); + DDFJanitor jin(in),jout(out); + out = getServiceProvider().getListenerService()->send(in); + if (out.islist()) { + DDF header = out.first(); + while (header.isstring()) { + m_unsetHeaders.push_back(pair(header.name(),header.string())); + header = out.next(); + } + } + } + else { + m_lock->unlock(); + } + m_lock->rdlock(); + } + + // Now holding read lock. + SharedLock unsetLock(m_lock, false); + for (vector< pair >::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i) + request.clearHeader(i->first.c_str(), i->second.c_str()); +} + +const multimap& Application::getEntityAttributes(const char* entityID) const +{ + // TODO + return m_entityAttributes[entityID]; +} diff --git a/shibsp/Application.h b/shibsp/Application.h index 118467f..e4d9c0b 100644 --- a/shibsp/Application.h +++ b/shibsp/Application.h @@ -33,6 +33,7 @@ # include #endif #include +#include namespace shibsp { @@ -41,11 +42,17 @@ namespace shibsp { class SHIBSP_API AttributeFilter; class SHIBSP_API AttributeResolver; #endif + class SHIBSP_API Attribute; class SHIBSP_API Handler; class SHIBSP_API ServiceProvider; class SHIBSP_API SessionInitiator; class SHIBSP_API SPRequest; +#if defined (_MSC_VER) + #pragma warning( push ) + #pragma warning( disable : 4251 ) +#endif + /** * Interface to a Shibboleth Application instance. * @@ -59,23 +66,45 @@ namespace shibsp { { MAKE_NONCOPYABLE(Application); protected: - Application() {} + /** + * Constructor. + * + * @param sp parent ServiceProvider instance + */ + Application(const ServiceProvider* sp); + + /** Pointer to parent SP instance. */ + const ServiceProvider* m_sp; + + /** Shared lock for manipulating application state. */ + mutable xmltooling::RWLock* m_lock; + + /** Cache of entity attributes. */ + mutable std::map< std::string,std::multimap > m_entityAttributes; + + /** Pairs of raw and normalized CGI header names to clear. */ + mutable std::vector< std::pair > m_unsetHeaders; + public: - virtual ~Application() {} + virtual ~Application(); /** * Returns the owning ServiceProvider instance. * * @return a locked ServiceProvider */ - virtual const ServiceProvider& getServiceProvider() const=0; + const ServiceProvider& getServiceProvider() const { + return *m_sp; + } /** * Returns the Application's ID. * * @return the ID */ - virtual const char* getId() const=0; + virtual const char* getId() const { + return getString("id").second; + } /** * Returns a unique hash for the Application. @@ -176,7 +205,15 @@ namespace shibsp { * * @param request SP request to clear */ - virtual void clearAttributeHeaders(SPRequest& request) const=0; + virtual void clearAttributeHeaders(SPRequest& request) const; + + /** + * Returns an indexed set of attributes associated with an entity (as opposed to a user). + * + * @param entityID unique ID of entity + * @return a map of attributes keyed by their ID + */ + virtual const std::multimap& getEntityAttributes(const char* entityID) const; /** * Returns the default SessionInitiator when automatically requesting a session. @@ -228,6 +265,11 @@ namespace shibsp { */ virtual const Handler* getHandler(const char* path) const=0; }; + +#if defined (_MSC_VER) + #pragma warning( pop ) +#endif + }; #endif /* __shibsp_app_h__ */ diff --git a/shibsp/ServiceProvider.cpp b/shibsp/ServiceProvider.cpp index c4b70b8..6bd3d6f 100644 --- a/shibsp/ServiceProvider.cpp +++ b/shibsp/ServiceProvider.cpp @@ -424,6 +424,34 @@ pair ServiceProvider::doExport(SPRequest& request, bool requireSessio } request.setHeader(a->first.c_str(), header.c_str()); } + + // Maybe export metadata attributes. + pair prefix = app->getString("metadataAttributePrefix"); + if (prefix.first && session->getEntityID()) { + const multimap& eattributes = app->getEntityAttributes(session->getEntityID()); + for (multimap::const_iterator a = eattributes.begin(); a!=eattributes.end(); ++a) { + string hname = string(prefix.second) + a->first; + string header(request.getSecureHeader(hname.c_str())); + const vector& vals = a->second->getSerializedValues(); + for (vector::const_iterator v = vals.begin(); v!=vals.end(); ++v) { + if (!header.empty()) + header += ";"; + string::size_type pos = v->find_first_of(';',string::size_type(0)); + if (pos!=string::npos) { + string value(*v); + for (; pos != string::npos; pos = value.find_first_of(';',pos)) { + value.insert(pos, "\\"); + pos += 2; + } + header += value; + } + else { + header += (*v); + } + } + request.setHeader(hname.c_str(), header.c_str()); + } + } return make_pair(false,0); } diff --git a/shibsp/handler/impl/AssertionConsumerService.cpp b/shibsp/handler/impl/AssertionConsumerService.cpp index eed44ec..c7cdc8e 100644 --- a/shibsp/handler/impl/AssertionConsumerService.cpp +++ b/shibsp/handler/impl/AssertionConsumerService.cpp @@ -281,22 +281,11 @@ ResolutionContext* AssertionConsumerService::resolveAttributes( const vector* tokens ) const { - const saml2md::EntityDescriptor* entity = dynamic_cast(issuer->getParent()); - // First we do the extraction of any pushed information, including from metadata. vector resolvedAttributes; AttributeExtractor* extractor = application.getAttributeExtractor(); if (extractor) { Locker extlocker(extractor); - if (entity) { - m_log.debug("extracting metadata-derived attributes..."); - try { - extractor->extractAttributes(application, issuer, *entity, resolvedAttributes); - } - catch (exception& ex) { - m_log.error("caught exception extracting attributes: %s", ex.what()); - } - } m_log.debug("extracting pushed attributes..."); if (v1nameid) { try { @@ -350,7 +339,7 @@ ResolutionContext* AssertionConsumerService::resolveAttributes( auto_ptr ctx( resolver->createResolutionContext( application, - entity, + issuer ? dynamic_cast(issuer->getParent()) : NULL, protocol, nameid, authncontext_class, diff --git a/shibsp/impl/XMLServiceProvider.cpp b/shibsp/impl/XMLServiceProvider.cpp index eb01515..cf5dd81 100644 --- a/shibsp/impl/XMLServiceProvider.cpp +++ b/shibsp/impl/XMLServiceProvider.cpp @@ -28,7 +28,6 @@ #include "ServiceProvider.h" #include "SessionCache.h" #include "SPConfig.h" -#include "SPRequest.h" #include "handler/SessionInitiator.h" #include "remoting/ListenerService.h" #include "util/DOMPropertySet.h" @@ -87,9 +86,6 @@ namespace { XMLApplication(const ServiceProvider*, const DOMElement* e, const XMLApplication* base=NULL); ~XMLApplication() { cleanup(); } - // Application - const ServiceProvider& getServiceProvider() const {return *m_sp;} - const char* getId() const {return getString("id").second;} const char* getHash() const {return m_hash.c_str();} #ifndef SHIBSP_LITE @@ -139,7 +135,6 @@ namespace { return (m_remoteUsers.empty() && m_base) ? m_base->getRemoteUserAttributeIds() : m_remoteUsers; } - void clearAttributeHeaders(SPRequest& request) const; const SessionInitiator* getDefaultSessionInitiator() const; const SessionInitiator* getSessionInitiatorById(const char* id) const; const Handler* getDefaultAssertionConsumerService() const; @@ -164,7 +159,6 @@ namespace { private: void cleanup(); - const ServiceProvider* m_sp; // this is ok because its locking scope includes us const XMLApplication* m_base; string m_hash; #ifndef SHIBSP_LITE @@ -184,10 +178,8 @@ namespace { map m_partyMap; #endif #endif + std::set m_remoteUsers; vector m_frontLogout,m_backLogout; - set m_remoteUsers; - mutable vector< pair > m_unsetHeaders; - RWLock* m_unsetLock; // manage handler objects vector m_handlers; @@ -456,13 +448,13 @@ XMLApplication::XMLApplication( const ServiceProvider* sp, const DOMElement* e, const XMLApplication* base - ) : m_sp(sp), m_base(base), + ) : Application(sp), m_base(base), #ifndef SHIBSP_LITE m_metadata(NULL), m_trust(NULL), m_attrExtractor(NULL), m_attrFilter(NULL), m_attrResolver(NULL), m_credResolver(NULL), m_partyDefault(NULL), #endif - m_unsetLock(NULL), m_acsDefault(NULL), m_sessionInitDefault(NULL), m_artifactResolutionDefault(NULL) + m_acsDefault(NULL), m_sessionInitDefault(NULL), m_artifactResolutionDefault(NULL) { #ifdef _DEBUG xmltooling::NDC ndc("XMLApplication"); @@ -513,6 +505,16 @@ XMLApplication::XMLApplication( attributes = getString("unsetHeaders"); if (attributes.first) { + string transformedprefix("HTTP_"); + const char* pch; + pair prefix = getString("metadataAttributePrefix"); + if (prefix.first) { + pch = prefix.second; + while (*pch) { + transformedprefix += (isalnum(*pch) ? toupper(*pch) : '_'); + pch++; + } + } char* dup = strdup(attributes.second); char* pos; char* start = dup; @@ -525,13 +527,15 @@ XMLApplication::XMLApplication( if (pos) *pos=0; - string transformed("HTTP_"); - const char* pch = start; + string transformed; + pch = start; while (*pch) { transformed += (isalnum(*pch) ? toupper(*pch) : '_'); pch++; } - m_unsetHeaders.push_back(pair(start,transformed)); + m_unsetHeaders.push_back(pair(start,string("HTTP_") + transformed)); + if (prefix.first) + m_unsetHeaders.push_back(pair(string(prefix.second) + start, transformedprefix + transformed)); start = pos ? pos+1 : NULL; } free(dup); @@ -805,14 +809,26 @@ XMLApplication::XMLApplication( m_unsetHeaders.push_back(pair("Shib-Application-ID","HTTP_SHIB_APPLICATION_ID")); } else { + string transformedprefix("HTTP_"); + const char* pch; + pair prefix = getString("metadataAttributePrefix"); + if (prefix.first) { + pch = prefix.second; + while (*pch) { + transformedprefix += (isalnum(*pch) ? toupper(*pch) : '_'); + pch++; + } + } for (vector::const_iterator hdr = unsetHeaders.begin(); hdr!=unsetHeaders.end(); ++hdr) { - string transformed("HTTP_"); - const char* pch = hdr->c_str(); + string transformed; + pch = hdr->c_str(); while (*pch) { transformed += (isalnum(*pch) ? toupper(*pch) : '_'); pch++; } - m_unsetHeaders.push_back(pair(*hdr,transformed)); + m_unsetHeaders.push_back(pair(*hdr, string("HTTP_") + transformed)); + if (prefix.first) + m_unsetHeaders.push_back(pair(string(prefix.second) + *hdr, transformedprefix + transformed)); } m_unsetHeaders.push_back(pair("Shib-Application-ID","HTTP_SHIB_APPLICATION_ID")); } @@ -849,11 +865,8 @@ XMLApplication::XMLApplication( } #endif - // In process only, we need a shared lock around accessing the header clearing list. - if (!conf.isEnabled(SPConfig::OutOfProcess)) { - m_unsetLock = RWLock::create(); - } - else if (!conf.isEnabled(SPConfig::InProcess)) { + // 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"; @@ -882,8 +895,6 @@ void XMLApplication::cleanup() string addr=string(getId()) + "::getHeaders::Application"; listener->unregListener(addr.c_str(),this); } - delete m_unsetLock; - m_unsetLock = NULL; for_each(m_handlers.begin(),m_handlers.end(),xmltooling::cleanup()); m_handlers.clear(); #ifndef SHIBSP_LITE @@ -1095,45 +1106,6 @@ const Handler* XMLApplication::getHandler(const char* path) const return m_base ? m_base->getHandler(path) : NULL; } -void XMLApplication::clearAttributeHeaders(SPRequest& request) const -{ - if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) { - for (vector< pair >::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i) - request.clearHeader(i->first.c_str(), i->second.c_str()); - return; - } - - m_unsetLock->rdlock(); - if (m_unsetHeaders.empty()) { - // No headers yet, so we have to request them from the remote half. - m_unsetLock->unlock(); - m_unsetLock->wrlock(); - if (m_unsetHeaders.empty()) { - SharedLock wrlock(m_unsetLock, false); - string addr=string(getId()) + "::getHeaders::Application"; - DDF out,in = DDF(addr.c_str()); - DDFJanitor jin(in),jout(out); - out = getServiceProvider().getListenerService()->send(in); - if (out.islist()) { - DDF header = out.first(); - while (header.isstring()) { - m_unsetHeaders.push_back(pair(header.name(),header.string())); - header = out.next(); - } - } - } - else { - m_unsetLock->unlock(); - } - m_unsetLock->rdlock(); - } - - // Now holding read lock. - SharedLock unsetLock(m_unsetLock, false); - for (vector< pair >::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i) - request.clearHeader(i->first.c_str(), i->second.c_str()); -} - short XMLConfigImpl::acceptNode(const DOMNode* node) const { if (!XMLString::equals(node->getNamespaceURI(),shibspconstants::SHIB2SPCONFIG_NS)) -- 2.1.4