https://bugs.internet2.edu/jira/browse/SSPCPP-255
authorcantor <cantor@de75baf8-a10c-0410-a50a-987c0e22f00f>
Wed, 4 Nov 2009 15:13:48 +0000 (15:13 +0000)
committercantor <cantor@de75baf8-a10c-0410-a50a-987c0e22f00f>
Wed, 4 Nov 2009 15:13:48 +0000 (15:13 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-xmltooling/branches/REL_1@676 de75baf8-a10c-0410-a50a-987c0e22f00f

xmltooling/XMLToolingConfig.cpp
xmltooling/io/HTTPResponse.cpp
xmltooling/io/HTTPResponse.h

index 9a43921..cadf7bc 100644 (file)
@@ -27,6 +27,7 @@
 #include "encryption/Encryption.h"
 #include "encryption/Encrypter.h"
 #include "impl/UnknownElement.h"
+#include "io/HTTPResponse.h"
 #include "security/TrustEngine.h"
 #include "security/OpenSSLCryptoX509CRL.h"
 #include "security/CredentialResolver.h"
@@ -56,6 +57,7 @@
 # include <log4cpp/OstreamAppender.hh>
 #endif
 #include <xercesc/util/PlatformUtils.hpp>
+#include <xercesc/util/XMLUniDefs.hpp>
 #ifndef XMLTOOLING_NO_XMLSEC
 # include <curl/curl.h>
 # include <openssl/err.h>
@@ -352,6 +354,9 @@ bool XMLToolingInternalConfig::init()
         m_pathResolver = new PathResolver();
         m_urlEncoder = new URLEncoder();
 
+        HTTPResponse::getAllowedSchemes().push_back("https");
+        HTTPResponse::getAllowedSchemes().push_back("http");
+
         // Register xml:id as an ID attribute.
         static const XMLCh xmlid[] = UNICODE_LITERAL_2(i,d);
         AttributeExtensibleXMLObject::registerIDAttribute(QName(xmlconstants::XML_NS, xmlid));
index ab2255a..63a3dfc 100644 (file)
@@ -24,7 +24,7 @@
 #include "HTTPResponse.h"
 
 using namespace xmltooling;
-using std::istream;
+using namespace std;
 
 GenericResponse::GenericResponse()
 {
@@ -34,6 +34,37 @@ GenericResponse::~GenericResponse()
 {
 }
 
+vector<string> HTTPResponse::m_allowedSchemes;
+
+vector<string>& HTTPResponse::getAllowedSchemes()
+{
+    return m_allowedSchemes;
+}
+
+void HTTPResponse::sanitizeURL(const char* url)
+{
+    const char* ch;
+    for (ch=url; *ch; ++ch) {
+        if (iscntrl(*ch))
+            throw IOException("URL contained a control character.");
+    }
+
+    ch = strchr(url, ':');
+    if (!ch)
+        throw IOException("URL is malformed.");
+    string s(url, ch - url);
+    for (vector<string>::const_iterator i = m_allowedSchemes.begin(); i != m_allowedSchemes.end(); ++i) {
+#ifdef HAVE_STRCASECMP
+        if (!strcasecmp(s.c_str(), i->c_str()))
+#else
+        if (!stricmp(s.c_str(), i->c_str()))
+#endif
+            return;
+    }
+
+    throw IOException("URL contains invalid scheme ($1).", params(1, s.c_str()));
+}
+
 HTTPResponse::HTTPResponse()
 {
 }
@@ -49,11 +80,30 @@ void HTTPResponse::setContentType(const char* type)
 
 void HTTPResponse::setCookie(const char* name, const char* value)
 {
-    std::string cookie(name);
+    string cookie(name);
     cookie = cookie + '=' + value;
     setResponseHeader("Set-Cookie", cookie.c_str());
 }
 
+void HTTPResponse::setResponseHeader(const char* name, const char* value)
+{
+    for (const char* ch=name; *ch; ++ch) {
+        if (iscntrl(*ch))
+            throw IOException("Response header name contained a control character.");
+    }
+
+    for (const char* ch=value; *ch; ++ch) {
+        if (iscntrl(*ch))
+            throw IOException("Value for response header ($1) contained a control character.", params(1,name));
+    }
+}
+
+long HTTPResponse::sendRedirect(const char* url)
+{
+    sanitizeURL(url);
+    return XMLTOOLING_HTTP_STATUS_MOVED;
+}
+
 long HTTPResponse::sendError(istream& inputStream)
 {
     return sendResponse(inputStream, XMLTOOLING_HTTP_STATUS_ERROR);
index 6c38321..912c0f8 100644 (file)
 
 #include <xmltooling/io/GenericResponse.h>
 
+#include <string>
+#include <vector>
+
 namespace xmltooling {
-    
+
+#if defined (_MSC_VER)
+    #pragma warning( push )
+    #pragma warning( disable : 4251 )
+#endif
+
     /**
      * Interface to HTTP response.
      * 
@@ -50,7 +58,7 @@ namespace xmltooling {
          * @param name  header name
          * @param value value to set, or NULL to clear
          */
-        virtual void setResponseHeader(const char* name, const char* value)=0;
+        virtual void setResponseHeader(const char* name, const char* value);
 
         /**
          * Sets a client cookie.
@@ -62,12 +70,15 @@ namespace xmltooling {
         
         /**
          * Redirect the client to the specified URL and complete the response.
-         * Any headers previously set will be sent ahead of the redirect.
          * 
+         * <p>Any headers previously set will be sent ahead of the redirect.
+         *
+         * <p>The URL will be validated with the sanitizeURL method below.
+         *
          * @param url   location to redirect client
          * @return a result code to return from the calling MessageEncoder
          */
-        virtual long sendRedirect(const char* url)=0;
+        virtual long sendRedirect(const char* url);
         
         /** Some common HTTP status codes. */
         enum status_t {
@@ -83,7 +94,31 @@ namespace xmltooling {
 
         using GenericResponse::sendResponse;
         long sendResponse(std::istream& inputStream);
+
+        /**
+         * Returns a modifiable array of schemes to permit in sanitized URLs.
+         *
+         * <p>Updates to this array must be externally synchronized with any use
+         * of this class or its subclasses.
+         *
+         * @return  a mutable array of strings containing the schemes to permit
+         */
+        static std::vector<std::string>& getAllowedSchemes();
+
+        /**
+         * Manually check for unsafe URLs vulnerable to injection attacks.
+         *
+         * @param url   location to check
+         */
+        static void sanitizeURL(const char* url);
+
+    private:
+        static std::vector<std::string> m_allowedSchemes;
     };
+
+#if defined (_MSC_VER)
+    #pragma warning( pop )
+#endif
 };
 
 #endif /* __xmltooling_httpres_h__ */