</Extensions>
-->
- <!-- The OutOfProcess section pertains to components that rely on a single long-lived process. -->
+ <!-- The OutOfProcess section pertains to components that run in the shibd daemon. -->
<OutOfProcess logger="@-PKGSYSCONFDIR-@/shibd.logger">
<!--
-->
</OutOfProcess>
- <!-- The InProcess section pertains to components that support transient process pools like most web servers. -->
+ <!-- The InProcess section pertains to components that run inside the web server. -->
<InProcess logger="@-PKGSYSCONFDIR-@/native.logger">
<!--
To customize behavior, map hostnames and path components to applicationId and other settings.
supportContact="root@localhost"
logoLocation="/shibboleth-sp/logo.jpg"
styleSheet="/shibboleth-sp/main.css"/>
+
+ <!-- Configure handling of outgoing messages. -->
+ <DefaultRelyingParty authType="TLS" signRequests="false" encryptRequests="true"/>
- <!-- Indicates what credentials to use when communicating -->
- <CredentialUse TLS="defcreds" Signing="defcreds" Encryption="defcreds"/>
-
- <!-- When adding multiple metadata sources, uncomment the chained provider around them. -->
- <!-- <MetadataProvider type="Chaining"> -->
+ <!-- Chains together all your metadata sources. -->
+ <MetadataProvider type="Chaining">
<!-- Dummy metadata for private testing, delete for production deployments. -->
<MetadataProvider type="XML" path="@-PKGSYSCONFDIR-@/example-metadata.xml"/>
- <!-- </MetadataProvider> -->
+ </MetadataProvider>
<!-- Chain the two built-in trust engines together. -->
<TrustEngine type="Chaining">
<TrustEngine type="PKIX"/>
</TrustEngine>
+ <!-- Built-in attribute resolver to extract data from SAML assertions. -->
<AttributeResolver type="Simple" path="@-PKGSYSCONFDIR-@/resolver-simple.xml"/>
- </Applications>
-
- <!-- Define all the private keys and certificates here that you reference from <CredentialUse>. -->
- <Credentials>
- <CredentialResolver id="defcreds">
+
+ <!-- Simple file-based resolver for key/certificate information. -->
+ <CredentialResolver type="File">
<Key>
<Path>@-PKGSYSCONFDIR-@/sp-example.key</Path>
</Key>
<Path>@-PKGSYSCONFDIR-@/sp-example.crt</Path>
</Certificate>
</CredentialResolver>
- </Credentials>
-
+ </Applications>
+
<!-- Each policy defines a set of rules to use to secure SAML and SOAP messages. -->
<SecurityPolicies>
<!-- The predefined policy handles SAML 1 and 2 protocols and permits signing and client TLS. -->
#include <xmltooling/unicode.h>
#include <xmltooling/XMLToolingConfig.h>
#include <xmltooling/util/NDC.h>
+#include <xmltooling/util/XMLConstants.h>
#include <xmltooling/util/XMLHelper.h>
#include <xercesc/util/XMLUniDefs.hpp>
#include <xmltooling/XMLToolingConfig.h>
#include <xmltooling/util/NDC.h>
#include <xmltooling/util/Threads.h>
+#include <xmltooling/util/XMLConstants.h>
#include <xmltooling/util/XMLHelper.h>
#include <xercesc/util/XMLUniDefs.hpp>
<element ref="conf:OutOfProcess"/>
<element ref="conf:InProcess"/>
<element ref="conf:Applications"/>
- <element ref="conf:Credentials" minOccurs="0"/>
<element ref="conf:SecurityPolicies"/>
</sequence>
<attribute name="logger" type="anyURI"/>
<sequence>\r
<element ref="conf:Sessions"/>\r
<element ref="conf:Errors"/>\r
- <element ref="conf:CredentialUse" minOccurs="0"/>\r
+ <element ref="conf:DefaultRelyingParty"/>\r
<element ref="saml:Audience" minOccurs="0" maxOccurs="unbounded"/>
<element name="MetadataProvider" type="conf:PluggableType"/>
<element name="TrustEngine" type="conf:PluggableType"/>\r
<element name="AttributeResolver" type="conf:PluggableType"/>\r
+ <element name="CredentialResolver" type="conf:PluggableType" minOccurs="0"/>\r
<element ref="conf:Application" minOccurs="0" maxOccurs="unbounded"/>\r
</sequence>\r
<attribute name="id" type="conf:string" fixed="default"/>\r
<sequence>\r
<element ref="conf:Sessions" minOccurs="0"/>\r
<element ref="conf:Errors" minOccurs="0"/>\r
- <element ref="conf:CredentialUse" minOccurs="0"/>\r
+ <element ref="conf:DefaultRelyingParty" minOccurs="0"/>\r
<element ref="saml:Audience" minOccurs="0" maxOccurs="unbounded"/>\r
<element name="MetadataProvider" type="conf:PluggableType" minOccurs="0"/>\r
<element name="TrustEngine" type="conf:PluggableType" minOccurs="0"/>\r
<element name="AttributeResolver" type="conf:PluggableType" minOccurs="0"/>\r
+ <element name="CredentialResolver" type="conf:PluggableType" minOccurs="0"/>\r
</sequence>\r
<attribute name="id" type="conf:string" use="required"/>\r
<attribute name="providerId" type="anyURI"/>\r
</complexType>\r
</element>\r
\r
- <attributeGroup name="CredentialUseGroup">\r
- <attribute name="TLS" type="conf:string"/>\r
- <attribute name="Signing" type="conf:string"/>\r
- <attribute name="Encryption" type="conf:string"/>\r
- <attribute name="signRequests" type="boolean" default="false"/>\r
- <attribute name="signatureAlg" type="anyURI"/>\r
- <attribute name="authType">\r
- <simpleType>\r
- <restriction base="conf:string">\r
- <enumeration value="basic"/>\r
- <enumeration value="digest"/>\r
- <enumeration value="ntlm"/>\r
- <enumeration value="gss"/>\r
- </restriction>\r
- </simpleType>\r
- </attribute>\r
- <attribute name="authUsername"/>\r
- <attribute name="authPassword"/>\r
- </attributeGroup>\r
-\r
- <element name="CredentialUse">\r
+ <element name="DefaultRelyingParty">\r
<annotation>\r
<documentation>Container for specifying security methods to use with particular peers</documentation>\r
</annotation>\r
<sequence>\r
<element name="RelyingParty" minOccurs="0" maxOccurs="unbounded">\r
<complexType>\r
- <sequence>\r
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
- </sequence>\r
+ <sequence/>\r
<attribute name="Name" type="conf:string" use="required"/>\r
- <attributeGroup ref="conf:CredentialUseGroup"/>\r
+ <attributeGroup ref="conf:RelyingPartyGroup"/>\r
<anyAttribute namespace="##other" processContents="lax"/>\r
</complexType>\r
</element>\r
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
</sequence>\r
- <attributeGroup ref="conf:CredentialUseGroup"/>\r
+ <attributeGroup ref="conf:RelyingPartyGroup"/>\r
<anyAttribute namespace="##other" processContents="lax"/>\r
</complexType>\r
</element>\r
\r
- <element name="Credentials">
- <annotation>\r
- <documentation>Container for specifying sources of credentials</documentation>\r
- </annotation>\r
- <complexType>\r
- <sequence>\r
- <element name="CredentialResolver" minOccurs="1" maxOccurs="unbounded">
- <annotation>\r
- <documentation>References CredentialResolver plugins</documentation>\r
- </annotation>\r
- <complexType>
- <complexContent>
- <restriction base="conf:PluggableType">
- <sequence>
- <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </sequence>
- <attribute name="id" type="conf:string" use="required"/>\r
- <anyAttribute namespace="##any" processContents="lax"/>
- </restriction>
- </complexContent>
- </complexType>
- </element>\r
- </sequence>
- </complexType>
- </element>\r
+ <attributeGroup name="RelyingPartyGroup">\r
+ <attribute name="authType" type="conf:string" default="TLS"/>\r
+ <attribute name="authUsername" type="conf:string"/>\r
+ <attribute name="authPassword" type="conf:string"/>\r
+ <attribute name="signRequests" type="boolean" default="false"/>
+ <attribute name="signatureAlg" type="anyURI"/>\r
+ <attribute name="encryptRequests" type="boolean" default="true"/>\r
+ </attributeGroup>\r
\r
<element name="SecurityPolicies">
<annotation>\r
#include <shibsp/remoting/ListenerService.h>\r
#include <xercesc/util/XMLUniDefs.hpp>\r
#include <xmltooling/XMLToolingConfig.h>\r
+#include <xmltooling/util/XMLConstants.h>\r
#include <xmltooling/util/XMLHelper.h>\r
\r
using namespace shibsp;\r
#include <shibsp/util/PropertySet.h>
#include <saml/saml2/metadata/MetadataProvider.h>
+#include <xmltooling/security/CredentialResolver.h>
#include <xmltooling/security/TrustEngine.h>
namespace shibsp {
virtual AttributeResolver* getAttributeResolver() const=0;
/**
- * Returns configuration properties governing security interactions with a peer entity.
+ * Returns the CredentialResolver instance associated with this Application.
+ *
+ * @return a CredentialResolver, or NULL
+ */
+ virtual xmltooling::CredentialResolver* getCredentialResolver() const=0;
+
+ /**
+ * Returns configuration properties governing security interactions with a peer.
*
* @param provider a peer entity's metadata
* @return the applicable PropertySet
*/
- virtual const PropertySet* getCredentialUse(const opensaml::saml2md::EntityDescriptor* provider) const=0;
+ virtual const PropertySet* getRelyingParty(const opensaml::saml2md::EntityDescriptor* provider) const=0;
/**
* Returns the default SessionInitiator Handler when automatically
#include <shibsp/util/PropertySet.h>
#include <saml/binding/SecurityPolicyRule.h>
-#include <xmltooling/security/CredentialResolver.h>
+#include <xmltooling/Lockable.h>
#include <xmltooling/util/StorageService.h>
namespace shibsp {
virtual ListenerService* getListenerService(bool required=true) const=0;
/**
- * Returns a CredentialResolver instance mapped to a key.
- *
- * @param id a NULL-terminated key identifying the CredentialResolver to the configuration
- * @return a CredentialResolver if available, or NULL
- */
- virtual xmltooling::CredentialResolver* getCredentialResolver(const char* id) const=0;
-
- /**
* Returns the security policy settings for an identified policy.
*
* @param id identifies the policy to return
}\r
}\r
\r
- CredentialResolver* cr=NULL;\r
const vector<saml2::EncryptedAttribute*>& encattrs = const_cast<const saml2::AttributeStatement*>(*s)->getEncryptedAttributes();\r
if (!encattrs.empty()) {\r
- const PropertySet* credUse = ctx.getApplication().getCredentialUse(ctx.getEntityDescriptor());\r
- if (credUse)\r
- cr = ctx.getApplication().getServiceProvider().getCredentialResolver(credUse->getString("Encryption").second);\r
+ const XMLCh* recipient = ctx.getApplication().getXMLString("providerId").second;\r
+ CredentialResolver* cr = ctx.getApplication().getCredentialResolver();\r
if (!cr) {\r
Category::getInstance(SHIBSP_LOGCAT".AttributeResolver").warn(\r
- "found encrypted attributes, but no decryption credential was available"\r
+ "found encrypted attributes, but no CredentialResolver was available"\r
);\r
return;\r
}\r
+\r
+ // We look up credentials based on the peer who did the encrypting.\r
+ CredentialCriteria cc;\r
+ cc.setPeerName(assertingParty.get());\r
+\r
Locker credlocker(cr);\r
- const XMLCh* recipient = ctx.getApplication().getXMLString("providerId").second;\r
for (vector<saml2::EncryptedAttribute*>::const_iterator ea = encattrs.begin(); ea!=encattrs.end(); ++ea) {\r
- auto_ptr<XMLObject> decrypted((*ea)->decrypt(cr, recipient));\r
+ auto_ptr<XMLObject> decrypted((*ea)->decrypt(*cr, recipient, &cc));\r
const saml2::Attribute* decattr = dynamic_cast<const saml2::Attribute*>(decrypted.get());\r
name = decattr->getName();\r
format = decattr->getNameFormat();\r
}\r
\r
SecurityPolicy policy;\r
+ MetadataCredentialCriteria mcc(*AA);\r
shibsp::SOAPClient soaper(ctx.getApplication(),policy);\r
const PropertySet* policySettings = ctx.getApplication().getServiceProvider().getPolicySettings(ctx.getApplication().getString("policyId").second);\r
pair<bool,bool> signedAssertions = policySettings->getBool("signedAssertions");\r
query->setResource(issuer.get());\r
request->setMinorVersion(version);\r
SAML1SOAPClient client(soaper);\r
- client.sendSAML(request, *AA, loc.get());\r
+ client.sendSAML(request, mcc, loc.get());\r
response = client.receiveSAML();\r
}\r
catch (exception& ex) {\r
}\r
\r
SecurityPolicy policy;\r
+ MetadataCredentialCriteria mcc(*AA);\r
shibsp::SOAPClient soaper(ctx.getApplication(),policy);\r
const PropertySet* policySettings = ctx.getApplication().getServiceProvider().getPolicySettings(ctx.getApplication().getString("policyId").second);\r
pair<bool,bool> signedAssertions = policySettings->getBool("signedAssertions");\r
query->setIssuer(iss);\r
iss->setName(issuer.get());\r
SAML2SOAPClient client(soaper);\r
- client.sendSAML(query, *AA, loc.get());\r
+ client.sendSAML(query, mcc, loc.get());\r
srt = client.receiveSAML();\r
}\r
catch (exception& ex) {\r
* Override handles message signing for SAML payloads.
*
* @param env SOAP envelope to send
- * @param peer peer to send message to, expressed in TrustEngine terms
+ * @param peer peer to send message to, expressed in metadata terms
* @param endpoint URL of endpoint to recieve message
*/
- void send(const soap11::Envelope& env, const xmltooling::KeyInfoSource& peer, const char* endpoint);
+ void send(const soap11::Envelope& env, opensaml::saml2md::MetadataCredentialCriteria& peer, const char* endpoint);
void reset();
/** Properties associated with the Application's security policy. */
const PropertySet* m_settings;
- /** CredentialUse properties, set after transport prep. */
- const PropertySet* m_credUse;
+ /** RelyingParty properties, set after transport prep. */
+ const PropertySet* m_relyingParty;
/** Locked CredentialResolver for transport, set after transport prep. */
xmltooling::CredentialResolver* m_credResolver;
using namespace log4cpp;
using namespace std;
-namespace {
- class SHIBSP_DLLLOCAL _addcert : public binary_function<X509Data*,XSECCryptoX509*,void> {
- public:
- void operator()(X509Data* bag, XSECCryptoX509* cert) const {
- safeBuffer& buf=cert->getDEREncodingSB();
- X509Certificate* x=X509CertificateBuilder::buildX509Certificate();
- x->setValue(buf.sbStrToXMLCh());
- bag->getX509Certificates().push_back(x);
- }
- };
-};
-
SOAPClient::SOAPClient(const Application& application, opensaml::SecurityPolicy& policy)
- : opensaml::SOAPClient(policy), m_app(application), m_settings(NULL), m_credUse(NULL), m_credResolver(NULL)
+ : opensaml::SOAPClient(policy), m_app(application), m_settings(NULL), m_relyingParty(NULL), m_credResolver(NULL)
{
pair<bool,const char*> policyId = m_app.getString("policyId");
m_settings = application.getServiceProvider().getPolicySettings(policyId.second);
setValidating(validate.first && validate.second);
}
-void SOAPClient::send(const soap11::Envelope& env, const KeyInfoSource& peer, const char* endpoint)
+void SOAPClient::send(const soap11::Envelope& env, MetadataCredentialCriteria& peer, const char* endpoint)
{
- if (!m_peer)
- m_peer = dynamic_cast<const RoleDescriptor*>(&peer);
-
- if (m_peer) {
- const EntityDescriptor* entity = m_peer ? dynamic_cast<const EntityDescriptor*>(m_peer->getParent()) : NULL;
- m_credUse = entity ? m_app.getCredentialUse(entity) : NULL;
- }
-
// Check for message signing requirements.
- if (m_credUse) {
- pair<bool,bool> flag = m_credUse->getBool("signRequests");
- if (flag.first && flag.second) {
- CredentialResolver* cr=NULL;
- pair<bool,const char*> cred = m_credUse->getString("Signing");
- if (cred.first && (cr=m_app.getServiceProvider().getCredentialResolver(cred.second))) {
- // Looks like we're supposed to sign, so check for message.
+ m_relyingParty = m_app.getRelyingParty(dynamic_cast<const EntityDescriptor*>(peer.getRole().getParent()));
+ pair<bool,bool> flag = m_relyingParty->getBool("signRequests");
+ if (flag.first && flag.second) {
+ m_credResolver=m_app.getCredentialResolver();
+ if (m_credResolver) {
+ m_credResolver->lock();
+ // Fill in criteria to use.
+ peer.setUsage(CredentialCriteria::SIGNING_CREDENTIAL);
+ pair<bool,const char*> algcrit = m_relyingParty->getString("sigAlgorithm");
+ if (algcrit.first)
+ peer.setKeyAlgorithm(algcrit.second);
+ const Credential* cred = m_credResolver->resolve(&peer);
+ peer.setKeyAlgorithm(NULL);
+
+ if (cred) {
+ // Check for message.
const vector<XMLObject*>& bodies=const_cast<const soap11::Body*>(env.getBody())->getUnknownXMLObjects();
if (!bodies.empty()) {
opensaml::SignableObject* msg = dynamic_cast<opensaml::SignableObject*>(bodies.front());
// Build a Signature.
Signature* sig = SignatureBuilder::buildSignature();
msg->setSignature(sig);
- pair<bool,const XMLCh*> alg = m_credUse->getXMLString("sigAlgorithm");
+ pair<bool,const XMLCh*> alg = m_relyingParty->getXMLString("sigAlgorithm");
if (alg.first)
sig->setSignatureAlgorithm(alg.second);
- Locker locker(cr);
- sig->setSigningKey(cr->getKey());
-
- // Build KeyInfo.
- const vector<XSECCryptoX509*>& certs = cr->getCertificates();
- if (!certs.empty()) {
- KeyInfo* keyInfo=KeyInfoBuilder::buildKeyInfo();
- sig->setKeyInfo(keyInfo);
- X509Data* x509Data=X509DataBuilder::buildX509Data();
- keyInfo->getX509Datas().push_back(x509Data);
- for_each(certs.begin(),certs.end(),bind1st(_addcert(),x509Data));
- }
// Sign it. The marshalling step in the base class should be a no-op.
vector<Signature*> sigs(1,sig);
- env.marshall((DOMDocument*)NULL,&sigs);
+ env.marshall((DOMDocument*)NULL,&sigs,cred);
}
}
}
+ else {
+ Category::getInstance(SHIBSP_LOGCAT".SOAPClient").error("no signing credential supplied, leaving unsigned.");
+ }
+ }
+ else {
+ Category::getInstance(SHIBSP_LOGCAT".SOAPClient").error("no CredentialResolver available, leaving unsigned.");
}
}
opensaml::SOAPClient::prepareTransport(transport);
- if (!m_credUse) {
- const EntityDescriptor* entity = m_peer ? dynamic_cast<const EntityDescriptor*>(m_peer->getParent()) : NULL;
- m_credUse = entity ? m_app.getCredentialUse(entity) : NULL;
- }
- if (m_credUse) {
- pair<bool,const char*> authType=m_credUse->getString("authType");
- if (authType.first) {
- SOAPTransport::transport_auth_t type=SOAPTransport::transport_auth_none;
- pair<bool,const char*> username=m_credUse->getString("authUsername");
- pair<bool,const char*> password=m_credUse->getString("authPassword");
- if (!username.first || !password.first)
- log.error("transport authType (%s) specified but authUsername or authPassword was missing", authType.second);
- else if (!strcmp(authType.second,"basic"))
- type = SOAPTransport::transport_auth_basic;
- else if (!strcmp(authType.second,"digest"))
- type = SOAPTransport::transport_auth_digest;
- else if (!strcmp(authType.second,"ntlm"))
- type = SOAPTransport::transport_auth_ntlm;
- else if (!strcmp(authType.second,"gss"))
- type = SOAPTransport::transport_auth_gss;
- else
- log.error("unknown authType (%s) specified in CredentialUse element", authType.second);
- if (type > SOAPTransport::transport_auth_none) {
- if (transport.setAuth(type,username.second,password.second))
- log.debug("configured for transport authentication (method=%s, username=%s)", authType.second, username.second);
- else
- log.error("failed to configure transport authentication (method=%s)", authType.second);
- }
- }
-
- authType = m_credUse->getString("TLS");
- if (authType.first) {
- m_credResolver = m_app.getServiceProvider().getCredentialResolver(authType.second);
- if (m_credResolver) {
+ pair<bool,const char*> authType=m_relyingParty->getString("authType");
+ if (!authType.first || !strcmp(authType.second,"TLS")) {
+ if (!m_credResolver) {
+ m_credResolver = m_app.getCredentialResolver();
+ if (m_credResolver)
m_credResolver->lock();
- if (!transport.setCredentialResolver(m_credResolver)) {
- m_credResolver->unlock();
- m_credResolver = NULL;
- log.error("failed to load CredentialResolver into SOAPTransport");
- }
+ }
+ if (m_credResolver) {
+ m_criteria->setUsage(CredentialCriteria::TLS_CREDENTIAL);
+ const Credential* cred = m_credResolver->resolve(m_criteria);
+ if (cred) {
+ if (!transport.setCredential(cred))
+ log.error("failed to load Credential into SOAPTransport");
}
else {
- log.error("unable to access CredentialResolver (%s)", authType.second);
+ log.error("no TLS credential supplied");
}
}
- }
-
+ else {
+ log.error("no CredentialResolver available for TLS");
+ }
+ }
+ else {
+ SOAPTransport::transport_auth_t type=SOAPTransport::transport_auth_none;
+ pair<bool,const char*> username=m_relyingParty->getString("authUsername");
+ pair<bool,const char*> password=m_relyingParty->getString("authPassword");
+ if (!username.first || !password.first)
+ log.error("transport authType (%s) specified but authUsername or authPassword was missing", authType.second);
+ else if (!strcmp(authType.second,"basic"))
+ type = SOAPTransport::transport_auth_basic;
+ else if (!strcmp(authType.second,"digest"))
+ type = SOAPTransport::transport_auth_digest;
+ else if (!strcmp(authType.second,"ntlm"))
+ type = SOAPTransport::transport_auth_ntlm;
+ else if (!strcmp(authType.second,"gss"))
+ type = SOAPTransport::transport_auth_gss;
+ else
+ log.error("unknown authType (%s) specified for RelyingParty", authType.second);
+ if (type > SOAPTransport::transport_auth_none) {
+ if (transport.setAuth(type,username.second,password.second))
+ log.debug("configured for transport authentication (method=%s, username=%s)", authType.second, username.second);
+ else
+ log.error("failed to configure transport authentication (method=%s)", authType.second);
+ }
+ }
+
transport.setConnectTimeout(m_settings->getUnsignedInt("connectTimeout").second);
transport.setTimeout(m_settings->getUnsignedInt("timeout").second);
void SOAPClient::reset()
{
- m_credUse = NULL;
+ m_relyingParty = NULL;
if (m_credResolver)
m_credResolver->unlock();
m_credResolver = NULL;
badtokens.push_back(*a);
}
}
-\r
- CredentialResolver* cr=NULL;\r
- const PropertySet* credUse = application.getCredentialUse(\r
- policy.getIssuerMetadata() ? dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent()) : NULL\r
- );\r
- if (credUse)\r
- cr = application.getServiceProvider().getCredentialResolver(credUse->getString("Encryption").second);
+
+ // We look up decryption credentials based on the peer who did the encrypting.
+ CredentialCriteria cc;
+ if (policy.getIssuerMetadata()) {
+ auto_ptr_char assertingParty(dynamic_cast<const EntityDescriptor*>(policy.getIssuerMetadata()->getParent())->getEntityID());
+ cc.setPeerName(assertingParty.get());
+ }
+ CredentialResolver* cr=application.getCredentialResolver();
+
if (!cr && !encassertions.empty())
- m_log.warn("found encrypted assertions, but no decryption credential was available");
+ m_log.warn("found encrypted assertions, but no CredentialResolver was available");
for (vector<saml2::EncryptedAssertion*>::const_iterator ea = encassertions.begin(); cr && ea!=encassertions.end(); ++ea) {
// Attempt to decrypt it.
saml2::Assertion* decrypted=NULL;
try {
Locker credlocker(cr);
- auto_ptr<XMLObject> wrapper((*ea)->decrypt(cr, application.getXMLString("providerId").second));
+ auto_ptr<XMLObject> wrapper((*ea)->decrypt(*cr, application.getXMLString("providerId").second, &cc));
decrypted = dynamic_cast<saml2::Assertion*>(wrapper.get());
if (decrypted) {
wrapper.release();
else {
Locker credlocker(cr);
try {
- auto_ptr<XMLObject> decryptedID(encname->decrypt(cr,application.getXMLString("providerId").second));
+ auto_ptr<XMLObject> decryptedID(encname->decrypt(*cr,application.getXMLString("providerId").second,&cc));
ssoName = dynamic_cast<NameID*>(decryptedID.get());
if (ssoName) {
ownedName = true;
AttributeResolver* getAttributeResolver() const {\r
return (!m_attrResolver && m_base) ? m_base->getAttributeResolver() : m_attrResolver;\r
}\r
-\r
- const PropertySet* getCredentialUse(const EntityDescriptor* provider) const;\r
+ CredentialResolver* getCredentialResolver() const {\r
+ return (!m_credResolver && m_base) ? m_base->getCredentialResolver() : m_credResolver;\r
+ }\r
+ const PropertySet* getRelyingParty(const EntityDescriptor* provider) const;\r
\r
const Handler* getDefaultSessionInitiator() const;\r
const Handler* getSessionInitiatorById(const char* id) const;\r
MetadataProvider* m_metadata;\r
TrustEngine* m_trust;\r
AttributeResolver* m_attrResolver;\r
+ CredentialResolver* m_credResolver;\r
vector<const XMLCh*> m_audiences;\r
\r
// manage handler objects\r
// pointer to default session initiator\r
const Handler* m_sessionInitDefault;\r
\r
- DOMPropertySet* m_credDefault;\r
+ // RelyingParty properties\r
+ DOMPropertySet* m_partyDefault;\r
#ifdef HAVE_GOOD_STL\r
- map<xstring,PropertySet*> m_credMap;\r
+ map<xstring,PropertySet*> m_partyMap;\r
#else\r
- map<const XMLCh*,PropertySet*> m_credMap;\r
+ map<const XMLCh*,PropertySet*> m_partyMap;\r
#endif\r
};\r
\r
\r
RequestMapper* m_requestMapper;\r
map<string,Application*> m_appmap;\r
- map<string,CredentialResolver*> m_credResolverMap;\r
map< string,pair< PropertySet*,vector<const SecurityPolicyRule*> > > m_policyMap;\r
\r
// Provides filter to exclude special config elements.\r
return (i!=m_impl->m_appmap.end()) ? i->second : NULL;\r
}\r
\r
- CredentialResolver* getCredentialResolver(const char* id) const {\r
- if (id) {\r
- map<string,CredentialResolver*>::const_iterator i=m_impl->m_credResolverMap.find(id);\r
- if (i!=m_impl->m_credResolverMap.end())\r
- return i->second;\r
- }\r
- return NULL;\r
- }\r
-\r
const PropertySet* getPolicySettings(const char* id) const {\r
map<string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::const_iterator i = m_impl->m_policyMap.find(id);\r
if (i!=m_impl->m_policyMap.end())\r
static const XMLCh Applications[] = UNICODE_LITERAL_12(A,p,p,l,i,c,a,t,i,o,n,s);\r
static const XMLCh _ArtifactMap[] = UNICODE_LITERAL_11(A,r,t,i,f,a,c,t,M,a,p);\r
static const XMLCh _AttributeResolver[] = UNICODE_LITERAL_17(A,t,t,r,i,b,u,t,e,R,e,s,o,l,v,e,r);\r
- static const XMLCh Credentials[] = UNICODE_LITERAL_11(C,r,e,d,e,n,t,i,a,l,s);\r
- static const XMLCh CredentialUse[] = UNICODE_LITERAL_13(C,r,e,d,e,n,t,i,a,l,U,s,e);\r
+ static const XMLCh _CredentialResolver[] = UNICODE_LITERAL_18(C,r,e,d,e,n,t,i,a,l,R,e,s,o,l,v,e,r);\r
+ static const XMLCh DefaultRelyingParty[] = UNICODE_LITERAL_19(D,e,f,a,u,l,t,R,e,l,y,i,n,g,P,a,r,t,y);\r
static const XMLCh fatal[] = UNICODE_LITERAL_5(f,a,t,a,l);\r
static const XMLCh _Handler[] = UNICODE_LITERAL_7(H,a,n,d,l,e,r);\r
static const XMLCh _id[] = UNICODE_LITERAL_2(i,d);\r
const ServiceProvider* sp,\r
const DOMElement* e,\r
const XMLApplication* base\r
- ) : m_sp(sp), m_base(base), m_metadata(NULL), m_trust(NULL), m_attrResolver(NULL),\r
- m_credDefault(NULL), m_sessionInitDefault(NULL), m_acsDefault(NULL)\r
+ ) : m_sp(sp), m_base(base), m_metadata(NULL), m_trust(NULL), m_attrResolver(NULL), m_credResolver(NULL),\r
+ m_partyDefault(NULL), m_sessionInitDefault(NULL), m_acsDefault(NULL)\r
{\r
#ifdef _DEBUG\r
xmltooling::NDC ndc("XMLApplication");\r
}\r
}\r
\r
- // Finally, load credential mappings.\r
- child = XMLHelper::getFirstChildElement(e,CredentialUse);\r
+ if (conf.isEnabled(SPConfig::Credentials)) {\r
+ child = XMLHelper::getFirstChildElement(e,_CredentialResolver);\r
+ if (child) {\r
+ auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
+ log.info("building CredentialResolver of type %s...",type.get());\r
+ try {\r
+ m_credResolver = xmlConf.CredentialResolverManager.newPlugin(type.get(),child);\r
+ }\r
+ catch (exception& ex) {\r
+ log.crit("error building CredentialResolver: %s", ex.what());\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ // Finally, load relying parties.\r
+ child = XMLHelper::getFirstChildElement(e,DefaultRelyingParty);\r
if (child) {\r
- m_credDefault=new DOMPropertySet();\r
- m_credDefault->load(child,log,this);\r
+ m_partyDefault=new DOMPropertySet();\r
+ m_partyDefault->load(child,log,this);\r
child = XMLHelper::getFirstChildElement(child,RelyingParty);\r
while (child) {\r
- DOMPropertySet* rp=new DOMPropertySet();\r
+ auto_ptr<DOMPropertySet> rp(new DOMPropertySet());\r
rp->load(child,log,this);\r
- m_credMap[child->getAttributeNS(NULL,saml2::Attribute::NAME_ATTRIB_NAME)]=rp;\r
+ m_partyMap[child->getAttributeNS(NULL,saml2::Attribute::NAME_ATTRIB_NAME)]=rp.release();\r
child = XMLHelper::getNextSiblingElement(child,RelyingParty);\r
}\r
}\r
\r
void XMLApplication::cleanup()\r
{\r
- for_each(m_handlers.begin(),m_handlers.end(),xmltooling::cleanup<Handler>());\r
- \r
- delete m_credDefault;\r
+ delete m_partyDefault;\r
#ifdef HAVE_GOOD_STL\r
- for_each(m_credMap.begin(),m_credMap.end(),cleanup_pair<xstring,PropertySet>());\r
+ for_each(m_partyMap.begin(),m_partyMap.end(),cleanup_pair<xstring,PropertySet>());\r
#else\r
- for_each(m_credMap.begin(),m_credMap.end(),cleanup_pair<const XMLCh*,PropertySet>());\r
+ for_each(m_partyMap.begin(),m_partyMap.end(),cleanup_pair<const XMLCh*,PropertySet>());\r
#endif\r
-\r
+ for_each(m_handlers.begin(),m_handlers.end(),xmltooling::cleanup<Handler>());\r
+ delete m_credResolver;\r
delete m_attrResolver;\r
delete m_trust;\r
delete m_metadata;\r
XMLString::equals(name,SingleLogoutService::LOCAL_NAME) ||\r
XMLString::equals(name,ManageNameIDService::LOCAL_NAME) ||\r
XMLString::equals(name,SessionInitiator) ||\r
- XMLString::equals(name,CredentialUse) ||\r
+ XMLString::equals(name,DefaultRelyingParty) ||\r
XMLString::equals(name,RelyingParty) ||\r
XMLString::equals(name,_MetadataProvider) ||\r
XMLString::equals(name,_TrustEngine) ||\r
+ XMLString::equals(name,_CredentialResolver) ||\r
XMLString::equals(name,_AttributeResolver))\r
return FILTER_REJECT;\r
\r
return m_base->getPropertySet(name,ns);\r
}\r
\r
-const PropertySet* XMLApplication::getCredentialUse(const EntityDescriptor* provider) const\r
+const PropertySet* XMLApplication::getRelyingParty(const EntityDescriptor* provider) const\r
{\r
- if (!m_credDefault && m_base)\r
- return m_base->getCredentialUse(provider);\r
+ if (!m_partyDefault && m_base)\r
+ return m_base->getRelyingParty(provider);\r
else if (!provider)\r
- return m_credDefault;\r
+ return m_partyDefault;\r
\r
#ifdef HAVE_GOOD_STL\r
- map<xstring,PropertySet*>::const_iterator i=m_credMap.find(provider->getEntityID());\r
- if (i!=m_credMap.end())\r
+ map<xstring,PropertySet*>::const_iterator i=m_partyMap.find(provider->getEntityID());\r
+ if (i!=m_partyMap.end())\r
return i->second;\r
const EntitiesDescriptor* group=dynamic_cast<const EntitiesDescriptor*>(provider->getParent());\r
while (group) {\r
if (group->getName()) {\r
- i=m_credMap.find(group->getName());\r
- if (i!=m_credMap.end())\r
+ i=m_partyMap.find(group->getName());\r
+ if (i!=m_partyMap.end())\r
return i->second;\r
}\r
group=dynamic_cast<const EntitiesDescriptor*>(group->getParent());\r
}\r
#else\r
- map<const XMLCh*,PropertySet*>::const_iterator i=m_credMap.begin();\r
- for (; i!=m_credMap.end(); i++) {\r
+ map<const XMLCh*,PropertySet*>::const_iterator i=m_partyMap.begin();\r
+ for (; i!=m_partyMap.end(); i++) {\r
if (XMLString::equals(i->first,provider->getId()))\r
return i->second;\r
const EntitiesDescriptor* group=dynamic_cast<const EntitiesDescriptor*>(provider->getParent());\r
}\r
}\r
#endif\r
- return m_credDefault;\r
+ return m_partyDefault;\r
}\r
\r
const Handler* XMLApplication::getDefaultSessionInitiator() const\r
const XMLCh* name=node->getLocalName();\r
if (XMLString::equals(name,Applications) ||\r
XMLString::equals(name,_ArtifactMap) ||\r
- XMLString::equals(name,Credentials) ||\r
XMLString::equals(name,Extensions::LOCAL_NAME) ||\r
XMLString::equals(name,Implementation) ||\r
XMLString::equals(name,Listener) ||\r
}\r
}\r
\r
- // Now we load the credentials map.\r
- if (conf.isEnabled(SPConfig::Credentials)) {\r
- child = XMLHelper::getLastChildElement(e,Credentials);\r
- if (child) {\r
- // Step down and process resolvers.\r
- child=XMLHelper::getFirstChildElement(child);\r
- while (child) {\r
- auto_ptr_char id(child->getAttributeNS(NULL,_id));\r
- auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
- try {\r
- CredentialResolver* cr=xmlConf.CredentialResolverManager.newPlugin(type.get(),child);\r
- m_credResolverMap[id.get()] = cr;\r
- }\r
- catch (exception& ex) {\r
- log.crit("failed to instantiate CredentialResolver (%s): %s", id.get(), ex.what());\r
- }\r
- child = XMLHelper::getNextSiblingElement(child);\r
- }\r
- }\r
- }\r
-\r
// Load security policies.\r
child = XMLHelper::getLastChildElement(e,SecurityPolicies);\r
if (child) {\r
XMLConfigImpl::~XMLConfigImpl()\r
{\r
for_each(m_appmap.begin(),m_appmap.end(),cleanup_pair<string,Application>());\r
- for_each(m_credResolverMap.begin(),m_credResolverMap.end(),cleanup_pair<string,CredentialResolver>());\r
for (map< string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::iterator i=m_policyMap.begin(); i!=m_policyMap.end(); ++i) {\r
delete i->second.first;\r
for_each(i->second.second.begin(), i->second.second.end(), xmltooling::cleanup<SecurityPolicyRule>());\r
#include "security/PKIXTrustEngine.h"
#include <saml/saml2/metadata/Metadata.h>
+#include <saml/saml2/metadata/MetadataCredentialCriteria.h>
+#include <saml/saml2/metadata/ObservableMetadataProvider.h>
#include <xmltooling/XMLToolingConfig.h>
#include <xmltooling/security/AbstractPKIXTrustEngine.h>
+#include <xmltooling/security/KeyInfoResolver.h>
+#include <xmltooling/security/X509Credential.h>
using namespace shibsp;
using namespace opensaml::saml2md;
using namespace std;
namespace shibsp {
- /**
- * Adapter between shibmd:KeyAuthority extension and the PKIXValidationInfoIterator interface.
- */
- class SHIBSP_API MetadataPKIXIterator : public AbstractPKIXTrustEngine::PKIXValidationInfoIterator
+
+ class SHIBSP_DLLLOCAL PKIXTrustEngine : public AbstractPKIXTrustEngine, public ObservableMetadataProvider::Observer
{
- const XMLObject* m_obj;
- const Extensions* m_extBlock;
- const KeyAuthority* m_current;
- vector<XMLObject*>::const_iterator m_iter;
-
- bool m_certsOwned;
- vector<XSECCryptoX509*> m_certs;
- vector<XSECCryptoX509CRL*> m_crls;
+ public:
+ PKIXTrustEngine(const DOMElement* e=NULL) : AbstractPKIXTrustEngine(e), m_credLock(RWLock::create()) {
+ }
+ virtual ~PKIXTrustEngine() {
+ delete m_credLock;
+ }
+ AbstractPKIXTrustEngine::PKIXValidationInfoIterator* getPKIXValidationInfoIterator(
+ const CredentialResolver& pkixSource, CredentialCriteria* criteria=NULL
+ ) const;
+
+ void onEvent(const MetadataProvider& metadata) const {
+ m_credLock->wrlock();
+ m_credentialMap[&metadata].clear();
+ m_credLock->unlock();
+ }
+
+ const KeyInfoResolver* getKeyInfoResolver() const {
+ return m_keyInfoResolver ? m_keyInfoResolver : XMLToolingConfig::getConfig().getKeyInfoResolver();
+ }
+
+ private:
+ friend class SHIBSP_DLLLOCAL MetadataPKIXIterator;
+ mutable RWLock* m_credLock;
+ typedef map< const KeyAuthority*,vector<X509Credential*> > credmap_t;
+ mutable map<const MetadataProvider*,credmap_t> m_credentialMap;
+ };
+
+ SHIBSP_DLLLOCAL PluginManager<TrustEngine,const DOMElement*>::Factory PKIXTrustEngineFactory;
+
+ TrustEngine* SHIBSP_DLLLOCAL PKIXTrustEngineFactory(const DOMElement* const & e)
+ {
+ return new PKIXTrustEngine(e);
+ }
+
+ class SHIBSP_DLLLOCAL MetadataPKIXIterator : public AbstractPKIXTrustEngine::PKIXValidationInfoIterator
+ {
public:
- MetadataPKIXIterator(const RoleDescriptor& role, const KeyResolver& keyResolver)
- : PKIXValidationInfoIterator(keyResolver), m_obj(role.getParent()), m_extBlock(NULL), m_current(NULL), m_certsOwned(false) {
+ MetadataPKIXIterator(const PKIXTrustEngine& engine, const MetadataProvider& pkixSource, MetadataCredentialCriteria& criteria)
+ : m_caching(false), m_engine(engine), m_obj(criteria.getRole().getParent()), m_extBlock(NULL), m_current(NULL) {
+ m_engine.m_credLock->rdlock();
+
+ const ObservableMetadataProvider* observable = dynamic_cast<const ObservableMetadataProvider*>(&pkixSource);
+
+ // While holding read lock, see if this metadata plugin has been seen before.
+ m_credCache = m_engine.m_credentialMap.find(&pkixSource);
+ if (m_credCache==m_engine.m_credentialMap.end()) {
+
+ // We need to elevate the lock and retry.
+ m_engine.m_credLock->unlock();
+ m_engine.m_credLock->wrlock();
+ m_credCache = m_engine.m_credentialMap.find(&pkixSource);
+ if (m_credCache==m_engine.m_credentialMap.end()) {
+
+ // It's still brand new, so see if we can hook it for cache activation.
+ if (observable)
+ observable->addObserver(&m_engine);
+
+ // Prime the map reference with an empty credential map.
+ m_credCache = m_engine.m_credentialMap.insert(make_pair(&pkixSource,PKIXTrustEngine::credmap_t())).first;
+
+ // Downgrade the lock.
+ // We don't have to recheck because we never erase the master map entry entirely, even on changes.
+ m_engine.m_credLock->unlock();
+ m_engine.m_credLock->rdlock();
+ }
+ }
+
+ if (observable) {
+ // We've hooked the metadata for changes, and we know we can cache against it.
+ m_caching = true;
+ }
}
virtual ~MetadataPKIXIterator() {
- clear();
+ m_engine.m_credLock->unlock();
+ for_each(m_ownedCreds.begin(), m_ownedCreds.end(), xmltooling::cleanup<Credential>());
}
bool next();
private:
void populate();
-
- void clear() {
- if (m_certsOwned)
- for_each(m_certs.begin(), m_certs.end(), xmltooling::cleanup<XSECCryptoX509>());
- m_certs.clear();
- for_each(m_crls.begin(), m_crls.end(), xmltooling::cleanup<XSECCryptoX509CRL>());
- m_crls.clear();
- }
- };
-
- class SHIBSP_DLLLOCAL PKIXTrustEngine : public AbstractPKIXTrustEngine
- {
- public:
- PKIXTrustEngine(const DOMElement* e=NULL) : AbstractPKIXTrustEngine(e) {}
- virtual ~PKIXTrustEngine() {}
-
- AbstractPKIXTrustEngine::PKIXValidationInfoIterator* getPKIXValidationInfoIterator(
- const KeyInfoSource& pkixSource, const KeyResolver& keyResolver
- ) const;
+ bool m_caching;
+ const PKIXTrustEngine& m_engine;
+ map<const MetadataProvider*,PKIXTrustEngine::credmap_t>::iterator m_credCache;
+ const XMLObject* m_obj;
+ const Extensions* m_extBlock;
+ const KeyAuthority* m_current;
+ vector<XMLObject*>::const_iterator m_iter;
+ vector<XSECCryptoX509*> m_certs;
+ vector<XSECCryptoX509CRL*> m_crls;
+ vector<X509Credential*> m_ownedCreds;
};
-
- SHIBSP_DLLLOCAL PluginManager<TrustEngine,const DOMElement*>::Factory PKIXTrustEngineFactory;
-
- TrustEngine* SHIBSP_DLLLOCAL PKIXTrustEngineFactory(const DOMElement* const & e)
- {
- return new PKIXTrustEngine(e);
- }
};
void shibsp::registerPKIXTrustEngine()
}
AbstractPKIXTrustEngine::PKIXValidationInfoIterator* PKIXTrustEngine::getPKIXValidationInfoIterator(
- const KeyInfoSource& pkixSource, const KeyResolver& keyResolver
+ const CredentialResolver& pkixSource, CredentialCriteria* criteria
) const
{
- return new MetadataPKIXIterator(dynamic_cast<const RoleDescriptor&>(pkixSource),keyResolver);
+ // Make sure these are metadata objects.
+ const MetadataProvider& metadata = dynamic_cast<const MetadataProvider&>(pkixSource);
+ MetadataCredentialCriteria* metacrit = dynamic_cast<MetadataCredentialCriteria*>(criteria);
+ if (!metacrit)
+ throw MetadataException("Cannot obtain PKIX information without a MetadataCredentialCriteria object.");
+
+ return new MetadataPKIXIterator(*this, metadata,*metacrit);
}
bool MetadataPKIXIterator::next()
void MetadataPKIXIterator::populate()
{
// Dump anything old.
- clear();
+ m_certs.clear();
+ m_crls.clear();
+ for_each(m_ownedCreds.begin(), m_ownedCreds.end(), xmltooling::cleanup<Credential>());
- // We have to aggregate the resolution results.
- KeyResolver::ResolvedCertificates certs;
- XSECCryptoX509CRL* crl;
+ if (m_caching) {
+ // We're holding a read lock. Search for "resolved" creds.
+ PKIXTrustEngine::credmap_t::iterator cached = m_credCache->second.find(m_current);
+ if (cached!=m_credCache->second.end()) {
+ // Copy over the information.
+ for (vector<X509Credential*>::const_iterator c=cached->second.begin(); c!=cached->second.end(); ++c) {
+ m_certs.insert(m_certs.end(), (*c)->getEntityCertificateChain().begin(), (*c)->getEntityCertificateChain().end());
+ m_crls.push_back((*c)->getCRL());
+ }
+ }
+ }
+
+ // We're either not caching or didn't find the results we need, so we have to resolve them.
const vector<KeyInfo*>& keyInfos = m_current->getKeyInfos();
for (vector<KeyInfo*>::const_iterator k = keyInfos.begin(); k!=keyInfos.end(); ++k) {
- vector<XSECCryptoX509*>::size_type count = m_keyResolver.resolveCertificates(*k,certs);
- if (count > 0) {
- // Transfer certificates out of wrapper.
- bool own = certs.release(m_certs);
- if (!m_certs.empty() && own != m_certsOwned) {
- // Ugh. We have a mashup of "owned" and "unowned".
- // The ones we just added need to be removed and perhaps freed.
- do {
- if (own)
- delete m_certs.back();
- m_certs.pop_back();
- } while (--count > 0);
- }
- m_certsOwned = own;
+ auto_ptr<Credential> cred (m_engine.getKeyInfoResolver()->resolve(*k));
+ X509Credential* xcred = dynamic_cast<X509Credential*>(cred.get());
+ if (xcred) {
+ m_ownedCreds.push_back(xcred);
+ cred.release();
+ }
+ }
+
+ // Copy over the new information.
+ for (vector<X509Credential*>::const_iterator c=m_ownedCreds.begin(); c!=m_ownedCreds.end(); ++c) {
+ m_certs.insert(m_certs.end(), (*c)->getEntityCertificateChain().begin(), (*c)->getEntityCertificateChain().end());
+ m_crls.push_back((*c)->getCRL());
+ }
+
+ // As a last step, if we're caching, try and elevate to a write lock for cache insertion.
+ if (m_caching) {
+ m_engine.m_credLock->unlock();
+ m_engine.m_credLock->wrlock();
+ PKIXTrustEngine::credmap_t::iterator cached = m_credCache->second.find(m_current);
+ if (m_credCache->second.count(m_current)==0) {
+ // Transfer objects into cache.
+ m_credCache->second[m_current] = m_ownedCreds;
+ m_ownedCreds.clear();
}
+ m_engine.m_credLock->unlock();
+ m_engine.m_credLock->rdlock();
- crl = m_keyResolver.resolveCRL(*k);
- if (crl)
- m_crls.push_back(crl);
+ // In theory we could have lost the objects but that shouldn't be possible
+ // since the metadata itself is locked and shouldn't change behind us.
}
}
\r
SecurityPolicy policy;\r
shibsp::SOAPClient soaper(*app,policy);\r
+ MetadataCredentialCriteria mcc(*AA);\r
\r
if (ver == v20) {\r
auto_ptr_XMLCh binding(samlconstants::SAML20_BINDING_SOAP);\r
nameid->setNameQualifier(domain.get());\r
iss->setName(issuer.get());\r
SAML2SOAPClient client(soaper);\r
- client.sendSAML(query, *AA, loc.get());\r
+ client.sendSAML(query, mcc, loc.get());\r
srt = client.receiveSAML();\r
}\r
catch (exception& ex) {\r
query->setResource(issuer.get());\r
request->setMinorVersion(ver==v11 ? 1 : 0);\r
SAML1SOAPClient client(soaper);\r
- client.sendSAML(request, *AA, loc.get());\r
+ client.sendSAML(request, mcc, loc.get());\r
response = client.receiveSAML();\r
}\r
catch (exception& ex) {\r