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