summaryrefslogtreecommitdiffstats
path: root/sca-cpp/trunk/modules/http/mod-openauth.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sca-cpp/trunk/modules/http/mod-openauth.cpp')
-rw-r--r--sca-cpp/trunk/modules/http/mod-openauth.cpp189
1 files changed, 118 insertions, 71 deletions
diff --git a/sca-cpp/trunk/modules/http/mod-openauth.cpp b/sca-cpp/trunk/modules/http/mod-openauth.cpp
index b1aabd73fe..2e308ecedb 100644
--- a/sca-cpp/trunk/modules/http/mod-openauth.cpp
+++ b/sca-cpp/trunk/modules/http/mod-openauth.cpp
@@ -44,6 +44,7 @@
#include "http.hpp"
#include "openauth.hpp"
+
extern "C" {
extern module AP_MODULE_DECLARE_DATA mod_tuscany_openauth;
}
@@ -64,6 +65,20 @@ public:
};
/**
+ * Authentication provider configuration.
+ */
+class AuthnProviderConf {
+public:
+ AuthnProviderConf() : name(), provider(NULL) {
+ }
+ AuthnProviderConf(const string name, const authn_provider* provider) : name(name), provider(provider) {
+ }
+
+ string name;
+ const authn_provider* provider;
+};
+
+/**
* Directory configuration.
*/
class DirConf {
@@ -75,6 +90,7 @@ public:
const char* dir;
bool enabled;
string login;
+ list<AuthnProviderConf> apcs;
};
#ifdef WANT_MAINTAINER_LOG
@@ -101,10 +117,39 @@ const bool debugSession(request_rec* r, session_rec* z) {
#endif
/**
+ * Run the authnz hooks to authenticate a request.
+ */
+const failable<int> checkAuthnzProviders(const string& user, const string& pw, request_rec* r, const list<AuthnProviderConf>& apcs) {
+ if (isNil(apcs))
+ return mkfailure<int>("Authentication failure for: " + user);
+ const AuthnProviderConf apc = car<AuthnProviderConf>(apcs);
+ if (apc.provider == NULL || !apc.provider->check_password)
+ return checkAuthnzProviders(user, pw, r, cdr(apcs));
+
+ apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, c_str(apc.name));
+ const authn_status auth_result = apc.provider->check_password(r, c_str(user), c_str(pw));
+ apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE);
+ if (auth_result != AUTH_GRANTED)
+ return checkAuthnzProviders(user, pw, r, cdr(apcs));
+ return OK;
+}
+
+const failable<int> checkAuthnz(const string& user, const string& pw, request_rec* r, const DirConf& dc) {
+ if (substr(user, 0, 1) == "/" && pw == "password")
+ return mkfailure<int>(string("Encountered FakeBasicAuth spoof: ") + user, HTTP_UNAUTHORIZED);
+
+ if (isNil(dc.apcs)) {
+ const authn_provider* provider = (const authn_provider*)ap_lookup_provider(AUTHN_PROVIDER_GROUP, AUTHN_DEFAULT_PROVIDER, AUTHN_PROVIDER_VERSION);
+ return checkAuthnzProviders(user, pw, r, mklist<AuthnProviderConf>(AuthnProviderConf(AUTHN_DEFAULT_PROVIDER, provider)));
+ }
+ return checkAuthnzProviders(user, pw, r, dc.apcs);
+}
+
+/**
* Return the user info from a form auth encrypted session cookie.
*/
static int (*ap_session_load_fn) (request_rec * r, session_rec ** z) = NULL;
-static void (*ap_session_get_fn) (request_rec * r, session_rec * z, const char *key, const char **value) = NULL;
+static int (*ap_session_get_fn) (request_rec * r, session_rec * z, const char *key, const char **value) = NULL;
const failable<value> userInfoFromSession(const string& realm, request_rec* r) {
debug("modopenauth::userInfoFromSession");
@@ -186,36 +231,23 @@ const failable<int> authenticated(const list<list<value> >& info, request_rec* r
}
/**
- * Run the authnz hooks to try to authenticate a request.
- */
-const failable<int> checkAuthnz(const string& user, const string& pw, request_rec* r) {
- const authn_provider* provider = (const authn_provider*)ap_lookup_provider(AUTHN_PROVIDER_GROUP, AUTHN_DEFAULT_PROVIDER, AUTHN_PROVIDER_VERSION);
- if (!provider || !provider->check_password)
- return mkfailure<int>("No Authn provider configured");
- apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, AUTHN_DEFAULT_PROVIDER);
- const authn_status auth_result = provider->check_password(r, c_str(user), c_str(pw));
- apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE);
- if (auth_result != AUTH_GRANTED)
- return mkfailure<int>("Authentication failure for: " + user);
- return OK;
-}
-
-/**
* Check user authentication.
*/
static int checkAuthn(request_rec *r) {
+ gc_scoped_pool pool(r->pool);
+
// Decline if we're not enabled or AuthType is not set to Open
const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_openauth);
if (!dc.enabled)
return DECLINED;
const char* atype = ap_auth_type(r);
- debug(atype, "modopenauth::checkAuthn::auth_type");
if (atype == NULL || strcasecmp(atype, "Open"))
return DECLINED;
-
- // Create a scoped memory pool
- gc_scoped_pool pool(r->pool);
debug_httpdRequest(r, "modopenauth::checkAuthn::input");
+ debug(atype, "modopenauth::checkAuthn::auth_type");
+
+ // Get the request args
+ const list<list<value> > args = httpd::queryArgs(r);
// Get session id from the request
const maybe<string> sid = sessionID(r, "TuscanyOpenAuth");
@@ -231,17 +263,17 @@ static int checkAuthn(request_rec *r) {
return httpd::reportStatus(mkfailure<int>("Missing AuthName"));
// Extract user info from the session id
- const failable<value> info = userInfoFromCookie(content(sid), aname, r);
- if (hasContent(info)) {
+ const failable<value> userinfo = userInfoFromCookie(content(sid), aname, r);
+ if (hasContent(userinfo)) {
// Try to authenticate the request
- const value uinfo = content(info);
- const failable<int> authz = checkAuthnz(cadr(assoc<value>("id", uinfo)), cadr(assoc<value>("password", uinfo)), r);
+ const value uinfo = content(userinfo);
+ const failable<int> authz = checkAuthnz(cadr(assoc<value>("id", uinfo)), cadr(assoc<value>("password", uinfo)), r, dc);
if (!hasContent(authz)) {
// Authentication failed, redirect to login page
r->ap_auth_type = const_cast<char*>(atype);
- return httpd::reportStatus(login(dc.login, r));
+ return httpd::reportStatus(login(dc.login, value(), 1, r));
}
// Successfully authenticated, store the user info in the request
@@ -265,12 +297,12 @@ static int checkAuthn(request_rec *r) {
// Try to authenticate the request
const value uinfo = content(info);
- const failable<int> authz = checkAuthnz(cadr(assoc<value>("id", uinfo)), cadr(assoc<value>("password", uinfo)), r);
+ const failable<int> authz = checkAuthnz(cadr(assoc<value>("id", uinfo)), cadr(assoc<value>("password", uinfo)), r, dc);
if (!hasContent(authz)) {
// Authentication failed, redirect to login page
r->ap_auth_type = const_cast<char*>(atype);
- return httpd::reportStatus(login(dc.login, r));
+ return httpd::reportStatus(login(dc.login, value(), 1, r));
}
// Successfully authenticated, store the user info in the request
@@ -279,9 +311,6 @@ static int checkAuthn(request_rec *r) {
}
}
- // Get the request args
- const list<list<value> > args = httpd::queryArgs(r);
-
// Decline if the request is for another authentication provider
if (!isNil(assoc<value>("openid_identifier", args)))
return DECLINED;
@@ -291,57 +320,59 @@ static int checkAuthn(request_rec *r) {
hasContent(sessionID(r, "TuscanyOAuth1")) ||
hasContent(sessionID(r, "TuscanyOAuth2")))
return DECLINED;
+
r->ap_auth_type = const_cast<char*>(atype);
- return httpd::reportStatus(login(dc.login, r));
+ return httpd::reportStatus(login(dc.login, value(), value(), r));
}
/**
- * Fixup cache control.
+ * Save the auth session cookie in the response.
*/
-bool filterCacheControl(const string& tok) {
- return tok != "no-cache";
+static int sessionCookieSave(request_rec* r, session_rec* z) {
+ gc_scoped_pool pool(r->pool);
+
+ const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_openauth);
+ if (!dc.enabled)
+ return DECLINED;
+
+ debug(c_str(cookie("TuscanyOpenAuth", z->encoded, httpd::hostName(r))), "modopenauth::setcookie");
+ apr_table_set(r->err_headers_out, "Set-Cookie", c_str(cookie("TuscanyOpenAuth", z->encoded, httpd::hostName(r))));
+ return OK;
}
-static apr_status_t outputFilter(ap_filter_t * f, apr_bucket_brigade * in) {
- request_rec *r = f->r->main;
- if (!r)
- r = f->r;
- for (; r != NULL; r = r->next) {
- if (r->status != HTTP_OK && r->status != HTTP_NOT_MODIFIED) {
-
- // Don't cache errors and redirects
- debug("no-cache", "modopenauth::outputFilter::nokCacheControl");
- apr_table_set(r->headers_out, "Cache-Control", "no-cache");
- continue;
- }
+/**
+ * Load the auth session cookie from the request. Similar
+ */
+static int sessionCookieLoad(request_rec* r, session_rec** z) {
+ gc_scoped_pool pool(r->pool);
- // Cache OK content
- const char* cc = apr_table_get(r->headers_out, "Cache-Control");
- if (cc == NULL) {
- debug("modopenauth::outputFilter::noCacheControl");
- continue;
- }
- debug(cc, "modopenauth::outputFilter::cacheControl");
- const string ncc = join(", ", filter<string>(filterCacheControl, tokenize(", ", cc)));
- if (length(ncc) == 0) {
- debug("modopenauth::outputFilter::noCacheControl");
- apr_table_unset(r->headers_out, "Cache-Control");
- continue;
- }
+ const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_openauth);
+ if (!dc.enabled)
+ return DECLINED;
- debug(ncc, "modopenauth::outputFilter::okCacheControl");
- apr_table_set(r->headers_out, "Cache-Control", c_str(ncc));
+ // First look in the notes
+ const char* note = apr_pstrcat(r->pool, "mod_openauth", "TuscanyOpenAuth", NULL);
+ session_rec* zz = (session_rec*)(void*)apr_table_get(r->notes, note);
+ if (zz != NULL) {
+ *z = zz;
+ return OK;
}
- ap_remove_output_filter(f);
- return ap_pass_brigade(f->next, in);
-}
+ // Parse the cookie
+ const maybe<string> sid = openauth::sessionID(r, "TuscanyOpenAuth");
-/**
- * Insert our cache control output filter.
- */
-static void insertOutputFilter(request_rec * r) {
- ap_add_output_filter("mod_openauth", NULL, r, r->connection);
+ // Create a new session
+ zz = (session_rec*)apr_pcalloc(r->pool, sizeof(session_rec));
+ zz->pool = r->pool;
+ zz->entries = apr_table_make(r->pool, 10);
+ zz->encoded = hasContent(sid)? c_str(content(sid)) : NULL;
+ zz->uuid = (apr_uuid_t *) apr_pcalloc(r->pool, sizeof(apr_uuid_t));
+ *z = zz;
+
+ // Store it in the notes
+ apr_table_setn(r->notes, note, (char*)zz);
+
+ return OK;
}
/**
@@ -357,6 +388,7 @@ int postConfigMerge(ServerConf& mainsc, server_rec* s) {
int postConfig(apr_pool_t* p, unused apr_pool_t* plog, unused apr_pool_t* ptemp, server_rec* s) {
gc_scoped_pool pool(p);
+
ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_openauth);
debug(httpd::serverName(s), "modopenauth::postConfig::serverName");
@@ -369,6 +401,7 @@ int postConfig(apr_pool_t* p, unused apr_pool_t* plog, unused apr_pool_t* ptemp,
*/
void childInit(apr_pool_t* p, server_rec* s) {
gc_scoped_pool pool(p);
+
ServerConf* psc = (ServerConf*)ap_get_module_config(s->module_config, &mod_tuscany_openauth);
if(psc == NULL) {
cfailure << "[Tuscany] Due to one or more errors mod_tuscany_openauth loading failed. Causing apache to stop loading." << endl;
@@ -395,11 +428,25 @@ const char* confLogin(cmd_parms *cmd, void *c, const char* arg) {
dc.login = arg;
return NULL;
}
+const char* confAuthnProvider(cmd_parms *cmd, void *c, const char* arg) {
+ gc_scoped_pool pool(cmd->pool);
+ DirConf& dc = httpd::dirConf<DirConf>(c);
+
+ // Lookup and cache the Authn provider
+ const authn_provider* provider = (authn_provider*)ap_lookup_provider(AUTHN_PROVIDER_GROUP, arg, AUTHN_PROVIDER_VERSION);
+ if (provider == NULL)
+ return apr_psprintf(cmd->pool, "Unknown Authn provider: %s", arg);
+ if (!provider->check_password)
+ return apr_psprintf(cmd->pool, "The '%s' Authn provider doesn't support password authentication", arg);
+ dc.apcs = append<AuthnProviderConf>(dc.apcs, mklist<AuthnProviderConf>(AuthnProviderConf(arg, provider)));
+ return NULL;
+}
/**
* HTTP server module declaration.
*/
const command_rec commands[] = {
+ AP_INIT_ITERATE("AuthOpenAuthProvider", (const char*(*)())confAuthnProvider, NULL, OR_AUTHCFG, "Auth providers for a directory or location"),
AP_INIT_FLAG("AuthOpenAuth", (const char*(*)())confEnabled, NULL, OR_AUTHCFG, "Tuscany Open Auth authentication On | Off"),
AP_INIT_TAKE1("AuthOpenAuthLoginPage", (const char*(*)())confLogin, NULL, OR_AUTHCFG, "Tuscany Open Auth login page"),
{NULL, NULL, NULL, 0, NO_ARGS, NULL}
@@ -409,8 +456,8 @@ void registerHooks(unused apr_pool_t *p) {
ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_child_init(childInit, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_check_authn(checkAuthn, NULL, NULL, APR_HOOK_MIDDLE, AP_AUTH_INTERNAL_PER_CONF);
- ap_register_output_filter("mod_openauth", outputFilter, NULL, AP_FTYPE_CONTENT_SET);
- ap_hook_insert_filter(insertOutputFilter, NULL, NULL, APR_HOOK_LAST);
+ ap_hook_session_load(sessionCookieLoad, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_session_save(sessionCookieSave, NULL, NULL, APR_HOOK_MIDDLE);
}
}