From 6c907f41ef5af1c8ab0d311280966df080d5e842 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Thu, 11 Mar 2010 17:12:38 +0000 Subject: [PATCH] https://issues.shibboleth.net/jira/browse/SSPCPP-263 --- Shibboleth.sln | 8 - adfs/adfs.cpp | 54 +- schemas/shibboleth-2.0-native-sp-config.xsd | 1439 +++++++++++---------- shibsp/AbstractSPRequest.cpp | 17 +- shibsp/handler/impl/AbstractHandler.cpp | 42 +- shibsp/handler/impl/FormSessionInitiator.cpp | 30 +- shibsp/handler/impl/SAML2SessionInitiator.cpp | 150 +-- shibsp/handler/impl/SAMLDSSessionInitiator.cpp | 81 +- shibsp/handler/impl/Shib1SessionInitiator.cpp | 47 +- shibsp/handler/impl/TransformSessionInitiator.cpp | 1 - shibsp/handler/impl/WAYFSessionInitiator.cpp | 57 +- 11 files changed, 965 insertions(+), 961 deletions(-) diff --git a/Shibboleth.sln b/Shibboleth.sln index c799c03..9e6cd25 100644 --- a/Shibboleth.sln +++ b/Shibboleth.sln @@ -157,16 +157,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{31B171C1-E EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Doc", "Doc", "{6ED5E3E7-1B0E-43FB-A8D1-77A0FCAE9AC8}" ProjectSection(SolutionItems) = preProject - doc\CREDITS.txt = doc\CREDITS.txt doc\FASTCGI.LICENSE = doc\FASTCGI.LICENSE - doc\LICENSE.txt = doc\LICENSE.txt - doc\LOG4CPP.LICENSE = doc\LOG4CPP.LICENSE - doc\logo.jpg = doc\logo.jpg - doc\main.css = doc\main.css doc\Makefile.am = doc\Makefile.am - doc\NOTICE.txt = doc\NOTICE.txt - doc\OPENSSL.LICENSE = doc\OPENSSL.LICENSE - doc\README.txt = doc\README.txt doc\RELEASE.txt = doc\RELEASE.txt EndProjectSection EndProject diff --git a/adfs/adfs.cpp b/adfs/adfs.cpp index 006c3bd..f724540 100644 --- a/adfs/adfs.cpp +++ b/adfs/adfs.cpp @@ -326,45 +326,42 @@ pair ADFSSessionInitiator::run(SPRequest& request, string& entityID, return make_pair(false,0L); string target; - const Handler* ACS=NULL; - const char* option; + pair prop; pair acClass; + const Handler* ACS=NULL; const Application& app=request.getApplication(); if (isHandler) { - option=request.getParameter("acsIndex"); - if (option) { - ACS = app.getAssertionConsumerServiceByIndex(atoi(option)); + prop.second = request.getParameter("acsIndex"); + if (prop.second && *prop.second) { + ACS = app.getAssertionConsumerServiceByIndex(atoi(prop.second)); if (!ACS) request.log(SPRequest::SPWarn, "invalid acsIndex specified in request, using acsIndex property"); } - option = request.getParameter("target"); - if (option) - target = option; + prop = getString("target", request); + if (prop.first) + target = prop.second; // Since we're passing the ACS by value, we need to compute the return URL, // so we'll need the target resource for real. - recoverRelayState(request.getApplication(), request, request, target, false); + recoverRelayState(app, request, request, target, false); - if (acClass.second = request.getParameter("authnContextClassRef")) - acClass.first = true; - else - acClass = getString("authnContextClassRef"); + acClass = getString("authnContextClassRef", request); } 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(); + // Check for a hardwired target value in the map or handler. + prop = getString("target", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); + if (prop.first) + target = prop.second; + else + target = request.getRequestURL(); - const PropertySet* settings = request.getRequestSettings().first; - acClass = settings->getString("authnContextClassRef"); - if (!acClass.first) - acClass = getString("authnContextClassRef"); + acClass = getString("authnContextClassRef", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); } if (!ACS) { - pair index = getUnsignedInt("acsIndex"); + pair index = getUnsignedInt("acsIndex", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); if (index.first) { ACS = app.getAssertionConsumerServiceByIndex(index.second); if (!ACS) @@ -392,16 +389,17 @@ pair ADFSSessionInitiator::run(SPRequest& request, string& entityID, // Since we're not passing by index, we need to fully compute the return URL. // Compute the ACS URL. We add the ACS location to the base handlerURL. string ACSloc=request.getHandlerURL(target.c_str()); - pair loc=ACS->getString("Location"); - if (loc.first) ACSloc+=loc.second; + prop = ACS->getString("Location"); + if (prop.first) + ACSloc += prop.second; 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. - target.erase(); - option = request.getParameter("target"); - if (option) - target = option; + // but we've turned it back into a resource by this point, so if there's + // a target on the URL, reset to that value. + prop.second = request.getParameter("target"); + if (prop.second && *prop.second) + target = prop.second; } m_log.debug("attempting to initiate session using ADFS with provider (%s)", entityID.c_str()); diff --git a/schemas/shibboleth-2.0-native-sp-config.xsd b/schemas/shibboleth-2.0-native-sp-config.xsd index 315b6ba..24497e5 100644 --- a/schemas/shibboleth-2.0-native-sp-config.xsd +++ b/schemas/shibboleth-2.0-native-sp-config.xsd @@ -10,724 +10,727 @@ blockDefault="substitution" version="2.4"> - - - - - - - 2.0 schema for XML-based configuration of Shibboleth Native SP instances. - First appearing in Shibboleth 2.0 release. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Root of configuration - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Container for extension libraries and custom configuration - - - - - - - - - - - - - - - - - - - - - References StorageService plugins - - - - - - - - - - - - - - - - - - References SessionCache plugins - - - - - - - - - - - - - - - - - - Ties ReplayCache to a custom StorageService - - - - - - - - - - Customizes an ArtifactMap - - - - - - - - - - - - Container for out-of-process (shibd) configuration - - - - - - - - - - - - - - - - Container for configuration of locally integrated or platform-specific - features (e.g. web server filters) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A simple example access policy language extension that supersedes Apache .htaccess - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Built-in request mapping syntax, decomposes URLs into Host/Path/Path/... - - - + + + + + + + 2.0 schema for XML-based configuration of Shibboleth Native SP instances. + First appearing in Shibboleth 2.0 release. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Root of configuration + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Container for extension libraries and custom configuration + + + + + + + + + + + + + + + + + + + + + References StorageService plugins + + + + + + + + + + + + + + + + + + References SessionCache plugins + + + + + + + + + + + + + + + + + + Ties ReplayCache to a custom StorageService + + + + + + + + + + Customizes an ArtifactMap + + + + + + + + + + + + Container for out-of-process (shibd) configuration + + + + + + + + + + + + + + + + Container for configuration of locally integrated or platform-specific + features (e.g. web server filters) + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Container for default settings and application-specific overrides - - - - - - - - - - - - - - - - - - - - - - - - - - - - Container for application-specific overrides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Container for specifying protocol handlers and session policy - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Used to reference Policy elements from profile endpoints. - - - - - - Used to specify handlers that can issue AuthnRequests or perform discovery - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Used to specify handlers that can issue LogoutRequests - - - - - - - - - - - - - - - - - - - - - Container for error templates and associated details - - - - - - - - - - - - - - - - - - - - - - - Container for specifying settings to use with particular peers - - - - - - - - - - - - - Used to specify locations to receive application notifications - - - - - - - - - - - - - - - - - - - Container for specifying sets of policy rules to apply to incoming messages - - - - - - Specifies a set of SecurityPolicyRule plugins - - - - - - - - - - - - - - - - - - - - - - Implementation-specific option to pass to SOAPTransport provider. - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + A simple example access policy language extension that supersedes Apache .htaccess + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Built-in request mapping syntax, decomposes URLs into Host/Path/Path/... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Container for default settings and application-specific overrides + + + + + + + + + + + + + + + + + + + + + + + + + + + + Container for application-specific overrides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Container for specifying protocol handlers and session policy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Used to reference Policy elements from profile endpoints. + + + + + + Used to specify handlers that can issue AuthnRequests or perform discovery + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Used to specify handlers that can issue LogoutRequests + + + + + + + + + + + + + + + + + + + + + Container for error templates and associated details + + + + + + + + + + + + + + + + + + + + + + + Container for specifying settings to use with particular peers + + + + + + + + + + + + + Used to specify locations to receive application notifications + + + + + + + + + + + + + + + + + + + Container for specifying sets of policy rules to apply to incoming messages + + + + + + Specifies a set of SecurityPolicyRule plugins + + + + + + + + + + + + + + + + + + + + + + Implementation-specific option to pass to SOAPTransport provider. + + + + + + + + + + + diff --git a/shibsp/AbstractSPRequest.cpp b/shibsp/AbstractSPRequest.cpp index 249db33..eb0c320 100644 --- a/shibsp/AbstractSPRequest.cpp +++ b/shibsp/AbstractSPRequest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2009 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. @@ -229,6 +229,21 @@ 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 diff --git a/shibsp/handler/impl/AbstractHandler.cpp b/shibsp/handler/impl/AbstractHandler.cpp index aa86b54..6e1a0ba 100644 --- a/shibsp/handler/impl/AbstractHandler.cpp +++ b/shibsp/handler/impl/AbstractHandler.cpp @@ -80,6 +80,23 @@ namespace shibsp { SHIBSP_DLLLOCAL PluginManager< Handler,string,pair >::Factory StatusHandlerFactory; SHIBSP_DLLLOCAL PluginManager< Handler,string,pair >::Factory SessionHandlerFactory; + void SHIBSP_DLLLOCAL absolutize(const HTTPRequest& request, string& url) { + if (url.empty()) + url = '/'; + if (url[0] == '/') { + // Compute a URL to the root of the site. + int port = request.getPort(); + const char* scheme = request.getScheme(); + string root = string(scheme) + "://" + request.getHostname(); + if ((!strcmp(scheme,"http") && port!=80) || (!strcmp(scheme,"https") && port!=443)) { + ostringstream portstr; + portstr << port; + root += ":" + portstr.str(); + } + url = root + url; + } + } + void SHIBSP_DLLLOCAL generateRandomHex(std::string& buf, unsigned int len) { static char DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; int r; @@ -95,6 +112,8 @@ namespace shibsp { buf += (DIGITS[0x0F & b2]); } } + + }; void SHIBSP_API shibsp::registerHandlers() @@ -234,9 +253,10 @@ void Handler::recoverRelayState( StorageService* storage = conf.getServiceProvider()->getStorageService(ssid.c_str()); if (storage) { ssid = key; - if (storage->readString("RelayState",ssid.c_str(),&relayState)>0) { + if (storage->readString("RelayState",ssid.c_str(),&relayState) > 0) { if (clear) storage->deleteString("RelayState",ssid.c_str()); + absolutize(request, relayState); return; } else @@ -263,6 +283,7 @@ void Handler::recoverRelayState( } else { relayState = out.string(); + absolutize(request, relayState); return; } } @@ -290,6 +311,7 @@ void Handler::recoverRelayState( exp += "; expires=Mon, 01 Jan 2001 00:00:00 GMT"; response.setCookie(relay_cookie.first.c_str(), exp.c_str()); } + absolutize(request, relayState); return; } } @@ -301,20 +323,12 @@ void Handler::recoverRelayState( if (relayState.empty() || relayState == "default" || relayState == "cookie") { pair homeURL=application.getString("homeURL"); if (homeURL.first) - relayState=homeURL.second; - else { - // Compute a URL to the root of the site. - int port = request.getPort(); - const char* scheme = request.getScheme(); - relayState = string(scheme) + "://" + request.getHostname(); - if ((!strcmp(scheme,"http") && port!=80) || (!strcmp(scheme,"https") && port!=443)) { - ostringstream portstr; - portstr << port; - relayState += ":" + portstr.str(); - } - relayState += '/'; - } + relayState = homeURL.second; + else + relayState = '/'; } + + absolutize(request, relayState); } AbstractHandler::AbstractHandler( diff --git a/shibsp/handler/impl/FormSessionInitiator.cpp b/shibsp/handler/impl/FormSessionInitiator.cpp index f419280..4dea39e 100644 --- a/shibsp/handler/impl/FormSessionInitiator.cpp +++ b/shibsp/handler/impl/FormSessionInitiator.cpp @@ -77,33 +77,39 @@ pair FormSessionInitiator::run(SPRequest& request, string& entityID, return make_pair(false,0L); string target; - const char* option; + pair prop; const Application& app=request.getApplication(); if (isHandler) { - option = request.getParameter("target"); - if (option) - target = option; + prop = getString("target", request); + if (prop.first) + target = prop.second; recoverRelayState(app, request, request, target, false); } else { - // We're running as a "virtual handler" from within the filter. - // The target resource is the current one. - target=request.getRequestURL(); + // Check for a hardwired target value in the map or handler. + prop = getString("target", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); + if (prop.first) + target = prop.second; + else + target = request.getRequestURL(); } // Compute the return URL. We start with a self-referential link. string returnURL=request.getHandlerURL(target.c_str()); pair thisloc = getString("Location"); - if (thisloc.first) returnURL += thisloc.second; + if (thisloc.first) + returnURL += thisloc.second; 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. - option = request.getParameter("target"); - if (option) - target = option; + // but we've turned it back into a resource by this point, so if there's + // a target on the URL, reset to that value. + prop.second = request.getParameter("target"); + if (prop.second && *prop.second) + target = prop.second; } + preserveRelayState(app, request, target); request.setContentType("text/html"); diff --git a/shibsp/handler/impl/SAML2SessionInitiator.cpp b/shibsp/handler/impl/SAML2SessionInitiator.cpp index 02e2550..30e303c 100644 --- a/shibsp/handler/impl/SAML2SessionInitiator.cpp +++ b/shibsp/handler/impl/SAML2SessionInitiator.cpp @@ -235,9 +235,8 @@ pair SAML2SessionInitiator::run(SPRequest& request, string& entityID, return make_pair(false,0L); string target; - string postData; + pair prop; const Handler* ACS=NULL; - const char* option; pair acClass, acComp, nidFormat, spQual; bool isPassive=false,forceAuthn=false; const Application& app=request.getApplication(); @@ -246,9 +245,9 @@ pair SAML2SessionInitiator::run(SPRequest& request, string& entityID, pair acsByIndex = ECP ? make_pair(true,false) : getBool("acsByIndex"); if (isHandler) { - option=request.getParameter("acsIndex"); - if (option) { - ACS = app.getAssertionConsumerServiceByIndex(atoi(option)); + prop.second = request.getParameter("acsIndex"); + if (prop.second && *prop.second) { + ACS = app.getAssertionConsumerServiceByIndex(atoi(prop.second)); if (!ACS) request.log(SPRequest::SPWarn, "invalid acsIndex specified in request, using acsIndex property"); else if (ECP && !XMLString::equals(ACS->getString("Binding").second, samlconstants::SAML20_BINDING_PAOS)) { @@ -257,82 +256,47 @@ pair SAML2SessionInitiator::run(SPRequest& request, string& entityID, } } - option = request.getParameter("target"); - if (option) - target = option; + prop = getString("target", request); + if (prop.first) + target = prop.second; // Always need to recover target URL to compute handler below. - recoverRelayState(request.getApplication(), request, request, target, false); + recoverRelayState(app, request, request, target, false); + + pair flag = getBool("isPassive", request); + isPassive = (flag.first && flag.second); - pair flag; - option = request.getParameter("isPassive"); - if (option) { - isPassive = (*option=='1' || *option=='t'); - } - else { - flag = getBool("isPassive"); - isPassive = (flag.first && flag.second); - } if (!isPassive) { - option = request.getParameter("forceAuthn"); - if (option) { - forceAuthn = (*option=='1' || *option=='t'); - } - else { - flag = getBool("forceAuthn"); - forceAuthn = (flag.first && flag.second); - } + flag = getBool("forceAuthn", request); + forceAuthn = (flag.first && flag.second); } - if (acClass.second = request.getParameter("authnContextClassRef")) - acClass.first = true; - else - acClass = getString("authnContextClassRef"); - - if (acComp.second = request.getParameter("authnContextComparison")) - acComp.first = true; - else - acComp = getString("authnContextComparison"); - - if (nidFormat.second = request.getParameter("NameIDFormat")) - nidFormat.first = true; - else - nidFormat = getString("NameIDFormat"); - - if (spQual.second = request.getParameter("SPNameQualifier")) - spQual.first = true; - else - spQual = getString("SPNameQualifier"); + // Populate via parameter, map, or property. + acClass = getString("authnContextClassRef", request); + acComp = getString("authnContextComparison", request); + nidFormat = getString("NameIDFormat", request); + spQual = getString("SPNameQualifier", request); } 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(); - const PropertySet* settings = request.getRequestSettings().first; - - pair flag = settings->getBool("isPassive"); - if (!flag.first) - flag = getBool("isPassive"); + // Check for a hardwired target value in the map or handler. + prop = getString("target", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); + if (prop.first) + target = prop.second; + else + target = request.getRequestURL(); + + pair flag = getBool("isPassive", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); isPassive = flag.first && flag.second; if (!isPassive) { - flag = settings->getBool("forceAuthn"); - if (!flag.first) - flag = getBool("forceAuthn"); + flag = getBool("forceAuthn", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); forceAuthn = flag.first && flag.second; } - acClass = settings->getString("authnContextClassRef"); - if (!acClass.first) - acClass = getString("authnContextClassRef"); - acComp = settings->getString("authnContextComparison"); - if (!acComp.first) - acComp = getString("authnContextComparison"); - nidFormat = settings->getString("NameIDFormat"); - if (!nidFormat.first) - nidFormat = getString("NameIDFormat"); - spQual = settings->getString("SPNameQualifier"); - if (!spQual.first) - spQual = getString("SPNameQualifier"); + // Populate via map or property. + acClass = getString("authnContextClassRef", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); + acComp = getString("authnContextComparison", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); + nidFormat = getString("NameIDFormat", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); + spQual = getString("SPNameQualifier", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); } if (ECP) @@ -348,7 +312,7 @@ pair SAML2SessionInitiator::run(SPRequest& request, string& entityID, ACS = handlers.front(); } else { - pair index = getUnsignedInt("acsIndex"); + pair index = getUnsignedInt("acsIndex", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); if (index.first) { ACS = app.getAssertionConsumerServiceByIndex(index.second); if (!ACS) @@ -381,7 +345,7 @@ pair SAML2SessionInitiator::run(SPRequest& request, string& entityID, // to express the ACS, by index or value, and if by value, where. // We have to compute the handlerURL no matter what, because we may need to // flip the index to an SSL-version. - string ACSloc=request.getHandlerURL(target.c_str()); + string ACSloc = request.getHandlerURL(target.c_str()); SPConfig& conf = SPConfig::getConfig(); if (conf.isEnabled(SPConfig::OutOfProcess)) { @@ -389,11 +353,11 @@ pair SAML2SessionInitiator::run(SPRequest& request, string& entityID, // 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. - target.erase(); - option = request.getParameter("target"); - if (option) - target = option; + // but we've turned it back into a resource by this point, so if there's + // a target on the URL, reset to that value. + prop.second = request.getParameter("target"); + if (prop.second && *prop.second) + target = prop.second; } // Determine index to use. @@ -425,16 +389,17 @@ pair SAML2SessionInitiator::run(SPRequest& request, string& entityID, // Since we're not passing by index, we need to fully compute the return URL and binding. // Compute the ACS URL. We add the ACS location to the base handlerURL. - pair loc=ACS ? ACS->getString("Location") : pair(false,NULL); - if (loc.first) ACSloc+=loc.second; + prop = ACS ? ACS->getString("Location") : pair(false,NULL); + if (prop.first) + ACSloc += prop.second; 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. - target.erase(); - option = request.getParameter("target"); - if (option) - target = option; + // but we've turned it back into a resource by this point, so if there's + // a target on the URL, reset to that value. + prop.second = request.getParameter("target"); + if (prop.second && *prop.second) + target = prop.second; } return doRequest( @@ -489,24 +454,25 @@ pair SAML2SessionInitiator::run(SPRequest& request, string& entityID, else { // Since we're not passing by index, we need to fully compute the return URL and binding. // Compute the ACS URL. We add the ACS location to the base handlerURL. - pair loc=ACS ? ACS->getString("Location") : pair(false,NULL); - if (loc.first) ACSloc+=loc.second; + prop = ACS ? ACS->getString("Location") : pair(false,NULL); + if (prop.first) + ACSloc += prop.second; in.addmember("acsLocation").string(ACSloc.c_str()); if (ACS) { - loc = ACS->getString("Binding"); - in.addmember("acsBinding").string(loc.second); - if (XMLString::equals(loc.second, samlconstants::SAML20_BINDING_HTTP_ARTIFACT)) + prop = ACS->getString("Binding"); + in.addmember("acsBinding").string(prop.second); + if (XMLString::equals(prop.second, samlconstants::SAML20_BINDING_HTTP_ARTIFACT)) in.addmember("artifact").integer(1); } } 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. - target.erase(); - option = request.getParameter("target"); - if (option) - target = option; + // but we've turned it back into a resource by this point, so if there's + // a target on the URL, reset to that value. + prop.second = request.getParameter("target"); + if (prop.second && *prop.second) + target = prop.second; } if (!target.empty()) in.addmember("RelayState").unsafe_string(target.c_str()); diff --git a/shibsp/handler/impl/SAMLDSSessionInitiator.cpp b/shibsp/handler/impl/SAMLDSSessionInitiator.cpp index d95c05e..10de535 100644 --- a/shibsp/handler/impl/SAMLDSSessionInitiator.cpp +++ b/shibsp/handler/impl/SAMLDSSessionInitiator.cpp @@ -150,45 +150,42 @@ pair SAMLDSSessionInitiator::run(SPRequest& request, string& entityID return make_pair(false,0L); string target; - const char* option; + pair prop; bool isPassive=false; const Application& app=request.getApplication(); pair discoveryURL = pair(true, m_url); if (isHandler) { - option = request.getParameter("SAMLDS"); - if (option && !strcmp(option,"1")) { + prop.second = request.getParameter("SAMLDS"); + if (prop.second && !strcmp(prop.second,"1")) { saml2md::MetadataException ex("No identity provider was selected by user."); ex.addProperty("statusCode", "urn:oasis:names:tc:SAML:2.0:status:Requester"); ex.addProperty("statusCode2", "urn:oasis:names:tc:SAML:2.0:status:NoAvailableIDP"); ex.raise(); } - option = request.getParameter("target"); - if (option) - target = option; - recoverRelayState(request.getApplication(), request, request, target, false); - - option = request.getParameter("isPassive"); - if (option) - isPassive = (*option=='t' || *option=='1'); - else { - pair passopt = getBool("isPassive"); - isPassive = passopt.first && passopt.second; - } + prop = getString("target", request); + if (prop.first) + target = prop.second; + + recoverRelayState(app, request, request, target, false); + + pair passopt = getBool("isPassive", request); + isPassive = passopt.first && passopt.second; - option = request.getParameter("discoveryURL"); - if (option) - discoveryURL.second = option; + prop.second = request.getParameter("discoveryURL"); + if (prop.second && *prop.second) + discoveryURL.second = prop.second; } 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 passopt = request.getRequestSettings().first->getBool("isPassive"); - if (!passopt.first) - passopt = getBool("isPassive"); + // Check for a hardwired target value in the map or handler. + prop = getString("target", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); + if (prop.first) + target = prop.second; + else + target = request.getRequestURL(); + + pair passopt = getBool("isPassive", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); isPassive = passopt.first && passopt.second; discoveryURL = request.getRequestSettings().first->getString("discoveryURL"); } @@ -198,21 +195,23 @@ pair SAMLDSSessionInitiator::run(SPRequest& request, string& entityID m_log.debug("sending request to SAMLDS (%s)", discoveryURL.second); // Compute the return URL. We start with a self-referential link. - string returnURL=request.getHandlerURL(target.c_str()); - pair thisloc = getString("Location"); - if (thisloc.first) returnURL += thisloc.second; + string returnURL = request.getHandlerURL(target.c_str()); + prop = getString("Location"); + if (prop.first) + returnURL += prop.second; returnURL += "?SAMLDS=1"; // signals us not to loop if we get no answer back 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. - option = request.getParameter("target"); - if (option) - target = option; + // but we've turned it back into a resource by this point, so if there's + // a target on the URL, reset to that value. + prop.second = request.getParameter("target"); + if (prop.second && *prop.second) + target = prop.second; } - preserveRelayState(request.getApplication(), request, target); + preserveRelayState(app, request, target); if (!isHandler) - preservePostData(request.getApplication(), request, request, target.c_str()); + preservePostData(app, request, request, target.c_str()); const URLEncoder* urlenc = XMLToolingConfig::getConfig().getURLEncoder(); if (isHandler) { @@ -231,15 +230,15 @@ pair SAMLDSSessionInitiator::run(SPRequest& request, string& entityID } else { // There's something in the query before target appears, so we have to find it. - thisloc.second = strstr(query,"&target="); - if (thisloc.second) { + prop.second = strstr(query, "&target="); + if (prop.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; + returnURL.append(query, prop.second - query); + query = prop.second + 8; // move up just past the equals sign. + prop.second = strchr(query, '&'); + if (prop.second) + returnURL += prop.second; } else { // No target in the existing query, so just append it as is. diff --git a/shibsp/handler/impl/Shib1SessionInitiator.cpp b/shibsp/handler/impl/Shib1SessionInitiator.cpp index 72f431b..cc2cd11 100644 --- a/shibsp/handler/impl/Shib1SessionInitiator.cpp +++ b/shibsp/handler/impl/Shib1SessionInitiator.cpp @@ -116,36 +116,38 @@ pair Shib1SessionInitiator::run(SPRequest& request, string& entityID, return make_pair(false,0L); string target; - string postData; + pair prop; const Handler* ACS=NULL; - const char* option; - const Application& app=request.getApplication(); + const Application& app = request.getApplication(); if (isHandler) { - option=request.getParameter("acsIndex"); - if (option) { - ACS = app.getAssertionConsumerServiceByIndex(atoi(option)); + prop.second = request.getParameter("acsIndex"); + if (prop.second && *prop.second) { + ACS = app.getAssertionConsumerServiceByIndex(atoi(prop.second)); if (!ACS) request.log(SPRequest::SPWarn, "invalid acsIndex specified in request, using acsIndex property"); } - option = request.getParameter("target"); - if (option) - target = option; + prop = getString("target", request); + if (prop.first) + target = prop.second; // Since we're passing the ACS by value, we need to compute the return URL, // so we'll need the target resource for real. - recoverRelayState(request.getApplication(), request, request, target, false); + recoverRelayState(app, request, request, target, false); } 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(); + // Check for a hardwired target value in the map or handler. + prop = getString("target", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); + if (prop.first) + target = prop.second; + else + target = request.getRequestURL(); } // Since we're not passing by index, we need to fully compute the return URL. if (!ACS) { - pair index = getUnsignedInt("acsIndex"); + pair index = getUnsignedInt("acsIndex", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); if (index.first) { ACS = app.getAssertionConsumerServiceByIndex(index.second); if (!ACS) @@ -171,17 +173,18 @@ pair Shib1SessionInitiator::run(SPRequest& request, string& entityID, } // Compute the ACS URL. We add the ACS location to the base handlerURL. - string ACSloc=request.getHandlerURL(target.c_str()); - pair loc=ACS ? ACS->getString("Location") : pair(false,NULL); - if (loc.first) ACSloc+=loc.second; + string ACSloc = request.getHandlerURL(target.c_str()); + prop = ACS ? ACS->getString("Location") : pair(false,NULL); + if (prop.first) + ACSloc += prop.second; 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. - target.erase(); - option = request.getParameter("target"); - if (option) - target = option; + // but we've turned it back into a resource by this point, so if there's + // a target on the URL, reset to that value. + prop.second = request.getParameter("target"); + if (prop.second && *prop.second) + target = prop.second; } // Is the in-bound binding artifact? diff --git a/shibsp/handler/impl/TransformSessionInitiator.cpp b/shibsp/handler/impl/TransformSessionInitiator.cpp index 590dbad..3aa012c 100644 --- a/shibsp/handler/impl/TransformSessionInitiator.cpp +++ b/shibsp/handler/impl/TransformSessionInitiator.cpp @@ -163,7 +163,6 @@ pair TransformSessionInitiator::run(SPRequest& request, string& entit if (entityID.empty() || !checkCompatibility(request, isHandler)) return make_pair(false,0L); - string target; const Application& app=request.getApplication(); m_log.debug("attempting to transform input (%s) into a valid entityID", entityID.c_str()); diff --git a/shibsp/handler/impl/WAYFSessionInitiator.cpp b/shibsp/handler/impl/WAYFSessionInitiator.cpp index e56f75e..86f9f45 100644 --- a/shibsp/handler/impl/WAYFSessionInitiator.cpp +++ b/shibsp/handler/impl/WAYFSessionInitiator.cpp @@ -86,39 +86,45 @@ pair WAYFSessionInitiator::run(SPRequest& request, string& entityID, return make_pair(false,0L); string target; - string postData; - const char* option; + pair prop; const Handler* ACS=NULL; const Application& app=request.getApplication(); pair discoveryURL = pair(true, m_url); if (isHandler) { - option=request.getParameter("acsIndex"); - if (option) { - ACS=app.getAssertionConsumerServiceByIndex(atoi(option)); + prop.second = request.getParameter("acsIndex"); + if (prop.second && *prop.second) { + ACS = app.getAssertionConsumerServiceByIndex(atoi(prop.second)); if (!ACS) request.log(SPRequest::SPWarn, "invalid acsIndex specified in request, using acsIndex property"); } - option = request.getParameter("target"); - if (option) - target = option; + prop = getString("target", request); + if (prop.first) + target = prop.second; + + // Since we're passing the ACS by value, we need to compute the return URL, + // so we'll need the target resource for real. recoverRelayState(request.getApplication(), request, request, target, false); - option = request.getParameter("discoveryURL"); - if (option) - discoveryURL.second = option; + prop.second = request.getParameter("discoveryURL"); + if (prop.second && *prop.second) + discoveryURL.second = prop.second; } 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(); + // Check for a hardwired target value in the map or handler. + prop = getString("target", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); + if (prop.first) + target = prop.second; + else + target = request.getRequestURL(); + discoveryURL = request.getRequestSettings().first->getString("discoveryURL"); } // Since we're not passing by index, we need to fully compute the return URL. if (!ACS) { - pair index = getUnsignedInt("acsIndex"); + pair index = getUnsignedInt("acsIndex", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); if (index.first) { ACS = app.getAssertionConsumerServiceByIndex(index.second); if (!ACS) @@ -148,20 +154,23 @@ pair WAYFSessionInitiator::run(SPRequest& request, string& entityID, m_log.debug("sending request to WAYF (%s)", discoveryURL.second); // Compute the ACS URL. We add the ACS location to the base handlerURL. - string ACSloc=request.getHandlerURL(target.c_str()); - pair loc=ACS ? ACS->getString("Location") : pair(false,NULL); - if (loc.first) ACSloc+=loc.second; + string ACSloc = request.getHandlerURL(target.c_str()); + prop = ACS ? ACS->getString("Location") : pair(false,NULL); + if (prop.first) + ACSloc += prop.second; 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. - option = request.getParameter("target"); - if (option) - target = option; + // but we've turned it back into a resource by this point, so if there's + // a target on the URL, reset to that value. + prop.second = request.getParameter("target"); + if (prop.second && *prop.second) + target = prop.second; } - preserveRelayState(request.getApplication(), request, target); + + preserveRelayState(app, request, target); if (!isHandler) - preservePostData(request.getApplication(), request, request, target.c_str()); + preservePostData(app, request, request, target.c_str()); // WAYF requires a target value. if (target.empty()) -- 2.1.4