https://issues.shibboleth.net/jira/browse/SSPCPP-263
[shibboleth/cpp-sp.git] / shibsp / AbstractSPRequest.cpp
index cb2d3eb..eb0c320 100644 (file)
@@ -1,6 +1,6 @@
 /*
- *  Copyright 2001-2007 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.
  * You may obtain a copy of the License at
 
 /**
  * AbstractSPRequest.cpp
- * 
- * Abstract base for SPRequest implementations  
+ *
+ * Abstract base for SPRequest implementations.
  */
 
 #include "internal.h"
+#include "exceptions.h"
 #include "AbstractSPRequest.h"
 #include "Application.h"
 #include "ServiceProvider.h"
 #include "SessionCache.h"
+#include "util/CGIParser.h"
 
 using namespace shibsp;
 using namespace opensaml;
 using namespace xmltooling;
 using namespace std;
 
+SPRequest::SPRequest()
+{
+}
+
+SPRequest::~SPRequest()
+{
+}
+
+string SPRequest::getSecureHeader(const char* name) const
+{
+    return getHeader(name);
+}
+
+void SPRequest::setAuthType(const char* authtype)
+{
+}
+
 AbstractSPRequest::AbstractSPRequest(const char* category)
     : m_sp(NULL), m_mapper(NULL), m_app(NULL), m_sessionTried(false), m_session(NULL),
         m_log(&Category::getInstance(category)), m_parser(NULL)
@@ -50,16 +69,26 @@ AbstractSPRequest::~AbstractSPRequest()
     delete m_parser;
 }
 
-RequestMapper::Settings AbstractSPRequest::getRequestSettings() const
+const ServiceProvider& AbstractSPRequest::getServiceProvider() const
 {
-    if (m_mapper)
-        return m_settings;
-
-    // Map request to application and content settings.
-    m_mapper=m_sp->getRequestMapper();
-    m_mapper->lock();
-    return m_settings = m_mapper->getSettings(*this);
+    return *m_sp;
+}
 
+RequestMapper::Settings AbstractSPRequest::getRequestSettings() const
+{
+    if (!m_mapper) {
+        // Map request to application and content settings.
+        m_mapper=m_sp->getRequestMapper();
+        m_mapper->lock();
+        m_settings = m_mapper->getSettings(*this);
+
+        if (reinterpret_cast<Category*>(m_log)->isDebugEnabled()) {
+            reinterpret_cast<Category*>(m_log)->debug(
+                "mapped %s to %s", getRequestURL(), m_settings.first->getString("applicationId").second
+                );
+        }
+    }
+    return m_settings;
 }
 
 const Application& AbstractSPRequest::getApplication() const
@@ -68,12 +97,12 @@ const Application& AbstractSPRequest::getApplication() const
         // Now find the application from the URL settings
         m_app=m_sp->getApplication(getRequestSettings().first->getString("applicationId").second);
         if (!m_app)
-            throw ConfigurationException("Unable to map request to application settings, check configuration.");
-    }    
+            throw ConfigurationException("Unable to map request to ApplicationOverride settings, check configuration.");
+    }
     return *m_app;
 }
 
-Session* AbstractSPRequest::getSession(bool checkTimeout, bool ignoreAddress, bool cache) const
+Session* AbstractSPRequest::getSession(bool checkTimeout, bool ignoreAddress, bool cache)
 {
     // Only attempt this once.
     if (cache && m_sessionTried)
@@ -81,17 +110,10 @@ Session* AbstractSPRequest::getSession(bool checkTimeout, bool ignoreAddress, bo
     else if (cache)
         m_sessionTried = true;
 
-    // Get session ID from cookie.
-    const Application& app = getApplication();
-    pair<string,const char*> shib_cookie = app.getCookieNameProps("_shibsession_");
-    const char* session_id = getCookie(shib_cookie.first.c_str());
-    if (!session_id || !*session_id)
-        return NULL;
-
     // Need address checking and timeout settings.
-    time_t timeout=0;
+    time_t timeout=3600;
     if (checkTimeout || !ignoreAddress) {
-        const PropertySet* props=app.getPropertySet("Sessions");
+        const PropertySet* props=getApplication().getPropertySet("Sessions");
         if (props) {
             if (checkTimeout) {
                 pair<bool,unsigned int> p=props->getUnsignedInt("timeout");
@@ -106,7 +128,7 @@ Session* AbstractSPRequest::getSession(bool checkTimeout, bool ignoreAddress, bo
 
     // The cache will either silently pass a session or NULL back, or throw an exception out.
     Session* session = getServiceProvider().getSessionCache()->find(
-        session_id, app, ignoreAddress ? NULL : getRemoteAddr().c_str(), checkTimeout ? &timeout : NULL
+        getApplication(), *this, ignoreAddress ? NULL : getRemoteAddr().c_str(), checkTimeout ? &timeout : NULL
         );
     if (cache)
         m_session = session;
@@ -134,17 +156,6 @@ void AbstractSPRequest::setRequestURI(const char* uri)
                 m_uri += uri;
                 break;
             }
-            else if (*uri == ';') {
-                // If this is Java being stupid, skip everything up to the query string, if any.
-                if (!strncmp(uri, ";jsessionid=", 12)) {
-                    if (uri = strchr(uri, '?'))
-                        m_uri += uri;
-                    break;
-                }
-                else {
-                    m_uri += *uri;
-                }
-            }
             else if (*uri != '%') {
                 m_uri += *uri;
             }
@@ -160,6 +171,11 @@ void AbstractSPRequest::setRequestURI(const char* uri)
     }
 }
 
+const char* AbstractSPRequest::getRequestURI() const
+{
+    return m_uri.c_str();
+}
+
 const char* AbstractSPRequest::getRequestURL() const
 {
     if (m_url.empty()) {
@@ -167,7 +183,7 @@ const char* AbstractSPRequest::getRequestURL() const
         int port = getPort();
         const char* scheme = getScheme();
         m_url = string(scheme) + "://" + getHostname();
-        if ((!strcmp(scheme,"http") && port!=80) || (!strcmp(scheme,"https") && port!=443)) { 
+        if ((!strcmp(scheme,"http") && port!=80) || (!strcmp(scheme,"https") && port!=443)) {
             ostringstream portstr;
             portstr << port;
             m_url += ":" + portstr.str();
@@ -177,11 +193,17 @@ const char* AbstractSPRequest::getRequestURL() const
     return m_url.c_str();
 }
 
+string AbstractSPRequest::getRemoteAddr() const
+{
+    pair<bool,const char*> addr = getRequestSettings().first->getString("REMOTE_ADDR");
+    return addr.first ? getHeader(addr.second) : "";
+}
+
 const char* AbstractSPRequest::getParameter(const char* name) const
 {
     if (!m_parser)
         m_parser=new CGIParser(*this);
-    
+
     pair<CGIParser::walker,CGIParser::walker> bounds=m_parser->getParameters(name);
     return (bounds.first==bounds.second) ? NULL : bounds.first->second;
 }
@@ -199,37 +221,6 @@ vector<const char*>::size_type AbstractSPRequest::getParameters(const char* name
     return values.size();
 }
 
-const char* AbstractSPRequest::getCookie(const char* name) const
-{
-    if (m_cookieMap.empty()) {
-        string cookies=getHeader("Cookie");
-
-        string::size_type pos=0,cname,namelen,val,vallen;
-        while (pos !=string::npos && pos < cookies.length()) {
-            while (isspace(cookies[pos])) pos++;
-            cname=pos;
-            pos=cookies.find_first_of("=",pos);
-            if (pos == string::npos)
-                break;
-            namelen=pos-cname;
-            pos++;
-            if (pos==cookies.length())
-                break;
-            val=pos;
-            pos=cookies.find_first_of(";",pos);
-            if (pos != string::npos) {
-                vallen=pos-val;
-                pos++;
-                m_cookieMap.insert(make_pair(cookies.substr(cname,namelen),cookies.substr(val,vallen)));
-            }
-            else
-                m_cookieMap.insert(make_pair(cookies.substr(cname,namelen),cookies.substr(val)));
-        }
-    }
-    map<string,string>::const_iterator lookup=m_cookieMap.find(name);
-    return (lookup==m_cookieMap.end()) ? NULL : lookup->second.c_str();
-}
-
 const char* AbstractSPRequest::getHandlerURL(const char* resource) const
 {
     if (!resource)
@@ -237,7 +228,22 @@ const char* AbstractSPRequest::getHandlerURL(const char* resource) const
 
     if (!m_handlerURL.empty() && resource && !strcmp(getRequestURL(),resource))
         return m_handlerURL.c_str();
-        
+
+    string stackresource;
+    if (resource && *resource == '/') {
+        // Compute a URL to the root of the site and point resource at constructed string.
+        int port = getPort();
+        const char* scheme = getScheme();
+        stackresource = string(scheme) + "://" + getHostname();
+        if ((!strcmp(scheme,"http") && port!=80) || (!strcmp(scheme,"https") && port!=443)) {
+            ostringstream portstr;
+            portstr << port;
+            stackresource += ":" + portstr.str();
+        }
+        stackresource += resource;
+        resource = stackresource.c_str();
+    }
+
 #ifdef HAVE_STRCASECMP
     if (!resource || (strncasecmp(resource,"http://",7) && strncasecmp(resource,"https://",8)))
 #else
@@ -245,9 +251,9 @@ const char* AbstractSPRequest::getHandlerURL(const char* resource) const
 #endif
         throw ConfigurationException("Target resource was not an absolute URL.");
 
-    bool ssl_only=false;
+    bool ssl_only=true;
     const char* handler=NULL;
-    const PropertySet* props=m_app->getPropertySet("Sessions");
+    const PropertySet* props=getApplication().getPropertySet("Sessions");
     if (props) {
         pair<bool,bool> p=props->getBool("handlerSSL");
         if (p.first)
@@ -256,11 +262,11 @@ const char* AbstractSPRequest::getHandlerURL(const char* resource) const
         if (p2.first)
             handler=p2.second;
     }
-    
+
     // Should never happen...
     if (!handler || (*handler!='/' && strncmp(handler,"http:",5) && strncmp(handler,"https:",6)))
         throw ConfigurationException(
-            "Invalid handlerURL property ($1) in Application ($2)",
+            "Invalid handlerURL property ($1) in <Sessions> element for Application ($2)",
             params(2, handler ? handler : "null", m_app->getId())
             );