const xmltooling::QName* role=NULL,
const xmltooling::TrustEngine* trustEngine=NULL,
bool validate=true
- ) : m_messageQName(NULL), m_messageID(NULL), m_issueInstant(0),
- m_issuer(NULL), m_issuerRole(NULL), m_secure(false), m_matchingPolicy(NULL),
- m_metadata(metadataProvider), m_role(NULL), m_trust(trustEngine), m_validate(validate) {
- if (role)
- m_role = new xmltooling::QName(*role);
- }
-
- /**
- * 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
- * @param role identifies the role (generally IdP or SP) of the policy peer
- * @param trustEngine TrustEngine to authenticate policy peer
- * @param validate true iff XML parsing should be done with validation
- */
- SecurityPolicy(
- const std::vector<const SecurityPolicyRule*>& rules,
- const saml2md::MetadataProvider* metadataProvider=NULL,
- const xmltooling::QName* role=NULL,
- const xmltooling::TrustEngine* trustEngine=NULL,
- bool validate=true
- ) : m_messageQName(NULL), m_messageID(NULL), m_issueInstant(0),
- m_issuer(NULL), m_issuerRole(NULL), m_secure(false), m_matchingPolicy(NULL),
- m_rules(rules), m_metadata(metadataProvider), m_role(NULL), m_trust(trustEngine), m_validate(validate) {
+ ) : m_messageID(NULL), m_issueInstant(0), m_issuer(NULL), m_issuerRole(NULL), m_secure(false),
+ m_matchingPolicy(NULL), m_metadata(metadataProvider), m_role(NULL), m_trust(trustEngine), m_validate(validate) {
if (role)
m_role = new xmltooling::QName(*role);
}
}
/**
- * Adds a SecurityPolicyRule to the policy. The lifetime of the policy rule
- * must be at least as long as the policy object.
+ * Gets a mutable array of installed policy rules.
+ *
+ * <p>If adding rules, their lifetime must be at least as long as the policy object.
*
- * @param rule SecurityPolicyRule to add
+ * @return mutable array of rules
*/
- void addRule(const SecurityPolicyRule* rule) {
- m_rules.push_back(rule);
+ std::vector<const SecurityPolicyRule*>& getRules() {
+ return m_rules;
}
/**
*
* @param message the incoming message
* @param request the protocol request
+ * @param protocol the protocol family in use
*
* @throws BindingException raised if the message/request is invalid according to the supplied rules
*/
- void evaluate(const xmltooling::XMLObject& message, const xmltooling::GenericRequest* request=NULL);
+ void evaluate(
+ const xmltooling::XMLObject& message, const xmltooling::GenericRequest* request=NULL, const XMLCh* protocol=NULL
+ );
/**
- * Resets the policy object and clears any per-message state.
+ * Resets the policy object and/or clears any per-message state.
+ *
+ * <p>Resets can be complete (the default) or merely clear the previous message ID and timestamp
+ * when evaluating multiple layers of a message.
+ *
+ * @param messageOnly true iff security and issuer state should be left in place
*/
- void reset();
+ void reset(bool messageOnly=false);
/**
- * Returns the message element/type as determined by the registered policies.
- *
- * @return message element/type as determined by the registered policies
- */
- const xmltooling::QName* getMessageQName() const {
- return m_messageQName;
- }
-
- /**
* Returns the message identifier as determined by the registered policies.
*
* @return message identifier as determined by the registered policies
}
/**
- * Sets the message element/type as determined by the registered policies.
- *
- * @param messageQName message element/type
- */
- void setMessageQName(const xmltooling::QName* messageQName) {
- delete m_messageQName;
- m_messageQName = messageQName ? new xmltooling::QName(*messageQName) : NULL;
- }
-
- /**
* Sets the message identifier as determined by the registered policies.
*
* @param id message identifier
private:
// information extracted from message
- xmltooling::QName* m_messageQName;
XMLCh* m_messageID;
time_t m_issueInstant;
saml2::Issuer* m_issuer;
virtual ~SecurityPolicyRule() {}
/**
+ * Returns the rule's class/type.
+ *
+ * @return the class/type of the object
+ */
+ virtual const char* getType() const=0;
+
+ /**
* Evaluates the rule against the given request and message.
*
+ * <p>An exception will be raised if the message is invalid according to
+ * a policy rule.
+ *
* @param message the incoming message
* @param request the protocol request
+ * @param protocol the protocol family in use
* @param policy SecurityPolicy to provide various components and track message data
- *
- * @throws BindingException raised if the message/request is not acceptable to the policy rule
*/
virtual void evaluate(
- const xmltooling::XMLObject& message, const xmltooling::GenericRequest* request, SecurityPolicy& policy
+ const xmltooling::XMLObject& message,
+ const xmltooling::GenericRequest* request,
+ const XMLCh* protocol,
+ SecurityPolicy& policy
) const=0;
};
ClientCertAuthRule(const DOMElement* e) {}
virtual ~ClientCertAuthRule() {}
- void evaluate(const xmltooling::XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const;
+ const char* getType() const {
+ return CLIENTCERTAUTH_POLICY_RULE;
+ }
+ void evaluate(const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy) const;
};
SecurityPolicyRule* SAML_DLLLOCAL ClientCertAuthRuleFactory(const DOMElement* const & e)
}
};
-void ClientCertAuthRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const
+void ClientCertAuthRule::evaluate(
+ const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy
+ ) const
{
Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.ClientCertAuth");
MessageFlowRule(const DOMElement* e);
virtual ~MessageFlowRule() {}
- void evaluate(const xmltooling::XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const;
+ const char* getType() const {
+ return MESSAGEFLOW_POLICY_RULE;
+ }
+ void evaluate(const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy) const;
private:
bool m_checkReplay;
}
}
-void MessageFlowRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const
+void MessageFlowRule::evaluate(
+ const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy
+ ) const
{
Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.MessageFlow");
log.debug("evaluating message flow policy (replay checking %s, expiration %lu)", m_checkReplay ? "on" : "off", m_expires);
NullSecurityRule(const DOMElement* e) : m_log(Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.NullSecurity")) {}
virtual ~NullSecurityRule() {}
- void evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const;
+ const char* getType() const {
+ return NULLSECURITY_POLICY_RULE;
+ }
+ void evaluate(const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy) const {
+ m_log.warn("security enforced using NULL policy rule, be sure you know what you're doing");
+ policy.setSecure(true);
+ }
private:
Category& m_log;
return new NullSecurityRule(e);
}
};
-
-void NullSecurityRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const
-{
- m_log.warn("security enforced using NULL policy rule, be sure you know what you're doing");
- policy.setSecure(true);
-}
SecurityPolicy::~SecurityPolicy()
{
- reset();
+ reset(false);
}
-void SecurityPolicy::reset()
+void SecurityPolicy::reset(bool messageOnly)
{
- delete m_messageQName;
XMLString::release(&m_messageID);
- delete m_issuer;
- m_messageQName=NULL;
m_messageID=NULL;
m_issueInstant=0;
- m_issuer=NULL;
- m_issuerRole=NULL;
- m_secure=false;
+ if (!messageOnly) {
+ delete m_issuer;
+ m_issuer=NULL;
+ m_issuerRole=NULL;
+ m_secure=false;
+ }
}
-void SecurityPolicy::evaluate(const XMLObject& message, const GenericRequest* request)
+void SecurityPolicy::evaluate(const XMLObject& message, const GenericRequest* request, const XMLCh* protocol)
{
for (vector<const SecurityPolicyRule*>::const_iterator i=m_rules.begin(); i!=m_rules.end(); ++i)
- (*i)->evaluate(message,request,*this);
+ (*i)->evaluate(message,request,protocol,*this);
}
void SecurityPolicy::setIssuer(const Issuer* issuer)
SimpleSigningRule(const DOMElement* e);
virtual ~SimpleSigningRule() {}
- void evaluate(const xmltooling::XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const;
+ const char* getType() const {
+ return SIMPLESIGNING_POLICY_RULE;
+ }
+ void evaluate(const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy) const;
private:
// Appends a raw parameter=value pair to the string.
}
}
-void SimpleSigningRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const
+void SimpleSigningRule::evaluate(
+ const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy
+ ) const
{
Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.SimpleSigning");
XMLSigningRule(const DOMElement* e);
virtual ~XMLSigningRule() {}
- void evaluate(const xmltooling::XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const;
+ const char* getType() const {
+ return XMLSIGNING_POLICY_RULE;
+ }
+ void evaluate(const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy) const;
private:
bool m_errorsFatal;
}
}
-void XMLSigningRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const
+void XMLSigningRule::evaluate(
+ const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy
+ ) const
{
Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.XMLSigning");
SAML1MessageRule(const DOMElement* e) {}
virtual ~SAML1MessageRule() {}
- void evaluate(const xmltooling::XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const;
+ const char* getType() const {
+ return SAML1MESSAGE_POLICY_RULE;
+ }
+ void evaluate(const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy) const;
};
SecurityPolicyRule* SAML_DLLLOCAL SAML1MessageRuleFactory(const DOMElement* const & e)
}
};
-void SAML1MessageRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const
+void SAML1MessageRule::evaluate(
+ const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy
+ ) const
{
- Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.SAML1Message");
-
- const QName& q = message.getElementQName();
- policy.setMessageQName(&q);
-
+ // Only handle SAML 1.x protocol and SAML 1.x messages.
+ if (!XMLString::equals(protocol, samlconstants::SAML11_PROTOCOL_ENUM) &&
+ !XMLString::equals(protocol, samlconstants::SAML10_PROTOCOL_ENUM))
+ return;
+ const QName& q = message.getElementQName();
if (!XMLString::equals(q.getNamespaceURI(), samlconstants::SAML1P_NS) &&
- !XMLString::equals(q.getNamespaceURI(), samlconstants::SAML1_NS)) {
+ !XMLString::equals(q.getNamespaceURI(), samlconstants::SAML1_NS))
return;
- }
+
+ Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.SAML1Message");
try {
const RootObject& samlRoot = dynamic_cast<const RootObject&>(message);
log.debug("extracting issuer from message");
- const XMLCh* protocol = NULL;
const saml1::Assertion* a = NULL;
// Handle assertions directly.
if (a) {
policy.setIssuer(a->getIssuer());
- pair<bool,int> minor = a->getMinorVersion();
- protocol = (minor.first && minor.second==0) ?
- samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM;
}
-
- if (!protocol) {
+ else {
log.warn("issuer identity not extracted");
return;
}
SchemaValidators.validate(xmlObject.get());
// Run through the policy.
- policy.evaluate(*response, &genericRequest);
+ pair<bool,int> minor = response->getMinorVersion();
+ policy.evaluate(
+ *response,
+ &genericRequest,
+ (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM
+ );
// Check recipient URL.
auto_ptr_char recipient(response->getRecipient());
if (m_correlate && response->getInResponseTo() && !XMLString::equals(m_correlate, response->getInResponseTo()))
throw SecurityPolicyException("InResponseTo attribute did not correlate with the Request ID.");
- m_soaper.getPolicy().evaluate(*response);
+ m_soaper.getPolicy().reset(true);
+ pair<bool,int> minor = response->getMinorVersion();
+ m_soaper.getPolicy().evaluate(
+ *response,
+ NULL,
+ (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM
+ );
if (!m_soaper.getPolicy().isSecure()) {
SecurityPolicyException ex("Security policy could not authenticate the message.");
Request* request = dynamic_cast<Request*>(body->getUnknownXMLObjects().front());
if (request) {
// Run through the policy at two layers.
- policy.evaluate(*env, &genericRequest);
- policy.evaluate(*request, &genericRequest);
+ pair<bool,int> minor = request->getMinorVersion();
+ policy.evaluate(
+ *env,
+ &genericRequest,
+ (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM
+ );
+ policy.reset(true);
+ policy.evaluate(
+ *request,
+ &genericRequest,
+ (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM
+ );
xmlObject.release();
body->detach(); // frees Envelope
request->detach(); // frees Body
}
}
- throw BindingException("SOAP Envelope did not contain a SAML Request.");
+ throw BindingException("SOAP Envelope did not contain a SAML 1.x Request.");
}
m_artifactResolver->resolve(*(artifact2.get()), dynamic_cast<const SSODescriptorType&>(*roledesc), policy)
);
- // The policy should be enforced against the ArtifactResponse by the resolve step.
+ // The policy should be enforced against the ArtifactResponse by the resolve step.
+ // Reset only the message state.
+ policy.reset(true);
// Extract payload and check that message.
XMLObject* payload = response->getPayload();
- policy.evaluate(*payload, &genericRequest);
+ policy.evaluate(*payload, &genericRequest, samlconstants::SAML20P_NS);
// Return the payload only.
response.release();
SAML2MessageRule(const DOMElement* e) {}
virtual ~SAML2MessageRule() {}
- void evaluate(const xmltooling::XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const;
+ const char* getType() const {
+ return SAML2MESSAGE_POLICY_RULE;
+ }
+ void evaluate(const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy) const;
};
SecurityPolicyRule* SAML_DLLLOCAL SAML2MessageRuleFactory(const DOMElement* const & e)
}
};
-void SAML2MessageRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const
+void SAML2MessageRule::evaluate(
+ const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy
+ ) const
{
- Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.SAML2Message");
-
- const QName& q = message.getElementQName();
- policy.setMessageQName(&q);
-
+ // Only handle SAML 2.0 protocol and 2.0 messages.
+ if (!XMLString::equals(protocol, samlconstants::SAML20P_NS))
+ return;
+ const QName& q = message.getElementQName();
if (!XMLString::equals(q.getNamespaceURI(), samlconstants::SAML20P_NS)&&
- !XMLString::equals(q.getNamespaceURI(), samlconstants::SAML20_NS)) {
+ !XMLString::equals(q.getNamespaceURI(), samlconstants::SAML20_NS))
return;
- }
+ Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.SAML2Message");
+
try {
const saml2::RootObject& samlRoot = dynamic_cast<const saml2::RootObject&>(message);
policy.setMessageID(samlRoot.getID());
}
log.debug("matched message issuer against metadata, searching for applicable role...");
- const RoleDescriptor* roledesc=entity->getRoleDescriptor(*policy.getRole(), samlconstants::SAML20P_NS);
+ const RoleDescriptor* roledesc=entity->getRoleDescriptor(*policy.getRole(), protocol);
if (!roledesc) {
log.warn("unable to find compatible role (%s) in metadata", policy.getRole()->toString().c_str());
return;
SchemaValidators.validate(xmlObject.get());
// Run through the policy.
- policy.evaluate(*root, &genericRequest);
+ policy.evaluate(*root, &genericRequest, samlconstants::SAML20P_NS);
// Check destination URL.
auto_ptr_char dest(request ? request->getDestination() : response->getDestination());
SchemaValidators.validate(xmlObject.get());
// Run through the policy.
- policy.evaluate(*root, &genericRequest);
+ policy.evaluate(*root, &genericRequest, samlconstants::SAML20P_NS);
// Check destination URL.
auto_ptr_char dest(request ? request->getDestination() : response->getDestination());
if (m_correlate && response->getInResponseTo() && !XMLString::equals(m_correlate, response->getInResponseTo()))
throw SecurityPolicyException("InResponseTo attribute did not correlate with the Request ID.");
- m_soaper.getPolicy().evaluate(*response);
+ m_soaper.getPolicy().reset(true);
+ m_soaper.getPolicy().evaluate(*response, NULL, samlconstants::SAML20P_NS);
if (!m_soaper.getPolicy().isSecure()) {
SecurityPolicyException ex("Security policy could not authenticate the message.");
annotateException(&ex, m_soaper.getPolicy().getIssuerMetadata(), response->getStatus()); // throws it
RequestAbstractType* request = dynamic_cast<RequestAbstractType*>(body->getUnknownXMLObjects().front());
if (request) {
// Run through the policy at two layers.
- policy.evaluate(*env, &genericRequest);
- policy.evaluate(*request, &genericRequest);
+ policy.evaluate(*env, &genericRequest, samlconstants::SAML20P_NS);
+ policy.reset(true);
+ policy.evaluate(*request, &genericRequest, samlconstants::SAML20P_NS);
xmlObject.release();
body->detach(); // frees Envelope
request->detach(); // frees Body
void testSAML1Artifact() {\r
try {\r
QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);\r
- SecurityPolicy policy(m_rules1, m_metadata, &idprole, m_trust, false);\r
+ SecurityPolicy policy(m_metadata, &idprole, m_trust, false);\r
+ policy.getRules().assign(m_rules1.begin(), m_rules1.end());\r
\r
// Read message to use from file.\r
string path = data_path + "saml1/binding/SAML1Assertion.xml";\r
TSM_ASSERT("Retrieved credential was null", cred!=NULL);\r
response->marshall((DOMDocument*)NULL,&sigs,cred);\r
SchemaValidators.validate(response.get());\r
- policy.evaluate(*(response.get()), this);\r
+ policy.evaluate(*(response.get()), this, samlconstants::SAML11_PROTOCOL_ENUM);\r
return response.release();\r
}\r
\r
void testSAML1POST() {
try {
QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);
- SecurityPolicy policy(m_rules1, m_metadata, &idprole, m_trust, false);
+ SecurityPolicy policy(m_metadata, &idprole, m_trust, false);
+ policy.getRules().assign(m_rules1.begin(), m_rules1.end());
// Read message to use from file.
string path = data_path + "saml1/binding/SAML1Response.xml";
void testSAML2Artifact() {
try {
QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);
- SecurityPolicy policy(m_rules2, m_metadata, &idprole, m_trust, false);
+ SecurityPolicy policy(m_metadata, &idprole, m_trust, false);
+ policy.getRules().assign(m_rules2.begin(), m_rules2.end());
// Read message to use from file.
string path = data_path + "saml2/binding/SAML2Response.xml";
sc->setValue(StatusCode::SUCCESS);
response->marshall();
SchemaValidators.validate(response.get());
- policy.evaluate(*(response.get()), this);
+ policy.evaluate(*(response.get()), this, samlconstants::SAML20P_NS);
return response.release();
}
};
void testSAML2POST() {
try {
QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);
- SecurityPolicy policy(m_rules2, m_metadata, &idprole, m_trust, false);
+ SecurityPolicy policy(m_metadata, &idprole, m_trust, false);
+ policy.getRules().assign(m_rules2.begin(), m_rules2.end());
// Read message to use from file.
string path = data_path + "saml2/binding/SAML2Response.xml";
void testSAML2POSTSimpleSign() {
try {
QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);
- SecurityPolicy policy(m_rules2, m_metadata, &idprole, m_trust, false);
+ SecurityPolicy policy(m_metadata, &idprole, m_trust, false);
+ policy.getRules().assign(m_rules2.begin(), m_rules2.end());
// Read message to use from file.
string path = data_path + "saml2/binding/SAML2Response.xml";
void testSAML2Redirect() {
try {
QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);
- SecurityPolicy policy(m_rules2, m_metadata, &idprole, m_trust, false);
+ SecurityPolicy policy(m_metadata, &idprole, m_trust, false);
+ policy.getRules().assign(m_rules2.begin(), m_rules2.end());
// Read message to use from file.
string path = data_path + "saml2/binding/SAML2Response.xml";