[shibboleth-sp2] 72/89: SSPCPP-466 - Filtering of duplicate values from headers

Ferenc Wágner wferi at moszumanska.debian.org
Thu Sep 1 09:24:11 UTC 2016


This is an automated email from the git hooks/post-receive script.

wferi pushed a commit to branch master
in repository shibboleth-sp2.

commit ec61dd16063a546c1325d7dfefa01b3e598f3bb6
Author: Scott Cantor <cantor.2 at osu.edu>
Date:   Tue Jun 21 10:40:39 2016 -0400

    SSPCPP-466 - Filtering of duplicate values from headers
    
    https://issues.shibboleth.net/jira/browse/SSPCPP-466
---
 schemas/shibboleth-2.0-native-sp-config.xsd |   1 +
 shibsp/ServiceProvider.cpp                  | 160 ++++++++++++++++++----------
 2 files changed, 105 insertions(+), 56 deletions(-)

diff --git a/schemas/shibboleth-2.0-native-sp-config.xsd b/schemas/shibboleth-2.0-native-sp-config.xsd
index e643c9a..d3b51c4 100644
--- a/schemas/shibboleth-2.0-native-sp-config.xsd
+++ b/schemas/shibboleth-2.0-native-sp-config.xsd
@@ -247,6 +247,7 @@
     <attribute name="exportAssertion" type="boolean"/>
     <attribute name="exportStdVars" type="boolean"/>
     <attribute name="exportCookie" type="boolean"/>
+    <attribute name="exportDuplicateValues" type="boolean"/>
     <attribute name="redirectToSSL" type="unsignedInt"/>
     <attribute name="entityID" type="anyURI"/>
     <attribute name="discoveryURL" type="anyURI"/>
diff --git a/shibsp/ServiceProvider.cpp b/shibsp/ServiceProvider.cpp
index e69e3b7..310ae94 100644
--- a/shibsp/ServiceProvider.cpp
+++ b/shibsp/ServiceProvider.cpp
@@ -162,6 +162,108 @@ namespace shibsp {
         app.clearAttributeHeaders(request);
         request.clearHeader("REMOTE_USER", "HTTP_REMOTE_USER");
     }
+
+    void SHIBSP_DLLLOCAL exportAttributes(SPRequest& request, const Session* session, RequestMapper::Settings settings) {
+
+        pair<bool,const char*> enc = settings.first->getString("encoding");
+        if (enc.first && strcmp(enc.second, "URL"))
+            throw ConfigurationException("Unsupported value for 'encoding' content setting ($1).", params(1,enc.second));
+
+        const URLEncoder* encoder = XMLToolingConfig::getConfig().getURLEncoder();
+
+        pair<bool,bool> exportDups = settings.first->getBool("exportDuplicateValues");
+        const multimap<string,const Attribute*>& attributes = session->getIndexedAttributes();
+
+        // Default export strategy will include duplicates.
+        if (!exportDups.first || exportDups.second) {
+            for (multimap<string,const Attribute*>::const_iterator a = attributes.begin(); a != attributes.end(); ++a) {
+                if (a->second->isInternal())
+                    continue;
+                string header(request.getApplication().getSecureHeader(request, a->first.c_str()));
+                const vector<string>& vals = a->second->getSerializedValues();
+                for (vector<string>::const_iterator v = vals.begin(); v != vals.end(); ++v) {
+                    if (!header.empty())
+                        header += ';';
+                    if (enc.first) {
+                        // If URL-encoding, any semicolons will get escaped anyway.
+                        header += encoder->encode(v->c_str());
+                    }
+                    else {
+                        string::size_type pos = v->find_first_of(';', string::size_type(0));
+                        if (pos != string::npos) {
+                            string value(*v);
+                            for (; pos != string::npos; pos = value.find_first_of(';', pos)) {
+                                value.insert(pos, "\\");
+                                pos += 2;
+                            }
+                            header += value;
+                        }
+                        else {
+                            header += (*v);
+                        }
+                    }
+                }
+                request.getApplication().setHeader(request, a->first.c_str(), header.c_str());
+            }
+        }
+        else {
+            // Capture values in a map of sets to check for duplicates on the fly.
+            map< string,set<string> > valueMap;
+            for (multimap<string,const Attribute*>::const_iterator a = attributes.begin(); a != attributes.end(); ++a) {
+                if (a->second->isInternal())
+                    continue;
+                const vector<string>& vals = a->second->getSerializedValues();
+                valueMap[a->first].insert(vals.begin(), vals.end());
+            }
+
+            // Export the mapped sets to the headers.
+            for (map< string,set<string> >::const_iterator deduped = valueMap.begin(); deduped != valueMap.end(); ++deduped) {
+                string header;
+                for (set<string>::const_iterator v = deduped->second.begin(); v != deduped->second.end(); ++v) {
+                    if (!header.empty())
+                        header += ';';
+                    if (enc.first) {
+                        // If URL-encoding, any semicolons will get escaped anyway.
+                        header += encoder->encode(v->c_str());
+                    }
+                    else {
+                        string::size_type pos = v->find_first_of(';', string::size_type(0));
+                        if (pos != string::npos) {
+                            string value(*v);
+                            for (; pos != string::npos; pos = value.find_first_of(';', pos)) {
+                                value.insert(pos, "\\");
+                                pos += 2;
+                            }
+                            header += value;
+                        }
+                        else {
+                            header += (*v);
+                        }
+                    }
+                }
+                request.getApplication().setHeader(request, deduped->first.c_str(), header.c_str());
+            }
+        }
+
+        // Check for REMOTE_USER.
+        bool remoteUserSet = false;
+        const vector<string>& rmids = request.getApplication().getRemoteUserAttributeIds();
+        for (vector<string>::const_iterator rmid = rmids.begin(); !remoteUserSet && rmid != rmids.end(); ++rmid) {
+            pair<multimap<string,const Attribute*>::const_iterator,multimap<string,const Attribute*>::const_iterator> matches =
+                attributes.equal_range(*rmid);
+            for (; matches.first != matches.second; ++matches.first) {
+                const vector<string>& vals = matches.first->second->getSerializedValues();
+                if (!vals.empty()) {
+                    if (enc.first)
+                        request.setRemoteUser(encoder->encode(vals.front().c_str()).c_str());
+                    else
+                        request.setRemoteUser(vals.front().c_str());
+                    remoteUserSet = true;
+                    break;
+                }
+            }
+        }
+    }
 };
 
 void SHIBSP_API shibsp::registerServiceProviders()
@@ -482,12 +584,6 @@ pair<bool,long> ServiceProvider::doExport(SPRequest& request, bool requireSessio
         		return make_pair(false, 0L);	// just bail silently
         }
 
-		pair<bool,const char*> enc = settings.first->getString("encoding");
-		if (enc.first && strcmp(enc.second, "URL"))
-			throw ConfigurationException("Unsupported value for 'encoding' content setting ($1).", params(1,enc.second));
-
-        const URLEncoder* encoder = XMLToolingConfig::getConfig().getURLEncoder();
-
         app->setHeader(request, "Shib-Application-ID", app->getId());
         app->setHeader(request, "Shib-Session-ID", session->getID());
 
@@ -543,7 +639,7 @@ pair<bool,long> ServiceProvider::doExport(SPRequest& request, bool requireSessio
                     count++;
                     *(exportName.rbegin()) = '0' + (count%10);
                     *(++exportName.rbegin()) = '0' + (count/10);
-                    string fullURL = baseURL + encoder->encode(*tokenids);
+                    string fullURL = baseURL + XMLToolingConfig::getConfig().getURLEncoder()->encode(*tokenids);
                     app->setHeader(request, exportName.c_str(), fullURL.c_str());
                 }
                 app->setHeader(request, "Shib-Assertion-Count", exportName.c_str() + 15);
@@ -551,55 +647,7 @@ pair<bool,long> ServiceProvider::doExport(SPRequest& request, bool requireSessio
         }
 
         // Export the attributes.
-        const multimap<string,const Attribute*>& attributes = session->getIndexedAttributes();
-        for (multimap<string,const Attribute*>::const_iterator a = attributes.begin(); a != attributes.end(); ++a) {
-            if (a->second->isInternal())
-                continue;
-            string header(app->getSecureHeader(request, a->first.c_str()));
-            const vector<string>& vals = a->second->getSerializedValues();
-            for (vector<string>::const_iterator v = vals.begin(); v != vals.end(); ++v) {
-                if (!header.empty())
-                    header += ";";
-				if (enc.first) {
-					// If URL-encoding, any semicolons will get escaped anyway.
-					header += encoder->encode(v->c_str());
-				}
-				else {
-					string::size_type pos = v->find_first_of(';', string::size_type(0));
-					if (pos != string::npos) {
-						string value(*v);
-						for (; pos != string::npos; pos = value.find_first_of(';', pos)) {
-							value.insert(pos, "\\");
-							pos += 2;
-						}
-						header += value;
-					}
-					else {
-						header += (*v);
-					}
-				}
-            }
-            app->setHeader(request, a->first.c_str(), header.c_str());
-        }
-
-        // Check for REMOTE_USER.
-        bool remoteUserSet = false;
-        const vector<string>& rmids = app->getRemoteUserAttributeIds();
-        for (vector<string>::const_iterator rmid = rmids.begin(); !remoteUserSet && rmid != rmids.end(); ++rmid) {
-            pair<multimap<string,const Attribute*>::const_iterator,multimap<string,const Attribute*>::const_iterator> matches =
-                attributes.equal_range(*rmid);
-            for (; matches.first != matches.second; ++matches.first) {
-                const vector<string>& vals = matches.first->second->getSerializedValues();
-                if (!vals.empty()) {
-					if (enc.first)
-						request.setRemoteUser(encoder->encode(vals.front().c_str()).c_str());
-					else
-						request.setRemoteUser(vals.front().c_str());
-                    remoteUserSet = true;
-                    break;
-                }
-            }
-        }
+        exportAttributes(request, session, settings);
 
         return make_pair(false,0L);
     }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-shibboleth/shibboleth-sp2.git



More information about the Pkg-shibboleth-devel mailing list