VS10 solution files, convert from NULL macro to nullptr.
[shibboleth/sp.git] / shibsp / handler / impl / AssertionLookup.cpp
1 /*
2  *  Copyright 2001-2010 Internet2
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * AssertionLookup.cpp
19  *
20  * Handler for looking up assertions in the SessionCache.
21  */
22
23 #include "internal.h"
24 #include "exceptions.h"
25 #include "Application.h"
26 #include "ServiceProvider.h"
27 #include "SessionCacheEx.h"
28 #include "SPRequest.h"
29 #include "handler/AbstractHandler.h"
30 #include "handler/RemotedHandler.h"
31 #include "util/SPConstants.h"
32
33 #ifndef SHIBSP_LITE
34 # include <saml/exceptions.h>
35 # include <saml/Assertion.h>
36 # include <xmltooling/util/XMLHelper.h>
37 using namespace opensaml;
38 #endif
39
40 using namespace shibspconstants;
41 using namespace shibsp;
42 using namespace xmltooling;
43 using namespace std;
44
45 namespace shibsp {
46
47 #if defined (_MSC_VER)
48     #pragma warning( push )
49     #pragma warning( disable : 4250 )
50 #endif
51
52     class SHIBSP_DLLLOCAL Blocker : public DOMNodeFilter
53     {
54     public:
55 #ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE
56         short
57 #else
58         FilterAction
59 #endif
60         acceptNode(const DOMNode* node) const {
61             return FILTER_REJECT;
62         }
63     };
64
65     static SHIBSP_DLLLOCAL Blocker g_Blocker;
66
67     class SHIBSP_API AssertionLookup : public AbstractHandler, public RemotedHandler
68     {
69     public:
70         AssertionLookup(const DOMElement* e, const char* appId);
71         virtual ~AssertionLookup() {}
72
73         pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
74         void receive(DDF& in, ostream& out);
75
76         const char* getType() const {
77             return "AssertionLookup";
78         }
79
80     private:
81         pair<bool,long> processMessage(const Application& application, HTTPRequest& httpRequest, HTTPResponse& httpResponse) const;
82
83         set<string> m_acl;
84     };
85
86 #if defined (_MSC_VER)
87     #pragma warning( pop )
88 #endif
89
90     Handler* SHIBSP_DLLLOCAL AssertionLookupFactory(const pair<const DOMElement*,const char*>& p)
91     {
92         return new AssertionLookup(p.first, p.second);
93     }
94
95 };
96
97 AssertionLookup::AssertionLookup(const DOMElement* e, const char* appId)
98     : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".AssertionLookup"), &g_Blocker)
99 {
100     setAddress("run::AssertionLookup");
101     if (SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
102         pair<bool,const char*> acl = getString("exportACL");
103         if (!acl.first) {
104             m_acl.insert("127.0.0.1");
105             return;
106         }
107         string aclbuf=acl.second;
108         int j = 0;
109         for (unsigned int i=0;  i < aclbuf.length();  i++) {
110             if (aclbuf.at(i)==' ') {
111                 m_acl.insert(aclbuf.substr(j, i-j));
112                 j = i+1;
113             }
114         }
115         m_acl.insert(aclbuf.substr(j, aclbuf.length()-j));
116     }
117 }
118
119 pair<bool,long> AssertionLookup::run(SPRequest& request, bool isHandler) const
120 {
121     string relayState;
122     SPConfig& conf = SPConfig::getConfig();
123     if (conf.isEnabled(SPConfig::InProcess)) {
124         if (m_acl.count(request.getRemoteAddr()) == 0) {
125             m_log.error("request for assertion lookup blocked from invalid address (%s)", request.getRemoteAddr().c_str());
126             istringstream msg("Assertion Lookup Blocked");
127             return make_pair(true,request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_FORBIDDEN));
128         }
129     }
130
131     try {
132         if (conf.isEnabled(SPConfig::OutOfProcess)) {
133             // When out of process, we run natively and directly process the message.
134             return processMessage(request.getApplication(), request, request);
135         }
136         else {
137             // When not out of process, we remote all the message processing.
138             DDF out,in = wrap(request);
139             DDFJanitor jin(in), jout(out);
140
141             out=request.getServiceProvider().getListenerService()->send(in);
142             return unwrap(request, out);
143         }
144     }
145     catch (exception& ex) {
146         m_log.error("error while processing request: %s", ex.what());
147         istringstream msg("Assertion Lookup Failed");
148         return make_pair(true,request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_ERROR));
149     }
150 }
151
152 void AssertionLookup::receive(DDF& in, ostream& out)
153 {
154     // Find application.
155     const char* aid=in["application_id"].string();
156     const Application* app=aid ? SPConfig::getConfig().getServiceProvider()->getApplication(aid) : nullptr;
157     if (!app) {
158         // Something's horribly wrong.
159         m_log.error("couldn't find application (%s) for assertion lookup", aid ? aid : "(missing)");
160         throw ConfigurationException("Unable to locate application for assertion lookup, deleted?");
161     }
162
163     // Unpack the request.
164     auto_ptr<HTTPRequest> req(getRequest(in));
165     //m_log.debug("found %d client certificates", req->getClientCertificates().size());
166
167     // Wrap a response shim.
168     DDF ret(nullptr);
169     DDFJanitor jout(ret);
170     auto_ptr<HTTPResponse> resp(getResponse(ret));
171
172     // Since we're remoted, the result should either be a throw, a false/0 return,
173     // which we just return as an empty structure, or a response/redirect,
174     // which we capture in the facade and send back.
175     processMessage(*app, *req.get(), *resp.get());
176     out << ret;
177 }
178
179 pair<bool,long> AssertionLookup::processMessage(const Application& application, HTTPRequest& httpRequest, HTTPResponse& httpResponse) const
180 {
181 #ifndef SHIBSP_LITE
182     const char* key = httpRequest.getParameter("key");
183     const char* ID = httpRequest.getParameter("ID");
184     if (!key || !*key || !ID || !*ID) {
185         m_log.error("assertion lookup request failed, missing required parameters");
186         throw FatalProfileException("Missing key or ID parameters.");
187     }
188
189     m_log.debug("processing assertion lookup request (session: %s, assertion: %s)", key, ID);
190
191     SessionCacheEx* cache = dynamic_cast<SessionCacheEx*>(application.getServiceProvider().getSessionCache());
192     if (!cache) {
193         m_log.error("session cache does not support extended API");
194         throw FatalProfileException("Session cache does not support assertion lookup.");
195     }
196
197     // The cache will either silently pass a session or nullptr back, or throw an exception out.
198     Session* session = cache->find(application, key);
199     if (!session) {
200         m_log.error("valid session (%s) not found for assertion lookup", key);
201         throw FatalProfileException("Session key not found.");
202     }
203
204     Locker locker(session, false);
205
206     const Assertion* assertion = session->getAssertion(ID);
207     if (!assertion) {
208         m_log.error("assertion (%s) not found in session (%s)", ID, key);
209         throw FatalProfileException("Assertion not found.");
210     }
211
212     stringstream s;
213     s << *assertion;
214     httpResponse.setContentType("application/samlassertion+xml");
215     return make_pair(true, httpResponse.sendResponse(s));
216 #else
217     return make_pair(false,0L);
218 #endif
219 }