Old and new discovery handlers.
authorScott Cantor <cantor.2@osu.edu>
Thu, 5 Apr 2007 02:35:23 +0000 (02:35 +0000)
committerScott Cantor <cantor.2@osu.edu>
Thu, 5 Apr 2007 02:35:23 +0000 (02:35 +0000)
shibsp/Makefile.am
shibsp/handler/impl/SAMLDSSessionInitiator.cpp [new file with mode: 0644]
shibsp/handler/impl/SessionInitiator.cpp
shibsp/handler/impl/Shib1SessionInitiator.cpp
shibsp/handler/impl/WAYFSessionInitiator.cpp [new file with mode: 0644]
shibsp/shibsp.vcproj

index 1683d89..f800d54 100644 (file)
@@ -101,8 +101,10 @@ libshibsp_la_SOURCES = \
        handler/impl/RemotedHandler.cpp \
        handler/impl/SAML1Consumer.cpp \
        handler/impl/SAML2Consumer.cpp \
+       handler/impl/SAMLDSSessionInitiator.cpp \
        handler/impl/SessionInitiator.cpp \
        handler/impl/Shib1SessionInitiator.cpp \
+       handler/impl/WAYFSessionInitiator.cpp \
        impl/RemotedSessionCache.cpp \
        impl/StorageServiceSessionCache.cpp \
        impl/XMLAccessControl.cpp \
diff --git a/shibsp/handler/impl/SAMLDSSessionInitiator.cpp b/shibsp/handler/impl/SAMLDSSessionInitiator.cpp
new file mode 100644 (file)
index 0000000..fc0b8d5
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ *  Copyright 2001-2007 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
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * SAMLDSSessionInitiator.cpp
+ * 
+ * SAML Discovery Service support.
+ */
+
+#include "internal.h"
+#include "Application.h"
+#include "exceptions.h"
+#include "SPRequest.h"
+#include "handler/AbstractHandler.h"
+#include "handler/SessionInitiator.h"
+
+#include <xmltooling/XMLToolingConfig.h>
+#include <xmltooling/util/URLEncoder.h>
+
+using namespace shibsp;
+using namespace opensaml;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+namespace shibsp {
+
+#if defined (_MSC_VER)
+    #pragma warning( push )
+    #pragma warning( disable : 4250 )
+#endif
+
+    class SHIBSP_DLLLOCAL SAMLDSSessionInitiator : public SessionInitiator, public AbstractHandler
+    {
+    public:
+        SAMLDSSessionInitiator(const DOMElement* e, const char* appId)
+                : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".SessionInitiator")), m_url(NULL), m_returnParam(NULL) {
+            pair<bool,const char*> url = getString("URL");
+            if (!url.first)
+                throw ConfigurationException("SAMLDS SessionInitiator requires a URL property.");
+            m_url = url.second;
+            url = getString("entityIDParam");
+            if (url.first)
+                m_returnParam = url.second;
+        }
+        virtual ~SAMLDSSessionInitiator() {}
+        
+        pair<bool,long> run(SPRequest& request, const char* entityID=NULL, bool isHandler=true) const;
+
+    private:
+        const char* m_url;
+        const char* m_returnParam;
+    };
+
+#if defined (_MSC_VER)
+    #pragma warning( pop )
+#endif
+
+    SessionInitiator* SHIBSP_DLLLOCAL SAMLDSSessionInitiatorFactory(const pair<const DOMElement*,const char*>& p)
+    {
+        return new SAMLDSSessionInitiator(p.first, p.second);
+    }
+
+};
+
+pair<bool,long> SAMLDSSessionInitiator::run(SPRequest& request, const char* entityID, bool isHandler) const
+{
+    // The IdP CANNOT be specified for us to run. Otherwise, we'd be redirecting to a DS
+    // anytime the IdP's metadata was wrong.
+    if (entityID && *entityID)
+        return make_pair(false,0);
+
+    string target;
+    bool isPassive=false;
+    const Application& app=request.getApplication();
+
+    if (isHandler) {
+        const char* option = request.getParameter("target");
+        if (option)
+            target = option;
+        recoverRelayState(request, target);
+
+        option = request.getParameter("isPassive");
+        if (option)
+            isPassive = !strcmp(option,"true");
+    }
+    else {
+        // We're running as a "virtual handler" from within the filter.
+        // The target resource is the current one and everything else is
+        // defaulted or set by content policy.
+        target=request.getRequestURL();
+        pair<bool,bool> passopt = getBool("isPassive");
+        isPassive = passopt.first && passopt.second;
+    }
+
+    m_log.debug("sending request to SAMLDS (%s)", m_url);
+
+    // Compute the return URL. We start with a self-referential link.
+    string returnURL=request.getHandlerURL(target.c_str());
+    pair<bool,const char*> thisloc = getString("Location");
+    if (thisloc.first) returnURL += thisloc.second;
+
+    preserveRelayState(request, target);
+
+    if (isHandler) {
+        // Now the hard part. The base assumption is to append the entire query string, if any,
+        // to the self-link. But we want to replace target with the RelayState-preserved value
+        // to hide it from the DS.
+        const char* query = request.getQueryString();
+        if (query) {
+            // See if it starts with target.
+            if (!strncmp(query, "target=", 7)) {
+                // We skip this altogether and advance the query past it to the first separator.
+                query = strchr(query, '&');
+                // If we still have more, just append it.
+                if (query && *(++query))
+                    returnURL = returnURL + '?' + query;
+            }
+            else {
+                // There's something in the query before target appears, so we have to find it.
+                thisloc.second = strstr(query,"&target=");
+                if (thisloc.second) {
+                    // We found it, so first append everything up to it.
+                    returnURL += '?';
+                    returnURL.append(query, thisloc.second - query);
+                    query = thisloc.second + 8; // move up just past the equals sign.
+                    thisloc.second = strchr(query, '&');
+                    if (thisloc.second)
+                        returnURL += thisloc.second;
+                }
+                else {
+                    // No target in the existing query, so just append it as is.
+                    returnURL = returnURL + '?' + query;
+                }
+            }
+        }
+
+        // Now append the sanitized target as needed.
+        if (!target.empty())
+            returnURL = returnURL + (returnURL.rfind('?')==string::npos ? '?' : '&') + "target=" + target;
+    }
+    else if (!target.empty()) {
+        // For a virtual handler, we just append target to the return link.
+        returnURL = returnURL + "?target=" + target;
+    }
+
+
+    const URLEncoder* urlenc = XMLToolingConfig::getConfig().getURLEncoder();
+
+    string req=string(m_url) + (strchr(m_url,'?') ? '&' : '?') + "entityID=" + urlenc->encode(app.getString("entityID").second) +
+        "&return=" + urlenc->encode(returnURL.c_str());
+    if (m_returnParam)
+        req = req + "&returnIDParam=" + m_returnParam;
+    if (isPassive)
+        req += "&isPassive=true";
+
+    return make_pair(true, request.sendRedirect(req.c_str()));
+}
index cb6a87d..6c4182c 100644 (file)
@@ -31,14 +31,17 @@ using namespace std;
 namespace shibsp {
     SHIBSP_DLLLOCAL PluginManager<SessionInitiator,pair<const DOMElement*,const char*>>::Factory ChainingSessionInitiatorFactory;
     SHIBSP_DLLLOCAL PluginManager<SessionInitiator,pair<const DOMElement*,const char*>>::Factory Shib1SessionInitiatorFactory;
+    SHIBSP_DLLLOCAL PluginManager<SessionInitiator,pair<const DOMElement*,const char*>>::Factory WAYFSessionInitiatorFactory;
+    SHIBSP_DLLLOCAL PluginManager<SessionInitiator,pair<const DOMElement*,const char*>>::Factory SAMLDSSessionInitiatorFactory;
 };
 
 void SHIBSP_API shibsp::registerSessionInitiators()
 {
     SPConfig& conf=SPConfig::getConfig();
-    
     conf.SessionInitiatorManager.registerFactory(CHAINING_SESSION_INITIATOR, ChainingSessionInitiatorFactory);
     conf.SessionInitiatorManager.registerFactory(SHIB1_SESSION_INITIATOR, Shib1SessionInitiatorFactory);
+    conf.SessionInitiatorManager.registerFactory(WAYF_SESSION_INITIATOR, WAYFSessionInitiatorFactory);
+    conf.SessionInitiatorManager.registerFactory(SAMLDS_SESSION_INITIATOR, SAMLDSSessionInitiatorFactory);
 }
 
 pair<bool,long> SessionInitiator::run(SPRequest& request, bool isHandler) const
index 0b6d5bc..1a43d2d 100644 (file)
@@ -22,7 +22,6 @@
 
 #include "internal.h"
 #include "Application.h"
-#include "exceptions.h"
 #include "SPRequest.h"
 #include "handler/AbstractHandler.h"
 #include "handler/SessionInitiator.h"
@@ -30,9 +29,7 @@
 
 #include <saml/saml2/metadata/Metadata.h>
 #include <saml/saml2/metadata/EndpointManager.h>
-#include <xercesc/util/XMLUniDefs.hpp>
 #include <xmltooling/XMLToolingConfig.h>
-#include <xmltooling/util/XMLHelper.h>
 #include <xmltooling/util/URLEncoder.h>
 
 using namespace shibsp;
diff --git a/shibsp/handler/impl/WAYFSessionInitiator.cpp b/shibsp/handler/impl/WAYFSessionInitiator.cpp
new file mode 100644 (file)
index 0000000..dcb8654
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ *  Copyright 2001-2007 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
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * WAYFSessionInitiator.cpp
+ * 
+ * Shibboleth WAYF support.
+ */
+
+#include "internal.h"
+#include "Application.h"
+#include "exceptions.h"
+#include "SPRequest.h"
+#include "handler/AbstractHandler.h"
+#include "handler/SessionInitiator.h"
+
+#include <xmltooling/XMLToolingConfig.h>
+#include <xmltooling/util/URLEncoder.h>
+
+using namespace shibsp;
+using namespace opensaml;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+namespace shibsp {
+
+#if defined (_MSC_VER)
+    #pragma warning( push )
+    #pragma warning( disable : 4250 )
+#endif
+
+    class SHIBSP_DLLLOCAL WAYFSessionInitiator : public SessionInitiator, public AbstractHandler
+    {
+    public:
+        WAYFSessionInitiator(const DOMElement* e, const char* appId)
+                : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".SessionInitiator")), m_url(NULL) {
+            pair<bool,const char*> url = getString("URL");
+            if (!url.first)
+                throw ConfigurationException("WAYF SessionInitiator requires a URL property.");
+            m_url = url.second;
+        }
+        virtual ~WAYFSessionInitiator() {}
+        
+        pair<bool,long> run(SPRequest& request, const char* entityID=NULL, bool isHandler=true) const;
+
+    private:
+        const char* m_url;
+    };
+
+#if defined (_MSC_VER)
+    #pragma warning( pop )
+#endif
+
+    SessionInitiator* SHIBSP_DLLLOCAL WAYFSessionInitiatorFactory(const pair<const DOMElement*,const char*>& p)
+    {
+        return new WAYFSessionInitiator(p.first, p.second);
+    }
+
+};
+
+pair<bool,long> WAYFSessionInitiator::run(SPRequest& request, const char* entityID, bool isHandler) const
+{
+    // The IdP CANNOT be specified for us to run. Otherwise, we'd be redirecting to a WAYF
+    // anytime the IdP's metadata was wrong.
+    if (entityID && *entityID)
+        return make_pair(false,0);
+
+    string target;
+    const Handler* ACS=NULL;
+    const Application& app=request.getApplication();
+
+    if (isHandler) {
+        const char* option=request.getParameter("acsIndex");
+        if (option)
+            ACS=app.getAssertionConsumerServiceByIndex(atoi(option));
+
+        option = request.getParameter("target");
+        if (option)
+            target = option;
+        recoverRelayState(request, target);
+    }
+    else {
+        // We're running as a "virtual handler" from within the filter.
+        // The target resource is the current one and everything else is defaulted.
+        target=request.getRequestURL();
+    }
+    
+    if (!ACS)
+        ACS = app.getDefaultAssertionConsumerService();
+
+    m_log.debug("sending request to WAYF (%s)", m_url);
+
+    // 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);
+    if (loc.first) ACSloc+=loc.second;
+
+    preserveRelayState(request, target);
+
+    char timebuf[16];
+    sprintf(timebuf,"%u",time(NULL));
+    const URLEncoder* urlenc = XMLToolingConfig::getConfig().getURLEncoder();
+    string req=string(m_url) + (strchr(m_url,'?') ? '&' : '?') + "shire=" + urlenc->encode(ACSloc.c_str()) +
+        "&time=" + timebuf + "&target=" + target +
+        "&providerId=" + urlenc->encode(app.getString("entityID").second);
+
+    return make_pair(true, request.sendRedirect(req.c_str()));
+}
index 7f7d96d..b7f3f32 100644 (file)
                                                >\r
                                        </File>\r
                                        <File\r
+                                               RelativePath=".\handler\impl\SAMLDSSessionInitiator.cpp"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
                                                RelativePath=".\handler\impl\SessionInitiator.cpp"\r
                                                >\r
                                        </File>\r
                                                RelativePath=".\handler\impl\Shib1SessionInitiator.cpp"\r
                                                >\r
                                        </File>\r
+                                       <File\r
+                                               RelativePath=".\handler\impl\WAYFSessionInitiator.cpp"\r
+                                               >\r
+                                       </File>\r
                                </Filter>\r
                        </Filter>\r
                </Filter>\r