X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=shibsp%2Fhandler%2Fimpl%2FSAML2ArtifactResolution.cpp;h=ae1150cdd79eb24dc5820eb3d85be83a2156f453;hb=c51bfd77603cf0ddb0b5e374c35586a8435895d6;hp=0584892c7a7035334636627c1bbbce9488775906;hpb=3b125206f61e371db1ec404decd16b3e21854643;p=shibboleth%2Fcpp-sp.git diff --git a/shibsp/handler/impl/SAML2ArtifactResolution.cpp b/shibsp/handler/impl/SAML2ArtifactResolution.cpp index 0584892..ae1150c 100644 --- a/shibsp/handler/impl/SAML2ArtifactResolution.cpp +++ b/shibsp/handler/impl/SAML2ArtifactResolution.cpp @@ -1,17 +1,21 @@ -/* - * Copyright 2001-2007 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 +/** + * Licensed to the University Corporation for Advanced Internet + * Development, Inc. (UCAID) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. * - * http://www.apache.org/licenses/LICENSE-2.0 + * UCAID licenses this file to you 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 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. */ /** @@ -21,15 +25,18 @@ */ #include "internal.h" -#include "Application.h" #include "exceptions.h" +#include "Application.h" #include "ServiceProvider.h" +#include "SPRequest.h" #include "handler/AbstractHandler.h" #include "handler/RemotedHandler.h" #include "util/SPConstants.h" #ifndef SHIBSP_LITE # include "security/SecurityPolicy.h" +# include "security/SecurityPolicyProvider.h" +# include # include # include # include @@ -38,21 +45,22 @@ # include # include # include -# include using namespace opensaml::saml2md; using namespace opensaml::saml2p; using namespace opensaml::saml2; -using namespace samlconstants; +using namespace opensaml; +#else +# include "lite/SAMLConstants.h" #endif +#include #include using namespace shibspconstants; using namespace shibsp; -using namespace opensaml; using namespace soap11; using namespace xmltooling; -using namespace log4cpp; +using namespace boost; using namespace std; namespace shibsp { @@ -66,26 +74,59 @@ namespace shibsp { { public: SAML2ArtifactResolution(const DOMElement* e, const char* appId); - virtual ~SAML2ArtifactResolution(); + virtual ~SAML2ArtifactResolution() {} pair run(SPRequest& request, bool isHandler=true) const; void receive(DDF& in, ostream& out); +#ifndef SHIBSP_LITE + const char* getType() const { + return "ArtifactResolutionService"; + } + + void generateMetadata(SPSSODescriptor& role, const char* handlerURL) const { + // Initial guess at index to use. + pair ix = pair(false,0); + if (!strncmp(handlerURL, "https", 5)) + ix = getUnsignedInt("sslIndex", shibspconstants::ASCII_SHIB2SPCONFIG_NS); + if (!ix.first) + ix = getUnsignedInt("index"); + if (!ix.first) + ix.second = 1; + + // Find maximum index in use and go one higher. + const vector& services = const_cast(role).getArtifactResolutionServices(); + if (!services.empty() && ix.second <= services.back()->getIndex().second) + ix.second = services.back()->getIndex().second + 1; + + const char* loc = getString("Location").second; + string hurl(handlerURL); + if (*loc != '/') + hurl += '/'; + hurl += loc; + auto_ptr_XMLCh widen(hurl.c_str()); + + auto_ptr ep(ArtifactResolutionServiceBuilder::buildArtifactResolutionService()); + ep->setLocation(widen.get()); + ep->setBinding(getXMLString("Binding").second); + ep->setIndex(ix.second); + role.getArtifactResolutionServices().push_back(ep.get()); + ep.release(); + } +#endif + const XMLCh* getProtocolFamily() const { + return samlconstants::SAML20P_NS; + } + private: pair processMessage(const Application& application, HTTPRequest& httpRequest, HTTPResponse& httpResponse) const; #ifndef SHIBSP_LITE - pair samlError( - const Application& app, - const ArtifactResolve& request, - HTTPResponse& httpResponse, - const XMLCh* code, - const XMLCh* subcode=NULL, - const char* msg=NULL + pair emptyResponse( + const Application& app, const ArtifactResolve& request, HTTPResponse& httpResponse, const EntityDescriptor* recipient ) const; - MessageEncoder* m_encoder; - MessageDecoder* m_decoder; - QName m_role; + scoped_ptr m_encoder; + scoped_ptr m_decoder; #endif }; @@ -101,23 +142,20 @@ namespace shibsp { }; SAML2ArtifactResolution::SAML2ArtifactResolution(const DOMElement* e, const char* appId) - : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".SAML2ArtifactResolution")) -#ifndef SHIBSP_LITE - ,m_encoder(NULL), m_decoder(NULL), m_role(samlconstants::SAML20MD_NS, opensaml::saml2md::IDPSSODescriptor::LOCAL_NAME) -#endif + : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT ".ArtifactResolution.SAML2")) { #ifndef SHIBSP_LITE if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) { - try { - m_encoder = SAMLConfig::getConfig().MessageEncoderManager.newPlugin(getString("Binding").second,e); - m_decoder = SAMLConfig::getConfig().MessageDecoderManager.newPlugin(getString("Binding").second,e); - } - catch (exception& ex) { - m_log.error("error building MessageEncoder/Decoder pair for binding (%s)", getString("Binding").second); - delete m_encoder; - delete m_decoder; - throw; - } + m_encoder.reset( + SAMLConfig::getConfig().MessageEncoderManager.newPlugin( + getString("Binding").second, pair(e,shibspconstants::SHIB2SPCONFIG_NS) + ) + ); + m_decoder.reset( + SAMLConfig::getConfig().MessageDecoderManager.newPlugin( + getString("Binding").second, pair(e,shibspconstants::SHIB2SPCONFIG_NS) + ) + ); } #endif string address(appId); @@ -126,14 +164,6 @@ SAML2ArtifactResolution::SAML2ArtifactResolution(const DOMElement* e, const char setAddress(address.c_str()); } -SAML2ArtifactResolution::~SAML2ArtifactResolution() -{ -#ifndef SHIBSP_LITE - delete m_encoder; - delete m_decoder; -#endif -} - pair SAML2ArtifactResolution::run(SPRequest& request, bool isHandler) const { string relayState; @@ -146,14 +176,14 @@ pair SAML2ArtifactResolution::run(SPRequest& request, bool isHandler) } else { // When not out of process, we remote all the message processing. - DDF out,in = wrap(request, NULL, true); + DDF out,in = wrap(request, nullptr, true); DDFJanitor jin(in), jout(out); - out=request.getServiceProvider().getListenerService()->send(in); + out = request.getServiceProvider().getListenerService()->send(in); return unwrap(request, out); } } - catch (exception& ex) { + catch (std::exception& ex) { m_log.error("error while processing request: %s", ex.what()); // Build a SOAP fault around the error. @@ -168,15 +198,16 @@ pair SAML2ArtifactResolution::run(SPRequest& request, bool isHandler) fs->setString(msg.get()); #ifndef SHIBSP_LITE // Use MessageEncoder to send back the fault. - long ret = m_encoder->encode(request, fault.get(), NULL); + long ret = m_encoder->encode(request, fault.get(), nullptr); fault.release(); return make_pair(true, ret); #else // Brute force the fault to avoid library dependency. - auto_ptr env(EnvelopeBuilder::buildEnvelope()); + scoped_ptr env(EnvelopeBuilder::buildEnvelope()); Body* body = BodyBuilder::buildBody(); env->setBody(body); - body->getUnknownXMLObjects().push_back(fault.release()); + body->getUnknownXMLObjects().push_back(fault.get()); + fault.release(); string xmlbuf; XMLHelper::serialize(env->marshall(), xmlbuf); istringstream s(xmlbuf); @@ -190,7 +221,7 @@ void SAML2ArtifactResolution::receive(DDF& in, ostream& out) { // Find application. const char* aid=in["application_id"].string(); - const Application* app=aid ? SPConfig::getConfig().getServiceProvider()->getApplication(aid) : NULL; + 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 artifact resolution", aid ? aid : "(missing)"); @@ -198,22 +229,22 @@ void SAML2ArtifactResolution::receive(DDF& in, ostream& out) } // Unpack the request. - auto_ptr req(getRequest(in)); + scoped_ptr req(getRequest(in)); //m_log.debug("found %d client certificates", req->getClientCertificates().size()); // Wrap a response shim. - DDF ret(NULL); + DDF ret(nullptr); DDFJanitor jout(ret); - auto_ptr resp(getResponse(ret)); + scoped_ptr resp(getResponse(ret)); try { // Since we're remoted, the result should either be a throw, 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. - processMessage(*app, *req.get(), *resp.get()); + processMessage(*app, *req, *resp); out << ret; } - catch (exception& ex) { + catch (std::exception& ex) { #ifndef SHIBSP_LITE m_log.error("error while processing request: %s", ex.what()); @@ -227,7 +258,7 @@ void SAML2ArtifactResolution::receive(DDF& in, ostream& out) pair flag = getBool("detailedErrors", m_configNS.get()); auto_ptr_XMLCh msg((flag.first && flag.second) ? ex.what() : "Error processing request."); fs->setString(msg.get()); - m_encoder->encode(*resp.get(), fault.get(), NULL); + m_encoder->encode(*resp, fault.get(), nullptr); fault.release(); out << ret; #else @@ -250,40 +281,40 @@ pair SAML2ArtifactResolution::processMessage(const Application& appli if (!policyId.first) policyId = application.getString("policyId"); // unqualified in Application(s) element - // Access policy properties. - const PropertySet* settings = application.getServiceProvider().getPolicySettings(policyId.second); - pair 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); + scoped_ptr policy( + application.getServiceProvider().getSecurityPolicyProvider()->createSecurityPolicy(application, &IDPSSODescriptor::ELEMENT_QNAME, policyId.second) + ); // Decode the message and verify that it's a secured ArtifactResolve request. string relayState; - auto_ptr msg(m_decoder->decode(relayState, httpRequest, policy)); - if (!msg.get()) + scoped_ptr msg(m_decoder->decode(relayState, httpRequest, *policy)); + if (!msg) throw BindingException("Failed to decode a SAML request."); const ArtifactResolve* req = dynamic_cast(msg.get()); if (!req) throw FatalProfileException("Decoded message was not a samlp::ArtifactResolve request."); + const EntityDescriptor* entity = policy->getIssuerMetadata() ? dynamic_cast(policy->getIssuerMetadata()->getParent()) : nullptr; + try { - auto_ptr_char artifact(req->getArtifact() ? req->getArtifact()->getArtifact() : NULL); + auto_ptr_char artifact(req->getArtifact() ? req->getArtifact()->getArtifact() : nullptr); if (!artifact.get() || !*artifact.get()) - return samlError(application, *req, httpResponse, StatusCode::REQUESTER, NULL, "Request did not contain an artifact to resolve."); - auto_ptr_char issuer(policy.getIssuer() ? policy.getIssuer()->getName() : NULL); + return emptyResponse(application, *req, httpResponse, entity); + auto_ptr_char issuer(policy->getIssuer() ? policy->getIssuer()->getName() : nullptr); m_log.info("resolving artifact (%s) for (%s)", artifact.get(), issuer.get() ? issuer.get() : "unknown"); // Parse the artifact and retrieve the object. - auto_ptr artobj(SAMLArtifact::parse(artifact.get())); + scoped_ptr artobj(SAMLArtifact::parse(artifact.get())); auto_ptr payload(artmap->retrieveContent(artobj.get(), issuer.get())); - if (!policy.isSecure()) { + if (!policy->isAuthenticated()) { m_log.error("request for artifact was unauthenticated, purging the artifact mapping"); - return samlError(application, *req, httpResponse, StatusCode::REQUESTER, StatusCode::AUTHN_FAILED, "Unable to authenticate request."); + return emptyResponse(application, *req, httpResponse, entity); } m_log.debug("artifact resolved, preparing response"); @@ -292,75 +323,38 @@ pair SAML2ArtifactResolution::processMessage(const Application& appli auto_ptr resp(ArtifactResponseBuilder::buildArtifactResponse()); resp->setInResponseTo(req->getID()); Issuer* me = IssuerBuilder::buildIssuer(); - me->setName(application.getXMLString("entityID").second); - resp->setPayload(payload.release()); - - const EntityDescriptor* entity = - policy.getIssuerMetadata() ? dynamic_cast(policy.getIssuerMetadata()->getParent()) : NULL; - const PropertySet* relyingParty = application.getRelyingParty(entity); - pair flag = relyingParty->getString("signResponses"); - if (policy.getIssuerMetadata() && flag.first && (!strcmp(flag.second, "true") || !strcmp(flag.second, "back"))) { - CredentialResolver* credResolver=application.getCredentialResolver(); - if (credResolver) { - Locker credLocker(credResolver); - // Fill in criteria to use. - MetadataCredentialCriteria mcc(*policy.getIssuerMetadata()); - mcc.setUsage(CredentialCriteria::SIGNING_CREDENTIAL); - pair keyName = relyingParty->getString("keyName"); - if (keyName.first) - mcc.getKeyNames().insert(keyName.second); - pair sigalg = relyingParty->getXMLString("signatureAlg"); - if (sigalg.first) - mcc.setXMLAlgorithm(sigalg.second); - const Credential* cred = credResolver->resolve(&mcc); - if (cred) { - // Signed request. - long ret = m_encoder->encode( - httpResponse, - resp.get(), - NULL, - entity, - relayState.c_str(), - NULL, - cred, - sigalg.second, - relyingParty->getXMLString("digestAlg").second - ); - resp.release(); // freed by encoder - return make_pair(true,ret); - } - else { - m_log.warn("no signing credential resolved, leaving response unsigned"); - } - } - } + me->setName(application.getRelyingParty(entity)->getXMLString("entityID").second); + resp->setPayload(payload.get()); + payload.release(); - long ret = m_encoder->encode(httpResponse, resp.get(), NULL, entity, relayState.c_str()); + long ret = sendMessage( + *m_encoder, resp.get(), relayState.c_str(), nullptr, policy->getIssuerMetadata(), application, httpResponse, "signResponses" + ); resp.release(); // freed by encoder - return make_pair(true,ret); + return make_pair(true, ret); } - catch (exception& ex) { - // Trap localized errors in a SAML Response. - m_log.error("error processing artifact request, returning SAML error: %s", ex.what()); - return samlError(application, *req, httpResponse, StatusCode::RESPONDER, NULL, ex.what()); + catch (std::exception& ex) { + // Trap localized errors. + m_log.error("error processing artifact request: %s", ex.what()); + return emptyResponse(application, *req, httpResponse, entity); } #else - return make_pair(false,0); + return make_pair(false,0L); #endif } #ifndef SHIBSP_LITE -pair SAML2ArtifactResolution::samlError( - const Application& app, const ArtifactResolve& request, HTTPResponse& httpResponse, const XMLCh* code, const XMLCh* subcode, const char* msg +pair SAML2ArtifactResolution::emptyResponse( + const Application& app, const ArtifactResolve& request, HTTPResponse& httpResponse, const EntityDescriptor* recipient ) const { auto_ptr resp(ArtifactResponseBuilder::buildArtifactResponse()); resp->setInResponseTo(request.getID()); Issuer* me = IssuerBuilder::buildIssuer(); - me->setName(app.getXMLString("entityID").second); - prepareResponse(*resp.get(), code, subcode, msg); - long ret = m_encoder->encode(httpResponse, resp.get(), NULL); + me->setName(app.getRelyingParty(recipient)->getXMLString("entityID").second); + fillStatus(*resp, StatusCode::SUCCESS); + long ret = m_encoder->encode(httpResponse, resp.get(), nullptr); resp.release(); // freed by encoder - return make_pair(true,ret); + return make_pair(true, ret); } #endif