/*
- * Copyright 2001-2010 Internet2
+ * Copyright 2001-2011 Internet2
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <xercesc/util/regx/RegularExpression.hpp>
#include <xmltooling/XMLToolingConfig.h>
#include <xmltooling/util/NDC.h>
+#include <xmltooling/util/ParserPool.h>
#include <xmltooling/util/Threads.h>
#include <xmltooling/util/XMLConstants.h>
#include <xmltooling/util/XMLHelper.h>
char* szApplicationId; // Shib applicationId value
char* szRequireWith; // require a session using a specific initiator?
char* szRedirectToSSL; // redirect non-SSL requests to SSL port
+ char* szAccessControl; // path to "external" AccessControl plugin file
int bOff; // flat-out disable all Shib processing
int bBasicHijack; // activate for AuthType Basic?
int bRequireSession; // require a session?
dc->szApplicationId = nullptr;
dc->szRequireWith = nullptr;
dc->szRedirectToSSL = nullptr;
+ dc->szAccessControl = nullptr;
dc->bOff = -1;
dc->bBasicHijack = -1;
dc->bRequireSession = -1;
else
dc->szRedirectToSSL=nullptr;
+ if (child->szAccessControl)
+ dc->szAccessControl=ap_pstrdup(p,child->szAccessControl);
+ else if (parent->szAccessControl)
+ dc->szAccessControl=ap_pstrdup(p,parent->szAccessControl);
+ else
+ dc->szAccessControl=nullptr;
+
dc->bOff=((child->bOff==-1) ? parent->bOff : child->bOff);
dc->bBasicHijack=((child->bBasicHijack==-1) ? parent->bBasicHijack : child->bBasicHijack);
dc->bRequireSession=((child->bRequireSession==-1) ? parent->bRequireSession : child->bRequireSession);
class ShibTargetApache : public AbstractSPRequest
-#if defined(HAVE_GSSAPI) && !defined(SHIB_APACHE_13)
+#if defined(SHIBSP_HAVE_GSSAPI) && !defined(SHIB_APACHE_13)
, public GSSRequest
#endif
{
const char* getScheme() const {
return m_sc->szScheme ? m_sc->szScheme : ap_http_method(m_req);
}
+ bool isSecure() const {
+ return HTTPRequest::isSecure();
+ }
const char* getHostname() const {
return ap_get_server_name(m_req);
}
(level == SPWarn ? APLOG_WARNING :
(level == SPError ? APLOG_ERR : APLOG_CRIT))))|APLOG_NOERRNO,
SH_AP_R(m_req),
+ "%s",
msg.c_str()
);
}
#endif
return m_body.c_str();
}
+ const char* getParameter(const char* name) const {
+ return AbstractSPRequest::getParameter(name);
+ }
+ vector<const char*>::size_type getParameters(const char* name, vector<const char*>& values) const {
+ return AbstractSPRequest::getParameters(name, values);
+ }
void clearHeader(const char* rawname, const char* cginame) {
if (m_dc->bUseHeaders == 1) {
// ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(m_req), "shib_clear_header: hdr\n");
return string(SH_AP_AUTH_TYPE(m_req) ? SH_AP_AUTH_TYPE(m_req) : "");
}
void setContentType(const char* type) {
- m_req->content_type = ap_psprintf(m_req->pool, type);
+ m_req->content_type = ap_psprintf(m_req->pool, "%s", type);
}
void setResponseHeader(const char* name, const char* value) {
HTTPResponse::setResponseHeader(name, value);
}
long returnDecline(void) { return DECLINED; }
long returnOK(void) { return OK; }
-#if defined(HAVE_GSSAPI) && !defined(SHIB_APACHE_13)
+#if defined(SHIBSP_HAVE_GSSAPI) && !defined(SHIB_APACHE_13)
gss_ctx_id_t getGSSContext() const {
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
apr_pool_userdata_get((void**)&ctx, g_szGSSContextKey, m_req->pool);
if (!sta)
throw ConfigurationException("Request wrapper object was not of correct type.");
- // mod_auth clone
-
int m=sta->m_req->method_number;
bool method_restricted=false;
const char *t, *w;
if (!reqs_arr)
return shib_acl_indeterminate; // should never happen
+ // Check for an "embedded" AccessControl plugin.
+ if (sta->m_dc->szAccessControl) {
+ aclresult_t result = shib_acl_false;
+ try {
+ ifstream aclfile(sta->m_dc->szAccessControl);
+ xercesc::DOMDocument* acldoc = XMLToolingConfig::getConfig().getParser().parse(aclfile);
+ XercesJanitor<xercesc::DOMDocument> docjanitor(acldoc);
+ static XMLCh _type[] = UNICODE_LITERAL_4(t,y,p,e);
+ string t(XMLHelper::getAttrString(acldoc ? acldoc->getDocumentElement() : nullptr, nullptr, _type));
+ if (t.empty())
+ throw ConfigurationException("Missing type attribute in AccessControl plugin configuration.");
+ auto_ptr<AccessControl> aclplugin(SPConfig::getConfig().AccessControlManager.newPlugin(t.c_str(), acldoc->getDocumentElement()));
+ Locker acllock(aclplugin.get());
+ result = aclplugin->authorized(request, session);
+ }
+ catch (exception& ex) {
+ request.log(SPRequest::SPError, ex.what());
+ }
+
+ if (result == shib_acl_true && sta->m_dc->bRequireAll != 1) {
+ // If we're not insisting that all rules be met, then we're done.
+ request.log(SPRequest::SPDebug, "htaccess: embedded AccessControl plugin was successful, granting access");
+ return shib_acl_true;
+ }
+ else if (result != shib_acl_true && sta->m_dc->bRequireAll == 1) {
+ // If we're insisting that all rules be met, which is not something Apache really handles well,
+ // then we either return false or indeterminate based on the authoritative option, which defaults on.
+ if (sta->m_dc->bAuthoritative != 0) {
+ request.log(SPRequest::SPDebug, "htaccess: embedded AccessControl plugin was unsuccessful, denying access");
+ return shib_acl_false;
+ }
+
+ request.log(SPRequest::SPDebug, "htaccess: embedded AccessControl plugin was unsuccessful but not authoritative, leaving it up to Apache");
+ return shib_acl_indeterminate;
+ }
+ }
+
+
require_line* reqs=(require_line*)reqs_arr->elts;
for (int x=0; x<reqs_arr->nelts; x++) {
if (!strcasecmp(w,"shibboleth")) {
// This is a dummy rule needed because Apache conflates authn and authz.
// Without some require rule, AuthType is ignored and no check_user hooks run.
- status = true; // treat it as an "accepted" rule
+
+ // We evaluate to false if ShibAccessControl is used and ShibRequireAll is off.
+ // This allows actual rules to dictate the result, since ShibAccessControl returned
+ // non-true, and if nothing else is used, access will be denied.
+ if (!sta->m_dc->szAccessControl || sta->m_dc->bRequireAll == 1) {
+ // We evaluate to true, because ShibRequireAll is enabled (so a true is just a no-op)
+ // or because there was no other AccessControl rule in place, so this may be the only
+ // rule in effect.
+ status = true;
+ }
}
else if (!strcmp(w,"valid-user") && session) {
request.log(SPRequest::SPDebug, "htaccess: accepting valid-user based on active session");
status = true;
}
else if (!strcmp(w,"user") && !remote_user.empty()) {
- bool regexp=false,negate=false;
+ bool regexp = false;
while (*t) {
- w=ap_getword_conf(sta->m_req->pool,&t);
- if (*w=='~') {
- regexp=true;
+ w = ap_getword_conf(sta->m_req->pool,&t);
+ if (*w == '~') {
+ regexp = true;
continue;
}
- else if (*w=='!') {
- negate=true;
- if (*(w+1)=='~')
- regexp=true;
+ else if (*w == '!') {
+ // A negated rule presumes success unless a match is found.
+ status = true;
+ if (*(w+1) == '~')
+ regexp = true;
continue;
}
string("htaccess plugin caught exception while parsing regular expression (") + w + "): " + tmp.get());
}
}
- else if (remote_user==w) {
+ else if (remote_user == w) {
match = true;
}
if (match) {
- // If we matched, then we're done with this rule either way and status is set to reflect the outcome.
- status = !negate;
+ // If we matched, then we're done with this rule either way and we flip status to reflect the outcome.
+ status = !status;
if (request.isPriorityEnabled(SPRequest::SPDebug))
request.log(SPRequest::SPDebug,
- string("htaccess: require user ") + (negate ? "rejecting (" : "accepting (") + remote_user + ")");
+ string("htaccess: require user ") + (!status ? "rejecting (" : "accepting (") + remote_user + ")");
break;
}
}
}
else if (!strcmp(w,"group") && !remote_user.empty()) {
- SH_AP_TABLE* grpstatus=nullptr;
+ SH_AP_TABLE* grpstatus = nullptr;
if (sta->m_dc->szAuthGrpFile) {
if (request.isPriorityEnabled(SPRequest::SPDebug))
request.log(SPRequest::SPDebug,string("htaccess plugin using groups file: ") + sta->m_dc->szAuthGrpFile);
- grpstatus=groups_for_user(sta->m_req,remote_user.c_str(),sta->m_dc->szAuthGrpFile);
+ grpstatus = groups_for_user(sta->m_req,remote_user.c_str(),sta->m_dc->szAuthGrpFile);
}
- bool negate=false;
while (*t) {
- w=ap_getword_conf(sta->m_req->pool,&t);
- if (*w=='!') {
- negate=true;
+ w = ap_getword_conf(sta->m_req->pool,&t);
+ if (*w == '!') {
+ // A negated rule presumes success unless a match is found.
+ status = true;
continue;
}
if (grpstatus && ap_table_get(grpstatus,w)) {
- // If we matched, then we're done with this rule either way and status is set to reflect the outcome.
- status = !negate;
- request.log(SPRequest::SPDebug, string("htaccess: require group ") + (negate ? "rejecting (" : "accepting (") + w + ")");
+ // If we matched, then we're done with this rule either way and we flip status to reflect the outcome.
+ status = !status;
+ request.log(SPRequest::SPDebug, string("htaccess: require group ") + (!status ? "rejecting (" : "accepting (") + w + ")");
break;
}
}
}
else if (!strcmp(w,"authnContextClassRef") || !strcmp(w,"authnContextDeclRef")) {
const char* ref = !strcmp(w,"authnContextClassRef") ? session->getAuthnContextClassRef() : session->getAuthnContextDeclRef();
- bool regexp=false,negate=false;
- while (ref && *t) {
- w=ap_getword_conf(sta->m_req->pool,&t);
- if (*w=='~') {
- regexp=true;
- continue;
- }
- else if (*w=='!') {
- negate=true;
- if (*(w+1)=='~')
+ if (ref && *ref) {
+ bool regexp = false;
+ while (ref && *t) {
+ w = ap_getword_conf(sta->m_req->pool,&t);
+ if (*w == '~') {
regexp=true;
- continue;
- }
+ continue;
+ }
+ else if (*w == '!') {
+ // A negated rule presumes success unless a match is found.
+ status = true;
+ if (*(w+1)=='~')
+ regexp = true;
+ continue;
+ }
- // Figure out if there's a match.
- bool match = false;
- if (regexp) {
- try {
- // To do regex matching, we have to convert from UTF-8.
- RegularExpression re(w);
- match = re.matches(ref);
+ // Figure out if there's a match.
+ bool match = false;
+ if (regexp) {
+ try {
+ // To do regex matching, we have to convert from UTF-8.
+ RegularExpression re(w);
+ match = re.matches(ref);
+ }
+ catch (XMLException& ex) {
+ auto_ptr_char tmp(ex.getMessage());
+ request.log(SPRequest::SPError,
+ string("htaccess plugin caught exception while parsing regular expression (") + w + "): " + tmp.get());
+ }
}
- catch (XMLException& ex) {
- auto_ptr_char tmp(ex.getMessage());
- request.log(SPRequest::SPError,
- string("htaccess plugin caught exception while parsing regular expression (") + w + "): " + tmp.get());
+ else if (!strcmp(w,ref)) {
+ match = true;
}
- }
- else if (!strcmp(w,ref)) {
- match = true;
- }
- if (match) {
- // If we matched, then we're done with this rule either way and status is set to reflect the outcome.
- status = !negate;
- if (request.isPriorityEnabled(SPRequest::SPDebug))
- request.log(SPRequest::SPDebug,
- string("htaccess: require authnContext ") + (negate ? "rejecting (" : "accepting (") + ref + ")");
- break;
+ if (match) {
+ // If we matched, then we're done with this rule either way and we flip status to reflect the outcome.
+ status = !status;
+ if (request.isPriorityEnabled(SPRequest::SPDebug))
+ request.log(SPRequest::SPDebug,
+ string("htaccess: require authnContext ") + (!status ? "rejecting (" : "accepting (") + ref + ")");
+ break;
+ }
}
}
+ else if (request.isPriorityEnabled(SPRequest::SPDebug)) {
+ request.log(SPRequest::SPDebug, "htaccess: require authnContext rejecting session with no context associated");
+ }
}
else if (!session) {
request.log(SPRequest::SPError, string("htaccess: require ") + w + " not given a valid session, are you using lazy sessions?");
// Initial look at a request - create the per-request structure
static int shib_post_read(request_rec *r)
{
- shib_request_config* rc = init_request_config(r);
+ init_request_config(r);
//ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r), "shib_post_read");
return DECLINED;
}
throw runtime_error("unknown error");
}
catch (exception& ex) {
- ap_log_error(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,SH_AP_R(s),ex.what());
+ ap_log_error(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,SH_AP_R(s),"%s",ex.what());
ap_log_error(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,SH_AP_R(s),"shib_child_init() failed to load configuration");
exit(1);
}
{"ShibRequestSetting", (config_fn_t)shib_table_set, nullptr,
OR_AUTHCFG, TAKE2, "Set arbitrary Shibboleth request property for content"},
+ {"ShibAccessControl", (config_fn_t)ap_set_string_slot,
+ (void *) XtOffsetOf (shib_dir_config, szAccessControl),
+ OR_AUTHCFG, TAKE1, "Set arbitrary Shibboleth access control plugin for content"},
+
{"ShibDisable", (config_fn_t)ap_set_flag_slot,
(void *) XtOffsetOf (shib_dir_config, bOff),
OR_AUTHCFG, FLAG, "Disable all Shib module activity here to save processing effort"},
AP_INIT_TAKE2("ShibRequestSetting", (config_fn_t)shib_table_set, nullptr,
OR_AUTHCFG, "Set arbitrary Shibboleth request property for content"),
+ AP_INIT_TAKE1("ShibAccessControl", (config_fn_t)ap_set_string_slot,
+ (void *) offsetof (shib_dir_config, szAccessControl),
+ OR_AUTHCFG, "Set arbitrary Shibboleth access control plugin for content"),
+
AP_INIT_FLAG("ShibDisable", (config_fn_t)ap_set_flag_slot,
(void *) offsetof (shib_dir_config, bOff),
OR_AUTHCFG, "Disable all Shib module activity here to save processing effort"),