Ejemplo n.º 1
0
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
}
Ejemplo n.º 2
0
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));
    }
}
Ejemplo n.º 3
0
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
}