https://issues.shibboleth.net/jira/browse/CPPXT-53
[shibboleth/cpp-xmltooling.git] / xmltooling / security / impl / FilesystemCredentialResolver.cpp
index 0bd090a..c3250e0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2001-2008 Internet2
+ *  Copyright 2001-2009 Internet2
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 /**
  * FilesystemCredentialResolver.cpp
  *
- * Supplies credentials from local files
+ * Supplies credentials from local files.
  */
 
 #include "internal.h"
 #include "logging.h"
+#include "io/HTTPResponse.h"
 #include "security/BasicX509Credential.h"
 #include "security/CredentialCriteria.h"
 #include "security/CredentialResolver.h"
 #include "security/KeyInfoResolver.h"
 #include "security/OpenSSLCredential.h"
 #include "security/SecurityHelper.h"
+#include "security/XSECCryptoX509CRL.h"
 #include "util/NDC.h"
 #include "util/PathResolver.h"
+#include "util/Threads.h"
 #include "util/XMLHelper.h"
 
+#include <memory>
+#include <algorithm>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <openssl/pkcs12.h>
@@ -43,6 +48,10 @@ using namespace xmltooling::logging;
 using namespace xmltooling;
 using namespace std;
 
+using xercesc::DOMElement;
+using xercesc::chLatin_f;
+using xercesc::chDigit_0;
+
 namespace xmltooling {
 
     // The ManagedResource classes handle memory management, loading of the files
@@ -57,7 +66,10 @@ 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:
@@ -121,7 +133,7 @@ namespace xmltooling {
         }
 
         bool local,reloadChanges;
-        string format,source,backing;
+        string format,source,backing,cacheTag;
         time_t filestamp,reloadInterval;
     };
 
@@ -201,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();
@@ -224,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)
@@ -240,9 +254,13 @@ namespace xmltooling {
     {
     public:
         FilesystemCredential(
-            FilesystemCredentialResolver* resolver, XSECCryptoKey* key, const vector<XSECCryptoX509*>& xseccerts, const vector<XSECCryptoX509CRL*>& crls
+            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();
+            if (m_resolver->m_extractNames)
+                extract();
             m_keyNames.insert(m_resolver->m_keynames.begin(), m_resolver->m_keynames.end());
         }
 
@@ -278,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);
@@ -293,7 +312,7 @@ namespace xmltooling {
 };
 
 FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
-    : m_lock(NULL), m_credential(NULL), m_usage(Credential::UNSPECIFIED_CREDENTIAL)
+    : m_lock(NULL), m_credential(NULL), m_usage(Credential::UNSPECIFIED_CREDENTIAL), m_extractNames(true)
 {
 #ifdef _DEBUG
     NDC ndc("FilesystemCredentialResolver");
@@ -334,6 +353,8 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
             path = e->getOwnerDocument()->createElementNS(NULL,Path);
             child->appendChild(path);
             path->appendChild(e->getOwnerDocument()->createTextNode(e->getAttributeNS(NULL,_certificate)));
+            if (e->hasAttributeNS(NULL, extractNames))
+                child->setAttributeNS(NULL, extractNames, e->getAttributeNS(NULL, extractNames));
         }
         e = dummy;  // reset "root" to the dummy config element
     }
@@ -341,7 +362,7 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
     const XMLCh* prop;
     const DOMElement* root = e;
 
-    // Save off usage flags.
+    // Save off usage bits.
     const XMLCh* usage = root->getAttributeNS(NULL,_use);
     if (usage && *usage) {
         auto_ptr_char u(usage);
@@ -476,6 +497,10 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
 
         const XMLCh* certformat = certnode->getAttributeNS(NULL,_format);
 
+        const XMLCh* extractFlag = certnode->getAttributeNS(NULL, extractNames);
+        if (extractFlag && (*extractFlag == chLatin_f || *extractFlag == chDigit_0))
+            m_extractNames = false;
+
         e = XMLHelper::getFirstChildElement(certnode);
         while (e) {
             if (e->hasChildNodes() && (XMLString::equals(e->getLocalName(), Path) || XMLString::equals(e->getLocalName(), CAPath))) {
@@ -554,7 +579,7 @@ Credential* FilesystemCredentialResolver::getCredential()
     // First, verify that the key and certificate match.
     if (m_key.key && !m_certs.empty()) {
         auto_ptr<XSECCryptoKey> temp(m_certs.front().certs.front()->clonePublicKey());
-        if (!SecurityHelper::matches(m_key.key, temp.get()))
+        if (!SecurityHelper::matches(*m_key.key, *temp.get()))
             throw XMLSecurityException("FilesystemCredentialResolver given mismatched key/certificate, check for consistency.");
     }
 
@@ -617,6 +642,15 @@ 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());
         }
@@ -629,6 +663,15 @@ Lockable* FilesystemCredentialResolver::lock()
                 i->load(log, (i==m_certs.begin()) ? m_certpass.c_str() : NULL);
                 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());
             }
@@ -642,6 +685,15 @@ Lockable* FilesystemCredentialResolver::lock()
                 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());
             }