X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=adfs%2Fadfs.cpp;fp=adfs%2Fadfs.cpp;h=f1191bee2b671f146decf328e30011496697a687;hb=997a4736b6fe81066e13822d3163de3a20cd6353;hp=c282eab22b2ee217af9d1dce8a38f79fa48e8c79;hpb=d98a71ccae3e120443eae38ce73ef68404d0c9c2;p=shibboleth%2Fsp.git diff --git a/adfs/adfs.cpp b/adfs/adfs.cpp index c282eab..f1191be 100644 --- a/adfs/adfs.cpp +++ b/adfs/adfs.cpp @@ -80,6 +80,7 @@ using namespace opensaml; using namespace xmltooling::logging; using namespace xmltooling; using namespace xercesc; +using namespace boost; using namespace std; #define WSFED_NS "http://schemas.xmlsoap.org/ws/2003/07/secext" @@ -153,6 +154,12 @@ namespace { return m_binding.get(); } +#ifndef SHIBSP_LITE + void generateMetadata(saml2md::SPSSODescriptor& role, const char* handlerURL) const { + doGenerateMetadata(role, handlerURL); + } +#endif + private: pair doRequest( const Application& application, @@ -336,13 +343,13 @@ pair ADFSSessionInitiator::run(SPRequest& request, string& entityID, { // We have to know the IdP to function. if (entityID.empty() || !checkCompatibility(request, isHandler)) - return make_pair(false,0L); + return make_pair(false, 0L); string target; pair prop; pair acClass; - const Handler* ACS=nullptr; - const Application& app=request.getApplication(); + const Handler* ACS = nullptr; + const Application& app = request.getApplication(); if (isHandler) { prop.second = request.getParameter("acsIndex"); @@ -359,6 +366,7 @@ pair ADFSSessionInitiator::run(SPRequest& request, string& entityID, // 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(app, request, request, target, false); + app.limitRedirect(request, target.c_str()); acClass = getString("authnContextClassRef", request); } @@ -390,7 +398,7 @@ 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()); + string ACSloc = request.getHandlerURL(target.c_str()); prop = ACS->getString("Location"); if (prop.first) ACSloc += prop.second; @@ -442,8 +450,8 @@ pair ADFSSessionInitiator::unwrap(SPRequest& request, DDF& out) const void ADFSSessionInitiator::receive(DDF& in, ostream& out) { // Find application. - const char* aid=in["application_id"].string(); - const Application* app=aid ? SPConfig::getConfig().getServiceProvider()->getApplication(aid) : nullptr; + const char* aid = in["application_id"].string(); + const Application* app = aid ? SPConfig::getConfig().getServiceProvider()->getApplication(aid) : nullptr; if (!app) { // Something's horribly wrong. m_log.error("couldn't find application (%s) to generate ADFS request", aid ? aid : "(missing)"); @@ -459,14 +467,14 @@ void ADFSSessionInitiator::receive(DDF& in, ostream& out) DDFJanitor jout(ret); // Wrap the outgoing object with a Response facade. - auto_ptr http(getResponse(ret)); + scoped_ptr http(getResponse(ret)); string relayState(in["RelayState"].string() ? in["RelayState"].string() : ""); // Since we're remoted, the result should either be a throw, which we pass on, // a false/0 return, which we just return as an empty structure, or a response/redirect, // which we capture in the facade and send back. - doRequest(*app, nullptr, *http.get(), entityID, acsLocation, in["authnContextClassRef"].string(), relayState); + doRequest(*app, nullptr, *http, entityID, acsLocation, in["authnContextClassRef"].string(), relayState); if (!ret.isstruct()) ret.structure(); ret.addmember("RelayState").unsafe_string(relayState.c_str()); @@ -485,10 +493,10 @@ pair ADFSSessionInitiator::doRequest( { #ifndef SHIBSP_LITE // Use metadata to invoke the SSO service directly. - MetadataProvider* m=app.getMetadataProvider(); + MetadataProvider* m = app.getMetadataProvider(); Locker locker(m); MetadataProviderCriteria mc(app, entityID, &IDPSSODescriptor::ELEMENT_QNAME, m_binding.get()); - pair entity=m->getEntityDescriptor(mc); + pair entity = m->getEntityDescriptor(mc); if (!entity.first) { m_log.warn("unable to locate metadata for provider (%s)", entityID); throw MetadataException("Unable to locate metadata for identity provider ($entityID)", namedparams(1, "entityID", entityID)); @@ -496,7 +504,7 @@ pair ADFSSessionInitiator::doRequest( else if (!entity.second) { m_log.log(getParent() ? Priority::INFO : Priority::WARN, "unable to locate ADFS-aware identity provider role for provider (%s)", entityID); if (getParent()) - return make_pair(false,0L); + return make_pair(false, 0L); throw MetadataException("Unable to locate ADFS-aware identity provider role for provider ($entityID)", namedparams(1, "entityID", entityID)); } const EndpointType* ep = EndpointManager( @@ -505,13 +513,13 @@ pair ADFSSessionInitiator::doRequest( if (!ep) { m_log.warn("unable to locate compatible SSO service for provider (%s)", entityID); if (getParent()) - return make_pair(false,0L); + return make_pair(false, 0L); throw MetadataException("Unable to locate compatible SSO service for provider ($entityID)", namedparams(1, "entityID", entityID)); } preserveRelayState(app, httpResponse, relayState); - auto_ptr ar_event(newAuthnRequestEvent(app, httpRequest)); + scoped_ptr ar_event(newAuthnRequestEvent(app, httpRequest)); if (ar_event.get()) { ar_event->m_binding = WSFED_NS; ar_event->m_protocol = WSFED_NS; @@ -547,7 +555,7 @@ pair ADFSSessionInitiator::doRequest( return make_pair(true, httpResponse.sendRedirect(req.c_str())); #else - return make_pair(false,0L); + return make_pair(false, 0L); #endif } @@ -650,7 +658,7 @@ void ADFSConsumer::implementProtocol( const saml1::NameIdentifier* saml1name=nullptr; const saml1::AuthenticationStatement* saml1statement=nullptr; - saml2::NameID* saml2name=nullptr; + const saml2::NameID* saml2name=nullptr; const saml2::AuthnStatement* saml2statement=nullptr; const XMLCh* authMethod=nullptr; const XMLCh* authInstant=nullptr; @@ -749,7 +757,7 @@ void ADFSConsumer::implementProtocol( // To complete processing, we need to extract and resolve attributes and then create the session. // Normalize a SAML 1.x NameIdentifier... - auto_ptr nameid(saml1name ? saml2::NameIDBuilder::buildNameID() : nullptr); + scoped_ptr nameid(saml1name ? saml2::NameIDBuilder::buildNameID() : nullptr); if (saml1name) { nameid->setName(saml1name->getName()); nameid->setFormat(saml1name->getFormat()); @@ -758,11 +766,13 @@ void ADFSConsumer::implementProtocol( // The context will handle deleting attributes and new tokens. vector tokens(1,token); - auto_ptr ctx( + scoped_ptr ctx( resolveAttributes( application, + &httpRequest, policy.getIssuerMetadata(), m_protocol.get(), + nullptr, saml1name, saml1statement, (saml1name ? nameid.get() : saml2name), @@ -793,11 +803,11 @@ void ADFSConsumer::implementProtocol( authMethod, nullptr, &tokens, - ctx.get() ? &ctx->getResolvedAttributes() : nullptr + ctx ? &ctx->getResolvedAttributes() : nullptr ); - auto_ptr login_event(newLoginEvent(application, httpRequest)); - if (login_event.get()) { + scoped_ptr login_event(newLoginEvent(application, httpRequest)); + if (login_event) { login_event->m_sessionID = session_id.c_str(); login_event->m_peer = entity; login_event->m_protocol = WSFED_NS; @@ -805,7 +815,7 @@ void ADFSConsumer::implementProtocol( login_event->m_saml1AuthnStatement = saml1statement; login_event->m_nameID = (saml1name ? nameid.get() : saml2name); login_event->m_saml2AuthnStatement = saml2statement; - if (ctx.get()) + if (ctx) login_event->m_attributes = &ctx->getResolvedAttributes(); application.getServiceProvider().getTransactionLog()->write(*login_event); } @@ -825,21 +835,19 @@ pair ADFSLogoutInitiator::run(SPRequest& request, bool isHandler) con try { session = request.getSession(false, true, false); // don't cache it and ignore all checks if (!session) - return make_pair(false,0L); + return make_pair(false, 0L); // We only handle ADFS sessions. if (!XMLString::equals(session->getProtocol(), WSFED_NS) || !session->getEntityID()) { session->unlock(); - return make_pair(false,0L); + return make_pair(false, 0L); } } - catch (exception& ex) { + catch (std::exception& ex) { m_log.error("error accessing current session: %s", ex.what()); return make_pair(false,0L); } - session->unlock(); - if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) { // When out of process, we run natively. return doRequest(request.getApplication(), request, request, session); @@ -849,7 +857,7 @@ pair ADFSLogoutInitiator::run(SPRequest& request, bool isHandler) con session->unlock(); vector headers(1,"Cookie"); headers.push_back("User-Agent"); - DDF out,in = wrap(request,&headers); + DDF out,in = wrap(request, &headers); DDFJanitor jin(in), jout(out); out=request.getServiceProvider().getListenerService()->send(in); return unwrap(request, out); @@ -864,8 +872,8 @@ void ADFSLogoutInitiator::receive(DDF& in, ostream& out) return LogoutHandler::receive(in, out); // Find application. - const char* aid=in["application_id"].string(); - const Application* app=aid ? SPConfig::getConfig().getServiceProvider()->getApplication(aid) : nullptr; + const char* aid = in["application_id"].string(); + const Application* app = aid ? SPConfig::getConfig().getServiceProvider()->getApplication(aid) : nullptr; if (!app) { // Something's horribly wrong. m_log.error("couldn't find application (%s) for logout", aid ? aid : "(missing)"); @@ -873,18 +881,18 @@ void ADFSLogoutInitiator::receive(DDF& in, ostream& out) } // Unpack the request. - auto_ptr req(getRequest(in)); + scoped_ptr req(getRequest(in)); // Set up a response shim. DDF ret(nullptr); DDFJanitor jout(ret); - auto_ptr resp(getResponse(ret)); + scoped_ptr resp(getResponse(ret)); Session* session = nullptr; try { - session = app->getServiceProvider().getSessionCache()->find(*app, *req.get(), nullptr, nullptr); + session = app->getServiceProvider().getSessionCache()->find(*app, *req, nullptr, nullptr); } - catch (exception& ex) { + catch (std::exception& ex) { m_log.error("error accessing current session: %s", ex.what()); } @@ -894,12 +902,12 @@ void ADFSLogoutInitiator::receive(DDF& in, ostream& out) // Since we're remoted, the result should either be a throw, which we pass on, // a false/0 return, which we just return as an empty structure, or a response/redirect, // which we capture in the facade and send back. - doRequest(*app, *req.get(), *resp.get(), session); + doRequest(*app, *req, *resp, session); } else { m_log.error("no issuing entityID found in session"); session->unlock(); - app->getServiceProvider().getSessionCache()->remove(*app, *req.get(), resp.get()); + app->getServiceProvider().getSessionCache()->remove(*app, *req, resp.get()); } } out << ret; @@ -912,27 +920,30 @@ pair ADFSLogoutInitiator::doRequest( const Application& application, const HTTPRequest& httpRequest, HTTPResponse& httpResponse, Session* session ) const { + Locker sessionLocker(session, false); + // Do back channel notification. vector sessions(1, session->getID()); if (!notifyBackChannel(application, httpRequest.getRequestURL(), sessions, false)) { #ifndef SHIBSP_LITE - auto_ptr logout_event(newLogoutEvent(application, &httpRequest, session)); - if (logout_event.get()) { + scoped_ptr logout_event(newLogoutEvent(application, &httpRequest, session)); + if (logout_event) { logout_event->m_logoutType = LogoutEvent::LOGOUT_EVENT_PARTIAL; application.getServiceProvider().getTransactionLog()->write(*logout_event); } #endif - session->unlock(); + sessionLocker.assign(); + session = nullptr; application.getServiceProvider().getSessionCache()->remove(application, httpRequest, &httpResponse); return sendLogoutPage(application, httpRequest, httpResponse, "partial"); } #ifndef SHIBSP_LITE - pair ret = make_pair(false,0L); + pair ret = make_pair(false, 0L); try { // With a session in hand, we can create a request message, if we can find a compatible endpoint. - MetadataProvider* m=application.getMetadataProvider(); + MetadataProvider* m = application.getMetadataProvider(); Locker metadataLocker(m); MetadataProviderCriteria mc(application, session->getEntityID(), &IDPSSODescriptor::ELEMENT_QNAME, m_binding.get()); pair entity=m->getEntityDescriptor(mc); @@ -957,24 +968,35 @@ pair ADFSLogoutInitiator::doRequest( ); } + const char* returnloc = httpRequest.getParameter("return"); + if (returnloc) + application.limitRedirect(httpRequest, returnloc); + // Log the request. - auto_ptr logout_event(newLogoutEvent(application, &httpRequest, session)); - if (logout_event.get()) { + scoped_ptr logout_event(newLogoutEvent(application, &httpRequest, session)); + if (logout_event) { logout_event->m_logoutType = LogoutEvent::LOGOUT_EVENT_UNKNOWN; application.getServiceProvider().getTransactionLog()->write(*logout_event); } - const URLEncoder* urlenc = XMLToolingConfig::getConfig().getURLEncoder(); - const char* returnloc = httpRequest.getParameter("return"); auto_ptr_char dest(ep->getLocation()); string req=string(dest.get()) + (strchr(dest.get(),'?') ? '&' : '?') + "wa=wsignout1.0"; - if (returnloc) - req += "&wreply=" + urlenc->encode(returnloc); + if (returnloc) { + req += "&wreply="; + if (*returnloc == '/') { + string s(returnloc); + httpRequest.absolutize(s); + req += XMLToolingConfig::getConfig().getURLEncoder()->encode(s.c_str()); + } + else { + req += XMLToolingConfig::getConfig().getURLEncoder()->encode(returnloc); + } + } ret.second = httpResponse.sendRedirect(req.c_str()); ret.first = true; if (session) { - session->unlock(); + sessionLocker.assign(); session = nullptr; application.getServiceProvider().getSessionCache()->remove(application, httpRequest, &httpResponse); } @@ -983,13 +1005,10 @@ pair ADFSLogoutInitiator::doRequest( // Less noise for IdPs that don't support logout m_log.info("unable to issue ADFS logout request: %s", mex.what()); } - catch (exception& ex) { + catch (std::exception& ex) { m_log.error("error issuing ADFS logout request: %s", ex.what()); } - if (session) - session->unlock(); - return ret; #else throw ConfigurationException("Cannot perform logout using lite version of shibsp library."); @@ -1039,12 +1058,21 @@ pair ADFSLogout::run(SPRequest& request, bool isHandler) const try { app.getServiceProvider().getSessionCache()->remove(app, request, &request); } - catch (exception& ex) { + catch (std::exception& ex) { m_log.error("error removing session (%s): %s", session_id.c_str(), ex.what()); } } - if (param) - return make_pair(true, request.sendRedirect(param)); + if (param) { + if (*param == '/') { + string p(param); + request.absolutize(p); + return make_pair(true, request.sendRedirect(p.c_str())); + } + else { + app.limitRedirect(request, param); + return make_pair(true, request.sendRedirect(param)); + } + } return sendLogoutPage(app, request, request, "global"); }