1 /**
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.
6 *
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
10 * License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
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.
19 */
20
21 /**
22 * AssertionLookup.cpp
23 *
24 * Handler for looking up assertions in the SessionCache.
25 */
26
27 #include "internal.h"
28 #include "exceptions.h"
29 #include "Application.h"
30 #include "ServiceProvider.h"
31 #include "SessionCache.h"
32 #include "SPRequest.h"
33 #include "handler/RemotedHandler.h"
34 #include "handler/SecuredHandler.h"
35
36 #include <boost/scoped_ptr.hpp>
37
38 #ifndef SHIBSP_LITE
39 # include <saml/exceptions.h>
40 # include <saml/Assertion.h>
41 # include <xmltooling/util/XMLHelper.h>
42 using namespace opensaml;
43 #endif
44
45 using namespace shibspconstants;
46 using namespace shibsp;
47 using namespace xmltooling;
48 using namespace boost;
49 using namespace std;
50
51 namespace shibsp {
52
53 #if defined (_MSC_VER)
54 #pragma warning( push )
55 #pragma warning( disable : 4250 )
56 #endif
57
58 class SHIBSP_API AssertionLookup : public SecuredHandler, public RemotedHandler
59 {
60 public:
61 AssertionLookup(const DOMElement* e, const char* appId);
~AssertionLookup()62 virtual ~AssertionLookup() {}
63
64 pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
65 void receive(DDF& in, ostream& out);
66
getType() const67 const char* getType() const {
68 return "AssertionLookup";
69 }
70
71 private:
72 pair<bool,long> processMessage(const Application& application, HTTPRequest& httpRequest, HTTPResponse& httpResponse) const;
73 };
74
75 #if defined (_MSC_VER)
76 #pragma warning( pop )
77 #endif
78
AssertionLookupFactory(const pair<const DOMElement *,const char * > & p,bool)79 Handler* SHIBSP_DLLLOCAL AssertionLookupFactory(const pair<const DOMElement*,const char*>& p, bool)
80 {
81 return new AssertionLookup(p.first, p.second);
82 }
83
84 };
85
AssertionLookup(const DOMElement * e,const char * appId)86 AssertionLookup::AssertionLookup(const DOMElement* e, const char* appId)
87 : SecuredHandler(e, Category::getInstance(SHIBSP_LOGCAT ".Handler.AssertionLookup"), "exportACL", "127.0.0.1 ::1")
88 {
89 pair<bool,const char*> prop = getString("Location");
90 if (!prop.first)
91 throw ConfigurationException("AssertionLookup handler requires Location property.");
92 string address(appId);
93 if (*prop.second != '/')
94 address += '/';
95 address += prop.second;
96 setAddress(address.c_str());
97 }
98
run(SPRequest & request,bool isHandler) const99 pair<bool,long> AssertionLookup::run(SPRequest& request, bool isHandler) const
100 {
101 // Check ACL in base class.
102 pair<bool,long> ret = SecuredHandler::run(request, isHandler);
103 if (ret.first)
104 return ret;
105
106 try {
107 if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) {
108 // When out of process, we run natively and directly process the message.
109 return processMessage(request.getApplication(), request, request);
110 }
111 else {
112 // When not out of process, we remote all the message processing.
113 DDF out,in = wrap(request);
114 DDFJanitor jin(in), jout(out);
115
116 out = send(request, in);
117 return unwrap(request, out);
118 }
119 }
120 catch (std::exception& ex) {
121 m_log.error("error while processing request: %s", ex.what());
122 istringstream msg("Assertion Lookup Failed");
123 return make_pair(true, request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_ERROR));
124 }
125 }
126
receive(DDF & in,ostream & out)127 void AssertionLookup::receive(DDF& in, ostream& out)
128 {
129 // Find application.
130 const char* aid = in["application_id"].string();
131 const Application* app = aid ? SPConfig::getConfig().getServiceProvider()->getApplication(aid) : nullptr;
132 if (!app) {
133 // Something's horribly wrong.
134 m_log.error("couldn't find application (%s) for assertion lookup", aid ? aid : "(missing)");
135 throw ConfigurationException("Unable to locate application for assertion lookup, deleted?");
136 }
137
138 // Unpack the request.
139 scoped_ptr<HTTPRequest> req(getRequest(*app, in));
140 //m_log.debug("found %d client certificates", req->getClientCertificates().size());
141
142 // Wrap a response shim.
143 DDF ret(nullptr);
144 DDFJanitor jout(ret);
145 scoped_ptr<HTTPResponse> resp(getResponse(*app, ret));
146
147 // Since we're remoted, the result should either be a throw, a false/0 return,
148 // which we just return as an empty structure, or a response/redirect,
149 // which we capture in the facade and send back.
150 processMessage(*app, *req, *resp);
151 out << ret;
152 }
153
processMessage(const Application & application,HTTPRequest & httpRequest,HTTPResponse & httpResponse) const154 pair<bool,long> AssertionLookup::processMessage(const Application& application, HTTPRequest& httpRequest, HTTPResponse& httpResponse) const
155 {
156 #ifndef SHIBSP_LITE
157 const char* key = httpRequest.getParameter("key");
158 const char* ID = httpRequest.getParameter("ID");
159 if (!key || !*key || !ID || !*ID) {
160 m_log.error("assertion lookup request failed, missing required parameters");
161 throw FatalProfileException("Missing key or ID parameters.");
162 }
163
164 m_log.debug("processing assertion lookup request (session: %s, assertion: %s)", key, ID);
165
166 SessionCache* cache = application.getServiceProvider().getSessionCache();
167 if (!cache) {
168 m_log.error("session cache does not support extended API");
169 throw FatalProfileException("Session cache does not support assertion lookup.");
170 }
171
172 // The cache will either silently pass a session or nullptr back, or throw an exception out.
173 Session* session = cache->find(application, key);
174 if (!session) {
175 m_log.error("valid session (%s) not found for assertion lookup", key);
176 throw FatalProfileException("Session key not found.");
177 }
178
179 Locker locker(session, false);
180
181 const Assertion* assertion = session->getAssertion(ID);
182 if (!assertion) {
183 m_log.error("assertion (%s) not found in session (%s)", ID, key);
184 throw FatalProfileException("Assertion not found.");
185 }
186
187 stringstream s;
188 s << *assertion;
189 httpResponse.setContentType("application/samlassertion+xml");
190 return make_pair(true, httpResponse.sendResponse(s));
191 #else
192 return make_pair(false, 0L);
193 #endif
194 }
195