2 * mod_apache.cpp -- the core Apache Module code
4 * Created by: Derek Atkins <derek@ihtfp.com>
10 #undef _XOPEN_SOURCE // causes gethostname conflict in unistd.h
14 #include <saml/saml.h>
15 #include <shib/shib.h>
16 #include <shib/shib-threads.h>
17 #include <shib-target/shib-target.h>
18 #include <xercesc/util/regx/RegularExpression.hpp>
22 // Apache specific header files
24 #include <http_config.h>
25 #include <http_protocol.h>
26 #include <http_main.h>
28 #include <http_core.h>
31 #ifndef SHIB_APACHE_13
32 #include <http_request.h>
33 #include <apr_strings.h>
34 #include <apr_pools.h>
41 #include <unistd.h> // for getpid()
46 using namespace shibboleth;
47 using namespace shibtarget;
49 extern "C" module MODULE_VAR_EXPORT mod_shib;
51 int shib_handler(request_rec* r, const IApplication* application, SHIRE& shire);
55 char* g_szSHIBConfig = NULL;
56 char* g_szSchemaDir = NULL;
57 ShibTargetConfig* g_Config = NULL;
58 static const char* g_UserDataKey = "_shib_check_user_";
61 /********************************************************************************/
62 // Basic Apache Configuration code.
65 // per-server module configuration structure
66 struct shib_server_config
71 // creates the per-server configuration
72 extern "C" void* create_shib_server_config(SH_AP_POOL* p, server_rec* s)
74 shib_server_config* sc=(shib_server_config*)ap_pcalloc(p,sizeof(shib_server_config));
79 // overrides server configuration in virtual servers
80 extern "C" void* merge_shib_server_config (SH_AP_POOL* p, void* base, void* sub)
82 shib_server_config* sc=(shib_server_config*)ap_pcalloc(p,sizeof(shib_server_config));
83 shib_server_config* parent=(shib_server_config*)base;
84 shib_server_config* child=(shib_server_config*)sub;
87 sc->szScheme=ap_pstrdup(p,child->szScheme);
88 else if (parent->szScheme)
89 sc->szScheme=ap_pstrdup(p,parent->szScheme);
96 // per-dir module configuration structure
97 struct shib_dir_config
100 char* szAuthGrpFile; // Auth GroupFile name
101 int bRequireAll; // all require directives must match, otherwise OR logic
103 // Content Configuration
104 int bBasicHijack; // activate for AuthType Basic?
105 int bRequireSession; // require a session?
106 int bExportAssertion; // export SAML assertion to the environment?
109 // creates per-directory config structure
110 extern "C" void* create_shib_dir_config (SH_AP_POOL* p, char* d)
112 shib_dir_config* dc=(shib_dir_config*)ap_pcalloc(p,sizeof(shib_dir_config));
113 dc->bBasicHijack = -1;
114 dc->bRequireSession = -1;
115 dc->bExportAssertion = -1;
116 dc->bRequireAll = -1;
117 dc->szAuthGrpFile = NULL;
121 // overrides server configuration in directories
122 extern "C" void* merge_shib_dir_config (SH_AP_POOL* p, void* base, void* sub)
124 shib_dir_config* dc=(shib_dir_config*)ap_pcalloc(p,sizeof(shib_dir_config));
125 shib_dir_config* parent=(shib_dir_config*)base;
126 shib_dir_config* child=(shib_dir_config*)sub;
128 if (child->szAuthGrpFile)
129 dc->szAuthGrpFile=ap_pstrdup(p,child->szAuthGrpFile);
130 else if (parent->szAuthGrpFile)
131 dc->szAuthGrpFile=ap_pstrdup(p,parent->szAuthGrpFile);
133 dc->szAuthGrpFile=NULL;
135 dc->bBasicHijack=((child->bBasicHijack==-1) ? parent->bBasicHijack : child->bBasicHijack);
136 dc->bRequireSession=((child->bRequireSession==-1) ? parent->bRequireSession : child->bRequireSession);
137 dc->bExportAssertion=((child->bExportAssertion==-1) ? parent->bExportAssertion : child->bExportAssertion);
138 dc->bRequireAll=((child->bRequireAll==-1) ? parent->bRequireAll : child->bRequireAll);
142 // generic global slot handlers
143 extern "C" const char* ap_set_global_string_slot(cmd_parms* parms, void*, const char* arg)
145 *((char**)(parms->info))=ap_pstrdup(parms->pool,arg);
149 extern "C" const char* shib_set_server_string_slot(cmd_parms* parms, void*, const char* arg)
151 char* base=(char*)ap_get_module_config(parms->server->module_config,&mod_shib);
152 int offset=(int)parms->info;
153 *((char**)(base + offset))=ap_pstrdup(parms->pool,arg);
157 extern "C" const char* shib_ap_set_file_slot(cmd_parms* parms,
158 #ifdef SHIB_APACHE_13
159 char* arg1, char* arg2
161 void* arg1, const char* arg2
165 ap_set_file_slot(parms, arg1, arg2);
169 /********************************************************************************/
170 // Apache ShibTarget subclass(es) here.
172 class ShibTargetApache : public ShibTarget
175 ShibTargetApache(request_rec* req) {
176 m_sc = (shib_server_config*)
177 ap_get_module_config(req->server->module_config, &mod_shib);
179 m_dc = (shib_dir_config*)ap_get_module_config(req->per_dir_config, &mod_shib);
182 m_sc->szScheme ? m_sc->szScheme : ap_http_method(req),
183 ap_get_server_name(req),
184 (int)ap_get_server_port(req),
186 ap_table_get(req->headers_in, "Content-type"),
187 req->connection->remote_ip,
193 ~ShibTargetApache() { }
195 virtual void log(ShibLogLevel level, const string &msg) {
196 ap_log_rerror(APLOG_MARK,
197 (level == LogLevelDebug ? APLOG_DEBUG :
198 (level == LogLevelInfo ? APLOG_INFO :
199 (level == LogLevelWarn ? APLOG_WARNING :
200 APLOG_ERR)))|APLOG_NOERRNO, SH_AP_R(m_req),
203 virtual string getCookies(void) const {
204 const char *c = ap_table_get(m_req->headers_in, "Cookie");
205 return string(c ? c : "");
207 virtual void setCookie(const string &name, const string &value) {
208 char* val = ap_psprintf(m_req->pool, "%s=%s", name.c_str(), value.c_str());
209 ap_table_addn(m_req->err_headers_out, "Set-Cookie", val);
211 virtual string getArgs(void) { return string(m_req->args ? m_req->args : ""); }
212 virtual string getPostData(void) {
213 // Read the posted data
214 if (ap_setup_client_block(m_req, REQUEST_CHUNKED_ERROR))
215 throw FatalProfileException("Apache function (setup_client_block) failed while reading profile submission.");
216 if (!ap_should_client_block(m_req))
217 throw FatalProfileException("Apache function (should_client_block) failed while reading profile submission.");
218 if (m_req->remaining > 1024*1024)
219 throw FatalProfileException("Blocked too-large a submission to profile endpoint.");
221 char buff[HUGE_STRING_LEN];
222 ap_hard_timeout("[mod_shib] getPostData", m_req);
223 memset(buff, 0, sizeof(buff));
224 while (ap_get_client_block(m_req, buff, sizeof(buff)-1) > 0) {
225 ap_reset_timeout(m_req);
227 memset(buff, 0, sizeof(buff));
229 ap_kill_timeout(m_req);
233 virtual void clearHeader(const string &name) {
234 ap_table_unset(m_req->headers_in, name.c_str());
236 virtual void setHeader(const string &name, const string &value) {
237 ap_table_set(m_req->headers_in, name.c_str(), value.c_str());
239 virtual string getHeader(const string &name) {
240 const char *hdr = ap_table_get(m_req->headers_in, name.c_str());
241 return string(hdr ? hdr : "");
243 virtual void setRemoteUser(const string &user) {
244 SH_AP_USER(m_req) = ap_pstrdup(m_req->pool, user.c_str());
246 virtual string getRemoteUser(void) {
247 return string(SH_AP_USER(m_req) ? SH_AP_USER(m_req) : "");
249 // override so we can look at the actual auth type and maybe override it.
250 virtual string getAuthType(void) {
251 const char *auth_type=ap_auth_type(m_req);
254 if (strcasecmp(auth_type, "shibboleth")) {
255 if (!strcasecmp(auth_type, "basic") && m_dc->bBasicHijack == 1) {
256 core_dir_config* conf= (core_dir_config*)ap_get_module_config(m_req->per_dir_config,
257 ap_find_linked_module("http_core.c"));
258 auth_type = conf->ap_auth_type = "shibboleth";
261 return string(auth_type);
264 virtual void* sendPage(
267 const string& content_type="text/html",
268 const Iterator<header_t>& headers=EMPTY(header_t)
270 m_req->content_type = ap_psprintf(m_req->pool, content_type.c_str());
271 while (headers.hasNext()) {
272 const header_t& h=headers.next();
273 ap_table_set(m_req->headers_out, h.first.c_str(), h.second.c_str());
275 ap_send_http_header(m_req);
276 ap_rprintf(m_req, msg.c_str());
277 return (void*)((code==200) ? DONE : code);
279 virtual void* sendRedirect(const string& url) {
280 ap_table_set(m_req->headers_out, "Location", url.c_str());
281 return (void*)REDIRECT;
283 virtual void* returnDecline(void) { return (void*)DECLINED; }
284 virtual void* returnOK(void) { return (void*)OK; }
287 shib_dir_config* m_dc;
288 shib_server_config* m_sc;
291 /********************************************************************************/
294 extern "C" int shib_check_user(request_rec* r)
296 ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r), "shib_check_user(%d): ENTER\n", (int)getpid());
298 ostringstream threadid;
299 threadid << "[" << getpid() << "] shib_check_user" << '\0';
300 saml::NDC ndc(threadid.str().c_str());
305 ShibTargetApache sta(r);
307 // Check user authentication, the set the handler bypass
308 pair<bool,void*> res = sta.doCheckAuthN(true);
309 apr_pool_userdata_setn((const void*)42,g_UserDataKey,NULL,r->pool);
310 if (res.first) return (int)res.second;
312 // user auth was okay -- export the assertions now
313 res = sta.doExportAssertions();
314 if (res.first) return (int)res.second;
316 // export happened successfully.. this user is ok.
321 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r), "shib_check_user threw an uncaught exception!");
327 extern "C" int shib_handler(request_rec* r)
329 ostringstream threadid;
330 threadid << "[" << getpid() << "] shib_handler" << '\0';
331 saml::NDC ndc(threadid.str().c_str());
333 #ifndef SHIB_APACHE_13
334 // With 2.x, this handler always runs, though last.
335 // We check if shib_check_user ran, because it will detect a handler request
336 // and dispatch it directly.
338 apr_pool_userdata_get(&data,g_UserDataKey,r->pool);
339 if (data==(const void*)42) {
340 ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),"shib_handler skipped since check_user ran");
345 ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),"shib_handler(%d): ENTER", (int)getpid());
350 ShibTargetApache sta(r);
352 pair<bool,void*> res = sta.doHandler();
353 if (res.first) return (int)res.second;
355 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r), "doHandler() did not do anything.");
360 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r), "shib_handler threw an uncaught exception!");
367 * shib_auth_checker() -- a simple resource manager to
368 * process the .htaccess settings
370 extern "C" int shib_auth_checker(request_rec* r)
372 ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r), "shib_auth_checker(%d): ENTER", (int)getpid());
374 ostringstream threadid;
375 threadid << "[" << getpid() << "] shib_auth_checker" << '\0';
376 saml::NDC ndc(threadid.str().c_str());
381 ShibTargetApache sta(r);
383 pair<bool,void*> res = sta.doCheckAuthZ();
384 if (res.first) return (int)res.second;
391 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r), "shib_auth_checker threw an uncaught exception!");
397 // Access control plugin that enforces htaccess rules
398 class htAccessControl : virtual public IAccessControl
402 ~htAccessControl() {}
407 const char* providerId,
408 const saml::SAMLAuthenticationStatement* authn,
409 const saml::SAMLResponse* attrs
413 IPlugIn* htAccessFactory(const DOMElement* e)
415 return new htAccessControl();
418 class ApacheRequestMapper : public virtual IRequestMapper, public virtual IPropertySet
421 struct ApacheRequestMapperSettings {
422 ApacheRequestMapperSettings(ShibTargetApache* sta, const IPropertySet* p) : m_sta(sta), m_props(p) {}
423 ShibTargetApache* m_sta;
424 const IPropertySet* m_props;
427 ApacheRequestMapper(const DOMElement* e);
428 ~ApacheRequestMapper() { delete m_mapper; delete m_htaccess; delete m_key; }
429 void lock() { m_mapper->lock(); }
430 void unlock() { delete (ApacheRequestMapperSettings*)(m_key->getData()); m_key->setData(NULL); m_mapper->unlock(); }
431 Settings getSettings(ShibTarget* st) const;
433 pair<bool,bool> getBool(const char* name, const char* ns=NULL) const;
434 pair<bool,const char*> getString(const char* name, const char* ns=NULL) const;
435 pair<bool,const XMLCh*> getXMLString(const char* name, const char* ns=NULL) const;
436 pair<bool,unsigned int> getUnsignedInt(const char* name, const char* ns=NULL) const;
437 pair<bool,int> getInt(const char* name, const char* ns=NULL) const;
438 const IPropertySet* getPropertySet(const char* name, const char* ns="urn:mace:shibboleth:target:config:1.0") const;
439 const DOMElement* getElement() const;
442 IRequestMapper* m_mapper;
444 IAccessControl* m_htaccess;
447 IPlugIn* ApacheRequestMapFactory(const DOMElement* e)
449 return new ApacheRequestMapper(e);
452 ApacheRequestMapper::ApacheRequestMapper(const DOMElement* e) : m_mapper(NULL), m_htaccess(NULL), m_key(NULL)
454 IPlugIn* p=SAMLConfig::getConfig().getPlugMgr().newPlugin(
455 "edu.internet2.middleware.shibboleth.sp.provider.XMLRequestMapProvider", e
457 m_mapper=dynamic_cast<IRequestMapper*>(p);
460 throw UnsupportedExtensionException("Embedded request mapper plugin was not of correct type.");
462 m_htaccess=new htAccessControl();
463 m_key=ThreadKey::create(NULL);
466 IRequestMapper::Settings ApacheRequestMapper::getSettings(ShibTarget* st) const
468 Settings s=m_mapper->getSettings(st);
469 m_key->setData(new ApacheRequestMapperSettings(dynamic_cast<ShibTargetApache*>(st),s.first));
470 return pair<const IPropertySet*,IAccessControl*>(this,s.second ? s.second : m_htaccess);
473 pair<bool,bool> ApacheRequestMapper::getBool(const char* name, const char* ns) const
475 ApacheRequestMapperSettings* arms=(ApacheRequestMapperSettings*)m_key->getData();
478 // Override Apache-settable boolean properties.
479 if (name && !strcmp(name,"requireSession") && arms->m_sta->m_dc->bRequireSession==1)
480 return make_pair(true,true);
481 else if (name && !strcmp(name,"exportAssertion") && arms->m_sta->m_dc->bExportAssertion==1)
482 return make_pair(true,true);
484 return arms->m_props->getBool(name,ns);
486 return make_pair(false,false);
489 pair<bool,const char*> ApacheRequestMapper::getString(const char* name, const char* ns) const
491 ApacheRequestMapperSettings* arms=(ApacheRequestMapperSettings*)m_key->getData();
492 return arms ? arms->m_props->getString(name,ns) : pair<bool,const char*>(false,NULL);
495 pair<bool,const XMLCh*> ApacheRequestMapper::getXMLString(const char* name, const char* ns) const
497 ApacheRequestMapperSettings* arms=(ApacheRequestMapperSettings*)m_key->getData();
498 return arms ? arms->m_props->getXMLString(name,ns) : pair<bool,const XMLCh*>(false,NULL);
501 pair<bool,unsigned int> ApacheRequestMapper::getUnsignedInt(const char* name, const char* ns) const
503 ApacheRequestMapperSettings* arms=(ApacheRequestMapperSettings*)m_key->getData();
504 return arms ? arms->m_props->getUnsignedInt(name,ns) : make_pair(false,0);
507 pair<bool,int> ApacheRequestMapper::getInt(const char* name, const char* ns) const
509 ApacheRequestMapperSettings* arms=(ApacheRequestMapperSettings*)m_key->getData();
510 return arms ? arms->m_props->getInt(name,ns) : make_pair(false,0);
513 const IPropertySet* ApacheRequestMapper::getPropertySet(const char* name, const char* ns) const
515 ApacheRequestMapperSettings* arms=(ApacheRequestMapperSettings*)m_key->getData();
516 return arms ? arms->m_props->getPropertySet(name,ns) : NULL;
519 const DOMElement* ApacheRequestMapper::getElement() const
521 ApacheRequestMapperSettings* arms=(ApacheRequestMapperSettings*)m_key->getData();
522 return arms ? arms->m_props->getElement() : NULL;
525 static SH_AP_TABLE* groups_for_user(request_rec* r, const char* user, char* grpfile)
528 SH_AP_TABLE* grps=ap_make_table(r->pool,15);
529 char l[MAX_STRING_LEN];
530 const char *group_name, *ll, *w;
532 #ifdef SHIB_APACHE_13
533 if (!(f=ap_pcfg_openfile(r->pool,grpfile))) {
535 if (ap_pcfg_openfile(&f,r->pool,grpfile) != APR_SUCCESS) {
537 ap_log_rerror(APLOG_MARK,APLOG_DEBUG,SH_AP_R(r),"groups_for_user() could not open group file: %s\n",grpfile);
542 #ifdef SHIB_APACHE_13
543 sp=ap_make_sub_pool(r->pool);
545 if (apr_pool_create(&sp,r->pool) != APR_SUCCESS) {
546 ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,
547 "groups_for_user() could not create a subpool");
552 while (!(ap_cfg_getline(l,MAX_STRING_LEN,f))) {
553 if ((*l=='#') || (!*l))
558 group_name=ap_getword(sp,&ll,':');
561 w=ap_getword_conf(sp,&ll);
562 if (!strcmp(w,user)) {
563 ap_table_setn(grps,ap_pstrdup(r->pool,group_name),"in");
573 bool htAccessControl::authorized(
575 const char* providerId,
576 const saml::SAMLAuthenticationStatement* authn,
577 const saml::SAMLResponse* attrs
580 // Make sure the object is our type.
581 ShibTargetApache* sta=dynamic_cast<ShibTargetApache*>(st);
583 throw ConfigurationException("Request wrapper object was not of correct type.");
587 int m=sta->m_req->method_number;
588 bool method_restricted=false;
591 const array_header* reqs_arr=ap_requires(sta->m_req);
595 require_line* reqs=(require_line*)reqs_arr->elts;
597 ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(sta->m_req),"REQUIRE nelts: %d", reqs_arr->nelts);
598 ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(sta->m_req),"REQUIRE all: %d", sta->m_dc->bRequireAll);
600 vector<bool> auth_OK(reqs_arr->nelts,false);
602 #define SHIB_AP_CHECK_IS_OK { \
603 if (sta->m_dc->bRequireAll < 1) \
609 for (int x=0; x<reqs_arr->nelts; x++) {
611 if (!(reqs[x].method_mask & (1 << m)))
613 method_restricted=true;
614 string remote_user = st->getRemoteUser();
616 t = reqs[x].requirement;
617 w = ap_getword_white(sta->m_req->pool, &t);
619 if (!strcasecmp(w,"Shibboleth")) {
620 // This is a dummy rule needed because Apache conflates authn and authz.
621 // Without some require rule, AuthType is ignored and no check_user hooks run.
624 else if (!strcmp(w,"valid-user")) {
625 st->log(ShibTarget::LogLevelDebug,"htAccessControl plugin accepting valid-user");
628 else if (!strcmp(w,"user") && !remote_user.empty()) {
631 w=ap_getword_conf(sta->m_req->pool,&t);
639 // To do regex matching, we have to convert from UTF-8.
640 auto_ptr<XMLCh> trans(fromUTF8(w));
641 RegularExpression re(trans.get());
642 auto_ptr<XMLCh> trans2(fromUTF8(remote_user.c_str()));
643 if (re.matches(trans2.get())) {
644 st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin accepting user (") + w + ")");
648 catch (XMLException& ex) {
649 auto_ptr_char tmp(ex.getMessage());
650 st->log(ShibTarget::LogLevelError,
651 string("htAccessControl plugin caught exception while parsing regular expression (") + w + "): " + tmp.get());
654 else if (remote_user==w) {
655 st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin accepting user (") + w + ")");
660 else if (!strcmp(w,"group")) {
661 SH_AP_TABLE* grpstatus=NULL;
662 if (sta->m_dc->szAuthGrpFile && !remote_user.empty()) {
663 st->log(ShibTarget::LogLevelDebug,string("htAccessControl plugin using groups file: ") + sta->m_dc->szAuthGrpFile);
664 grpstatus=groups_for_user(sta->m_req,remote_user.c_str(),sta->m_dc->szAuthGrpFile);
670 w=ap_getword_conf(sta->m_req->pool,&t);
671 if (ap_table_get(grpstatus,w)) {
672 st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin accepting group (") + w + ")");
678 Iterator<IAAP*> provs=st->getApplication()->getAAPProviders();
679 AAP wrapper(provs,w);
680 if (wrapper.fail()) {
681 st->log(ShibTarget::LogLevelWarn, string("htAccessControl plugin didn't recognize require rule: ") + w);
686 const char* vals=ap_table_get(sta->m_req->headers_in,wrapper->getHeader());
688 w=ap_getword_conf(sta->m_req->pool,&t);
695 auto_ptr<RegularExpression> re;
698 auto_ptr<XMLCh> trans(fromUTF8(w));
699 auto_ptr<RegularExpression> temp(new RegularExpression(trans.get()));
703 string vals_str(vals);
705 for (int i = 0; i < vals_str.length(); i++) {
706 if (vals_str.at(i) == ';') {
708 st->log(ShibTarget::LogLevelError, string("htAccessControl plugin found invalid header encoding (") +
709 vals + "): starts with a semicolon");
710 throw SAMLException("Invalid information supplied to authorization plugin.");
713 if (vals_str.at(i-1) == '\\') {
714 vals_str.erase(i-1, 1);
719 string val = vals_str.substr(j, i-j);
722 auto_ptr<XMLCh> trans(fromUTF8(val.c_str()));
723 if (re->matches(trans.get())) {
724 st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin expecting ") + w +
725 ", got " + val + ": authorization granted");
729 else if ((wrapper->getCaseSensitive() && val==w) || (!wrapper->getCaseSensitive() && !strcasecmp(val.c_str(),w))) {
730 st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin expecting ") + w +
731 ", got " + val + ": authorization granted.");
735 st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin expecting ") + w +
736 ", got " + val + ": authoritzation not granted.");
741 string val = vals_str.substr(j, vals_str.length()-j);
743 auto_ptr<XMLCh> trans(fromUTF8(val.c_str()));
744 if (re->matches(trans.get())) {
745 st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin expecting ") + w +
746 ", got " + val + ": authorization granted.");
750 else if ((wrapper->getCaseSensitive() && val==w) || (!wrapper->getCaseSensitive() && !strcasecmp(val.c_str(),w))) {
751 st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin expecting ") + w +
752 ", got " + val + ": authorization granted");
756 st->log(ShibTarget::LogLevelDebug, string("htAccessControl plugin expecting ") + w +
757 ", got " + val + ": authorization not granted");
760 catch (XMLException& ex) {
761 auto_ptr_char tmp(ex.getMessage());
762 st->log(ShibTarget::LogLevelError, string("htAccessControl plugin caught exception while parsing regular expression (")
763 + w + "): " + tmp.get());
769 // check if all require directives are true
770 bool auth_all_OK = true;
771 for (int i= 0; i<reqs_arr->nelts; i++) {
772 auth_all_OK &= auth_OK[i];
774 if (auth_all_OK || !method_restricted)
780 #ifndef SHIB_APACHE_13
783 * Empty cleanup hook, Apache 2.x doesn't check NULL very well...
785 extern "C" apr_status_t shib_exit(void* data)
788 g_Config->shutdown();
791 ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,NULL,"shib_exit() done\n");
799 * Cleanup the (per-process) pool info.
801 #ifdef SHIB_APACHE_13
802 extern "C" void shib_child_exit(server_rec* s, SH_AP_POOL* p)
805 extern "C" apr_status_t shib_child_exit(void* data)
807 server_rec* s = NULL;
810 ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_child_exit(%d) dealing with g_Config..", (int)getpid());
811 g_Config->shutdown();
813 ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_child_exit() done\n");
815 #ifndef SHIB_APACHE_13
822 * Things to do when the child process is initialized.
823 * (or after the configs are read in apache-2)
825 #ifdef SHIB_APACHE_13
826 extern "C" void shib_child_init(server_rec* s, SH_AP_POOL* p)
828 extern "C" void shib_child_init(apr_pool_t* p, server_rec* s)
831 // Initialize runtime components.
833 ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_child_init(%d) starting", (int)getpid());
836 ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,SH_AP_R(s),"shib_child_init() already initialized!");
841 g_Config=&ShibTargetConfig::getConfig();
842 g_Config->setFeatures(
843 ShibTargetConfig::Listener |
844 ShibTargetConfig::Metadata |
845 ShibTargetConfig::AAP |
846 ShibTargetConfig::RequestMapper |
847 ShibTargetConfig::LocalExtensions |
848 ShibTargetConfig::Logging
850 if (!g_Config->init(g_szSchemaDir)) {
851 ap_log_error(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,SH_AP_R(s),"shib_child_init() failed to initialize libraries");
854 SAMLConfig::getConfig().getPlugMgr().regFactory(shibtarget::XML::htAccessControlType,&htAccessFactory);
855 SAMLConfig::getConfig().getPlugMgr().regFactory(shibtarget::XML::ApacheRequestMapType,&ApacheRequestMapFactory);
857 // We hijack the legacy type so that 1.2 config files will load this plugin instead of the basic plugin.
858 SAMLConfig::getConfig().getPlugMgr().regFactory(shibtarget::XML::LegacyRequestMapType,&ApacheRequestMapFactory);
860 if (!g_Config->load(g_szSHIBConfig)) {
861 ap_log_error(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,SH_AP_R(s),"shib_child_init() failed to load configuration");
866 ap_log_error(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,SH_AP_R(s),"shib_child_init() failed to initialize system");
870 // Set the cleanup handler
871 apr_pool_cleanup_register(p, NULL, &shib_exit, &shib_child_exit);
873 ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_child_init() done");
876 typedef const char* (*config_fn_t)(void);
878 #ifdef SHIB_APACHE_13
880 // SHIB Module commands
882 static command_rec shire_cmds[] = {
883 {"SHIREConfig", (config_fn_t)ap_set_global_string_slot, &g_szSHIBConfig,
884 RSRC_CONF, TAKE1, "Path to shibboleth.xml config file."},
885 {"ShibConfig", (config_fn_t)ap_set_global_string_slot, &g_szSHIBConfig,
886 RSRC_CONF, TAKE1, "Path to shibboleth.xml config file."},
887 {"ShibSchemaDir", (config_fn_t)ap_set_global_string_slot, &g_szSchemaDir,
888 RSRC_CONF, TAKE1, "Path to Shibboleth XML schema directory."},
890 {"ShibURLScheme", (config_fn_t)shib_set_server_string_slot,
891 (void *) XtOffsetOf (shib_server_config, szScheme),
892 RSRC_CONF, TAKE1, "URL scheme to force into generated URLs for a vhost."},
894 {"ShibBasicHijack", (config_fn_t)ap_set_flag_slot,
895 (void *) XtOffsetOf (shib_dir_config, bBasicHijack),
896 OR_AUTHCFG, FLAG, "Respond to AuthType Basic and convert to shib?"},
897 {"ShibRequireSession", (config_fn_t)ap_set_flag_slot,
898 (void *) XtOffsetOf (shib_dir_config, bRequireSession),
899 OR_AUTHCFG, FLAG, "Initiates a new session if one does not exist."},
900 {"ShibExportAssertion", (config_fn_t)ap_set_flag_slot,
901 (void *) XtOffsetOf (shib_dir_config, bExportAssertion),
902 OR_AUTHCFG, FLAG, "Export SAML assertion to Shibboleth-defined header?"},
903 {"AuthGroupFile", (config_fn_t)shib_ap_set_file_slot,
904 (void *) XtOffsetOf (shib_dir_config, szAuthGrpFile),
905 OR_AUTHCFG, TAKE1, "text file containing group names and member user IDs"},
906 {"ShibRequireAll", (config_fn_t)ap_set_flag_slot,
907 (void *) XtOffsetOf (shib_dir_config, bRequireAll),
908 OR_AUTHCFG, FLAG, "All require directives must match!"},
914 handler_rec shib_handlers[] = {
915 { "shib-handler", shib_handler },
919 module MODULE_VAR_EXPORT mod_shib = {
920 STANDARD_MODULE_STUFF,
921 NULL, /* initializer */
922 create_shib_dir_config, /* dir config creater */
923 merge_shib_dir_config, /* dir merger --- default is to override */
924 create_shib_server_config, /* server config */
925 merge_shib_server_config, /* merge server config */
926 shire_cmds, /* command table */
927 shib_handlers, /* handlers */
928 NULL, /* filename translation */
929 shib_check_user, /* check_user_id */
930 shib_auth_checker, /* check auth */
931 NULL, /* check access */
932 NULL, /* type_checker */
935 NULL, /* header parser */
936 shib_child_init, /* child_init */
937 shib_child_exit, /* child_exit */
938 NULL /* post read-request */
941 #elif defined(SHIB_APACHE_20)
943 extern "C" void shib_register_hooks (apr_pool_t *p)
945 ap_hook_child_init(shib_child_init, NULL, NULL, APR_HOOK_MIDDLE);
946 ap_hook_check_user_id(shib_check_user, NULL, NULL, APR_HOOK_MIDDLE);
947 ap_hook_auth_checker(shib_auth_checker, NULL, NULL, APR_HOOK_FIRST);
948 ap_hook_handler(shib_handler, NULL, NULL, APR_HOOK_LAST);
951 // SHIB Module commands
954 static command_rec shib_cmds[] = {
955 AP_INIT_TAKE1("ShibConfig",
956 (config_fn_t)ap_set_global_string_slot, &g_szSHIBConfig,
957 RSRC_CONF, "Path to shibboleth.xml config file."),
958 AP_INIT_TAKE1("ShibSchemaDir",
959 (config_fn_t)ap_set_global_string_slot, &g_szSchemaDir,
960 RSRC_CONF, "Path to Shibboleth XML schema directory."),
962 AP_INIT_TAKE1("ShibURLScheme",
963 (config_fn_t)shib_set_server_string_slot,
964 (void *) offsetof (shib_server_config, szScheme),
965 RSRC_CONF, "URL scheme to force into generated URLs for a vhost."),
967 AP_INIT_FLAG("ShibBasicHijack", (config_fn_t)ap_set_flag_slot,
968 (void *) offsetof (shib_dir_config, bBasicHijack),
969 OR_AUTHCFG, "Respond to AuthType Basic and convert to shib?"),
970 AP_INIT_FLAG("ShibRequireSession", (config_fn_t)ap_set_flag_slot,
971 (void *) offsetof (shib_dir_config, bRequireSession),
972 OR_AUTHCFG, "Initiates a new session if one does not exist."),
973 AP_INIT_FLAG("ShibExportAssertion", (config_fn_t)ap_set_flag_slot,
974 (void *) offsetof (shib_dir_config, bExportAssertion),
975 OR_AUTHCFG, "Export SAML assertion to Shibboleth-defined header?"),
976 AP_INIT_TAKE1("AuthGroupFile", (config_fn_t)shib_ap_set_file_slot,
977 (void *) offsetof (shib_dir_config, szAuthGrpFile),
978 OR_AUTHCFG, "text file containing group names and member user IDs"),
979 AP_INIT_FLAG("ShibRequireAll", (config_fn_t)ap_set_flag_slot,
980 (void *) offsetof (shib_dir_config, bRequireAll),
981 OR_AUTHCFG, "All require directives must match!"),
986 module AP_MODULE_DECLARE_DATA mod_shib = {
987 STANDARD20_MODULE_STUFF,
988 create_shib_dir_config, /* create dir config */
989 merge_shib_dir_config, /* merge dir config --- default is to override */
990 create_shib_server_config, /* create server config */
991 merge_shib_server_config, /* merge server config */
992 shib_cmds, /* command table */
993 shib_register_hooks /* register hooks */
997 #error "undefined APACHE version"