* $Id$
*/
+#ifdef SOLARIS2
+#undef _XOPEN_SOURCE // causes gethostname conflict in unistd.h
+#endif
+
// SAML Runtime
#include <saml/saml.h>
#include <shib/shib.h>
using namespace shibtarget;
extern "C" module MODULE_VAR_EXPORT mod_shib;
-int shib_handler(request_rec* r, const IApplication* application, const IPropertySet* sessionProps, SHIRE& shire);
+int shib_handler(request_rec* r, const IApplication* application, SHIRE& shire);
namespace {
char* g_szSHIBConfig = NULL;
static const char* g_UserDataKey = "_shib_check_user_";
}
+// per-server module configuration structure
+struct shib_server_config
+{
+ char* szScheme;
+};
+
+// creates the per-server configuration
+extern "C" void* create_shib_server_config(SH_AP_POOL* p, server_rec* s)
+{
+ shib_server_config* sc=(shib_server_config*)ap_pcalloc(p,sizeof(shib_server_config));
+ sc->szScheme = NULL;
+ return sc;
+}
+
+// overrides server configuration in virtual servers
+extern "C" void* merge_shib_server_config (SH_AP_POOL* p, void* base, void* sub)
+{
+ shib_server_config* sc=(shib_server_config*)ap_pcalloc(p,sizeof(shib_server_config));
+ shib_server_config* parent=(shib_server_config*)base;
+ shib_server_config* child=(shib_server_config*)sub;
+
+ if (child->szScheme)
+ sc->szScheme=ap_pstrdup(p,child->szScheme);
+ else if (parent->szScheme)
+ sc->szScheme=ap_pstrdup(p,parent->szScheme);
+ else
+ sc->szScheme=NULL;
+
+ return sc;
+}
+
// per-dir module configuration structure
struct shib_dir_config
{
return NULL;
}
+extern "C" const char* shib_set_server_string_slot(cmd_parms* parms, void*, const char* arg)
+{
+ char* base=(char*)ap_get_module_config(parms->server->module_config,&mod_shib);
+ int offset=(int)parms->info;
+ *((char**)(base + offset))=ap_pstrdup(parms->pool,arg);
+ return NULL;
+}
+
typedef const char* (*config_fn_t)(void);
static int shib_error_page(request_rec* r, const IApplication* app, const char* page, ShibMLP& mlp)
return SERVER_ERROR;
}
+static char* shib_get_targeturl(request_rec* r, const char* scheme=NULL)
+{
+ // On 1.3, this is always canonical, but on 2.0, UseCanonicalName comes into play.
+ // However, we also have a setting to forcibly replace the scheme for esoteric cases.
+ if (scheme) {
+ unsigned port = ap_get_server_port(r);
+ if ((!strcmp(scheme,"http") && port==80) || (!strcmp(scheme,"https") && port==443)) {
+ return ap_pstrcat(r->pool, scheme, "://", ap_get_server_name(r), r->unparsed_uri, NULL);
+ }
+ return ap_psprintf(r->pool, "%s://%s:%u%s", scheme, ap_get_server_name(r), port, r->unparsed_uri);
+ }
+ return ap_construct_url(r->pool,r->unparsed_uri,r);
+}
+
extern "C" int shib_check_user(request_rec* r)
{
ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),"shib_check_user: ENTER");
shib_dir_config* dc=(shib_dir_config*)ap_get_module_config(r->per_dir_config,&mod_shib);
+ shib_server_config* sc=(shib_server_config*)ap_get_module_config(r->server->module_config,&mod_shib);
ostringstream threadid;
threadid << "[" << getpid() << "] shib_check_user" << '\0';
saml::NDC ndc(threadid.str().c_str());
- // This will always be normalized, because Apache uses ap_get_server_name in this API call.
- const char* targeturl=ap_construct_url(r->pool,r->unparsed_uri,r);
+ const char* targeturl=shib_get_targeturl(r,sc->szScheme);
// We lock the configuration system for the duration.
IConfig* conf=g_Config->getINI();
IRequestMapper* mapper=conf->getRequestMapper();
Locker locker2(mapper);
IRequestMapper::Settings settings=mapper->getSettingsFromParsedURL(
- ap_http_method(r), ap_get_server_name(r), ap_get_server_port(r), r->unparsed_uri
+ (sc-> szScheme ? sc-> szScheme : ap_http_method(r)), ap_get_server_name(r), ap_get_server_port(r), r->unparsed_uri
);
pair<bool,const char*> application_id=settings.first->getString("applicationId");
const IApplication* application=conf->getApplication(application_id.second);
- const IPropertySet* sessionProps=application ? application->getPropertySet("Sessions") : NULL;
- if (!application || !sessionProps) {
+ if (!application) {
ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,SH_AP_R(r),
- "shib_check_user: unable to map request to application session settings, check configuration");
+ "shib_check_user: unable to map request to application settings, check configuration");
return SERVER_ERROR;
}
// Declare SHIRE object for this request.
SHIRE shire(application);
+ const char* shireURL=shire.getShireURL(targeturl);
+ if (!shireURL) {
+ ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,SH_AP_R(r),
+ "shib_check_user: unable to map request to proper shireURL setting, check configuration");
+ return SERVER_ERROR;
+ }
+
// Get location of this application's assertion consumer service and see if this is it.
- if (strstr(targeturl,shire.getShireURL(targeturl))) {
- return shib_handler(r,application,sessionProps,shire);
+ if (strstr(targeturl,shireURL)) {
+ return shib_handler(r,application,shire);
}
// We can short circuit the handler if we run this...
ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),"shib_check_user: session check for %s",targeturl);
- pair<bool,const char*> shib_cookie=sessionProps->getString("cookieName");
- if (!shib_cookie.first) {
- ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,SH_AP_R(r),
- "shib_check_user: no cookieName set for %s",
- application_id.second);
- return SERVER_ERROR;
- }
+ pair<const char*,const char*> shib_cookie=shire.getCookieNameProps(); // always returns *something*
// We're in charge, so check for cookie.
const char* session_id=NULL;
if (cookies) {
ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),"shib_check_user: cookies found: %s",cookies);
- if (session_id=strstr(cookies,shib_cookie.second)) {
+ if (session_id=strstr(cookies,shib_cookie.first)) {
// Yep, we found a cookie -- pull it out (our session_id)
- session_id+=strlen(shib_cookie.second) + 1; /* Skip over the '=' */
+ session_id+=strlen(shib_cookie.first) + 1; /* Skip over the '=' */
char* cookiebuf = ap_pstrdup(r->pool,session_id);
char* cookieend = strchr(cookiebuf,';');
if (cookieend)
// Do we have an access control plugin?
if (settings.second) {
Locker acllock(settings.second);
- if (!settings.second->authorized(assertions)) {
+ if (!settings.second->authorized(*sso_statement,assertions)) {
for (int k = 0; k < assertions.size(); k++)
delete assertions[k];
delete sso_statement;
Iterator<const IAttributeRule*> rules=aap->getAttributeRules();
while (rules.hasNext()) {
const char* header=rules.next()->getHeader();
- if (header)
+ if (header) {
ap_table_unset(r->headers_in,header);
+ ap_table_set(r->headers_in,header,"");
+ }
}
}
catch(...) {
ap_table_unset(r->headers_in,"Shib-Origin-Site");
ap_table_unset(r->headers_in,"Shib-Authentication-Method");
ap_table_unset(r->headers_in,"Shib-NameIdentifier-Format");
- if (sso_statement) {
- auto_ptr_char os(sso_statement->getSubject()->getNameIdentifier()->getNameQualifier());
- auto_ptr_char am(sso_statement->getAuthMethod());
- ap_table_set(r->headers_in,"Shib-Origin-Site", os.get());
- ap_table_set(r->headers_in,"Shib-Authentication-Method", am.get());
-
- // Export NameID?
- AAP wrapper(provs,sso_statement->getSubject()->getNameIdentifier()->getFormat(),Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
- if (!wrapper.fail() && wrapper->getHeader()) {
- auto_ptr_char form(sso_statement->getSubject()->getNameIdentifier()->getFormat());
- auto_ptr_char nameid(sso_statement->getSubject()->getNameIdentifier()->getName());
- ap_table_set(r->headers_in,"Shib-NameIdentifier-Format",form.get());
- if (!strcmp(wrapper->getHeader(),"REMOTE_USER"))
- SH_AP_USER(r)=ap_pstrdup(r->pool,nameid.get());
- else
- ap_table_set(r->headers_in,wrapper->getHeader(),nameid.get());
- }
+ auto_ptr_char os(sso_statement->getSubject()->getNameIdentifier()->getNameQualifier());
+ auto_ptr_char am(sso_statement->getAuthMethod());
+ ap_table_set(r->headers_in,"Shib-Origin-Site", os.get());
+ ap_table_set(r->headers_in,"Shib-Authentication-Method", am.get());
+
+ // Export NameID?
+ AAP wrapper(provs,sso_statement->getSubject()->getNameIdentifier()->getFormat(),Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
+ if (!wrapper.fail() && wrapper->getHeader()) {
+ auto_ptr_char form(sso_statement->getSubject()->getNameIdentifier()->getFormat());
+ auto_ptr_char nameid(sso_statement->getSubject()->getNameIdentifier()->getName());
+ ap_table_set(r->headers_in,"Shib-NameIdentifier-Format",form.get());
+ if (!strcmp(wrapper->getHeader(),"REMOTE_USER"))
+ SH_AP_USER(r)=ap_pstrdup(r->pool,nameid.get());
+ else
+ ap_table_set(r->headers_in,wrapper->getHeader(),nameid.get());
}
ap_table_unset(r->headers_in,"Shib-Application-ID");
extern "C" int shib_post_handler(request_rec* r)
{
+ ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),
+ "shib_post_handler(%d): ENTER", (int)getpid());
+ shib_server_config* sc=(shib_server_config*)ap_get_module_config(r->server->module_config,&mod_shib);
+
#ifndef SHIB_APACHE_13
// With 2.x, this handler always runs, though last.
// We check if shib_check_user ran, because it will detect a SHIRE request
IRequestMapper* mapper=conf->getRequestMapper();
Locker locker2(mapper);
IRequestMapper::Settings settings=mapper->getSettingsFromParsedURL(
- ap_http_method(r), ap_get_server_name(r), ap_get_server_port(r), r->unparsed_uri
+ (sc->szScheme ? sc->szScheme : ap_http_method(r)), ap_get_server_name(r), ap_get_server_port(r), r->unparsed_uri
);
pair<bool,const char*> application_id=settings.first->getString("applicationId");
const IApplication* application=conf->getApplication(application_id.second);
- const IPropertySet* sessionProps=application ? application->getPropertySet("Sessions") : NULL;
- if (!application || !sessionProps) {
+ if (!application) {
ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,SH_AP_R(r),
- "shib_post_handler: unable to map request to application session settings, check configuration");
+ "shib_post_handler: unable to map request to application settings, check configuration");
return SERVER_ERROR;
}
// Declare SHIRE object for this request.
SHIRE shire(application);
- return shib_handler(r, application, sessionProps, shire);
+ return shib_handler(r, application, shire);
}
-int shib_handler(request_rec* r, const IApplication* application, const IPropertySet* sessionProps, SHIRE& shire)
+int shib_handler(request_rec* r, const IApplication* application, SHIRE& shire)
{
- // Prime the pump...
- const char* targeturl = ap_construct_url(r->pool,r->unparsed_uri,r);
+ shib_server_config* sc=(shib_server_config*)ap_get_module_config(r->server->module_config,&mod_shib);
+
+ const char* targeturl=shib_get_targeturl(r,sc->szScheme);
+
+ const char* shireURL=shire.getShireURL(targeturl);
+ if (!shireURL) {
+ ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,SH_AP_R(r),
+ "shib_post_handler: unable to map request to proper shireURL setting, check configuration");
+ return SERVER_ERROR;
+ }
// Make sure we only process the SHIRE requests.
- if (!strstr(targeturl,shire.getShireURL(targeturl)))
+ if (!strstr(targeturl,shireURL))
return DECLINED;
ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),"shib_handler() running");
- pair<bool,const char*> shib_cookie=sessionProps->getString("cookieName");
- pair<bool,const char*> shib_cookie_props=sessionProps->getString("cookieProps");
- if (!shib_cookie.first) {
- ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,SH_AP_R(r),
- "shib_handler: no cookieName set for %s", application->getId());
+ const IPropertySet* sessionProps=application->getPropertySet("Sessions");
+ if (!sessionProps) {
+ ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,SH_AP_R(r),
+ "shib_post_handler: unable to map request to application session settings, check configuration");
return SERVER_ERROR;
}
+ pair<const char*,const char*> shib_cookie=shire.getCookieNameProps(); // always returns something
+
ShibMLP markupProcessor;
markupProcessor.insert("requestURL", targeturl);
ap_hard_timeout("[mod_shib] CGI Parser", r);
memset(buff, 0, sizeof(buff));
while (ap_get_client_block(r, buff, sizeof(buff)-1) > 0) {
+ ap_reset_timeout(r);
cgistr += buff;
memset(buff, 0, sizeof(buff));
}
"shib_handler() POST process succeeded. New session: %s", cookie.c_str());
// We've got a good session, set the cookie...
- char* val = ap_psprintf(r->pool,"%s=%s%s",shib_cookie.second,cookie.c_str(),
- shib_cookie_props.first ? shib_cookie_props.second : "; path=/");
+ char* val = ap_psprintf(r->pool,"%s=%s%s",shib_cookie.first,cookie.c_str(),shib_cookie.second);
ap_table_setn(r->err_headers_out, "Set-Cookie", val);
ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r), "shib_handler() setting cookie: %s", val);
return shib_error_page(r, application, "access", markupProcessor);
}
+#ifndef SHIB_APACHE_13
/*
* shib_exit()
+ * Empty cleanup hook, Apache 2.x doesn't check NULL very well...
+ */
+extern "C" apr_status_t shib_exit(void* data)
+{
+ ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,NULL,"shib_exit() done\n");
+ return OK;
+}
+#endif
+
+
+/*
+ * shib_child_exit()
* Cleanup the (per-process) pool info.
*/
#ifdef SHIB_APACHE_13
-extern "C" void shib_exit(server_rec* s, SH_AP_POOL* p)
+extern "C" void shib_child_exit(server_rec* s, SH_AP_POOL* p)
{
#else
-extern "C" apr_status_t shib_exit(void* data)
+extern "C" apr_status_t shib_child_exit(void* data)
{
- server_rec* s = NULL;
+ server_rec* s = NULL;
#endif
+
+ ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_child_exit(%d) dealing with g_Config..", (int)getpid());
g_Config->shutdown();
g_Config = NULL;
- ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_exit() done");
+ ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_child_exit() done\n");
+
#ifndef SHIB_APACHE_13
return OK;
#endif
#ifdef SHIB_APACHE_13
extern "C" void shib_child_init(server_rec* s, SH_AP_POOL* p)
#else
-extern "C" int shib_post_config(apr_pool_t* pconf, apr_pool_t* plog,
- apr_pool_t* ptemp, server_rec* s)
+extern "C" void shib_child_init(apr_pool_t* p, server_rec* s)
#endif
{
// Initialize runtime components.
- ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_child_init() starting");
+ ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_child_init(%d) starting", (int)getpid());
if (g_Config) {
ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,SH_AP_R(s),"shib_child_init() already initialized!");
-#ifdef SHIB_APACHE_13
exit(1);
-#else
- return OK;
-#endif
}
try {
ShibTargetConfig::Metadata |
ShibTargetConfig::AAP |
ShibTargetConfig::RequestMapper |
- ShibTargetConfig::SHIREExtensions
+ ShibTargetConfig::SHIREExtensions |
+ ShibTargetConfig::Logging
);
if (!g_Config->init(g_szSchemaDir,g_szSHIBConfig)) {
ap_log_error(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,SH_AP_R(s),"shib_child_init() failed to initialize SHIB Target");
}
// Set the cleanup handler
- apr_pool_cleanup_register(pconf, NULL, shib_exit, NULL);
+ apr_pool_cleanup_register(p, NULL, &shib_exit, &shib_child_exit);
ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_child_init() done");
-
-#ifndef SHIB_APACHE_13
- return OK;
-#endif
}
#ifdef SHIB_APACHE_13
{"ShibSchemaDir", (config_fn_t)ap_set_global_string_slot, &g_szSchemaDir,
RSRC_CONF, TAKE1, "Path to Shibboleth XML schema directory."},
+ {"ShibURLScheme", (config_fn_t)shib_set_server_string_slot,
+ (void *) XtOffsetOf (shib_server_config, szScheme),
+ RSRC_CONF, TAKE1, "URL scheme to force into generated URLs for a vhost."},
+
{"ShibBasicHijack", (config_fn_t)ap_set_flag_slot,
(void *) XtOffsetOf (shib_dir_config, bBasicHijack),
OR_AUTHCFG, FLAG, "Respond to AuthType Basic and convert to shib?"},
NULL, /* initializer */
create_shib_dir_config, /* dir config creater */
merge_shib_dir_config, /* dir merger --- default is to override */
- NULL, /* server config */
- NULL, /* merge server config */
+ create_shib_server_config, /* server config */
+ merge_shib_server_config, /* merge server config */
shire_cmds, /* command table */
shib_handlers, /* handlers */
NULL, /* filename translation */
NULL, /* logger */
NULL, /* header parser */
shib_child_init, /* child_init */
- shib_exit, /* child_exit */
+ shib_child_exit, /* child_exit */
NULL /* post read-request */
};
extern "C" void shib_register_hooks (apr_pool_t *p)
{
- ap_hook_post_config(shib_post_config, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_child_init(shib_child_init, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_check_user_id(shib_check_user, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_auth_checker(shib_auth_checker, NULL, NULL, APR_HOOK_FIRST);
ap_hook_handler(shib_post_handler, NULL, NULL, APR_HOOK_LAST);
(config_fn_t)ap_set_global_string_slot, &g_szSchemaDir,
RSRC_CONF, "Path to Shibboleth XML schema directory."),
+ AP_INIT_TAKE1("ShibURLScheme",
+ (config_fn_t)shib_set_server_string_slot,
+ (void *) offsetof (shib_server_config, szScheme),
+ RSRC_CONF, "URL scheme to force into generated URLs for a vhost."),
+
AP_INIT_FLAG("ShibBasicHijack", (config_fn_t)ap_set_flag_slot,
(void *) offsetof (shib_dir_config, bBasicHijack),
OR_AUTHCFG, "Respond to AuthType Basic and convert to shib?"),
module AP_MODULE_DECLARE_DATA mod_shib = {
STANDARD20_MODULE_STUFF,
- create_shib_dir_config, /* create dir config */
- merge_shib_dir_config, /* merge dir config --- default is to override */
- NULL, /* create server config */
- NULL, /* merge server config */
- shib_cmds, /* command table */
- shib_register_hooks /* register hooks */
+ create_shib_dir_config, /* create dir config */
+ merge_shib_dir_config, /* merge dir config --- default is to override */
+ create_shib_server_config, /* create server config */
+ merge_shib_server_config, /* merge server config */
+ shib_cmds, /* command table */
+ shib_register_hooks /* register hooks */
};
#else