#include "Application.h"
#include "ServiceProvider.h"
#include "SessionCache.h"
-#include "util/CGIParser.h"
#include <log4cpp/Category.hh>
+#include <saml/util/CGIParser.h>
using namespace shibsp;
+using namespace opensaml;
using namespace xmltooling;
using namespace log4cpp;
using namespace std;
AbstractSPRequest::AbstractSPRequest()
: m_sp(NULL), m_mapper(NULL), m_app(NULL), m_sessionTried(false), m_session(NULL),
- m_log(&Category::getInstance(SHIBSP_LOGCAT)), m_parser(NULL)
+ m_log(&Category::getInstance(SHIBSP_LOGCAT".SPRequest")), m_parser(NULL)
{
m_sp=SPConfig::getConfig().getServiceProvider();
m_sp->lock();
#include <shibsp/exceptions.h>
#include <shibsp/SPRequest.h>
+#include <saml/util/CGIParser.h>
namespace shibsp {
-
- class SHIBSP_API CGIParser;
/**
* Abstract base for SPRequest implementations
void* m_log; // declared void* to avoid log4cpp header conflicts in Apache
mutable std::string m_handlerURL;
mutable std::map<std::string,std::string> m_cookieMap;
- mutable CGIParser* m_parser;
+ mutable opensaml::CGIParser* m_parser;
};
};
reminclude_HEADERS = \
ddf.h \
- ListenerService.h
+ ListenerService.h \
+ RemotedHandler.h
secinclude_HEADERS = \
security/PKIXTrustEngine.h
metadata/MetadataExtSchemaValidators.cpp \
remoting/impl/ddf.cpp \
remoting/impl/ListenerService.cpp \
+ remoting/impl/RemotedHandler.cpp \
remoting/impl/SocketListener.cpp \
remoting/impl/TCPListener.cpp \
remoting/impl/UnixListener.cpp \
--- /dev/null
+/*
+ * Copyright 2001-2007 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file shibsp/remoting/RemotedHandler.h
+ *
+ * Base class for handlers that need SP request/response layer to be remoted.
+ */
+
+#ifndef __shibsp_remhandler_h__
+#define __shibsp_remhandler_h__
+
+#include <shibsp/SPRequest.h>
+#include <shibsp/Handler.h>
+#include <shibsp/remoting/ListenerService.h>
+
+namespace shibsp {
+
+ /**
+ * Base class for handlers that need HTTP request/response layer to be remoted.
+ */
+ class SHIBSP_API RemotedHandler : public Handler, public Remoted
+ {
+ public:
+ virtual ~RemotedHandler() {}
+
+ protected:
+ RemotedHandler(const xercesc::DOMElement* e=NULL) {}
+
+ /**
+ * Wraps a request by annotating an outgoing data flow with the data needed
+ * to remote the request information.
+ *
+ * @param request an SPRequest to remote
+ * @param in the dataflow object to annotate
+ * @param headers array of request headers to copy to remote request
+ * @param certs true iff client certificates should be available for the remote request
+ * @return the input dataflow object
+ */
+ const DDF& wrap(const SPRequest& request, DDF& in, const std::vector<std::string>& headers, bool certs=false) const;
+
+ /**
+ * Unwraps a response by examining an incoming data flow to determine
+ * whether a response was produced by the remoted handler.
+ *
+ * @param request SP request context
+ * @param out the dataflow object to unpack
+ * @return a pair containing a "request completed" indicator and a server-specific response code
+ */
+ virtual std::pair<bool,long> unwrap(SPRequest& request, DDF& out) const;
+
+ /**
+ * Builds a new request instance around a remoted data object.
+ *
+ * @param in the dataflow object containing the remoted request
+ * @return a call-specific request object based on the input, to be freed by the caller
+ */
+ opensaml::HTTPRequest* getRequest(DDF& in) const;
+
+ /**
+ * Builds a new response instance around an outgoing data object.
+ *
+ * @param out the dataflow object to be returned by the caller
+ * @return a call-specific response object, to be freed by the caller
+ */
+ opensaml::HTTPResponse* getResponse(DDF& out) const;
+ };
+};
+
+#endif /* __shibsp_remhandler_h__ */
--- /dev/null
+/*
+ * Copyright 2001-2007 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * RemotedHandler.cpp
+ *
+ * Base class for handlers that need SP request/response layer to be remoted.
+ */
+
+#include "internal.h"
+#include "remoting/RemotedHandler.h"
+
+#include <algorithm>
+#include <log4cpp/Category.hh>
+#include <saml/util/CGIParser.h>
+#include <xmltooling/unicode.h>
+#include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
+#include <xsec/enc/XSECCryptoException.hpp>
+#include <xsec/framework/XSECException.hpp>
+#include <xsec/framework/XSECProvider.hpp>
+
+using namespace shibsp;
+using namespace opensaml;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace xercesc;
+using namespace std;
+
+namespace shibsp {
+ class SHIBSP_DLLLOCAL RemotedRequest : public virtual opensaml::HTTPRequest
+ {
+ DDF& m_input;
+ mutable CGIParser* m_parser;
+ mutable vector<XSECCryptoX509*> m_certs;
+ public:
+ RemotedRequest(DDF& input) : m_input(input), m_parser(NULL) {}
+ virtual ~RemotedRequest() {
+ for_each(m_certs.begin(), m_certs.end(), xmltooling::cleanup<XSECCryptoX509>());
+ delete m_parser;
+ }
+
+ // GenericRequest
+ const char* getScheme() const {
+ return m_input["scheme"].string();
+ }
+ const char* getHostname() const {
+ return m_input["hostname"].string();
+ }
+ int getPort() const {
+ return m_input["port"].integer();
+ }
+ std::string getContentType() const {
+ DDF s = m_input["content_type"];
+ return s.string() ? s.string() : "";
+ }
+ long getContentLength() const {
+ return m_input["content_length"].integer();
+ }
+ const char* getRequestBody() const {
+ return m_input["body"].string();
+ }
+
+ const char* getParameter(const char* name) const;
+ std::vector<const char*>::size_type getParameters(const char* name, std::vector<const char*>& values) const;
+
+ std::string getRemoteUser() const {
+ DDF s = m_input["remote_user"];
+ return s.string() ? s.string() : "";
+ }
+ std::string getRemoteAddr() const {
+ DDF s = m_input["client_addr"];
+ return s.string() ? s.string() : "";
+ }
+
+ const std::vector<XSECCryptoX509*>& getClientCertificates() const;
+
+ // HTTPRequest
+ const char* getMethod() const {
+ return m_input["method"].string();
+ }
+ const char* getRequestURI() const {
+ return m_input["uri"].string();
+ }
+ const char* getRequestURL() const {
+ return m_input["url"].string();
+ }
+ const char* getQueryString() const {
+ return m_input["query"].string();
+ }
+ std::string getHeader(const char* name) const {
+ DDF s = m_input["headers"][name];
+ return s.string() ? s.string() : "";
+ }
+ };
+
+ class SHIBSP_DLLLOCAL RemotedResponse : public virtual opensaml::HTTPResponse
+ {
+ DDF& m_output;
+ public:
+ RemotedResponse(DDF& output) : m_output(output) {}
+ virtual ~RemotedResponse() {}
+
+ // GenericResponse
+ long sendResponse(std::istream& inputStream, long status);
+
+ // HTTPResponse
+ void setResponseHeader(const char* name, const char* value);
+ long sendRedirect(const char* url);
+ };
+}
+
+const char* RemotedRequest::getParameter(const char* name) const
+{
+ if (!m_parser)
+ m_parser=new CGIParser(*this);
+
+ pair<CGIParser::walker,CGIParser::walker> bounds=m_parser->getParameters(name);
+ return (bounds.first==bounds.second) ? NULL : bounds.first->second;
+}
+
+std::vector<const char*>::size_type RemotedRequest::getParameters(const char* name, std::vector<const char*>& values) const
+{
+ if (!m_parser)
+ m_parser=new CGIParser(*this);
+
+ pair<CGIParser::walker,CGIParser::walker> bounds=m_parser->getParameters(name);
+ while (bounds.first!=bounds.second) {
+ values.push_back(bounds.first->second);
+ ++bounds.first;
+ }
+ return values.size();
+}
+
+const std::vector<XSECCryptoX509*>& RemotedRequest::getClientCertificates() const
+{
+ if (m_certs.empty()) {
+ DDF cert = m_input["certificates"].first();
+ while (cert.isstring()) {
+ try {
+ auto_ptr<XSECCryptoX509> x509(XSECPlatformUtils::g_cryptoProvider->X509());
+ x509->loadX509Base64Bin(cert.string(), cert.strlen());
+ m_certs.push_back(x509.release());
+ }
+ catch(XSECException& e) {
+ auto_ptr_char temp(e.getMsg());
+ Category::getInstance(SHIBSP_LOGCAT".SPRequest").error("XML-Security exception loading client certificate: %s", temp.get());
+ }
+ catch(XSECCryptoException& e) {
+ Category::getInstance(SHIBSP_LOGCAT".SPRequest").error("XML-Security exception loading client certificate: %s", e.getMsg());
+ }
+ cert = cert.next();
+ }
+ }
+ return m_certs;
+}
+
+long RemotedResponse::sendResponse(std::istream& in, long status)
+{
+ string msg;
+ char buf[1024];
+ while (in) {
+ in.read(buf,1024);
+ msg.append(buf,in.gcount());
+ }
+ if (!m_output.isstruct())
+ m_output.structure();
+ m_output.addmember("response.data").string(msg.c_str());
+ m_output.addmember("response.status").integer(status);
+ return status;
+}
+
+void RemotedResponse::setResponseHeader(const char* name, const char* value)
+{
+ if (!m_output.isstruct())
+ m_output.structure();
+ DDF hdrs = m_output["headers"];
+ if (hdrs.isnull())
+ hdrs = m_output.addmember("headers").structure();
+ hdrs.addmember(name).string(value);
+}
+
+long RemotedResponse::sendRedirect(const char* url)
+{
+ if (!m_output.isstruct())
+ m_output.structure();
+ m_output.addmember("redirect").string(url);
+ return HTTPResponse::SAML_HTTP_STATUS_MOVED;
+}
+
+
+const DDF& RemotedHandler::wrap(const SPRequest& request, DDF& in, const vector<string>& headers, bool certs) const
+{
+ if (!in.isstruct())
+ in.structure();
+ in.addmember("scheme").string(request.getScheme());
+ in.addmember("hostname").string(request.getHostname());
+ in.addmember("port").integer(request.getPort());
+ in.addmember("content_type").string(request.getContentType().c_str());
+ in.addmember("content_length").integer(request.getContentLength());
+ in.addmember("body").string(request.getRequestBody());
+ in.addmember("remote_user").string(request.getRemoteUser().c_str());
+ in.addmember("client_addr").string(request.getRemoteAddr().c_str());
+ in.addmember("method").string(request.getMethod());
+ in.addmember("uri").string(request.getRequestURI());
+ in.addmember("url").string(request.getRequestURL());
+ in.addmember("query").string(request.getQueryString());
+
+ string hdr;
+ DDF hin = in.addmember("headers").structure();
+ for (vector<string>::const_iterator h = headers.begin(); h!=headers.end(); ++h) {
+ hdr = request.getHeader(h->c_str());
+ if (!hdr.empty())
+ hin.addmember(h->c_str()).string(hdr.c_str());
+ }
+
+ if (certs) {
+ const vector<XSECCryptoX509*>& xvec = request.getClientCertificates();
+ if (!xvec.empty()) {
+ hin = in.addmember("certificates").list();
+ for (vector<XSECCryptoX509*>::const_iterator x = xvec.begin(); x!=xvec.end(); ++x) {
+ DDF x509 = DDF(NULL).string((*x)->getDEREncodingSB().rawCharBuffer());
+ hin.add(x509);
+ }
+ }
+ }
+
+ return in;
+}
+
+pair<bool,long> RemotedHandler::unwrap(SPRequest& request, DDF& out) const
+{
+ DDF h = out["headers"];
+ h = h.first();
+ while (h.isstring()) {
+ request.setResponseHeader(h.name(), h.string());
+ h = h.next();
+ }
+ h = out["redirect"];
+ if (h.isstring())
+ return make_pair(true, request.sendRedirect(h.string()));
+ h = out["response"];
+ if (h.isstruct()) {
+ istringstream s(h["data"].string());
+ return make_pair(true, static_cast<GenericResponse&>(request).sendResponse(s, h["status"].integer()));
+ }
+ return make_pair(false,0);
+}
+
+HTTPRequest* RemotedHandler::getRequest(DDF& in) const
+{
+ return new RemotedRequest(in);
+}
+
+HTTPResponse* RemotedHandler::getResponse(DDF& out) const
+{
+ return new RemotedResponse(out);
+}
Name="util"\r
>\r
<File\r
- RelativePath=".\util\CGIParser.cpp"\r
- >\r
- </File>\r
- <File\r
RelativePath=".\util\DOMPropertySet.cpp"\r
>\r
</File>\r
>\r
</File>\r
<File\r
+ RelativePath=".\remoting\impl\RemotedHandler.cpp"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\remoting\impl\SocketListener.cpp"\r
>\r
</File>\r
Name="util"\r
>\r
<File\r
- RelativePath=".\util\CGIParser.h"\r
- >\r
- </File>\r
- <File\r
RelativePath=".\util\DOMPropertySet.h"\r
>\r
</File>\r
RelativePath=".\remoting\ListenerService.h"\r
>\r
</File>\r
+ <File\r
+ RelativePath=".\remoting\RemotedHandler.h"\r
+ >\r
+ </File>\r
</Filter>\r
<Filter\r
Name="attribute"\r
+++ /dev/null
-/*
- * Copyright 2001-2007 Internet2
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * CGIParser.cpp
- *
- * CGI GET/POST parameter parsing
- */
-
-#include "internal.h"
-#include "util/CGIParser.h"
-
-#include <saml/SAMLConfig.h>
-#include <saml/binding/URLEncoder.h>
-
-using namespace shibsp;
-using namespace opensaml;
-using namespace std;
-
-
-CGIParser::CGIParser(const SPRequest& request)
-{
- const char* pch=NULL;
- if (!strcmp(request.getMethod(),"POST"))
- pch=request.getRequestBody();
- else
- pch=request.getQueryString();
- size_t cl=pch ? strlen(pch) : 0;
-
-
- while (cl && pch) {
- char *name;
- char *value;
- value=fmakeword('&',&cl,&pch);
- plustospace(value);
- SAMLConfig::getConfig().getURLEncoder()->decode(value);
- name=makeword(value,'=');
- kvp_map.insert(pair<string,char*>(name,value));
- free(name);
- }
-}
-
-CGIParser::~CGIParser()
-{
- for (multimap<string,char*>::iterator i=kvp_map.begin(); i!=kvp_map.end(); i++)
- free(i->second);
-}
-
-pair<CGIParser::walker,CGIParser::walker> CGIParser::getParameters(const char* name) const
-{
- return kvp_map.equal_range(name);
-}
-
-/* Parsing routines modified from NCSA source. */
-char* CGIParser::makeword(char *line, char stop)
-{
- int x = 0,y;
- char *word = (char *) malloc(sizeof(char) * (strlen(line) + 1));
-
- for(x=0;((line[x]) && (line[x] != stop));x++)
- word[x] = line[x];
-
- word[x] = '\0';
- if(line[x])
- ++x;
- y=0;
-
- while(line[x])
- line[y++] = line[x++];
- line[y] = '\0';
- return word;
-}
-
-char* CGIParser::fmakeword(char stop, size_t *cl, const char** ppch)
-{
- int wsize;
- char *word;
- int ll;
-
- wsize = 1024;
- ll=0;
- word = (char *) malloc(sizeof(char) * (wsize + 1));
-
- while(1)
- {
- word[ll] = *((*ppch)++);
- if(ll==wsize-1)
- {
- word[ll+1] = '\0';
- wsize+=1024;
- word = (char *)realloc(word,sizeof(char)*(wsize+1));
- }
- --(*cl);
- if((word[ll] == stop) || word[ll] == EOF || (!(*cl)))
- {
- if(word[ll] != stop)
- ll++;
- word[ll] = '\0';
- return word;
- }
- ++ll;
- }
-}
-
-void CGIParser::plustospace(char *str)
-{
- register int x;
-
- for(x=0;str[x];x++)
- if(str[x] == '+') str[x] = ' ';
-}
+++ /dev/null
-/*
- * Copyright 2001-2007 Internet2
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * @file shibsp/util/CGIParser.h
- *
- * CGI GET/POST parameter parsing
- */
-
-#ifndef __shibsp_cgi_h__
-#define __shibsp_cgi_h__
-
-#include <shibsp/SPRequest.h>
-
-namespace shibsp {
-
- /**
- * CGI GET/POST parameter parsing
- */
- class SHIBSP_API CGIParser
- {
- MAKE_NONCOPYABLE(CGIParser);
- public:
- /**
- * Constructor
- *
- * @param request SP request
- */
- CGIParser(const SPRequest& request);
-
- ~CGIParser();
-
- typedef std::multimap<std::string,char*>::const_iterator walker;
-
- /**
- * Returns a pair of bounded iterators around the values of a parameter.
- *
- * @param name name of parameter
- * @return a pair of multimap iterators surrounding the matching value(s)
- */
- std::pair<walker,walker> getParameters(const char* name) const;
-
- private:
- char* fmakeword(char stop, unsigned int *cl, const char** ppch);
- char* makeword(char *line, char stop);
- void plustospace(char *str);
-
- std::multimap<std::string,char*> kvp_map;
- };
-};
-
-#endif /* __shibsp_cgi_h__ */