From 16c2224b2d82d63462f552406e31ac81ee921116 Mon Sep 17 00:00:00 2001 From: cantor Date: Thu, 8 Mar 2007 21:42:16 +0000 Subject: [PATCH] Add option to use redirection for handler errors, capture relay state when propagating exceptions. git-svn-id: https://svn.middleware.georgetown.edu/cpp-sp/trunk@2189 cb58f699-b61c-0410-a6fe-9272a202ed29 --- configs/shibboleth.xml.in | 4 +- schemas/shibboleth-spconfig-2.0.xsd | 13 ++- shibsp/handler/impl/AbstractHandler.cpp | 12 +-- shibsp/handler/impl/AssertionConsumerService.cpp | 103 +++++++++++++++-------- 4 files changed, 87 insertions(+), 45 deletions(-) diff --git a/configs/shibboleth.xml.in b/configs/shibboleth.xml.in index 410552c..918ced7 100644 --- a/configs/shibboleth.xml.in +++ b/configs/shibboleth.xml.in @@ -138,8 +138,8 @@ --> - diff --git a/schemas/shibboleth-spconfig-2.0.xsd b/schemas/shibboleth-spconfig-2.0.xsd index ec7247a..c2699db 100644 --- a/schemas/shibboleth-spconfig-2.0.xsd +++ b/schemas/shibboleth-spconfig-2.0.xsd @@ -397,6 +397,7 @@ + @@ -408,6 +409,13 @@ + + + + Used to reference Policy elements from profile endpoints. + + + Used to specify handlers that can issue AuthnRequests @@ -418,10 +426,11 @@ + + - - + diff --git a/shibsp/handler/impl/AbstractHandler.cpp b/shibsp/handler/impl/AbstractHandler.cpp index 4d5b404..7808ddc 100644 --- a/shibsp/handler/impl/AbstractHandler.cpp +++ b/shibsp/handler/impl/AbstractHandler.cpp @@ -67,15 +67,15 @@ void AbstractHandler::checkError(const XMLObject* response) const if (code && !XMLString::equals(code,saml2p::StatusCode::SUCCESS)) { FatalProfileException ex("SAML Response message contained an error."); auto_ptr_char c1(code); - ex.addProperty("code", c1.get()); + ex.addProperty("StatusCode", c1.get()); if (sc->getStatusCode()) { code = sc->getStatusCode()->getValue(); auto_ptr_char c2(code); - ex.addProperty("code2", c2.get()); + ex.addProperty("StatusCode2", c2.get()); } if (status->getStatusMessage()) { auto_ptr_char msg(status->getStatusMessage()->getMessage()); - ex.addProperty("message", msg.get()); + ex.addProperty("StatusMessage", msg.get()); } } } @@ -89,15 +89,15 @@ void AbstractHandler::checkError(const XMLObject* response) const const QName* code = sc ? sc->getValue() : NULL; if (code && *code != saml1p::StatusCode::SUCCESS) { FatalProfileException ex("SAML Response message contained an error."); - ex.addProperty("code", code->toString().c_str()); + ex.addProperty("StatusCode", code->toString().c_str()); if (sc->getStatusCode()) { code = sc->getStatusCode()->getValue(); if (code) - ex.addProperty("code2", code->toString().c_str()); + ex.addProperty("StatusCode2", code->toString().c_str()); } if (status->getStatusMessage()) { auto_ptr_char msg(status->getStatusMessage()->getMessage()); - ex.addProperty("message", msg.get()); + ex.addProperty("StatusMessage", msg.get()); } } } diff --git a/shibsp/handler/impl/AssertionConsumerService.cpp b/shibsp/handler/impl/AssertionConsumerService.cpp index e89ecfc..1498faa 100644 --- a/shibsp/handler/impl/AssertionConsumerService.cpp +++ b/shibsp/handler/impl/AssertionConsumerService.cpp @@ -56,32 +56,57 @@ AssertionConsumerService::~AssertionConsumerService() pair AssertionConsumerService::run(SPRequest& request, bool isHandler) const { + string relayState; SPConfig& conf = SPConfig::getConfig(); - if (conf.isEnabled(SPConfig::OutOfProcess)) { - // When out of process, we run natively and directly process the message. - // RelayState will be fully handled during message processing. - string relayState, providerId; - string key = processMessage(request.getApplication(), request, providerId, relayState); - return sendRedirect(request, key.c_str(), providerId.c_str(), relayState.c_str()); - } - else { - // When not out of process, we remote all the message processing. - DDF in = wrap(request); - DDFJanitor jin(in); - in.addmember("application_id").string(request.getApplication().getId()); - DDF out=request.getServiceProvider().getListenerService()->send(in); - DDFJanitor jout(out); - - // If it worked, we have a session key. - if (!out["key"].isstring()) - throw FatalProfileException("Remote processing of SSO profile did not return a usable session key."); + + try { + if (conf.isEnabled(SPConfig::OutOfProcess)) { + // When out of process, we run natively and directly process the message. + // RelayState will be fully handled during message processing. + string providerId; + string key = processMessage(request.getApplication(), request, providerId, relayState); + return sendRedirect(request, key.c_str(), providerId.c_str(), relayState.c_str()); + } + else { + // When not out of process, we remote all the message processing. + DDF out,in = wrap(request); + DDFJanitor jin(in), jout(out); + + in.addmember("application_id").string(request.getApplication().getId()); + try { + out=request.getServiceProvider().getListenerService()->send(in); + } + catch (XMLToolingException& ex) { + // Try for RelayState recovery. + if (ex.getProperty("RelayState")) + relayState = ex.getProperty("RelayState"); + try { + recoverRelayState(request, relayState); + } + catch (exception& ex2) { + m_log.error("trapped an error during RelayState recovery while handling an error: %s", ex2.what()); + } + throw; + } + + // We invoke RelayState recovery one last time on this side of the boundary. + if (out["RelayState"].isstring()) + relayState = out["RelayState"].string(); + recoverRelayState(request, relayState); + + // If it worked, we have a session key. + if (!out["key"].isstring()) + throw FatalProfileException("Remote processing of SSO profile did not return a usable session key."); - // We invoke the RelayState method one last time on this side of the process boundary. - string relayState; - if (out["RelayState"].isstring()) - relayState = out["RelayState"].string(); - recoverRelayState(request, relayState); - return sendRedirect(request, out["key"].string(), out["provider_id"].string(), relayState.c_str()); + // Take care of cookie business and wrap it up. + return sendRedirect(request, out["key"].string(), out["provider_id"].string(), relayState.c_str()); + } + } + catch (XMLToolingException& ex) { + // Try and preserve RelayState. + if (!relayState.empty()) + ex.addProperty("RelayState", relayState.c_str()); + throw; } } @@ -101,17 +126,25 @@ void AssertionConsumerService::receive(DDF& in, ostream& out) // Do the work. string relayState, providerId; - string key = processMessage(*app, *http.get(), providerId, relayState); - - // Repack for return to caller. - DDF ret=DDF(NULL).structure(); - DDFJanitor jret(ret); - ret.addmember("key").string(key.c_str()); - if (!providerId.empty()) - ret.addmember("provider_id").string(providerId.c_str()); - if (!relayState.empty()) - ret.addmember("RelayState").string(relayState.c_str()); - out << ret; + try { + string key = processMessage(*app, *http.get(), providerId, relayState); + + // Repack for return to caller. + DDF ret=DDF(NULL).structure(); + DDFJanitor jret(ret); + ret.addmember("key").string(key.c_str()); + if (!providerId.empty()) + ret.addmember("provider_id").string(providerId.c_str()); + if (!relayState.empty()) + ret.addmember("RelayState").string(relayState.c_str()); + out << ret; + } + catch (XMLToolingException& ex) { + // Try and preserve RelayState if we can. + if (!relayState.empty()) + ex.addProperty("RelayState", relayState.c_str()); + throw; + } } string AssertionConsumerService::processMessage( -- 2.1.4