Convert from NULL macro to nullptr.
[shibboleth/cpp-xmltooling.git] / xmltooling / security / impl / FilesystemCredentialResolver.cpp
index ef620bf..7009214 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2001-2009 Internet2
+ *  Copyright 2001-2010 Internet2
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
 
 #include "internal.h"
 #include "logging.h"
+#include "io/HTTPResponse.h"
 #include "security/BasicX509Credential.h"
 #include "security/CredentialCriteria.h"
 #include "security/CredentialResolver.h"
@@ -65,11 +66,14 @@ namespace xmltooling {
         SOAPTransport* getTransport() {
             SOAPTransport::Address addr("FilesystemCredentialResolver", source.c_str(), source.c_str());
             string scheme(addr.m_endpoint, strchr(addr.m_endpoint,':') - addr.m_endpoint);
-            return XMLToolingConfig::getConfig().SOAPTransportManager.newPlugin(scheme.c_str(), addr);
+            SOAPTransport* ret = XMLToolingConfig::getConfig().SOAPTransportManager.newPlugin(scheme.c_str(), addr);
+            if (ret)
+                ret->setCacheTag(&cacheTag);
+            return ret;
         }
 
     public:
-        bool stale(Category& log, RWLock* lock=NULL) {
+        bool stale(Category& log, RWLock* lock=nullptr) {
             if (local) {
 #ifdef WIN32
                 struct _stat stat_buf;
@@ -102,7 +106,7 @@ namespace xmltooling {
                 log.info("change detected, reloading local resource...");
             }
             else {
-                time_t now = time(NULL);
+                time_t now = time(nullptr);
 
                 // Time to reload?
                 if (now - filestamp < reloadInterval)
@@ -129,18 +133,18 @@ namespace xmltooling {
         }
 
         bool local,reloadChanges;
-        string format,source,backing;
+        string format,source,backing,cacheTag;
         time_t filestamp,reloadInterval;
     };
 
     class XMLTOOL_DLLLOCAL ManagedKey : public ManagedResource {
     public:
-        ManagedKey() : key(NULL) {}
+        ManagedKey() : key(nullptr) {}
         ~ManagedKey() { delete key; }
         void load(Category& log, const char* password) {
             if (source.empty())
                 return;
-            XSECCryptoKey* nkey=NULL;
+            XSECCryptoKey* nkey=nullptr;
             if (local) {
                 nkey = SecurityHelper::loadKeyFromFile(source.c_str(), format.c_str(), password);
             }
@@ -209,7 +213,6 @@ namespace xmltooling {
     class XMLTOOL_DLLLOCAL FilesystemCredential;
     class XMLTOOL_DLLLOCAL FilesystemCredentialResolver : public CredentialResolver
     {
-        friend class XMLTOOL_DLLLOCAL FilesystemCredential;
     public:
         FilesystemCredentialResolver(const DOMElement* e);
         virtual ~FilesystemCredentialResolver();
@@ -219,10 +222,10 @@ namespace xmltooling {
             m_lock->unlock();
         }
 
-        const Credential* resolve(const CredentialCriteria* criteria=NULL) const;
+        const Credential* resolve(const CredentialCriteria* criteria=nullptr) const;
 
         virtual vector<const Credential*>::size_type resolve(
-            vector<const Credential*>& results, const CredentialCriteria* criteria=NULL
+            vector<const Credential*>& results, const CredentialCriteria* criteria=nullptr
             ) const;
 
     private:
@@ -232,11 +235,14 @@ namespace xmltooling {
         Credential* m_credential;
         string m_keypass,m_certpass;
         unsigned int m_keyinfomask,m_usage;
+        bool m_extractNames;
         vector<string> m_keynames;
 
         ManagedKey m_key;
         vector<ManagedCert> m_certs;
         vector<ManagedCRL> m_crls;
+
+        friend class XMLTOOL_DLLLOCAL FilesystemCredential;
     };
 
 #if defined (_MSC_VER)
@@ -248,9 +254,13 @@ namespace xmltooling {
     {
     public:
         FilesystemCredential(
-            FilesystemCredentialResolver* resolver, XSECCryptoKey* key, const vector<XSECCryptoX509*>& xseccerts, const vector<XSECCryptoX509CRL*>& crls
-            ) : BasicX509Credential(key ? key : (xseccerts.empty() ? NULL : xseccerts.front()->clonePublicKey()), xseccerts, crls), m_resolver(resolver) {
-            //extract();
+            FilesystemCredentialResolver* resolver,
+            XSECCryptoKey* key,
+            const vector<XSECCryptoX509*>& xseccerts,
+            const vector<XSECCryptoX509CRL*>& crls
+            ) : BasicX509Credential(key ? key : (xseccerts.empty() ? nullptr : xseccerts.front()->clonePublicKey()), xseccerts, crls), m_resolver(resolver) {
+            if (m_resolver->m_extractNames)
+                extract();
             m_keyNames.insert(m_resolver->m_keynames.begin(), m_resolver->m_keynames.end());
         }
 
@@ -286,6 +296,7 @@ namespace xmltooling {
     static const XMLCh Certificate[] =      UNICODE_LITERAL_11(C,e,r,t,i,f,i,c,a,t,e);
     static const XMLCh _certificate[] =     UNICODE_LITERAL_11(c,e,r,t,i,f,i,c,a,t,e);
     static const XMLCh CRL[] =              UNICODE_LITERAL_3(C,R,L);
+    static const XMLCh extractNames[] =     UNICODE_LITERAL_12(e,x,t,r,a,c,t,N,a,m,e,s);
     static const XMLCh _format[] =          UNICODE_LITERAL_6(f,o,r,m,a,t);
     static const XMLCh Key[] =              UNICODE_LITERAL_3(K,e,y);
     static const XMLCh _key[] =             UNICODE_LITERAL_3(k,e,y);
@@ -301,7 +312,7 @@ namespace xmltooling {
 };
 
 FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
-    : m_lock(NULL), m_credential(NULL), m_usage(Credential::UNSPECIFIED_CREDENTIAL)
+    : m_lock(nullptr), m_credential(nullptr), m_usage(Credential::UNSPECIFIED_CREDENTIAL), m_extractNames(true)
 {
 #ifdef _DEBUG
     NDC ndc("FilesystemCredentialResolver");
@@ -314,34 +325,36 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
         Credential::KEYINFO_KEY_VALUE |
         X509Credential::KEYINFO_X509_CERTIFICATE |
         X509Credential::KEYINFO_X509_SUBJECTNAME;
-    if (e && e->hasAttributeNS(NULL,keyInfoMask))
-        m_keyinfomask = XMLString::parseInt(e->getAttributeNS(NULL,keyInfoMask));
+    if (e && e->hasAttributeNS(nullptr,keyInfoMask))
+        m_keyinfomask = XMLString::parseInt(e->getAttributeNS(nullptr,keyInfoMask));
 
-    if (e && (e->hasAttributeNS(NULL,_certificate) || e->hasAttributeNS(NULL,_key))) {
+    if (e && (e->hasAttributeNS(nullptr,_certificate) || e->hasAttributeNS(nullptr,_key))) {
         // Dummy up a simple file resolver config using these attributes.
-        DOMElement* dummy = e->getOwnerDocument()->createElementNS(NULL,_CredentialResolver);
+        DOMElement* dummy = e->getOwnerDocument()->createElementNS(nullptr,_CredentialResolver);
         DOMElement* child;
         DOMElement* path;
-        if (e->hasAttributeNS(NULL,_key)) {
-            child = e->getOwnerDocument()->createElementNS(NULL,Key);
+        if (e->hasAttributeNS(nullptr,_key)) {
+            child = e->getOwnerDocument()->createElementNS(nullptr,Key);
             dummy->appendChild(child);
-            path = e->getOwnerDocument()->createElementNS(NULL,Path);
+            path = e->getOwnerDocument()->createElementNS(nullptr,Path);
             child->appendChild(path);
-            path->appendChild(e->getOwnerDocument()->createTextNode(e->getAttributeNS(NULL,_key)));
-            if (e->hasAttributeNS(NULL,password))
-                child->setAttributeNS(NULL,password,e->getAttributeNS(NULL,password));
-            if (e->hasAttributeNS(NULL,keyName)) {
-                path = e->getOwnerDocument()->createElementNS(NULL,Name);
+            path->appendChild(e->getOwnerDocument()->createTextNode(e->getAttributeNS(nullptr,_key)));
+            if (e->hasAttributeNS(nullptr,password))
+                child->setAttributeNS(nullptr,password,e->getAttributeNS(nullptr,password));
+            if (e->hasAttributeNS(nullptr,keyName)) {
+                path = e->getOwnerDocument()->createElementNS(nullptr,Name);
                 child->appendChild(path);
-                path->appendChild(e->getOwnerDocument()->createTextNode(e->getAttributeNS(NULL,keyName)));
+                path->appendChild(e->getOwnerDocument()->createTextNode(e->getAttributeNS(nullptr,keyName)));
             }
         }
-        if (e->hasAttributeNS(NULL,_certificate)) {
-            child = e->getOwnerDocument()->createElementNS(NULL,Certificate);
+        if (e->hasAttributeNS(nullptr,_certificate)) {
+            child = e->getOwnerDocument()->createElementNS(nullptr,Certificate);
             dummy->appendChild(child);
-            path = e->getOwnerDocument()->createElementNS(NULL,Path);
+            path = e->getOwnerDocument()->createElementNS(nullptr,Path);
             child->appendChild(path);
-            path->appendChild(e->getOwnerDocument()->createTextNode(e->getAttributeNS(NULL,_certificate)));
+            path->appendChild(e->getOwnerDocument()->createTextNode(e->getAttributeNS(nullptr,_certificate)));
+            if (e->hasAttributeNS(nullptr, extractNames))
+                child->setAttributeNS(nullptr, extractNames, e->getAttributeNS(nullptr, extractNames));
         }
         e = dummy;  // reset "root" to the dummy config element
     }
@@ -349,8 +362,8 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
     const XMLCh* prop;
     const DOMElement* root = e;
 
-    // Save off usage flags.
-    const XMLCh* usage = root->getAttributeNS(NULL,_use);
+    // Save off usage bits.
+    const XMLCh* usage = root->getAttributeNS(nullptr,_use);
     if (usage && *usage) {
         auto_ptr_char u(usage);
         if (!strcmp(u.get(), "signing"))
@@ -364,13 +377,13 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
     // Move to Key.
     const DOMElement* keynode = XMLHelper::getFirstChildElement(root,Key);
     if (keynode) {
-        prop = keynode->getAttributeNS(NULL,_format);
+        prop = keynode->getAttributeNS(nullptr,_format);
         if (prop && *prop) {
             auto_ptr_char f(prop);
             m_key.format = f.get();
         }
 
-        prop = keynode->getAttributeNS(NULL,password);
+        prop = keynode->getAttributeNS(nullptr,password);
         if (prop && *prop) {
             auto_ptr_char kp(prop);
             m_keypass = kp.get();
@@ -382,7 +395,7 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
             m_key.source = kpath.get();
             XMLToolingConfig::getConfig().getPathResolver()->resolve(m_key.source, PathResolver::XMLTOOLING_CFG_FILE);
             m_key.local = true;
-            prop = e->getAttributeNS(NULL,_reloadChanges);
+            prop = e->getAttributeNS(nullptr,_reloadChanges);
             if (prop && (*prop==chLatin_f) || (*prop==chDigit_0))
                 m_key.reloadChanges = false;
         }
@@ -391,13 +404,13 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
             auto_ptr_char kpath(prop);
             m_key.source = kpath.get();
             m_key.local = false;
-            prop = e->getAttributeNS(NULL,backingFilePath);
+            prop = e->getAttributeNS(nullptr,backingFilePath);
             if (!prop || !*prop)
                 throw XMLSecurityException("FilesystemCredentialResolver can't access key, backingFilePath missing from URL element.");
             auto_ptr_char b(prop);
             m_key.backing = b.get();
             XMLToolingConfig::getConfig().getPathResolver()->resolve(m_key.backing, PathResolver::XMLTOOLING_RUN_FILE);
-            prop = e->getAttributeNS(NULL,_reloadInterval);
+            prop = e->getAttributeNS(nullptr,_reloadInterval);
             if (prop && *prop)
                 m_key.reloadInterval = XMLString::parseInt(prop);
         }
@@ -420,7 +433,7 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
     // Check for CRL.
     const DOMElement* crlnode = XMLHelper::getFirstChildElement(root,CRL);
     if (crlnode) {
-        const XMLCh* crlformat = crlnode->getAttributeNS(NULL,_format);
+        const XMLCh* crlformat = crlnode->getAttributeNS(nullptr,_format);
         e = XMLHelper::getFirstChildElement(crlnode,Path);
         while (e) {
             if (e->hasChildNodes()) {
@@ -435,7 +448,7 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
                 crl.source = crlpath.get();
                 XMLToolingConfig::getConfig().getPathResolver()->resolve(crl.source, PathResolver::XMLTOOLING_CFG_FILE);
                 crl.local = true;
-                prop = e->getAttributeNS(NULL,_reloadChanges);
+                prop = e->getAttributeNS(nullptr,_reloadChanges);
                 if (prop && (*prop==chLatin_f) || (*prop==chDigit_0))
                     crl.reloadChanges = false;
             }
@@ -455,13 +468,13 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
                 auto_ptr_char crlpath(prop);
                 crl.source = crlpath.get();
                 crl.local = false;
-                prop = e->getAttributeNS(NULL,backingFilePath);
+                prop = e->getAttributeNS(nullptr,backingFilePath);
                 if (!prop || !*prop)
                     throw XMLSecurityException("FilesystemCredentialResolver can't access CRL, backingFilePath missing from URL element.");
                 auto_ptr_char b(prop);
                 crl.backing = b.get();
                 XMLToolingConfig::getConfig().getPathResolver()->resolve(crl.backing, PathResolver::XMLTOOLING_RUN_FILE);
-                prop = e->getAttributeNS(NULL,_reloadInterval);
+                prop = e->getAttributeNS(nullptr,_reloadInterval);
                 if (prop && *prop)
                     crl.reloadInterval = XMLString::parseInt(prop);
             }
@@ -476,13 +489,17 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
     // Check for Certificate
     DOMElement* certnode = XMLHelper::getFirstChildElement(root,Certificate);
     if (certnode) {
-        prop = certnode->getAttributeNS(NULL,password);
+        prop = certnode->getAttributeNS(nullptr,password);
         if (prop && *prop) {
             auto_ptr_char certpass(prop);
             m_certpass = certpass.get();
         }
 
-        const XMLCh* certformat = certnode->getAttributeNS(NULL,_format);
+        const XMLCh* certformat = certnode->getAttributeNS(nullptr,_format);
+
+        const XMLCh* extractFlag = certnode->getAttributeNS(nullptr, extractNames);
+        if (extractFlag && (*extractFlag == chLatin_f || *extractFlag == chDigit_0))
+            m_extractNames = false;
 
         e = XMLHelper::getFirstChildElement(certnode);
         while (e) {
@@ -498,7 +515,7 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
                 cert.source = certpath.get();
                 XMLToolingConfig::getConfig().getPathResolver()->resolve(cert.source, PathResolver::XMLTOOLING_CFG_FILE);
                 cert.local = true;
-                prop = e->getAttributeNS(NULL,_reloadChanges);
+                prop = e->getAttributeNS(nullptr,_reloadChanges);
                 if (prop && (*prop==chLatin_f) || (*prop==chDigit_0))
                     cert.reloadChanges = false;
             }
@@ -513,13 +530,13 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
                 auto_ptr_char certpath(prop);
                 cert.source = certpath.get();
                 cert.local = false;
-                prop = e->getAttributeNS(NULL,backingFilePath);
+                prop = e->getAttributeNS(nullptr,backingFilePath);
                 if (!prop || !*prop)
                     throw XMLSecurityException("FilesystemCredentialResolver can't access certificate, backingFilePath missing from URL element.");
                 auto_ptr_char b(prop);
                 cert.backing = b.get();
                 XMLToolingConfig::getConfig().getPathResolver()->resolve(cert.backing, PathResolver::XMLTOOLING_RUN_FILE);
-                prop = e->getAttributeNS(NULL,_reloadInterval);
+                prop = e->getAttributeNS(nullptr,_reloadInterval);
                 if (prop && *prop)
                     cert.reloadInterval = XMLString::parseInt(prop);
             }
@@ -533,11 +550,11 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
 
     // Do an initial load of all the objects. If anything blows up here, whatever's
     // been loaded should be freed during teardown of the embedded objects.
-    time_t now = time(NULL);
+    time_t now = time(nullptr);
     m_key.filestamp = now;
     m_key.load(log, m_keypass.c_str());
     for (vector<ManagedCert>::iterator i = m_certs.begin(); i != m_certs.end(); ++i) {
-        i->load(log, (i==m_certs.begin()) ? m_certpass.c_str() : NULL);
+        i->load(log, (i==m_certs.begin()) ? m_certpass.c_str() : nullptr);
         i->filestamp = now;
     }
     for (vector<ManagedCRL>::iterator j = m_crls.begin(); j != m_crls.end(); ++j) {
@@ -568,8 +585,8 @@ Credential* FilesystemCredentialResolver::getCredential()
 
     // We (unfortunately) need to duplicate all the objects and put them in one set of arrays
     // in order to create the credential wrapper.
-    FilesystemCredential* credential=NULL;
-    auto_ptr<XSECCryptoKey> xseckey(m_key.key ? m_key.key->clone() : NULL);
+    FilesystemCredential* credential=nullptr;
+    auto_ptr<XSECCryptoKey> xseckey(m_key.key ? m_key.key->clone() : nullptr);
     vector<XSECCryptoX509*> xseccerts;
     vector<XSECCryptoX509CRL*> xseccrls;
     try {
@@ -625,18 +642,36 @@ Lockable* FilesystemCredentialResolver::lock()
             m_key.load(log, m_keypass.c_str());
             updated = true;
         }
+        catch (long& ex) {
+            if (ex == HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED) {
+                log.info("remote key (%s) unchanged from cached version", m_key.source.c_str());
+            }
+            else {
+                // Shouldn't happen, we should only get codes intended to be gracefully handled.
+                log.crit("maintaining existing key, remote fetch returned atypical status code (%d)", ex);
+            }
+        }
         catch (exception& ex) {
             log.crit("maintaining existing key: %s", ex.what());
         }
     }
 
     for (vector<ManagedCert>::iterator i = m_certs.begin(); i != m_certs.end(); ++i) {
-        if (i->stale(log, writelock ? NULL : m_lock)) {
+        if (i->stale(log, writelock ? nullptr : m_lock)) {
             writelock = true;
             try {
-                i->load(log, (i==m_certs.begin()) ? m_certpass.c_str() : NULL);
+                i->load(log, (i==m_certs.begin()) ? m_certpass.c_str() : nullptr);
                 updated = true;
             }
+            catch (long& ex) {
+                if (ex == HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED) {
+                    log.info("remote certificate(s) (%s) unchanged from cached version", i->source.c_str());
+                }
+                else {
+                    // Shouldn't happen, we should only get codes intended to be gracefully handled.
+                    log.crit("maintaining existing certificate(s), remote fetch returned atypical status code (%d)", ex);
+                }
+            }
             catch (exception& ex) {
                 log.crit("maintaining existing certificate(s): %s", ex.what());
             }
@@ -644,12 +679,21 @@ Lockable* FilesystemCredentialResolver::lock()
     }
 
     for (vector<ManagedCRL>::iterator j = m_crls.begin(); j != m_crls.end(); ++j) {
-        if (j->stale(log, writelock ? NULL : m_lock)) {
+        if (j->stale(log, writelock ? nullptr : m_lock)) {
             writelock = true;
             try {
                 j->load(log);
                 updated = true;
             }
+            catch (long& ex) {
+                if (ex == HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED) {
+                    log.info("remote CRL(s) (%s) unchanged from cached version", j->source.c_str());
+                }
+                else {
+                    // Shouldn't happen, we should only get codes intended to be gracefully handled.
+                    log.crit("maintaining existing CRL(s), remote fetch returned atypical status code (%d)", ex);
+                }
+            }
             catch (exception& ex) {
                 log.crit("maintaining existing CRL(s): %s", ex.what());
             }
@@ -676,7 +720,7 @@ Lockable* FilesystemCredentialResolver::lock()
 
 const Credential* FilesystemCredentialResolver::resolve(const CredentialCriteria* criteria) const
 {
-    return (criteria ? (criteria->matches(*m_credential) ? m_credential : NULL) : m_credential);
+    return (criteria ? (criteria->matches(*m_credential) ? m_credential : nullptr) : m_credential);
 }
 
 vector<const Credential*>::size_type FilesystemCredentialResolver::resolve(
@@ -729,11 +773,11 @@ void FilesystemCredential::attach(SSL_CTX* ctx) const
     else if (m_resolver->m_key.format == "PKCS12") {
         BIO* in=BIO_new(BIO_s_file_internal());
         if (in && BIO_read_filename(in,path)>0) {
-            PKCS12* p12 = d2i_PKCS12_bio(in, NULL);
+            PKCS12* p12 = d2i_PKCS12_bio(in, nullptr);
             if (p12) {
-                EVP_PKEY* pkey=NULL;
-                X509* x=NULL;
-                PKCS12_parse(p12, const_cast<char*>(m_resolver->m_keypass.c_str()), &pkey, &x, NULL);
+                EVP_PKEY* pkey=nullptr;
+                X509* x=nullptr;
+                PKCS12_parse(p12, const_cast<char*>(m_resolver->m_keypass.c_str()), &pkey, &x, nullptr);
                 PKCS12_free(p12);
                 if (x)
                     X509_free(x);