const HTTPRequest& httpRequest,
HTTPResponse& httpResponse,
SecurityPolicy& policy,
- const PropertySet* settings,
+ const PropertySet*,
const XMLObject& xmlObject
) const;
#endif
const HTTPRequest& httpRequest,
HTTPResponse& httpResponse,
SecurityPolicy& policy,
- const PropertySet* settings,
+ const PropertySet*,
const XMLObject& xmlObject
) const
{
<anyAttribute namespace="##any" processContents="lax"/>
</complexType>
- <complexType name="SecurityPoliciesType">
- <annotation>
- <documentation>Container for specifying sets of policy rules to apply to incoming messages</documentation>
- </annotation>
- <sequence>
- <element name="Policy" minOccurs="1" maxOccurs="unbounded">
- <annotation>
- <documentation>Specifies a set of SecurityPolicyRule plugins</documentation>
- </annotation>
- <complexType>
- <choice>
- <element name="Rule" type="conf:PluggableType" minOccurs="1" maxOccurs="unbounded"/>
- <element name="PolicyRule" type="conf:PluggableType" minOccurs="1" maxOccurs="unbounded"/>
- </choice>
- <attribute name="id" type="conf:string" use="required"/>
- <attribute name="validate" type="boolean"/>
- <anyAttribute namespace="##any" processContents="lax"/>
- </complexType>
- </element>
- <choice minOccurs="0">
- <element name="AlgorithmWhitelist" type="conf:listOfURIs"/>
- <element name="AlgorithmBlacklist" type="conf:listOfURIs"/>
- </choice>
- </sequence>
- </complexType>
+ <element name="SecurityPolicies">
+ <complexType>
+ <annotation>
+ <documentation>Container for specifying sets of policy rules to apply to incoming messages</documentation>
+ </annotation>
+ <sequence>
+ <element name="Policy" minOccurs="1" maxOccurs="unbounded">
+ <annotation>
+ <documentation>Specifies a set of SecurityPolicyRule plugins</documentation>
+ </annotation>
+ <complexType>
+ <choice>
+ <element name="Rule" type="conf:PluggableType" minOccurs="1" maxOccurs="unbounded"/>
+ <element name="PolicyRule" type="conf:PluggableType" minOccurs="1" maxOccurs="unbounded"/>
+ </choice>
+ <attribute name="id" type="conf:string" use="required"/>
+ <attribute name="validate" type="boolean"/>
+ <anyAttribute namespace="##any" processContents="lax"/>
+ </complexType>
+ </element>
+ <choice minOccurs="0">
+ <element name="AlgorithmWhitelist" type="conf:listOfURIs"/>
+ <element name="AlgorithmBlacklist" type="conf:listOfURIs"/>
+ </choice>
+ </sequence>
+ </complexType>
+ </element>
<element name="TransportOption">
<annotation>
<element name="ArtifactMap" type="conf:ArtifactMapType" minOccurs="0"/>
<element name="RequestMapper" type="conf:PluggableType" minOccurs="0"/>
<element name="ApplicationDefaults" type="conf:ApplicationDefaultsType"/>
- <element name="SecurityPolicies" type="conf:SecurityPoliciesType"/>
+ <choice>
+ <element name="SecurityPolicyProvider" type="conf:PluggableType"/>
+ <element ref="conf:SecurityPolicies"/> <!-- deprecated -->
+ </choice>
<element ref="conf:TransportOption" minOccurs="0" maxOccurs="unbounded"/>
<element ref="ds:Signature" minOccurs="0"/>
</sequence>
secinclude_HEADERS = \
security/PKIXTrustEngine.h \
- security/SecurityPolicy.h
+ security/SecurityPolicy.h \
+ security/SecurityPolicyProvider.h
utilinclude_HEADERS = \
util/CGIParser.h \
attribute/resolver/impl/XMLAttributeExtractor.cpp \
binding/impl/ArtifactResolver.cpp \
binding/impl/SOAPClient.cpp \
+ impl/XMLSecurityPolicyProvider.cpp \
metadata/DynamicMetadataProvider.cpp \
metadata/MetadataExtImpl.cpp \
metadata/MetadataExtSchemaValidators.cpp \
# include "binding/ArtifactResolver.h"
# include "metadata/MetadataExt.h"
# include "security/PKIXTrustEngine.h"
+# include "security/SecurityPolicyProvider.h"
# include <saml/SAMLConfig.h>
#endif
registerAttributeFilters();
registerMatchFunctors();
}
+ registerSecurityPolicyProviders();
#endif
if (isEnabled(Listener))
Attribute::deregisterFactories();
#ifndef SHIBSP_LITE
+ SecurityPolicyProviderManager.deregisterFactories();
if (isEnabled(AttributeResolution)) {
MatchFunctorManager.deregisterFactories();
AttributeFilterManager.deregisterFactories();
class SHIBSP_API AttributeResolver;
class SHIBSP_API FilterPolicyContext;
class SHIBSP_API MatchFunctor;
+ class SHIBSP_API SecurityPolicyProvider;
#endif
#if defined (_MSC_VER)
* Manages factories for MatchFunctor plugins.
*/
xmltooling::PluginManager< MatchFunctor,xmltooling::QName,std::pair<const FilterPolicyContext*,const xercesc::DOMElement*> > MatchFunctorManager;
+
+ /**
+ * Manages factories for SecurityPolicyProvider plugins.
+ */
+ xmltooling::PluginManager<SecurityPolicyProvider,std::string,const xercesc::DOMElement*> SecurityPolicyProviderManager;
#endif
/**
{
}
+#ifndef SHIBSP_LITE
+SecurityPolicyProvider* ServiceProvider::getSecurityPolicyProvider(bool required) const
+{
+ if (required)
+ throw ConfigurationException("No SecurityPolicyProvider available.");
+ return NULL;
+}
+#endif
+
pair<bool,long> ServiceProvider::doAuthentication(SPRequest& request, bool handler) const
{
#ifdef _DEBUG
class SHIBSP_API SPRequest;
class SHIBSP_API TemplateParameters;
#ifndef SHIBSP_LITE
+ class SHIBSP_API SecurityPolicyProvider;
class SHIBSP_API TransactionLog;
#endif
#ifndef SHIBSP_LITE
/**
+ * Returns a SecurityPolicyProvider instance.
+ *
+ * @param required true iff an exception should be thrown if no SecurityPolicyProvider is available
+ * @return a SecurityPolicyProvider
+ */
+ virtual SecurityPolicyProvider* getSecurityPolicyProvider(bool required=true) const;
+
+ /**
+ * @deprecated
* Returns the security policy settings for an identified policy.
*
* @param id identifies the policy to return
virtual const PropertySet* getPolicySettings(const char* id) const=0;
/**
+ * @deprecated
* Returns the security policy rules for an identified policy.
*
* @param id identifies the policy to return
void generateMetadata(opensaml::saml2md::SPSSODescriptor& role, const char* handlerURL) const;
/**
+ * @deprecated
* Returns a SecurityPolicy instance to use for an incoming request.
*
* <p>Allows handlers to customize the type of policy object their policy rules might require.
* @param httpRequest client request that included message
* @param httpResponse response to client
* @param policy the SecurityPolicy in effect, after having evaluated the message
- * @param settings policy configuration settings in effect
+ * @param reserved ignore this parameter
* @param xmlObject a protocol-specific message object
*/
virtual void implementProtocol(
const xmltooling::HTTPRequest& httpRequest,
xmltooling::HTTPResponse& httpResponse,
opensaml::SecurityPolicy& policy,
- const PropertySet* settings,
+ const PropertySet* reserved,
const xmltooling::XMLObject& xmlObject
) const=0;
# include "attribute/resolver/ResolutionContext.h"
# include "metadata/MetadataProviderCriteria.h"
# include "security/SecurityPolicy.h"
+# include "security/SecurityPolicyProvider.h"
# include <saml/exceptions.h>
# include <saml/SAMLConfig.h>
# include <saml/saml1/core/Assertions.h>
if (!policyId.first)
policyId = application.getString("policyId"); // unqualified in Application(s) element
- // Access policy properties.
- const PropertySet* settings = application.getServiceProvider().getPolicySettings(policyId.second);
- pair<bool,bool> validate = settings->getBool("validate");
-
// Lock metadata for use by policy.
Locker metadataLocker(application.getMetadataProvider());
// Create the policy.
auto_ptr<opensaml::SecurityPolicy> policy(
- createSecurityPolicy(application, &m_role, validate.first && validate.second, policyId.second)
+ application.getServiceProvider().getSecurityPolicyProvider()->createSecurityPolicy(application, &m_role, policyId.second)
);
string relayState;
DDF postData = recoverPostData(application, httpRequest, httpResponse, relayState.c_str());
DDFJanitor postjan(postData);
recoverRelayState(application, httpRequest, httpResponse, relayState);
- implementProtocol(application, httpRequest, httpResponse, *(policy.get()), settings, *msg.get());
+ implementProtocol(application, httpRequest, httpResponse, *(policy.get()), NULL, *msg.get());
auto_ptr_char issuer(policy->getIssuer() ? policy->getIssuer()->getName() : nullptr);
// Check for isPassive error condition.
const char* sc2 = ex.getProperty("statusCode2");
if (sc2 && !strcmp(sc2, "urn:oasis:names:tc:SAML:2.0:status:NoPassive")) {
- validate = getBool("ignoreNoPassive", m_configNS.get()); // namespace-qualified if inside handler element
- if (validate.first && validate.second && !relayState.empty()) {
+ pair<bool,bool> ignore = getBool("ignoreNoPassive", m_configNS.get()); // namespace-qualified if inside handler element
+ if (ignore.first && ignore.second && !relayState.empty()) {
m_log.debug("ignoring SAML status of NoPassive and redirecting to resource...");
return make_pair(true, httpResponse.sendRedirect(relayState.c_str()));
}
const HTTPRequest& httpRequest,
HTTPResponse& httpResponse,
SecurityPolicy& policy,
- const PropertySet* settings,
+ const PropertySet*,
const XMLObject& xmlObject
) const;
const HTTPRequest& httpRequest,
HTTPResponse& httpResponse,
SecurityPolicy& policy,
- const PropertySet* settings,
+ const PropertySet*,
const XMLObject& xmlObject
) const
{
const HTTPRequest& httpRequest,
HTTPResponse& httpResponse,
SecurityPolicy& policy,
- const PropertySet* settings,
+ const PropertySet*,
const XMLObject& xmlObject
) const;
const HTTPRequest& httpRequest,
HTTPResponse& httpResponse,
SecurityPolicy& policy,
- const PropertySet* settings,
+ const PropertySet*,
const XMLObject& xmlObject
) const
{
--- /dev/null
+/*\r
+ * Copyright 2010 Internet2\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * XMLSecurityPolicyProvider.cpp\r
+ *\r
+ * XML-based security policy provider.\r
+ */\r
+\r
+#include "internal.h"\r
+#include "exceptions.h"\r
+#include "Application.h"\r
+#include "security/SecurityPolicy.h"\r
+#include "security/SecurityPolicyProvider.h"\r
+#include "util/DOMPropertySet.h"\r
+#include "util/SPConstants.h"\r
+\r
+#include <map>\r
+#include <saml/SAMLConfig.h>\r
+#include <saml/binding/SecurityPolicyRule.h>\r
+#include <xmltooling/io/HTTPResponse.h>\r
+#include <xmltooling/util/NDC.h>\r
+#include <xmltooling/util/ReloadableXMLFile.h>\r
+#include <xmltooling/util/Threads.h>\r
+#include <xmltooling/util/XMLHelper.h>\r
+#include <xercesc/util/XMLStringTokenizer.hpp>\r
+#include <xercesc/util/XMLUniDefs.hpp>\r
+\r
+using shibspconstants::SHIB2SPCONFIG_NS;\r
+using opensaml::SAMLConfig;\r
+using opensaml::SecurityPolicyRule;\r
+using namespace shibsp;\r
+using namespace xmltooling;\r
+using namespace std;\r
+\r
+namespace shibsp {\r
+\r
+#if defined (_MSC_VER)\r
+ #pragma warning( push )\r
+ #pragma warning( disable : 4250 )\r
+#endif\r
+\r
+ class SHIBSP_DLLLOCAL XMLSecurityPolicyProviderImpl\r
+ {\r
+ public:\r
+ XMLSecurityPolicyProviderImpl(const DOMElement* e, Category& log);\r
+ ~XMLSecurityPolicyProviderImpl() {\r
+ for (map< string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::iterator i = m_policyMap.begin(); i != m_policyMap.end(); ++i) {\r
+ delete i->second.first;\r
+ for_each(i->second.second.begin(), i->second.second.end(), xmltooling::cleanup<SecurityPolicyRule>());\r
+ }\r
+ if (m_document)\r
+ m_document->release();\r
+ }\r
+\r
+ void setDocument(DOMDocument* doc) {\r
+ m_document = doc;\r
+ }\r
+\r
+ private:\r
+ DOMDocument* m_document;\r
+ vector<xstring> m_whitelist,m_blacklist;\r
+ map< string,pair< PropertySet*,vector<const SecurityPolicyRule*> > > m_policyMap;\r
+\r
+ friend class SHIBSP_DLLLOCAL XMLSecurityPolicyProvider;\r
+ };\r
+\r
+ class XMLSecurityPolicyProvider : public SecurityPolicyProvider, public ReloadableXMLFile\r
+ {\r
+ public:\r
+ XMLSecurityPolicyProvider(const DOMElement* e)\r
+ : ReloadableXMLFile(e, Category::getInstance(SHIBSP_LOGCAT".SecurityPolicyProvider.XML")), m_impl(nullptr) {\r
+ background_load(); // guarantees an exception or the policy is loaded\r
+ }\r
+\r
+ ~XMLSecurityPolicyProvider() {\r
+ shutdown();\r
+ delete m_impl;\r
+ }\r
+\r
+ const PropertySet* getPolicySettings(const char* id) const {\r
+ map<string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::const_iterator i = m_impl->m_policyMap.find(id);\r
+ if (i != m_impl->m_policyMap.end())\r
+ return i->second.first;\r
+ throw ConfigurationException("Security Policy ($1) not found, check <SecurityPolicies> element.", params(1,id));\r
+ }\r
+\r
+ const vector<const SecurityPolicyRule*>& getPolicyRules(const char* id) const {\r
+ map<string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::const_iterator i = m_impl->m_policyMap.find(id);\r
+ if (i != m_impl->m_policyMap.end())\r
+ return i->second.second;\r
+ throw ConfigurationException("Security Policy ($1) not found, check <SecurityPolicies> element.", params(1,id));\r
+ }\r
+ const vector<xstring>& getAlgorithmBlacklist() const {\r
+ return m_impl->m_blacklist;\r
+ }\r
+ const vector<xstring>& getAlgorithmWhitelist() const {\r
+ return m_impl->m_whitelist;\r
+ }\r
+ \r
+ protected:\r
+ pair<bool,DOMElement*> load(bool backup);\r
+ pair<bool,DOMElement*> background_load();\r
+\r
+ private:\r
+ XMLSecurityPolicyProviderImpl* m_impl;\r
+ };\r
+\r
+#if defined (_MSC_VER)\r
+ #pragma warning( pop )\r
+#endif\r
+\r
+ SecurityPolicyProvider* SHIBSP_DLLLOCAL XMLSecurityPolicyProviderFactory(const DOMElement* const & e)\r
+ {\r
+ return new XMLSecurityPolicyProvider(e);\r
+ }\r
+\r
+ class SHIBSP_DLLLOCAL PolicyNodeFilter : public DOMNodeFilter\r
+ {\r
+ public:\r
+#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE\r
+ short\r
+#else\r
+ FilterAction\r
+#endif\r
+ acceptNode(const DOMNode* node) const {\r
+ return FILTER_REJECT;\r
+ }\r
+ };\r
+\r
+ static const XMLCh _id[] = UNICODE_LITERAL_2(i,d);\r
+ static const XMLCh _type[] = UNICODE_LITERAL_4(t,y,p,e);\r
+ static const XMLCh AlgorithmBlacklist[] = UNICODE_LITERAL_18(A,l,g,o,r,i,t,h,m,B,l,a,c,k,l,i,s,t);\r
+ static const XMLCh AlgorithmWhitelist[] = UNICODE_LITERAL_18(A,l,g,o,r,i,t,h,m,W,h,i,t,e,l,i,s,t);\r
+ static const XMLCh Policy[] = UNICODE_LITERAL_6(P,o,l,i,c,y);\r
+ static const XMLCh PolicyRule[] = UNICODE_LITERAL_10(P,o,l,i,c,y,R,u,l,e);\r
+ static const XMLCh Rule[] = UNICODE_LITERAL_4(R,u,l,e);\r
+ static const XMLCh SecurityPolicies[] = UNICODE_LITERAL_16(S,e,c,u,r,i,t,y,P,o,l,i,c,i,e,s);\r
+}\r
+\r
+void SHIBSP_API shibsp::registerSecurityPolicyProviders()\r
+{\r
+ SPConfig::getConfig().SecurityPolicyProviderManager.registerFactory(XML_SECURITYPOLICY_PROVIDER, XMLSecurityPolicyProviderFactory);\r
+}\r
+\r
+SecurityPolicyProvider::SecurityPolicyProvider()\r
+{\r
+}\r
+\r
+SecurityPolicyProvider::~SecurityPolicyProvider()\r
+{\r
+}\r
+\r
+opensaml::SecurityPolicy* SecurityPolicyProvider::createSecurityPolicy(\r
+ const Application& application, const xmltooling::QName* role, const char* policyId\r
+ ) const\r
+{\r
+ pair<bool,bool> validate = getPolicySettings(policyId ? policyId : application.getString("policyId").second)->getBool("validate");\r
+ return new SecurityPolicy(application, role, (validate.first && validate.second), policyId);\r
+}\r
+\r
+XMLSecurityPolicyProviderImpl::XMLSecurityPolicyProviderImpl(const DOMElement* e, Category& log) : m_document(nullptr)\r
+{\r
+#ifdef _DEBUG\r
+ xmltooling::NDC ndc("XMLSecurityPolicyProviderImpl");\r
+#endif\r
+\r
+ if (!XMLHelper::isNodeNamed(e, SHIB2SPCONFIG_NS, SecurityPolicies))\r
+ throw ConfigurationException("XML SecurityPolicyProvider requires conf:SecurityPolicies at root of configuration.");\r
+\r
+ const XMLCh* algs = nullptr;\r
+ const DOMElement* alglist = XMLHelper::getLastChildElement(e, AlgorithmBlacklist);\r
+ if (alglist && alglist->hasChildNodes()) {\r
+ algs = alglist->getFirstChild()->getNodeValue();\r
+ }\r
+ else if ((alglist = XMLHelper::getLastChildElement(e, AlgorithmWhitelist)) && alglist->hasChildNodes()) {\r
+ algs = alglist->getFirstChild()->getNodeValue();\r
+ }\r
+ if (algs) {\r
+ const XMLCh* token;\r
+ XMLStringTokenizer tokenizer(algs);\r
+ while (tokenizer.hasMoreTokens()) {\r
+ token = tokenizer.nextToken();\r
+ if (token) {\r
+ if (XMLString::equals(alglist->getLocalName(), AlgorithmBlacklist))\r
+ m_blacklist.push_back(token);\r
+ else\r
+ m_whitelist.push_back(token);\r
+ }\r
+ }\r
+ }\r
+\r
+ PolicyNodeFilter filter;\r
+ SAMLConfig& samlConf = SAMLConfig::getConfig();\r
+ e = XMLHelper::getFirstChildElement(e, Policy);\r
+ while (e) {\r
+ auto_ptr_char id(e->getAttributeNS(nullptr, _id));\r
+ pair< PropertySet*,vector<const SecurityPolicyRule*> >& rules = m_policyMap[id.get()];\r
+ rules.first = nullptr;\r
+ auto_ptr<DOMPropertySet> settings(new DOMPropertySet());\r
+ settings->load(e, nullptr, &filter);\r
+ rules.first = settings.release();\r
+\r
+ // Process PolicyRule elements.\r
+ const DOMElement* rule = XMLHelper::getFirstChildElement(e, PolicyRule);\r
+ while (rule) {\r
+ auto_ptr_char type(rule->getAttributeNS(nullptr, _type));\r
+ try {\r
+ rules.second.push_back(samlConf.SecurityPolicyRuleManager.newPlugin(type.get(), rule));\r
+ }\r
+ catch (exception& ex) {\r
+ log.crit("error instantiating policy rule (%s) in policy (%s): %s", type.get(), id.get(), ex.what());\r
+ }\r
+ rule = XMLHelper::getNextSiblingElement(rule, PolicyRule);\r
+ }\r
+\r
+ if (rules.second.size() == 0) {\r
+ // Process Rule elements.\r
+ log.warn("detected legacy Policy configuration, please convert to new PolicyRule syntax");\r
+ rule = XMLHelper::getFirstChildElement(e, Rule);\r
+ while (rule) {\r
+ auto_ptr_char type(rule->getAttributeNS(nullptr, _type));\r
+ try {\r
+ rules.second.push_back(samlConf.SecurityPolicyRuleManager.newPlugin(type.get(), rule));\r
+ }\r
+ catch (exception& ex) {\r
+ log.crit("error instantiating policy rule (%s) in policy (%s): %s", type.get(), id.get(), ex.what());\r
+ }\r
+ rule = XMLHelper::getNextSiblingElement(rule, Rule);\r
+ }\r
+\r
+ // Manually add a basic Conditions rule.\r
+ log.info("installing a default Conditions rule in policy (%s) for compatibility with legacy configuration", id.get());\r
+ rules.second.push_back(samlConf.SecurityPolicyRuleManager.newPlugin(CONDITIONS_POLICY_RULE, nullptr));\r
+ }\r
+\r
+ e = XMLHelper::getNextSiblingElement(e, Policy);\r
+ }\r
+}\r
+\r
+pair<bool,DOMElement*> XMLSecurityPolicyProvider::load(bool backup)\r
+{\r
+ // Load from source using base class.\r
+ pair<bool,DOMElement*> raw = ReloadableXMLFile::load(backup);\r
+\r
+ // If we own it, wrap it.\r
+ XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : nullptr);\r
+\r
+ XMLSecurityPolicyProviderImpl* impl = new XMLSecurityPolicyProviderImpl(raw.second, m_log);\r
+\r
+ // If we held the document, transfer it to the impl. If we didn't, it's a no-op.\r
+ impl->setDocument(docjanitor.release());\r
+\r
+ // Perform the swap inside a lock.\r
+ if (m_lock)\r
+ m_lock->wrlock();\r
+ SharedLock locker(m_lock, false);\r
+ delete m_impl;\r
+ m_impl = impl;\r
+\r
+\r
+ return make_pair(false,(DOMElement*)nullptr);\r
+}\r
+\r
+pair<bool,DOMElement*> XMLSecurityPolicyProvider::background_load()\r
+{\r
+ try {\r
+ return load(false);\r
+ }\r
+ catch (long& ex) {\r
+ if (ex == HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED)\r
+ m_log.info("remote resource (%s) unchanged", m_source.c_str());\r
+ if (!m_loaded && !m_backing.empty())\r
+ return load(true);\r
+ throw;\r
+ }\r
+ catch (exception&) {\r
+ if (!m_loaded && !m_backing.empty())\r
+ return load(true);\r
+ throw;\r
+ }\r
+}\r
# include "attribute/resolver/AttributeExtractor.h"
# include "attribute/resolver/AttributeResolver.h"
# include "security/PKIXTrustEngine.h"
+# include "security/SecurityPolicyProvider.h"
# include <saml/SAMLConfig.h>
# include <saml/version.h>
# include <saml/binding/ArtifactMap.h>
# include <saml/binding/SAMLArtifact.h>
-# include <saml/binding/SecurityPolicyRule.h>
# include <saml/saml1/core/Assertions.h>
# include <saml/saml2/core/Assertions.h>
# include <saml/saml2/binding/SAML2ArtifactType0004.h>
# include <xmltooling/security/TrustEngine.h>
# include <xmltooling/util/ReplayCache.h>
# include <xmltooling/util/StorageService.h>
-# include <xercesc/util/XMLStringTokenizer.hpp>
# include <xsec/utils/XSECPlatformUtils.hpp>
using namespace opensaml::saml2;
using namespace opensaml::saml2p;
RequestMapper* m_requestMapper;
map<string,Application*> m_appmap;
#ifndef SHIBSP_LITE
- map< string,pair< PropertySet*,vector<const SecurityPolicyRule*> > > m_policyMap;
+ SecurityPolicyProvider* m_policy;
vector< pair< string, pair<string,string> > > m_transportOptions;
#endif
#endif
}
+#ifndef SHIBSP_LITE
+ // Lockable
+ Lockable* lock() {
+ ReloadableXMLFile::lock();
+ if (m_impl->m_policy)
+ m_impl->m_policy->lock();
+ return this;
+ }
+ void unlock() {
+ if (m_impl->m_policy)
+ m_impl->m_policy->unlock();
+ ReloadableXMLFile::unlock();
+ }
+#endif
+
// PropertySet
const PropertySet* getParent() const { return m_impl->getParent(); }
void setParent(const PropertySet* parent) {return m_impl->setParent(parent);}
}
#ifndef SHIBSP_LITE
+ SecurityPolicyProvider* getSecurityPolicyProvider(bool required=true) const {
+ if (required && !m_impl->m_policy)
+ throw ConfigurationException("No SecurityPolicyProvider available.");
+ return m_impl->m_policy;
+ }
+
const PropertySet* getPolicySettings(const char* id) const {
- map<string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::const_iterator i = m_impl->m_policyMap.find(id);
- if (i!=m_impl->m_policyMap.end())
- return i->second.first;
- throw ConfigurationException("Security Policy ($1) not found, check <SecurityPolicies> element.", params(1,id));
+ return getSecurityPolicyProvider()->getPolicySettings(id);
}
const vector<const SecurityPolicyRule*>& getPolicyRules(const char* id) const {
- map<string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::const_iterator i = m_impl->m_policyMap.find(id);
- if (i!=m_impl->m_policyMap.end())
- return i->second.second;
- throw ConfigurationException("Security Policy ($1) not found, check <SecurityPolicies> element.", params(1,id));
+ return getSecurityPolicyProvider()->getPolicyRules(id);
}
bool setTransportOptions(SOAPTransport& transport) const {
#pragma warning( pop )
#endif
- static const XMLCh AlgorithmBlacklist[] = UNICODE_LITERAL_18(A,l,g,o,r,i,t,h,m,B,l,a,c,k,l,i,s,t);
- static const XMLCh AlgorithmWhitelist[] = UNICODE_LITERAL_18(A,l,g,o,r,i,t,h,m,W,h,i,t,e,l,i,s,t);
static const XMLCh ApplicationOverride[] = UNICODE_LITERAL_19(A,p,p,l,i,c,a,t,i,o,n,O,v,e,r,r,i,d,e);
static const XMLCh ApplicationDefaults[] = UNICODE_LITERAL_19(A,p,p,l,i,c,a,t,i,o,n,D,e,f,a,u,l,t,s);
static const XMLCh _ArtifactMap[] = UNICODE_LITERAL_11(A,r,t,i,f,a,c,t,M,a,p);
static const XMLCh _option[] = UNICODE_LITERAL_6(o,p,t,i,o,n);
static const XMLCh OutOfProcess[] = UNICODE_LITERAL_12(O,u,t,O,f,P,r,o,c,e,s,s);
static const XMLCh _path[] = UNICODE_LITERAL_4(p,a,t,h);
- static const XMLCh Policy[] = UNICODE_LITERAL_6(P,o,l,i,c,y);
- static const XMLCh PolicyRule[] = UNICODE_LITERAL_10(P,o,l,i,c,y,R,u,l,e);
static const XMLCh _provider[] = UNICODE_LITERAL_8(p,r,o,v,i,d,e,r);
static const XMLCh RelyingParty[] = UNICODE_LITERAL_12(R,e,l,y,i,n,g,P,a,r,t,y);
static const XMLCh _ReplayCache[] = UNICODE_LITERAL_11(R,e,p,l,a,y,C,a,c,h,e);
static const XMLCh _RequestMapper[] = UNICODE_LITERAL_13(R,e,q,u,e,s,t,M,a,p,p,e,r);
- static const XMLCh Rule[] = UNICODE_LITERAL_4(R,u,l,e);
static const XMLCh SecurityPolicies[] = UNICODE_LITERAL_16(S,e,c,u,r,i,t,y,P,o,l,i,c,i,e,s);
+ static const XMLCh SecurityPolicyProvider[] = UNICODE_LITERAL_22(S,e,c,u,r,i,t,y,P,o,l,i,c,y,P,r,o,v,i,d,e,r);
static const XMLCh _SessionCache[] = UNICODE_LITERAL_12(S,e,s,s,i,o,n,C,a,c,h,e);
static const XMLCh _SessionInitiator[] = UNICODE_LITERAL_16(S,e,s,s,i,o,n,I,n,i,t,i,a,t,o,r);
static const XMLCh _SingleLogoutService[] = UNICODE_LITERAL_19(S,i,n,g,l,e,L,o,g,o,u,t,S,e,r,v,i,c,e);
static const XMLCh _TrustEngine[] = UNICODE_LITERAL_11(T,r,u,s,t,E,n,g,i,n,e);
static const XMLCh _type[] = UNICODE_LITERAL_4(t,y,p,e);
static const XMLCh UnixListener[] = UNICODE_LITERAL_12(U,n,i,x,L,i,s,t,e,n,e,r);
-
-#ifndef SHIBSP_LITE
- class SHIBSP_DLLLOCAL PolicyNodeFilter : public DOMNodeFilter
- {
- public:
-#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE
- short
-#else
- FilterAction
-#endif
- acceptNode(const DOMNode* node) const {
- return FILTER_REJECT;
- }
- };
-#endif
};
namespace shibsp {
XMLString::equals(name,_RequestMapper) ||
XMLString::equals(name,_ReplayCache) ||
XMLString::equals(name,SecurityPolicies) ||
+ XMLString::equals(name,SecurityPolicyProvider) ||
XMLString::equals(name,_SessionCache) ||
XMLString::equals(name,Site) ||
XMLString::equals(name,_StorageService) ||
}
XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* outer, Category& log)
- : m_requestMapper(nullptr), m_outer(outer), m_document(nullptr)
+ : m_requestMapper(nullptr),
+#ifndef SHIBSP_LITE
+ m_policy(nullptr),
+#endif
+ m_outer(outer), m_document(nullptr)
{
#ifdef _DEBUG
xmltooling::NDC ndc("XMLConfigImpl");
// First load any property sets.
load(e,nullptr,this);
- const DOMElement* child;
+ DOMElement* child;
string plugtype;
// Much of the processing can only occur on the first instantiation.
throw ConfigurationException("Can't build SessionCache, missing conf:SessionCache element?");
}
}
-
-#ifndef SHIBSP_LITE
- child = XMLHelper::getLastChildElement(e, SecurityPolicies);
- if (child) {
- const XMLCh* algs = nullptr;
- const DOMElement* alglist = XMLHelper::getLastChildElement(child, AlgorithmBlacklist);
- if (alglist && alglist->hasChildNodes()) {
- algs = alglist->getFirstChild()->getNodeValue();
- }
- else if ((alglist = XMLHelper::getLastChildElement(child, AlgorithmWhitelist)) && alglist->hasChildNodes()) {
- algs = alglist->getFirstChild()->getNodeValue();
- }
- if (algs) {
-#ifdef SHIBSP_XMLSEC_WHITELISTING
- const XMLCh* token;
- XMLStringTokenizer tokenizer(algs);
- while (tokenizer.hasMoreTokens()) {
- token = tokenizer.nextToken();
- if (token) {
- if (XMLString::equals(alglist->getLocalName(), AlgorithmBlacklist))
- XSECPlatformUtils::blacklistAlgorithm(token);
- else
- XSECPlatformUtils::whitelistAlgorithm(token);
- }
- }
-#else
- log.fatal("XML-Security-C library prior to 1.6.0 does not support algorithm white/blacklists");
- throw ConfigurationException("XML-Security-C library prior to 1.6.0 does not support algorithm white/blacklists.");
-#endif
- }
- }
-#endif
} // end of first-time-only stuff
// Back to the fully dynamic stuff...next up is the RequestMapper.
if (conf.isEnabled(SPConfig::RequestMapping)) {
- child=XMLHelper::getFirstChildElement(e,_RequestMapper);
- if (child) {
+ if (child = XMLHelper::getFirstChildElement(e,_RequestMapper)) {
auto_ptr_char type(child->getAttributeNS(nullptr,_type));
log.info("building RequestMapper of type %s...",type.get());
m_requestMapper=conf.RequestMapperManager.newPlugin(type.get(),child);
#ifndef SHIBSP_LITE
// Load security policies.
- child = XMLHelper::getLastChildElement(e,SecurityPolicies);
- if (child) {
- PolicyNodeFilter filter;
- child = XMLHelper::getFirstChildElement(child,Policy);
- while (child) {
- auto_ptr_char id(child->getAttributeNS(nullptr,_id));
- pair< PropertySet*,vector<const SecurityPolicyRule*> >& rules = m_policyMap[id.get()];
- rules.first = nullptr;
- auto_ptr<DOMPropertySet> settings(new DOMPropertySet());
- settings->load(child, nullptr, &filter);
- rules.first = settings.release();
-
- // Process PolicyRule elements.
- const DOMElement* rule = XMLHelper::getFirstChildElement(child,PolicyRule);
- while (rule) {
- auto_ptr_char type(rule->getAttributeNS(nullptr,_type));
- try {
- rules.second.push_back(samlConf.SecurityPolicyRuleManager.newPlugin(type.get(),rule));
- }
- catch (exception& ex) {
- log.crit("error instantiating policy rule (%s) in policy (%s): %s", type.get(), id.get(), ex.what());
- }
- rule = XMLHelper::getNextSiblingElement(rule,PolicyRule);
- }
-
- if (rules.second.size() == 0) {
- // Process Rule elements.
- log.warn("detected legacy Policy configuration, please convert to new PolicyRule syntax");
- rule = XMLHelper::getFirstChildElement(child,Rule);
- while (rule) {
- auto_ptr_char type(rule->getAttributeNS(nullptr,_type));
- try {
- rules.second.push_back(samlConf.SecurityPolicyRuleManager.newPlugin(type.get(),rule));
- }
- catch (exception& ex) {
- log.crit("error instantiating policy rule (%s) in policy (%s): %s", type.get(), id.get(), ex.what());
- }
- rule = XMLHelper::getNextSiblingElement(rule,Rule);
- }
-
- // Manually add a basic Conditions rule.
- log.info("installing a default Conditions rule in policy (%s) for compatibility with legacy configuration", id.get());
- rules.second.push_back(samlConf.SecurityPolicyRuleManager.newPlugin(CONDITIONS_POLICY_RULE, nullptr));
- }
+ if (child = XMLHelper::getLastChildElement(e, SecurityPolicyProvider)) {
+ auto_ptr_char type(child->getAttributeNS(nullptr, _type));
+ log.info("building SecurityPolicyProvider of type %s...", type.get());
+ m_policy = conf.SecurityPolicyProviderManager.newPlugin(type.get(), child);
+ }
+ else if (child = XMLHelper::getLastChildElement(e, SecurityPolicies)) {
+ // For backward compatibility, wrap in a plugin element.
+ DOMElement* polwrapper = e->getOwnerDocument()->createElementNS(nullptr, SecurityPolicyProvider);
+ polwrapper->appendChild(child);
+ log.info("building SecurityPolicyProvider of type %s...", XML_SECURITYPOLICY_PROVIDER);
+ m_policy = conf.SecurityPolicyProviderManager.newPlugin(XML_SECURITYPOLICY_PROVIDER, polwrapper);
+ }
+ else {
+ log.fatal("can't build SecurityPolicyProvider, missing conf:SecurityPolicyProvider element?");
+ throw ConfigurationException("Can't build SecurityPolicyProvider, missing conf:SecurityPolicyProvider element?");
+ }
- child = XMLHelper::getNextSiblingElement(child,Policy);
+ if (first) {
+#ifdef SHIBSP_XMLSEC_WHITELISTING
+ vector<xstring>::const_iterator alg;
+ if (!m_policy->getAlgorithmBlacklist().empty()) {
+ for (alg = m_policy->getAlgorithmBlacklist().begin(); alg != m_policy->getAlgorithmBlacklist().end(); ++alg)
+ XSECPlatformUtils::blacklistAlgorithm(alg->c_str());
+ }
+ else if (!m_policy->getAlgorithmWhitelist().empty()) {
+ for (alg = m_policy->getAlgorithmWhitelist().begin(); alg != m_policy->getAlgorithmWhitelist().end(); ++alg)
+ XSECPlatformUtils::whitelistAlgorithm(alg->c_str());
}
+#else
+ log.fatal("XML-Security-C library prior to 1.6.0 does not support algorithm white/blacklists");
+ throw ConfigurationException("XML-Security-C library prior to 1.6.0 does not support algorithm white/blacklists.");
+#endif
}
// Process TransportOption elements.
for_each(m_appmap.begin(),m_appmap.end(),cleanup_pair<string,Application>());
m_appmap.clear();
#ifndef SHIBSP_LITE
- for (map< string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::iterator i=m_policyMap.begin(); i!=m_policyMap.end(); ++i) {
- delete i->second.first;
- for_each(i->second.second.begin(), i->second.second.end(), xmltooling::cleanup<SecurityPolicyRule>());
- }
- m_policyMap.clear();
+ delete m_policy;
+ m_policy = nullptr;
#endif
delete m_requestMapper;
m_requestMapper = nullptr;
--- /dev/null
+/*\r
+ * Copyright 2010 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * @file shibsp/security/SecurityPolicyProvider.h\r
+ * \r
+ * Interface to a source of security policy settings and rules.\r
+ */\r
+\r
+#ifndef __shibsp_policyfactory_h__\r
+#define __shibsp_policyfactory_h__\r
+\r
+#ifndef SHIBSP_LITE\r
+\r
+#include <shibsp/base.h>\r
+\r
+#include <vector>\r
+#include <xmltooling/Lockable.h>\r
+#include <xmltooling/unicode.h>\r
+\r
+namespace xmltooling {\r
+ class XMLTOOL_API QName;\r
+};\r
+\r
+namespace opensaml {\r
+ class SAML_API SecurityPolicy;\r
+ class SAML_API SecurityPolicyRule;\r
+};\r
+\r
+namespace shibsp {\r
+\r
+ class SHIBSP_API Application;\r
+ class SHIBSP_API PropertySet;\r
+\r
+ /**\r
+ * Interface to a source of security policy settings and rules.\r
+ */\r
+ class SHIBSP_API SecurityPolicyProvider : public virtual xmltooling::Lockable\r
+ {\r
+ MAKE_NONCOPYABLE(SecurityPolicyProvider);\r
+ protected:\r
+ SecurityPolicyProvider();\r
+ public:\r
+ virtual ~SecurityPolicyProvider();\r
+ \r
+ /**\r
+ * Returns the security policy settings for an identified policy.\r
+ *\r
+ * @param id identifies the policy to return\r
+ * @return a PropertySet\r
+ */\r
+ virtual const PropertySet* getPolicySettings(const char* id) const=0;\r
+\r
+ /**\r
+ * Returns the security policy rules for an identified policy.\r
+ *\r
+ * @param id identifies the policy to return\r
+ * @return an array of policy rules\r
+ */\r
+ virtual const std::vector<const opensaml::SecurityPolicyRule*>& getPolicyRules(const char* id) const=0;\r
+\r
+ /**\r
+ * Returns a set of XML Signature/Encryption algorithm identifiers to block.\r
+ *\r
+ * @return an array of algorithm URIs to block\r
+ */\r
+ virtual const std::vector<xmltooling::xstring>& getAlgorithmBlacklist() const=0;\r
+\r
+ /**\r
+ * Returns a set of XML Signature/Encryption algorithm identifiers to permit.\r
+ *\r
+ * @return an array of algorithm URIs to permit\r
+ */\r
+ virtual const std::vector<xmltooling::xstring>& getAlgorithmWhitelist() const=0;\r
+\r
+ /**\r
+ * Returns a SecurityPolicy applicable to an application and/or policy identifier.\r
+ *\r
+ * <p>The caller <strong>MUST</strong> lock the application's MetadataProvider for the life\r
+ * of the returned object.\r
+ *\r
+ * @param application reference to application applying policy\r
+ * @param role identifies the role (generally IdP or SP) of the policy peer\r
+ * @param policyId identifies policy, defaults to the application's default\r
+ * @return a new policy instance, which the caller is responsible for freeing\r
+ */\r
+ virtual opensaml::SecurityPolicy* createSecurityPolicy(\r
+ const Application& application, const xmltooling::QName* role, const char* policyId=nullptr\r
+ ) const;\r
+ };\r
+\r
+ /**\r
+ * Registers SecurityPolicyProvider classes into the runtime.\r
+ */\r
+ void SHIBSP_API registerSecurityPolicyProviders();\r
+\r
+ /** SecurityPolicyProvider based on an XML configuration format. */\r
+ #define XML_SECURITYPOLICY_PROVIDER "XML"\r
+};\r
+\r
+#endif\r
+\r
+#endif /* __shibsp_policyfactory_h__ */\r
<ItemGroup>\r
<ClCompile Include="AbstractSPRequest.cpp" />\r
<ClCompile Include="Application.cpp" />\r
+ <ClCompile Include="impl\XMLSecurityPolicyProvider.cpp" />\r
<ClCompile Include="ServiceProvider.cpp" />\r
<ClCompile Include="SPConfig.cpp" />\r
<ClCompile Include="util\CGIParser.cpp" />\r
<ClInclude Include="internal.h" />\r
<ClInclude Include="RequestMapper.h" />\r
<ClInclude Include="resource.h" />\r
+ <ClInclude Include="security\SecurityPolicyProvider.h" />\r
<ClInclude Include="ServiceProvider.h" />\r
<ClInclude Include="SessionCache.h" />\r
<ClInclude Include="SessionCacheEx.h" />\r
<ClCompile Include="handler\impl\WAYFSessionInitiator.cpp">\r
<Filter>Source Files\handler\impl</Filter>\r
</ClCompile>\r
+ <ClCompile Include="impl\XMLSecurityPolicyProvider.cpp">\r
+ <Filter>Source Files\impl</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="remoting\impl\SocketListener.h">\r
<ClInclude Include="metadata\MetadataProviderCriteria.h">\r
<Filter>Header Files\metadata</Filter>\r
</ClInclude>\r
+ <ClInclude Include="security\SecurityPolicyProvider.h">\r
+ <Filter>Header Files\security</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<ResourceCompile Include="shibsp.rc">\r