From: Scott Cantor Date: Thu, 15 Nov 2007 22:02:26 +0000 (+0000) Subject: Clean Solaris build. X-Git-Tag: 2.0-beta2~26 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-sp.git;a=commitdiff_plain;h=e2b9ec01820f056dfa91f9a60689b501c941eac6 Clean Solaris build. --- diff --git a/adfs/adfs.cpp b/adfs/adfs.cpp index 833cc63..c06a203 100644 --- a/adfs/adfs.cpp +++ b/adfs/adfs.cpp @@ -312,7 +312,7 @@ pair ADFSSessionInitiator::run(SPRequest& request, const char* entity { // We have to know the IdP to function. if (!entityID || !*entityID) - return make_pair(false,0); + return make_pair(false,0L); string target; const Handler* ACS=NULL; @@ -339,11 +339,11 @@ pair ADFSSessionInitiator::run(SPRequest& request, const char* entity const vector& handlers = app.getAssertionConsumerServicesByBinding(m_binding.get()); // Index comes from request, or default set in the handler, or we just pick the first endpoint. - pair index = make_pair(false,0); + pair index(false,0); if (isHandler) { option = request.getParameter("acsIndex"); if (option) - index = make_pair(true, atoi(option)); + index = pair(true, atoi(option)); } if (!index.first) index = getUnsignedInt("defaultACSIndex"); @@ -443,14 +443,14 @@ pair ADFSSessionInitiator::doRequest( } else if (!entity.second) { m_log.error("unable to locate ADFS-aware identity provider role for provider (%s)", entityID); - return make_pair(false,0); + return make_pair(false,0L); } const EndpointType* ep = EndpointManager( dynamic_cast(entity.second)->getSingleSignOnServices() ).getByBinding(m_binding.get()); if (!ep) { m_log.error("unable to locate compatible SSO service for provider (%s)", entityID); - return make_pair(false,0); + return make_pair(false,0L); } preserveRelayState(app, httpResponse, relayState); @@ -476,7 +476,7 @@ pair ADFSSessionInitiator::doRequest( return make_pair(true, httpResponse.sendRedirect(req.c_str())); #else - return make_pair(false,0); + return make_pair(false,0L); #endif } @@ -655,17 +655,17 @@ pair ADFSLogoutInitiator::run(SPRequest& request, bool isHandler) con try { session = request.getSession(false, true, false); // don't cache it and ignore all checks if (!session) - return make_pair(false,0); + return make_pair(false,0L); // We only handle ADFS sessions. if (!XMLString::equals(session->getProtocol(), WSFED_NS) || !session->getEntityID()) { session->unlock(); - return make_pair(false,0); + return make_pair(false,0L); } } catch (exception& ex) { m_log.error("error accessing current session: %s", ex.what()); - return make_pair(false,0); + return make_pair(false,0L); } string entityID(session->getEntityID()); @@ -754,7 +754,7 @@ pair ADFSLogoutInitiator::doRequest( m_log.error("error issuing ADFS logout request: %s", ex.what()); } - return make_pair(false,0); + return make_pair(false,0L); #else throw ConfigurationException("Cannot perform logout using lite version of shibsp library."); #endif diff --git a/apache/mod_apache.cpp b/apache/mod_apache.cpp index 46250dc..cbd7c2e 100644 --- a/apache/mod_apache.cpp +++ b/apache/mod_apache.cpp @@ -788,7 +788,7 @@ pair ApacheRequestMapper::getUnsignedInt(const char* name, co else if (sta->m_dc->tSettings) { const char* prop = ap_table_get(sta->m_dc->tSettings, name); if (prop) - return make_pair(true, strtol(prop, NULL, 10)); + return pair(true, atoi(prop)); } } return s ? s->getUnsignedInt(name,ns) : pair(false,0); diff --git a/shibsp/attribute/ScopedAttributeDecoder.cpp b/shibsp/attribute/ScopedAttributeDecoder.cpp index c194896..cdfacad 100644 --- a/shibsp/attribute/ScopedAttributeDecoder.cpp +++ b/shibsp/attribute/ScopedAttributeDecoder.cpp @@ -1,198 +1,198 @@ -/* - * Copyright 2001-2007 Internet2 - * - * 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. - */ - -/** - * ScopedAttributeDecoder.cpp - * - * Decodes SAML into ScopedAttributes - */ - -#include "internal.h" -#include "attribute/AttributeDecoder.h" -#include "attribute/ScopedAttribute.h" - -#include -#include - -using namespace shibsp; -using namespace opensaml::saml1; -using namespace opensaml::saml2; -using namespace xmltooling; -using namespace std; - -namespace shibsp { - static const XMLCh Scope[] = UNICODE_LITERAL_5(S,c,o,p,e); - static const XMLCh scopeDelimeter[] = UNICODE_LITERAL_14(s,c,o,p,e,D,e,l,i,m,e,t,e,r); - - class SHIBSP_DLLLOCAL ScopedAttributeDecoder : virtual public AttributeDecoder - { - public: - ScopedAttributeDecoder(const DOMElement* e) : AttributeDecoder(e), m_delimeter('@') { - if (e) { - if (e->hasAttributeNS(NULL,scopeDelimeter)) { - auto_ptr_char d(e->getAttributeNS(NULL,scopeDelimeter)); - m_delimeter = *(d.get()); - } - } - } - ~ScopedAttributeDecoder() {} - - shibsp::Attribute* decode( - const vector& ids, const XMLObject* xmlObject, const char* assertingParty=NULL, const char* relyingParty=NULL - ) const; - - private: - char m_delimeter; - }; - - AttributeDecoder* SHIBSP_DLLLOCAL ScopedAttributeDecoderFactory(const DOMElement* const & e) - { - return new ScopedAttributeDecoder(e); - } -}; - -shibsp::Attribute* ScopedAttributeDecoder::decode( - const vector& ids, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty - ) const -{ - char* val; - char* scope; - const XMLCh* xmlscope; - QName scopeqname(NULL,Scope); - auto_ptr scoped(new ScopedAttribute(ids, m_delimeter)); - scoped->setCaseSensitive(m_caseSensitive); - vector< pair >& dest = scoped->getValues(); - vector::const_iterator v,stop; - - Category& log = Category::getInstance(SHIBSP_LOGCAT".AttributeDecoder"); - - if (xmlObject && XMLString::equals(opensaml::saml1::Attribute::LOCAL_NAME,xmlObject->getElementQName().getLocalPart())) { - const opensaml::saml2::Attribute* saml2attr = dynamic_cast(xmlObject); - if (saml2attr) { - const vector& values = saml2attr->getAttributeValues(); - v = values.begin(); - stop = values.end(); - if (log.isDebugEnabled()) { - auto_ptr_char n(saml2attr->getName()); - log.debug( - "decoding ScopedAttribute (%s) from SAML 2 Attribute (%s) with %lu value(s)", - ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size() - ); - } - } - else { - const opensaml::saml1::Attribute* saml1attr = dynamic_cast(xmlObject); - if (saml1attr) { - const vector& values = saml1attr->getAttributeValues(); - v = values.begin(); - stop = values.end(); - if (log.isDebugEnabled()) { - auto_ptr_char n(saml1attr->getAttributeName()); - log.debug( - "decoding ScopedAttribute (%s) from SAML 1 Attribute (%s) with %lu value(s)", - ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size() - ); - } - } - else { - log.warn("XMLObject type not recognized by ScopedAttributeDecoder, no values returned"); - return NULL; - } - } - - for (; v!=stop; ++v) { - if (!(*v)->hasChildren()) { - val = toUTF8((*v)->getTextContent()); - if (val && *val) { - const AttributeExtensibleXMLObject* aexo=dynamic_cast(*v); - xmlscope = aexo->getAttribute(scopeqname); - if (xmlscope && *xmlscope) { - scope = toUTF8(xmlscope); - dest.push_back(make_pair(val,scope)); - delete[] scope; - } - else { - scope = strchr(val, m_delimeter); - if (scope) { - *scope++ = 0; - if (*scope) - dest.push_back(make_pair(val,scope)); - else - log.warn("ignoring unscoped AttributeValue"); - } - else { - log.warn("ignoring unscoped AttributeValue"); - } - } - } - else { - log.warn("skipping empty AttributeValue"); - } - delete[] val; - } - else { - log.warn("skipping complex AttributeValue"); - } - } - - return dest.empty() ? NULL : scoped.release(); - } - - const NameID* saml2name = dynamic_cast(xmlObject); - if (saml2name) { - if (log.isDebugEnabled()) { - auto_ptr_char f(saml2name->getFormat()); - log.debug("decoding ScopedAttribute (%s) from SAML 2 NameID with Format (%s)", ids.front().c_str(), f.get() ? f.get() : "unspecified"); - } - val = toUTF8(saml2name->getName()); - } - else { - const NameIdentifier* saml1name = dynamic_cast(xmlObject); - if (saml1name) { - if (log.isDebugEnabled()) { - auto_ptr_char f(saml1name->getFormat()); - log.debug( - "decoding ScopedAttribute (%s) from SAML 1 NameIdentifier with Format (%s)", - ids.front().c_str(), f.get() ? f.get() : "unspecified" - ); - } - val = toUTF8(saml1name->getName()); - } - else { - log.warn("XMLObject type not recognized by ScopedAttributeDecoder, no values returned"); - return NULL; - } - } - - if (val && *val && *val!=m_delimeter) { - scope = strchr(val, m_delimeter); - if (scope) { - *scope++ = 0; - if (*scope) - dest.push_back(make_pair(val,scope)); - else - log.warn("ignoring NameID with no scope"); - } - else { - log.warn("ignoring NameID with no scope delimiter (%c)", m_delimeter); - } - } - else { - log.warn("ignoring empty NameID"); - } - delete[] val; - return dest.empty() ? NULL : scoped.release(); -} +/* + * Copyright 2001-2007 Internet2 + * + * 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. + */ + +/** + * ScopedAttributeDecoder.cpp + * + * Decodes SAML into ScopedAttributes + */ + +#include "internal.h" +#include "attribute/AttributeDecoder.h" +#include "attribute/ScopedAttribute.h" + +#include +#include + +using namespace shibsp; +using namespace opensaml::saml1; +using namespace opensaml::saml2; +using namespace xmltooling; +using namespace std; + +namespace shibsp { + static const XMLCh Scope[] = UNICODE_LITERAL_5(S,c,o,p,e); + static const XMLCh scopeDelimeter[] = UNICODE_LITERAL_14(s,c,o,p,e,D,e,l,i,m,e,t,e,r); + + class SHIBSP_DLLLOCAL ScopedAttributeDecoder : virtual public AttributeDecoder + { + public: + ScopedAttributeDecoder(const DOMElement* e) : AttributeDecoder(e), m_delimeter('@') { + if (e) { + if (e->hasAttributeNS(NULL,scopeDelimeter)) { + auto_ptr_char d(e->getAttributeNS(NULL,scopeDelimeter)); + m_delimeter = *(d.get()); + } + } + } + ~ScopedAttributeDecoder() {} + + shibsp::Attribute* decode( + const vector& ids, const XMLObject* xmlObject, const char* assertingParty=NULL, const char* relyingParty=NULL + ) const; + + private: + char m_delimeter; + }; + + AttributeDecoder* SHIBSP_DLLLOCAL ScopedAttributeDecoderFactory(const DOMElement* const & e) + { + return new ScopedAttributeDecoder(e); + } +}; + +shibsp::Attribute* ScopedAttributeDecoder::decode( + const vector& ids, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty + ) const +{ + char* val; + char* scope; + const XMLCh* xmlscope; + QName scopeqname(NULL,Scope); + auto_ptr scoped(new ScopedAttribute(ids, m_delimeter)); + scoped->setCaseSensitive(m_caseSensitive); + vector< pair >& dest = scoped->getValues(); + vector::const_iterator v,stop; + + Category& log = Category::getInstance(SHIBSP_LOGCAT".AttributeDecoder"); + + if (xmlObject && XMLString::equals(opensaml::saml1::Attribute::LOCAL_NAME,xmlObject->getElementQName().getLocalPart())) { + const opensaml::saml2::Attribute* saml2attr = dynamic_cast(xmlObject); + if (saml2attr) { + const vector& values = saml2attr->getAttributeValues(); + v = values.begin(); + stop = values.end(); + if (log.isDebugEnabled()) { + auto_ptr_char n(saml2attr->getName()); + log.debug( + "decoding ScopedAttribute (%s) from SAML 2 Attribute (%s) with %lu value(s)", + ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size() + ); + } + } + else { + const opensaml::saml1::Attribute* saml1attr = dynamic_cast(xmlObject); + if (saml1attr) { + const vector& values = saml1attr->getAttributeValues(); + v = values.begin(); + stop = values.end(); + if (log.isDebugEnabled()) { + auto_ptr_char n(saml1attr->getAttributeName()); + log.debug( + "decoding ScopedAttribute (%s) from SAML 1 Attribute (%s) with %lu value(s)", + ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size() + ); + } + } + else { + log.warn("XMLObject type not recognized by ScopedAttributeDecoder, no values returned"); + return NULL; + } + } + + for (; v!=stop; ++v) { + if (!(*v)->hasChildren()) { + val = toUTF8((*v)->getTextContent()); + if (val && *val) { + const AttributeExtensibleXMLObject* aexo=dynamic_cast(*v); + xmlscope = aexo->getAttribute(scopeqname); + if (xmlscope && *xmlscope) { + scope = toUTF8(xmlscope); + dest.push_back(pair(val,scope)); + delete[] scope; + } + else { + scope = strchr(val, m_delimeter); + if (scope) { + *scope++ = 0; + if (*scope) + dest.push_back(pair(val,scope)); + else + log.warn("ignoring unscoped AttributeValue"); + } + else { + log.warn("ignoring unscoped AttributeValue"); + } + } + } + else { + log.warn("skipping empty AttributeValue"); + } + delete[] val; + } + else { + log.warn("skipping complex AttributeValue"); + } + } + + return dest.empty() ? NULL : scoped.release(); + } + + const NameID* saml2name = dynamic_cast(xmlObject); + if (saml2name) { + if (log.isDebugEnabled()) { + auto_ptr_char f(saml2name->getFormat()); + log.debug("decoding ScopedAttribute (%s) from SAML 2 NameID with Format (%s)", ids.front().c_str(), f.get() ? f.get() : "unspecified"); + } + val = toUTF8(saml2name->getName()); + } + else { + const NameIdentifier* saml1name = dynamic_cast(xmlObject); + if (saml1name) { + if (log.isDebugEnabled()) { + auto_ptr_char f(saml1name->getFormat()); + log.debug( + "decoding ScopedAttribute (%s) from SAML 1 NameIdentifier with Format (%s)", + ids.front().c_str(), f.get() ? f.get() : "unspecified" + ); + } + val = toUTF8(saml1name->getName()); + } + else { + log.warn("XMLObject type not recognized by ScopedAttributeDecoder, no values returned"); + return NULL; + } + } + + if (val && *val && *val!=m_delimeter) { + scope = strchr(val, m_delimeter); + if (scope) { + *scope++ = 0; + if (*scope) + dest.push_back(pair(val,scope)); + else + log.warn("ignoring NameID with no scope"); + } + else { + log.warn("ignoring NameID with no scope delimiter (%c)", m_delimeter); + } + } + else { + log.warn("ignoring empty NameID"); + } + delete[] val; + return dest.empty() ? NULL : scoped.release(); +} diff --git a/shibsp/attribute/filtering/impl/AndMatchFunctor.cpp b/shibsp/attribute/filtering/impl/AndMatchFunctor.cpp index 4951005..857050d 100644 --- a/shibsp/attribute/filtering/impl/AndMatchFunctor.cpp +++ b/shibsp/attribute/filtering/impl/AndMatchFunctor.cpp @@ -114,6 +114,6 @@ MatchFunctor* AndMatchFunctor::buildFunctor(const DOMElement* e, const FilterPol throw ConfigurationException("Child Rule found with no xsi:type."); MatchFunctor* func = SPConfig::getConfig().MatchFunctorManager.newPlugin(*type.get(), make_pair(functorMap,e)); - functorMap->getMatchFunctors().insert(make_pair(id, func)); + functorMap->getMatchFunctors().insert(multimap::value_type(id, func)); return func; } diff --git a/shibsp/attribute/filtering/impl/NotMatchFunctor.cpp b/shibsp/attribute/filtering/impl/NotMatchFunctor.cpp index 17d9bcd..0f79a84 100644 --- a/shibsp/attribute/filtering/impl/NotMatchFunctor.cpp +++ b/shibsp/attribute/filtering/impl/NotMatchFunctor.cpp @@ -104,6 +104,6 @@ MatchFunctor* NotMatchFunctor::buildFunctor(const DOMElement* e, const FilterPol throw ConfigurationException("Child Rule found with no xsi:type."); MatchFunctor* func = SPConfig::getConfig().MatchFunctorManager.newPlugin(*type.get(), make_pair(functorMap,e)); - functorMap->getMatchFunctors().insert(make_pair(id, func)); + functorMap->getMatchFunctors().insert(multimap::value_type(id, func)); return func; } diff --git a/shibsp/attribute/filtering/impl/OrMatchFunctor.cpp b/shibsp/attribute/filtering/impl/OrMatchFunctor.cpp index e58d7c7..cd29548 100644 --- a/shibsp/attribute/filtering/impl/OrMatchFunctor.cpp +++ b/shibsp/attribute/filtering/impl/OrMatchFunctor.cpp @@ -110,6 +110,6 @@ MatchFunctor* OrMatchFunctor::buildFunctor(const DOMElement* e, const FilterPoli throw ConfigurationException("Child Rule found with no xsi:type."); MatchFunctor* func = SPConfig::getConfig().MatchFunctorManager.newPlugin(*type.get(), make_pair(functorMap,e)); - functorMap->getMatchFunctors().insert(make_pair(id, func)); + functorMap->getMatchFunctors().insert(multimap::value_type(id, func)); return func; } diff --git a/shibsp/attribute/filtering/impl/XMLAttributeFilter.cpp b/shibsp/attribute/filtering/impl/XMLAttributeFilter.cpp index 0e50fbb..d1656e5 100644 --- a/shibsp/attribute/filtering/impl/XMLAttributeFilter.cpp +++ b/shibsp/attribute/filtering/impl/XMLAttributeFilter.cpp @@ -172,14 +172,14 @@ XMLFilterImpl::XMLFilterImpl(const DOMElement* e, Category& log) : m_log(log), m if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, AttributeRule)) { pair rule = buildAttributeRule(e, valFunctors, false); if (rule.second) - m_policies.back().m_rules.insert(rule); + m_policies.back().m_rules.insert(Policy::rules_t::value_type(rule.first, rule.second)); } else if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, AttributeRuleReference)) { auto_ptr_char ref(e->getAttributeNS(NULL, _ref)); if (ref.get() && *ref.get()) { map< string,pair >::const_iterator ar = m_attrRules.find(ref.get()); if (ar != m_attrRules.end()) - m_policies.back().m_rules.insert(ar->second); + m_policies.back().m_rules.insert(Policy::rules_t::value_type(ar->second.first, ar->second.second)); else m_log.warn("skipping invalid AttributeRuleReference (%s)", ref.get()); } @@ -219,7 +219,7 @@ MatchFunctor* XMLFilterImpl::buildFunctor( if (type.get()) { try { MatchFunctor* func = SPConfig::getConfig().MatchFunctorManager.newPlugin(*type.get(), make_pair(&functorMap,e)); - functorMap.getMatchFunctors().insert(make_pair(id, func)); + functorMap.getMatchFunctors().insert(multimap::value_type(id, func)); return func; } catch (exception& ex) { @@ -241,12 +241,12 @@ pair XMLFilterImpl::buildAttributeRule(const DOMElem if (standalone && !*id) { m_log.warn("skipping stand-alone AttributeRule with no id"); - return make_pair(string(),(MatchFunctor*)NULL); + return make_pair(string(),(const MatchFunctor*)NULL); } else if (*id && m_attrRules.count(id)) { if (standalone) { m_log.warn("skipping duplicate stand-alone AttributeRule with id (%s)", id); - return make_pair(string(),(MatchFunctor*)NULL); + return make_pair(string(),(const MatchFunctor*)NULL); } else id = ""; @@ -271,13 +271,13 @@ pair XMLFilterImpl::buildAttributeRule(const DOMElem if (func) { if (*id) - return m_attrRules[id] = make_pair(attrID.get(), func); + return m_attrRules[id] = pair(attrID.get(), func); else - return make_pair(attrID.get(), func); + return pair(attrID.get(), func); } m_log.warn("skipping AttributeRule (%s), PermitValueRule invalid or missing", id); - return make_pair(string(),(MatchFunctor*)NULL); + return make_pair(string(),(const MatchFunctor*)NULL); } void XMLFilterImpl::filterAttributes(const FilteringContext& context, vector& attributes) const diff --git a/shibsp/attribute/resolver/impl/XMLAttributeExtractor.cpp b/shibsp/attribute/resolver/impl/XMLAttributeExtractor.cpp index 2b5621d..eb4c6ec 100644 --- a/shibsp/attribute/resolver/impl/XMLAttributeExtractor.cpp +++ b/shibsp/attribute/resolver/impl/XMLAttributeExtractor.cpp @@ -205,11 +205,11 @@ XMLExtractorImpl::XMLExtractorImpl(const DOMElement* e, Category& log) : m_log(l // Fetch/create the map entry and see if it's a duplicate rule. #ifdef HAVE_GOOD_STL - pair< AttributeDecoder*,vector >& decl = m_attrMap[make_pair(name,format)]; + pair< AttributeDecoder*,vector >& decl = m_attrMap[pair(name,format)]; #else auto_ptr_char n(name); auto_ptr_char f(format); - pair< AttributeDecoder*,vector >& decl = m_attrMap[make_pair(n.get(),f.get())]; + pair< AttributeDecoder*,vector >& decl = m_attrMap[pair(n.get(),f.get())]; #endif if (decl.first) { m_log.warn("skipping duplicate Attribute mapping (same name and nameFormat)"); @@ -272,10 +272,10 @@ void XMLExtractorImpl::extractAttributes( if (!format || !*format) format = NameIdentifier::UNSPECIFIED; #ifdef HAVE_GOOD_STL - if ((rule=m_attrMap.find(make_pair(format,xstring()))) != m_attrMap.end()) { + if ((rule=m_attrMap.find(pair(format,xstring()))) != m_attrMap.end()) { #else auto_ptr_char temp(format); - if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) { + if ((rule=m_attrMap.find(pair(temp.get(),string()))) != m_attrMap.end()) { #endif Attribute* a = rule->second.first->decode(rule->second.second, &nameid, assertingParty, application.getString("entityID").second); if (a) @@ -297,10 +297,10 @@ void XMLExtractorImpl::extractAttributes( if (!format || !*format) format = NameID::UNSPECIFIED; #ifdef HAVE_GOOD_STL - if ((rule=m_attrMap.find(make_pair(format,xstring()))) != m_attrMap.end()) { + if ((rule=m_attrMap.find(pair(format,xstring()))) != m_attrMap.end()) { #else auto_ptr_char temp(format); - if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) { + if ((rule=m_attrMap.find(pair(temp.get(),string()))) != m_attrMap.end()) { #endif Attribute* a = rule->second.first->decode(rule->second.second, &nameid, assertingParty, application.getString("entityID").second); if (a) @@ -325,11 +325,11 @@ void XMLExtractorImpl::extractAttributes( if (!format || XMLString::equals(format, shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI)) format = &chNull; #ifdef HAVE_GOOD_STL - if ((rule=m_attrMap.find(make_pair(name,format))) != m_attrMap.end()) { + if ((rule=m_attrMap.find(pair(name,format))) != m_attrMap.end()) { #else auto_ptr_char temp1(name); auto_ptr_char temp2(format); - if ((rule=m_attrMap.find(make_pair(temp1.get(),temp2.get()))) != m_attrMap.end()) { + if ((rule=m_attrMap.find(pair(temp1.get(),temp2.get()))) != m_attrMap.end()) { #endif Attribute* a = rule->second.first->decode(rule->second.second, &attr, assertingParty, application.getString("entityID").second); if (a) @@ -356,11 +356,11 @@ void XMLExtractorImpl::extractAttributes( else if (XMLString::equals(format, saml2::Attribute::URI_REFERENCE)) format = &chNull; #ifdef HAVE_GOOD_STL - if ((rule=m_attrMap.find(make_pair(name,format))) != m_attrMap.end()) { + if ((rule=m_attrMap.find(pair(name,format))) != m_attrMap.end()) { #else auto_ptr_char temp1(name); auto_ptr_char temp2(format); - if ((rule=m_attrMap.find(make_pair(temp1.get(),temp2.get()))) != m_attrMap.end()) { + if ((rule=m_attrMap.find(pair(temp1.get(),temp2.get()))) != m_attrMap.end()) { #endif Attribute* a = rule->second.first->decode(rule->second.second, &attr, assertingParty, application.getString("entityID").second); if (a) diff --git a/shibsp/handler/impl/AssertionLookup.cpp b/shibsp/handler/impl/AssertionLookup.cpp index 24915a7..c43712e 100644 --- a/shibsp/handler/impl/AssertionLookup.cpp +++ b/shibsp/handler/impl/AssertionLookup.cpp @@ -196,6 +196,6 @@ pair AssertionLookup::processMessage(const Application& application, httpResponse.setContentType("application/samlassertion+xml"); return make_pair(true, httpResponse.sendResponse(s)); #else - return make_pair(false,0); + return make_pair(false,0L); #endif } diff --git a/shibsp/handler/impl/MetadataGenerator.cpp b/shibsp/handler/impl/MetadataGenerator.cpp index d694926..ca5c926 100644 --- a/shibsp/handler/impl/MetadataGenerator.cpp +++ b/shibsp/handler/impl/MetadataGenerator.cpp @@ -310,6 +310,6 @@ pair MetadataGenerator::processMessage(const Application& application httpResponse.setContentType("application/samlmetadata+xml"); return make_pair(true, httpResponse.sendResponse(s)); #else - return make_pair(false,0); + return make_pair(false,0L); #endif } diff --git a/shibsp/handler/impl/SAML2ArtifactResolution.cpp b/shibsp/handler/impl/SAML2ArtifactResolution.cpp index 07fa66e..df95366 100644 --- a/shibsp/handler/impl/SAML2ArtifactResolution.cpp +++ b/shibsp/handler/impl/SAML2ArtifactResolution.cpp @@ -315,7 +315,7 @@ pair SAML2ArtifactResolution::processMessage(const Application& appli return samlError(application, *req, httpResponse, StatusCode::RESPONDER, NULL, ex.what()); } #else - return make_pair(false,0); + return make_pair(false,0L); #endif } diff --git a/shibsp/handler/impl/SAML2Logout.cpp b/shibsp/handler/impl/SAML2Logout.cpp index 23b5421..05a80a7 100644 --- a/shibsp/handler/impl/SAML2Logout.cpp +++ b/shibsp/handler/impl/SAML2Logout.cpp @@ -146,7 +146,9 @@ SAML2Logout::SAML2Logout(const DOMElement* e, const char* appId) SAMLConfig& conf = SAMLConfig::getConfig(); // Handle incoming binding. - m_decoder = conf.MessageDecoderManager.newPlugin(getString("Binding").second,make_pair(e,shibspconstants::SHIB2SPCONFIG_NS)); + m_decoder = conf.MessageDecoderManager.newPlugin( + getString("Binding").second, pair(e,shibspconstants::SHIB2SPCONFIG_NS) + ); m_decoder->setArtifactResolver(SPConfig::getConfig().getArtifactResolver()); if (m_decoder->isUserAgentPresent()) { @@ -172,7 +174,9 @@ SAML2Logout::SAML2Logout(const DOMElement* e, const char* appId) m_bindings.push_back(start); try { auto_ptr_char b(start); - MessageEncoder * encoder = conf.MessageEncoderManager.newPlugin(b.get(),make_pair(e,shibspconstants::SHIB2SPCONFIG_NS)); + MessageEncoder * encoder = conf.MessageEncoderManager.newPlugin( + b.get(), pair(e,shibspconstants::SHIB2SPCONFIG_NS) + ); m_encoders[start] = encoder; m_log.debug("supporting outgoing front-channel binding (%s)", b.get()); } @@ -187,7 +191,7 @@ SAML2Logout::SAML2Logout(const DOMElement* e, const char* appId) } else { MessageEncoder* encoder = conf.MessageEncoderManager.newPlugin( - getString("Binding").second,make_pair(e,shibspconstants::SHIB2SPCONFIG_NS) + getString("Binding").second, pair(e,shibspconstants::SHIB2SPCONFIG_NS) ); m_encoders.insert(pair(NULL, encoder)); } @@ -530,7 +534,7 @@ pair SAML2Logout::doRequest( if (policy.getIssuerMetadata()) annotateException(&ex, policy.getIssuerMetadata()); // throws it ex.raise(); - return make_pair(false,0); // never happen, satisfies compiler + return make_pair(false,0L); // never happen, satisfies compiler #else throw ConfigurationException("Cannot process logout message using lite version of shibsp library."); #endif diff --git a/shibsp/handler/impl/SAML2LogoutInitiator.cpp b/shibsp/handler/impl/SAML2LogoutInitiator.cpp index 06edde9..50f06b9 100644 --- a/shibsp/handler/impl/SAML2LogoutInitiator.cpp +++ b/shibsp/handler/impl/SAML2LogoutInitiator.cpp @@ -184,17 +184,17 @@ pair SAML2LogoutInitiator::run(SPRequest& request, bool isHandler) co try { session = request.getSession(false, true, false); // don't cache it and ignore all checks if (!session) - return make_pair(false,0); + return make_pair(false,0L); // We only handle SAML 2.0 sessions. if (!XMLString::equals(session->getProtocol(), m_protocol.get())) { session->unlock(); - return make_pair(false,0); + return make_pair(false,0L); } } catch (exception& ex) { m_log.error("error accessing current session: %s", ex.what()); - return make_pair(false,0); + return make_pair(false,0L); } if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) { @@ -284,7 +284,7 @@ pair SAML2LogoutInitiator::doRequest( } #ifndef SHIBSP_LITE - pair ret = make_pair(false,0); + pair ret = make_pair(false,0L); try { // With a session in hand, we can create a LogoutRequest message, if we can find a compatible endpoint. MetadataProvider* m = application.getMetadataProvider(); diff --git a/shibsp/handler/impl/SAML2NameIDMgmt.cpp b/shibsp/handler/impl/SAML2NameIDMgmt.cpp index 0f90abb..a63bc6c 100644 --- a/shibsp/handler/impl/SAML2NameIDMgmt.cpp +++ b/shibsp/handler/impl/SAML2NameIDMgmt.cpp @@ -142,7 +142,9 @@ SAML2NameIDMgmt::SAML2NameIDMgmt(const DOMElement* e, const char* appId) SAMLConfig& conf = SAMLConfig::getConfig(); // Handle incoming binding. - m_decoder = conf.MessageDecoderManager.newPlugin(getString("Binding").second,make_pair(e,shibspconstants::SHIB2SPCONFIG_NS)); + m_decoder = conf.MessageDecoderManager.newPlugin( + getString("Binding").second, pair(e,shibspconstants::SHIB2SPCONFIG_NS) + ); m_decoder->setArtifactResolver(SPConfig::getConfig().getArtifactResolver()); if (m_decoder->isUserAgentPresent()) { @@ -168,7 +170,9 @@ SAML2NameIDMgmt::SAML2NameIDMgmt(const DOMElement* e, const char* appId) m_bindings.push_back(start); try { auto_ptr_char b(start); - MessageEncoder * encoder = conf.MessageEncoderManager.newPlugin(b.get(),make_pair(e,shibspconstants::SHIB2SPCONFIG_NS)); + MessageEncoder * encoder = conf.MessageEncoderManager.newPlugin( + b.get(), pair(e,shibspconstants::SHIB2SPCONFIG_NS) + ); m_encoders[start] = encoder; m_log.debug("supporting outgoing front-channel binding (%s)", b.get()); } @@ -183,7 +187,7 @@ SAML2NameIDMgmt::SAML2NameIDMgmt(const DOMElement* e, const char* appId) } else { MessageEncoder* encoder = conf.MessageEncoderManager.newPlugin( - getString("Binding").second,make_pair(e,shibspconstants::SHIB2SPCONFIG_NS) + getString("Binding").second, pair(e,shibspconstants::SHIB2SPCONFIG_NS) ); m_encoders.insert(pair(NULL, encoder)); } @@ -464,7 +468,7 @@ pair SAML2NameIDMgmt::doRequest( if (policy.getIssuerMetadata()) annotateException(&ex, policy.getIssuerMetadata()); // throws it ex.raise(); - return make_pair(false,0); // never happen, satisfies compiler + return make_pair(false,0L); // never happen, satisfies compiler #else throw ConfigurationException("Cannot process NameID mgmt message using lite version of shibsp library."); #endif diff --git a/shibsp/handler/impl/SAML2SessionInitiator.cpp b/shibsp/handler/impl/SAML2SessionInitiator.cpp index 6d74a34..a022c91 100644 --- a/shibsp/handler/impl/SAML2SessionInitiator.cpp +++ b/shibsp/handler/impl/SAML2SessionInitiator.cpp @@ -216,7 +216,7 @@ pair SAML2SessionInitiator::run(SPRequest& request, const char* entit // We have to know the IdP to function unless this is ECP. if (!ECP && (!entityID || !*entityID)) - return make_pair(false,0); + return make_pair(false,0L); string target; const Handler* ACS=NULL; @@ -471,7 +471,7 @@ pair SAML2SessionInitiator::doRequest( encoder = m_ecp; if (!encoder) { m_log.error("MessageEncoder for PAOS binding not available"); - return make_pair(false,0); + return make_pair(false,0L); } } else { @@ -486,7 +486,7 @@ pair SAML2SessionInitiator::doRequest( } else if (!entity.second) { m_log.error("unable to locate SAML 2.0 identity provider role for provider (%s)", entityID); - return make_pair(false,0); + return make_pair(false,0L); } // Loop over the supportable outgoing bindings. @@ -502,7 +502,7 @@ pair SAML2SessionInitiator::doRequest( } if (!ep || !encoder) { m_log.error("unable to locate compatible SSO service for provider (%s)", entityID); - return make_pair(false,0); + return make_pair(false,0L); } } @@ -587,6 +587,6 @@ pair SAML2SessionInitiator::doRequest( req.release(); // freed by encoder return make_pair(true,ret); #else - return make_pair(false,0); + return make_pair(false,0L); #endif } diff --git a/shibsp/handler/impl/SAMLDSSessionInitiator.cpp b/shibsp/handler/impl/SAMLDSSessionInitiator.cpp index ddbcd6b..1aec1e2 100644 --- a/shibsp/handler/impl/SAMLDSSessionInitiator.cpp +++ b/shibsp/handler/impl/SAMLDSSessionInitiator.cpp @@ -80,7 +80,7 @@ pair SAMLDSSessionInitiator::run(SPRequest& request, const char* enti // The IdP CANNOT be specified for us to run. Otherwise, we'd be redirecting to a DS // anytime the IdP's metadata was wrong. if (entityID && *entityID) - return make_pair(false,0); + return make_pair(false,0L); string target; const char* option; diff --git a/shibsp/handler/impl/Shib1SessionInitiator.cpp b/shibsp/handler/impl/Shib1SessionInitiator.cpp index f370e77..6d2152f 100644 --- a/shibsp/handler/impl/Shib1SessionInitiator.cpp +++ b/shibsp/handler/impl/Shib1SessionInitiator.cpp @@ -107,7 +107,7 @@ pair Shib1SessionInitiator::run(SPRequest& request, const char* entit { // We have to know the IdP to function. if (!entityID || !*entityID) - return make_pair(false,0); + return make_pair(false,0L); string target; const Handler* ACS=NULL; @@ -232,14 +232,14 @@ pair Shib1SessionInitiator::doRequest( } else if (!entity.second) { m_log.error("unable to locate Shibboleth-aware identity provider role for provider (%s)", entityID); - return make_pair(false,0); + return make_pair(false,0L); } const EndpointType* ep=EndpointManager( dynamic_cast(entity.second)->getSingleSignOnServices() ).getByBinding(shibspconstants::SHIB1_AUTHNREQUEST_PROFILE_URI); if (!ep) { m_log.error("unable to locate compatible SSO service for provider (%s)", entityID); - return make_pair(false,0); + return make_pair(false,0L); } preserveRelayState(app, httpResponse, relayState); @@ -258,6 +258,6 @@ pair Shib1SessionInitiator::doRequest( return make_pair(true, httpResponse.sendRedirect(req.c_str())); #else - return make_pair(false,0); + return make_pair(false,0L); #endif } diff --git a/shibsp/handler/impl/StatusHandler.cpp b/shibsp/handler/impl/StatusHandler.cpp index 8862f58..f090bb0 100644 --- a/shibsp/handler/impl/StatusHandler.cpp +++ b/shibsp/handler/impl/StatusHandler.cpp @@ -446,6 +446,6 @@ pair StatusHandler::processMessage( httpResponse.setContentType("text/xml"); return make_pair(true, httpResponse.sendResponse(s)); #else - return make_pair(false,0); + return make_pair(false,0L); #endif } diff --git a/shibsp/handler/impl/WAYFSessionInitiator.cpp b/shibsp/handler/impl/WAYFSessionInitiator.cpp index 49f1242..fe627d1 100644 --- a/shibsp/handler/impl/WAYFSessionInitiator.cpp +++ b/shibsp/handler/impl/WAYFSessionInitiator.cpp @@ -77,7 +77,7 @@ pair WAYFSessionInitiator::run(SPRequest& request, const char* entity // The IdP CANNOT be specified for us to run. Otherwise, we'd be redirecting to a WAYF // anytime the IdP's metadata was wrong. if (entityID && *entityID) - return make_pair(false,0); + return make_pair(false,0L); string target; const char* option; diff --git a/shibsp/impl/RemotedSessionCache.cpp b/shibsp/impl/RemotedSessionCache.cpp index f9162b7..d203319 100644 --- a/shibsp/impl/RemotedSessionCache.cpp +++ b/shibsp/impl/RemotedSessionCache.cpp @@ -1,506 +1,506 @@ -/* - * Copyright 2001-2007 Internet2 - * - * 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. - */ - -/** - * RemotedSessionCache.cpp - * - * SessionCache implementation that delegates to a remoted version. - */ - -#include "internal.h" -#include "Application.h" -#include "exceptions.h" -#include "ServiceProvider.h" -#include "SessionCache.h" -#include "attribute/Attribute.h" -#include "remoting/ListenerService.h" -#include "util/SPConstants.h" - -#include -#include -#include -#include -#include -#include - -using namespace shibsp; -using namespace xmltooling; -using namespace std; - -namespace shibsp { - - class RemotedCache; - class RemotedSession : public virtual Session - { - public: - RemotedSession(RemotedCache* cache, DDF& obj) : m_version(obj["version"].integer()), m_obj(obj), - m_expires(0), m_lastAccess(time(NULL)), m_cache(cache), m_lock(NULL) { - auto_ptr_XMLCh exp(m_obj["expires"].string()); - if (exp.get()) { - DateTime iso(exp.get()); - iso.parseDateTime(); - m_expires = iso.getEpoch(); - } - - m_lock = Mutex::create(); - } - - ~RemotedSession() { - delete m_lock; - m_obj.destroy(); - for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup()); - } - - Lockable* lock() { - m_lock->lock(); - return this; - } - void unlock() { - m_lock->unlock(); - } - - const char* getID() const { - return m_obj.name(); - } - const char* getApplicationID() const { - return m_obj["application_id"].string(); - } - const char* getClientAddress() const { - return m_obj["client_addr"].string(); - } - const char* getEntityID() const { - return m_obj["entity_id"].string(); - } - const char* getProtocol() const { - return m_obj["protocol"].string(); - } - const char* getAuthnInstant() const { - return m_obj["authn_instant"].string(); - } - const char* getSessionIndex() const { - return m_obj["session_index"].string(); - } - const char* getAuthnContextClassRef() const { - return m_obj["authncontext_class"].string(); - } - const char* getAuthnContextDeclRef() const { - return m_obj["authncontext_decl"].string(); - } - const vector& getAttributes() const { - if (m_attributes.empty()) - unmarshallAttributes(); - return m_attributes; - } - const multimap& getIndexedAttributes() const { - if (m_attributeIndex.empty()) { - if (m_attributes.empty()) - unmarshallAttributes(); - for (vector::const_iterator a = m_attributes.begin(); a != m_attributes.end(); ++a) { - const vector& aliases = (*a)->getAliases(); - for (vector::const_iterator alias = aliases.begin(); alias != aliases.end(); ++alias) - m_attributeIndex.insert(make_pair(*alias, *a)); - } - } - return m_attributeIndex; - } - const vector& getAssertionIDs() const { - if (m_ids.empty()) { - DDF ids = m_obj["assertions"]; - DDF id = ids.first(); - while (id.isstring()) { - m_ids.push_back(id.string()); - id = ids.next(); - } - } - return m_ids; - } - - time_t expires() const { return m_expires; } - time_t lastAccess() const { return m_lastAccess; } - void validate(const Application& application, const char* client_addr, time_t* timeout); - - private: - void unmarshallAttributes() const; - - int m_version; - mutable DDF m_obj; - mutable vector m_attributes; - mutable multimap m_attributeIndex; - mutable vector m_ids; - time_t m_expires,m_lastAccess; - RemotedCache* m_cache; - Mutex* m_lock; - }; - - class RemotedCache : public SessionCache - { - public: - RemotedCache(const DOMElement* e); - ~RemotedCache(); - - Session* find(const char* key, const Application& application, const char* client_addr=NULL, time_t* timeout=NULL); - void remove(const char* key, const Application& application); - - void cleanup(); - - Category& m_log; - private: - const DOMElement* m_root; // Only valid during initialization - RWLock* m_lock; - map m_hashtable; - - void dormant(const char* key); - static void* cleanup_fn(void*); - bool shutdown; - CondWait* shutdown_wait; - Thread* cleanup_thread; - }; - - SessionCache* SHIBSP_DLLLOCAL RemotedCacheFactory(const DOMElement* const & e) - { - return new RemotedCache(e); - } -} - -void RemotedSession::unmarshallAttributes() const -{ - Attribute* attribute; - DDF attrs = m_obj["attributes"]; - DDF attr = attrs.first(); - while (!attr.isnull()) { - try { - attribute = Attribute::unmarshall(attr); - m_attributes.push_back(attribute); - if (m_cache->m_log.isDebugEnabled()) - m_cache->m_log.debug("unmarshalled attribute (ID: %s) with %d value%s", - attribute->getId(), attr.first().integer(), attr.first().integer()!=1 ? "s" : ""); - } - catch (AttributeException& ex) { - const char* id = attr.first().name(); - m_cache->m_log.error("error unmarshalling attribute (ID: %s): %s", id ? id : "none", ex.what()); - } - attr = attrs.next(); - } -} - -void RemotedSession::validate(const Application& application, const char* client_addr, time_t* timeout) -{ - // Basic expiration? - time_t now = time(NULL); - if (now > m_expires) { - m_cache->m_log.info("session expired (ID: %s)", getID()); - throw opensaml::RetryableProfileException("Your session has expired, and you must re-authenticate."); - } - - // Address check? - if (client_addr) { - if (m_cache->m_log.isDebugEnabled()) - m_cache->m_log.debug("comparing client address %s against %s", client_addr, getClientAddress()); - if (strcmp(getClientAddress(),client_addr)) { - m_cache->m_log.warn("client address mismatch"); - throw opensaml::RetryableProfileException( - "Your IP address ($1) does not match the address recorded at the time the session was established.", - params(1,client_addr) - ); - } - } - - if (!timeout) - return; - - DDF in("touch::"REMOTED_SESSION_CACHE"::SessionCache"), out; - DDFJanitor jin(in); - in.structure(); - in.addmember("key").string(getID()); - in.addmember("version").integer(m_obj["version"].integer()); - if (*timeout) { - // On 64-bit Windows, time_t doesn't fit in a long, so I'm using ISO timestamps. -#ifndef HAVE_GMTIME_R - struct tm* ptime=gmtime(timeout); -#else - struct tm res; - struct tm* ptime=gmtime_r(timeout,&res); -#endif - char timebuf[32]; - strftime(timebuf,32,"%Y-%m-%dT%H:%M:%SZ",ptime); - in.addmember("timeout").string(timebuf); - } - - try { - out=application.getServiceProvider().getListenerService()->send(in); - } - catch (...) { - out.destroy(); - throw; - } - - if (out.isstruct()) { - // We got an updated record back. - m_ids.clear(); - for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup()); - m_attributes.clear(); - m_attributeIndex.clear(); - m_obj.destroy(); - m_obj = out; - } - - m_lastAccess = now; -} - -RemotedCache::RemotedCache(const DOMElement* e) - : SessionCache(e, 900), m_log(Category::getInstance(SHIBSP_LOGCAT".SessionCache")), m_root(e), m_lock(NULL), shutdown(false) -{ - if (!SPConfig::getConfig().getServiceProvider()->getListenerService()) - throw ConfigurationException("RemotedCacheService requires a ListenerService, but none available."); - - m_lock = RWLock::create(); - shutdown_wait = CondWait::create(); - cleanup_thread = Thread::create(&cleanup_fn, (void*)this); -} - -RemotedCache::~RemotedCache() -{ - // Shut down the cleanup thread and let it know... - shutdown = true; - shutdown_wait->signal(); - cleanup_thread->join(NULL); - - for_each(m_hashtable.begin(),m_hashtable.end(),xmltooling::cleanup_pair()); - delete m_lock; - delete shutdown_wait; -} - -Session* RemotedCache::find(const char* key, const Application& application, const char* client_addr, time_t* timeout) -{ -#ifdef _DEBUG - xmltooling::NDC ndc("find"); -#endif - - RemotedSession* session=NULL; - m_log.debug("searching local cache for session (%s)", key); - m_lock->rdlock(); - map::const_iterator i=m_hashtable.find(key); - if (i==m_hashtable.end()) { - m_lock->unlock(); - m_log.debug("session not found locally, searching remote cache"); - - DDF in("find::"REMOTED_SESSION_CACHE"::SessionCache"), out; - DDFJanitor jin(in); - in.structure(); - in.addmember("key").string(key); - in.addmember("application_id").string(application.getId()); - if (timeout && *timeout) { - // On 64-bit Windows, time_t doesn't fit in a long, so I'm using ISO timestamps. -#ifndef HAVE_GMTIME_R - struct tm* ptime=gmtime(timeout); -#else - struct tm res; - struct tm* ptime=gmtime_r(timeout,&res); -#endif - char timebuf[32]; - strftime(timebuf,32,"%Y-%m-%dT%H:%M:%SZ",ptime); - in.addmember("timeout").string(timebuf); - } - - try { - out=application.getServiceProvider().getListenerService()->send(in); - if (!out.isstruct()) { - out.destroy(); - m_log.debug("session not found in remote cache"); - return NULL; - } - - // Wrap the results in a local entry and save it. - session = new RemotedSession(this, out); - // The remote end has handled timeout issues, we handle address and expiration checks. - timeout = NULL; - } - catch (...) { - out.destroy(); - throw; - } - - // Lock for writing and repeat the search to avoid duplication. - m_lock->wrlock(); - SharedLock shared(m_lock, false); - if (m_hashtable.count(key)) { - // We're using an existing session entry. - delete session; - session = m_hashtable[key]; - session->lock(); - } - else { - m_hashtable[key]=session; - session->lock(); - } - } - else { - // Save off and lock the session. - session = i->second; - session->lock(); - m_lock->unlock(); - - m_log.debug("session found locally, validating it for use"); - } - - if (!XMLString::equals(session->getApplicationID(), application.getId())) { - m_log.error("an application (%s) tried to access another application's session", application.getId()); - session->unlock(); - return NULL; - } - - // Verify currency and update the timestamp if indicated by caller. - try { - session->validate(application, client_addr, timeout); - } - catch (...) { - session->unlock(); - remove(key, application); - throw; - } - - return session; -} - -void RemotedCache::remove(const char* key, const Application& application) -{ - // Take care of local copy. - dormant(key); - - // Now remote... - DDF in("remove::"REMOTED_SESSION_CACHE"::SessionCache"); - DDFJanitor jin(in); - in.structure(); - in.addmember("key").string(key); - in.addmember("application_id").string(application.getId()); - - DDF out = application.getServiceProvider().getListenerService()->send(in); - out.destroy(); -} - -void RemotedCache::dormant(const char* key) -{ -#ifdef _DEBUG - xmltooling::NDC ndc("dormant"); -#endif - - m_log.debug("deleting local copy of session (%s)", key); - - // lock the cache for writing, which means we know nobody is sitting in find() - m_lock->wrlock(); - - // grab the entry from the table - map::const_iterator i=m_hashtable.find(key); - if (i==m_hashtable.end()) { - m_lock->unlock(); - return; - } - - // ok, remove the entry and lock it - RemotedSession* entry=i->second; - m_hashtable.erase(key); - entry->lock(); - - // unlock the cache - m_lock->unlock(); - - // we can release the cache entry lock because we know we're not in the cache anymore - entry->unlock(); - - delete entry; -} - -void RemotedCache::cleanup() -{ -#ifdef _DEBUG - xmltooling::NDC ndc("cleanup"); -#endif - - Mutex* mutex = Mutex::create(); - - // Load our configuration details... - static const XMLCh cleanupInterval[] = UNICODE_LITERAL_15(c,l,e,a,n,u,p,I,n,t,e,r,v,a,l); - const XMLCh* tag=m_root ? m_root->getAttributeNS(NULL,cleanupInterval) : NULL; - int rerun_timer = 900; - if (tag && *tag) - rerun_timer = XMLString::parseInt(tag); - if (rerun_timer <= 0) - rerun_timer = 900; - - mutex->lock(); - - m_log.info("cleanup thread started...run every %d secs; timeout after %d secs", rerun_timer, m_cacheTimeout); - - while (!shutdown) { - shutdown_wait->timedwait(mutex,rerun_timer); - if (shutdown) - break; - - // Ok, let's run through the cleanup process and clean out - // really old sessions. This is a two-pass process. The - // first pass is done holding a read-lock while we iterate over - // the cache. The second pass doesn't need a lock because - // the 'deletes' will lock the cache. - - // Pass 1: iterate over the map and find all entries that have not been - // used in X hours - vector stale_keys; - time_t stale = time(NULL) - m_cacheTimeout; - - m_log.debug("cleanup thread running"); - - m_lock->rdlock(); - for (map::const_iterator i=m_hashtable.begin(); i!=m_hashtable.end(); ++i) { - // If the last access was BEFORE the stale timeout... - i->second->lock(); - time_t last=i->second->lastAccess(); - i->second->unlock(); - if (last < stale) - stale_keys.push_back(i->first); - } - m_lock->unlock(); - - if (!stale_keys.empty()) { - m_log.info("purging %d old sessions", stale_keys.size()); - - // Pass 2: walk through the list of stale entries and remove them from the cache - for (vector::const_iterator j = stale_keys.begin(); j != stale_keys.end(); ++j) - dormant(j->c_str()); - } - - m_log.debug("cleanup thread completed"); - } - - m_log.info("cleanup thread exiting"); - - mutex->unlock(); - delete mutex; - Thread::exit(NULL); -} - -void* RemotedCache::cleanup_fn(void* cache_p) -{ - RemotedCache* cache = reinterpret_cast(cache_p); - -#ifndef WIN32 - // First, let's block all signals - Thread::mask_all_signals(); -#endif - - // Now run the cleanup process. - cache->cleanup(); - return NULL; -} +/* + * Copyright 2001-2007 Internet2 + * + * 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. + */ + +/** + * RemotedSessionCache.cpp + * + * SessionCache implementation that delegates to a remoted version. + */ + +#include "internal.h" +#include "Application.h" +#include "exceptions.h" +#include "ServiceProvider.h" +#include "SessionCache.h" +#include "attribute/Attribute.h" +#include "remoting/ListenerService.h" +#include "util/SPConstants.h" + +#include +#include +#include +#include +#include +#include + +using namespace shibsp; +using namespace xmltooling; +using namespace std; + +namespace shibsp { + + class RemotedCache; + class RemotedSession : public virtual Session + { + public: + RemotedSession(RemotedCache* cache, DDF& obj) : m_version(obj["version"].integer()), m_obj(obj), + m_expires(0), m_lastAccess(time(NULL)), m_cache(cache), m_lock(NULL) { + auto_ptr_XMLCh exp(m_obj["expires"].string()); + if (exp.get()) { + DateTime iso(exp.get()); + iso.parseDateTime(); + m_expires = iso.getEpoch(); + } + + m_lock = Mutex::create(); + } + + ~RemotedSession() { + delete m_lock; + m_obj.destroy(); + for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup()); + } + + Lockable* lock() { + m_lock->lock(); + return this; + } + void unlock() { + m_lock->unlock(); + } + + const char* getID() const { + return m_obj.name(); + } + const char* getApplicationID() const { + return m_obj["application_id"].string(); + } + const char* getClientAddress() const { + return m_obj["client_addr"].string(); + } + const char* getEntityID() const { + return m_obj["entity_id"].string(); + } + const char* getProtocol() const { + return m_obj["protocol"].string(); + } + const char* getAuthnInstant() const { + return m_obj["authn_instant"].string(); + } + const char* getSessionIndex() const { + return m_obj["session_index"].string(); + } + const char* getAuthnContextClassRef() const { + return m_obj["authncontext_class"].string(); + } + const char* getAuthnContextDeclRef() const { + return m_obj["authncontext_decl"].string(); + } + const vector& getAttributes() const { + if (m_attributes.empty()) + unmarshallAttributes(); + return m_attributes; + } + const multimap& getIndexedAttributes() const { + if (m_attributeIndex.empty()) { + if (m_attributes.empty()) + unmarshallAttributes(); + for (vector::const_iterator a = m_attributes.begin(); a != m_attributes.end(); ++a) { + const vector& aliases = (*a)->getAliases(); + for (vector::const_iterator alias = aliases.begin(); alias != aliases.end(); ++alias) + m_attributeIndex.insert(multimap::value_type(*alias, *a)); + } + } + return m_attributeIndex; + } + const vector& getAssertionIDs() const { + if (m_ids.empty()) { + DDF ids = m_obj["assertions"]; + DDF id = ids.first(); + while (id.isstring()) { + m_ids.push_back(id.string()); + id = ids.next(); + } + } + return m_ids; + } + + time_t expires() const { return m_expires; } + time_t lastAccess() const { return m_lastAccess; } + void validate(const Application& application, const char* client_addr, time_t* timeout); + + private: + void unmarshallAttributes() const; + + int m_version; + mutable DDF m_obj; + mutable vector m_attributes; + mutable multimap m_attributeIndex; + mutable vector m_ids; + time_t m_expires,m_lastAccess; + RemotedCache* m_cache; + Mutex* m_lock; + }; + + class RemotedCache : public SessionCache + { + public: + RemotedCache(const DOMElement* e); + ~RemotedCache(); + + Session* find(const char* key, const Application& application, const char* client_addr=NULL, time_t* timeout=NULL); + void remove(const char* key, const Application& application); + + void cleanup(); + + Category& m_log; + private: + const DOMElement* m_root; // Only valid during initialization + RWLock* m_lock; + map m_hashtable; + + void dormant(const char* key); + static void* cleanup_fn(void*); + bool shutdown; + CondWait* shutdown_wait; + Thread* cleanup_thread; + }; + + SessionCache* SHIBSP_DLLLOCAL RemotedCacheFactory(const DOMElement* const & e) + { + return new RemotedCache(e); + } +} + +void RemotedSession::unmarshallAttributes() const +{ + Attribute* attribute; + DDF attrs = m_obj["attributes"]; + DDF attr = attrs.first(); + while (!attr.isnull()) { + try { + attribute = Attribute::unmarshall(attr); + m_attributes.push_back(attribute); + if (m_cache->m_log.isDebugEnabled()) + m_cache->m_log.debug("unmarshalled attribute (ID: %s) with %d value%s", + attribute->getId(), attr.first().integer(), attr.first().integer()!=1 ? "s" : ""); + } + catch (AttributeException& ex) { + const char* id = attr.first().name(); + m_cache->m_log.error("error unmarshalling attribute (ID: %s): %s", id ? id : "none", ex.what()); + } + attr = attrs.next(); + } +} + +void RemotedSession::validate(const Application& application, const char* client_addr, time_t* timeout) +{ + // Basic expiration? + time_t now = time(NULL); + if (now > m_expires) { + m_cache->m_log.info("session expired (ID: %s)", getID()); + throw opensaml::RetryableProfileException("Your session has expired, and you must re-authenticate."); + } + + // Address check? + if (client_addr) { + if (m_cache->m_log.isDebugEnabled()) + m_cache->m_log.debug("comparing client address %s against %s", client_addr, getClientAddress()); + if (strcmp(getClientAddress(),client_addr)) { + m_cache->m_log.warn("client address mismatch"); + throw opensaml::RetryableProfileException( + "Your IP address ($1) does not match the address recorded at the time the session was established.", + params(1,client_addr) + ); + } + } + + if (!timeout) + return; + + DDF in("touch::"REMOTED_SESSION_CACHE"::SessionCache"), out; + DDFJanitor jin(in); + in.structure(); + in.addmember("key").string(getID()); + in.addmember("version").integer(m_obj["version"].integer()); + if (*timeout) { + // On 64-bit Windows, time_t doesn't fit in a long, so I'm using ISO timestamps. +#ifndef HAVE_GMTIME_R + struct tm* ptime=gmtime(timeout); +#else + struct tm res; + struct tm* ptime=gmtime_r(timeout,&res); +#endif + char timebuf[32]; + strftime(timebuf,32,"%Y-%m-%dT%H:%M:%SZ",ptime); + in.addmember("timeout").string(timebuf); + } + + try { + out=application.getServiceProvider().getListenerService()->send(in); + } + catch (...) { + out.destroy(); + throw; + } + + if (out.isstruct()) { + // We got an updated record back. + m_ids.clear(); + for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup()); + m_attributes.clear(); + m_attributeIndex.clear(); + m_obj.destroy(); + m_obj = out; + } + + m_lastAccess = now; +} + +RemotedCache::RemotedCache(const DOMElement* e) + : SessionCache(e, 900), m_log(Category::getInstance(SHIBSP_LOGCAT".SessionCache")), m_root(e), m_lock(NULL), shutdown(false) +{ + if (!SPConfig::getConfig().getServiceProvider()->getListenerService()) + throw ConfigurationException("RemotedCacheService requires a ListenerService, but none available."); + + m_lock = RWLock::create(); + shutdown_wait = CondWait::create(); + cleanup_thread = Thread::create(&cleanup_fn, (void*)this); +} + +RemotedCache::~RemotedCache() +{ + // Shut down the cleanup thread and let it know... + shutdown = true; + shutdown_wait->signal(); + cleanup_thread->join(NULL); + + for_each(m_hashtable.begin(),m_hashtable.end(),xmltooling::cleanup_pair()); + delete m_lock; + delete shutdown_wait; +} + +Session* RemotedCache::find(const char* key, const Application& application, const char* client_addr, time_t* timeout) +{ +#ifdef _DEBUG + xmltooling::NDC ndc("find"); +#endif + + RemotedSession* session=NULL; + m_log.debug("searching local cache for session (%s)", key); + m_lock->rdlock(); + map::const_iterator i=m_hashtable.find(key); + if (i==m_hashtable.end()) { + m_lock->unlock(); + m_log.debug("session not found locally, searching remote cache"); + + DDF in("find::"REMOTED_SESSION_CACHE"::SessionCache"), out; + DDFJanitor jin(in); + in.structure(); + in.addmember("key").string(key); + in.addmember("application_id").string(application.getId()); + if (timeout && *timeout) { + // On 64-bit Windows, time_t doesn't fit in a long, so I'm using ISO timestamps. +#ifndef HAVE_GMTIME_R + struct tm* ptime=gmtime(timeout); +#else + struct tm res; + struct tm* ptime=gmtime_r(timeout,&res); +#endif + char timebuf[32]; + strftime(timebuf,32,"%Y-%m-%dT%H:%M:%SZ",ptime); + in.addmember("timeout").string(timebuf); + } + + try { + out=application.getServiceProvider().getListenerService()->send(in); + if (!out.isstruct()) { + out.destroy(); + m_log.debug("session not found in remote cache"); + return NULL; + } + + // Wrap the results in a local entry and save it. + session = new RemotedSession(this, out); + // The remote end has handled timeout issues, we handle address and expiration checks. + timeout = NULL; + } + catch (...) { + out.destroy(); + throw; + } + + // Lock for writing and repeat the search to avoid duplication. + m_lock->wrlock(); + SharedLock shared(m_lock, false); + if (m_hashtable.count(key)) { + // We're using an existing session entry. + delete session; + session = m_hashtable[key]; + session->lock(); + } + else { + m_hashtable[key]=session; + session->lock(); + } + } + else { + // Save off and lock the session. + session = i->second; + session->lock(); + m_lock->unlock(); + + m_log.debug("session found locally, validating it for use"); + } + + if (!XMLString::equals(session->getApplicationID(), application.getId())) { + m_log.error("an application (%s) tried to access another application's session", application.getId()); + session->unlock(); + return NULL; + } + + // Verify currency and update the timestamp if indicated by caller. + try { + session->validate(application, client_addr, timeout); + } + catch (...) { + session->unlock(); + remove(key, application); + throw; + } + + return session; +} + +void RemotedCache::remove(const char* key, const Application& application) +{ + // Take care of local copy. + dormant(key); + + // Now remote... + DDF in("remove::"REMOTED_SESSION_CACHE"::SessionCache"); + DDFJanitor jin(in); + in.structure(); + in.addmember("key").string(key); + in.addmember("application_id").string(application.getId()); + + DDF out = application.getServiceProvider().getListenerService()->send(in); + out.destroy(); +} + +void RemotedCache::dormant(const char* key) +{ +#ifdef _DEBUG + xmltooling::NDC ndc("dormant"); +#endif + + m_log.debug("deleting local copy of session (%s)", key); + + // lock the cache for writing, which means we know nobody is sitting in find() + m_lock->wrlock(); + + // grab the entry from the table + map::const_iterator i=m_hashtable.find(key); + if (i==m_hashtable.end()) { + m_lock->unlock(); + return; + } + + // ok, remove the entry and lock it + RemotedSession* entry=i->second; + m_hashtable.erase(key); + entry->lock(); + + // unlock the cache + m_lock->unlock(); + + // we can release the cache entry lock because we know we're not in the cache anymore + entry->unlock(); + + delete entry; +} + +void RemotedCache::cleanup() +{ +#ifdef _DEBUG + xmltooling::NDC ndc("cleanup"); +#endif + + Mutex* mutex = Mutex::create(); + + // Load our configuration details... + static const XMLCh cleanupInterval[] = UNICODE_LITERAL_15(c,l,e,a,n,u,p,I,n,t,e,r,v,a,l); + const XMLCh* tag=m_root ? m_root->getAttributeNS(NULL,cleanupInterval) : NULL; + int rerun_timer = 900; + if (tag && *tag) + rerun_timer = XMLString::parseInt(tag); + if (rerun_timer <= 0) + rerun_timer = 900; + + mutex->lock(); + + m_log.info("cleanup thread started...run every %d secs; timeout after %d secs", rerun_timer, m_cacheTimeout); + + while (!shutdown) { + shutdown_wait->timedwait(mutex,rerun_timer); + if (shutdown) + break; + + // Ok, let's run through the cleanup process and clean out + // really old sessions. This is a two-pass process. The + // first pass is done holding a read-lock while we iterate over + // the cache. The second pass doesn't need a lock because + // the 'deletes' will lock the cache. + + // Pass 1: iterate over the map and find all entries that have not been + // used in X hours + vector stale_keys; + time_t stale = time(NULL) - m_cacheTimeout; + + m_log.debug("cleanup thread running"); + + m_lock->rdlock(); + for (map::const_iterator i=m_hashtable.begin(); i!=m_hashtable.end(); ++i) { + // If the last access was BEFORE the stale timeout... + i->second->lock(); + time_t last=i->second->lastAccess(); + i->second->unlock(); + if (last < stale) + stale_keys.push_back(i->first); + } + m_lock->unlock(); + + if (!stale_keys.empty()) { + m_log.info("purging %d old sessions", stale_keys.size()); + + // Pass 2: walk through the list of stale entries and remove them from the cache + for (vector::const_iterator j = stale_keys.begin(); j != stale_keys.end(); ++j) + dormant(j->c_str()); + } + + m_log.debug("cleanup thread completed"); + } + + m_log.info("cleanup thread exiting"); + + mutex->unlock(); + delete mutex; + Thread::exit(NULL); +} + +void* RemotedCache::cleanup_fn(void* cache_p) +{ + RemotedCache* cache = reinterpret_cast(cache_p); + +#ifndef WIN32 + // First, let's block all signals + Thread::mask_all_signals(); +#endif + + // Now run the cleanup process. + cache->cleanup(); + return NULL; +} diff --git a/shibsp/impl/StorageServiceSessionCache.cpp b/shibsp/impl/StorageServiceSessionCache.cpp index 5aa9a7e..4d20c95 100644 --- a/shibsp/impl/StorageServiceSessionCache.cpp +++ b/shibsp/impl/StorageServiceSessionCache.cpp @@ -118,7 +118,7 @@ namespace shibsp { for (vector::const_iterator a = m_attributes.begin(); a != m_attributes.end(); ++a) { const vector& aliases = (*a)->getAliases(); for (vector::const_iterator alias = aliases.begin(); alias != aliases.end(); ++alias) - m_attributeIndex.insert(make_pair(*alias, *a)); + m_attributeIndex.insert(multimap::value_type(*alias, *a)); } } return m_attributeIndex; @@ -227,7 +227,7 @@ void StoredSession::unmarshallAttributes() const try { attribute = Attribute::unmarshall(attr); m_attributes.push_back(attribute); - m_attributeIndex.insert(make_pair(attribute->getId(), attribute)); + m_attributeIndex.insert(multimap::value_type(attribute->getId(), attribute)); if (m_cache->m_log.isDebugEnabled()) m_cache->m_log.debug("unmarshalled attribute (ID: %s) with %d value%s", attribute->getId(), attr.first().integer(), attr.first().integer()!=1 ? "s" : ""); diff --git a/shibsp/impl/XMLRequestMapper.cpp b/shibsp/impl/XMLRequestMapper.cpp index 1f2174b..1d214ee 100644 --- a/shibsp/impl/XMLRequestMapper.cpp +++ b/shibsp/impl/XMLRequestMapper.cpp @@ -1,654 +1,654 @@ -/* - * Copyright 2001-2007 Internet2 - * - * 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 - * - * XML-based RequestMapper implementation - */ - -#include "internal.h" -#include "exceptions.h" -#include "AccessControl.h" -#include "RequestMapper.h" -#include "SPRequest.h" -#include "util/DOMPropertySet.h" -#include "util/SPConstants.h" - -#include -#include -#include -#include -#include - -using namespace shibsp; -using namespace xmltooling; -using namespace std; - -namespace shibsp { - - // Blocks access when an ACL plugin fails to load. - class AccessControlDummy : public AccessControl - { - public: - Lockable* lock() { - return this; - } - - void unlock() {} - - aclresult_t authorized(const SPRequest& request, const Session* session) const { - return shib_acl_false; - } - }; - - class Override : public DOMPropertySet, public DOMNodeFilter - { - public: - Override() : m_acl(NULL) {} - Override(const DOMElement* e, Category& log, const Override* base=NULL); - ~Override(); - - // Provides filter to exclude special config elements. - short acceptNode(const DOMNode* node) const { - return FILTER_REJECT; - } - - const Override* locate(const HTTPRequest& request) const; - AccessControl* getAC() const { return (m_acl ? m_acl : (getParent() ? dynamic_cast(getParent())->getAC() : NULL)); } - - protected: - void loadACL(const DOMElement* e, Category& log); - - map m_map; - vector< pair > m_regexps; - vector< pair< pair,Override*> > m_queries; - - private: - AccessControl* m_acl; - }; - - class XMLRequestMapperImpl : public Override - { - public: - 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 HTTPRequest& request) const; - - private: - map m_extras; - DOMDocument* m_document; - }; - -#if defined (_MSC_VER) - #pragma warning( push ) - #pragma warning( disable : 4250 ) -#endif - - class XMLRequestMapper : public RequestMapper, public ReloadableXMLFile - { - public: - XMLRequestMapper(const DOMElement* e) : ReloadableXMLFile(e,Category::getInstance(SHIBSP_LOGCAT".RequestMapper")), m_impl(NULL) { - load(); - } - - ~XMLRequestMapper() { - delete m_impl; - } - - Settings getSettings(const HTTPRequest& request) const; - - protected: - pair load(); - - private: - XMLRequestMapperImpl* m_impl; - }; - -#if defined (_MSC_VER) - #pragma warning( pop ) -#endif - - RequestMapper* SHIBSP_DLLLOCAL XMLRequestMapperFactory(const DOMElement* const & e) - { - return new XMLRequestMapper(e); - } - - 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 Host[] = UNICODE_LITERAL_4(H,o,s,t); - static const XMLCh HostRegex[] = UNICODE_LITERAL_9(H,o,s,t,R,e,g,e,x); - static const XMLCh htaccess[] = UNICODE_LITERAL_8(h,t,a,c,c,e,s,s); - static const XMLCh ignoreCase[] = UNICODE_LITERAL_10(i,g,n,o,r,e,C,a,s,e); - static const XMLCh ignoreOption[] = UNICODE_LITERAL_1(i); - static const XMLCh Path[] = UNICODE_LITERAL_4(P,a,t,h); - static const XMLCh PathRegex[] = UNICODE_LITERAL_9(P,a,t,h,R,e,g,e,x); - static const XMLCh Query[] = UNICODE_LITERAL_5(Q,u,e,r,y); - static const XMLCh name[] = UNICODE_LITERAL_4(n,a,m,e); - static const XMLCh regex[] = UNICODE_LITERAL_5(r,e,g,e,x); - static const XMLCh _type[] = UNICODE_LITERAL_4(t,y,p,e); -} - -void SHIBSP_API shibsp::registerRequestMappers() -{ - SPConfig& conf=SPConfig::getConfig(); - conf.RequestMapperManager.registerFactory(XML_REQUEST_MAPPER, XMLRequestMapperFactory); - conf.RequestMapperManager.registerFactory(NATIVE_REQUEST_MAPPER, XMLRequestMapperFactory); -} - -void Override::loadACL(const DOMElement* e, Category& log) -{ - try { - const DOMElement* acl=XMLHelper::getFirstChildElement(e,htaccess); - if (acl) { - log.info("building Apache htaccess AccessControl provider..."); - m_acl=SPConfig::getConfig().AccessControlManager.newPlugin(HT_ACCESS_CONTROL,acl); - } - else { - acl=XMLHelper::getFirstChildElement(e,_AccessControl); - if (acl) { - log.info("building XML-based AccessControl provider..."); - m_acl=SPConfig::getConfig().AccessControlManager.newPlugin(XML_ACCESS_CONTROL,acl); - } - else { - acl=XMLHelper::getFirstChildElement(e,AccessControlProvider); - if (acl) { - auto_ptr_char type(acl->getAttributeNS(NULL,_type)); - log.info("building AccessControl provider of type %s...",type.get()); - m_acl=SPConfig::getConfig().AccessControlManager.newPlugin(type.get(),acl); - } - } - } - } - 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_acl(NULL) -{ - try { - // Load the property set. - load(e,log,this); - setParent(base); - - // Load any AccessControl provider. - loadACL(e,log); - - // Handle nested Paths. - 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); - 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::SHIB2SPCONFIG_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 name=o->getString("name"); - char* dup=strdup(name.second); - for (char* pch=dup; *pch; pch++) - *pch=tolower(*pch); - if (m_map.count(dup)) { - log.warn("skipping duplicate Path element (%s)",dup); - free(dup); - delete o; - continue; - } - m_map[dup]=o; - log.debug("added Path mapping (%s)", dup); - free(dup); - } - - if (!XMLString::equals(e->getLocalName(), PathRegex)) { - // Handle nested PathRegexs. - path = XMLHelper::getFirstChildElement(e,PathRegex); - for (int i=1; path; ++i, path=XMLHelper::getNextSiblingElement(path,PathRegex)) { - const XMLCh* n=path->getAttributeNS(NULL,regex); - if (!n || !*n) { - log.warn("skipping PathRegex element (%d) with empty regex attribute",i); - continue; - } - - auto_ptr o(new Override(path,log,this)); - - const XMLCh* flag=path->getAttributeNS(NULL,ignoreCase); - try { - auto_ptr re( - new RegularExpression(n, (flag && (*flag==chLatin_f || *flag==chDigit_0)) ? &chNull : ignoreOption) - ); - m_regexps.push_back(make_pair(re.release(), o.release())); - } - catch (XMLException& ex) { - auto_ptr_char tmp(ex.getMessage()); - log.error("caught exception while parsing PathRegex regular expression (%d): %s", i, tmp.get()); - throw ConfigurationException("Invalid regular expression in PathRegex element."); - } - - if (log.isDebugEnabled()) - log.debug("added mapping (%s)", m_regexps.back().second->getString("regex").second); - } - } - - // Handle nested Querys. - path = XMLHelper::getFirstChildElement(e,Query); - for (int i=1; path; ++i, path=XMLHelper::getNextSiblingElement(path,Query)) { - const XMLCh* n=path->getAttributeNS(NULL,name); - if (!n || !*n) { - log.warn("skipping Query element (%d) with empty name attribute",i); - continue; - } - auto_ptr_char ntemp(n); - const XMLCh* v=path->getAttributeNS(NULL,regex); - - auto_ptr o(new Override(path,log,this)); - try { - RegularExpression* re = NULL; - if (v && *v) - re = new RegularExpression(v); - m_queries.push_back(make_pair(make_pair(ntemp.get(),re), o.release())); - } - catch (XMLException& ex) { - auto_ptr_char tmp(ex.getMessage()); - log.error("caught exception while parsing Query regular expression (%d): %s", i, tmp.get()); - throw ConfigurationException("Invalid regular expression in Query element."); - } - - log.debug("added mapping (%s)", ntemp.get()); - } - } - catch (exception&) { - delete m_acl; - for_each(m_map.begin(),m_map.end(),xmltooling::cleanup_pair()); - for (vector< pair >::iterator i = m_regexps.begin(); i != m_regexps.end(); ++i) { - delete i->first; - delete i->second; - } - for (vector< pair< pair,Override*> >::iterator j = m_queries.begin(); j != m_queries.end(); ++j) { - delete j->first.second; - delete j->second; - } - throw; - } -} - -Override::~Override() -{ - delete m_acl; - for_each(m_map.begin(),m_map.end(),xmltooling::cleanup_pair()); - for (vector< pair >::iterator i = m_regexps.begin(); i != m_regexps.end(); ++i) { - delete i->first; - delete i->second; - } - for (vector< pair< pair,Override*> >::iterator j = m_queries.begin(); j != m_queries.end(); ++j) { - delete j->first.second; - delete j->second; - } -} - -const Override* Override::locate(const HTTPRequest& request) const -{ - // This function is confusing because it's *not* recursive. - // The whole path is tokenized and mapped in a loop, so the - // path parameter starts with the entire request path and - // we can skip the leading slash as irrelevant. - const char* path = request.getRequestURI(); - if (*path == '/') - path++; - - // Now we copy the path, chop the query string, and lower case it. - char* dup=strdup(path); - char* sep=strchr(dup,'?'); - if (sep) - *sep=0; - for (char* pch=dup; *pch; pch++) - *pch=tolower(*pch); - - // Default is for the current object to provide settings. - const Override* o=this; - - // Tokenize the path by segment and try and map each segment. -#ifdef HAVE_STRTOK_R - char* pos=NULL; - const char* token=strtok_r(dup,"/",&pos); -#else - const char* token=strtok(dup,"/"); -#endif - while (token) { - map::const_iterator i=o->m_map.find(token); - if (i==o->m_map.end()) - break; // Once there's no match, we've consumed as much of the path as possible here. - // We found a match, so reset the settings pointer. - o=i->second; - - // We descended a step down the path, so we need to advance the original - // parameter for the regex step later. - path += strlen(token); - if (*path == '/') - path++; - - // Get the next segment, if any. -#ifdef HAVE_STRTOK_R - token=strtok_r(NULL,"/",&pos); -#else - token=strtok(NULL,"/"); -#endif - } - - free(dup); - - // If there's anything left, we try for a regex match on the rest of the path minus the query string. - if (*path) { - string path2(path); - path2 = path2.substr(0,path2.find('?')); - - for (vector< pair >::const_iterator re = o->m_regexps.begin(); re != o->m_regexps.end(); ++re) { - if (re->first->matches(path2.c_str())) { - o = re->second; - break; - } - } - } - - // Finally, check for query string matches. This is another "unrolled" recursive descent in a loop. - bool descended; - do { - descended = false; - for (vector< pair< pair,Override*> >::const_iterator q = o->m_queries.begin(); !descended && q != o->m_queries.end(); ++q) { - vector vals; - if (request.getParameters(q->first.first.c_str(), vals)) { - if (q->first.second) { - // We have to match one of the values. - for (vector::const_iterator v = vals.begin(); v != vals.end(); ++v) { - if (q->first.second->matches(*v)) { - o = q->second; - descended = true; - break; - } - } - } - else { - // The simple presence of the parameter is sufficient to match. - o = q->second; - descended = true; - } - } - } - } while (descended); - - return o; -} - -XMLRequestMapperImpl::XMLRequestMapperImpl(const DOMElement* e, Category& log) : m_document(NULL) -{ -#ifdef _DEBUG - xmltooling::NDC ndc("XMLRequestMapperImpl"); -#endif - - // Load the property set. - load(e,log,this); - - // Load any AccessControl provider. - loadACL(e,log); - - // Loop over the HostRegex elements. - const DOMElement* host = XMLHelper::getFirstChildElement(e,HostRegex); - for (int i=1; host; ++i, host=XMLHelper::getNextSiblingElement(host,HostRegex)) { - const XMLCh* n=host->getAttributeNS(NULL,regex); - if (!n || !*n) { - log.warn("Skipping HostRegex element (%d) with empty regex attribute",i); - continue; - } - - auto_ptr o(new Override(host,log,this)); - - const XMLCh* flag=host->getAttributeNS(NULL,ignoreCase); - try { - auto_ptr re( - new RegularExpression(n, (flag && (*flag==chLatin_f || *flag==chDigit_0)) ? &chNull : ignoreOption) - ); - m_regexps.push_back(make_pair(re.release(), o.release())); - } - catch (XMLException& ex) { - auto_ptr_char tmp(ex.getMessage()); - log.error("caught exception while parsing HostRegex regular expression (%d): %s", i, tmp.get()); - } - - log.debug("Added mapping for %s", m_regexps.back().second->getString("regex").second); - } - - // Loop over the Host elements. - 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; - } - - Override* o=new Override(host,log,this); - pair name=o->getString("name"); - pair scheme=o->getString("scheme"); - pair port=o->getString("port"); - - char* dup=strdup(name.second); - for (char* pch=dup; *pch; pch++) - *pch=tolower(*pch); - auto_ptr dupwrap(dup); - - if (!scheme.first && port.first) { - // No scheme, but a port, so assume http. - scheme = pair(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 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 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 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 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 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 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 mapping for %s",url.c_str()); - } - } -} - -const Override* XMLRequestMapperImpl::findOverride(const char* vhost, const HTTPRequest& request) const -{ - const Override* o=NULL; - map::const_iterator i=m_map.find(vhost); - if (i!=m_map.end()) - o=i->second; - else { - i=m_extras.find(vhost); - if (i!=m_extras.end()) - o=i->second; - else { - for (vector< pair >::const_iterator re = m_regexps.begin(); !o && re != m_regexps.end(); ++re) { - if (re->first->matches(vhost)) - o=re->second; - } - } - } - - return o ? o->locate(request) : this; -} - -pair XMLRequestMapper::load() -{ - // Load from source using base class. - pair raw = ReloadableXMLFile::load(); - - // If we own it, wrap it. - XercesJanitor docjanitor(raw.first ? raw.second->getOwnerDocument() : NULL); - - 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()); - - delete m_impl; - m_impl = impl; - - return make_pair(false,(DOMElement*)NULL); -} - -RequestMapper::Settings XMLRequestMapper::getSettings(const HTTPRequest& request) const -{ - ostringstream vhost; - vhost << request.getScheme() << "://" << request.getHostname() << ':' << request.getPort(); - - const Override* o=m_impl->findOverride(vhost.str().c_str(), request); - - if (m_log.isDebugEnabled()) { -#ifdef _DEBUG - xmltooling::NDC ndc("getSettings"); -#endif - pair ret=o->getString("applicationId"); - m_log.debug("mapped %s%s to %s", vhost.str().c_str(), request.getRequestURI() ? request.getRequestURI() : "", ret.second); - } - - return Settings(o,o->getAC()); -} +/* + * Copyright 2001-2007 Internet2 + * + * 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 + * + * XML-based RequestMapper implementation + */ + +#include "internal.h" +#include "exceptions.h" +#include "AccessControl.h" +#include "RequestMapper.h" +#include "SPRequest.h" +#include "util/DOMPropertySet.h" +#include "util/SPConstants.h" + +#include +#include +#include +#include +#include + +using namespace shibsp; +using namespace xmltooling; +using namespace std; + +namespace shibsp { + + // Blocks access when an ACL plugin fails to load. + class AccessControlDummy : public AccessControl + { + public: + Lockable* lock() { + return this; + } + + void unlock() {} + + aclresult_t authorized(const SPRequest& request, const Session* session) const { + return shib_acl_false; + } + }; + + class Override : public DOMPropertySet, public DOMNodeFilter + { + public: + Override() : m_acl(NULL) {} + Override(const DOMElement* e, Category& log, const Override* base=NULL); + ~Override(); + + // Provides filter to exclude special config elements. + short acceptNode(const DOMNode* node) const { + return FILTER_REJECT; + } + + const Override* locate(const HTTPRequest& request) const; + AccessControl* getAC() const { return (m_acl ? m_acl : (getParent() ? dynamic_cast(getParent())->getAC() : NULL)); } + + protected: + void loadACL(const DOMElement* e, Category& log); + + map m_map; + vector< pair > m_regexps; + vector< pair< pair,Override*> > m_queries; + + private: + AccessControl* m_acl; + }; + + class XMLRequestMapperImpl : public Override + { + public: + 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 HTTPRequest& request) const; + + private: + map m_extras; + DOMDocument* m_document; + }; + +#if defined (_MSC_VER) + #pragma warning( push ) + #pragma warning( disable : 4250 ) +#endif + + class XMLRequestMapper : public RequestMapper, public ReloadableXMLFile + { + public: + XMLRequestMapper(const DOMElement* e) : ReloadableXMLFile(e,Category::getInstance(SHIBSP_LOGCAT".RequestMapper")), m_impl(NULL) { + load(); + } + + ~XMLRequestMapper() { + delete m_impl; + } + + Settings getSettings(const HTTPRequest& request) const; + + protected: + pair load(); + + private: + XMLRequestMapperImpl* m_impl; + }; + +#if defined (_MSC_VER) + #pragma warning( pop ) +#endif + + RequestMapper* SHIBSP_DLLLOCAL XMLRequestMapperFactory(const DOMElement* const & e) + { + return new XMLRequestMapper(e); + } + + 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 Host[] = UNICODE_LITERAL_4(H,o,s,t); + static const XMLCh HostRegex[] = UNICODE_LITERAL_9(H,o,s,t,R,e,g,e,x); + static const XMLCh htaccess[] = UNICODE_LITERAL_8(h,t,a,c,c,e,s,s); + static const XMLCh ignoreCase[] = UNICODE_LITERAL_10(i,g,n,o,r,e,C,a,s,e); + static const XMLCh ignoreOption[] = UNICODE_LITERAL_1(i); + static const XMLCh Path[] = UNICODE_LITERAL_4(P,a,t,h); + static const XMLCh PathRegex[] = UNICODE_LITERAL_9(P,a,t,h,R,e,g,e,x); + static const XMLCh Query[] = UNICODE_LITERAL_5(Q,u,e,r,y); + static const XMLCh name[] = UNICODE_LITERAL_4(n,a,m,e); + static const XMLCh regex[] = UNICODE_LITERAL_5(r,e,g,e,x); + static const XMLCh _type[] = UNICODE_LITERAL_4(t,y,p,e); +} + +void SHIBSP_API shibsp::registerRequestMappers() +{ + SPConfig& conf=SPConfig::getConfig(); + conf.RequestMapperManager.registerFactory(XML_REQUEST_MAPPER, XMLRequestMapperFactory); + conf.RequestMapperManager.registerFactory(NATIVE_REQUEST_MAPPER, XMLRequestMapperFactory); +} + +void Override::loadACL(const DOMElement* e, Category& log) +{ + try { + const DOMElement* acl=XMLHelper::getFirstChildElement(e,htaccess); + if (acl) { + log.info("building Apache htaccess AccessControl provider..."); + m_acl=SPConfig::getConfig().AccessControlManager.newPlugin(HT_ACCESS_CONTROL,acl); + } + else { + acl=XMLHelper::getFirstChildElement(e,_AccessControl); + if (acl) { + log.info("building XML-based AccessControl provider..."); + m_acl=SPConfig::getConfig().AccessControlManager.newPlugin(XML_ACCESS_CONTROL,acl); + } + else { + acl=XMLHelper::getFirstChildElement(e,AccessControlProvider); + if (acl) { + auto_ptr_char type(acl->getAttributeNS(NULL,_type)); + log.info("building AccessControl provider of type %s...",type.get()); + m_acl=SPConfig::getConfig().AccessControlManager.newPlugin(type.get(),acl); + } + } + } + } + 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_acl(NULL) +{ + try { + // Load the property set. + load(e,log,this); + setParent(base); + + // Load any AccessControl provider. + loadACL(e,log); + + // Handle nested Paths. + 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); + 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::SHIB2SPCONFIG_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 name=o->getString("name"); + char* dup=strdup(name.second); + for (char* pch=dup; *pch; pch++) + *pch=tolower(*pch); + if (m_map.count(dup)) { + log.warn("skipping duplicate Path element (%s)",dup); + free(dup); + delete o; + continue; + } + m_map[dup]=o; + log.debug("added Path mapping (%s)", dup); + free(dup); + } + + if (!XMLString::equals(e->getLocalName(), PathRegex)) { + // Handle nested PathRegexs. + path = XMLHelper::getFirstChildElement(e,PathRegex); + for (int i=1; path; ++i, path=XMLHelper::getNextSiblingElement(path,PathRegex)) { + const XMLCh* n=path->getAttributeNS(NULL,regex); + if (!n || !*n) { + log.warn("skipping PathRegex element (%d) with empty regex attribute",i); + continue; + } + + auto_ptr o(new Override(path,log,this)); + + const XMLCh* flag=path->getAttributeNS(NULL,ignoreCase); + try { + auto_ptr re( + new RegularExpression(n, (flag && (*flag==chLatin_f || *flag==chDigit_0)) ? &chNull : ignoreOption) + ); + m_regexps.push_back(make_pair(re.release(), o.release())); + } + catch (XMLException& ex) { + auto_ptr_char tmp(ex.getMessage()); + log.error("caught exception while parsing PathRegex regular expression (%d): %s", i, tmp.get()); + throw ConfigurationException("Invalid regular expression in PathRegex element."); + } + + if (log.isDebugEnabled()) + log.debug("added mapping (%s)", m_regexps.back().second->getString("regex").second); + } + } + + // Handle nested Querys. + path = XMLHelper::getFirstChildElement(e,Query); + for (int i=1; path; ++i, path=XMLHelper::getNextSiblingElement(path,Query)) { + const XMLCh* n=path->getAttributeNS(NULL,name); + if (!n || !*n) { + log.warn("skipping Query element (%d) with empty name attribute",i); + continue; + } + auto_ptr_char ntemp(n); + const XMLCh* v=path->getAttributeNS(NULL,regex); + + auto_ptr o(new Override(path,log,this)); + try { + RegularExpression* re = NULL; + if (v && *v) + re = new RegularExpression(v); + m_queries.push_back(make_pair(make_pair(string(ntemp.get()),re), o.release())); + } + catch (XMLException& ex) { + auto_ptr_char tmp(ex.getMessage()); + log.error("caught exception while parsing Query regular expression (%d): %s", i, tmp.get()); + throw ConfigurationException("Invalid regular expression in Query element."); + } + + log.debug("added mapping (%s)", ntemp.get()); + } + } + catch (exception&) { + delete m_acl; + for_each(m_map.begin(),m_map.end(),xmltooling::cleanup_pair()); + for (vector< pair >::iterator i = m_regexps.begin(); i != m_regexps.end(); ++i) { + delete i->first; + delete i->second; + } + for (vector< pair< pair,Override*> >::iterator j = m_queries.begin(); j != m_queries.end(); ++j) { + delete j->first.second; + delete j->second; + } + throw; + } +} + +Override::~Override() +{ + delete m_acl; + for_each(m_map.begin(),m_map.end(),xmltooling::cleanup_pair()); + for (vector< pair >::iterator i = m_regexps.begin(); i != m_regexps.end(); ++i) { + delete i->first; + delete i->second; + } + for (vector< pair< pair,Override*> >::iterator j = m_queries.begin(); j != m_queries.end(); ++j) { + delete j->first.second; + delete j->second; + } +} + +const Override* Override::locate(const HTTPRequest& request) const +{ + // This function is confusing because it's *not* recursive. + // The whole path is tokenized and mapped in a loop, so the + // path parameter starts with the entire request path and + // we can skip the leading slash as irrelevant. + const char* path = request.getRequestURI(); + if (*path == '/') + path++; + + // Now we copy the path, chop the query string, and lower case it. + char* dup=strdup(path); + char* sep=strchr(dup,'?'); + if (sep) + *sep=0; + for (char* pch=dup; *pch; pch++) + *pch=tolower(*pch); + + // Default is for the current object to provide settings. + const Override* o=this; + + // Tokenize the path by segment and try and map each segment. +#ifdef HAVE_STRTOK_R + char* pos=NULL; + const char* token=strtok_r(dup,"/",&pos); +#else + const char* token=strtok(dup,"/"); +#endif + while (token) { + map::const_iterator i=o->m_map.find(token); + if (i==o->m_map.end()) + break; // Once there's no match, we've consumed as much of the path as possible here. + // We found a match, so reset the settings pointer. + o=i->second; + + // We descended a step down the path, so we need to advance the original + // parameter for the regex step later. + path += strlen(token); + if (*path == '/') + path++; + + // Get the next segment, if any. +#ifdef HAVE_STRTOK_R + token=strtok_r(NULL,"/",&pos); +#else + token=strtok(NULL,"/"); +#endif + } + + free(dup); + + // If there's anything left, we try for a regex match on the rest of the path minus the query string. + if (*path) { + string path2(path); + path2 = path2.substr(0,path2.find('?')); + + for (vector< pair >::const_iterator re = o->m_regexps.begin(); re != o->m_regexps.end(); ++re) { + if (re->first->matches(path2.c_str())) { + o = re->second; + break; + } + } + } + + // Finally, check for query string matches. This is another "unrolled" recursive descent in a loop. + bool descended; + do { + descended = false; + for (vector< pair< pair,Override*> >::const_iterator q = o->m_queries.begin(); !descended && q != o->m_queries.end(); ++q) { + vector vals; + if (request.getParameters(q->first.first.c_str(), vals)) { + if (q->first.second) { + // We have to match one of the values. + for (vector::const_iterator v = vals.begin(); v != vals.end(); ++v) { + if (q->first.second->matches(*v)) { + o = q->second; + descended = true; + break; + } + } + } + else { + // The simple presence of the parameter is sufficient to match. + o = q->second; + descended = true; + } + } + } + } while (descended); + + return o; +} + +XMLRequestMapperImpl::XMLRequestMapperImpl(const DOMElement* e, Category& log) : m_document(NULL) +{ +#ifdef _DEBUG + xmltooling::NDC ndc("XMLRequestMapperImpl"); +#endif + + // Load the property set. + load(e,log,this); + + // Load any AccessControl provider. + loadACL(e,log); + + // Loop over the HostRegex elements. + const DOMElement* host = XMLHelper::getFirstChildElement(e,HostRegex); + for (int i=1; host; ++i, host=XMLHelper::getNextSiblingElement(host,HostRegex)) { + const XMLCh* n=host->getAttributeNS(NULL,regex); + if (!n || !*n) { + log.warn("Skipping HostRegex element (%d) with empty regex attribute",i); + continue; + } + + auto_ptr o(new Override(host,log,this)); + + const XMLCh* flag=host->getAttributeNS(NULL,ignoreCase); + try { + auto_ptr re( + new RegularExpression(n, (flag && (*flag==chLatin_f || *flag==chDigit_0)) ? &chNull : ignoreOption) + ); + m_regexps.push_back(make_pair(re.release(), o.release())); + } + catch (XMLException& ex) { + auto_ptr_char tmp(ex.getMessage()); + log.error("caught exception while parsing HostRegex regular expression (%d): %s", i, tmp.get()); + } + + log.debug("Added mapping for %s", m_regexps.back().second->getString("regex").second); + } + + // Loop over the Host elements. + 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; + } + + Override* o=new Override(host,log,this); + pair name=o->getString("name"); + pair scheme=o->getString("scheme"); + pair port=o->getString("port"); + + char* dup=strdup(name.second); + for (char* pch=dup; *pch; pch++) + *pch=tolower(*pch); + auto_ptr dupwrap(dup); + + if (!scheme.first && port.first) { + // No scheme, but a port, so assume http. + scheme = pair(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 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 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 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 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 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 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 mapping for %s",url.c_str()); + } + } +} + +const Override* XMLRequestMapperImpl::findOverride(const char* vhost, const HTTPRequest& request) const +{ + const Override* o=NULL; + map::const_iterator i=m_map.find(vhost); + if (i!=m_map.end()) + o=i->second; + else { + i=m_extras.find(vhost); + if (i!=m_extras.end()) + o=i->second; + else { + for (vector< pair >::const_iterator re = m_regexps.begin(); !o && re != m_regexps.end(); ++re) { + if (re->first->matches(vhost)) + o=re->second; + } + } + } + + return o ? o->locate(request) : this; +} + +pair XMLRequestMapper::load() +{ + // Load from source using base class. + pair raw = ReloadableXMLFile::load(); + + // If we own it, wrap it. + XercesJanitor docjanitor(raw.first ? raw.second->getOwnerDocument() : NULL); + + 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()); + + delete m_impl; + m_impl = impl; + + return make_pair(false,(DOMElement*)NULL); +} + +RequestMapper::Settings XMLRequestMapper::getSettings(const HTTPRequest& request) const +{ + ostringstream vhost; + vhost << request.getScheme() << "://" << request.getHostname() << ':' << request.getPort(); + + const Override* o=m_impl->findOverride(vhost.str().c_str(), request); + + if (m_log.isDebugEnabled()) { +#ifdef _DEBUG + xmltooling::NDC ndc("getSettings"); +#endif + pair ret=o->getString("applicationId"); + m_log.debug("mapped %s%s to %s", vhost.str().c_str(), request.getRequestURI() ? request.getRequestURI() : "", ret.second); + } + + return Settings(o,o->getAC()); +} diff --git a/shibsp/impl/XMLServiceProvider.cpp b/shibsp/impl/XMLServiceProvider.cpp index 91869c0..8002859 100644 --- a/shibsp/impl/XMLServiceProvider.cpp +++ b/shibsp/impl/XMLServiceProvider.cpp @@ -559,7 +559,9 @@ XMLApplication::XMLApplication( static const XMLCh _acl[] = UNICODE_LITERAL_9(e,x,p,o,r,t,A,C,L); exportElement->setAttributeNS(NULL,_acl,exportACL.second); } - handler = conf.HandlerManager.newPlugin(samlconstants::SAML20_BINDING_URI, make_pair(exportElement, getId())); + handler = conf.HandlerManager.newPlugin( + samlconstants::SAML20_BINDING_URI, pair(exportElement, getId()) + ); m_handlers.push_back(handler); // Insert into location map. If it contains the handlerURL, we skip past that part. @@ -1415,7 +1417,7 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o auto_ptr_char value(rule->getFirstChild()->getNodeValue()); if (provider.get() && *provider.get() && option.get() && *option.get() && value.get() && *value.get()) { m_transportOptionMap[id.get()].push_back( - make_pair(provider.get(), make_pair(option.get(), value.get())) + make_pair(string(provider.get()), make_pair(string(option.get()), string(value.get()))) ); } } diff --git a/shibsp/remoting/impl/SocketListener.cpp b/shibsp/remoting/impl/SocketListener.cpp index d302b5d..32bfadf 100644 --- a/shibsp/remoting/impl/SocketListener.cpp +++ b/shibsp/remoting/impl/SocketListener.cpp @@ -35,6 +35,10 @@ # include #endif +#ifdef HAVE_UNISTD_H +# include +#endif + using namespace shibsp; using namespace xmltooling; using namespace std; diff --git a/shibsp/util/DOMPropertySet.cpp b/shibsp/util/DOMPropertySet.cpp index 05f2ee0..d7dc70f 100644 --- a/shibsp/util/DOMPropertySet.cpp +++ b/shibsp/util/DOMPropertySet.cpp @@ -153,7 +153,7 @@ pair DOMPropertySet::getString(const char* name, const char* n i=m_map.find(name); if (i!=m_map.end()) - return make_pair(true,i->second.first); + return pair(true,i->second.first); else if (m_parent) return m_parent->getString(name,ns); return pair(false,NULL); diff --git a/shibsp/util/TemplateParameters.cpp b/shibsp/util/TemplateParameters.cpp index eee522d..93a5a42 100644 --- a/shibsp/util/TemplateParameters.cpp +++ b/shibsp/util/TemplateParameters.cpp @@ -39,7 +39,7 @@ void TemplateParameters::setPropertySet(const PropertySet* props) time_t now = time(NULL); #ifdef HAVE_CTIME_R char timebuf[32]; - m_map["now"] = ctime_r(&now,timebuf); + m_map["now"] = ctime_r(&now,timebuf,sizeof(timebuf)); #else m_map["now"] = ctime(&now); #endif