2 * Licensed to the University Corporation for Advanced Internet
3 * Development, Inc. (UCAID) under one or more contributor license
4 * agreements. See the NOTICE file distributed with this work for
5 * additional information regarding copyright ownership.
7 * UCAID licenses this file to you under the Apache License,
8 * Version 2.0 (the "License"); you may not use this file except
9 * in compliance with the License. You may obtain a copy of the
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17 * either express or implied. See the License for the specific
18 * language governing permissions and limitations under the License.
24 * Handler for looking up assertions in the SessionCache.
28 #include "exceptions.h"
29 #include "Application.h"
30 #include "ServiceProvider.h"
31 #include "SessionCacheEx.h"
32 #include "SPRequest.h"
33 #include "handler/RemotedHandler.h"
34 #include "handler/SecuredHandler.h"
36 #include <boost/scoped_ptr.hpp>
39 # include <saml/exceptions.h>
40 # include <saml/Assertion.h>
41 # include <xmltooling/util/XMLHelper.h>
42 using namespace opensaml;
45 using namespace shibspconstants;
46 using namespace shibsp;
47 using namespace xmltooling;
48 using namespace boost;
53 #if defined (_MSC_VER)
54 #pragma warning( push )
55 #pragma warning( disable : 4250 )
58 class SHIBSP_API AssertionLookup : public SecuredHandler, public RemotedHandler
61 AssertionLookup(const DOMElement* e, const char* appId);
62 virtual ~AssertionLookup() {}
64 pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
65 void receive(DDF& in, ostream& out);
67 const char* getType() const {
68 return "AssertionLookup";
72 pair<bool,long> processMessage(const Application& application, HTTPRequest& httpRequest, HTTPResponse& httpResponse) const;
75 #if defined (_MSC_VER)
76 #pragma warning( pop )
79 Handler* SHIBSP_DLLLOCAL AssertionLookupFactory(const pair<const DOMElement*,const char*>& p)
81 return new AssertionLookup(p.first, p.second);
86 AssertionLookup::AssertionLookup(const DOMElement* e, const char* appId)
87 : SecuredHandler(e, Category::getInstance(SHIBSP_LOGCAT ".AssertionLookup"), "exportACL", "127.0.0.1 ::1")
89 setAddress("run::AssertionLookup");
92 pair<bool,long> AssertionLookup::run(SPRequest& request, bool isHandler) const
94 // Check ACL in base class.
95 pair<bool,long> ret = SecuredHandler::run(request, isHandler);
100 if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
101 // When out of process, we run natively and directly process the message.
102 return processMessage(request.getApplication(), request, request);
105 // When not out of process, we remote all the message processing.
106 DDF out,in = wrap(request);
107 DDFJanitor jin(in), jout(out);
109 out=request.getServiceProvider().getListenerService()->send(in);
110 return unwrap(request, out);
113 catch (std::exception& ex) {
114 m_log.error("error while processing request: %s", ex.what());
115 istringstream msg("Assertion Lookup Failed");
116 return make_pair(true, request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_ERROR));
120 void AssertionLookup::receive(DDF& in, ostream& out)
123 const char* aid = in["application_id"].string();
124 const Application* app = aid ? SPConfig::getConfig().getServiceProvider()->getApplication(aid) : nullptr;
126 // Something's horribly wrong.
127 m_log.error("couldn't find application (%s) for assertion lookup", aid ? aid : "(missing)");
128 throw ConfigurationException("Unable to locate application for assertion lookup, deleted?");
131 // Unpack the request.
132 scoped_ptr<HTTPRequest> req(getRequest(in));
133 //m_log.debug("found %d client certificates", req->getClientCertificates().size());
135 // Wrap a response shim.
137 DDFJanitor jout(ret);
138 scoped_ptr<HTTPResponse> resp(getResponse(ret));
140 // Since we're remoted, the result should either be a throw, a false/0 return,
141 // which we just return as an empty structure, or a response/redirect,
142 // which we capture in the facade and send back.
143 processMessage(*app, *req, *resp);
147 pair<bool,long> AssertionLookup::processMessage(const Application& application, HTTPRequest& httpRequest, HTTPResponse& httpResponse) const
150 const char* key = httpRequest.getParameter("key");
151 const char* ID = httpRequest.getParameter("ID");
152 if (!key || !*key || !ID || !*ID) {
153 m_log.error("assertion lookup request failed, missing required parameters");
154 throw FatalProfileException("Missing key or ID parameters.");
157 m_log.debug("processing assertion lookup request (session: %s, assertion: %s)", key, ID);
159 SessionCacheEx* cache = dynamic_cast<SessionCacheEx*>(application.getServiceProvider().getSessionCache());
161 m_log.error("session cache does not support extended API");
162 throw FatalProfileException("Session cache does not support assertion lookup.");
165 // The cache will either silently pass a session or nullptr back, or throw an exception out.
166 Session* session = cache->find(application, key);
168 m_log.error("valid session (%s) not found for assertion lookup", key);
169 throw FatalProfileException("Session key not found.");
172 Locker locker(session, false);
174 const Assertion* assertion = session->getAssertion(ID);
176 m_log.error("assertion (%s) not found in session (%s)", ID, key);
177 throw FatalProfileException("Assertion not found.");
182 httpResponse.setContentType("application/samlassertion+xml");
183 return make_pair(true, httpResponse.sendResponse(s));
185 return make_pair(false, 0L);