[cpp-sp] branch main updated: CPPSP-36 - Implement passthrough handler
Codeberg
noreply at shibboleth.net
Tue Dec 23 17:49:23 UTC 2025
This is an automated email from the git hooks/post-receive script.
codeberg pushed a commit to branch main
in repository cpp-sp.
View the commit online:
https://codeberg.org/Shibboleth/cpp-sp/commit/4b41368267780589aed2944d7833f9fe8c438478
The following commit(s) were added to refs/heads/main by this push:
new 4b413682 CPPSP-36 - Implement passthrough handler
4b413682 is described below
commit 4b41368267780589aed2944d7833f9fe8c438478
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Dec 23 12:48:02 2025 -0500
CPPSP-36 - Implement passthrough handler
https://shibboleth.atlassian.net/browse/CPPSP-36
Add support for absolute handlers.
---
shibsp/Agent.cpp | 76 ++++++++++++++++------
shibsp/handler/HandlerConfiguration.h | 14 +++-
.../handler/impl/DefaultHandlerConfiguration.cpp | 70 +++++++++++++-------
shibsp/remoting/ddf.h | 1 +
shibsp/remoting/impl/ddf.cpp | 11 +++-
5 files changed, 125 insertions(+), 47 deletions(-)
diff --git a/shibsp/Agent.cpp b/shibsp/Agent.cpp
index 0ca0503f..724da36e 100644
--- a/shibsp/Agent.cpp
+++ b/shibsp/Agent.cpp
@@ -118,8 +118,6 @@ long Agent::handleError(SPRequest& request, const Session* session, exception* e
pair<bool,long> Agent::doAuthentication(SPRequest& request, bool handler) const
{
- string targetURL = request.getRequestURL();
-
try {
RequestMapper::Settings settings = request.getRequestSettings();
@@ -143,7 +141,27 @@ pair<bool,long> Agent::doAuthentication(SPRequest& request, bool handler) const
}
}
- const char* handlerURL=request.getHandlerURL(targetURL.c_str());
+ // First check if this is a request to an absolute handler location.
+ const HandlerConfiguration& handlerConfig = request.getAgent().getHandlerConfiguration(
+ request.getRequestSettings().first->getString(RequestMapper::HANDLER_CONFIG_ID_PROP_NAME));
+ const Handler* absolute = handlerConfig.getAbsoluteHandler(request);
+ if (absolute) {
+ // Either dispatch directly or just pass back control based on parameter to this method.
+ if (handler) {
+ pair<bool,long> hret = absolute->run(request);
+ // Did the handler run successfully?
+ if (hret.first) {
+ return hret;
+ }
+ throw ConfigurationException("Configured Shibboleth handler failed to process the request.");
+ }
+ else {
+ return make_pair(true, request.returnOK());
+ }
+ }
+
+ const char* targetURL = request.getRequestURL();
+ const char* handlerURL=request.getHandlerURL(targetURL);
if (!handlerURL) {
throw ConfigurationException("Cannot determine handler from resource URL, check configuration.");
}
@@ -152,7 +170,19 @@ pair<bool,long> Agent::doAuthentication(SPRequest& request, bool handler) const
// directly or just pass back control based on parameter to this method.
if (boost::contains(targetURL, handlerURL)) {
if (handler) {
- return doHandler(request);
+ // We dispatch based on our path info. We know the request URL begins with or equals the handler URL,
+ // so the path info is the next character (or null).
+ const Handler* relative = handlerConfig.getRelativeHandler(targetURL + strlen(handlerURL));
+ if (!relative) {
+ throw ConfigurationException("Shibboleth handler invoked at an unconfigured location.");
+ }
+
+ pair<bool,long> hret = relative->run(request);
+ // Did the handler run successfully?
+ if (hret.first) {
+ return hret;
+ }
+ throw ConfigurationException("Configured Shibboleth handler failed to process the request.");
}
else {
return make_pair(true, request.returnOK());
@@ -186,7 +216,7 @@ pair<bool,long> Agent::doAuthentication(SPRequest& request, bool handler) const
catch (const exception& e) {
request.warn("error during session lookup: %s", e.what());
// If it's not a retryable session failure, we throw to the outer handler for reporting.
- if (dynamic_cast<const SessionValidationException*>(&e) == nullptr) {
+ if (!dynamic_cast<const SessionValidationException*>(&e)) {
throw;
}
}
@@ -223,10 +253,7 @@ pair<bool,long> Agent::doAuthentication(SPRequest& request, bool handler) const
return make_pair(true, request.returnOK());
}
- // No session, but we require one. Initiate a new session.
- const HandlerConfiguration& handlerConfig = request.getAgent().getHandlerConfiguration(
- request.getRequestSettings().first->getString(RequestMapper::HANDLER_CONFIG_ID_PROP_NAME));
-
+ // No session, but we require one.
// Dispatch to SessionInitiator. This MUST handle the request, or we want to fail here.
// Used to fall through into doExport, but this is a cleaner exit path.
pair<bool,long> ret = handlerConfig.getSessionInitiator().run(request, false);
@@ -251,8 +278,7 @@ pair<bool,long> Agent::doAuthentication(SPRequest& request, bool handler) const
pair<bool,long> Agent::doAuthorization(SPRequest& request) const
{
unique_lock<Session> session;
- string targetURL = request.getRequestURL();
-
+
try {
RequestMapper::Settings settings = request.getRequestSettings();
@@ -311,7 +337,6 @@ pair<bool,long> Agent::doAuthorization(SPRequest& request) const
pair<bool,long> Agent::doExport(SPRequest& request, bool requireSession) const
{
unique_lock<Session> session;
- string targetURL = request.getRequestURL();
try {
RequestMapper::Settings settings = request.getRequestSettings();
@@ -361,8 +386,6 @@ pair<bool,long> Agent::doExport(SPRequest& request, bool requireSession) const
pair<bool,long> Agent::doHandler(SPRequest& request) const
{
- const char* targetURL = request.getRequestURL();
-
try {
RequestMapper::Settings settings = request.getRequestSettings();
@@ -385,27 +408,40 @@ pair<bool,long> Agent::doHandler(SPRequest& request) const
}
}
+ const HandlerConfiguration& handlerConfig = request.getAgent().getHandlerConfiguration(
+ request.getRequestSettings().first->getString(RequestMapper::HANDLER_CONFIG_ID_PROP_NAME));
+
+ // First check if this is a request to an absolute handler location.
+ const Handler* handler = handlerConfig.getAbsoluteHandler(request);
+ if (handler) {
+ pair<bool,long> hret = handler->run(request);
+ // Did the handler run successfully?
+ if (hret.first) {
+ return hret;
+ }
+ throw ConfigurationException("Configured Shibboleth handler failed to process the request.");
+ }
+
+ // Otherwise check for a relative handler.
+ const char* targetURL = request.getRequestURL();
const char* handlerURL = request.getHandlerURL(targetURL);
if (!handlerURL) {
throw ConfigurationException("Cannot determine handler from resource URL, check configuration.");
}
// Make sure we only process handler requests and advance into the URL to find the handler's path.
- if (!boost::contains(targetURL, handlerURL))
+ if (!boost::contains(targetURL, handlerURL)) {
return make_pair(true, request.returnDecline());
+ }
// We dispatch based on our path info. We know the request URL begins with or equals the handler URL,
// so the path info is the next character (or null).
-
- const HandlerConfiguration& handlerConfig = request.getAgent().getHandlerConfiguration(
- request.getRequestSettings().first->getString(RequestMapper::HANDLER_CONFIG_ID_PROP_NAME));
- const Handler* handler = handlerConfig.getHandler(targetURL + strlen(handlerURL));
+ handler = handlerConfig.getRelativeHandler(targetURL + strlen(handlerURL));
if (!handler) {
throw ConfigurationException("Shibboleth handler invoked at an unconfigured location.");
}
pair<bool,long> hret = handler->run(request);
-
// Did the handler run successfully?
if (hret.first) {
return hret;
diff --git a/shibsp/handler/HandlerConfiguration.h b/shibsp/handler/HandlerConfiguration.h
index 906c1c4d..23139887 100644
--- a/shibsp/handler/HandlerConfiguration.h
+++ b/shibsp/handler/HandlerConfiguration.h
@@ -24,6 +24,7 @@
#include <shibsp/base.h>
#include <memory>
+#include <utility>
namespace shibsp {
@@ -42,6 +43,15 @@ namespace shibsp {
public:
virtual ~HandlerConfiguration();
+ /**
+ * Gets the Handler installed at an absolute path if one is installed.
+ *
+ * @param path absolute path to map to a Handler
+ *
+ * @return the Handler configured at the request's location, or null
+ */
+ virtual const Handler* getAbsoluteHandler(SPRequest& request) const=0;
+
/**
* Gets the Handler installed at a particular path, relative to a "base" URL used for
* triggering all Handlers.
@@ -50,7 +60,7 @@ namespace shibsp {
*
* @return the Handler configured at the supplied location, or null
*/
- virtual const Handler* getHandler(const char* path) const=0;
+ virtual const Handler* getRelativeHandler(const char* path) const=0;
/**
* Gets the Handler used for SSO session initiation.
@@ -75,7 +85,7 @@ namespace shibsp {
* <p>Legacy configurations designed to avoid externally visible changes may continue
* to operate multiple handlers to support different SSO bindings or patterns, while
* newer deployments should avoid this practice and stick to a single location. The
- * "meta-informatin" required to support this legacy practice will be embedded within
+ * "meta-information" required to support this legacy practice will be embedded within
* the structure returned.</p>
*
* @param handlerURL the handler base URL with which to prefix the token consumer
diff --git a/shibsp/handler/impl/DefaultHandlerConfiguration.cpp b/shibsp/handler/impl/DefaultHandlerConfiguration.cpp
index 7843a677..b87a072d 100644
--- a/shibsp/handler/impl/DefaultHandlerConfiguration.cpp
+++ b/shibsp/handler/impl/DefaultHandlerConfiguration.cpp
@@ -28,6 +28,7 @@
#include "logging/Category.h"
#include "remoting/ddf.h"
+#include <boost/algorithm/string.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
@@ -46,13 +47,15 @@ namespace {
DefaultHandlerConfiguration(const char* pathname);
~DefaultHandlerConfiguration() {}
- const Handler* getHandler(const char* path) const;
+ const Handler* getAbsoluteHandler(SPRequest& request) const;
+ const Handler* getRelativeHandler(const char* path) const;
const Handler& getSessionInitiator() const;
DDF getTokenConsumerInfo(const char* handlerURL=nullptr) const;
private:
ptree m_pt;
- map<string,unique_ptr<Handler>> m_handlerMap;
+ map<string,unique_ptr<Handler>> m_absoluteHandlerMap;
+ map<string,unique_ptr<Handler>> m_relativeHandlerMap;
const Handler* m_sessionInitiator;
DDF m_tokenConsumerConfig;
};
@@ -89,8 +92,10 @@ DefaultHandlerConfiguration::DefaultHandlerConfiguration(const char* pathname)
throw ConfigurationException("Multiple SessionInitiator handlers were configured, only one is permitted.");
}
+ bool relative = false;
string handlerPath(child.first);
if (handlerPath.front() != '/') {
+ relative = true;
handlerPath = '/' + handlerPath;
}
@@ -100,25 +105,33 @@ DefaultHandlerConfiguration::DefaultHandlerConfiguration(const char* pathname)
unique_ptr<Handler> handler(AgentConfig::getConfig().HandlerManager.newPlugin(
type.get(), pair<ptree&,const char*>(child.second, handlerPath.c_str()), false));
- m_handlerMap[handlerPath] = std::move(handler);
- log.info("config (%s) installed %s handler at %s", pathname, type.get().c_str(), handlerPath.c_str());
-
- // Save off a single SessionInitiator.
- if (*type == SESSION_INITIATOR_HANDLER) {
- m_sessionInitiator = m_handlerMap[handlerPath].get();
- }
- else if (*type == TOKEN_CONSUMER_HANDLER) {
- DDF tokenConsumer(nullptr);
- // String value of DDF is the handler location.
- tokenConsumer.string(handlerPath.c_str());
- m_tokenConsumerConfig.add(tokenConsumer);
-
- // Check for legacy "binding" value to carry along with path as the name of the node.
- boost::optional<string> legacyBinding = child.second.get_optional<string>(LEGACY_BINDING_PROP_NAME);
- if (legacyBinding) {
- tokenConsumer.name(legacyBinding->c_str());
+ if (relative) {
+ // Save off a single SessionInitiator.
+ if (*type == SESSION_INITIATOR_HANDLER) {
+ m_sessionInitiator = handler.get();
+ }
+ else if (*type == TOKEN_CONSUMER_HANDLER) {
+ DDF tokenConsumer(nullptr);
+ // String value of DDF is the handler location.
+ tokenConsumer.string(handlerPath);
+ m_tokenConsumerConfig.add(tokenConsumer);
+
+ // Check for legacy "binding" value to carry along with path as the name of the node.
+ boost::optional<string> legacyBinding = child.second.get_optional<string>(LEGACY_BINDING_PROP_NAME);
+ if (legacyBinding) {
+ tokenConsumer.name(legacyBinding.get());
+ }
}
+ m_relativeHandlerMap[handlerPath] = std::move(handler);
}
+ else if (type.get() != PASSTHROUGH_HANDLER) {
+ throw ConfigurationException("Only Passtrhough handlers may be absolute.");
+ }
+ else {
+ m_absoluteHandlerMap[handlerPath] = std::move(handler);
+ }
+ log.info("config (%s) installed %s %s handler at %s", pathname, relative ? "relative" : "absolute",
+ type.get().c_str(), handlerPath.c_str());
}
// If a single token consumer with no binding label is installed, convert list to a string node.
@@ -130,13 +143,26 @@ DefaultHandlerConfiguration::DefaultHandlerConfiguration(const char* pathname)
}
}
-const Handler* DefaultHandlerConfiguration::getHandler(const char* path) const
+const Handler* DefaultHandlerConfiguration::getAbsoluteHandler(SPRequest& request) const
+{
+ // Check for a request URI (minus query string) that matches an absolute handler.
+ string wrapped_uri(request.getRequestURI());
+ wrapped_uri = wrapped_uri.substr(0, wrapped_uri.find(';'));
+ const auto& mapping = m_absoluteHandlerMap.find(wrapped_uri.substr(0, wrapped_uri.find('?')));
+ if (mapping != m_absoluteHandlerMap.end()) {
+ return mapping->second.get();
+ }
+
+ return nullptr;
+}
+
+const Handler* DefaultHandlerConfiguration::getRelativeHandler(const char* path) const
{
if (path) {
string wrap(path);
wrap = wrap.substr(0, wrap.find(';'));
- const auto& mapping = m_handlerMap.find(wrap.substr(0, wrap.find('?')));
- if (mapping != m_handlerMap.end()) {
+ const auto& mapping = m_relativeHandlerMap.find(wrap.substr(0, wrap.find('?')));
+ if (mapping != m_relativeHandlerMap.end()) {
return mapping->second.get();
}
}
diff --git a/shibsp/remoting/ddf.h b/shibsp/remoting/ddf.h
index 1ce82409..77c2fe52 100644
--- a/shibsp/remoting/ddf.h
+++ b/shibsp/remoting/ddf.h
@@ -58,6 +58,7 @@ namespace shibsp {
// property accessors
const char* name() const;
DDF& name(const char* n);
+ DDF& name(const std::string& n);
// basic type checking
bool isnull() const;
diff --git a/shibsp/remoting/impl/ddf.cpp b/shibsp/remoting/impl/ddf.cpp
index 0e7fd5ba..3eb114a4 100644
--- a/shibsp/remoting/impl/ddf.cpp
+++ b/shibsp/remoting/impl/ddf.cpp
@@ -201,15 +201,15 @@ const char* DDF::name() const
return (m_handle) ? m_handle->name : nullptr;
}
-DDF& DDF::name(const char* name)
+DDF& DDF::name(const char* n)
{
char trunc_name[MAX_NAME_LEN+1]="";
if (m_handle) {
if (m_handle->name)
free(m_handle->name);
- if (name && *name) {
- strncpy(trunc_name,name,MAX_NAME_LEN);
+ if (n && *n) {
+ strncpy(trunc_name, n, MAX_NAME_LEN);
trunc_name[MAX_NAME_LEN]='\0';
m_handle->name=ddf_strdup(trunc_name);
if (!m_handle->name)
@@ -221,6 +221,11 @@ DDF& DDF::name(const char* name)
return *this;
}
+DDF& DDF::name(const std::string& n)
+{
+ return name(n.c_str());
+}
+
bool DDF::isnull() const
{
return m_handle ? false : true;
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list