const IProviderRole* role, const SAMLSignedObject& token,
const Iterator<IMetadata*>& metadatas) const
{
- bool ret=false;
m_trusts.reset();
- while (!ret && m_trusts.hasNext()) {
- ITrust* i=m_trusts.next();
- i->lock();
- ret=i->validate(revocations,role,token,metadatas);
- i->unlock();
+ while (m_trusts.hasNext()) {
+ if (m_trusts.next()->validate(revocations,role,token,metadatas))
+ return true;
}
- return ret;
+ return false;
}
bool Trust::attach(const Iterator<IRevocation*>& revocations, const IProviderRole* role, void* ctx) const
{
- bool ret=false;
m_trusts.reset();
- while (!ret && m_trusts.hasNext()) {
- ITrust* i=m_trusts.next();
- i->lock();
- ret=i->attach(revocations,role,ctx);
- i->unlock();
+ while (m_trusts.hasNext()) {
+ if (m_trusts.next()->attach(revocations,role,ctx))
+ return true;
}
- return ret;
+ return false;
}
const ICredResolver* Credentials::lookup(const char* id)
using namespace log4cpp;
using namespace std;
-ReloadableXMLFileImpl::ReloadableXMLFileImpl(const DOMElement* e) : m_doc(NULL), m_root(saml::XML::getFirstChildElement(e)) {}
+ReloadableXMLFileImpl::ReloadableXMLFileImpl(const DOMElement* e) : m_doc(NULL), m_root(e) {}
ReloadableXMLFileImpl::ReloadableXMLFileImpl(const char* pathname) : m_doc(NULL), m_root(NULL)
{
ReloadableXMLFile::ReloadableXMLFile(const DOMElement* e) : m_root(e), m_impl(NULL), m_filestamp(0), m_lock(NULL)
{
- static const XMLCh url[] = { chLatin_u, chLatin_r, chLatin_l, chNull };
+ static const XMLCh url[] = { chLatin_u, chLatin_r, chLatin_i, chNull };
const XMLCh* pathname=e->getAttributeNS(NULL,url);
if (pathname && *pathname)
{
{
try
{
- ReloadableXMLFileImpl* new_config=newImplementation(m_source.c_str());
+ ReloadableXMLFileImpl* new_config=newImplementation(m_source.c_str(),false);
delete m_impl;
m_impl=new_config;
m_filestamp=stat_buf.st_mtime;
{
if (!m_impl) {
if (m_source.empty())
- m_impl=newImplementation(m_root);
+ m_impl=newImplementation(saml::XML::getFirstChildElement(m_root));
else
m_impl=newImplementation(m_source.c_str());
}
SAMLResponse* ShibBinding::send(
SAMLRequest& req,
- const IProvider* provider,
+ const IAttributeAuthorityRole* AA,
const char* credResolverId,
+ const Iterator<const XMLCh*>& audiences,
const Iterator<SAMLAuthorityBinding*>& bindings,
SAMLConfig::SAMLBindingConfig& conf
)
{
NDC ndc("send");
+ Category& log=Category::getInstance(SHIB_LOGCAT".ShibBinding");
+
static const XMLCh VER[] = {chDigit_1, chNull};
static const saml::QName qname(saml::XML::SAMLP_NS,L(AttributeQuery));
conf.ssl_ctx_callback=reinterpret_cast<SAMLConfig::SAMLBindingConfig::ssl_ctx_callback_fn>(ssl_ctx_callback);
conf.ssl_ctx_data=this;
- m_AA=NULL;
+ m_AA=AA;
m_credResolverId=credResolverId;
- // Try to locate an AA role.
- Iterator<const IProviderRole*> roles=provider->getRoles();
- while (!m_AA && roles.hasNext()) {
- const IProviderRole* role=roles.next();
- if (dynamic_cast<const IAttributeAuthorityRole*>(role)) {
- // Check for SAML 1.x protocol support.
- Iterator<const XMLCh*> protocols=role->getProtocolSupportEnumeration();
- while (!m_AA && protocols.hasNext()) {
- if (!XMLString::compareString(protocols.next(),saml::XML::SAMLP_NS))
- m_AA=dynamic_cast<const IAttributeAuthorityRole*>(role);
- }
- }
- }
- if (!m_AA)
- throw MetadataException("ShibBinding::send() unable to locate metadata for provider's Attribute Authority");
-
// First try any bindings provided by caller.
const XMLCh* prevBinding=NULL;
Trust t(m_trusts);
auto_ptr<SAMLResponse> r(m_binding->send(*ab, req, conf));
if (r->isSigned() && !t.validate(m_revocations,m_AA,*r))
throw TrustException("ShibBinding::send() unable to verify signed response");
- Iterator<SAMLAssertion*> iter_a=r->getAssertions();
- while (iter_a.hasNext()) {
- SAMLAssertion* _a=iter_a.next();
- if (_a->isSigned() && !t.validate(m_revocations,m_AA,*_a))
- throw TrustException("ShibBinding::send() unable to verify signed assertion");
+ Iterator<SAMLAssertion*> _a=r->getAssertions();
+ for (unsigned long i=0; i < _a.size(); i++) {
+ // Check any conditions.
+ Iterator<SAMLCondition*> conds=_a[i]->getConditions();
+ while (conds.hasNext()) {
+ SAMLAudienceRestrictionCondition* cond=dynamic_cast<SAMLAudienceRestrictionCondition*>(conds.next());
+ if (!cond || !cond->eval(audiences)) {
+ log.warn("assertion condition is false, removing it");
+ r->removeAssertion(i);
+ i--;
+ break;
+ }
+ }
+
+ // Check signature.
+ if (_a[i]->isSigned() && !t.validate(m_revocations,m_AA,*(_a[i]))) {
+ log.warn("signed assertion failed to validate, removing it");
+ r->removeAssertion(i);
+ i--;
+ }
}
- return r.release();
+
+ // Any left?
+ if (r->getAssertions().size())
+ return r.release();
+ else
+ log.warn("all assertions removed from response, dumping it");
}
catch (SAMLException& e) {
- Category::getInstance(SHIB_LOGCAT".ShibBinding").error("caught SAML exception during SAML attribute query: %s", e.what());
+ log.error("caught SAML exception during SAML attribute query: %s", e.what());
}
}
auto_ptr<SAMLResponse> r(m_binding->send(ab, req, conf));
if (r->isSigned() && !t.validate(m_revocations,m_AA,*r))
throw TrustException("ShibBinding::send() unable to verify signed response");
- Iterator<SAMLAssertion*> iter_a=r->getAssertions();
- while (iter_a.hasNext()) {
- SAMLAssertion* _a=iter_a.next();
- if (_a->isSigned() && !t.validate(m_revocations,m_AA,*_a))
- throw TrustException("ShibBinding::send() unable to verify signed assertion");
+
+ Iterator<SAMLAssertion*> _a=r->getAssertions();
+ for (unsigned long i=0; i < _a.size();) {
+ // Check any conditions.
+ Iterator<SAMLCondition*> conds=_a[i]->getConditions();
+ while (conds.hasNext()) {
+ SAMLAudienceRestrictionCondition* cond=dynamic_cast<SAMLAudienceRestrictionCondition*>(conds.next());
+ if (!cond || !cond->eval(audiences)) {
+ log.warn("assertion condition is false, removing it");
+ r->removeAssertion(i);
+ }
+ }
+
+ // Check signature.
+ if (_a[i]->isSigned() && !t.validate(m_revocations,m_AA,*(_a[i]))) {
+ log.warn("signed assertion failed to validate, removing it");
+ r->removeAssertion(i);
+ }
}
- return r.release();
+
+ // Any left?
+ if (r->getAssertions().size())
+ return r.release();
+ else
+ log.warn("all assertions removed from response, dumping it");
}
catch (SAMLException& e) {
- Category::getInstance(SHIB_LOGCAT".ShibBinding").error("caught SAML exception during SAML attribute query: %s", e.what());
+ log.error("caught SAML exception during SAML attribute query: %s", e.what());
}
}
using namespace log4cpp;
using namespace std;
-SAML_EXCEPTION_FACTORY(UnsupportedProtocolException);
SAML_EXCEPTION_FACTORY(MetadataException);
SAML_EXCEPTION_FACTORY(CredentialException);
namespace {
- ShibInternalConfig g_config;
+ ShibConfig g_config;
}
-ShibConfig::~ShibConfig() {}
-
-bool ShibInternalConfig::init()
+bool ShibConfig::init()
{
- saml::NDC ndc("init");
-
- REGISTER_EXCEPTION_FACTORY(edu.internet2.middleware.shibboleth.common,UnsupportedProtocolException);
REGISTER_EXCEPTION_FACTORY(edu.internet2.middleware.shibboleth.common,MetadataException);
REGISTER_EXCEPTION_FACTORY(edu.internet2.middleware.shibboleth.common,CredentialException);
-
return true;
}
-void ShibInternalConfig::regFactory(const char* type, MetadataFactory* factory)
-{
- if (type && factory)
- m_metadataFactoryMap[type]=factory;
-}
+void ShibConfig::term() {}
-void ShibInternalConfig::regFactory(const char* type, RevocationFactory* factory)
+void PlugManager::regFactory(const char* type, Factory* factory)
{
if (type && factory)
- m_revocationFactoryMap[type]=factory;
+ m_map[type]=factory;
}
-void ShibInternalConfig::regFactory(const char* type, TrustFactory* factory)
+IPlugIn* PlugManager::newPlugin(const char* type, const DOMElement* source)
{
- if (type && factory)
- m_trustFactoryMap[type]=factory;
-}
-
-void ShibInternalConfig::regFactory(const char* type, CredentialsFactory* factory)
-{
- if (type && factory)
- {
- m_credFactoryMap[type]=factory;
- SAMLConfig::getConfig().binding_defaults.ssl_ctx_callback=
- reinterpret_cast<SAMLConfig::SAMLBindingConfig::ssl_ctx_callback_fn>(ssl_ctx_callback);
- }
-}
-
-void ShibInternalConfig::regFactory(const char* type, CredResolverFactory* factory)
-{
- if (type && factory)
- m_credResolverFactoryMap[type]=factory;
-}
-
-void ShibInternalConfig::regFactory(const char* type, AAPFactory* factory)
-{
- if (type && factory)
- m_aapFactoryMap[type]=factory;
-}
-
-void ShibInternalConfig::unregFactory(const char* type)
-{
- if (type) {
- m_metadataFactoryMap.erase(type);
- m_revocationFactoryMap.erase(type);
- m_trustFactoryMap.erase(type);
- m_credFactoryMap.erase(type);
- m_aapFactoryMap.erase(type);
- m_credResolverFactoryMap.erase(type);
- }
-}
-
-IMetadata* ShibInternalConfig::newMetadata(const char* type, const DOMElement* source) const
-{
- MetadataFactoryMap::const_iterator i=m_metadataFactoryMap.find(type);
- if (i==m_metadataFactoryMap.end())
- {
- NDC ndc("newMetadata");
- Category::getInstance(SHIB_LOGCAT".ShibInternalConfig").error("unknown metadata type: %s",type);
- return NULL;
- }
- return i->second(source);
-}
-
-IRevocation* ShibInternalConfig::newRevocation(const char* type, const DOMElement* source) const
-{
- RevocationFactoryMap::const_iterator i=m_revocationFactoryMap.find(type);
- if (i==m_revocationFactoryMap.end())
- {
- NDC ndc("newRevocation");
- Category::getInstance(SHIB_LOGCAT".ShibInternalConfig").error("unknown revocation type: %s",type);
- return NULL;
- }
- return i->second(source);
-}
-
-ITrust* ShibInternalConfig::newTrust(const char* type, const DOMElement* source) const
-{
- TrustFactoryMap::const_iterator i=m_trustFactoryMap.find(type);
- if (i==m_trustFactoryMap.end())
- {
- NDC ndc("newTrust");
- Category::getInstance(SHIB_LOGCAT".ShibInternalConfig").error("unknown trust type: %s",type);
- return NULL;
- }
- return i->second(source);
-}
-
-ICredentials* ShibInternalConfig::newCredentials(const char* type, const DOMElement* source) const
-{
- CredentialsFactoryMap::const_iterator i=m_credFactoryMap.find(type);
- if (i==m_credFactoryMap.end())
- {
- NDC ndc("newCredentials");
- Category::getInstance(SHIB_LOGCAT".ShibInternalConfig").error("unknown credentials type: %s",type);
- return NULL;
- }
- return i->second(source);
-}
-
-IAAP* ShibInternalConfig::newAAP(const char* type, const DOMElement* source) const
-{
- AAPFactoryMap::const_iterator i=m_aapFactoryMap.find(type);
- if (i==m_aapFactoryMap.end())
- {
- NDC ndc("newAAP");
- Category::getInstance(SHIB_LOGCAT".ShibInternalConfig").error("unknown AAP type: %s",type);
- return NULL;
- }
+ FactoryMap::const_iterator i=m_map.find(type);
+ if (i==m_map.end())
+ throw saml::UnsupportedExtensionException(std::string("unable to build plugin of type '") + type + "'");
return i->second(source);
}
-ICredResolver* ShibInternalConfig::newCredResolver(const char* type, const DOMElement* source) const
+void PlugManager::unregFactory(const char* type)
{
- CredResolverFactoryMap::const_iterator i=m_credResolverFactoryMap.find(type);
- if (i==m_credResolverFactoryMap.end())
- {
- NDC ndc("newCredResolver");
- Category::getInstance(SHIB_LOGCAT".ShibInternalConfig").error("unknown cred resolver type: %s",type);
- return NULL;
- }
- return i->second(source);
+ if (type)
+ m_map.erase(type);
}
ShibConfig& ShibConfig::getConfig()
const XMLCh* ShibPOSTProfile::getProviderId(const saml::SAMLResponse& r)
{
+ // Favor an AuthnStatement Subject NameQualifier, but use Issuer if need be.
+ const XMLCh* ret=NULL;
Iterator<SAMLAssertion*> ia=r.getAssertions();
while (ia.hasNext()) {
- Iterator<SAMLStatement*> is=ia.next()->getStatements();
+ SAMLAssertion* a=ia.next();
+ ret=a->getIssuer();
+ Iterator<SAMLStatement*> is=a->getStatements();
while (is.hasNext()) {
- SAMLStatement* s=is.next();
- SAMLAuthenticationStatement* as=dynamic_cast<SAMLAuthenticationStatement*>(s);
- if (as)
+ SAMLAuthenticationStatement* as=dynamic_cast<SAMLAuthenticationStatement*>(is.next());
+ if (as && as->getSubject()->getNameQualifier())
return as->getSubject()->getNameQualifier();
}
}
- return NULL;
+ return ret;
}
SAMLResponse* ShibPOSTProfile::accept(
while (roles.hasNext()) {
const IProviderRole* role=roles.next();
if (dynamic_cast<const IIDPProviderRole*>(role)) {
- const IProviderRole* IDP=dynamic_cast<const IProviderRole*>(role);
- // Check for SAML 1.x protocol support.
- Iterator<const XMLCh*> protocols=IDP->getProtocolSupportEnumeration();
- while (protocols.hasNext()) {
- if (!XMLString::compareString(protocols.next(),Constants::SHIB_NS)) {
- log.debug("passing response to trust layer");
-
- // Use this role to evaluate the signature.
- Trust t(m_trusts);
- if (!t.validate(m_revocations,role,*r))
- throw TrustException("ShibPOSTProfile::accept() unable to verify signed response");
-
- // Assertion(s) signed?
- Iterator<SAMLAssertion*> itera=r->getAssertions();
- while (itera.hasNext()) {
- SAMLAssertion* _a=itera.next();
- if (_a->isSigned()) {
- log.debug("passing signed assertion to trust layer");
- if (!t.validate(m_revocations,role,*_a))
- throw TrustException("ShibPOSTProfile::accept() unable to verify signed assertion");
- }
+ // Check for Shibboleth 1.x protocol support.
+ if (role->hasSupport(Constants::SHIB_NS)) {
+ log.debug("passing response to trust layer");
+
+ // Use this role to evaluate the signature.
+ Trust t(m_trusts);
+ if (!t.validate(m_revocations,role,*r))
+ throw TrustException("ShibPOSTProfile::accept() unable to verify signed response");
+
+ // Assertion(s) signed?
+ Iterator<SAMLAssertion*> itera=r->getAssertions();
+ while (itera.hasNext()) {
+ SAMLAssertion* _a=itera.next();
+ if (_a->isSigned()) {
+ log.debug("passing signed assertion to trust layer");
+ if (!t.validate(m_revocations,role,*_a))
+ throw TrustException("ShibPOSTProfile::accept() unable to verify signed assertion");
}
- return r.release();
}
+ return r.release();
}
}
}
namespace shibboleth
{
+ /*
class ShibInternalConfig : public ShibConfig
{
public:
AAPFactoryMap m_aapFactoryMap;
CredResolverFactoryMap m_credResolverFactoryMap;
};
+ */
// OpenSSL Utilities
virtual ~name() throw () {} \
}
- DECLARE_SHIB_EXCEPTION(UnsupportedProtocolException,SAMLException);
DECLARE_SHIB_EXCEPTION(MetadataException,SAMLException);
DECLARE_SHIB_EXCEPTION(CredentialException,SAMLException);
+ // Manages pluggable implementations of interfaces
+ // Would prefer this to be a template, but the Windows STL isn't DLL-safe.
+
+ struct SHIB_EXPORTS IPlugIn
+ {
+ virtual ~IPlugIn() {}
+ };
+
+ class SHIB_EXPORTS PlugManager
+ {
+ public:
+ PlugManager() {}
+ ~PlugManager() {}
+
+ typedef IPlugIn* Factory(const DOMElement* source);
+ void regFactory(const char* type, Factory* factory);
+ void unregFactory(const char* type);
+ IPlugIn* newPlugin(const char* type, const DOMElement* source);
+
+ private:
+ typedef std::map<std::string, Factory*> FactoryMap;
+ FactoryMap m_map;
+ };
+
// Metadata abstract interfaces, inching toward SAML 2.0...
struct SHIB_EXPORTS ILockable
{
virtual const IProvider* getProvider() const=0;
virtual saml::Iterator<const XMLCh*> getProtocolSupportEnumeration() const=0;
+ virtual bool hasSupport(const XMLCh* version) const=0;
virtual saml::Iterator<const IKeyDescriptor*> getKeyDescriptors() const=0;
virtual const IOrganization* getOrganization() const=0;
virtual saml::Iterator<const IContactPerson*> getContacts() const=0;
virtual ~IProvider() {}
};
- struct SHIB_EXPORTS IMetadata : public virtual ILockable
+ struct SHIB_EXPORTS IMetadata : public virtual ILockable, public virtual IPlugIn
{
virtual const IProvider* lookup(const XMLCh* providerId) const=0;
virtual ~IMetadata() {}
};
- struct SHIB_EXPORTS IRevocation : public virtual ILockable
+ struct SHIB_EXPORTS IRevocation : public virtual ILockable, public virtual IPlugIn
{
virtual saml::Iterator<void*> getRevocationLists(const IProvider* provider, const IProviderRole* role=NULL) const=0;
virtual ~IRevocation() {}
// Trust interface hides *all* details of signature and SSL validation.
// Pluggable providers can fully override the Shibboleth trust model here.
- struct SHIB_EXPORTS ITrust : public virtual ILockable
+ struct SHIB_EXPORTS ITrust : public virtual IPlugIn
{
virtual bool validate(
const saml::Iterator<IRevocation*>& revocations,
const IProviderRole* role, const saml::SAMLSignedObject& token,
const saml::Iterator<IMetadata*>& metadatas=EMPTY(IMetadata*)
- ) const=0;
- virtual bool attach(const saml::Iterator<IRevocation*>& revocations, const IProviderRole* role, void* ctx) const=0;
+ )=0;
+ virtual bool attach(const saml::Iterator<IRevocation*>& revocations, const IProviderRole* role, void* ctx)=0;
virtual ~ITrust() {}
};
- struct SHIB_EXPORTS ICredResolver
+ struct SHIB_EXPORTS ICredResolver : public virtual IPlugIn
{
virtual void attach(void* ctx) const=0;
virtual XSECCryptoKey* getKey() const=0;
virtual ~ICredResolver() {}
};
- struct SHIB_EXPORTS ICredentials : public virtual ILockable
+ struct SHIB_EXPORTS ICredentials : public virtual ILockable, public virtual IPlugIn
{
virtual const ICredResolver* lookup(const char* id) const=0;
virtual ~ICredentials() {}
virtual ~IAttributeRule() {}
};
- struct SHIB_EXPORTS IAAP : public virtual ILockable
+ struct SHIB_EXPORTS IAAP : public virtual ILockable, public virtual IPlugIn
{
virtual const IAttributeRule* lookup(const XMLCh* attrName, const XMLCh* attrNamespace=NULL) const=0;
virtual const IAttributeRule* lookup(const char* alias) const=0;
// Glue classes between abstract metadata and concrete providers
+ class SHIB_EXPORTS Locker
+ {
+ public:
+ Locker(ILockable* lockee) : m_lockee(lockee) {m_lockee->lock();}
+ ~Locker() {if (m_lockee) m_lockee->unlock();}
+
+ private:
+ Locker(const Locker&);
+ void operator=(const Locker&);
+ ILockable* m_lockee;
+ };
+
class SHIB_EXPORTS Metadata
{
public:
saml::SAMLResponse* send(
saml::SAMLRequest& req,
- const IProvider* provider,
+ const IAttributeAuthorityRole* AA,
const char* credResolverId=NULL,
+ const saml::Iterator<const XMLCh*>& audiences=EMPTY(const XMLCh*),
const saml::Iterator<saml::SAMLAuthorityBinding*>& bindings=EMPTY(saml::SAMLAuthorityBinding*),
saml::SAMLConfig::SAMLBindingConfig& conf=saml::SAMLConfig::getConfig().binding_defaults
);
saml::SAMLBinding* m_binding;
};
- extern "C" {
- typedef IMetadata* MetadataFactory(const DOMElement* source);
- typedef IRevocation* RevocationFactory(const DOMElement* source);
- typedef ITrust* TrustFactory(const DOMElement* source);
- typedef ICredentials* CredentialsFactory(const DOMElement* source);
- typedef IAAP* AAPFactory(const DOMElement* source);
- typedef ICredResolver* CredResolverFactory(const DOMElement* source);
- }
-
class SHIB_EXPORTS ShibConfig
{
public:
ShibConfig() {}
- virtual ~ShibConfig();
+ virtual ~ShibConfig() {}
// global per-process setup and shutdown of Shibboleth runtime
- virtual bool init()=0;
- virtual void term()=0;
+ virtual bool init();
+ virtual void term();
// enables runtime and clients to access configuration
static ShibConfig& getConfig();
// allows pluggable implementations of metadata and configuration data
- virtual void regFactory(const char* type, MetadataFactory* factory)=0;
- virtual void regFactory(const char* type, RevocationFactory* factory)=0;
- virtual void regFactory(const char* type, TrustFactory* factory)=0;
- virtual void regFactory(const char* type, CredentialsFactory* factory)=0;
- virtual void regFactory(const char* type, AAPFactory* factory)=0;
- virtual void regFactory(const char* type, CredResolverFactory* factory)=0;
- virtual void unregFactory(const char* type)=0;
-
- // build a specific metadata lookup object
- virtual IMetadata* newMetadata(const char* type, const DOMElement* source) const=0;
- virtual IRevocation* newRevocation(const char* type, const DOMElement* source) const=0;
- virtual ITrust* newTrust(const char* type, const DOMElement* source) const=0;
- virtual ICredentials* newCredentials(const char* type, const DOMElement* source) const=0;
- virtual IAAP* newAAP(const char* type, const DOMElement* source) const=0;
- virtual ICredResolver* newCredResolver(const char* type, const DOMElement* source) const=0;
+ PlugManager m_plugMgr;
};
/* Helper classes for implementing reloadable XML-based config files
ReloadableXMLFileImpl* getImplementation() const;
protected:
- virtual ReloadableXMLFileImpl* newImplementation(const char* pathname) const=0;
- virtual ReloadableXMLFileImpl* newImplementation(const DOMElement* e) const=0;
+ virtual ReloadableXMLFileImpl* newImplementation(const char* pathname, bool first=true) const=0;
+ virtual ReloadableXMLFileImpl* newImplementation(const DOMElement* e, bool first=true) const=0;
+ mutable ReloadableXMLFileImpl* m_impl;
private:
const DOMElement* m_root;
std::string m_source;
time_t m_filestamp;
RWLock* m_lock;
- mutable ReloadableXMLFileImpl* m_impl;
};
}