const xmltooling::XMLObject& message,
const saml2md::MetadataProvider* metadataProvider,
const xmltooling::QName* role,
- const TrustEngine* trustEngine,
- const MessageExtractor& extractor
+ const TrustEngine* trustEngine
) const;
+
+ protected:
+ /**
+ * Examines the message and/or its contents and extracts the issuer's claimed
+ * identity along with a protocol identifier. The two together can be used to
+ * locate metadata to use in validating the signature. Conventions may be needed
+ * to properly encode non-SAML2 issuer information into a compatible form.
+ *
+ * <p>The caller is responsible for freeing the Issuer object.
+ *
+ * @param message message to examine
+ * @return a pair consisting of a SAML 2.0 Issuer object and a protocol constant.
+ */
+ virtual std::pair<saml2::Issuer*,const XMLCh*> getIssuerAndProtocol(const xmltooling::XMLObject& message) const;
};
-
};
const xmltooling::XMLObject& message,
const saml2md::MetadataProvider* metadataProvider,
const xmltooling::QName* role,
- const TrustEngine* trustEngine,
- const MessageExtractor& extractor
+ const TrustEngine* trustEngine
) const;
/**
const saml2md::MetadataProvider* metadataProvider=NULL,
const xmltooling::QName* role=NULL,
const TrustEngine* trustEngine=NULL
- ) : m_issuer(NULL), m_issuerRole(NULL), m_matchingPolicy(NULL), m_extractor(NULL),
- m_metadata(metadataProvider), m_role(role ? *role : xmltooling::QName()), m_trust(trustEngine) {
+ ) : m_issuer(NULL), m_issuerRole(NULL), m_matchingPolicy(NULL), m_metadata(metadataProvider),
+ m_role(role ? *role : xmltooling::QName()), m_trust(trustEngine) {
}
/**
const saml2md::MetadataProvider* metadataProvider=NULL,
const xmltooling::QName* role=NULL,
const TrustEngine* trustEngine=NULL
- ) : m_issuer(NULL), m_issuerRole(NULL), m_matchingPolicy(NULL), m_extractor(NULL), m_rules(rules),
- m_metadata(metadataProvider), m_role(role ? *role : xmltooling::QName()), m_trust(trustEngine) {
+ ) : m_issuer(NULL), m_issuerRole(NULL), m_matchingPolicy(NULL), m_rules(rules), m_metadata(metadataProvider),
+ m_role(role ? *role : xmltooling::QName()), m_trust(trustEngine) {
}
virtual ~SecurityPolicy();
m_matchingPolicy = matchingPolicy;
}
- /**
- * Returns the MessageExtractor in effect.
- *
- * @return the effective MessageExtractor
- */
- const SecurityPolicyRule::MessageExtractor& getMessageExtractor() const {
- return m_extractor ? *m_extractor : m_defaultExtractor;
- }
-
- /**
- * Sets the MessageExtractor in effect. Setting no extractor will
- * cause the default extractor to be used.
- *
- * <p>The extractor will be freed by the SecurityPolicy.
- *
- * @param extractor the MessageExtractor to use
- */
- void setMessageExtractor(SecurityPolicyRule::MessageExtractor* extractor) {
- delete m_extractor;
- m_extractor = extractor;
- }
-
protected:
/** A shared matching object that just supports the default matching rules. */
static IssuerMatchingPolicy m_defaultMatching;
- /** A shared extractor object that just supports the default SAML message types. */
- static SecurityPolicyRule::MessageExtractor m_defaultExtractor;
-
private:
saml2::Issuer* m_issuer;
const saml2md::RoleDescriptor* m_issuerRole;
IssuerMatchingPolicy* m_matchingPolicy;
- SecurityPolicyRule::MessageExtractor* m_extractor;
-
std::vector<const SecurityPolicyRule*> m_rules;
const saml2md::MetadataProvider* m_metadata;
xmltooling::QName m_role;
public:
virtual ~SecurityPolicyRule() {}
- /** Allows override of code for extracting saml2:Issuer and protocol information. */
- class SAML_API MessageExtractor {
- MAKE_NONCOPYABLE(MessageExtractor);
- public:
- MessageExtractor() {}
- virtual ~MessageExtractor() {}
-
- /**
- * Examines the message and/or its contents and extracts the issuer's claimed
- * identity along with a protocol identifier. Conventions may be needed
- * to properly encode non-SAML2 issuer information into a compatible form.
- *
- * <p>The caller is responsible for freeing the Issuer object.
- *
- * @param message message to examine
- * @return a pair consisting of a SAML 2.0 Issuer object and a protocol constant.
- * @throws std::bad_cast thrown if the message is not of an expected type
- */
- virtual std::pair<saml2::Issuer*,const XMLCh*> getIssuerAndProtocol(const xmltooling::XMLObject& message) const;
- };
-
/**
* Evaluates the rule against the given request and message. If an Issuer is
* returned, the caller is responsible for freeing the Issuer object.
const xmltooling::XMLObject& message,
const saml2md::MetadataProvider* metadataProvider,
const xmltooling::QName* role,
- const TrustEngine* trustEngine,
- const MessageExtractor& extractor
+ const TrustEngine* trustEngine
) const=0;
};
/**
* 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
{
const xmltooling::XMLObject& message,
const saml2md::MetadataProvider* metadataProvider,
const xmltooling::QName* role,
- const TrustEngine* trustEngine,
- const MessageExtractor& extractor
+ const TrustEngine* trustEngine
) const;
+
+ protected:
+ /**
+ * Examines the message and/or its contents and extracts the issuer's claimed
+ * identity along with a protocol identifier. The two together can be used to
+ * locate metadata to use in validating the signature. Conventions may be needed
+ * to properly encode non-SAML2 issuer information into a compatible form.
+ *
+ * <p>The caller is responsible for freeing the Issuer object.
+ *
+ * @param message message to examine
+ * @return a pair consisting of a SAML 2.0 Issuer object and a protocol constant.
+ */
+ virtual std::pair<saml2::Issuer*,const XMLCh*> getIssuerAndProtocol(const xmltooling::XMLObject& message) const;
};
};
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
{
const xmltooling::XMLObject& message,
const saml2md::MetadataProvider* metadataProvider,
const xmltooling::QName* role,
- const TrustEngine* trustEngine,
- const MessageExtractor& extractor
+ const TrustEngine* trustEngine
) const;
+
+ protected:
+ /**
+ * Examines the message and/or its contents and extracts the issuer's claimed
+ * identity along with a protocol identifier. The two together can be used to
+ * locate metadata to use in validating the signature. Conventions may be needed
+ * to properly encode non-SAML2 issuer information into a compatible form.
+ *
+ * <p>The caller is responsible for freeing the Issuer object.
+ *
+ * @param message message to examine
+ * @return a pair consisting of a SAML 2.0 Issuer object and a protocol constant.
+ */
+ virtual std::pair<saml2::Issuer*,const XMLCh*> getIssuerAndProtocol(const xmltooling::XMLObject& message) const;
};
};
const XMLObject& message,
const MetadataProvider* metadataProvider,
const QName* role,
- const opensaml::TrustEngine* trustEngine,
- const MessageExtractor& extractor
+ const opensaml::TrustEngine* trustEngine
) const
{
Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.ClientCertAuth");
try {
log.debug("extracting issuer from message");
- pair<saml2::Issuer*,const XMLCh*> issuerInfo = extractor.getIssuerAndProtocol(message);
+ pair<saml2::Issuer*,const XMLCh*> issuerInfo = getIssuerAndProtocol(message);
auto_ptr<saml2::Issuer> issuer(issuerInfo.first);
if (!issuerInfo.first || !issuerInfo.second ||
}
return ret;
}
+
+pair<saml2::Issuer*,const XMLCh*> ClientCertAuthRule::getIssuerAndProtocol(const XMLObject& message) const
+{
+ // We just let any bad casts throw here.
+
+ // Shortcuts some of the casting.
+ const XMLCh* ns = message.getElementQName().getNamespaceURI();
+ if (ns) {
+ if (XMLString::equals(ns, samlconstants::SAML20P_NS)) {
+ // 2.0 namespace should be castable to a specialized 2.0 root.
+ const saml2::RootObject& root = dynamic_cast<const saml2::RootObject&>(message);
+ saml2::Issuer* issuer = root.getIssuer();
+ if (issuer && issuer->getName())
+ return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS);
+ }
+ }
+ return pair<saml2::Issuer*,const XMLCh*>(NULL,NULL);
+}
namespace saml1p {
SAML_DLLLOCAL PluginManager<MessageDecoder,const DOMElement*>::Factory SAML1ArtifactDecoderFactory;
SAML_DLLLOCAL PluginManager<MessageDecoder,const DOMElement*>::Factory SAML1POSTDecoderFactory;
+ SAML_DLLLOCAL PluginManager<MessageDecoder,const DOMElement*>::Factory SAML1SOAPDecoderFactory;
};
namespace saml2p {
SAMLConfig& conf=SAMLConfig::getConfig();
conf.MessageDecoderManager.registerFactory(samlconstants::SAML1_PROFILE_BROWSER_ARTIFACT, saml1p::SAML1ArtifactDecoderFactory);
conf.MessageDecoderManager.registerFactory(samlconstants::SAML1_PROFILE_BROWSER_POST, saml1p::SAML1POSTDecoderFactory);
+ conf.MessageDecoderManager.registerFactory(samlconstants::SAML1_BINDING_SOAP, saml1p::SAML1SOAPDecoderFactory);
conf.MessageDecoderManager.registerFactory(samlconstants::SAML20_BINDING_HTTP_ARTIFACT, saml2p::SAML2ArtifactDecoderFactory);
conf.MessageDecoderManager.registerFactory(samlconstants::SAML20_BINDING_HTTP_POST, saml2p::SAML2POSTDecoderFactory);
conf.MessageDecoderManager.registerFactory(samlconstants::SAML20_BINDING_HTTP_POST_SIMPLESIGN, saml2p::SAML2POSTDecoderFactory);
#include "exceptions.h"
#include "RootObject.h"
#include "binding/MessageFlowRule.h"
+#include "util/SAMLConstants.h"
#include <xmltooling/util/NDC.h>
#include <xmltooling/util/ReplayCache.h>
const XMLObject& message,
const saml2md::MetadataProvider* metadataProvider,
const QName* role,
- const opensaml::TrustEngine* trustEngine,
- const MessageExtractor& extractor
+ const opensaml::TrustEngine* trustEngine
) const
{
+ Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.MessageFlow");
+ log.debug("evaluating message flow policy");
+
try {
- const RootObject& obj = dynamic_cast<const RootObject&>(message);
- check(obj.getID(), obj.getIssueInstantEpoch());
+ const XMLCh* ns = message.getElementQName().getNamespaceURI();
+ if (ns && (XMLString::equals(ns, samlconstants::SAML20P_NS) || XMLString::equals(ns, samlconstants::SAML1P_NS))) {
+ const RootObject& obj = dynamic_cast<const RootObject&>(message);
+ check(obj.getID(), obj.getIssueInstantEpoch());
+ }
+ else {
+ log.debug("ignoring unrecognized message type");
+ }
}
catch (bad_cast&) {
- throw BindingException("Message was not of a recognized type.");
+ log.warn("caught a bad_cast while extracting issuer");
}
return pair<saml2::Issuer*,const saml2md::RoleDescriptor*>(NULL,NULL);
}
SecurityPolicy::IssuerMatchingPolicy SecurityPolicy::m_defaultMatching;
-SecurityPolicyRule::MessageExtractor SecurityPolicy::m_defaultExtractor;
-
SecurityPolicy::~SecurityPolicy()
{
- delete m_extractor;
delete m_matchingPolicy;
delete m_issuer;
}
for (vector<const SecurityPolicyRule*>::const_iterator i=m_rules.begin(); i!=m_rules.end(); ++i) {
// Run the rule...
- pair<Issuer*,const RoleDescriptor*> ident =
- (*i)->evaluate(request,message,m_metadata,&m_role,m_trust,getMessageExtractor());
+ pair<Issuer*,const RoleDescriptor*> ident = (*i)->evaluate(request,message,m_metadata,&m_role,m_trust);
// Make sure returned issuer doesn't conflict.
return true;
}
-
-
-pair<saml2::Issuer*,const XMLCh*> SecurityPolicyRule::MessageExtractor::getIssuerAndProtocol(const XMLObject& message) const
-{
- // We just let any bad casts throw here.
-
- saml2::Issuer* issuer;
-
- // Shortcuts some of the casting.
- const XMLCh* ns = message.getElementQName().getNamespaceURI();
- if (ns) {
- if (XMLString::equals(ns, samlconstants::SAML20P_NS) || XMLString::equals(ns, samlconstants::SAML20_NS)) {
- // 2.0 namespace should be castable to a specialized 2.0 root.
- const saml2::RootObject& root = dynamic_cast<const saml2::RootObject&>(message);
- issuer = root.getIssuer();
- if (issuer && issuer->getName()) {
- return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS);
- }
-
- // No issuer in the message, so we have to try the Response approach.
- const vector<saml2::Assertion*>& assertions = dynamic_cast<const saml2p::Response&>(message).getAssertions();
- if (!assertions.empty()) {
- issuer = assertions.front()->getIssuer();
- if (issuer && issuer->getName())
- return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS);
- }
- }
- else if (XMLString::equals(ns, samlconstants::SAML1P_NS)) {
- // Should be a samlp:Response, at least in OpenSAML.
- const vector<saml1::Assertion*>& assertions = dynamic_cast<const saml1p::Response&>(message).getAssertions();
- if (!assertions.empty()) {
- const saml1::Assertion* a = assertions.front();
- if (a->getIssuer()) {
- issuer = saml2::IssuerBuilder::buildIssuer();
- issuer->setName(a->getIssuer());
- pair<bool,int> minor = a->getMinorVersion();
- return make_pair(
- issuer,
- (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM
- );
- }
- }
- }
- else if (XMLString::equals(ns, samlconstants::SAML1_NS)) {
- // Should be a saml:Assertion.
- const saml1::Assertion& a = dynamic_cast<const saml1::Assertion&>(message);
- if (a.getIssuer()) {
- issuer = saml2::IssuerBuilder::buildIssuer();
- issuer->setName(a.getIssuer());
- pair<bool,int> minor = a.getMinorVersion();
- return make_pair(
- issuer,
- (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM
- );
- }
- }
- }
- return pair<saml2::Issuer*,const XMLCh*>(NULL,NULL);
-}
#include "exceptions.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"
const XMLObject& message,
const MetadataProvider* metadataProvider,
const QName* role,
- const opensaml::TrustEngine* trustEngine,
- const MessageExtractor& extractor
+ const opensaml::TrustEngine* trustEngine
) const
{
Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.SimpleSigning");
try {
log.debug("extracting issuer from message");
- pair<saml2::Issuer*,const XMLCh*> issuerInfo = extractor.getIssuerAndProtocol(message);
+ pair<saml2::Issuer*,const XMLCh*> issuerInfo = getIssuerAndProtocol(message);
auto_ptr<saml2::Issuer> issuer(issuerInfo.first);
if (!issuerInfo.first || !issuerInfo.second ||
}
return ret;
}
+
+pair<saml2::Issuer*,const XMLCh*> SimpleSigningRule::getIssuerAndProtocol(const XMLObject& message) const
+{
+ // We just let any bad casts throw here.
+
+ // Shortcuts some of the casting.
+ const XMLCh* ns = message.getElementQName().getNamespaceURI();
+ if (ns) {
+ if (XMLString::equals(ns, samlconstants::SAML20P_NS)) {
+ // 2.0 namespace should be castable to a specialized 2.0 root.
+ const saml2::RootObject& root = dynamic_cast<const saml2::RootObject&>(message);
+ saml2::Issuer* issuer = root.getIssuer();
+ if (issuer && issuer->getName())
+ return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS);
+
+ // No issuer in the message, so we have to try the Response approach.
+ const vector<saml2::Assertion*>& assertions = dynamic_cast<const saml2p::Response&>(message).getAssertions();
+ if (!assertions.empty()) {
+ issuer = assertions.front()->getIssuer();
+ if (issuer && issuer->getName())
+ return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS);
+ }
+ }
+ }
+ return pair<saml2::Issuer*,const XMLCh*>(NULL,NULL);
+}
#include "internal.h"
#include "exceptions.h"
#include "binding/XMLSigningRule.h"
-#include "saml2/core/Assertions.h"
+#include "saml1/core/Assertions.h"
+#include "saml1/core/Protocols.h"
+#include "saml2/core/Protocols.h"
#include "saml2/metadata/Metadata.h"
#include "saml2/metadata/MetadataProvider.h"
#include "security/TrustEngine.h"
const XMLObject& message,
const MetadataProvider* metadataProvider,
const QName* role,
- const opensaml::TrustEngine* trustEngine,
- const MessageExtractor& extractor
+ const opensaml::TrustEngine* trustEngine
) const
{
Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.XMLSigning");
}
try {
- const RootObject& root = dynamic_cast<const RootObject&>(message);
- if (!root.getSignature()) {
- log.debug("ignoring unsigned message");
+ const SignableObject* signable = dynamic_cast<const SignableObject*>(&message);
+ if (!signable || !signable->getSignature()) {
+ log.debug("ignoring unsigned or unrecognized message");
return ret;
}
log.debug("extracting issuer from message");
- pair<saml2::Issuer*,const XMLCh*> issuerInfo = extractor.getIssuerAndProtocol(message);
+ pair<saml2::Issuer*,const XMLCh*> issuerInfo = getIssuerAndProtocol(message);
auto_ptr<saml2::Issuer> issuer(issuerInfo.first);
if (!issuerInfo.first || !issuerInfo.second ||
return ret;
}
- if (!trustEngine->validate(*(root.getSignature()), *roledesc, metadataProvider->getKeyResolver())) {
+ if (!trustEngine->validate(*(signable->getSignature()), *roledesc, metadataProvider->getKeyResolver())) {
log.error("unable to verify signature on message with supplied trust engine");
return ret;
}
}
return ret;
}
+
+pair<saml2::Issuer*,const XMLCh*> XMLSigningRule::getIssuerAndProtocol(const XMLObject& message) const
+{
+ // We just let any bad casts throw here.
+
+ saml2::Issuer* issuer;
+
+ // Shortcuts some of the casting.
+ const XMLCh* ns = message.getElementQName().getNamespaceURI();
+ if (ns) {
+ if (XMLString::equals(ns, samlconstants::SAML20P_NS) || XMLString::equals(ns, samlconstants::SAML20_NS)) {
+ // 2.0 namespace should be castable to a specialized 2.0 root.
+ const saml2::RootObject& root = dynamic_cast<const saml2::RootObject&>(message);
+ issuer = root.getIssuer();
+ if (issuer && issuer->getName()) {
+ return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS);
+ }
+
+ // No issuer in the message, so we have to try the Response approach.
+ const vector<saml2::Assertion*>& assertions = dynamic_cast<const saml2p::Response&>(message).getAssertions();
+ if (!assertions.empty()) {
+ issuer = assertions.front()->getIssuer();
+ if (issuer && issuer->getName())
+ return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS);
+ }
+ }
+ else if (XMLString::equals(ns, samlconstants::SAML1P_NS)) {
+ // Should be a samlp:Response, at least in OpenSAML.
+ const vector<saml1::Assertion*>& assertions = dynamic_cast<const saml1p::Response&>(message).getAssertions();
+ if (!assertions.empty()) {
+ const saml1::Assertion* a = assertions.front();
+ if (a->getIssuer()) {
+ issuer = saml2::IssuerBuilder::buildIssuer();
+ issuer->setName(a->getIssuer());
+ pair<bool,int> minor = a->getMinorVersion();
+ return make_pair(
+ issuer,
+ (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM
+ );
+ }
+ }
+ }
+ }
+ return pair<saml2::Issuer*,const XMLCh*>(NULL,NULL);
+}