X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=shibsp%2FServiceProvider.cpp;h=3ac5236055fb77aad116eaf417142f93b525331c;hb=HEAD;hp=8d12c3d7128eba2862db5444a13a994f2775372e;hpb=3968f4eac0a112d55ca7ec0041f9cdb98400e7b3;p=shibboleth%2Fcpp-sp.git diff --git a/shibsp/ServiceProvider.cpp b/shibsp/ServiceProvider.cpp index 8d12c3d..3ac5236 100644 --- a/shibsp/ServiceProvider.cpp +++ b/shibsp/ServiceProvider.cpp @@ -95,6 +95,7 @@ namespace shibsp { redirectErrors = props->getString("redirectErrors"); if (redirectErrors.first) { string loc(redirectErrors.second); + request.absolutize(loc); loc = loc + '?' + tp.toQueryString(); return request.sendRedirect(loc.c_str()); } @@ -148,6 +149,7 @@ namespace shibsp { void SHIBSP_DLLLOCAL clearHeaders(SPRequest& request) { const Application& app = request.getApplication(); + app.clearHeader(request, "Shib-Cookie-Name", "HTTP_SHIB_COOKIE_NAME"); app.clearHeader(request, "Shib-Session-ID", "HTTP_SHIB_SESSION_ID"); app.clearHeader(request, "Shib-Session-Index", "HTTP_SHIB_SESSION_INDEX"); app.clearHeader(request, "Shib-Identity-Provider", "HTTP_SHIB_IDENTITY_PROVIDER"); @@ -191,7 +193,7 @@ Remoted* ServiceProvider::regListener(const char* address, Remoted* listener) if (i != m_listenerMap.end()) ret = i->second; m_listenerMap[address] = listener; - Category::getInstance(SHIBSP_LOGCAT".ServiceProvider").info("registered remoted message endpoint (%s)",address); + Category::getInstance(SHIBSP_LOGCAT ".ServiceProvider").info("registered remoted message endpoint (%s)",address); return ret; } @@ -203,7 +205,7 @@ bool ServiceProvider::unregListener(const char* address, Remoted* current, Remot m_listenerMap[address] = restore; else m_listenerMap.erase(address); - Category::getInstance(SHIBSP_LOGCAT".ServiceProvider").info("unregistered remoted message endpoint (%s)",address); + Category::getInstance(SHIBSP_LOGCAT ".ServiceProvider").info("unregistered remoted message endpoint (%s)",address); return true; } return false; @@ -220,7 +222,7 @@ pair ServiceProvider::doAuthentication(SPRequest& request, bool handl #ifdef _DEBUG xmltooling::NDC ndc("doAuthentication"); #endif - Category& log = Category::getInstance(SHIBSP_LOGCAT".ServiceProvider"); + Category& log = Category::getInstance(SHIBSP_LOGCAT ".ServiceProvider"); const Application* app = nullptr; string targetURL = request.getRequestURL(); @@ -267,10 +269,11 @@ pair ServiceProvider::doAuthentication(SPRequest& request, bool handl return make_pair(true, request.returnOK()); } - // Three settings dictate how to proceed. + // These settings dictate how to proceed. pair authType = settings.first->getString("authType"); pair requireSession = settings.first->getBool("requireSession"); pair requireSessionWith = settings.first->getString("requireSessionWith"); + pair requireLogoutWith = settings.first->getString("requireLogoutWith"); // If no session is required AND the AuthType (an Apache-derived concept) isn't recognized, // then we ignore this request and consider it unprotected. Apache might lie to us if @@ -284,7 +287,7 @@ pair ServiceProvider::doAuthentication(SPRequest& request, bool handl Session* session = nullptr; try { - session = request.getSession(); + session = request.getSession(true, false, false); // don't cache it } catch (exception& e) { log.warn("error during session lookup: %s", e.what()); @@ -293,7 +296,32 @@ pair ServiceProvider::doAuthentication(SPRequest& request, bool handl throw; } - if (!session) { + Locker slocker(session, false); // pop existing lock on exit + if (session) { + // Check for logout interception. + if (requireLogoutWith.first) { + // Check for a completion parameter on the query string. + const char* qstr = request.getQueryString(); + if (!qstr || !strstr(qstr, "shiblogoutdone=1")) { + // First leg of circuit, so we redirect to the logout endpoint specified with this URL as a return location. + string selfurl = request.getRequestURL(); + if (qstr) + selfurl += '&'; + else + selfurl += '?'; + selfurl += "shiblogoutdone=1"; + string loc = requireLogoutWith.second; + request.absolutize(loc); + if (loc.find('?') != string::npos) + loc += '&'; + else + loc += '?'; + loc += "return=" + XMLToolingConfig::getConfig().getURLEncoder()->encode(selfurl.c_str()); + return make_pair(true, request.sendRedirect(loc.c_str())); + } + } + } + else { // No session. Maybe that's acceptable? if ((!requireSession.first || !requireSession.second) && !requireSessionWith.first) return make_pair(true, request.returnOK()); @@ -304,7 +332,7 @@ pair ServiceProvider::doAuthentication(SPRequest& request, bool handl initiator=app->getSessionInitiatorById(requireSessionWith.second); if (!initiator) { throw ConfigurationException( - "No session initiator found with id ($1), check requireSessionWith command.", params(1,requireSessionWith.second) + "No session initiator found with id ($1), check requireSessionWith command.", params(1, requireSessionWith.second) ); } } @@ -314,7 +342,12 @@ pair ServiceProvider::doAuthentication(SPRequest& request, bool handl throw ConfigurationException("No default session initiator found, check configuration."); } - return initiator->run(request, false); + // 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 ret = initiator->run(request, false); + if (ret.first) + return ret; + throw ConfigurationException("Session initiator did not handle request for a new session, check configuration."); } request.setAuthType(authType.second); @@ -328,7 +361,7 @@ pair ServiceProvider::doAuthentication(SPRequest& request, bool handl request.log(SPRequest::SPError, e.what()); TemplateParameters tp(&e); tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?')); - return make_pair(true,sendError(log, request, app, "session", tp)); + return make_pair(true, sendError(log, request, app, "session", tp)); } } @@ -337,10 +370,11 @@ pair ServiceProvider::doAuthorization(SPRequest& request) const #ifdef _DEBUG xmltooling::NDC ndc("doAuthorization"); #endif - Category& log = Category::getInstance(SHIBSP_LOGCAT".ServiceProvider"); + Category& log = Category::getInstance(SHIBSP_LOGCAT ".ServiceProvider"); const Application* app = nullptr; - const Session* session = nullptr; + Session* session = nullptr; + Locker slocker; string targetURL = request.getRequestURL(); try { @@ -362,7 +396,9 @@ pair ServiceProvider::doAuthorization(SPRequest& request) const // Do we have an access control plugin? if (settings.second) { try { - session = request.getSession(false); + session = request.getSession(false, false, false); // ignore timeout and do not cache + if (session) + slocker.assign(session, false); // assign to lock popper } catch (exception& e) { log.warn("unable to obtain session to pass to access control provider: %s", e.what()); @@ -395,7 +431,7 @@ pair ServiceProvider::doAuthorization(SPRequest& request) const request.log(SPRequest::SPError, e.what()); TemplateParameters tp(&e, nullptr, session); tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?')); - return make_pair(true,sendError(log, request, app, "access", tp)); + return make_pair(true, sendError(log, request, app, "access", tp)); } } @@ -404,10 +440,11 @@ pair ServiceProvider::doExport(SPRequest& request, bool requireSessio #ifdef _DEBUG xmltooling::NDC ndc("doExport"); #endif - Category& log = Category::getInstance(SHIBSP_LOGCAT".ServiceProvider"); + Category& log = Category::getInstance(SHIBSP_LOGCAT ".ServiceProvider"); const Application* app = nullptr; - const Session* session = nullptr; + Session* session = nullptr; + Locker slocker; string targetURL = request.getRequestURL(); try { @@ -415,7 +452,9 @@ pair ServiceProvider::doExport(SPRequest& request, bool requireSessio app = &(request.getApplication()); try { - session = request.getSession(false); + session = request.getSession(false, false, false); // ignore timeout and do not cache + if (session) + slocker.assign(session, false); // assign to lock popper } catch (exception& e) { log.warn("unable to obtain session to export to request: %s", e.what()); @@ -465,6 +504,13 @@ pair ServiceProvider::doExport(SPRequest& request, bool requireSessio app->setHeader(request, "Shib-Session-Index", hval); } + // Check for export of algorithmically-derived portion of cookie names. + stdvars = settings.first->getBool("exportCookie"); + if (stdvars.first && stdvars.second) { + pair cookieprops = app->getCookieNameProps(nullptr); + app->setHeader(request, "Shib-Cookie-Name", cookieprops.first.c_str()); + } + // Maybe export the assertion keys. pair exp = settings.first->getBool("exportAssertion"); if (exp.first && exp.second) { @@ -550,7 +596,7 @@ pair ServiceProvider::doExport(SPRequest& request, bool requireSessio request.log(SPRequest::SPError, e.what()); TemplateParameters tp(&e, nullptr, session); tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?')); - return make_pair(true,sendError(log, request, app, "session", tp)); + return make_pair(true, sendError(log, request, app, "session", tp)); } } @@ -559,7 +605,7 @@ pair ServiceProvider::doHandler(SPRequest& request) const #ifdef _DEBUG xmltooling::NDC ndc("doHandler"); #endif - Category& log = Category::getInstance(SHIBSP_LOGCAT".ServiceProvider"); + Category& log = Category::getInstance(SHIBSP_LOGCAT ".ServiceProvider"); const Application* app = nullptr; string targetURL = request.getRequestURL(); @@ -628,12 +674,13 @@ pair ServiceProvider::doHandler(SPRequest& request) const } catch (exception& e) { request.log(SPRequest::SPError, e.what()); - const Session* session = nullptr; + Session* session = nullptr; try { - session = request.getSession(false, true); + session = request.getSession(false, true, false); // do not cache } catch (exception&) { } + Locker slocker(session, false); // pop existing lock on exit TemplateParameters tp(&e, nullptr, session); tp.m_map["requestURL"] = targetURL.substr(0, targetURL.find('?')); tp.m_request = &request;