const xmltooling::XMLObject& message,
const saml2md::MetadataProvider* metadataProvider,
const xmltooling::QName* role,
- const TrustEngine* trustEngine
+ const TrustEngine* trustEngine,
+ const MessageExtractor& extractor
) 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_metadata(metadataProvider),
- m_role(role ? *role : xmltooling::QName()), m_trust(trustEngine) {
+ ) : m_issuer(NULL), m_issuerRole(NULL), m_matchingPolicy(NULL), m_extractor(NULL),
+ m_metadata(metadataProvider), m_role(role ? *role : xmltooling::QName()), m_trust(trustEngine) {
}
/**
- * Constructor for policy using existing rules.
+ * Constructor for policy using existing rules. The lifetime of the policy rules
+ * must be at least as long as the policy object.
*
* @param rules reference to array of policy rules to use
* @param metadataProvider locked MetadataProvider instance
const saml2md::MetadataProvider* metadataProvider=NULL,
const xmltooling::QName* role=NULL,
const TrustEngine* trustEngine=NULL
- ) : m_issuer(NULL), m_issuerRole(NULL), m_matchingPolicy(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_extractor(NULL), m_rules(rules),
+ m_metadata(metadataProvider), m_role(role ? *role : xmltooling::QName()), m_trust(trustEngine) {
}
virtual ~SecurityPolicy();
}
/**
+ * Adds a SecurityPolicyRule to the policy. The lifetime of the policy rule
+ * must be at least as long as the policy object.
+ *
+ * @param rule SecurityPolicyRule to add
+ */
+ void addRule(const SecurityPolicyRule* rule) {
+ m_rules.push_back(rule);
+ }
+
+ /**
* Sets a locked MetadataProvider for the policy.
*
* @param metadata a locked MetadataProvider or NULL
*
* @return the effective IssuerMatchingPolicy
*/
- const IssuerMatchingPolicy* getIssuerMatchingPolicy() const {
- return m_matchingPolicy ? m_matchingPolicy : &m_defaultMatching;
+ const IssuerMatchingPolicy& getIssuerMatchingPolicy() const {
+ return m_matchingPolicy ? *m_matchingPolicy : m_defaultMatching;
}
/**
*
* @param matchingPolicy the IssuerMatchingPolicy to use
*/
- void getIssuerMatchingPolicy(IssuerMatchingPolicy* matchingPolicy) {
+ void setIssuerMatchingPolicy(IssuerMatchingPolicy* matchingPolicy) {
delete m_matchingPolicy;
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.
* @param metadataProvider locked MetadataProvider instance to authenticate the message
* @param role identifies the role (generally IdP or SP) of the peer who issued the message
* @param trustEngine TrustEngine to authenticate the message
+ * @param extractor MessageExtractor to use in examining message
* @return the identity of the message issuer, in two forms, or NULL
*
* @throws BindingException thrown if the request/message do not meet the requirements of this rule
const xmltooling::XMLObject& message,
const saml2md::MetadataProvider* metadataProvider,
const xmltooling::QName* role,
- const TrustEngine* trustEngine
+ const TrustEngine* trustEngine,
+ const MessageExtractor& extractor
) const=0;
};
const xmltooling::XMLObject& message,
const saml2md::MetadataProvider* metadataProvider,
const xmltooling::QName* role,
- const TrustEngine* trustEngine
+ const TrustEngine* trustEngine,
+ const MessageExtractor& extractor
) 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 TrustEngine* trustEngine,
+ const MessageExtractor& extractor
) 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 saml2md::MetadataProvider* metadataProvider,
const QName* role,
- const opensaml::TrustEngine* trustEngine
+ const opensaml::TrustEngine* trustEngine,
+ const MessageExtractor& extractor
) const
{
try {
#include "internal.h"
#include "exceptions.h"
#include "binding/SecurityPolicy.h"
+#include "saml1/core/Assertions.h"
+#include "saml1/core/Protocols.h"
#include "saml2/core/Assertions.h"
+#include "saml2/core/Protocols.h"
using namespace opensaml::saml2md;
using namespace opensaml::saml2;
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);
+ pair<Issuer*,const RoleDescriptor*> ident =
+ (*i)->evaluate(request,message,m_metadata,&m_role,m_trust,getMessageExtractor());
// Make sure returned issuer doesn't conflict.
if (ident.first) {
- if (!(m_matchingPolicy ? m_matchingPolicy : &m_defaultMatching)->issuerMatches(ident.first, m_issuer)) {
+ if (!getIssuerMatchingPolicy().issuerMatches(ident.first, m_issuer)) {
delete ident.first;
throw BindingException("Policy rules returned differing Issuers.");
}
void SecurityPolicy::setIssuer(saml2::Issuer* issuer)
{
- if (!((m_matchingPolicy ? m_matchingPolicy : &m_defaultMatching))->issuerMatches(issuer, m_issuer)) {
+ if (!getIssuerMatchingPolicy().issuerMatches(issuer, m_issuer)) {
delete issuer;
throw BindingException("Externally provided Issuer conflicts with policy results.");
}
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);
+}
const XMLObject& message,
const MetadataProvider* metadataProvider,
const QName* role,
- const opensaml::TrustEngine* trustEngine
+ const opensaml::TrustEngine* trustEngine,
+ const MessageExtractor& extractor
) const
{
Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.SimpleSigning");
try {
log.debug("extracting issuer from message");
- pair<saml2::Issuer*,const XMLCh*> issuerInfo = getIssuerAndProtocol(message);
+ pair<saml2::Issuer*,const XMLCh*> issuerInfo = extractor.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) || 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);
- 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 "exceptions.h"
#include "RootObject.h"
#include "binding/XMLSigningRule.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"
const XMLObject& message,
const MetadataProvider* metadataProvider,
const QName* role,
- const opensaml::TrustEngine* trustEngine
+ const opensaml::TrustEngine* trustEngine,
+ const MessageExtractor& extractor
) const
{
Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.XMLSigning");
}
log.debug("extracting issuer from message");
- pair<saml2::Issuer*,const XMLCh*> issuerInfo = getIssuerAndProtocol(message);
+ pair<saml2::Issuer*,const XMLCh*> issuerInfo = extractor.getIssuerAndProtocol(message);
auto_ptr<saml2::Issuer> issuer(issuerInfo.first);
if (!issuerInfo.first || !issuerInfo.second ||
}
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
- );
- }
- }
- }
- 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);
-}