pair<bool,long> AssertionConsumerService::processMessage( const Application& application, const HTTPRequest& httpRequest, HTTPResponse& httpResponse ) const { #ifndef SHIBSP_LITE // Locate policy key. pair<bool,const char*> policyId = getString("policyId", m_configNS.get()); // namespace-qualified if inside handler element if (!policyId.first) policyId = application.getString("policyId"); // unqualified in Application(s) element // Access policy properties. const PropertySet* settings = application.getServiceProvider().getPolicySettings(policyId.second); pair<bool,bool> validate = settings->getBool("validate"); // Lock metadata for use by policy. Locker metadataLocker(application.getMetadataProvider()); // Create the policy. shibsp::SecurityPolicy policy(application, &m_role, validate.first && validate.second); string relayState; try { // Decode the message and process it in a protocol-specific way. auto_ptr<XMLObject> msg(m_decoder->decode(relayState, httpRequest, policy)); if (!msg.get()) throw BindingException("Failed to decode an SSO protocol response."); recoverRelayState(application, httpRequest, httpResponse, relayState); implementProtocol(application, httpRequest, httpResponse, policy, settings, *msg.get()); auto_ptr_char issuer(policy.getIssuer() ? policy.getIssuer()->getName() : NULL); // History cookie. if (issuer.get() && *issuer.get()) maintainHistory(application, httpRequest, httpResponse, issuer.get()); // Now redirect to the state value. By now, it should be set to *something* usable. return make_pair(true, httpResponse.sendRedirect(relayState.c_str())); } catch (XMLToolingException& ex) { if (!relayState.empty()) ex.addProperty("RelayState", relayState.c_str()); throw; } #else throw ConfigurationException("Cannot process message using lite version of shibsp library."); #endif }
pair<bool,long> AssertionConsumerService::finalizeResponse( const Application& application, const HTTPRequest& httpRequest, HTTPResponse& httpResponse, string& relayState ) const { DDF postData = recoverPostData(application, httpRequest, httpResponse, relayState.c_str()); DDFJanitor postjan(postData); recoverRelayState(application, httpRequest, httpResponse, relayState); application.limitRedirect(httpRequest, relayState.c_str()); // Now redirect to the state value. By now, it should be set to *something* usable. // First check for POST data. if (!postData.islist()) { m_log.debug("ACS returning via redirect to: %s", relayState.c_str()); return make_pair(true, httpResponse.sendRedirect(relayState.c_str())); } else { m_log.debug("ACS returning via POST to: %s", relayState.c_str()); return make_pair(true, sendPostResponse(application, httpResponse, relayState.c_str(), postData)); } }
pair<bool,long> AssertionConsumerService::processMessage( const Application& application, const HTTPRequest& httpRequest, HTTPResponse& httpResponse ) const { #ifndef SHIBSP_LITE // Locate policy key. pair<bool,const char*> prop = getString("policyId", m_configNS.get()); // may be namespace-qualified if inside handler element if (!prop.first) prop = getString("policyId"); // try unqualified if (!prop.first) prop = application.getString("policyId"); // unqualified in Application(s) element // Lock metadata for use by policy. Locker metadataLocker(application.getMetadataProvider()); // Create the policy. scoped_ptr<opensaml::SecurityPolicy> policy( application.getServiceProvider().getSecurityPolicyProvider()->createSecurityPolicy( application, &IDPSSODescriptor::ELEMENT_QNAME, prop.second ) ); string relayState; scoped_ptr<XMLObject> msg; try { // Decode the message and process it in a protocol-specific way. msg.reset(m_decoder->decode(relayState, httpRequest, *(policy.get()))); if (!msg) throw BindingException("Failed to decode an SSO protocol response."); implementProtocol(application, httpRequest, httpResponse, *policy, nullptr, *msg); // History cookie. auto_ptr_char issuer(policy->getIssuer() ? policy->getIssuer()->getName() : nullptr); if (issuer.get() && *issuer.get()) maintainHistory(application, httpRequest, httpResponse, issuer.get()); const EntityDescriptor* entity = dynamic_cast<const EntityDescriptor*>(policy->getIssuerMetadata() ? policy->getIssuerMetadata()->getParent() : nullptr); prop = application.getRelyingParty(entity)->getString("sessionHook"); if (prop.first) { string hook(prop.second); httpRequest.absolutize(hook); // Compute the return URL. We use a self-referential link plus a hook indicator to break the cycle // and the relay state. const URLEncoder* encoder = XMLToolingConfig::getConfig().getURLEncoder(); string returnURL = httpRequest.getRequestURL(); returnURL = returnURL.substr(0, returnURL.find('?')) + "?hook=1"; if (!relayState.empty()) returnURL += "&target=" + encoder->encode(relayState.c_str()); if (hook.find('?') == string::npos) hook += '?'; else hook += '&'; hook += "return=" + encoder->encode(returnURL.c_str()); // Add the translated target resource in case it's of interest. if (!relayState.empty()) { try { recoverRelayState(application, httpRequest, httpResponse, relayState, false); hook += "&target=" + encoder->encode(relayState.c_str()); } catch (std::exception& ex) { m_log.warn("error recovering relay state: %s", ex.what()); } } return make_pair(true, httpResponse.sendRedirect(hook.c_str())); } return finalizeResponse(application, httpRequest, httpResponse, relayState); } catch (XMLToolingException& ex) { // Recover relay state. if (!relayState.empty()) { try { recoverRelayState(application, httpRequest, httpResponse, relayState, false); } catch (std::exception& rsex) { m_log.warn("error recovering relay state: %s", rsex.what()); relayState.erase(); recoverRelayState(application, httpRequest, httpResponse, relayState, false); } } // Check for isPassive error condition. const char* sc2 = ex.getProperty("statusCode2"); if (sc2 && !strcmp(sc2, "urn:oasis:names:tc:SAML:2.0:status:NoPassive")) { pair<bool,bool> ignore = getBool("ignoreNoPassive", m_configNS.get()); // may be namespace-qualified inside handler element if (!ignore.first) ignore = getBool("ignoreNoPassive"); // try unqualified if (ignore.first && ignore.second && !relayState.empty()) { m_log.debug("ignoring SAML status of NoPassive and redirecting to resource..."); return make_pair(true, httpResponse.sendRedirect(relayState.c_str())); } } if (!relayState.empty()) { ex.addProperty("RelayState", relayState.c_str()); } // Log the error. try { scoped_ptr<TransactionLog::Event> event(SPConfig::getConfig().EventManager.newPlugin(LOGIN_EVENT, nullptr)); LoginEvent* error_event = dynamic_cast<LoginEvent*>(event.get()); if (error_event) { error_event->m_exception = &ex; error_event->m_request = &httpRequest; error_event->m_app = &application; if (policy->getIssuerMetadata()) error_event->m_peer = dynamic_cast<const EntityDescriptor*>(policy->getIssuerMetadata()->getParent()); auto_ptr_char prot(getProtocolFamily()); error_event->m_protocol = prot.get(); error_event->m_binding = getString("Binding").second; error_event->m_saml2Response = dynamic_cast<const saml2p::StatusResponseType*>(msg.get()); if (!error_event->m_saml2Response) error_event->m_saml1Response = dynamic_cast<const saml1p::Response*>(msg.get()); application.getServiceProvider().getTransactionLog()->write(*error_event); } else { m_log.warn("unable to audit event, log event object was of an incorrect type"); } } catch (std::exception& ex2) { m_log.warn("exception auditing event: %s", ex2.what()); } // If no sign of annotation, try to annotate it now. if (!ex.getProperty("statusCode")) { annotateException(&ex, policy->getIssuerMetadata(), nullptr, false); // wait to throw it } throw; } #else throw ConfigurationException("Cannot process message using lite version of shibsp library."); #endif }