/*
* Copyright 2001-2007 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
/**
* @file saml/binding/SecurityPolicy.h
- *
+ *
* Overall policy used to verify the security of an incoming message.
*/
#ifndef __saml_secpol_h__
#define __saml_secpol_h__
-#include <saml/base.h>
+#include <saml/saml2/metadata/MetadataProvider.h>
#include <ctime>
#include <vector>
-#include <xmltooling/XMLObject.h>
#include <xmltooling/io/GenericRequest.h>
#include <xmltooling/security/TrustEngine.h>
namespace saml2 {
class SAML_API Issuer;
};
- namespace saml2md {
- class SAML_API MetadataProvider;
- class SAML_API RoleDescriptor;
- };
-
+
class SAML_API SecurityPolicyRule;
-
+
/**
* A policy used to verify the security of an incoming message.
- *
+ *
* <p>Its security mechanisms may be used to examine the transport layer
* (e.g client certificates and HTTP basic auth passwords) or to check the
* payload of a request to ensure it meets certain criteria (e.g. valid
* digital signature, freshness, replay).
- *
- * <p>Policy objects can be reused, but are not thread-safe.
+ *
+ * <p>Policy objects can be reused, but are not thread-safe.
*/
class SAML_API SecurityPolicy
{
public:
/**
* Constructor for policy.
- *
+ *
* @param metadataProvider locked MetadataProvider instance
- * @param role identifies the role (generally IdP or SP) of the policy peer
+ * @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
*/
const xmltooling::QName* role=NULL,
const xmltooling::TrustEngine* trustEngine=NULL,
bool validate=true
- ) : m_messageID(NULL), m_issueInstant(0), m_issuer(NULL), m_issuerRole(NULL), m_authenticated(false),
+ ) : m_metadataCriteria(NULL), m_messageID(NULL), m_issueInstant(0), m_issuer(NULL), m_issuerRole(NULL), m_authenticated(false),
m_matchingPolicy(NULL), m_metadata(metadataProvider), m_role(NULL), m_trust(trustEngine), m_validate(validate), m_entityOnly(true) {
if (role)
m_role = new xmltooling::QName(*role);
/**
* Returns the locked MetadataProvider supplied to the policy.
- *
+ *
* @return the supplied MetadataProvider or NULL
*/
const saml2md::MetadataProvider* getMetadataProvider() const {
}
/**
+ * Returns a reference to a MetadataProvider::Criteria instance suitable for use with the
+ * installed MetadataProvider.
+ *
+ * @return reference to a MetadataProvider::Criteria instance
+ */
+ virtual saml2md::MetadataProvider::Criteria& getMetadataProviderCriteria() const;
+
+ /**
* Returns the peer role element/type supplied to the policy.
- *
+ *
* @return the peer role element/type, or an empty QName
*/
const xmltooling::QName* getRole() const {
/**
* Returns the TrustEngine supplied to the policy.
- *
+ *
* @return the supplied TrustEngine or NULL
*/
const xmltooling::TrustEngine* getTrustEngine() const {
/**
* Returns XML message validation setting.
- *
+ *
* @return validation flag
*/
bool getValidating() const {
return m_validate;
}
-
+
/**
* Returns flag controlling non-entity issuer support.
- *
+ *
* @return flag controlling non-entity issuer support
*/
bool requireEntityIssuer() const {
* Gets a mutable array of installed policy rules.
*
* <p>If adding rules, their lifetime must be at least as long as the policy object.
- *
+ *
* @return mutable array of rules
*/
std::vector<const SecurityPolicyRule*>& getRules() {
/**
* Sets a locked MetadataProvider for the policy.
- *
+ *
* @param metadata a locked MetadataProvider or NULL
*/
void setMetadataProvider(const saml2md::MetadataProvider* metadata) {
/**
* Sets a peer role element/type for to the policy.
- *
+ *
* @param role the peer role element/type or NULL
*/
void setRole(const xmltooling::QName* role) {
/**
* Sets a TrustEngine for the policy.
- *
+ *
* @param trust a TrustEngine or NULL
*/
void setTrustEngine(const xmltooling::TrustEngine* trust) {
/**
* Controls schema validation of incoming XML messages.
* This is separate from other forms of programmatic validation of objects,
- * but can detect a much wider range of syntax errors.
- *
+ * but can detect a much wider range of syntax errors.
+ *
* @param validate validation setting
*/
void setValidating(bool validate=true) {
/**
* Sets flag controlling non-entity issuer support.
- *
- * @param entityOnly require that Issuer be in entity format
+ *
+ * @param entityOnly require that Issuer be in entity format
*/
void requireEntityIssuer(bool entityOnly=true) {
m_entityOnly = entityOnly;
}
-
+
/**
* Evaluates the policy against the given request and message,
* possibly populating message information in the policy object.
- *
+ *
* @param message the incoming message
* @param request the protocol request
*
* @param messageOnly true iff security and issuer state should be left in place
*/
void reset(bool messageOnly=false);
-
+
/**
* Returns the message identifier as determined by the registered policies.
- *
+ *
* @return message identifier as determined by the registered policies
*/
const XMLCh* getMessageID() const {
/**
* Returns the message timestamp as determined by the registered policies.
- *
+ *
* @return message timestamp as determined by the registered policies
*/
time_t getIssueInstant() const {
/**
* Gets the issuer of the message as determined by the registered policies.
- *
+ *
* @return issuer of the message as determined by the registered policies
*/
const saml2::Issuer* getIssuer() const {
/**
* Gets the metadata for the role the issuer is operating in.
- *
+ *
* @return metadata for the role the issuer is operating in
*/
const saml2md::RoleDescriptor* getIssuerMetadata() const {
/**
* Returns the authentication status of the message as determined by the registered policies.
- *
- * @return true iff a SecurityPolicyRule has indicated the issuer/message has been authenticated
+ *
+ * @return true iff a SecurityPolicyRule has indicated the issuer/message has been authenticated
*/
bool isAuthenticated() const {
return m_authenticated;
/**
* Sets the message identifier as determined by the registered policies.
- *
+ *
* @param id message identifier
*/
void setMessageID(const XMLCh* id) {
/**
* Sets the message timestamp as determined by the registered policies.
- *
+ *
* @param issueInstant message timestamp
*/
void setIssueInstant(time_t issueInstant) {
/**
* Sets the issuer of the message as determined by the registered policies.
- *
+ *
* @param issuer issuer of the message
*/
void setIssuer(const saml2::Issuer* issuer);
/**
* Sets the issuer of the message as determined by the registered policies.
- *
+ *
* @param issuer issuer of the message
*/
void setIssuer(const XMLCh* issuer);
-
+
/**
* Sets the metadata for the role the issuer is operating in.
- *
+ *
* @param issuerRole metadata for the role the issuer is operating in
*/
void setIssuerMetadata(const saml2md::RoleDescriptor* issuerRole);
/**
* Sets the authentication status of the message as determined by the registered policies.
- *
+ *
* @param auth indicates whether the issuer/message has been authenticated
*/
void setAuthenticated(bool auth) {
m_authenticated = auth;
}
-
+
/** Allows override of rules for comparing saml2:Issuer information. */
class SAML_API IssuerMatchingPolicy {
MAKE_NONCOPYABLE(IssuerMatchingPolicy);
public:
IssuerMatchingPolicy() {}
virtual ~IssuerMatchingPolicy() {}
-
+
/**
* Returns true iff the two operands "match". Applications can override this method to
- * support non-standard issuer matching for complex policies.
- *
+ * support non-standard issuer matching for complex policies.
+ *
* <p>The default implementation does a basic comparison of the XML content, treating
* an unsupplied Format as an "entityID".
- *
+ *
* @param issuer1 the first Issuer to match
* @param issuer2 the second Issuer to match
* @return true iff the operands match
/**
* Returns true iff the two operands "match". Applications can override this method to
- * support non-standard issuer matching for complex policies.
- *
+ * support non-standard issuer matching for complex policies.
+ *
* <p>The default implementation does a basic comparison of the XML content, treating
* an unsupplied Format as an "entityID".
- *
+ *
* @param issuer1 the first Issuer to match
* @param issuer2 the second Issuer to match
* @return true iff the operands match
/**
* Returns the IssuerMatchingPolicy in effect.
- *
+ *
* @return the effective IssuerMatchingPolicy
*/
const IssuerMatchingPolicy& getIssuerMatchingPolicy() const {
/**
* Sets the IssuerMatchingPolicy in effect. Setting no policy will
* cause the simple, default approach to be used.
- *
+ *
* <p>The matching object will be freed by the SecurityPolicy.
- *
+ *
* @param matchingPolicy the IssuerMatchingPolicy to use
*/
void setIssuerMatchingPolicy(IssuerMatchingPolicy* matchingPolicy) {
/** A shared matching object that just supports the default matching rules. */
static IssuerMatchingPolicy m_defaultMatching;
+ /** Manufactured MetadataProvider::Criteria instance. */
+ mutable saml2md::MetadataProvider::Criteria* m_metadataCriteria;
+
private:
- // information extracted from message
+ // information extracted from message
XMLCh* m_messageID;
time_t m_issueInstant;
saml2::Issuer* m_issuer;
const saml2md::RoleDescriptor* m_issuerRole;
bool m_authenticated;
-
+
// components governing policy rules
IssuerMatchingPolicy* m_matchingPolicy;
std::vector<const SecurityPolicyRule*> m_rules;
/*
* Copyright 2001-2007 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
/**
* SecurityPolicy.cpp
- *
- * Overall policy used to verify the security of an incoming message.
+ *
+ * Overall policy used to verify the security of an incoming message.
*/
#include "internal.h"
XMLString::release(&m_messageID);
m_messageID=NULL;
m_issueInstant=0;
+ delete m_metadataCriteria;
+ m_metadataCriteria=NULL;
if (!messageOnly) {
delete m_issuer;
m_issuer=NULL;
}
}
+MetadataProvider::Criteria& SecurityPolicy::getMetadataProviderCriteria() const
+{
+ if (!m_metadataCriteria)
+ m_metadataCriteria=new MetadataProvider::Criteria();
+ return *m_metadataCriteria;
+}
+
void SecurityPolicy::evaluate(const XMLObject& message, const GenericRequest* request)
{
for (vector<const SecurityPolicyRule*>::const_iterator i=m_rules.begin(); i!=m_rules.end(); ++i)
{
if (!getIssuerMatchingPolicy().issuerMatches(m_issuer, issuer))
throw SecurityPolicyException("An Issuer was supplied that conflicts with previous results.");
-
+
if (!m_issuer) {
if (m_entityOnly && issuer->getFormat() && !XMLString::equals(issuer->getFormat(), NameIDType::ENTITY))
throw SecurityPolicyException("A non-entity Issuer was supplied, violating policy.");
{
if (!getIssuerMatchingPolicy().issuerMatches(m_issuer, issuer))
throw SecurityPolicyException("An Issuer was supplied that conflicts with previous results.");
-
+
if (!m_issuer && issuer && *issuer) {
m_issuerRole = NULL;
m_issuer = IssuerBuilder::buildIssuer();
// NULL matches anything for the purposes of this interface.
if (!issuer1 || !issuer2)
return true;
-
+
const XMLCh* op1=issuer1->getName();
const XMLCh* op2=issuer2->getName();
if (!op1 || !op2 || !XMLString::equals(op1,op2))
return false;
-
+
op1=issuer1->getFormat();
op2=issuer2->getFormat();
if (!XMLString::equals(op1 ? op1 : NameIDType::ENTITY, op2 ? op2 : NameIDType::ENTITY))
return false;
-
+
op1=issuer1->getNameQualifier();
op2=issuer2->getNameQualifier();
if (!XMLString::equals(op1 ? op1 : &chNull, op2 ? op2 : &chNull))
op2=issuer2->getSPNameQualifier();
if (!XMLString::equals(op1 ? op1 : &chNull, op2 ? op2 : &chNull))
return false;
-
+
return true;
}
// NULL matches anything for the purposes of this interface.
if (!issuer1 || !issuer2 || !*issuer2)
return true;
-
+
const XMLCh* op1=issuer1->getName();
if (!op1 || !XMLString::equals(op1,issuer2))
return false;
-
+
op1=issuer1->getFormat();
if (op1 && *op1 && !XMLString::equals(op1, NameIDType::ENTITY))
return false;
-
+
op1=issuer1->getNameQualifier();
if (op1 && *op1)
return false;
op1=issuer1->getSPNameQualifier();
if (op1 && *op1)
return false;
-
+
return true;
}
/*
* Copyright 2001-2007 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
/**
* SAML1ArtifactDecoder.cpp
- *
+ *
* SAML 1.x Artifact binding/profile message decoder
*/
using namespace std;
namespace opensaml {
- namespace saml1p {
+ namespace saml1p {
class SAML_DLLLOCAL SAML1ArtifactDecoder : public SAML1MessageDecoder
{
public:
SAML1ArtifactDecoder() {}
virtual ~SAML1ArtifactDecoder() {}
-
+
xmltooling::XMLObject* decode(
std::string& relayState,
const GenericRequest& genericRequest,
SecurityPolicy& policy
) const;
- };
+ };
MessageDecoder* SAML_DLLLOCAL SAML1ArtifactDecoderFactory(const pair<const DOMElement*,const XMLCh*>& p)
{
for (vector<const char*>::const_iterator raw=SAMLart.begin(); raw!=SAMLart.end(); ++raw) {
try {
log.debug("processing encoded artifact (%s)", *raw);
-
+
// Check replay.
ReplayCache* replayCache = XMLToolingConfig::getConfig().getReplayCache();
if (replayCache) {
throw;
}
}
-
+
log.debug("attempting to determine source of artifact(s)...");
- MetadataProvider::Criteria mc(artifacts.front(), policy.getRole(), samlconstants::SAML11_PROTOCOL_ENUM);
+ MetadataProvider::Criteria& mc = policy.getMetadataProviderCriteria();
+ mc.artifact = artifacts.front();
+ mc.role = policy.getRole();
+ mc.protocol = samlconstants::SAML11_PROTOCOL_ENUM;
mc.protocol2 = samlconstants::SAML10_PROTOCOL_ENUM;
pair<const EntityDescriptor*,const RoleDescriptor*> provider=policy.getMetadataProvider()->getEntityDescriptor(mc);
if (!provider.first) {
for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup<SAMLArtifact>());
throw BindingException("Metadata lookup failed, unable to determine artifact issuer");
}
-
+
if (log.isDebugEnabled()) {
auto_ptr_char issuer(provider.first->getEntityID());
log.debug("artifact issued by (%s)", issuer.get());
// Set Issuer for the policy.
policy.setIssuer(provider.first->getEntityID());
policy.setIssuerMetadata(provider.second);
-
+
try {
log.debug("calling ArtifactResolver...");
auto_ptr<Response> response(
m_artifactResolver->resolve(artifacts, dynamic_cast<const IDPSSODescriptor&>(*provider.second), policy)
);
-
+
// The policy should be enforced against the Response by the resolve step.
-
+
for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup<SAMLArtifact>());
return response.release();
}
/*
* Copyright 2001-2007 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
/**
* SAML1MessageDecoder.cpp
- *
+ *
* Base class for SAML 1.x MessageDecoders.
*/
if (policy.getMetadataProvider() && policy.getRole()) {
log.debug("searching metadata for response issuer...");
-
- MetadataProvider::Criteria mc(issuer, policy.getRole(), protocol);
+ MetadataProvider::Criteria& mc = policy.getMetadataProviderCriteria();
+ mc.entityID_unicode = issuer;
+ mc.role = policy.getRole();
+ mc.protocol = protocol;
pair<const EntityDescriptor*,const RoleDescriptor*> entity = policy.getMetadataProvider()->getEntityDescriptor(mc);
if (!entity.first) {
/*
* Copyright 2001-2007 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
/**
* SAML2ArtifactDecoder.cpp
- *
+ *
* SAML 2.0 Artifact binding message decoder
*/
using namespace std;
namespace opensaml {
- namespace saml2p {
+ namespace saml2p {
class SAML_DLLLOCAL SAML2ArtifactDecoder : public SAML2MessageDecoder
{
public:
SAML2ArtifactDecoder() {}
virtual ~SAML2ArtifactDecoder() {}
-
+
xmltooling::XMLObject* decode(
std::string& relayState,
const GenericRequest& genericRequest,
SecurityPolicy& policy
) const;
- };
+ };
MessageDecoder* SAML_DLLLOCAL SAML2ArtifactDecoderFactory(const pair<const DOMElement*,const XMLCh*>& p)
{
SAMLArtifact* artifact=NULL;
try {
log.debug("processing encoded artifact (%s)", SAMLart);
-
+
// Check replay.
ReplayCache* replayCache = XMLToolingConfig::getConfig().getReplayCache();
if (replayCache) {
log.error("error parsing artifact (%s)", SAMLart);
throw;
}
-
+
// Check the type.
auto_ptr<SAML2Artifact> artifact2(dynamic_cast<SAML2Artifact*>(artifact));
if (!artifact2.get()) {
throw BindingException("Artifact binding requires SAML 2.0 artifact.");
delete artifact;
}
-
+
log.debug("attempting to determine source of artifact...");
- MetadataProvider::Criteria mc(artifact, policy.getRole(), samlconstants::SAML20P_NS);
+ MetadataProvider::Criteria& mc = policy.getMetadataProviderCriteria();
+ mc.artifact = artifact;
+ mc.role = policy.getRole();
+ mc.protocol = samlconstants::SAML20P_NS;
pair<const EntityDescriptor*,const RoleDescriptor*> provider=policy.getMetadataProvider()->getEntityDescriptor(mc);
if (!provider.first) {
log.error(
);
throw BindingException("Metadata lookup failed, unable to determine artifact issuer.");
}
-
+
if (log.isDebugEnabled()) {
auto_ptr_char issuer(provider.first->getEntityID());
log.debug("lookup succeeded, artifact issued by (%s)", issuer.get());
// Set issuer into policy.
policy.setIssuer(provider.first->getEntityID());
policy.setIssuerMetadata(provider.second);
-
+
log.debug("calling ArtifactResolver...");
auto_ptr<ArtifactResponse> response(
m_artifactResolver->resolve(*(artifact2.get()), dynamic_cast<const SSODescriptorType&>(*provider.second), policy)
);
-
+
// The policy should be enforced against the ArtifactResponse by the resolve step.
// Reset only the message state.
policy.reset(true);
// Return the payload only.
response.release();
- payload->detach();
+ payload->detach();
return payload;
}
/*
* Copyright 2001-2007 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
/**
* SAML2MessageDecoder.cpp
- *
+ *
* Base class for SAML 2.0 MessageDecoders.
*/
policy.setIssuer(issuer);
}
else if (XMLString::equals(q.getLocalPart(), Response::LOCAL_NAME)) {
- // No issuer in the message, so we have to try the Response approach.
+ // No issuer in the message, so we have to try the Response approach.
const vector<saml2::Assertion*>& assertions = dynamic_cast<const Response&>(samlRoot).getAssertions();
if (!assertions.empty()) {
issuer = assertions.front()->getIssuer();
log.warn("non-system entity issuer, skipping metadata lookup");
return;
}
-
- log.debug("searching metadata for message issuer...");
- MetadataProvider::Criteria mc(issuer->getName(), policy.getRole(), protocol);
+ log.debug("searching metadata for message issuer...");
+ MetadataProvider::Criteria& mc = policy.getMetadataProviderCriteria();
+ mc.entityID_unicode = issuer->getName();
+ mc.role = policy.getRole();
+ mc.protocol = protocol;
pair<const EntityDescriptor*,const RoleDescriptor*> entity = policy.getMetadataProvider()->getEntityDescriptor(mc);
if (!entity.first) {
auto_ptr_char temp(issuer->getName());
*/
struct SAML_API Criteria {
/**
+ * Default constructor.
+ */
+ Criteria() : entityID_unicode(NULL), entityID_ascii(NULL), artifact(NULL), role(NULL), protocol(NULL), protocol2(NULL), validOnly(true) {
+ }
+
+ /**
* Constructor.
*
* @param id entityID to lookup