X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=shibsp%2Fhandler%2Fimpl%2FWAYFSessionInitiator.cpp;h=b04f0187e267da729744dad3270bbc193daf69c1;hb=c51bfd77603cf0ddb0b5e374c35586a8435895d6;hp=92de9004d73bd45420e760d0cc429fe5457a8779;hpb=f5d5edeafe98f6322238730ff34ef86dc5220e04;p=shibboleth%2Fcpp-sp.git diff --git a/shibsp/handler/impl/WAYFSessionInitiator.cpp b/shibsp/handler/impl/WAYFSessionInitiator.cpp index 92de900..b04f018 100644 --- a/shibsp/handler/impl/WAYFSessionInitiator.cpp +++ b/shibsp/handler/impl/WAYFSessionInitiator.cpp @@ -1,17 +1,21 @@ -/* - * 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 +/** + * Licensed to the University Corporation for Advanced Internet + * Development, Inc. (UCAID) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. * - * http://www.apache.org/licenses/LICENSE-2.0 + * UCAID licenses this file to you 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 * - * 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. + * 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. */ /** @@ -27,14 +31,21 @@ #include "handler/AbstractHandler.h" #include "handler/SessionInitiator.h" +#ifndef SHIBSP_LITE +# include +#else +# include "lite/SAMLConstants.h" +#endif + #include +#include #include #include using namespace shibsp; using namespace opensaml; using namespace xmltooling; -using namespace log4cpp; +using namespace boost; using namespace std; namespace shibsp { @@ -48,7 +59,7 @@ namespace shibsp { { public: WAYFSessionInitiator(const DOMElement* e, const char* appId) - : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".SessionInitiator")), m_url(NULL) { + : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT ".SessionInitiator.WAYF"), nullptr, &m_remapper), m_url(nullptr) { pair url = getString("URL"); if (!url.first) throw ConfigurationException("WAYF SessionInitiator requires a URL property."); @@ -56,7 +67,11 @@ namespace shibsp { } virtual ~WAYFSessionInitiator() {} - pair run(SPRequest& request, const char* entityID=NULL, bool isHandler=true) const; + pair run(SPRequest& request, string& entityID, bool isHandler=true) const; + + const XMLCh* getProtocolFamily() const { + return samlconstants::SAML11_PROTOCOL_ENUM; + } private: const char* m_url; @@ -73,62 +88,98 @@ namespace shibsp { }; -pair WAYFSessionInitiator::run(SPRequest& request, const char* entityID, bool isHandler) const +pair WAYFSessionInitiator::run(SPRequest& request, string& 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); + if (!entityID.empty() || !checkCompatibility(request, isHandler)) + return make_pair(false, 0L); string target; - const char* option; - const Handler* ACS=NULL; - const Application& app=request.getApplication(); + pair prop; + const Handler* ACS = nullptr; + const Application& app = request.getApplication(); + pair discoveryURL = pair(true, m_url); if (isHandler) { - option=request.getParameter("acsIndex"); - if (option) - ACS=app.getAssertionConsumerServiceByIndex(atoi(option)); - - option = request.getParameter("target"); - if (option) - target = option; - recoverRelayState(request.getApplication(), request, target, false); + 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"); + } + + 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); + request.getApplication().limitRedirect(request, target.c_str()); + + 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"); } - if (!ACS) - ACS = app.getDefaultAssertionConsumerService(); + if (!ACS) { + // Try fixed index property. + pair index = getUnsignedInt("acsIndex", request, HANDLER_PROPERTY_MAP|HANDLER_PROPERTY_FIXED); + if (index.first) + ACS = app.getAssertionConsumerServiceByIndex(index.second); + } - m_log.debug("sending request to WAYF (%s)", m_url); + // If we picked by index, validate the ACS for use with this protocol. + if (!ACS || !XMLString::equals(samlconstants::SAML11_PROTOCOL_ENUM, ACS->getProtocolFamily())) { + if (ACS) + request.log(SPRequest::SPWarn, "invalid acsIndex property, or non-SAML 1.x ACS, using default SAML 1.x ACS"); + ACS = app.getAssertionConsumerServiceByProtocol(getProtocolFamily()); + if (!ACS) + throw ConfigurationException("Unable to locate a SAML 1.x ACS endpoint to use for response."); + } + + if (!discoveryURL.first) + discoveryURL.second = m_url; + m_log.debug("sending request to WAYF (%s)", discoveryURL.second); + // 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 ? ACS->getString("Location") : pair(false,NULL); - if (loc.first) ACSloc+=loc.second; + string ACSloc = request.getHandlerURL(target.c_str()); + 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. - 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(app, request, request, target.c_str()); // WAYF requires a target value. if (target.empty()) target = "default"; - 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=" + urlenc->encode(target.c_str()) + + string req=string(discoveryURL.second) + (strchr(discoveryURL.second,'?') ? '&' : '?') + "shire=" + urlenc->encode(ACSloc.c_str()) + + "&time=" + lexical_cast(time(nullptr)) + "&target=" + urlenc->encode(target.c_str()) + "&providerId=" + urlenc->encode(app.getString("entityID").second); return make_pair(true, request.sendRedirect(req.c_str()));