Merge in updated Apache POST body code.
authorcantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Wed, 30 May 2007 17:31:39 +0000 (17:31 +0000)
committercantor <cantor@cb58f699-b61c-0410-a6fe-9272a202ed29>
Wed, 30 May 2007 17:31:39 +0000 (17:31 +0000)
Add per-initiator ACS defaulting to handle different SAML versions.

git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@2269 cb58f699-b61c-0410-a6fe-9272a202ed29

apache/mod_apache.cpp
apache/mod_shib20.vcproj
apache/mod_shib22.vcproj
configs/shibboleth.xml.in
schemas/shibboleth-2.0-native-sp-config.xsd
shibsp/handler/impl/SAML2SessionInitiator.cpp
shibsp/handler/impl/Shib1SessionInitiator.cpp
shibsp/handler/impl/WAYFSessionInitiator.cpp

index 91e196f..417892f 100644 (file)
@@ -66,6 +66,7 @@
 
 #ifndef SHIB_APACHE_13
 #include <http_request.h>
+#include <apr_buckets.h>
 #include <apr_strings.h>
 #include <apr_pools.h>
 #endif
@@ -328,6 +329,7 @@ public:
   const char* getRequestBody() const {
     if (m_gotBody || m_req->method_number==M_GET)
         return m_body.c_str();
+#ifdef SHIB_APACHE_13
     // Read the posted data
     if (ap_setup_client_block(m_req, REQUEST_CHUNKED_DECHUNK) != OK) {
         m_gotBody=true;
@@ -350,6 +352,39 @@ public:
       m_body.append(buff, len);
     }
     ap_kill_timeout(m_req);
+#else
+    const char *data;
+    apr_size_t len;
+    int seen_eos = 0;
+    apr_bucket_brigade* bb = apr_brigade_create(m_req->pool, m_req->connection->bucket_alloc);
+    do {
+        apr_bucket *bucket;
+        apr_status_t rv = ap_get_brigade(m_req->input_filters, bb, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN);
+        if (rv != APR_SUCCESS) {
+            log(SPError, "Apache function (ap_get_brigade) failed while reading request body.");
+            break;
+        }
+
+        for (bucket = APR_BRIGADE_FIRST(bb); bucket != APR_BRIGADE_SENTINEL(bb); bucket = APR_BUCKET_NEXT(bucket)) {
+            if (APR_BUCKET_IS_EOS(bucket)) {
+                seen_eos = 1;
+                break;
+            }
+
+            /* We can't do much with this. */
+            if (APR_BUCKET_IS_FLUSH(bucket))
+                continue;
+
+            /* read */
+            apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
+            if (len > 0)
+                m_body.append(data, len);
+        }
+        apr_brigade_cleanup(bb);
+    } while (!seen_eos);
+    apr_brigade_destroy(bb);
+    m_gotBody=true;
+#endif
     return m_body.c_str();
   }
   void clearHeader(const char* name) {
index 662a4a1..a1ac6ef 100644 (file)
                        />
                        <Tool
                                Name="VCLinkerTool"
-                               AdditionalDependencies="log4cpp.lib xerces-c_2.lib libapr.lib libhttpd.lib xmltooling-lite1.lib"
+                               AdditionalDependencies="log4cpp.lib xerces-c_2.lib libapr.lib libaprutil.lib libhttpd.lib xmltooling-lite1.lib"
                                OutputFile="mod_shib20___Win32_Release/mod_shib_20.so"
                                LinkIncremental="1"
                                SuppressStartupBanner="true"
-                               AdditionalLibraryDirectories="&quot;..\..\cpp-xmltooling\Release&quot;,\httpd-2.0.52\srclib\apr\Release,\httpd-2.0.52\Release"
+                               AdditionalLibraryDirectories="&quot;..\..\cpp-xmltooling\Release&quot;;\Apache2\lib"
                                ProgramDatabaseFile=".\mod_shib20___Win32_Release/mod_shib_20.pdb"
                                ImportLibrary=".\mod_shib20___Win32_Release/mod_shib_20.lib"
                                TargetMachine="1"
                        />
                        <Tool
                                Name="VCLinkerTool"
-                               AdditionalDependencies="log4cppD.lib xerces-c_2D.lib libapr.lib libhttpd.lib xmltooling-lite1D.lib"
+                               AdditionalDependencies="log4cppD.lib xerces-c_2D.lib libapr.lib libaprutil.lib libhttpd.lib xmltooling-lite1D.lib"
                                OutputFile="mod_shib20___Win32_Debug/mod_shib_20.so"
                                LinkIncremental="2"
                                SuppressStartupBanner="true"
-                               AdditionalLibraryDirectories="&quot;..\..\cpp-xmltooling\Debug&quot;;\httpd-2.0.52\srclib\apr\Debug,\httpd-2.0.52\Debug"
+                               AdditionalLibraryDirectories="&quot;..\..\cpp-xmltooling\Debug&quot;;\Apache2D\lib"
                                GenerateDebugInformation="true"
                                ImportLibrary=".\mod_shib20___Win32_Debug/mod_shib_20.lib"
                                TargetMachine="1"
index 80e8921..989dd78 100644 (file)
@@ -75,7 +75,7 @@
                        />\r
                        <Tool\r
                                Name="VCLinkerTool"\r
-                               AdditionalDependencies="log4cpp.lib xerces-c_2.lib xmltooling-lite1.lib libapr-1.lib libhttpd.lib"\r
+                               AdditionalDependencies="log4cpp.lib xerces-c_2.lib xmltooling-lite1.lib libapr-1.lib libaprutil-1.lib libhttpd.lib"\r
                                OutputFile="mod_shib22___Win32_Release/mod_shib_22.so"\r
                                LinkIncremental="1"\r
                                SuppressStartupBanner="true"\r
                        />\r
                        <Tool\r
                                Name="VCLinkerTool"\r
-                               AdditionalDependencies="log4cppD.lib xerces-c_2D.lib xmltooling-lite1D.lib libapr-1.lib libhttpd.lib"\r
+                               AdditionalDependencies="log4cppD.lib xerces-c_2D.lib xmltooling-lite1D.lib libapr-1.lib libaprutil-1.lib libhttpd.lib"\r
                                OutputFile="mod_shib22___Win32_Debug/mod_shib_22.so"\r
                                LinkIncremental="2"\r
                                SuppressStartupBanner="true"\r
index f7d7ebc..170ff7e 100644 (file)
                        -->
 
                        <!-- Default example directs to a specific IdP's SSO service (favoring SAML 2 over Shib 1). -->
-                       <SessionInitiator type="Chaining" Location="/Login" isDefault="true" id="example.org"
+                       <SessionInitiator type="Chaining" Location="/Login" isDefault="true" id="idp.example.org"
                                        relayState="cookie" entityID="https://idp.example.org/shibboleth">
-                               <SessionInitiator type="SAML2" template="@-PKGSYSCONFDIR-@/bindingTemplate.html"/>
-                               <SessionInitiator type="Shibboleth"/>
+                               <SessionInitiator type="SAML2" defaultACSIndex="1" template="@-PKGSYSCONFDIR-@/bindingTemplate.html"/>
+                               <SessionInitiator type="Shibboleth" defaultACSIndex="3"/>
                        </SessionInitiator>
                        
                        <!-- An example using an old-style WAYF, which means Shib 1 only unless an entityID is provided. -->
                        <SessionInitiator type="Chaining" Location="/WAYF" id="WAYF" relayState="cookie">
-                               <SessionInitiator type="SAML2" template="@-PKGSYSCONFDIR-@/bindingTemplate.html"/>
-                               <SessionInitiator type="Shibboleth"/>
-                               <SessionInitiator type="WAYF" URL="https://wayf.example.org/WAYF"/>
+                               <SessionInitiator type="SAML2" defaultACSIndex="1" template="@-PKGSYSCONFDIR-@/bindingTemplate.html"/>
+                               <SessionInitiator type="Shibboleth" defaultACSIndex="3"/>
+                               <SessionInitiator type="WAYF" defaultACSIndex="3" URL="https://wayf.example.org/WAYF"/>
                        </SessionInitiator>
 
                        <!-- An example supporting the new-style of discovery service. -->
                        <SessionInitiator type="Chaining" Location="/DS" id="DS" relayState="cookie">
                                <SessionInitiator type="SAML2" template="@-PKGSYSCONFDIR-@/bindingTemplate.html"/>
-                               <SessionInitiator type="Shibboleth"/>
+                               <SessionInitiator type="Shibboleth" defaultACSIndex="3"/>
                                <SessionInitiator type="SAMLDS" URL="https://ds.example.org/DS"/>
                        </SessionInitiator>
                        
                        are used when sessions are initiated to determine how to tell the IdP where and
                        how to return the response.
                        -->
-                       <md:AssertionConsumerService Location="/SAML2/POST" index="1" isDefault="true"
+                       <md:AssertionConsumerService Location="/SAML2/POST" index="1"
                                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"/>
                        <md:AssertionConsumerService Location="/SAML2/Artifact" index="2"
                                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"/>
index f36f284..50ee9f2 100644 (file)
                                        <attribute name="template" type="anyURI"/>\r
                                        <attribute name="postArtifact" type="boolean"/>\r
                                        <attribute name="acsByIndex" type="boolean"/>\r
+                                       <attribute name="defaultACSIndex" type="unsignedShort"/>\r
                                        <anyAttribute namespace="##any" processContents="lax"/>\r
                                </restriction>\r
                        </complexContent>\r
index 5f9e87f..afb5e70 100644 (file)
@@ -197,7 +197,7 @@ pair<bool,long> SAML2SessionInitiator::run(SPRequest& request, const char* entit
         if (option) {
             ACS = app.getAssertionConsumerServiceByIndex(atoi(option));
             if (!ACS)
-                throw ConfigurationException("AssertionConsumerService with index ($1) not found, check configuration.", params(1,option));
+                request.log(SPRequest::SPWarn, "invalid acsIndex specified in request, using default ACS location");
         }
 
         option = request.getParameter("target");
@@ -240,13 +240,24 @@ pair<bool,long> SAML2SessionInitiator::run(SPRequest& request, const char* entit
 
     m_log.debug("attempting to initiate session using SAML 2.0 with provider (%s)", entityID);
 
-    // To invoke the request builder, the key requirement is to figure out how and whether
+    if (!ACS) {
+        pair<bool,unsigned int> index = getUnsignedInt("defaultACSIndex");
+        if (index.first) {
+            ACS = app.getAssertionConsumerServiceByIndex(index.second);
+            if (!ACS)
+                request.log(SPRequest::SPWarn, "invalid defaultACSIndex, using default ACS location");
+        }
+        if (!ACS)
+            ACS = app.getDefaultAssertionConsumerService();
+    }
+
+    // To invoke the request builder, the key requirement is to figure out how
     // to express the ACS, by index or value, and if by value, where.
 
     SPConfig& conf = SPConfig::getConfig();
     if (conf.isEnabled(SPConfig::OutOfProcess)) {
         if (!acsByIndex.first || acsByIndex.second) {
-            // Pass by Index. This also allows for defaulting it entirely and sending nothing.
+            // Pass by Index.
             if (isHandler) {
                 // We may already have RelayState set if we looped back here,
                 // but just in case target is a resource, we reset it back.
@@ -266,9 +277,6 @@ pair<bool,long> SAML2SessionInitiator::run(SPRequest& request, const char* entit
         }
 
         // Since we're not passing by index, we need to fully compute the return URL and binding.
-        if (!ACS)
-            ACS = app.getDefaultAssertionConsumerService();
-
         // Compute the ACS URL. We add the ACS location to the base handlerURL.
         string ACSloc=request.getHandlerURL(target.c_str());
         pair<bool,const char*> loc=ACS ? ACS->getString("Location") : pair<bool,const char*>(false,NULL);
@@ -312,9 +320,6 @@ pair<bool,long> SAML2SessionInitiator::run(SPRequest& request, const char* entit
     }
     else {
         // Since we're not passing by index, we need to fully compute the return URL and binding.
-        if (!ACS)
-            ACS = app.getDefaultAssertionConsumerService();
-
         // Compute the ACS URL. We add the ACS location to the base handlerURL.
         string ACSloc=request.getHandlerURL(target.c_str());
         pair<bool,const char*> loc=ACS ? ACS->getString("Location") : pair<bool,const char*>(false,NULL);
index c085095..d98b608 100644 (file)
@@ -117,8 +117,11 @@ pair<bool,long> Shib1SessionInitiator::run(SPRequest& request, const char* entit
 
     if (isHandler) {
         option=request.getParameter("acsIndex");
-        if (option)
+        if (option) {
             ACS = app.getAssertionConsumerServiceByIndex(atoi(option));
+            if (!ACS)
+                request.log(SPRequest::SPWarn, "invalid acsIndex specified in request, using default ACS location");
+        }
 
         option = request.getParameter("target");
         if (option)
@@ -134,9 +137,17 @@ pair<bool,long> Shib1SessionInitiator::run(SPRequest& request, const char* entit
         target=request.getRequestURL();
     }
 
-    // Since we're not passing by index, we need to fully compute the return URL and binding.
-    if (!ACS)
-        ACS = app.getDefaultAssertionConsumerService();
+    // Since we're not passing by index, we need to fully compute the return URL.
+    if (!ACS) {
+        pair<bool,unsigned int> index = getUnsignedInt("defaultACSIndex");
+        if (index.first) {
+            ACS = app.getAssertionConsumerServiceByIndex(index.second);
+            if (!ACS)
+                request.log(SPRequest::SPWarn, "invalid defaultACSIndex, using default ACS location");
+        }
+        if (!ACS)
+            ACS = app.getDefaultAssertionConsumerService();
+    }
 
     // Compute the ACS URL. We add the ACS location to the base handlerURL.
     string ACSloc=request.getHandlerURL(target.c_str());
index 92de900..be55d48 100644 (file)
@@ -87,8 +87,11 @@ pair<bool,long> WAYFSessionInitiator::run(SPRequest& request, const char* entity
 
     if (isHandler) {
         option=request.getParameter("acsIndex");
-        if (option)
+        if (option) {
             ACS=app.getAssertionConsumerServiceByIndex(atoi(option));
+            if (!ACS)
+                request.log(SPRequest::SPWarn, "invalid acsIndex specified in request, using default ACS location");
+        }
 
         option = request.getParameter("target");
         if (option)
@@ -101,8 +104,17 @@ pair<bool,long> WAYFSessionInitiator::run(SPRequest& request, const char* entity
         target=request.getRequestURL();
     }
     
-    if (!ACS)
-        ACS = app.getDefaultAssertionConsumerService();
+    // Since we're not passing by index, we need to fully compute the return URL.
+    if (!ACS) {
+        pair<bool,unsigned int> index = getUnsignedInt("defaultACSIndex");
+        if (index.first) {
+            ACS = app.getAssertionConsumerServiceByIndex(index.second);
+            if (!ACS)
+                request.log(SPRequest::SPWarn, "invalid defaultACSIndex, using default ACS location");
+        }
+        if (!ACS)
+            ACS = app.getDefaultAssertionConsumerService();
+    }
 
     m_log.debug("sending request to WAYF (%s)", m_url);