From b951e528ad7d0764ddc4ced037a8bd53bd3c9890 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Thu, 9 Nov 2006 05:44:14 +0000 Subject: [PATCH] Add TLS client auth rule. --- saml/Makefile.am | 2 + saml/binding/ClientCertAuthRule.h | 46 ++++++++++++ saml/binding/SecurityPolicyRule.h | 8 +++ saml/binding/SimpleSigningRule.h | 3 - saml/binding/XMLSigningRule.h | 3 - saml/binding/impl/ClientCertAuthRule.cpp | 117 +++++++++++++++++++++++++++++++ saml/binding/impl/SecurityPolicy.cpp | 2 + saml/binding/impl/SimpleSigningRule.cpp | 6 +- saml/binding/impl/XMLSigningRule.cpp | 7 +- saml/saml.vcproj | 8 +++ 10 files changed, 188 insertions(+), 14 deletions(-) create mode 100644 saml/binding/ClientCertAuthRule.h create mode 100644 saml/binding/impl/ClientCertAuthRule.cpp diff --git a/saml/Makefile.am b/saml/Makefile.am index e840ce5..f03cc16 100644 --- a/saml/Makefile.am +++ b/saml/Makefile.am @@ -33,6 +33,7 @@ libsamlinclude_HEADERS = \ samlbindinclude_HEADERS = \ binding/ArtifactMap.h \ + binding/ClientCertAuthRule.h \ binding/GenericRequest.h \ binding/GenericResponse.h \ binding/HTTPRequest.h \ @@ -106,6 +107,7 @@ noinst_HEADERS = \ libsaml_la_SOURCES = \ SAMLConfig.cpp \ binding/impl/ArtifactMap.cpp \ + binding/impl/ClientCertAuthRule.cpp \ binding/impl/MessageDecoder.cpp \ binding/impl/MessageEncoder.cpp \ binding/impl/MessageFlowRule.cpp \ diff --git a/saml/binding/ClientCertAuthRule.h b/saml/binding/ClientCertAuthRule.h new file mode 100644 index 0000000..287f0e4 --- /dev/null +++ b/saml/binding/ClientCertAuthRule.h @@ -0,0 +1,46 @@ +/* + * Copyright 2001-2006 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. + */ + +/** + * @file saml/binding/ClientCertAuthRule.h + * + * TLS client authentication SecurityPolicyRule + */ + +#include + + +namespace opensaml { + /** + * TLS client authentication SecurityPolicyRule + */ + class SAML_API ClientCertAuthRule : public SecurityPolicyRule + { + public: + ClientCertAuthRule(const DOMElement* e) {} + virtual ~ClientCertAuthRule() {} + + std::pair evaluate( + const GenericRequest& request, + const xmltooling::XMLObject& message, + const saml2md::MetadataProvider* metadataProvider, + const xmltooling::QName* role, + const TrustEngine* trustEngine, + const MessageExtractor& extractor + ) const; + }; + +}; diff --git a/saml/binding/SecurityPolicyRule.h b/saml/binding/SecurityPolicyRule.h index 9a1b49f..14e0352 100644 --- a/saml/binding/SecurityPolicyRule.h +++ b/saml/binding/SecurityPolicyRule.h @@ -103,6 +103,14 @@ namespace opensaml { void SAML_API registerSecurityPolicyRules(); /** + * SecurityPolicyRule for TLS client certificate authentication. + * + * Requires that messages carry information about the issuer, and then + * evaluates the claimed certificates against the issuer's metadata. + */ + #define CLIENTCERTAUTH_POLICY_RULE "org.opensaml.binding.ClientCertAuthRule" + + /** * SecurityPolicyRule for replay detection and freshness checking. * *

A ReplayCache instance must be available from the runtime, unless diff --git a/saml/binding/SimpleSigningRule.h b/saml/binding/SimpleSigningRule.h index a4d79e2..e0488c0 100644 --- a/saml/binding/SimpleSigningRule.h +++ b/saml/binding/SimpleSigningRule.h @@ -27,9 +27,6 @@ namespace opensaml { /** * Blob-oriented signature checking SecurityPolicyRule for * bindings that support non-XML signature techniques. - * - * Subclasses can provide support for additional message types - * by overriding the issuer derivation method. */ class SAML_API SimpleSigningRule : public SecurityPolicyRule { diff --git a/saml/binding/XMLSigningRule.h b/saml/binding/XMLSigningRule.h index 29816b7..2b01d39 100644 --- a/saml/binding/XMLSigningRule.h +++ b/saml/binding/XMLSigningRule.h @@ -26,9 +26,6 @@ namespace opensaml { /** * XML Signature checking SecurityPolicyRule - * - * Subclasses can provide support for additional message types - * by overriding the issuer derivation method. */ class SAML_API XMLSigningRule : public SecurityPolicyRule { diff --git a/saml/binding/impl/ClientCertAuthRule.cpp b/saml/binding/impl/ClientCertAuthRule.cpp new file mode 100644 index 0000000..63a6bb1 --- /dev/null +++ b/saml/binding/impl/ClientCertAuthRule.cpp @@ -0,0 +1,117 @@ +/* + * Copyright 2001-2006 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. + */ + +/** + * ClientCertAuthRule.cpp + * + * XML Signature checking SecurityPolicyRule + */ + +#include "internal.h" +#include "exceptions.h" +#include "binding/ClientCertAuthRule.h" +#include "saml2/metadata/Metadata.h" +#include "saml2/metadata/MetadataProvider.h" +#include "security/X509TrustEngine.h" + +#include +#include +#include + +using namespace opensaml::saml2md; +using namespace opensaml; +using namespace xmltooling; +using namespace log4cpp; +using namespace std; + +namespace opensaml { + SecurityPolicyRule* SAML_DLLLOCAL ClientCertAuthRuleFactory(const DOMElement* const & e) + { + return new ClientCertAuthRule(e); + } +}; + +pair ClientCertAuthRule::evaluate( + const GenericRequest& request, + const XMLObject& message, + const MetadataProvider* metadataProvider, + const QName* role, + const opensaml::TrustEngine* trustEngine, + const MessageExtractor& extractor + ) const +{ + Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.ClientCertAuth"); + log.debug("evaluating client certificate authentication policy"); + + pair ret = pair(NULL,NULL); + + const opensaml::X509TrustEngine* x509trust; + if (!metadataProvider || !role || !(x509trust=dynamic_cast(trustEngine))) { + log.debug("ignoring message, no metadata or X509TrustEngine supplied"); + return ret; + } + + const std::vector& chain = request.getClientCertificates(); + if (chain.empty()) { + log.debug("ignoring message, no client certificates in request"); + return ret; + } + + try { + log.debug("extracting issuer from message"); + pair issuerInfo = extractor.getIssuerAndProtocol(message); + + auto_ptr issuer(issuerInfo.first); + if (!issuerInfo.first || !issuerInfo.second || + (issuer->getFormat() && !XMLString::equals(issuer->getFormat(), saml2::NameIDType::ENTITY))) { + log.warn("issuer identity not estabished, or was not an entityID"); + return ret; + } + + log.debug("searching metadata for message issuer..."); + const EntityDescriptor* entity = metadataProvider->getEntityDescriptor(issuer->getName()); + if (!entity) { + auto_ptr_char temp(issuer->getName()); + log.warn("no metadata found, can't establish identity of issuer (%s)", temp.get()); + return ret; + } + + log.debug("matched message issuer against metadata, searching for applicable role..."); + const RoleDescriptor* roledesc=entity->getRoleDescriptor(*role, issuerInfo.second); + if (!roledesc) { + log.warn("unable to find compatible role (%s) in metadata", role->toString().c_str()); + return ret; + } + + if (!x509trust->validate(chain.front(), chain, *roledesc, true, metadataProvider->getKeyResolver())) { + log.error("unable to verify certificate chain with supplied trust engine"); + return ret; + } + + if (log.isDebugEnabled()) { + auto_ptr_char iname(entity->getEntityID()); + log.debug("message from (%s), signature verified", iname.get()); + } + + ret.first = issuer.release(); + ret.second = roledesc; + } + catch (bad_cast&) { + // Just trap it. + log.warn("caught a bad_cast while extracting issuer"); + } + return ret; +} diff --git a/saml/binding/impl/SecurityPolicy.cpp b/saml/binding/impl/SecurityPolicy.cpp index 2edad23..89aad2d 100644 --- a/saml/binding/impl/SecurityPolicy.cpp +++ b/saml/binding/impl/SecurityPolicy.cpp @@ -35,6 +35,7 @@ using namespace xmltooling; using namespace std; namespace opensaml { + SAML_DLLLOCAL PluginManager::Factory ClientCertAuthRuleFactory; SAML_DLLLOCAL PluginManager::Factory MessageFlowRuleFactory; SAML_DLLLOCAL PluginManager::Factory SimpleSigningRuleFactory; SAML_DLLLOCAL PluginManager::Factory XMLSigningRuleFactory; @@ -43,6 +44,7 @@ namespace opensaml { void SAML_API opensaml::registerSecurityPolicyRules() { SAMLConfig& conf=SAMLConfig::getConfig(); + conf.SecurityPolicyRuleManager.registerFactory(CLIENTCERTAUTH_POLICY_RULE, ClientCertAuthRuleFactory); conf.SecurityPolicyRuleManager.registerFactory(MESSAGEFLOW_POLICY_RULE, MessageFlowRuleFactory); conf.SecurityPolicyRuleManager.registerFactory(SIMPLESIGNING_POLICY_RULE, SimpleSigningRuleFactory); conf.SecurityPolicyRuleManager.registerFactory(XMLSIGNING_POLICY_RULE, XMLSigningRuleFactory); diff --git a/saml/binding/impl/SimpleSigningRule.cpp b/saml/binding/impl/SimpleSigningRule.cpp index 44c6e9c..6ba58f8 100644 --- a/saml/binding/impl/SimpleSigningRule.cpp +++ b/saml/binding/impl/SimpleSigningRule.cpp @@ -22,10 +22,8 @@ #include "internal.h" #include "exceptions.h" -#include "RootObject.h" #include "binding/HTTPRequest.h" #include "binding/SimpleSigningRule.h" -#include "saml2/core/Protocols.h" #include "saml2/metadata/Metadata.h" #include "saml2/metadata/MetadataProvider.h" #include "security/TrustEngine.h" @@ -69,7 +67,7 @@ namespace opensaml { }; -pair SimpleSigningRule::evaluate( +pair SimpleSigningRule::evaluate( const GenericRequest& request, const XMLObject& message, const MetadataProvider* metadataProvider, @@ -119,7 +117,7 @@ pair SimpleSigningRule::evaluate( return ret; } - log.debug("matched assertion issuer against metadata, searching for applicable role..."); + log.debug("matched message issuer against metadata, searching for applicable role..."); const RoleDescriptor* roledesc=entity->getRoleDescriptor(*role, issuerInfo.second); if (!roledesc) { log.warn("unable to find compatible role (%s) in metadata", role->toString().c_str()); diff --git a/saml/binding/impl/XMLSigningRule.cpp b/saml/binding/impl/XMLSigningRule.cpp index a63c18c..552cef8 100644 --- a/saml/binding/impl/XMLSigningRule.cpp +++ b/saml/binding/impl/XMLSigningRule.cpp @@ -22,9 +22,8 @@ #include "internal.h" #include "exceptions.h" -#include "RootObject.h" #include "binding/XMLSigningRule.h" -#include "saml2/core/Protocols.h" +#include "saml2/core/Assertions.h" #include "saml2/metadata/Metadata.h" #include "saml2/metadata/MetadataProvider.h" #include "security/TrustEngine.h" @@ -46,7 +45,7 @@ namespace opensaml { } }; -pair XMLSigningRule::evaluate( +pair XMLSigningRule::evaluate( const GenericRequest& request, const XMLObject& message, const MetadataProvider* metadataProvider, @@ -90,7 +89,7 @@ pair XMLSigningRule::evaluate( return ret; } - log.debug("matched assertion issuer against metadata, searching for applicable role..."); + log.debug("matched message issuer against metadata, searching for applicable role..."); const RoleDescriptor* roledesc=entity->getRoleDescriptor(*role, issuerInfo.second); if (!roledesc) { log.warn("unable to find compatible role (%s) in metadata", role->toString().c_str()); diff --git a/saml/saml.vcproj b/saml/saml.vcproj index d6ca290..2a461bf 100644 --- a/saml/saml.vcproj +++ b/saml/saml.vcproj @@ -474,6 +474,10 @@ > + + @@ -773,6 +777,10 @@ > + + -- 2.1.4