-/*
- * The Shibboleth License, Version 1.
- * Copyright (c) 2002
- * University Corporation for Advanced Internet Development, Inc.
- * All rights reserved
+/*
+ * Copyright 2001-2005 Internet2
*
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution, if any, must include
- * the following acknowledgment: "This product includes software developed by
- * the University Corporation for Advanced Internet Development
- * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement
- * may appear in the software itself, if and wherever such third-party
- * acknowledgments normally appear.
- *
- * Neither the name of Shibboleth nor the names of its contributors, nor
- * Internet2, nor the University Corporation for Advanced Internet Development,
- * Inc., nor UCAID may be used to endorse or promote products derived from this
- * software without specific prior written permission. For written permission,
- * please contact shibboleth@shibboleth.org
- *
- * Products derived from this software may not be called Shibboleth, Internet2,
- * UCAID, or the University Corporation for Advanced Internet Development, nor
- * may Shibboleth appear in their name, without prior written permission of the
- * University Corporation for Advanced Internet Development.
- *
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
- * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
- * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
/* XMLRequestMapper.cpp - an XML-based map of URLs to application names and settings
#include "internal.h"
-#include <log4cpp/Category.hh>
+#include <algorithm>
+#include <shibsp/DOMPropertySet.h>
+#include <xmltooling/util/ReloadableXMLFile.h>
+#include <xmltooling/util/XMLHelper.h>
-using namespace std;
-using namespace log4cpp;
-using namespace saml;
-using namespace shibboleth;
+using namespace shibsp;
using namespace shibtarget;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
namespace shibtarget {
- class Override : public XMLPropertySet, public DOMNodeFilter
+ // Blocks access when an ACL plugin fails to load.
+ class AccessControlDummy : public IAccessControl
+ {
+ public:
+ Lockable* lock() {
+ return this;
+ }
+
+ void unlock() {}
+
+ bool authorized(ShibTarget* st, ISessionCacheEntry* entry) const {
+ return false;
+ }
+ };
+
+ class Override : public DOMPropertySet, public DOMNodeFilter
{
public:
Override() : m_base(NULL), m_acl(NULL) {}
Override(const DOMElement* e, Category& log, const Override* base=NULL);
~Override();
- IAccessControl* m_acl;
- // IPropertySet
+ // PropertySet
pair<bool,bool> getBool(const char* name, const char* ns=NULL) const;
pair<bool,const char*> getString(const char* name, const char* ns=NULL) const;
pair<bool,const XMLCh*> getXMLString(const char* name, const char* ns=NULL) const;
pair<bool,unsigned int> getUnsignedInt(const char* name, const char* ns=NULL) const;
pair<bool,int> getInt(const char* name, const char* ns=NULL) const;
- const IPropertySet* getPropertySet(const char* name, const char* ns="urn:mace:shibboleth:target:config:1.0") const;
+ const PropertySet* getPropertySet(const char* name, const char* ns="urn:mace:shibboleth:target:config:1.0") const;
// Provides filter to exclude special config elements.
short acceptNode(const DOMNode* node) const;
const Override* locate(const char* path) const;
+ IAccessControl* getAC() const { return (m_acl ? m_acl : (m_base ? m_base->getAC() : NULL)); }
protected:
void loadACL(const DOMElement* e, Category& log);
private:
const Override* m_base;
+ IAccessControl* m_acl;
};
- class XMLRequestMapperImpl : public ReloadableXMLFileImpl, public Override
+ class XMLRequestMapperImpl : public Override
{
public:
- XMLRequestMapperImpl(const char* pathname) : ReloadableXMLFileImpl(pathname) { init(); }
- XMLRequestMapperImpl(const DOMElement* e) : ReloadableXMLFileImpl(e) { init(); }
- void init();
- ~XMLRequestMapperImpl() {}
+ XMLRequestMapperImpl(const DOMElement* e, Category& log);
+
+ ~XMLRequestMapperImpl() {
+ if (m_document)
+ m_document->release();
+ }
+
+ void setDocument(DOMDocument* doc) {
+ m_document = doc;
+ }
const Override* findOverride(const char* vhost, const char* path) const;
- Category* log;
private:
map<string,Override*> m_extras;
+ DOMDocument* m_document;
};
- // An implementation of the URL->application mapping API using an XML file
+#if defined (_MSC_VER)
+ #pragma warning( push )
+ #pragma warning( disable : 4250 )
+#endif
+
class XMLRequestMapper : public IRequestMapper, public ReloadableXMLFile
{
public:
- XMLRequestMapper(const DOMElement* e) : ReloadableXMLFile(e) {}
- ~XMLRequestMapper() {}
+ XMLRequestMapper(const DOMElement* e)
+ : ReloadableXMLFile(e), m_impl(NULL), m_log(Category::getInstance(SHIBT_LOGCAT".RequestMapper")) {
+ load();
+ }
- virtual Settings getSettingsFromURL(const char* url) const;
- virtual Settings getSettingsFromParsedURL(
- const char* scheme, const char* hostname, unsigned int port, const char* path=NULL
- ) const;
+ ~XMLRequestMapper() {
+ delete m_impl;
+ }
+
+ virtual Settings getSettings(ShibTarget* st) const;
protected:
- virtual ReloadableXMLFileImpl* newImplementation(const char* pathname, bool first=true) const;
- virtual ReloadableXMLFileImpl* newImplementation(const DOMElement* e, bool first=true) const;
+ pair<bool,DOMElement*> load();
+
+ private:
+ XMLRequestMapperImpl* m_impl;
+ Category& m_log;
};
+
+#if defined (_MSC_VER)
+ #pragma warning( pop )
+#endif
+
+ static const XMLCh AccessControl[] = UNICODE_LITERAL_13(A,c,c,e,s,s,C,o,n,t,r,o,l);
+ static const XMLCh AccessControlProvider[] = UNICODE_LITERAL_21(A,c,c,e,s,s,C,o,n,t,r,o,l,P,r,o,v,i,d,e,r);
+ static const XMLCh htaccess[] = UNICODE_LITERAL_8(h,t,a,c,c,e,s,s);
+ static const XMLCh Host[] = UNICODE_LITERAL_4(H,o,s,t);
+ static const XMLCh Path[] = UNICODE_LITERAL_4(P,a,t,h);
+ static const XMLCh name[] = UNICODE_LITERAL_4(n,a,m,e);
+ static const XMLCh type[] = UNICODE_LITERAL_4(t,y,p,e);
}
-IPlugIn* XMLRequestMapFactory(const DOMElement* e)
+saml::IPlugIn* XMLRequestMapFactory(const DOMElement* e)
{
- XMLRequestMapper* m=new XMLRequestMapper(e);
- try {
- m->getImplementation();
- }
- catch (...) {
- delete m;
- throw;
- }
- return m;
+ return new XMLRequestMapper(e);
}
short Override::acceptNode(const DOMNode* node) const
{
- if (XMLString::compareString(node->getNamespaceURI(),ShibTargetConfig::SHIBTARGET_NS))
+ if (!XMLString::equals(node->getNamespaceURI(),shibspconstants::SHIB1SPCONFIG_NS))
return FILTER_ACCEPT;
const XMLCh* name=node->getLocalName();
- if (XMLString::compareString(name,SHIBT_L(AccessControlProvider)) ||
- XMLString::compareString(name,SHIBT_L(Host)) ||
- XMLString::compareString(name,SHIBT_L(Path)))
+ if (XMLString::equals(name,Host) ||
+ XMLString::equals(name,Path) ||
+ XMLString::equals(name,AccessControl) ||
+ XMLString::equals(name,htaccess) ||
+ XMLString::equals(name,AccessControlProvider))
return FILTER_REJECT;
return FILTER_ACCEPT;
void Override::loadACL(const DOMElement* e, Category& log)
{
- IPlugIn* plugin=NULL;
- const DOMElement* acl=saml::XML::getFirstChildElement(e,ShibTargetConfig::SHIBTARGET_NS,SHIBT_L(htaccess));
- if (acl) {
- log.info("building htaccess provider...");
- plugin=SAMLConfig::getConfig().m_plugMgr.newPlugin(shibtarget::XML::htaccessType,acl);
- }
- else {
- acl=saml::XML::getFirstChildElement(e,ShibTargetConfig::SHIBTARGET_NS,SHIBT_L(AccessControlProvider));
+ try {
+ saml::IPlugIn* plugin=NULL;
+ const DOMElement* acl=XMLHelper::getFirstChildElement(e,htaccess);
if (acl) {
- auto_ptr_char type(acl->getAttributeNS(NULL,SHIBT_L(type)));
- log.info("building Access Control provider of type %s...",type.get());
- plugin=SAMLConfig::getConfig().m_plugMgr.newPlugin(type.get(),acl);
+ log.info("building Apache htaccess provider...");
+ plugin=saml::SAMLConfig::getConfig().getPlugMgr().newPlugin(HTACCESS_ACCESSCONTROL,acl);
}
- }
- if (plugin) {
- IAccessControl* acl=dynamic_cast<IAccessControl*>(plugin);
- if (acl)
- m_acl=acl;
else {
- delete plugin;
- log.fatal("plugin was not an Access Control provider");
- throw UnsupportedExtensionException("plugin was not an Access Control provider");
+ acl=XMLHelper::getFirstChildElement(e,AccessControl);
+ if (acl) {
+ log.info("building XML-based Access Control provider...");
+ plugin=saml::SAMLConfig::getConfig().getPlugMgr().newPlugin(XML_ACCESSCONTROL,acl);
+ }
+ else {
+ acl=XMLHelper::getFirstChildElement(e,AccessControlProvider);
+ if (acl) {
+ xmltooling::auto_ptr_char type(acl->getAttributeNS(NULL,type));
+ log.info("building Access Control provider of type %s...",type.get());
+ plugin=saml::SAMLConfig::getConfig().getPlugMgr().newPlugin(type.get(),acl);
+ }
+ }
+ }
+ if (plugin) {
+ IAccessControl* acl=dynamic_cast<IAccessControl*>(plugin);
+ if (acl)
+ m_acl=acl;
+ else {
+ delete plugin;
+ throw UnknownExtensionException("plugin was not an Access Control provider");
+ }
}
}
+ catch (exception& ex) {
+ log.crit("exception building AccessControl provider: %s", ex.what());
+ m_acl = new AccessControlDummy();
+ }
}
Override::Override(const DOMElement* e, Category& log, const Override* base) : m_base(base), m_acl(NULL)
loadACL(e,log);
// Handle nested Paths.
- DOMNodeList* nlist=e->getElementsByTagNameNS(ShibTargetConfig::SHIBTARGET_NS,SHIBT_L(Path));
- for (int i=0; nlist && i<nlist->getLength(); i++) {
- DOMElement* path=static_cast<DOMElement*>(nlist->item(i));
- const XMLCh* n=path->getAttributeNS(NULL,SHIBT_L(name));
+ DOMElement* path = XMLHelper::getFirstChildElement(e,Path);
+ for (int i=1; path; ++i, path=XMLHelper::getNextSiblingElement(path,Path)) {
+ const XMLCh* n=path->getAttributeNS(NULL,name);
+
+ // Skip any leading slashes.
+ while (n && *n==chForwardSlash)
+ n++;
+
+ // Check for empty name.
if (!n || !*n) {
- log.warn("skipping Path element (%d) with empty name attribute",i);
+ log.warn("skipping Path element (%d) with empty name attribute", i);
continue;
}
- else if (*n==chForwardSlash && !n[1]) {
- log.warn("skipping Path element (%d) with a lone slash in the name attribute",i);
- continue;
+
+ // Check for an embedded slash.
+ int slash=XMLString::indexOf(n,chForwardSlash);
+ if (slash>0) {
+ // Copy the first path segment.
+ XMLCh* namebuf=new XMLCh[slash + 1];
+ for (int pos=0; pos < slash; pos++)
+ namebuf[pos]=n[pos];
+ namebuf[slash]=chNull;
+
+ // Move past the slash in the original pathname.
+ n=n+slash+1;
+
+ // Skip any leading slashes again.
+ while (*n==chForwardSlash)
+ n++;
+
+ if (*n) {
+ // Create a placeholder Path element for the first path segment and replant under it.
+ DOMElement* newpath=path->getOwnerDocument()->createElementNS(shibspconstants::SHIB1SPCONFIG_NS,Path);
+ newpath->setAttributeNS(NULL,name,namebuf);
+ path->setAttributeNS(NULL,name,n);
+ path->getParentNode()->replaceChild(newpath,path);
+ newpath->appendChild(path);
+
+ // Repoint our locals at the new parent.
+ path=newpath;
+ n=path->getAttributeNS(NULL,name);
+ }
+ else {
+ // All we had was a pathname with trailing slash(es), so just reset it without them.
+ path->setAttributeNS(NULL,name,namebuf);
+ n=path->getAttributeNS(NULL,name);
+ }
+ delete[] namebuf;
}
+
Override* o=new Override(path,log,this);
pair<bool,const char*> name=o->getString("name");
char* dup=strdup(name.second);
free(dup);
}
}
- catch (...) {
- this->~Override();
+ catch (exception&) {
+ delete m_acl;
+ for_each(m_map.begin(),m_map.end(),xmltooling::cleanup_pair<string,Override>());
throw;
}
}
Override::~Override()
{
delete m_acl;
- for (map<string,Override*>::iterator i=m_map.begin(); i!=m_map.end(); i++)
- delete i->second;
+ for_each(m_map.begin(),m_map.end(),xmltooling::cleanup_pair<string,Override>());
}
pair<bool,bool> Override::getBool(const char* name, const char* ns) const
{
- pair<bool,bool> ret=XMLPropertySet::getBool(name,ns);
+ pair<bool,bool> ret=DOMPropertySet::getBool(name,ns);
if (ret.first)
return ret;
return m_base ? m_base->getBool(name,ns) : ret;
pair<bool,const char*> Override::getString(const char* name, const char* ns) const
{
- pair<bool,const char*> ret=XMLPropertySet::getString(name,ns);
+ pair<bool,const char*> ret=DOMPropertySet::getString(name,ns);
if (ret.first)
return ret;
return m_base ? m_base->getString(name,ns) : ret;
pair<bool,const XMLCh*> Override::getXMLString(const char* name, const char* ns) const
{
- pair<bool,const XMLCh*> ret=XMLPropertySet::getXMLString(name,ns);
+ pair<bool,const XMLCh*> ret=DOMPropertySet::getXMLString(name,ns);
if (ret.first)
return ret;
return m_base ? m_base->getXMLString(name,ns) : ret;
pair<bool,unsigned int> Override::getUnsignedInt(const char* name, const char* ns) const
{
- pair<bool,unsigned int> ret=XMLPropertySet::getUnsignedInt(name,ns);
+ pair<bool,unsigned int> ret=DOMPropertySet::getUnsignedInt(name,ns);
if (ret.first)
return ret;
return m_base ? m_base->getUnsignedInt(name,ns) : ret;
pair<bool,int> Override::getInt(const char* name, const char* ns) const
{
- pair<bool,int> ret=XMLPropertySet::getInt(name,ns);
+ pair<bool,int> ret=DOMPropertySet::getInt(name,ns);
if (ret.first)
return ret;
return m_base ? m_base->getInt(name,ns) : ret;
}
-const IPropertySet* Override::getPropertySet(const char* name, const char* ns) const
+const PropertySet* Override::getPropertySet(const char* name, const char* ns) const
{
- const IPropertySet* ret=XMLPropertySet::getPropertySet(name,ns);
+ const PropertySet* ret=DOMPropertySet::getPropertySet(name,ns);
if (ret || !m_base)
return ret;
return m_base->getPropertySet(name,ns);
return o;
}
-void XMLRequestMapperImpl::init()
+XMLRequestMapperImpl::XMLRequestMapperImpl(const DOMElement* e, Category& log) : m_document(NULL)
{
- NDC ndc("init");
- log=&Category::getInstance("shibtarget.XMLRequestMapper");
+#ifdef _DEBUG
+ xmltooling::NDC ndc("XMLRequestMapperImpl");
+#endif
- try {
- if (!saml::XML::isElementNamed(ReloadableXMLFileImpl::m_root,ShibTargetConfig::SHIBTARGET_NS,SHIBT_L(RequestMap))) {
- log->error("Construction requires a valid request mapping file: (conf:RequestMap as root element)");
- throw MalformedException("Construction requires a valid request mapping file: (conf:RequestMap as root element)");
+ // Load the property set.
+ load(e,log,this);
+
+ // Load any AccessControl provider.
+ loadACL(e,log);
+
+ // Loop over the Host elements.
+ const DOMElement* host = XMLHelper::getFirstChildElement(e,Host);
+ for (int i=1; host; ++i, host=XMLHelper::getNextSiblingElement(host,Host)) {
+ const XMLCh* n=host->getAttributeNS(NULL,name);
+ if (!n || !*n) {
+ log.warn("Skipping Host element (%d) with empty name attribute",i);
+ continue;
}
-
- // Load the property set.
- load(ReloadableXMLFileImpl::m_root,*log,this);
- // Load any AccessControl provider.
- loadACL(ReloadableXMLFileImpl::m_root,*log);
-
- // Loop over the Host elements.
- DOMNodeList* nlist = ReloadableXMLFileImpl::m_root->getElementsByTagNameNS(ShibTargetConfig::SHIBTARGET_NS,SHIBT_L(Host));
- for (int i=0; nlist && i<nlist->getLength(); i++) {
- DOMElement* host=static_cast<DOMElement*>(nlist->item(i));
- const XMLCh* n=host->getAttributeNS(NULL,SHIBT_L(name));
- if (!n || !*n) {
- log->warn("Skipping Host element (%d) with empty name attribute",i);
- continue;
- }
-
- Override* o=new Override(host,*log,this);
- pair<bool,const char*> name=o->getString("name");
- pair<bool,const char*> scheme=o->getString("scheme");
- pair<bool,const char*> port=o->getString("port");
-
- char* dup=strdup(name.second);
- for (char* pch=dup; *pch; pch++)
- *pch=tolower(*pch);
- auto_ptr<char> dupwrap(dup);
-
- if (!scheme.first && port.first) {
- // No scheme, but a port, so assume http.
- scheme = pair<bool,const char*>(true,"http");
- }
- else if (scheme.first && !port.first) {
- // Scheme, no port, so default it.
- // XXX Use getservbyname instead?
- port.first = true;
- if (!strcmp(scheme.second,"http"))
- port.second = "80";
- else if (!strcmp(scheme.second,"https"))
- port.second = "443";
- else if (!strcmp(scheme.second,"ftp"))
- port.second = "21";
- else if (!strcmp(scheme.second,"ldap"))
- port.second = "389";
- else if (!strcmp(scheme.second,"ldaps"))
- port.second = "636";
- }
+ Override* o=new Override(host,log,this);
+ pair<bool,const char*> name=o->getString("name");
+ pair<bool,const char*> scheme=o->getString("scheme");
+ pair<bool,const char*> port=o->getString("port");
+
+ char* dup=strdup(name.second);
+ for (char* pch=dup; *pch; pch++)
+ *pch=tolower(*pch);
+ auto_ptr<char> dupwrap(dup);
+
+ if (!scheme.first && port.first) {
+ // No scheme, but a port, so assume http.
+ scheme = pair<bool,const char*>(true,"http");
+ }
+ else if (scheme.first && !port.first) {
+ // Scheme, no port, so default it.
+ // XXX Use getservbyname instead?
+ port.first = true;
+ if (!strcmp(scheme.second,"http"))
+ port.second = "80";
+ else if (!strcmp(scheme.second,"https"))
+ port.second = "443";
+ else if (!strcmp(scheme.second,"ftp"))
+ port.second = "21";
+ else if (!strcmp(scheme.second,"ldap"))
+ port.second = "389";
+ else if (!strcmp(scheme.second,"ldaps"))
+ port.second = "636";
+ }
- if (scheme.first) {
- string url(scheme.second);
- url=url + "://" + dup;
-
- // Is this the default port?
- if ((!strcmp(scheme.second,"http") && !strcmp(port.second,"80")) ||
- (!strcmp(scheme.second,"https") && !strcmp(port.second,"443")) ||
- (!strcmp(scheme.second,"ftp") && !strcmp(port.second,"21")) ||
- (!strcmp(scheme.second,"ldap") && !strcmp(port.second,"389")) ||
- (!strcmp(scheme.second,"ldaps") && !strcmp(port.second,"636"))) {
- // First store a port-less version.
- if (m_map.count(url) || m_extras.count(url)) {
- log->warn("Skipping duplicate Host element (%s)",url.c_str());
- delete o;
- continue;
- }
- m_map[url]=o;
- log->debug("Added <Host> mapping for %s",url.c_str());
-
- // Now append the port. We use the extras vector, to avoid double freeing the object later.
- url=url + ':' + port.second;
- m_extras[url]=o;
- log->debug("Added <Host> mapping for %s",url.c_str());
- }
- else {
- url=url + ':' + port.second;
- if (m_map.count(url) || m_extras.count(url)) {
- log->warn("Skipping duplicate Host element (%s)",url.c_str());
- delete o;
- continue;
- }
- m_map[url]=o;
- log->debug("Added <Host> mapping for %s",url.c_str());
- }
- }
- else {
- // No scheme or port, so we enter dual hosts on http:80 and https:443
- string url("http://");
- url = url + dup;
+ if (scheme.first) {
+ string url(scheme.second);
+ url=url + "://" + dup;
+
+ // Is this the default port?
+ if ((!strcmp(scheme.second,"http") && !strcmp(port.second,"80")) ||
+ (!strcmp(scheme.second,"https") && !strcmp(port.second,"443")) ||
+ (!strcmp(scheme.second,"ftp") && !strcmp(port.second,"21")) ||
+ (!strcmp(scheme.second,"ldap") && !strcmp(port.second,"389")) ||
+ (!strcmp(scheme.second,"ldaps") && !strcmp(port.second,"636"))) {
+ // First store a port-less version.
if (m_map.count(url) || m_extras.count(url)) {
- log->warn("Skipping duplicate Host element (%s)",url.c_str());
+ log.warn("Skipping duplicate Host element (%s)",url.c_str());
delete o;
continue;
}
m_map[url]=o;
- log->debug("Added <Host> mapping for %s",url.c_str());
+ log.debug("Added <Host> mapping for %s",url.c_str());
- url = url + ":80";
- if (m_map.count(url) || m_extras.count(url)) {
- log->warn("Skipping duplicate Host element (%s)",url.c_str());
- continue;
- }
+ // Now append the port. We use the extras vector, to avoid double freeing the object later.
+ url=url + ':' + port.second;
m_extras[url]=o;
- log->debug("Added <Host> mapping for %s",url.c_str());
-
- url = "https://";
- url = url + dup;
- if (m_map.count(url) || m_extras.count(url)) {
- log->warn("Skipping duplicate Host element (%s)",url.c_str());
- continue;
- }
- m_extras[url]=o;
- log->debug("Added <Host> mapping for %s",url.c_str());
-
- url = url + ":443";
+ log.debug("Added <Host> mapping for %s",url.c_str());
+ }
+ else {
+ url=url + ':' + port.second;
if (m_map.count(url) || m_extras.count(url)) {
- log->warn("Skipping duplicate Host element (%s)",url.c_str());
+ log.warn("Skipping duplicate Host element (%s)",url.c_str());
+ delete o;
continue;
}
- m_extras[url]=o;
- log->debug("Added <Host> mapping for %s",url.c_str());
+ m_map[url]=o;
+ log.debug("Added <Host> mapping for %s",url.c_str());
}
}
+ else {
+ // No scheme or port, so we enter dual hosts on http:80 and https:443
+ string url("http://");
+ url = url + dup;
+ if (m_map.count(url) || m_extras.count(url)) {
+ log.warn("Skipping duplicate Host element (%s)",url.c_str());
+ delete o;
+ continue;
+ }
+ m_map[url]=o;
+ log.debug("Added <Host> mapping for %s",url.c_str());
+
+ url = url + ":80";
+ if (m_map.count(url) || m_extras.count(url)) {
+ log.warn("Skipping duplicate Host element (%s)",url.c_str());
+ continue;
+ }
+ m_extras[url]=o;
+ log.debug("Added <Host> mapping for %s",url.c_str());
+
+ url = "https://";
+ url = url + dup;
+ if (m_map.count(url) || m_extras.count(url)) {
+ log.warn("Skipping duplicate Host element (%s)",url.c_str());
+ continue;
+ }
+ m_extras[url]=o;
+ log.debug("Added <Host> mapping for %s",url.c_str());
+
+ url = url + ":443";
+ if (m_map.count(url) || m_extras.count(url)) {
+ log.warn("Skipping duplicate Host element (%s)",url.c_str());
+ continue;
+ }
+ m_extras[url]=o;
+ log.debug("Added <Host> mapping for %s",url.c_str());
+ }
}
- catch (SAMLException& e) {
- log->errorStream() << "Error while parsing request mapping configuration: " << e.what() << CategoryStream::ENDLINE;
- throw;
- }
-#ifndef _DEBUG
- catch (...)
- {
- log->error("Unexpected error while parsing request mapping configuration");
- throw;
- }
-#endif
}
const Override* XMLRequestMapperImpl::findOverride(const char* vhost, const char* path) const
return o ? o->locate(path) : this;
}
-const char* split_url(const char* url, string& vhost)
-{
- const char* path=NULL;
- const char* slash=strchr(url,'/');
- if (slash)
- {
- slash=strchr(slash,'/');
- if (slash)
- {
- path=strchr(slash,'/');
- if (path)
- vhost.append(url,path-url);
- else
- vhost=url;
- }
- }
- return path;
-}
-
-ReloadableXMLFileImpl* XMLRequestMapper::newImplementation(const char* pathname, bool first) const
-{
- return new XMLRequestMapperImpl(pathname);
-}
-
-ReloadableXMLFileImpl* XMLRequestMapper::newImplementation(const DOMElement* e, bool first) const
-{
- return new XMLRequestMapperImpl(e);
-}
-
-IRequestMapper::Settings XMLRequestMapper::getSettingsFromURL(const char* url) const
+pair<bool,DOMElement*> XMLRequestMapper::load()
{
- string vhost;
- const char* path=split_url(url,vhost);
+ // Load from source using base class.
+ pair<bool,DOMElement*> raw = ReloadableXMLFile::load();
+
+ // If we own it, wrap it.
+ XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : NULL);
- XMLRequestMapperImpl* impl=static_cast<XMLRequestMapperImpl*>(getImplementation());
- const Override* o=impl->findOverride(vhost.c_str(), path);
+ XMLRequestMapperImpl* impl = new XMLRequestMapperImpl(raw.second,m_log);
+
+ // If we held the document, transfer it to the impl. If we didn't, it's a no-op.
+ impl->setDocument(docjanitor.release());
- if (impl->log->isDebugEnabled()) {
- saml::NDC ndc("getApplicationFromURL");
- pair<bool,const char*> ret=o->getString("applicationId");
- impl->log->debug("mapped %s to %s", url, ret.second);
- }
+ delete m_impl;
+ m_impl = impl;
- return Settings(o,o->m_acl);
+ return make_pair(false,(DOMElement*)NULL);
}
-IRequestMapper::Settings XMLRequestMapper::getSettingsFromParsedURL(
- const char* scheme, const char* hostname, unsigned int port, const char* path
- ) const
+IRequestMapper::Settings XMLRequestMapper::getSettings(ShibTarget* st) const
{
- char buf[21];
- string vhost(scheme);
- vhost=vhost + "://" + hostname + ':';
-#ifdef WIN32
- _snprintf(buf,20,"%u",port);
-#else
- snprintf(buf,20,"%u",port);
-#endif
- vhost+=buf;
+ ostringstream vhost;
+ vhost << st->getProtocol() << "://" << st->getHostname() << ':' << st->getPort();
- XMLRequestMapperImpl* impl=static_cast<XMLRequestMapperImpl*>(getImplementation());
- const Override* o=impl->findOverride(vhost.c_str(), path);
+ const Override* o=m_impl->findOverride(vhost.str().c_str(), st->getRequestURI());
- if (impl->log->isDebugEnabled())
- {
- saml::NDC ndc("getApplicationFromParsedURL");
+ if (m_log.isDebugEnabled()) {
+#ifdef _DEBUG
+ xmltooling::NDC ndc("getSettings");
+#endif
pair<bool,const char*> ret=o->getString("applicationId");
- impl->log->debug("mapped %s%s to %s", vhost.c_str(), path ? path : "", ret.second);
+ m_log.debug("mapped %s%s to %s", vhost.str().c_str(), st->getRequestURI() ? st->getRequestURI() : "", ret.second);
}
- return Settings(o,o->m_acl);
+ return Settings(o,o->getAC());
}