X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=shibsp%2FServiceProvider.cpp;h=9c2487b52afa4cacc57cff4e7f5834e66e5f7a5f;hb=73514022d6a44deb8da9be57c8ed9d7e823d3b6b;hp=944dc2658e63fab6f5995ced661db3064d802f7a;hpb=ba0c0400da295ead92558de3f55a74f11bf57a0d;p=shibboleth%2Fsp.git diff --git a/shibsp/ServiceProvider.cpp b/shibsp/ServiceProvider.cpp index 944dc26..9c2487b 100644 --- a/shibsp/ServiceProvider.cpp +++ b/shibsp/ServiceProvider.cpp @@ -1,6 +1,6 @@ /* - * Copyright 2001-2007 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. * You may obtain a copy of the License at @@ -16,7 +16,7 @@ /** * ServiceProvider.cpp - * + * * Interface to a Shibboleth ServiceProvider instance. */ @@ -33,8 +33,13 @@ #include #include +#ifndef SHIBSP_LITE +# include +# include +#endif #include #include +#include #include #include @@ -51,11 +56,18 @@ namespace shibsp { ) { // The properties we need can be set in the RequestMap, or the Errors element. - bool mderror = dynamic_cast(tp.getRichException())!=NULL; - pair redirectErrors = pair(false,NULL); - pair pathname = pair(false,NULL); - const PropertySet* props=app ? app->getPropertySet("Errors") : NULL; + bool mderror = dynamic_cast(tp.getRichException())!=nullptr; + bool accesserror = (strcmp(page, "access")==0); + pair redirectErrors = pair(false,nullptr); + pair pathname = pair(false,nullptr); + + // Strictly for error handling, detect a nullptr application and point at the default. + if (!app) + app = request.getServiceProvider().getApplication("default"); + const PropertySet* props=app->getPropertySet("Errors"); + + // First look for settings in the request map of the form pageError. try { RequestMapper::Settings settings = request.getRequestSettings(); if (mderror) @@ -72,8 +84,8 @@ namespace shibsp { log.error(ex.what()); } + // Check for redirection on errors instead of template. if (mayRedirect) { - // Check for redirection on errors instead of template. if (!redirectErrors.first && props) redirectErrors = props->getString("redirectErrors"); if (redirectErrors.first) { @@ -86,44 +98,60 @@ namespace shibsp { request.setContentType("text/html"); request.setResponseHeader("Expires","01-Jan-1997 12:00:00 GMT"); request.setResponseHeader("Cache-Control","private,no-store,no-cache"); - + + // Nothing in the request map, so check for a property named "page" in the Errors property set. if (!pathname.first && props) { if (mderror) pathname=props->getString("metadata"); if (!pathname.first) pathname=props->getString(page); } - if (pathname.first) { - ifstream infile(pathname.second); + + // If there's still no template to use, just use pageError.html unless it's an access issue. + string fname; + if (!pathname.first) { + if (!accesserror) { + fname = string(page) + "Error.html"; + pathname.second = fname.c_str(); + } + } + else { + fname = pathname.second; + } + + // If we have a template to use, use it. + if (!fname.empty()) { + ifstream infile(XMLToolingConfig::getConfig().getPathResolver()->resolve(fname, PathResolver::XMLTOOLING_CFG_FILE).c_str()); if (infile) { tp.setPropertySet(props); stringstream str; XMLToolingConfig::getConfig().getTemplateEngine()->run(infile, str, tp, tp.getRichException()); - return request.sendResponse(str); + return request.sendError(str); } } - - if (!strcmp(page,"access")) { + + // If we got here, then either it's an access error or a template failed. + if (accesserror) { istringstream msg("Access Denied"); - return request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_UNAUTHORIZED); + return request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_FORBIDDEN); } - - log.error("sendError could not process error template (%s)", page); + + log.error("sendError could not process error template (%s)", pathname.second); istringstream msg("Internal Server Error. Please contact the site administrator."); return request.sendError(msg); } - + void SHIBSP_DLLLOCAL clearHeaders(SPRequest& request) { - request.clearHeader("Shib-Session-ID", "HTTP_SHIB_SESSION_ID"); - request.clearHeader("Shib-Identity-Provider", "HTTP_SHIB_IDENTITY_PROVIDER"); - request.clearHeader("Shib-Authentication-Method", "HTTP_SHIB_AUTHENTICATION_METHOD"); - request.clearHeader("Shib-Authentication-Instant", "HTTP_SHIB_AUTHENTICATION_INSTANT"); - request.clearHeader("Shib-AuthnContext-Class", "HTTP_SHIB_AUTHNCONTEXT_CLASS"); - request.clearHeader("Shib-AuthnContext-Decl", "HTTP_SHIB_AUTHNCONTEXT_DECL"); - request.clearHeader("Shib-Assertion-Count", "HTTP_SHIB_ASSERTION_COUNT"); + const Application& app = request.getApplication(); + app.clearHeader(request, "Shib-Session-ID", "HTTP_SHIB_SESSION_ID"); + app.clearHeader(request, "Shib-Identity-Provider", "HTTP_SHIB_IDENTITY_PROVIDER"); + app.clearHeader(request, "Shib-Authentication-Method", "HTTP_SHIB_AUTHENTICATION_METHOD"); + app.clearHeader(request, "Shib-Authentication-Instant", "HTTP_SHIB_AUTHENTICATION_INSTANT"); + app.clearHeader(request, "Shib-AuthnContext-Class", "HTTP_SHIB_AUTHNCONTEXT_CLASS"); + app.clearHeader(request, "Shib-AuthnContext-Decl", "HTTP_SHIB_AUTHNCONTEXT_DECL"); + app.clearHeader(request, "Shib-Assertion-Count", "HTTP_SHIB_ASSERTION_COUNT"); + app.clearAttributeHeaders(request); request.clearHeader("REMOTE_USER", "HTTP_REMOTE_USER"); - //request.clearHeader("Shib-Application-ID"); handle inside app method - request.getApplication().clearAttributeHeaders(request); } }; @@ -132,6 +160,23 @@ void SHIBSP_API shibsp::registerServiceProviders() SPConfig::getConfig().ServiceProviderManager.registerFactory(XML_SERVICE_PROVIDER, XMLServiceProviderFactory); } +ServiceProvider::ServiceProvider() +{ +} + +ServiceProvider::~ServiceProvider() +{ +} + +#ifndef SHIBSP_LITE +SecurityPolicyProvider* ServiceProvider::getSecurityPolicyProvider(bool required) const +{ + if (required) + throw ConfigurationException("No SecurityPolicyProvider available."); + return NULL; +} +#endif + pair ServiceProvider::doAuthentication(SPRequest& request, bool handler) const { #ifdef _DEBUG @@ -139,7 +184,7 @@ pair ServiceProvider::doAuthentication(SPRequest& request, bool handl #endif Category& log = Category::getInstance(SHIBSP_LOGCAT".ServiceProvider"); - const Application* app=NULL; + const Application* app=nullptr; string targetURL = request.getRequestURL(); try { @@ -170,7 +215,7 @@ pair ServiceProvider::doAuthentication(SPRequest& request, bool handl } } } - + const char* handlerURL=request.getHandlerURL(targetURL.c_str()); if (!handlerURL) throw ConfigurationException("Cannot determine handler from resource URL, check configuration."); @@ -203,14 +248,14 @@ pair ServiceProvider::doAuthentication(SPRequest& request, bool handl // Fix for secadv 20050901 clearHeaders(request); - Session* session = NULL; + Session* session = nullptr; try { session = request.getSession(); } catch (exception& e) { log.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(&e)==NULL) + if (dynamic_cast(&e)==nullptr) throw; } @@ -220,7 +265,7 @@ pair ServiceProvider::doAuthentication(SPRequest& request, bool handl return make_pair(true,request.returnOK()); // No session, but we require one. Initiate a new session using the indicated method. - const Handler* initiator=NULL; + const SessionInitiator* initiator=nullptr; if (requireSessionWith.first) { initiator=app->getSessionInitiatorById(requireSessionWith.second); if (!initiator) { @@ -238,12 +283,15 @@ pair ServiceProvider::doAuthentication(SPRequest& request, bool handl return initiator->run(request,false); } + request.setAuthType("shibboleth"); + // We're done. Everything is okay. Nothing to report. Nothing to do.. // Let the caller decide how to proceed. log.debug("doAuthentication succeeded"); return make_pair(false,0L); } catch (exception& e) { + 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)); @@ -257,7 +305,7 @@ pair ServiceProvider::doAuthorization(SPRequest& request) const #endif Category& log = Category::getInstance(SHIBSP_LOGCAT".ServiceProvider"); - const Application* app=NULL; + const Application* app=nullptr; string targetURL = request.getRequestURL(); try { @@ -282,14 +330,14 @@ pair ServiceProvider::doAuthorization(SPRequest& request) const // Do we have an access control plugin? if (settings.second) { - const Session* session = NULL; + const Session* session = nullptr; try { session = request.getSession(false); } catch (exception& e) { log.warn("unable to obtain session to pass to access control provider: %s", e.what()); } - + Locker acllock(settings.second); switch (settings.second->authorized(request,session)) { case AccessControl::shib_acl_true: @@ -314,6 +362,7 @@ pair ServiceProvider::doAuthorization(SPRequest& request) const } } catch (exception& e) { + 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, "access", tp)); @@ -327,14 +376,14 @@ pair ServiceProvider::doExport(SPRequest& request, bool requireSessio #endif Category& log = Category::getInstance(SHIBSP_LOGCAT".ServiceProvider"); - const Application* app=NULL; + const Application* app=nullptr; string targetURL = request.getRequestURL(); try { RequestMapper::Settings settings = request.getRequestSettings(); app = &(request.getApplication()); - const Session* session = NULL; + const Session* session = nullptr; try { session = request.getSession(false); } @@ -352,31 +401,31 @@ pair ServiceProvider::doExport(SPRequest& request, bool requireSessio else return make_pair(false,0L); // just bail silently } - - request.setHeader("Shib-Application-ID", app->getId()); - request.setHeader("Shib-Session-ID", session->getID()); + + app->setHeader(request, "Shib-Application-ID", app->getId()); + app->setHeader(request, "Shib-Session-ID", session->getID()); // Export the IdP name and Authn method/context info. const char* hval = session->getEntityID(); if (hval) - request.setHeader("Shib-Identity-Provider", hval); + app->setHeader(request, "Shib-Identity-Provider", hval); hval = session->getAuthnInstant(); if (hval) - request.setHeader("Shib-Authentication-Instant", hval); + app->setHeader(request, "Shib-Authentication-Instant", hval); hval = session->getAuthnContextClassRef(); if (hval) { - request.setHeader("Shib-Authentication-Method", hval); - request.setHeader("Shib-AuthnContext-Class", hval); + app->setHeader(request, "Shib-Authentication-Method", hval); + app->setHeader(request, "Shib-AuthnContext-Class", hval); } hval = session->getAuthnContextDeclRef(); if (hval) - request.setHeader("Shib-AuthnContext-Decl", hval); - + app->setHeader(request, "Shib-AuthnContext-Decl", hval); + // Maybe export the assertion keys. pair exp=settings.first->getBool("exportAssertion"); if (exp.first && exp.second) { const PropertySet* sessions=app->getPropertySet("Sessions"); - pair exportLocation = sessions ? sessions->getString("exportLocation") : pair(false,NULL); + pair exportLocation = sessions ? sessions->getString("exportLocation") : pair(false,nullptr); if (!exportLocation.first) log.warn("can't export assertions without an exportLocation Sessions property"); else { @@ -395,16 +444,18 @@ pair ServiceProvider::doExport(SPRequest& request, bool requireSessio *(exportName.rbegin()) = '0' + (count%10); *(++exportName.rbegin()) = '0' + (count/10); string fullURL = baseURL + encoder->encode(*tokenids); - request.setHeader(exportName.c_str(), fullURL.c_str()); + app->setHeader(request, exportName.c_str(), fullURL.c_str()); } - request.setHeader("Shib-Assertion-Count", exportName.c_str() + 15); + app->setHeader(request, "Shib-Assertion-Count", exportName.c_str() + 15); } } // Export the attributes. const multimap& attributes = session->getIndexedAttributes(); for (multimap::const_iterator a = attributes.begin(); a!=attributes.end(); ++a) { - string header(request.getSecureHeader(a->first.c_str())); + if (a->second->isInternal()) + continue; + string header(app->getSecureHeader(request, a->first.c_str())); const vector& vals = a->second->getSerializedValues(); for (vector::const_iterator v = vals.begin(); v!=vals.end(); ++v) { if (!header.empty()) @@ -422,7 +473,7 @@ pair ServiceProvider::doExport(SPRequest& request, bool requireSessio header += (*v); } } - request.setHeader(a->first.c_str(), header.c_str()); + app->setHeader(request, a->first.c_str(), header.c_str()); } // Check for REMOTE_USER. @@ -431,7 +482,7 @@ pair ServiceProvider::doExport(SPRequest& request, bool requireSessio for (vector::const_iterator rmid = rmids.begin(); !remoteUserSet && rmid != rmids.end(); ++rmid) { pair::const_iterator,multimap::const_iterator> matches = attributes.equal_range(*rmid); - while (matches.first != matches.second) { + for (; matches.first != matches.second; ++matches.first) { const vector& vals = matches.first->second->getSerializedValues(); if (!vals.empty()) { request.setRemoteUser(vals.front().c_str()); @@ -444,6 +495,7 @@ pair ServiceProvider::doExport(SPRequest& request, bool requireSessio return make_pair(false,0L); } catch (exception& e) { + 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)); @@ -457,7 +509,7 @@ pair ServiceProvider::doHandler(SPRequest& request) const #endif Category& log = Category::getInstance(SHIBSP_LOGCAT".ServiceProvider"); - const Application* app=NULL; + const Application* app=nullptr; string targetURL = request.getRequestURL(); try { @@ -503,7 +555,7 @@ pair ServiceProvider::doHandler(SPRequest& request) const // Process incoming request. pair handlerSSL=sessionProps->getBool("handlerSSL"); - + // Make sure this is SSL, if it should be if ((!handlerSSL.first || handlerSSL.second) && !request.isSecure()) throw opensaml::FatalProfileException("Blocked non-SSL access to Shibboleth handler."); @@ -519,12 +571,14 @@ pair ServiceProvider::doHandler(SPRequest& request) const // Did the handler run successfully? if (hret.first) return hret; - + throw ConfigurationException("Configured Shibboleth handler failed to process the request."); } catch (exception& e) { + request.log(SPRequest::SPError, e.what()); TemplateParameters tp(&e); tp.m_map["requestURL"] = targetURL.substr(0,targetURL.find('?')); + tp.m_request = &request; return make_pair(true,sendError(log, request, app, "session", tp)); } }