2 * Copyright 2001-2007 Internet2
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * Base class for handlers that need SP request/response layer to be remoted.
24 #include "handler/RemotedHandler.h"
27 #include <log4cpp/Category.hh>
28 #include <saml/util/CGIParser.h>
29 #include <xmltooling/unicode.h>
30 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
31 #include <xsec/enc/XSECCryptoException.hpp>
32 #include <xsec/framework/XSECException.hpp>
33 #include <xsec/framework/XSECProvider.hpp>
35 using namespace shibsp;
36 using namespace opensaml;
37 using namespace xmltooling;
38 using namespace log4cpp;
39 using namespace xercesc;
43 class SHIBSP_DLLLOCAL RemotedRequest : public virtual opensaml::HTTPRequest
46 mutable CGIParser* m_parser;
47 mutable vector<XSECCryptoX509*> m_certs;
49 RemotedRequest(DDF& input) : m_input(input), m_parser(NULL) {}
50 virtual ~RemotedRequest() {
51 for_each(m_certs.begin(), m_certs.end(), xmltooling::cleanup<XSECCryptoX509>());
56 const char* getScheme() const {
57 return m_input["scheme"].string();
59 const char* getHostname() const {
60 return m_input["hostname"].string();
63 return m_input["port"].integer();
65 std::string getContentType() const {
66 DDF s = m_input["content_type"];
67 return s.string() ? s.string() : "";
69 long getContentLength() const {
70 return m_input["content_length"].integer();
72 const char* getRequestBody() const {
73 return m_input["body"].string();
76 const char* getParameter(const char* name) const;
77 std::vector<const char*>::size_type getParameters(const char* name, std::vector<const char*>& values) const;
79 std::string getRemoteUser() const {
80 DDF s = m_input["remote_user"];
81 return s.string() ? s.string() : "";
83 std::string getRemoteAddr() const {
84 DDF s = m_input["client_addr"];
85 return s.string() ? s.string() : "";
88 const std::vector<XSECCryptoX509*>& getClientCertificates() const;
91 const char* getMethod() const {
92 return m_input["method"].string();
94 const char* getRequestURI() const {
95 return m_input["uri"].string();
97 const char* getRequestURL() const {
98 return m_input["url"].string();
100 const char* getQueryString() const {
101 return m_input["query"].string();
103 std::string getHeader(const char* name) const {
104 DDF s = m_input["headers"][name];
105 return s.string() ? s.string() : "";
109 class SHIBSP_DLLLOCAL RemotedResponse : public virtual opensaml::HTTPResponse
113 RemotedResponse(DDF& output) : m_output(output) {}
114 virtual ~RemotedResponse() {}
117 long sendResponse(std::istream& inputStream, long status);
120 void setResponseHeader(const char* name, const char* value);
121 long sendRedirect(const char* url);
125 const char* RemotedRequest::getParameter(const char* name) const
128 m_parser=new CGIParser(*this);
130 pair<CGIParser::walker,CGIParser::walker> bounds=m_parser->getParameters(name);
131 return (bounds.first==bounds.second) ? NULL : bounds.first->second;
134 std::vector<const char*>::size_type RemotedRequest::getParameters(const char* name, std::vector<const char*>& values) const
137 m_parser=new CGIParser(*this);
139 pair<CGIParser::walker,CGIParser::walker> bounds=m_parser->getParameters(name);
140 while (bounds.first!=bounds.second) {
141 values.push_back(bounds.first->second);
144 return values.size();
147 const std::vector<XSECCryptoX509*>& RemotedRequest::getClientCertificates() const
149 if (m_certs.empty()) {
150 DDF cert = m_input["certificates"].first();
151 while (cert.isstring()) {
153 auto_ptr<XSECCryptoX509> x509(XSECPlatformUtils::g_cryptoProvider->X509());
154 x509->loadX509Base64Bin(cert.string(), cert.strlen());
155 m_certs.push_back(x509.release());
157 catch(XSECException& e) {
158 auto_ptr_char temp(e.getMsg());
159 Category::getInstance(SHIBSP_LOGCAT".SPRequest").error("XML-Security exception loading client certificate: %s", temp.get());
161 catch(XSECCryptoException& e) {
162 Category::getInstance(SHIBSP_LOGCAT".SPRequest").error("XML-Security exception loading client certificate: %s", e.getMsg());
170 long RemotedResponse::sendResponse(std::istream& in, long status)
176 msg.append(buf,in.gcount());
178 if (!m_output.isstruct())
179 m_output.structure();
180 m_output.addmember("response.data").string(msg.c_str());
181 m_output.addmember("response.status").integer(status);
185 void RemotedResponse::setResponseHeader(const char* name, const char* value)
187 if (!m_output.isstruct())
188 m_output.structure();
189 DDF hdrs = m_output["headers"];
191 hdrs = m_output.addmember("headers").structure();
192 hdrs.addmember(name).string(value);
195 long RemotedResponse::sendRedirect(const char* url)
197 if (!m_output.isstruct())
198 m_output.structure();
199 m_output.addmember("redirect").string(url);
200 return HTTPResponse::SAML_HTTP_STATUS_MOVED;
204 const DDF& RemotedHandler::wrap(const SPRequest& request, DDF& in, const vector<string>& headers, bool certs) const
208 in.addmember("scheme").string(request.getScheme());
209 in.addmember("hostname").string(request.getHostname());
210 in.addmember("port").integer(request.getPort());
211 in.addmember("content_type").string(request.getContentType().c_str());
212 in.addmember("content_length").integer(request.getContentLength());
213 in.addmember("body").string(request.getRequestBody());
214 in.addmember("remote_user").string(request.getRemoteUser().c_str());
215 in.addmember("client_addr").string(request.getRemoteAddr().c_str());
216 in.addmember("method").string(request.getMethod());
217 in.addmember("uri").string(request.getRequestURI());
218 in.addmember("url").string(request.getRequestURL());
219 in.addmember("query").string(request.getQueryString());
222 DDF hin = in.addmember("headers").structure();
223 for (vector<string>::const_iterator h = headers.begin(); h!=headers.end(); ++h) {
224 hdr = request.getHeader(h->c_str());
226 hin.addmember(h->c_str()).string(hdr.c_str());
230 const vector<XSECCryptoX509*>& xvec = request.getClientCertificates();
232 hin = in.addmember("certificates").list();
233 for (vector<XSECCryptoX509*>::const_iterator x = xvec.begin(); x!=xvec.end(); ++x) {
234 DDF x509 = DDF(NULL).string((*x)->getDEREncodingSB().rawCharBuffer());
243 pair<bool,long> RemotedHandler::unwrap(SPRequest& request, DDF& out) const
245 DDF h = out["headers"];
247 while (h.isstring()) {
248 request.setResponseHeader(h.name(), h.string());
253 return make_pair(true, request.sendRedirect(h.string()));
256 istringstream s(h["data"].string());
257 return make_pair(true, static_cast<GenericResponse&>(request).sendResponse(s, h["status"].integer()));
259 return make_pair(false,0);
262 HTTPRequest* RemotedHandler::getRequest(DDF& in) const
264 return new RemotedRequest(in);
267 HTTPResponse* RemotedHandler::getResponse(DDF& out) const
269 return new RemotedResponse(out);