-/*\r
- * Copyright 2001-2007 Internet2\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/* shibauthorizer.cpp - Shibboleth FastCGI Authorizer\r
-\r
- Andre Cruz\r
-*/\r
-\r
-#define SHIBSP_LITE\r
-#include "config_win32.h"\r
-\r
-#define _CRT_NONSTDC_NO_DEPRECATE 1\r
-#define _CRT_SECURE_NO_DEPRECATE 1\r
-#define _SCL_SECURE_NO_WARNINGS 1\r
-\r
-#include <shibsp/AbstractSPRequest.h>\r
-#include <shibsp/SPConfig.h>\r
-#include <shibsp/ServiceProvider.h>\r
-#include <xmltooling/unicode.h>\r
-#include <xmltooling/XMLToolingConfig.h>\r
-#include <xmltooling/util/NDC.h>\r
-#include <xmltooling/util/XMLConstants.h>\r
-#include <xmltooling/util/XMLHelper.h>\r
-#include <xercesc/util/XMLUniDefs.hpp>\r
-\r
-#include <stdexcept>\r
-#include <stdlib.h>\r
-#ifdef HAVE_UNISTD_H\r
-# include <unistd.h>\r
-# include <sys/mman.h>\r
-#endif\r
-#include <fcgio.h>\r
-\r
-using namespace shibsp;\r
-using namespace xmltooling;\r
-using namespace xercesc;\r
-using namespace std;\r
-\r
-static const XMLCh path[] = UNICODE_LITERAL_4(p,a,t,h);\r
-static const XMLCh validate[] = UNICODE_LITERAL_8(v,a,l,i,d,a,t,e);\r
-\r
-typedef enum {\r
- SHIB_RETURN_OK,\r
- SHIB_RETURN_KO,\r
- SHIB_RETURN_DONE\r
-} shib_return_t;\r
-\r
-class ShibTargetFCGIAuth : public AbstractSPRequest\r
-{\r
- FCGX_Request* m_req;\r
- int m_port;\r
- string m_scheme,m_hostname;\r
- multimap<string,string> m_response_headers;\r
-public:\r
- map<string,string> m_request_headers;\r
-\r
- ShibTargetFCGIAuth(FCGX_Request* req, const char* scheme=NULL, const char* hostname=NULL, int port=0)\r
- : AbstractSPRequest(SHIBSP_LOGCAT".FastCGI"), m_req(req) {\r
- const char* server_name_str = hostname;\r
- if (!server_name_str || !*server_name_str)\r
- server_name_str = FCGX_GetParam("SERVER_NAME", req->envp);\r
- m_hostname = server_name_str;\r
-\r
- m_port = port;\r
- if (!m_port) {\r
- char* server_port_str = FCGX_GetParam("SERVER_PORT", req->envp);\r
- m_port = strtol(server_port_str, &server_port_str, 10);\r
- if (*server_port_str) {\r
- cerr << "can't parse SERVER_PORT (" << FCGX_GetParam("SERVER_PORT", req->envp) << ")" << endl;\r
- throw runtime_error("Unable to determine server port.");\r
- }\r
- }\r
-\r
- const char* server_scheme_str = scheme;\r
- if (!server_scheme_str || !*server_scheme_str)\r
- server_scheme_str = (m_port == 443 || m_port == 8443) ? "https" : "http";\r
- m_scheme = server_scheme_str;\r
-\r
- setRequestURI(FCGX_GetParam("REQUEST_URI", m_req->envp));\r
- }\r
-\r
- ~ShibTargetFCGIAuth() { }\r
-\r
- const char* getScheme() const {\r
- return m_scheme.c_str();\r
- }\r
- const char* getHostname() const {\r
- return m_hostname.c_str();\r
- }\r
- int getPort() const {\r
- return m_port;\r
- }\r
- const char* getMethod() const {\r
- return FCGX_GetParam("REQUEST_METHOD", m_req->envp);\r
- }\r
- string getContentType() const {\r
- const char* s = FCGX_GetParam("CONTENT_TYPE", m_req->envp);\r
- return s ? s : "";\r
- }\r
- long getContentLength() const {\r
- const char* s = FCGX_GetParam("CONTENT_LENGTH", m_req->envp);\r
- return s ? atol(s) : 0;\r
- }\r
- string getRemoteAddr() const {\r
- const char* s = FCGX_GetParam("REMOTE_ADDR", m_req->envp);\r
- return s ? s : "";\r
- }\r
- void log(SPLogLevel level, const string& msg) const {\r
- AbstractSPRequest::log(level,msg);\r
- if (level >= SPError)\r
- cerr << "shib: " << msg;\r
- }\r
- void clearHeader(const char* rawname, const char* cginame) {\r
- // no need, since request headers turn into actual environment variables\r
- }\r
- void setHeader(const char* name, const char* value) {\r
- if (value)\r
- m_request_headers[name] = value;\r
- else\r
- m_request_headers.erase(name);\r
- }\r
- virtual string getHeader(const char* name) const {\r
- map<string,string>::const_iterator i = m_request_headers.find(name);\r
- if (i != m_request_headers.end())\r
- return i->second;\r
- else\r
- return "";\r
- }\r
- void setRemoteUser(const char* user) {\r
- if (user)\r
- m_request_headers["REMOTE_USER"] = user;\r
- else\r
- m_request_headers.erase("REMOTE_USER");\r
- }\r
- string getRemoteUser() const {\r
- map<string,string>::const_iterator i = m_request_headers.find("REMOTE_USER");\r
- if (i != m_request_headers.end())\r
- return i->second;\r
- else {\r
- char* remote_user = FCGX_GetParam("REMOTE_USER", m_req->envp);\r
- if (remote_user)\r
- return remote_user;\r
- }\r
- return "";\r
- }\r
- void setResponseHeader(const char* name, const char* value) {\r
- // Set for later.\r
- if (value)\r
- m_response_headers.insert(make_pair(name,value));\r
- else\r
- m_response_headers.erase(name);\r
- }\r
- const char* getQueryString() const {\r
- return FCGX_GetParam("QUERY_STRING", m_req->envp);\r
- }\r
- const char* getRequestBody() const {\r
- throw runtime_error("getRequestBody not implemented by FastCGI authorizer.");\r
- }\r
-\r
- long sendResponse(istream& in, long status) {\r
- string hdr = string("Connection: close\r\n");\r
- for (multimap<string,string>::const_iterator i=m_response_headers.begin(); i!=m_response_headers.end(); ++i)\r
- hdr += i->first + ": " + i->second + "\r\n";\r
-\r
- // We can't return 200 OK here or else the filter is bypassed\r
- // so custom Shib errors will get turned into a generic page.\r
- const char* codestr="Status: 500 Server Error";\r
- switch (status) {\r
- case XMLTOOLING_HTTP_STATUS_UNAUTHORIZED: codestr="Status: 401 Authorization Required"; break;\r
- case XMLTOOLING_HTTP_STATUS_FORBIDDEN: codestr="Status: 403 Forbidden"; break;\r
- case XMLTOOLING_HTTP_STATUS_NOTFOUND: codestr="Status: 404 Not Found"; break;\r
- }\r
- cout << codestr << "\r\n" << hdr << "\r\n";\r
- char buf[1024];\r
- while (in) {\r
- in.read(buf,1024);\r
- cout.write(buf, in.gcount());\r
- }\r
- return SHIB_RETURN_DONE;\r
- }\r
-\r
- long sendRedirect(const char* url) {\r
- string hdr=string("Status: 302 Please Wait\r\nLocation: ") + url + "\r\n"\r
- "Content-Type: text/html\r\n"\r
- "Content-Length: 40\r\n"\r
- "Expires: 01-Jan-1997 12:00:00 GMT\r\n"\r
- "Cache-Control: private,no-store,no-cache\r\n";\r
- for (multimap<string,string>::const_iterator i=m_response_headers.begin(); i!=m_response_headers.end(); ++i)\r
- hdr += i->first + ": " + i->second + "\r\n";\r
- hdr += "\r\n";\r
-\r
- cout << hdr << "<HTML><BODY>Redirecting...</BODY></HTML>";\r
- return SHIB_RETURN_DONE;\r
- }\r
-\r
- long returnDecline() {\r
- return SHIB_RETURN_KO;\r
- }\r
-\r
- long returnOK() {\r
- return SHIB_RETURN_OK;\r
- }\r
-\r
- const vector<string>& getClientCertificates() const {\r
- static vector<string> g_NoCerts;\r
- return g_NoCerts;\r
- }\r
-};\r
-\r
-static void print_ok(const map<string,string>& headers)\r
-{\r
- cout << "Status: 200 OK" << "\r\n";\r
- for (map<string,string>::const_iterator iter = headers.begin(); iter != headers.end(); iter++) {\r
- cout << "Variable-" << iter->first << ": " << iter->second << "\r\n";\r
- }\r
- cout << "\r\n";\r
-}\r
-\r
-static void print_error(const char* msg)\r
-{\r
- cout << "Status: 500 Server Error" << "\r\n\r\n" << msg;\r
-}\r
-\r
-int main(void)\r
-{\r
- SPConfig* g_Config=&SPConfig::getConfig();\r
- g_Config->setFeatures(\r
- SPConfig::Listener |\r
- SPConfig::Caching |\r
- SPConfig::RequestMapping |\r
- SPConfig::InProcess |\r
- SPConfig::Logging |\r
- SPConfig::Handlers\r
- );\r
- if (!g_Config->init()) {\r
- cerr << "failed to initialize Shibboleth libraries" << endl;\r
- exit(1);\r
- }\r
-\r
- try {\r
- if (!g_Config->instantiate(NULL, true))\r
- throw exception("unknown error");\r
- }\r
- catch (exception& ex) {\r
- g_Config->term();\r
- cerr << "exception while initializing Shibboleth configuration: " << ex.what() << endl;\r
- exit(1);\r
- }\r
-\r
- string g_ServerScheme;\r
- string g_ServerName;\r
- int g_ServerPort=0;\r
-\r
- // Load "authoritative" URL fields.\r
- char* var = getenv("SHIBSP_SERVER_NAME");\r
- if (var)\r
- g_ServerName = var;\r
- var = getenv("SHIBSP_SERVER_SCHEME");\r
- if (var)\r
- g_ServerScheme = var;\r
- var = getenv("SHIBSP_SERVER_PORT");\r
- if (var)\r
- g_ServerPort = atoi(var);\r
-\r
- streambuf* cout_streambuf = cout.rdbuf();\r
- streambuf* cerr_streambuf = cerr.rdbuf();\r
-\r
- FCGX_Request request;\r
-\r
- FCGX_Init();\r
- FCGX_InitRequest(&request, 0, 0);\r
-\r
- cout << "Shibboleth initialization complete. Starting request loop." << endl;\r
- while (FCGX_Accept_r(&request) == 0)\r
- {\r
- // Note that the default bufsize (0) will cause the use of iostream\r
- // methods that require positioning (such as peek(), seek(),\r
- // unget() and putback()) to fail (in favour of more efficient IO).\r
- fcgi_streambuf cout_fcgi_streambuf(request.out);\r
- fcgi_streambuf cerr_fcgi_streambuf(request.err);\r
-\r
- cout.rdbuf(&cout_fcgi_streambuf);\r
- cerr.rdbuf(&cerr_fcgi_streambuf);\r
-\r
- try {\r
- xmltooling::NDC ndc("FastCGI shibauthorizer");\r
- ShibTargetFCGIAuth sta(&request, g_ServerScheme.c_str(), g_ServerName.c_str(), g_ServerPort);\r
-\r
- pair<bool,long> res = sta.getServiceProvider().doAuthentication(sta);\r
- if (res.first) {\r
-#ifdef _DEBUG\r
- cerr << "shib: doAuthentication handled the request" << endl;\r
-#endif\r
- switch(res.second) {\r
- case SHIB_RETURN_OK:\r
- print_ok(sta.m_request_headers);\r
- continue;\r
-\r
- case SHIB_RETURN_KO:\r
- print_ok(sta.m_request_headers);\r
- continue;\r
-\r
- case SHIB_RETURN_DONE:\r
- continue;\r
-\r
- default:\r
- cerr << "shib: doAuthentication returned an unexpected result: " << res.second << endl;\r
- print_error("<html><body>FastCGI Shibboleth authorizer returned an unexpected result.</body></html>");\r
- continue;\r
- }\r
- }\r
-\r
- res = sta.getServiceProvider().doExport(sta);\r
- if (res.first) {\r
-#ifdef _DEBUG\r
- cerr << "shib: doExport handled request" << endl;\r
-#endif\r
- switch(res.second) {\r
- case SHIB_RETURN_OK:\r
- print_ok(sta.m_request_headers);\r
- continue;\r
-\r
- case SHIB_RETURN_KO:\r
- print_ok(sta.m_request_headers);\r
- continue;\r
-\r
- case SHIB_RETURN_DONE:\r
- continue;\r
-\r
- default:\r
- cerr << "shib: doExport returned an unexpected result: " << res.second << endl;\r
- print_error("<html><body>FastCGI Shibboleth authorizer returned an unexpected result.</body></html>");\r
- continue;\r
- }\r
- }\r
-\r
- res = sta.getServiceProvider().doAuthorization(sta);\r
- if (res.first) {\r
-#ifdef _DEBUG\r
- cerr << "shib: doAuthorization handled request" << endl;\r
-#endif\r
- switch(res.second) {\r
- case SHIB_RETURN_OK:\r
- print_ok(sta.m_request_headers);\r
- continue;\r
-\r
- case SHIB_RETURN_KO:\r
- print_ok(sta.m_request_headers);\r
- continue;\r
-\r
- case SHIB_RETURN_DONE:\r
- continue;\r
-\r
- default:\r
- cerr << "shib: doAuthorization returned an unexpected result: " << res.second << endl;\r
- print_error("<html><body>FastCGI Shibboleth authorizer returned an unexpected result.</body></html>");\r
- continue;\r
- }\r
- }\r
-\r
- print_ok(sta.m_request_headers);\r
-\r
- }\r
- catch (exception& e) {\r
- cerr << "shib: FastCGI authorizer caught an exception: " << e.what() << endl;\r
- print_error("<html><body>FastCGI Shibboleth authorizer caught an exception, check log for details.</body></html>");\r
- }\r
-\r
- // If the output streambufs had non-zero bufsizes and\r
- // were constructed outside of the accept loop (i.e.\r
- // their destructor won't be called here), they would\r
- // have to be flushed here.\r
- }\r
- cout << "Request loop ended." << endl;\r
-\r
- cout.rdbuf(cout_streambuf);\r
- cerr.rdbuf(cerr_streambuf);\r
-\r
- if (g_Config)\r
- g_Config->term();\r
-\r
- return 0;\r
-}\r
+/**
+ * Licensed to the University Corporation for Advanced Internet
+ * Development, Inc. (UCAID) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * UCAID licenses this file to you 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.
+ */
+
+/* shibauthorizer.cpp - Shibboleth FastCGI Authorizer
+
+ Andre Cruz
+*/
+
+#define SHIBSP_LITE
+#include "config_win32.h"
+
+#define _CRT_NONSTDC_NO_DEPRECATE 1
+#define _CRT_SECURE_NO_DEPRECATE 1
+#define _SCL_SECURE_NO_WARNINGS 1
+
+#include <shibsp/AbstractSPRequest.h>
+#include <shibsp/SPConfig.h>
+#include <shibsp/ServiceProvider.h>
+#include <xmltooling/unicode.h>
+#include <xmltooling/XMLToolingConfig.h>
+#include <xmltooling/util/NDC.h>
+#include <xmltooling/util/XMLConstants.h>
+#include <xmltooling/util/XMLHelper.h>
+#include <xercesc/util/XMLUniDefs.hpp>
+
+#include <stdexcept>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+# include <sys/mman.h>
+#endif
+#include <fcgio.h>
+
+using namespace shibsp;
+using namespace xmltooling;
+using namespace xercesc;
+using namespace std;
+
+static const XMLCh path[] = UNICODE_LITERAL_4(p,a,t,h);
+static const XMLCh validate[] = UNICODE_LITERAL_8(v,a,l,i,d,a,t,e);
+
+typedef enum {
+ SHIB_RETURN_OK,
+ SHIB_RETURN_KO,
+ SHIB_RETURN_DONE
+} shib_return_t;
+
+class ShibTargetFCGIAuth : public AbstractSPRequest
+{
+ FCGX_Request* m_req;
+ int m_port;
+ string m_scheme,m_hostname;
+ multimap<string,string> m_response_headers;
+public:
+ map<string,string> m_request_headers;
+
+ ShibTargetFCGIAuth(FCGX_Request* req, const char* scheme=nullptr, const char* hostname=nullptr, int port=0)
+ : AbstractSPRequest(SHIBSP_LOGCAT ".FastCGI"), m_req(req) {
+ const char* server_name_str = hostname;
+ if (!server_name_str || !*server_name_str)
+ server_name_str = FCGX_GetParam("SERVER_NAME", req->envp);
+ m_hostname = server_name_str;
+
+ m_port = port;
+ if (!m_port) {
+ char* server_port_str = FCGX_GetParam("SERVER_PORT", req->envp);
+ m_port = strtol(server_port_str, &server_port_str, 10);
+ if (*server_port_str) {
+ cerr << "can't parse SERVER_PORT (" << FCGX_GetParam("SERVER_PORT", req->envp) << ")" << endl;
+ throw runtime_error("Unable to determine server port.");
+ }
+ }
+
+ const char* server_scheme_str = scheme;
+ if (!server_scheme_str || !*server_scheme_str)
+ server_scheme_str = (m_port == 443 || m_port == 8443) ? "https" : "http";
+ m_scheme = server_scheme_str;
+
+ setRequestURI(FCGX_GetParam("REQUEST_URI", m_req->envp));
+ }
+
+ ~ShibTargetFCGIAuth() { }
+
+ const char* getScheme() const {
+ return m_scheme.c_str();
+ }
+ const char* getHostname() const {
+ return m_hostname.c_str();
+ }
+ int getPort() const {
+ return m_port;
+ }
+ const char* getMethod() const {
+ return FCGX_GetParam("REQUEST_METHOD", m_req->envp);
+ }
+ string getContentType() const {
+ const char* s = FCGX_GetParam("CONTENT_TYPE", m_req->envp);
+ return s ? s : "";
+ }
+ long getContentLength() const {
+ const char* s = FCGX_GetParam("CONTENT_LENGTH", m_req->envp);
+ return s ? atol(s) : 0;
+ }
+ string getRemoteAddr() const {
+ string ret = AbstractSPRequest::getRemoteAddr();
+ if (!ret.empty())
+ return ret;
+ const char* s = FCGX_GetParam("REMOTE_ADDR", m_req->envp);
+ return s ? s : "";
+ }
+ void log(SPLogLevel level, const string& msg) const {
+ AbstractSPRequest::log(level,msg);
+ if (level >= SPError)
+ cerr << "shib: " << msg;
+ }
+ void clearHeader(const char* rawname, const char* cginame) {
+ // No need, since we use environment variables.
+ }
+ void setHeader(const char* name, const char* value) {
+ if (value)
+ m_request_headers[name] = value;
+ else
+ m_request_headers.erase(name);
+ }
+ string getHeader(const char* name) const {
+ // Look in the local map first.
+ map<string,string>::const_iterator i = m_request_headers.find(name);
+ if (i != m_request_headers.end())
+ return i->second;
+ // Nothing set locally and this isn't a "secure" call, so check the request.
+ string hdr("HTTP_");
+ for (; *name; ++name) {
+ if (*name=='-')
+ hdr += '_';
+ else
+ hdr += toupper(*name);
+ }
+ char* s = FCGX_GetParam(hdr.c_str(), m_req->envp);
+ return s ? s : "";
+ }
+ string getSecureHeader(const char* name) const {
+ // Look in the local map only.
+ map<string,string>::const_iterator i = m_request_headers.find(name);
+ if (i != m_request_headers.end())
+ return i->second;
+ return "";
+ }
+ void setRemoteUser(const char* user) {
+ if (user)
+ m_request_headers["REMOTE_USER"] = user;
+ else
+ m_request_headers.erase("REMOTE_USER");
+ }
+ string getRemoteUser() const {
+ map<string,string>::const_iterator i = m_request_headers.find("REMOTE_USER");
+ if (i != m_request_headers.end())
+ return i->second;
+ else {
+ char* remote_user = FCGX_GetParam("REMOTE_USER", m_req->envp);
+ if (remote_user)
+ return remote_user;
+ }
+ return "";
+ }
+ void setAuthType(const char* authtype) {
+ if (authtype)
+ m_request_headers["AUTH_TYPE"] = authtype;
+ else
+ m_request_headers.erase("AUTH_TYPE");
+ }
+ string getAuthType() const {
+ map<string,string>::const_iterator i = m_request_headers.find("AUTH_TYPE");
+ if (i != m_request_headers.end())
+ return i->second;
+ else {
+ char* auth_type = FCGX_GetParam("AUTH_TYPE", m_req->envp);
+ if (auth_type)
+ return auth_type;
+ }
+ return "";
+ }
+ void setResponseHeader(const char* name, const char* value) {
+ HTTPResponse::setResponseHeader(name, value);
+ if (name) {
+ // Set for later.
+ if (value)
+ m_response_headers.insert(make_pair(name,value));
+ else
+ m_response_headers.erase(name);
+ }
+ }
+ const char* getQueryString() const {
+ return FCGX_GetParam("QUERY_STRING", m_req->envp);
+ }
+ const char* getRequestBody() const {
+ throw runtime_error("getRequestBody not implemented by FastCGI authorizer.");
+ }
+
+ long sendResponse(istream& in, long status) {
+ string hdr = string("Connection: close\r\n");
+ for (multimap<string,string>::const_iterator i=m_response_headers.begin(); i!=m_response_headers.end(); ++i)
+ hdr += i->first + ": " + i->second + "\r\n";
+
+ // We can't return 200 OK here or else the filter is bypassed
+ // so custom Shib errors will get turned into a generic page.
+ const char* codestr="Status: 500 Server Error";
+ switch (status) {
+ case XMLTOOLING_HTTP_STATUS_NOTMODIFIED: codestr="Status: 304 Not Modified"; break;
+ case XMLTOOLING_HTTP_STATUS_UNAUTHORIZED: codestr="Status: 401 Authorization Required"; break;
+ case XMLTOOLING_HTTP_STATUS_FORBIDDEN: codestr="Status: 403 Forbidden"; break;
+ case XMLTOOLING_HTTP_STATUS_NOTFOUND: codestr="Status: 404 Not Found"; break;
+ }
+ cout << codestr << "\r\n" << hdr << "\r\n";
+ char buf[1024];
+ while (in) {
+ in.read(buf,1024);
+ cout.write(buf, in.gcount());
+ }
+ return SHIB_RETURN_DONE;
+ }
+
+ long sendRedirect(const char* url) {
+ HTTPResponse::sendRedirect(url);
+ string hdr=string("Status: 302 Please Wait\r\nLocation: ") + url + "\r\n"
+ "Content-Type: text/html\r\n"
+ "Content-Length: 40\r\n"
+ "Expires: Wed, 01 Jan 1997 12:00:00 GMT\r\n"
+ "Cache-Control: private,no-store,no-cache,max-age=0\r\n";
+ for (multimap<string,string>::const_iterator i=m_response_headers.begin(); i!=m_response_headers.end(); ++i)
+ hdr += i->first + ": " + i->second + "\r\n";
+ hdr += "\r\n";
+
+ cout << hdr << "<HTML><BODY>Redirecting...</BODY></HTML>";
+ return SHIB_RETURN_DONE;
+ }
+
+ long returnDecline() {
+ return SHIB_RETURN_KO;
+ }
+
+ long returnOK() {
+ return SHIB_RETURN_OK;
+ }
+
+ const vector<string>& getClientCertificates() const {
+ static vector<string> g_NoCerts;
+ return g_NoCerts;
+ }
+};
+
+static void print_ok(const map<string,string>& headers)
+{
+ cout << "Status: 200 OK" << "\r\n";
+ for (map<string,string>::const_iterator iter = headers.begin(); iter != headers.end(); iter++) {
+ cout << "Variable-" << iter->first << ": " << iter->second << "\r\n";
+ }
+ cout << "\r\n";
+}
+
+static void print_error(const char* msg)
+{
+ cout << "Status: 500 Server Error" << "\r\n\r\n" << msg;
+}
+
+int main(void)
+{
+ SPConfig* g_Config=&SPConfig::getConfig();
+ g_Config->setFeatures(
+ SPConfig::Listener |
+ SPConfig::Caching |
+ SPConfig::RequestMapping |
+ SPConfig::InProcess |
+ SPConfig::Logging |
+ SPConfig::Handlers
+ );
+ if (!g_Config->init()) {
+ cerr << "failed to initialize Shibboleth libraries" << endl;
+ exit(1);
+ }
+
+ try {
+ if (!g_Config->instantiate(nullptr, true))
+ throw runtime_error("unknown error");
+ }
+ catch (exception& ex) {
+ g_Config->term();
+ cerr << "exception while initializing Shibboleth configuration: " << ex.what() << endl;
+ exit(1);
+ }
+
+ string g_ServerScheme;
+ string g_ServerName;
+ int g_ServerPort=0;
+
+ // Load "authoritative" URL fields.
+ char* var = getenv("SHIBSP_SERVER_NAME");
+ if (var)
+ g_ServerName = var;
+ var = getenv("SHIBSP_SERVER_SCHEME");
+ if (var)
+ g_ServerScheme = var;
+ var = getenv("SHIBSP_SERVER_PORT");
+ if (var)
+ g_ServerPort = atoi(var);
+
+ streambuf* cout_streambuf = cout.rdbuf();
+ streambuf* cerr_streambuf = cerr.rdbuf();
+
+ FCGX_Request request;
+
+ FCGX_Init();
+ FCGX_InitRequest(&request, 0, 0);
+
+ cout << "Shibboleth initialization complete. Starting request loop." << endl;
+ while (FCGX_Accept_r(&request) == 0)
+ {
+ // Note that the default bufsize (0) will cause the use of iostream
+ // methods that require positioning (such as peek(), seek(),
+ // unget() and putback()) to fail (in favour of more efficient IO).
+ fcgi_streambuf cout_fcgi_streambuf(request.out);
+ fcgi_streambuf cerr_fcgi_streambuf(request.err);
+
+ cout.rdbuf(&cout_fcgi_streambuf);
+ cerr.rdbuf(&cerr_fcgi_streambuf);
+
+ try {
+ xmltooling::NDC ndc("FastCGI shibauthorizer");
+ ShibTargetFCGIAuth sta(&request, g_ServerScheme.c_str(), g_ServerName.c_str(), g_ServerPort);
+
+ pair<bool,long> res = sta.getServiceProvider().doAuthentication(sta);
+ if (res.first) {
+ sta.log(SPRequest::SPDebug, "shib: doAuthentication handled the request");
+ switch(res.second) {
+ case SHIB_RETURN_OK:
+ print_ok(sta.m_request_headers);
+ continue;
+
+ case SHIB_RETURN_KO:
+ print_ok(sta.m_request_headers);
+ continue;
+
+ case SHIB_RETURN_DONE:
+ continue;
+
+ default:
+ cerr << "shib: doAuthentication returned an unexpected result: " << res.second << endl;
+ print_error("<html><body>FastCGI Shibboleth authorizer returned an unexpected result.</body></html>");
+ continue;
+ }
+ }
+
+ res = sta.getServiceProvider().doExport(sta);
+ if (res.first) {
+ sta.log(SPRequest::SPDebug, "shib: doExport handled request");
+ switch(res.second) {
+ case SHIB_RETURN_OK:
+ print_ok(sta.m_request_headers);
+ continue;
+
+ case SHIB_RETURN_KO:
+ print_ok(sta.m_request_headers);
+ continue;
+
+ case SHIB_RETURN_DONE:
+ continue;
+
+ default:
+ cerr << "shib: doExport returned an unexpected result: " << res.second << endl;
+ print_error("<html><body>FastCGI Shibboleth authorizer returned an unexpected result.</body></html>");
+ continue;
+ }
+ }
+
+ res = sta.getServiceProvider().doAuthorization(sta);
+ if (res.first) {
+ sta.log(SPRequest::SPDebug, "shib: doAuthorization handled request");
+ switch(res.second) {
+ case SHIB_RETURN_OK:
+ print_ok(sta.m_request_headers);
+ continue;
+
+ case SHIB_RETURN_KO:
+ print_ok(sta.m_request_headers);
+ continue;
+
+ case SHIB_RETURN_DONE:
+ continue;
+
+ default:
+ cerr << "shib: doAuthorization returned an unexpected result: " << res.second << endl;
+ print_error("<html><body>FastCGI Shibboleth authorizer returned an unexpected result.</body></html>");
+ continue;
+ }
+ }
+
+ print_ok(sta.m_request_headers);
+
+ }
+ catch (exception& e) {
+ cerr << "shib: FastCGI authorizer caught an exception: " << e.what() << endl;
+ print_error("<html><body>FastCGI Shibboleth authorizer caught an exception, check log for details.</body></html>");
+ }
+
+ // If the output streambufs had non-zero bufsizes and
+ // were constructed outside of the accept loop (i.e.
+ // their destructor won't be called here), they would
+ // have to be flushed here.
+ }
+ cout << "Request loop ended." << endl;
+
+ cout.rdbuf(cout_streambuf);
+ cerr.rdbuf(cerr_streambuf);
+
+ if (g_Config)
+ g_Config->term();
+
+ return 0;
+}