#include "util/DOMPropertySet.h"
#include "util/SPConstants.h"
-#include <log4cpp/Category.hh>
-#include <log4cpp/PropertyConfigurator.hh>
+#if defined(XMLTOOLING_LOG4SHIB)
+# include <log4shib/PropertyConfigurator.hh>
+#elif defined(XMLTOOLING_LOG4CPP)
+# include <log4cpp/PropertyConfigurator.hh>
+#else
+# error "Supported logging library not available."
+#endif
#include <xercesc/util/XMLUniDefs.hpp>
#include <xmltooling/XMLToolingConfig.h>
#include <xmltooling/util/NDC.h>
using namespace shibsp;
using namespace xmltooling;
-using namespace log4cpp;
using namespace std;
namespace {
return (m_audiences.empty() && m_base) ? m_base->getAudiences() : m_audiences;
}
#endif
+ string getNotificationURL(const char* resource, bool front, unsigned int index) const;
+
const set<string>& getRemoteUserAttributeIds() const {
return (m_remoteUsers.empty() && m_base) ? m_base->getRemoteUserAttributeIds() : m_remoteUsers;
}
DDF header;
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());
+ for (vector< pair<string,string> >::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i) {
+ header = DDF(i->first.c_str()).string(i->second.c_str());
ret.add(header);
}
out << ret;
map<const XMLCh*,PropertySet*> m_partyMap;
#endif
#endif
+ vector<string> m_frontLogout,m_backLogout;
set<string> m_remoteUsers;
- mutable vector<string> m_unsetHeaders;
+ mutable vector< pair<string,string> > m_unsetHeaders;
RWLock* m_unsetLock;
// manage handler objects
private:
void doExtensions(const DOMElement* e, const char* label, Category& log);
+ void cleanup();
const XMLConfig* m_outer;
DOMDocument* m_document;
}
// PropertySet
+ const PropertySet* getParent() const { return m_impl->getParent(); }
void setParent(const PropertySet* parent) {return m_impl->setParent(parent);}
pair<bool,bool> getBool(const char* name, const char* ns=NULL) const {return m_impl->getBool(name,ns);}
pair<bool,const char*> getString(const char* name, const char* ns=NULL) const {return m_impl->getString(name,ns);}
static const XMLCh _ArtifactResolutionService[] =UNICODE_LITERAL_25(A,r,t,i,f,a,c,t,R,e,s,o,l,u,t,i,o,n,S,e,r,v,i,c,e);
static const XMLCh _Audience[] = UNICODE_LITERAL_8(A,u,d,i,e,n,c,e);
static const XMLCh Binding[] = UNICODE_LITERAL_7(B,i,n,d,i,n,g);
+ 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 DefaultRelyingParty[] = UNICODE_LITERAL_19(D,e,f,a,u,l,t,R,e,l,y,i,n,g,P,a,r,t,y);
static const XMLCh _Extensions[] = UNICODE_LITERAL_10(E,x,t,e,n,s,i,o,n,s);
static const XMLCh InProcess[] = UNICODE_LITERAL_9(I,n,P,r,o,c,e,s,s);
static const XMLCh Library[] = UNICODE_LITERAL_7(L,i,b,r,a,r,y);
static const XMLCh Listener[] = UNICODE_LITERAL_8(L,i,s,t,e,n,e,r);
+ static const XMLCh Location[] = UNICODE_LITERAL_8(L,o,c,a,t,i,o,n);
static const XMLCh logger[] = UNICODE_LITERAL_6(l,o,g,g,e,r);
+ static const XMLCh _LogoutInitiator[] = UNICODE_LITERAL_15(L,o,g,o,u,t,I,n,i,t,i,a,t,o,r);
static const XMLCh _ManageNameIDService[] = UNICODE_LITERAL_19(M,a,n,a,g,e,N,a,m,e,I,D,S,e,r,v,i,c,e);
static const XMLCh MemoryListener[] = UNICODE_LITERAL_14(M,e,m,o,r,y,L,i,s,t,e,n,e,r);
static const XMLCh _MetadataProvider[] = UNICODE_LITERAL_16(M,e,t,a,d,a,t,a,P,r,o,v,i,d,e,r);
+ static const XMLCh Notify[] = UNICODE_LITERAL_6(N,o,t,i,f,y);
static const XMLCh OutOfProcess[] = UNICODE_LITERAL_12(O,u,t,O,f,P,r,o,c,e,s,s);
static const XMLCh _path[] = UNICODE_LITERAL_4(p,a,t,h);
static const XMLCh Policy[] = UNICODE_LITERAL_6(P,o,l,i,c,y);
static const XMLCh _type[] = UNICODE_LITERAL_4(t,y,p,e);
static const XMLCh UnixListener[] = UNICODE_LITERAL_12(U,n,i,x,L,i,s,t,e,n,e,r);
+
class SHIBSP_DLLLOCAL PolicyNodeFilter : public DOMNodeFilter
{
public:
pos = strchr(start,' ');
if (pos)
*pos=0;
- m_unsetHeaders.push_back(start);
+
+ string transformed("HTTP_");
+ const char* pch = start;
+ while (*pch) {
+ transformed += (isalnum(*pch) ? toupper(*pch) : '_');
+ pch++;
+ }
+ m_unsetHeaders.push_back(pair<string,string>(start,transformed));
start = pos ? pos+1 : NULL;
}
free(dup);
- m_unsetHeaders.push_back("Shib-Application-ID");
+ m_unsetHeaders.push_back(pair<string,string>("Shib-Application-ID","HTTP_SHIB_APPLICATION_ID"));
}
}
handler = conf.HandlerManager.newPlugin(samlconstants::SAML20_BINDING_URI, make_pair(sessions->getElement(), getId()));
m_handlers.push_back(handler);
- // Insert into location map.
+ // Insert into location map. If it contains the handlerURL, we skip past that part.
+ const char* pch = strstr(location.second, sessions->getString("handlerURL").second);
+ if (pch)
+ location.second = pch + strlen(sessions->getString("handlerURL").second);
if (*location.second == '/')
m_handlerMap[location.second]=handler;
else
m_sessionInitDefault=sihandler;
}
}
+ else if (XMLString::equals(child->getLocalName(),_LogoutInitiator)) {
+ auto_ptr_char type(child->getAttributeNS(NULL,_type));
+ if (!type.get() || !*(type.get())) {
+ log.warn("LogoutInitiator element has no type attribute, skipping it...");
+ child = XMLHelper::getNextSiblingElement(child);
+ continue;
+ }
+ handler=conf.LogoutInitiatorManager.newPlugin(type.get(),make_pair(child, getId()));
+ }
else if (XMLString::equals(child->getLocalName(),_ArtifactResolutionService)) {
auto_ptr_char bindprop(child->getAttributeNS(NULL,Binding));
if (!bindprop.get() || !*(bindprop.get())) {
child = XMLHelper::getNextSiblingElement(child);
}
+ // Notification.
+ DOMNodeList* nlist=e->getElementsByTagNameNS(shibspconstants::SHIB2SPCONFIG_NS,Notify);
+ for (XMLSize_t i=0; nlist && i<nlist->getLength(); i++) {
+ if (nlist->item(i)->getParentNode()->isSameNode(e)) {
+ const XMLCh* channel = static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,Channel);
+ auto_ptr_char loc(static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,Location));
+ if (loc.get() && *loc.get()) {
+ if (channel && *channel == chLatin_f)
+ m_frontLogout.push_back(loc.get());
+ else
+ m_backLogout.push_back(loc.get());
+ }
+ }
+ }
+
#ifndef SHIBSP_LITE
- DOMNodeList* nlist=e->getElementsByTagNameNS(samlconstants::SAML20_NS,Audience::LOCAL_NAME);
+ nlist=e->getElementsByTagNameNS(samlconstants::SAML20_NS,Audience::LOCAL_NAME);
for (XMLSize_t i=0; nlist && i<nlist->getLength(); i++)
if (nlist->item(i)->getParentNode()->isSameNode(e) && nlist->item(i)->hasChildNodes())
m_audiences.push_back(nlist->item(i)->getFirstChild()->getNodeValue());
}
if (m_unsetHeaders.empty()) {
+ vector<string> unsetHeaders;
if (m_attrExtractor) {
Locker extlock(m_attrExtractor);
- m_attrExtractor->getAttributeIds(m_unsetHeaders);
+ m_attrExtractor->getAttributeIds(unsetHeaders);
}
if (m_attrResolver) {
Locker reslock(m_attrResolver);
- m_attrResolver->getAttributeIds(m_unsetHeaders);
+ m_attrResolver->getAttributeIds(unsetHeaders);
+ }
+ if (unsetHeaders.empty()) {
+ if (m_base)
+ m_unsetHeaders.insert(m_unsetHeaders.end(), m_base->m_unsetHeaders.begin(), m_base->m_unsetHeaders.end());
+ else
+ m_unsetHeaders.push_back(pair<string,string>("Shib-Application-ID","HTTP_SHIB_APPLICATION_ID"));
+ }
+ else {
+ for (vector<string>::const_iterator hdr = unsetHeaders.begin(); hdr!=unsetHeaders.end(); ++hdr) {
+ string transformed("HTTP_");
+ const char* pch = hdr->c_str();
+ while (*pch) {
+ transformed += (isalnum(*pch) ? toupper(*pch) : '_');
+ pch++;
+ }
+ m_unsetHeaders.push_back(pair<string,string>(*hdr,transformed));
+ }
+ m_unsetHeaders.push_back(pair<string,string>("Shib-Application-ID","HTTP_SHIB_APPLICATION_ID"));
}
- if (m_base && m_unsetHeaders.empty())
- m_unsetHeaders.insert(m_unsetHeaders.end(), m_base->m_unsetHeaders.begin(), m_base->m_unsetHeaders.end());
- else
- m_unsetHeaders.push_back("Shib-Application-ID");
}
}
listener->unregListener(addr.c_str(),this);
}
delete m_unsetLock;
+ m_unsetLock = NULL;
for_each(m_handlers.begin(),m_handlers.end(),xmltooling::cleanup<Handler>());
+ m_handlers.clear();
#ifndef SHIBSP_LITE
delete m_partyDefault;
+ m_partyDefault = NULL;
#ifdef HAVE_GOOD_STL
for_each(m_partyMap.begin(),m_partyMap.end(),cleanup_pair<xstring,PropertySet>());
#else
for_each(m_partyMap.begin(),m_partyMap.end(),cleanup_pair<const XMLCh*,PropertySet>());
#endif
+ m_partyMap.clear();
delete m_credResolver;
+ m_credResolver = NULL;
delete m_attrResolver;
+ m_attrResolver = NULL;
delete m_attrFilter;
+ m_attrFilter = NULL;
delete m_attrExtractor;
+ m_attrExtractor = NULL;
delete m_trust;
+ m_trust = NULL;
delete m_metadata;
+ m_metadata = NULL;
#endif
}
const XMLCh* name=node->getLocalName();
if (XMLString::equals(name,_Application) ||
XMLString::equals(name,_Audience) ||
+ XMLString::equals(name,Notify) ||
XMLString::equals(name,_AssertionConsumerService) ||
XMLString::equals(name,_ArtifactResolutionService) ||
- XMLString::equals(name,_SingleLogoutService) ||
+ XMLString::equals(name,_LogoutInitiator) ||
XMLString::equals(name,_ManageNameIDService) ||
XMLString::equals(name,_SessionInitiator) ||
+ XMLString::equals(name,_SingleLogoutService) ||
XMLString::equals(name,DefaultRelyingParty) ||
XMLString::equals(name,RelyingParty) ||
XMLString::equals(name,_MetadataProvider) ||
#else
map<const XMLCh*,PropertySet*>::const_iterator i=m_partyMap.begin();
for (; i!=m_partyMap.end(); i++) {
- if (XMLString::equals(i->first,provider->getId()))
+ if (XMLString::equals(i->first,provider->getEntityID()))
return i->second;
const EntitiesDescriptor* group=dynamic_cast<const EntitiesDescriptor*>(provider->getParent());
while (group) {
#endif
+string XMLApplication::getNotificationURL(const char* resource, bool front, unsigned int index) const
+{
+ const vector<string>& locs = front ? m_frontLogout : m_backLogout;
+ if (locs.empty())
+ return m_base ? m_base->getNotificationURL(resource, front, index) : string();
+ else if (index >= locs.size())
+ return string();
+
+#ifdef HAVE_STRCASECMP
+ if (!resource || (strncasecmp(resource,"http://",7) && strncasecmp(resource,"https://",8)))
+#else
+ if (!resource || (strnicmp(resource,"http://",7) && strnicmp(resource,"https://",8)))
+#endif
+ throw ConfigurationException("Request URL was not absolute.");
+
+ const char* handler=locs[index].c_str();
+
+ // Should never happen...
+ if (!handler || (*handler!='/' && strncmp(handler,"http:",5) && strncmp(handler,"https:",6)))
+ throw ConfigurationException(
+ "Invalid Location property ($1) in Notify element for Application ($2)",
+ params(2, handler ? handler : "null", getId())
+ );
+
+ // The "Location" property can be in one of three formats:
+ //
+ // 1) a full URI: http://host/foo/bar
+ // 2) a hostless URI: http:///foo/bar
+ // 3) a relative path: /foo/bar
+ //
+ // # Protocol Host Path
+ // 1 handler handler handler
+ // 2 handler resource handler
+ // 3 resource resource handler
+
+ const char* path = NULL;
+
+ // Decide whether to use the handler or the resource for the "protocol"
+ const char* prot;
+ if (*handler != '/') {
+ prot = handler;
+ }
+ else {
+ prot = resource;
+ path = handler;
+ }
+
+ // break apart the "protocol" string into protocol, host, and "the rest"
+ const char* colon=strchr(prot,':');
+ colon += 3;
+ const char* slash=strchr(colon,'/');
+ if (!path)
+ path = slash;
+
+ // Compute the actual protocol and store.
+ string notifyURL(prot, colon-prot);
+
+ // create the "host" from either the colon/slash or from the target string
+ // If prot == handler then we're in either #1 or #2, else #3.
+ // If slash == colon then we're in #2.
+ if (prot != handler || slash == colon) {
+ colon = strchr(resource, ':');
+ colon += 3; // Get past the ://
+ slash = strchr(colon, '/');
+ }
+ string host(colon, (slash ? slash-colon : strlen(colon)));
+
+ // Build the URL
+ notifyURL += host + path;
+ return notifyURL;
+}
+
const SessionInitiator* XMLApplication::getDefaultSessionInitiator() const
{
if (m_sessionInitDefault) return m_sessionInitDefault;
void XMLApplication::clearAttributeHeaders(SPRequest& request) const
{
if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
- for (vector<string>::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i)
- request.clearHeader(i->c_str());
+ for (vector< pair<string,string> >::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i)
+ request.clearHeader(i->first.c_str(), i->second.c_str());
return;
}
if (out.islist()) {
DDF header = out.first();
while (header.isstring()) {
- m_unsetHeaders.push_back(header.string());
+ m_unsetHeaders.push_back(pair<string,string>(header.name(),header.string()));
header = out.next();
}
}
// Now holding read lock.
SharedLock unsetLock(m_unsetLock, false);
- for (vector<string>::const_iterator i = m_unsetHeaders.begin(); i!=m_unsetHeaders.end(); ++i)
- request.clearHeader(i->c_str());
+ for (vector< pair<string,string> >::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
}
}
catch (exception&) {
- this->~XMLConfigImpl();
+ cleanup();
throw;
}
#ifndef _DEBUG
catch (...) {
- this->~XMLConfigImpl();
+ cleanup();
throw;
}
#endif
XMLConfigImpl::~XMLConfigImpl()
{
+ cleanup();
+}
+
+void XMLConfigImpl::cleanup()
+{
for_each(m_appmap.begin(),m_appmap.end(),cleanup_pair<string,Application>());
+ m_appmap.clear();
#ifndef SHIBSP_LITE
for (map< string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::iterator i=m_policyMap.begin(); i!=m_policyMap.end(); ++i) {
delete i->second.first;
for_each(i->second.second.begin(), i->second.second.end(), xmltooling::cleanup<SecurityPolicyRule>());
}
+ m_policyMap.clear();
#endif
delete m_requestMapper;
+ m_requestMapper = NULL;
if (m_document)
m_document->release();
+ m_document = NULL;
}
void XMLConfig::receive(DDF& in, ostream& out)