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