X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=shibsp%2Fhandler%2Fimpl%2FSAML2NameIDMgmt.cpp;h=34bc87d233e3323a8463dce153c04e105387b30b;hb=c51bfd77603cf0ddb0b5e374c35586a8435895d6;hp=a724a519572547262a54f92fe930eccbf51a53ea;hpb=ea0d1cda4dc06194b0ec8196bf3b1d2b4f165c2e;p=shibboleth%2Fcpp-sp.git diff --git a/shibsp/handler/impl/SAML2NameIDMgmt.cpp b/shibsp/handler/impl/SAML2NameIDMgmt.cpp index a724a51..34bc87d 100644 --- a/shibsp/handler/impl/SAML2NameIDMgmt.cpp +++ b/shibsp/handler/impl/SAML2NameIDMgmt.cpp @@ -38,6 +38,8 @@ # include "security/SecurityPolicy.h" # include "security/SecurityPolicyProvider.h" # include +# include +# include # include # include # include @@ -53,8 +55,11 @@ using namespace opensaml; # include "lite/SAMLConstants.h" #endif +#include + using namespace shibsp; using namespace xmltooling; +using namespace boost; using namespace std; namespace shibsp { @@ -68,15 +73,7 @@ namespace shibsp { { public: SAML2NameIDMgmt(const DOMElement* e, const char* appId); - virtual ~SAML2NameIDMgmt() { -#ifndef SHIBSP_LITE - if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) { - delete m_decoder; - XMLString::release(&m_outgoing); - for_each(m_encoders.begin(), m_encoders.end(), cleanup_pair()); - } -#endif - } + virtual ~SAML2NameIDMgmt() {} void receive(DDF& in, ostream& out); pair run(SPRequest& request, bool isHandler=true) const; @@ -122,11 +119,9 @@ namespace shibsp { bool front ) const; - xmltooling::QName m_role; - MessageDecoder* m_decoder; - XMLCh* m_outgoing; - vector m_bindings; - map m_encoders; + scoped_ptr m_decoder; + vector m_bindings; + map< string,boost::shared_ptr > m_encoders; #endif }; @@ -141,70 +136,59 @@ namespace shibsp { }; SAML2NameIDMgmt::SAML2NameIDMgmt(const DOMElement* e, const char* appId) - : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".NameIDMgmt.SAML2")) -#ifndef SHIBSP_LITE - ,m_role(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME), m_decoder(nullptr), m_outgoing(nullptr) -#endif + : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT ".NameIDMgmt.SAML2")) { #ifndef SHIBSP_LITE if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) { SAMLConfig& conf = SAMLConfig::getConfig(); // Handle incoming binding. - m_decoder = conf.MessageDecoderManager.newPlugin( - getString("Binding").second, pair(e,shibspconstants::SHIB2SPCONFIG_NS) + m_decoder.reset( + conf.MessageDecoderManager.newPlugin( + getString("Binding").second, pair(e,shibspconstants::SHIB2SPCONFIG_NS) + ) ); m_decoder->setArtifactResolver(SPConfig::getConfig().getArtifactResolver()); if (m_decoder->isUserAgentPresent()) { // Handle front-channel binding setup. - pair outgoing = getXMLString("outgoingBindings", m_configNS.get()); + string dupBindings; + pair outgoing = getString("outgoingBindings", m_configNS.get()); if (outgoing.first) { - m_outgoing = XMLString::replicate(outgoing.second); - XMLString::trim(m_outgoing); + dupBindings = outgoing.second; + trim(dupBindings); } else { // No override, so we'll install a default binding precedence. - string prec = string(samlconstants::SAML20_BINDING_HTTP_REDIRECT) + ' ' + samlconstants::SAML20_BINDING_HTTP_POST + ' ' + + dupBindings = string(samlconstants::SAML20_BINDING_HTTP_REDIRECT) + ' ' + samlconstants::SAML20_BINDING_HTTP_POST + ' ' + samlconstants::SAML20_BINDING_HTTP_POST_SIMPLESIGN + ' ' + samlconstants::SAML20_BINDING_HTTP_ARTIFACT; - m_outgoing = XMLString::transcode(prec.c_str()); } - int pos; - XMLCh* start = m_outgoing; - while (start && *start) { - pos = XMLString::indexOf(start,chSpace); - if (pos != -1) - *(start + pos)=chNull; - m_bindings.push_back(start); + split(m_bindings, dupBindings, is_space(), algorithm::token_compress_on); + for (vector::const_iterator b = m_bindings.begin(); b != m_bindings.end(); ++b) { try { - auto_ptr_char b(start); - MessageEncoder * encoder = conf.MessageEncoderManager.newPlugin( - b.get(), pair(e,shibspconstants::SHIB2SPCONFIG_NS) + boost::shared_ptr encoder( + conf.MessageEncoderManager.newPlugin(*b, pair(e,shibspconstants::SHIB2SPCONFIG_NS)) ); if (encoder->isUserAgentPresent() && XMLString::equals(getProtocolFamily(), encoder->getProtocolFamily())) { - m_encoders[start] = encoder; - m_log.debug("supporting outgoing binding (%s)", b.get()); + m_encoders[*b] = encoder; + m_log.debug("supporting outgoing binding (%s)", b->c_str()); } else { - delete encoder; - m_log.warn("skipping outgoing binding (%s), not a SAML 2.0 front-channel mechanism", b.get()); + m_log.warn("skipping outgoing binding (%s), not a SAML 2.0 front-channel mechanism", b->c_str()); } } - catch (exception& ex) { + catch (std::exception& ex) { m_log.error("error building MessageEncoder: %s", ex.what()); } - if (pos != -1) - start = start + pos + 1; - else - break; } } else { - MessageEncoder* encoder = conf.MessageEncoderManager.newPlugin( - getString("Binding").second, pair(e,shibspconstants::SHIB2SPCONFIG_NS) + pair b = getString("Binding"); + boost::shared_ptr encoder( + conf.MessageEncoderManager.newPlugin(b.second, pair(e,shibspconstants::SHIB2SPCONFIG_NS)) ); - m_encoders.insert(pair(nullptr, encoder)); + m_encoders[b.second] = encoder; } } #endif @@ -235,8 +219,8 @@ pair SAML2NameIDMgmt::run(SPRequest& request, bool isHandler) const void SAML2NameIDMgmt::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) for NameID mgmt", aid ? aid : "(missing)"); @@ -244,29 +228,29 @@ void SAML2NameIDMgmt::receive(DDF& in, ostream& out) } // Unpack the request. - auto_ptr req(getRequest(in)); + scoped_ptr req(getRequest(in)); // Wrap a response shim. DDF ret(nullptr); DDFJanitor jout(ret); - auto_ptr resp(getResponse(ret)); + scoped_ptr resp(getResponse(ret)); // 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()); + doRequest(*app, *req, *resp); out << ret; } -pair SAML2NameIDMgmt::doRequest( - const Application& application, const HTTPRequest& request, HTTPResponse& response - ) const +pair SAML2NameIDMgmt::doRequest(const Application& application, const HTTPRequest& request, HTTPResponse& response) const { #ifndef SHIBSP_LITE SessionCache* cache = application.getServiceProvider().getSessionCache(); // Locate policy key. - pair policyId = getString("policyId", m_configNS.get()); // namespace-qualified if inside handler element + pair policyId = getString("policyId", m_configNS.get()); // may be namespace-qualified inside handler element + if (!policyId.first) + policyId = getString("policyId"); // try unqualified if (!policyId.first) policyId = application.getString("policyId"); // unqualified in Application(s) element @@ -274,13 +258,13 @@ pair SAML2NameIDMgmt::doRequest( Locker metadataLocker(application.getMetadataProvider()); // Create the policy. - auto_ptr policy( - application.getServiceProvider().getSecurityPolicyProvider()->createSecurityPolicy(application, &m_role, policyId.second) + scoped_ptr policy( + application.getServiceProvider().getSecurityPolicyProvider()->createSecurityPolicy(application, &IDPSSODescriptor::ELEMENT_QNAME, policyId.second) ); // Decode the message. string relayState; - auto_ptr msg(m_decoder->decode(relayState, request, *policy.get())); + scoped_ptr msg(m_decoder->decode(relayState, request, *policy)); const ManageNameIDRequest* mgmtRequest = dynamic_cast(msg.get()); if (mgmtRequest) { if (!policy->isAuthenticated()) @@ -305,7 +289,7 @@ pair SAML2NameIDMgmt::doRequest( EntityDescriptor* entity = policy->getIssuerMetadata() ? dynamic_cast(policy->getIssuerMetadata()->getParent()) : nullptr; - bool ownedName = false; + scoped_ptr decryptedID; NameID* nameid = mgmtRequest->getNameID(); if (!nameid) { // Check for EncryptedID. @@ -316,20 +300,14 @@ pair SAML2NameIDMgmt::doRequest( m_log.warn("found encrypted NameID, but no decryption credential was available"); else { Locker credlocker(cr); - auto_ptr mcc( + scoped_ptr mcc( policy->getIssuerMetadata() ? new MetadataCredentialCriteria(*policy->getIssuerMetadata()) : nullptr ); try { - auto_ptr decryptedID( - encname->decrypt(*cr,application.getRelyingParty(entity)->getXMLString("entityID").second,mcc.get()) - ); + decryptedID.reset(encname->decrypt(*cr, application.getRelyingParty(entity)->getXMLString("entityID").second, mcc.get())); nameid = dynamic_cast(decryptedID.get()); - if (nameid) { - ownedName = true; - decryptedID.release(); - } } - catch (exception& ex) { + catch (std::exception& ex) { m_log.error(ex.what()); } } @@ -349,8 +327,6 @@ pair SAML2NameIDMgmt::doRequest( ); } - auto_ptr namewrapper(ownedName ? nameid : nullptr); - // For a front-channel request, we have to match the information in the request // against the current session. if (!session_id.empty()) { @@ -369,7 +345,7 @@ pair SAML2NameIDMgmt::doRequest( } // Determine what's happening... - bool ownedNewID = false; + scoped_ptr newDecryptedID; NewID* newid = nullptr; if (!mgmtRequest->getTerminate()) { // Better be a NewID in there. @@ -383,20 +359,14 @@ pair SAML2NameIDMgmt::doRequest( m_log.warn("found encrypted NewID, but no decryption credential was available"); else { Locker credlocker(cr); - auto_ptr mcc( + scoped_ptr mcc( policy->getIssuerMetadata() ? new MetadataCredentialCriteria(*policy->getIssuerMetadata()) : nullptr ); try { - auto_ptr decryptedID( - encnewid->decrypt(*cr,application.getRelyingParty(entity)->getXMLString("entityID").second,mcc.get()) - ); - newid = dynamic_cast(decryptedID.get()); - if (newid) { - ownedNewID = true; - decryptedID.release(); - } + newDecryptedID.reset(encnewid->decrypt(*cr, application.getRelyingParty(entity)->getXMLString("entityID").second, mcc.get())); + newid = dynamic_cast(newDecryptedID.get()); } - catch (exception& ex) { + catch (std::exception& ex) { m_log.error(ex.what()); } } @@ -418,8 +388,6 @@ pair SAML2NameIDMgmt::doRequest( } } - auto_ptr newwrapper(ownedNewID ? newid : nullptr); - // TODO: maybe support in-place modification of sessions? /* vector sessions; @@ -448,7 +416,7 @@ pair SAML2NameIDMgmt::doRequest( */ // Do back-channel app notifications. - // Not supporting front-channel due to privacy fears. + // Not supporting front-channel due to privacy concerns. bool worked = notifyBackChannel(application, request.getRequestURL(), *nameid, newid); return sendResponse( @@ -482,10 +450,8 @@ pair SAML2NameIDMgmt::doRequest( */ FatalProfileException ex("Incoming message was not a samlp:ManageNameIDRequest."); - if (policy->getIssuerMetadata()) - annotateException(&ex, policy->getIssuerMetadata()); // throws it - ex.raise(); - return make_pair(false,0L); // never happen, satisfies compiler + annotateException(&ex, policy->getIssuerMetadata()); // throws it + return make_pair(false, 0L); // never happen, satisfies compiler #else throw ConfigurationException("Cannot process NameID mgmt message using lite version of shibsp library."); #endif @@ -510,11 +476,12 @@ pair SAML2NameIDMgmt::sendResponse( const MessageEncoder* encoder = nullptr; if (front) { const IDPSSODescriptor* idp = dynamic_cast(role); - for (vector::const_iterator b = m_bindings.begin(); idp && b!=m_bindings.end(); ++b) { - if ((ep=EndpointManager(idp->getManageNameIDServices()).getByBinding(*b))) { - map::const_iterator enc = m_encoders.find(*b); - if (enc!=m_encoders.end()) - encoder = enc->second; + for (vector::const_iterator b = m_bindings.begin(); idp && b != m_bindings.end(); ++b) { + auto_ptr_XMLCh wideb(b->c_str()); + if ((ep = EndpointManager(idp->getManageNameIDServices()).getByBinding(wideb.get()))) { + map< string,boost::shared_ptr >::const_iterator enc = m_encoders.find(*b); + if (enc != m_encoders.end()) + encoder = enc->second.get(); break; } } @@ -526,7 +493,7 @@ pair SAML2NameIDMgmt::sendResponse( } } else { - encoder = m_encoders.begin()->second; + encoder = m_encoders.begin()->second.get(); } // Prepare response. @@ -541,13 +508,13 @@ pair SAML2NameIDMgmt::sendResponse( Issuer* issuer = IssuerBuilder::buildIssuer(); nim->setIssuer(issuer); issuer->setName(application.getRelyingParty(dynamic_cast(role->getParent()))->getXMLString("entityID").second); - fillStatus(*nim.get(), code, subcode, msg); + fillStatus(*nim, code, subcode, msg); auto_ptr_char dest(nim->getDestination()); long ret = sendMessage(*encoder, nim.get(), relayState, dest.get(), role, application, httpResponse); nim.release(); // freed by encoder - return make_pair(true,ret); + return make_pair(true, ret); } #include "util/SPConstants.h" @@ -570,7 +537,6 @@ namespace { HTTPSOAPTransport* http = dynamic_cast(&transport); if (http) { http->useChunkedEncoding(false); - http->setRequestHeader("User-Agent", PACKAGE_NAME); http->setRequestHeader(PACKAGE_NAME, PACKAGE_VERSION); } } @@ -586,7 +552,7 @@ bool SAML2NameIDMgmt::notifyBackChannel( if (endpoint.empty()) return true; - auto_ptr env(EnvelopeBuilder::buildEnvelope()); + scoped_ptr env(EnvelopeBuilder::buildEnvelope()); Body* body = BodyBuilder::buildBody(); env->setBody(body); ElementProxy* msg = new AnyElementImpl(shibspconstants::SHIB2SPNOTIFY_NS, NameIDNotification); @@ -601,10 +567,10 @@ bool SAML2NameIDMgmt::notifyBackChannel( SOAPNotifier soaper; while (!endpoint.empty()) { try { - soaper.send(*env.get(), SOAPTransport::Address(application.getId(), application.getId(), endpoint.c_str())); + soaper.send(*env, SOAPTransport::Address(application.getId(), application.getId(), endpoint.c_str())); delete soaper.receive(); } - catch (exception& ex) { + catch (std::exception& ex) { m_log.error("error notifying application of logout event: %s", ex.what()); result = false; }