static vector<const Handler*> g_noHandlers;\r
\r
// Application configuration wrapper\r
- class SHIBSP_DLLLOCAL XMLApplication : public virtual Application, public DOMPropertySet, public DOMNodeFilter\r
+ class SHIBSP_DLLLOCAL XMLApplication : public virtual Application, public Remoted, public DOMPropertySet, public DOMNodeFilter\r
{\r
public:\r
XMLApplication(const ServiceProvider*, const DOMElement* e, const XMLApplication* base=NULL);\r
}\r
#endif\r
const set<string>& getRemoteUserAttributeIds() const {\r
- return (m_attributeIds.empty() && m_base) ? m_base->getRemoteUserAttributeIds() : m_attributeIds;\r
+ return (m_remoteUsers.empty() && m_base) ? m_base->getRemoteUserAttributeIds() : m_remoteUsers;\r
}\r
\r
+ void clearAttributeHeaders(SPRequest& request) const;\r
const SessionInitiator* getDefaultSessionInitiator() const;\r
const SessionInitiator* getSessionInitiatorById(const char* id) const;\r
const Handler* getDefaultAssertionConsumerService() const;\r
const vector<const Handler*>& getAssertionConsumerServicesByBinding(const XMLCh* binding) const;\r
const Handler* getHandler(const char* path) const;\r
\r
+ void receive(DDF& in, ostream& out) {\r
+ DDF header;\r
+ DDF ret=DDF(NULL).list();
+ DDFJanitor jret(ret);
+ for (vector<string>::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i) {
+ header = DDF(NULL).string(i->c_str());
+ ret.add(header);
+ }
+ out << ret;
+ }\r
+\r
// Provides filter to exclude special config elements.\r
short acceptNode(const DOMNode* node) const;\r
\r
CredentialResolver* m_credResolver;\r
vector<const XMLCh*> m_audiences;\r
#endif\r
- set<string> m_attributeIds;\r
+ set<string> m_remoteUsers;\r
+ mutable vector<string> m_unsetHeaders;\r
+ RWLock* m_unsetLock;\r
\r
// manage handler objects\r
vector<Handler*> m_handlers;\r
#ifndef SHIBSP_LITE\r
m_metadata(NULL), m_trust(NULL), m_attrExtractor(NULL), m_attrFilter(NULL), m_attrResolver(NULL), m_credResolver(NULL), m_partyDefault(NULL),\r
#endif\r
- m_sessionInitDefault(NULL), m_acsDefault(NULL)\r
+ m_sessionInitDefault(NULL), m_unsetLock(NULL), m_acsDefault(NULL)\r
{\r
#ifdef _DEBUG\r
xmltooling::NDC ndc("XMLApplication");\r
#endif\r
XMLToolingConfig& xmlConf=XMLToolingConfig::getConfig();\r
\r
- m_hash=getId();\r
- m_hash+=getString("entityID").second;\r
- // TODO: some kind of non-hash method\r
- //m_hash=samlConf.hashSHA1(m_hash.c_str(), true);\r
-\r
- pair<bool,const char*> attributes = getString("REMOTE_USER");\r
- if (attributes.first) {\r
- char* dup = strdup(attributes.second);\r
- char* pos;\r
- char* start = dup;\r
- while (start && *start) {\r
- while (*start && isspace(*start))\r
- start++;\r
- if (!*start)\r
- break;\r
- pos = strchr(start,' ');\r
- if (pos)\r
- *pos=0;\r
- m_attributeIds.insert(start);\r
- start = pos ? pos+1 : NULL;\r
+ // This used to be an actual hash, but now it's just a hex-encode to avoid xmlsec.\r
+ static char DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};\r
+ string tohash=getId();\r
+ tohash+=getString("entityID").second;\r
+ for (const char* ch = tohash.c_str(); *ch; ++ch) {\r
+ m_hash += (DIGITS[((unsigned char)(0xF0 & *ch)) >> 4 ]);\r
+ m_hash += (DIGITS[0x0F & *ch]);\r
+ }\r
+\r
+ // Load attribute ID lists for REMOTE_USER and header clearing.\r
+ if (conf.isEnabled(SPConfig::InProcess)) {\r
+ pair<bool,const char*> attributes = getString("REMOTE_USER");\r
+ if (attributes.first) {\r
+ char* dup = strdup(attributes.second);\r
+ char* pos;\r
+ char* start = dup;\r
+ while (start && *start) {\r
+ while (*start && isspace(*start))\r
+ start++;\r
+ if (!*start)\r
+ break;\r
+ pos = strchr(start,' ');\r
+ if (pos)\r
+ *pos=0;\r
+ m_remoteUsers.insert(start);\r
+ start = pos ? pos+1 : NULL;\r
+ }\r
+ free(dup);\r
+ }\r
+\r
+ attributes = getString("unsetHeaders");\r
+ if (attributes.first) {\r
+ char* dup = strdup(attributes.second);\r
+ char* pos;\r
+ char* start = dup;\r
+ while (start && *start) {\r
+ while (*start && isspace(*start))\r
+ start++;\r
+ if (!*start)\r
+ break;\r
+ pos = strchr(start,' ');\r
+ if (pos)\r
+ *pos=0;\r
+ m_unsetHeaders.push_back(start);\r
+ start = pos ? pos+1 : NULL;\r
+ }\r
+ free(dup);\r
+ m_unsetHeaders.push_back("Shib-Application-ID");\r
}\r
- free(dup);\r
}\r
\r
const PropertySet* sessions = getPropertySet("Sessions");\r
log.crit("error building AttributeResolver: %s", ex.what());\r
}\r
}\r
+\r
+ if (m_unsetHeaders.empty()) {\r
+ if (m_attrExtractor) {\r
+ Locker extlock(m_attrExtractor);\r
+ m_attrExtractor->getAttributeIds(m_unsetHeaders);\r
+ }\r
+ if (m_attrResolver) {\r
+ Locker reslock(m_attrResolver);\r
+ m_attrResolver->getAttributeIds(m_unsetHeaders);\r
+ }\r
+ if (m_base && m_unsetHeaders.empty())\r
+ m_unsetHeaders.insert(m_unsetHeaders.end(), m_base->m_unsetHeaders.begin(), m_base->m_unsetHeaders.end());\r
+ else\r
+ m_unsetHeaders.push_back("Shib-Application-ID");\r
+ }\r
}\r
\r
if (conf.isEnabled(SPConfig::Credentials)) {\r
child = XMLHelper::getNextSiblingElement(child,RelyingParty);\r
}\r
}\r
-#endif \r
+#endif\r
+\r
+ // In process only, we need a shared lock around accessing the header clearing list.\r
+ if (!conf.isEnabled(SPConfig::OutOfProcess)) {\r
+ m_unsetLock = RWLock::create();\r
+ }\r
+ else 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");
+ }
}\r
catch (exception&) {\r
cleanup();\r
\r
void XMLApplication::cleanup()\r
{\r
+ ListenerService* listener=getServiceProvider().getListenerService(false);
+ if (listener && SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess) && !SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
+ string addr=string(getId()) + "::getHeaders::Application";
+ listener->unregListener(addr.c_str(),this);
+ }
+ delete m_unsetLock;\r
for_each(m_handlers.begin(),m_handlers.end(),xmltooling::cleanup<Handler>());\r
#ifndef SHIBSP_LITE\r
delete m_partyDefault;\r
return m_base ? m_base->getHandler(path) : NULL;\r
}\r
\r
+void XMLApplication::clearAttributeHeaders(SPRequest& request) const\r
+{\r
+ if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {\r
+ for (vector<string>::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i)\r
+ request.clearHeader(i->c_str());\r
+ return;\r
+ }\r
+\r
+ m_unsetLock->rdlock();\r
+ if (m_unsetHeaders.empty()) {\r
+ // No headers yet, so we have to request them from the remote half.\r
+ m_unsetLock->unlock();\r
+ m_unsetLock->wrlock();\r
+ if (m_unsetHeaders.empty()) {\r
+ SharedLock wrlock(m_unsetLock, false);\r
+ string addr=string(getId()) + "::getHeaders::Application";\r
+ 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(header.string());
+ header = out.next();
+ }
+ }
+ }\r
+ else {\r
+ m_unsetLock->unlock();\r
+ }\r
+ m_unsetLock->rdlock();\r
+ }\r
+\r
+ // Now holding read lock.\r
+ SharedLock unsetLock(m_unsetLock, false);\r
+ for (vector<string>::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i)\r
+ request.clearHeader(i->c_str());\r
+}\r
+\r
short XMLConfigImpl::acceptNode(const DOMNode* node) const\r
{\r
if (!XMLString::equals(node->getNamespaceURI(),shibspconstants::SHIB2SPCONFIG_NS))\r