From 4bf87cb9f4f6b9812c06a8d2c500869c48ebc2dc Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Thu, 18 Jun 2009 17:12:22 +0000 Subject: Complete almost all code, compiles. --- module/Makefile.am | 5 +- module/consumer.cc | 198 +++++-- module/consumer.h | 18 - module/mod_auth_singleid.c | 1333 +++++++------------------------------------- module/mod_auth_singleid.h | 81 +++ module/request.h | 16 - module/storage.c | 156 +++--- module/storage.h | 34 -- 8 files changed, 516 insertions(+), 1325 deletions(-) delete mode 100644 module/consumer.h create mode 100644 module/mod_auth_singleid.h delete mode 100644 module/request.h delete mode 100644 module/storage.h (limited to 'module') diff --git a/module/Makefile.am b/module/Makefile.am index f2b92ca..cb4d829 100644 --- a/module/Makefile.am +++ b/module/Makefile.am @@ -6,8 +6,9 @@ AM_LDFLAGS = ${OPKELE_LIBS} libmodauthsingleid_la_SOURCES = \ mod_auth_singleid.c \ - consumer.cc consumer.h \ - storage.c storage.h + mod_auth_singleid.h \ + storage.c \ + consumer.cc install-exec-local: @APXS@ -i -a -n 'auth_singleid' mod_auth_singleid.la diff --git a/module/consumer.cc b/module/consumer.cc index 15eadc8..91ab773 100644 --- a/module/consumer.cc +++ b/module/consumer.cc @@ -1,35 +1,77 @@ -#include "consumer.h" +#include "mod_auth_singleid.h" + +#include +#include +#include +#include +#include using opkele::assoc_t; using opkele::association; -using opkele::endpoint_t; +using opkele::bad_input; +using opkele::dumb_RP; +using opkele::exception; +using opkele::failed_discovery; using opkele::failed_lookup; -using opkele::params; +using opkele::failed_xri_resolution; +using opkele::no_endpoint; +using opkele::openid_endpoint_t; +using opkele::openid_message_t; +using opkele::params_t; using opkele::prequeue_RP; using opkele::secret_t; using std::string; using std::vector; +class LockShared +{ +public: + LockShared() + { sid_shared_lock (); } + ~LockShared() + { sid_shared_unlock (); } +}; + +class AdaptorFix : + public params_t +{ +public: + AdaptorFix(params_t& params) + { _params = params; }; + virtual bool has_field(const string& n) const + { return _params.has_param("openid." + n); } + virtual const string& get_field(const string& n) const + { return _params.get_param("openid." + n); } +private: + params_t _params; +}; + + class Consumer : public prequeue_RP { private: // types - vector endpoints; + typedef vector endpoints; public: // interface - Consumer(const char *url, singleid_board_t *board) - : _url(url), _board(board) + Consumer(const char *url, sid_storage_t *store) + : _url(url), _store(store), _index(0) { } public: // overrides - virtual void begin_queueing() const - { _endpoints.clear(); } + virtual void begin_queueing() + { _endpoints.clear(); _index = 0; } virtual void queue_endpoint(const openid_endpoint_t& oep) - { _endpoints.push(oep); } + { _endpoints.push_back(oep); } + + virtual const openid_endpoint_t& get_endpoint() const; + + virtual void next_endpoint() + { _index++; } virtual void set_normalized_id(const string& nid) { _normalized = nid; } @@ -37,7 +79,7 @@ public: // overrides virtual const string get_normalized_id() const { return _normalized; } - virtual const string get_this_url() + virtual const string get_this_url() const { return _url; } virtual assoc_t store_assoc(const string& server, const string& handle, @@ -48,25 +90,37 @@ public: // overrides virtual assoc_t retrieve_assoc(const string& server, const string& handle); - virtual assoc_t invalidate_assoc(const string& server, const string& handle); + virtual void invalidate_assoc(const string& server, const string& handle); virtual void check_nonce(const string& server, const string& nonce); private: // data - singleid_board_t _board; + sid_storage_t *_store; endpoints _endpoints; string _normalized; string _url; + endpoints::size_type _index; }; +const openid_endpoint_t& +Consumer::get_endpoint() const +{ + if (_index >= _endpoints.size()) + throw no_endpoint("no more endpoints"); + return _endpoints[_index]; +} + assoc_t Consumer::store_assoc(const string& server, const string& handle, const string& type, const secret_t& secret, int expires_in) { - singleid_assoc_t data; + sid_assoc_t data; int res; + if (!_store) + throw dumb_RP("no storage initialized"); + data.server = server.c_str(); data.handle = handle.c_str(); data.type = type.c_str(); @@ -76,27 +130,32 @@ Consumer::store_assoc(const string& server, const string& handle, { LockShared lock; /* scoped lock */ - res = singleid_board_store_assoc (_board, &data); + res = sid_storage_store_assoc (_store, &data); } if (!res) - throw dump_RP("association data was too large to fit in shared storage"); + throw dumb_RP("association data was too large to fit in shared storage"); - return assoc_t(new association(server, handle, type, secret, expires_on, false)); + return assoc_t(new association(server, handle, type, secret, expires_in, false)); } assoc_t Consumer::find_assoc(const string& server) { - singleid_assoc_t data = { 0, }; - association assoc = NULL; + sid_assoc_t data = { 0, }; + association *assoc = NULL; + + if (!_store) + throw dumb_RP("no storage initialized"); { LockShared lock; - if (singleid_board_find_assoc (_board, server.c_str(), NULL, &data)) + if (sid_storage_find_assoc (_store, server.c_str(), NULL, &data)) { + secret_t secret; + secret.assign(data.secret, data.secret + data.n_secret); assoc = new association(data.server, data.handle, data.type, - secret_t(data.secret, data.secret + data.n_secret), - data.expires, false); + secret, data.expires, false); + } } if (!assoc) @@ -108,15 +167,20 @@ Consumer::find_assoc(const string& server) assoc_t Consumer::retrieve_assoc(const string& server, const string& handle) { - singleid_assoc_t data = { 0, }; - association assoc = NULL; + sid_assoc_t data = { 0, }; + association *assoc = NULL; + + if (!_store) + throw dumb_RP("no storage initialized"); { LockShared lock; - if (singleid_board_find_assoc (_board, server.c_str(), handle.c_str(), &data)) + if (sid_storage_find_assoc (_store, server.c_str(), handle.c_str(), &data)) { + secret_t secret; + secret.assign(data.secret, data.secret + data.n_secret); assoc = new association(data.server, data.handle, data.type, - secret_t(data.secret, data.secret + data.n_secret), - data.expires, false); + secret, data.expires, false); + } } if (!assoc) @@ -125,19 +189,24 @@ Consumer::retrieve_assoc(const string& server, const string& handle) return assoc_t(assoc); } -assoc_t +void Consumer::invalidate_assoc(const string& server, const string& handle) { + if (!_store) + throw dumb_RP("no storage initialized"); + LockShared lock; - singleid_board_invalidate_assoc (_board, server.c_str(), handle.c_str()); + sid_storage_invalidate_assoc (_store, server.c_str(), handle.c_str()); } - void Consumer::check_nonce(const string& server, const string& nonce) { + if (!_store) + throw dumb_RP("no storage initialized"); + LockShared lock; - singleid_board_check_nonce (_board, server.c_str(), nonce.c_str()); + sid_storage_check_nonce (_store, server.c_str(), nonce.c_str()); } /* ----------------------------------------------------------------------- @@ -145,17 +214,13 @@ Consumer::check_nonce(const string& server, const string& nonce) */ static void -filter_openid_params (params_t ¶ms, params_t &extensions) +filter_openid_params (params_t ¶ms) { for (params_t::iterator it = params.begin(); it != params.end(); ) { const string& name = it->first; if (name.find ("openid.") == 0) { - /* Extension params have at least a second dot */ - if (name.find ('.', sizeof ("openid."))) - extensions.insert(*it); - /* We erase an increment together, must use post-increment operator */ - it->erase(it++); + params.erase (it++); } else { /* Did not match, just go to next element */ ++it; @@ -164,7 +229,32 @@ filter_openid_params (params_t ¶ms, params_t &extensions) } static void -start_auth (sid_request_t *req, Consumer &consumer, params_t ¶ms, +parse_query_string (const char *qs, params_t ¶ms) +{ + string pair, key, value; + const char *at; + + while (qs && *qs) { + at = strchr (qs, '&'); + if (at == NULL) + at = qs + strlen (qs); + pair = string(qs, at); + string::size_type loc = pair.find('=', 0); + if (loc != string::npos) { + key = pair.substr (0, loc); + value = pair.substr (loc + 1); + } else { + key = pair; + value = ""; + } + + params[opkele::util::url_decode(key)] = opkele::util::url_decode(value); + qs = at; + } +} + +static void +begin_auth (sid_request_t *req, Consumer &consumer, params_t ¶ms, const string& trust_root, const string &identity) { /* Remove all openid params, and stash away extensions */ @@ -172,32 +262,43 @@ start_auth (sid_request_t *req, Consumer &consumer, params_t ¶ms, string return_to = params.append_query (consumer.get_this_url(), ""); params_t result; + string redirect; try { openid_message_t cm; consumer.initiate (identity); - result = consumer.checkid_ (cm, opkele::mode_checkid_setup, return_to, trust_root); - output = result.append_query (consumer.get_endpoint().uri); + consumer.checkid_ (cm, opkele::mode_checkid_setup, return_to, trust_root); + redirect = cm.append_query (consumer.get_endpoint().uri); } catch (failed_xri_resolution &ex) { - sid_request_respond (xxx, xxx, xxx); + sid_request_respond (req, 503, "Invalid Identifier", NULL, NULL); + sid_request_log_error (req, "failed xri resolution while while discovering identity provider", + ex.what ()); return; } catch (failed_discovery &ex) { - sid_request_respond (xxx, xxx, xxx); + sid_request_respond (req, 503, "Invalid Identifier", NULL, NULL); + sid_request_log_error (req, "failed discovery while while discovering identity provider", + ex.what ()); return; } catch (bad_input &ex) { - sid_request_respond (xxx, xxx, xxx); + sid_request_respond (req, 503, "Invalid Identifier", NULL, NULL); + sid_request_log_error (req, "bad input while while discovering identity provider", + ex.what()); return; } catch (exception &ex) { - sid_request_respond (xxx, xxx, xxx); - xxx log xxx; + sid_request_respond (req, 500, NULL, NULL, NULL); + sid_request_log_error (req, "error while while discovering identity provider", + ex.what()); return; } - sid_request_respond (xxx, xxx, xxx); + sid_request_respond (req, 307, "Moved Temporarily", NULL, + "Location", redirect.c_str(), + "Cache-Control", "no-cache", + NULL); } static void @@ -208,14 +309,15 @@ complete_auth (sid_request_t *req, Consumer &consumer, params_t ¶ms) string identity = consumer.get_claimed_id(); sid_request_authenticated (req, identity.c_str()); } catch (exception &ex) { - sid_request_respond (xxx, xxx, xxx); + sid_request_respond (req, 500, NULL, NULL, NULL); + sid_request_log_error (req, "error while completing authentication: %s", ex.what()); } } static void cancelled_auth (sid_request_t *req, Consumer &consumer, params_t ¶ms) { - sid_request_respond (xxx, xxx, xxx); + sid_request_respond (req, 401, "Authentication Required", NULL, NULL); } void @@ -239,6 +341,4 @@ sid_consumer_authenticate(sid_request_t *req, sid_storage_t *store, cancelled_auth (req, consumer, params); else begin_auth (req, consumer, params, trust_root, identity); - - consumer.close(); } diff --git a/module/consumer.h b/module/consumer.h deleted file mode 100644 index 5cea9f8..0000000 --- a/module/consumer.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef CONSUMER_H_ -#define CONSUMER_H_ - -#include "request.h" -#include "storage.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void sid_consumer_authenticate (sid_request_t *req, sid_storage_t *store, - const char *trust_root, const char *identity); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* CONSUMER_H_ */ diff --git a/module/mod_auth_singleid.c b/module/mod_auth_singleid.c index 6085fec..3b6304a 100644 --- a/module/mod_auth_singleid.c +++ b/module/mod_auth_singleid.c @@ -36,10 +36,6 @@ * */ - -#include "consumer.h" -#include "storage.h" - #include #include @@ -49,6 +45,7 @@ #include #include #include +#include #include #include @@ -57,8 +54,6 @@ #include #include -#include - /* Apache defines these */ #undef PACKAGE_BUGREPORT #undef PACKAGE_NAME @@ -67,6 +62,9 @@ #undef PACKAGE_VERSION #include "config.h" +#include "mod_auth_singleid.h" + +#include #include extern module AP_MODULE_DECLARE_DATA auth_singleid_module; @@ -74,23 +72,24 @@ extern module AP_MODULE_DECLARE_DATA auth_singleid_module; /* * Per directory configuration. */ -typedef struct singleid_context { +typedef struct sid_context { const char *trust_root; - const char *identity; - void *shared_block; -} singleid_context_t; + const char *identifier; + sid_storage_t *store; +} sid_context_t; -#define SINGLEID_AUTHTYPE "SINGLEID" +#define SID_AUTHTYPE "SingleID" /* ------------------------------------------------------------------------------- - * SHARED MEMORY + * SHARED MEMORY and LOCKING */ static apr_global_mutex_t *shared_lock = NULL; static const char *shared_lock_name = NULL; +static size_t shared_size = 64 * 1024; static int -shared_initialize (apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) +shared_initialize (apr_pool_t *p, server_rec *s) { apr_file_t *file = NULL; const char *tmpdir; @@ -167,6 +166,9 @@ shared_create (apr_pool_t* p, size_t size) void *addr; int rc; + if (!shared_lock) + return NULL; + /* Get the temp directory */ rc = apr_temp_dir_get (&tmpdir, p); if (rc != APR_SUCCESS) { @@ -216,939 +218,100 @@ shared_create (apr_pool_t* p, size_t size) return NULL; } -/* ------------------------------------------------------------------------------------------------- - * COMMON STORAGE - */ - -typedef struct storage_context { - void* shared; - size_t size; -} storage_context_t; - -/* ------------------------------------------------------------------------------------------------- - * OPENID CONSUMER - */ - -#if 0 -static void* storage_shared = NULL; -static size_t storage_size = NULL; -#endif - -#if 0 - -static int -shared_get_if_changed (httpauth_context_t *ctx, int version, httpauth_shared_t *shared) +void +sid_shared_lock (void) { - httpauth_shared_t *block; - int ret = 0; - - if (!ctx->shared_block || !shared_lock) - return 0; - apr_global_mutex_lock (shared_lock); - - block = ctx->shared_block; - if (block->version != version) { - ret = 1; - if (shared) - memcpy (shared, block, sizeof (*shared)); - } - - apr_global_mutex_unlock (shared_lock); - - return ret; } -static void -shared_set_if_changed (httpauth_context_t *ctx, httpauth_shared_t *shared) +void +sid_shared_unlock (void) { - httpauth_shared_t *block; - - if (!ctx->shared_block || !shared_lock) - return; - - apr_global_mutex_lock (shared_lock); - - block = ctx->shared_block; - if (memcmp (shared, block, sizeof (*shared)) != 0) { - - /* Increment the version beyond all */ - if (block->version > shared->version) - shared->version = block->version; - ++shared->version; - - /* And write it out */ - memcpy (block, shared, sizeof (*shared)); - } - apr_global_mutex_unlock (shared_lock); } -#endif /* ------------------------------------------------------------------------------- - * Per Directory Config and Context Code + * CONFIGURATION */ static void* dir_config_creator (apr_pool_t* p, char* dir) { -#if 0 - httpauth_context_t* ctx; - httpauth_shared_t shared; - const char *tmpdir; - char *filename; - apr_file_t *file; - apr_mmap_t *map; - void *addr; - int rc; + sid_context_t* ctx; + void *shared; - ctx = (httpauth_context_t*)apr_pcalloc(p, sizeof(*ctx)); + ctx = (sid_context_t*)apr_pcalloc(p, sizeof(*ctx)); memset(ctx, 0, sizeof(*ctx)); - ctx->socket = -1; - ctx->types = 0xFFFFFFFF; - ctx->child_pool = p; - ctx->needed_groups = NULL; - ctx->alloced_groups = 0; - ctx->shared_version = 0; - ctx->retries = 1; + ctx->identifier = NULL; + ctx->store = NULL; + ctx->trust_root = NULL; if (!dir) return ctx; - /* Get the temp directory */ - rc = apr_temp_dir_get (&tmpdir, p); - if (rc != APR_SUCCESS) - ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL, - "httpauth: couldn't get temporary directory"); - - /* Create the shared file */ - if (rc == APR_SUCCESS) { - filename = apr_pstrcat (p, tmpdir, "/", "mod-httpauth.board.XXXXXX", NULL); - rc = apr_file_mktemp (&file, filename, 0, p); - if (rc != APR_SUCCESS) - ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL, - "httpauth: couldn't create temporary file: %s", filename); - } - - /* Write a shared block to file */ - if (rc == APR_SUCCESS) { - memset (&shared, 0, sizeof (shared)); - rc = apr_file_write_full (file, &shared, sizeof (shared), NULL); - if (rc != APR_SUCCESS) - ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL, - "httpauth: couldn't write to temporary file: %s", filename); - } - - /* Map the shared file into memory */ - if (rc == APR_SUCCESS) { - rc = apr_mmap_create (&map, file, 0, sizeof (shared), - APR_MMAP_READ | APR_MMAP_WRITE, p); - if (rc != APR_SUCCESS) - ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL, - "httpauth: couldn't map temporary file: %s", filename); - } - - /* Get the actual address of the mapping */ - if (rc == APR_SUCCESS) { - rc = apr_mmap_offset (&addr, map, 0); - if (rc != APR_SUCCESS) - ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL, - "httpauth: couldn't get shared memory"); - } - - if (rc == APR_SUCCESS) - ctx->shared_block = addr; + shared = shared_create (p, shared_size); + ctx->store = sid_storage_initialize (shared, shared_size); return ctx; -#endif - return NULL; } -#if 0 -static const char* set_socket(cmd_parms* cmd, void* config, const char* val) +static const char* +set_identifier (cmd_parms* cmd, void* config, const char* val) { - struct sockaddr_any sany; - - if (sock_any_pton_n (val, &sany, 1, DEFAULT_PORT | SANY_OPT_NORESOLV) == -1) - return "Invalid socket name or ip in HttpAuthSocket"; - - ((httpauth_context_t*)config)->socketname = val; + sid_context_t *ctx = config; + ctx->identifier = apr_pstrdup (cmd->pool, val); return NULL; } -static const char* set_handler(cmd_parms* cmd, void* config, const char* val) -{ - httpauth_context_t* conf = (httpauth_context_t*)config; - conf->handler = val; - return NULL; -} - -static const char* set_types(cmd_parms* cmd, void* config, const char* val) -{ - httpauth_context_t* conf = (httpauth_context_t*)config; - int type = 0; - - if(strcasecmp(val, AUTH_PREFIX_BASIC) == 0) - type = AUTH_TYPE_BASIC; - else if(strcasecmp(val, AUTH_PREFIX_DIGEST) == 0) - type = AUTH_TYPE_DIGEST; - else if(strcasecmp(val, AUTH_PREFIX_NTLM) == 0) - type = AUTH_TYPE_NTLM; - else if(strcasecmp(val, "any")) - type = AUTH_TYPE_ANY; - else - return "Invalid type in HttpAuthTypes"; - - if(conf->types == 0xFFFFFFFF) - conf->types = type; - else - conf->types |= type; - - return NULL; -} - -static const char* set_domain(cmd_parms* cmd, void* config, const char* val) +static const char* +set_trust_root (cmd_parms* cmd, void* config, const char* val) { - httpauth_context_t* conf = (httpauth_context_t*)config; - conf->domain = trim_space(apr_pstrdup(cmd->pool, val)); - return NULL; + sid_context_t *ctx = config; + if (!ap_is_url (val)) + return "Not a valid URL in SingleTrustRoot"; + ctx->trust_root = apr_pstrdup (cmd->pool, val); + return NULL; } -#endif -static const command_rec command_table[] = -{ -#if 0 - AP_INIT_RAW_ARGS( "HttpAuthSocket", set_socket, NULL, OR_AUTHCFG, - "The socket that httpauthd is listening on" ), - AP_INIT_TAKE1( "HttpAuthHandler", set_handler, NULL, OR_AUTHCFG, - "The handler that httpauthd should use to authenticate" ), - AP_INIT_ITERATE( "HttpAuthTypes", set_types, NULL, OR_AUTHCFG, - "The types of authentiction allowed (Basic, Digest, NTLM ...)" ), - AP_INIT_RAW_ARGS( "HttpAuthDigestDomain", set_domain, NULL, OR_AUTHCFG, - "The domain for which digest authentication is relevant" ), -#endif - { NULL } +static const command_rec command_table[] = { + AP_INIT_TAKE1( "SingleIdentifier", set_identifier, NULL, OR_AUTHCFG, + "The OpenID identifier we should perform ID selection on when authenticating" ), + AP_INIT_TAKE1( "SingleTrustRoot", set_trust_root, NULL, OR_AUTHCFG, + "The OpenID Trust Root of this site."), + { NULL } }; -#if 0 - -/* ------------------------------------------------------------------------------- - * Socket handling code +/* ------------------------------------------------------------------------------------------- + * COOKIE SESSIONS */ -static apr_status_t cleanup_socket(void *fdv) -{ - close((int)(long)fdv); - return OK; -} - -void disconnect_socket(httpauth_context_t* ctx, server_rec* s) -{ - if(ctx->socket != -1) - { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "httpauth: disconnecting from daemon"); - - apr_pool_cleanup_kill(ctx->child_pool, (void*)(long)ctx->socket, - cleanup_socket); - close(ctx->socket); - ctx->socket = -1; - - /* Make sure we send our list of groups to daemon again */ - if (ctx->needed_groups) - ctx->needed_groups[0] = 0; - } -} - -void read_junk(httpauth_context_t* ctx, request_rec* r) -{ - char buf[16]; - const char* t; - int said = 0; - int l; - - if(ctx->socket == -1) - return; - - /* Make it non blocking */ - fcntl(ctx->socket, F_SETFL, fcntl(ctx->socket, F_GETFL, 0) | O_NONBLOCK); - - for(;;) - { - l = read(ctx->socket, buf, sizeof(buf) - 1); - if(l <= 0) - break; - - buf[l] = 0; - t = trim_start(buf); - - if(!said && *t) - { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, - "httpauth: received junk data from daemon"); - said = 1; - } - } - - fcntl(ctx->socket, F_SETFL, fcntl(ctx->socket, F_GETFL, 0) & ~O_NONBLOCK); -} - -int read_line(httpauth_context_t* ctx, request_rec* r, char** line) -{ - int l; - int al = 256; - char* t; - const char* e; - - e = t = NULL; - *line = NULL; - - for(;;) - { - if(!*line || t + 2 == e) - { - char* n; - int d; - - n = (char*)apr_palloc(r->pool, al * 2); - - if(*line) - memcpy(n, *line, al); - - al *= 2; - - /* The difference */ - d = t - *line; - - *line = n; - t = n + d; - e = n + al; - } - - l = read(ctx->socket, (void*)t, sizeof(char)); - - /* We got a character */ - if(l == 1) - { - /* Skip junky CRLFs */ - if(*t == '\r') - { - *t = ' '; - continue; - } - - /* End of line */ - else if(*t == '\n') - { - t++; - break; - } - - t++; - } - - /* If it's the end of file then return that */ - else if(l == 0) - { - /* Disconnect from socket quietly so we can reconnect later */ - disconnect_socket(ctx, r->server); - return -1; - } - - /* Transient errors */ - else if(l == -1 && errno == EAGAIN) - continue; - - /* Fatal errors */ - else if(l == -1) - { - ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(errno), r, - "httpauth: couldn't read data from daemon"); - return -1; - } - } - - *t = 0; - return 0; -} - -int -read_response (httpauth_context_t *ctx, request_rec *r, - int *code, int *ccode, char **details, - int return_errors) -{ - int c, ret = -1; - char *line; - char *t; - char *t2; - - if (read_line (ctx, r, &line) == -1) - return -1; - - line = trim_space (line); - - ap_log_rerror (APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: received response line from daemon: %s", line); - - /* Get response code */ - t = ap_getword_nc (r->pool, &line, ' '); - c = strtol (t, &t2, 10); - if (*t2 || c < 100 || c > 999) { - ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: protocol error: invalid code: %s", t); - goto finally; - } - - if (code) - *code = c; - - if (c >= 400 && !return_errors) { - ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: received error from httpauthd: %d %s", c, line); - goto finally; - } - - /* Get the second response code if we're a 200 */ - if (c == 200) { - t = ap_getword_nc (r->pool, &line, ' '); - c = strtol (t, &t2, 10); - if (*t2 || c < 100 || c > 999) { - ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: protocol error: invalid code: %s", t); - goto finally; - } - - if (ccode) - *ccode = c; - } - - if (details) - *details = trim_space (line); - - ret = 0; - -finally: - if (ret < 0 && ctx->socket >= 0) { - disconnect_socket (ctx, r->server); - ++ctx->address_seed; - } - - return ret; -} - -static int -read_process_headers(httpauth_context_t* ctx, int ccode, - request_rec* r, char **groups) -{ - char* line; - const char* name; - apr_table_t* headers; - int c = 0; - - if(ccode > 299) - headers = r->err_headers_out; - else - headers = r->headers_out; - - for(;;) - { - if(read_line(ctx, r, &line) == -1) - return -1; - - /* If that's it then break */ - if(!*line) - break; - - if(apr_isspace(*line)) - { - line = (char*)trim_start(line); - - /* End of headers */ - if(!*line) - break; - - if(c > 0) - { - /* - * TODO: We really should be supporting headers split - * across lines. But httpauthd doesn't currently produce - * headers like that, so we don't need to care about it. - */ - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, - "httpauth: protocol error: server sent us an split header, which we don't support."); - } - else - { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: protocol error: invalid headers."); - } - } - - name = ap_getword_nc(r->pool, &line, ':'); - if(!name || !*name) - break; - - /* - * If that was the end of the line, then it's an - * invalid header :( - */ - if(!*line) - { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: protocol header: invalid headers"); - return -1; - } - - line = trim_space(line); - - if(strcasecmp(name, "WWW-Authenticate") == 0) - { - if(strncasecmp(line, AUTH_PREFIX_BASIC, strlen(AUTH_PREFIX_BASIC)) == 0 && - !(ctx->types & AUTH_TYPE_BASIC)) - continue; - - else if(strncasecmp(line, AUTH_PREFIX_DIGEST, strlen(AUTH_PREFIX_DIGEST)) == 0 && - !(ctx->types & AUTH_TYPE_DIGEST)) - continue; - - /* Only allow unknown if we don't have it */ - else if(!(ctx->types & AUTH_TYPE_ANY)) - continue; - - /* Fix up when we're a proxy */ - if(r->proxyreq == PROXYREQ_PROXY) - name = "Proxy-Authenticate"; - } - - else if(strcasecmp(name, "Authentication-Info") == 0) - { - if(r->proxyreq == PROXYREQ_PROXY) - name = "Proxy-Authentication-Info"; - } - - else if (strcasecmp(name, "X-HttpAuth-Groups") == 0) - { - if (groups && line) - *groups = line; - } - - c++; - apr_table_addn(headers, name, line); - } - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: received %d headers from daemon", c); - - return 0; -} - -int write_data(httpauth_context_t* ctx, server_rec* s, const char* data) -{ - int r; - - if(ctx->socket == -1) - { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "httpauth: Socket to httpauthd daemon closed. Can't write data."); - return -1; - } - - while(*data != 0) - { - r = write(ctx->socket, data, strlen(data)); - - if(r > 0) - data += r; - - else if(r == -1) - { - if(errno == EAGAIN) - continue; - - /* The other end closed. no message */ - if(errno == EPIPE) - disconnect_socket(ctx, s); - - else - ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(errno), s, - "httpauth: Couldn't write data to daemon"); - - return -1; - } - } - - return 0; -} - -static int -try_connect_socket (httpauth_context_t *ctx, struct sockaddr_any *sany, - request_rec *r) -{ - char peername[256]; - int rc; - - if (sock_any_ntop (sany, peername, sizeof (peername), 0) < 0) - strcpy (peername, "[unknown]"); - - ctx->socket = socket (SANY_TYPE (*sany), SOCK_STREAM, 0); - if(ctx->socket == -1) { - ap_log_rerror (APLOG_MARK, APLOG_CRIT, APR_FROM_OS_ERROR (errno), r, - "httpauth: Can't create socket"); - return -1; - } - - if (connect (ctx->socket, &SANY_ADDR (*sany), SANY_LEN(*sany)) != 0) { - rc = APR_FROM_OS_ERROR (errno); - ap_log_rerror (APLOG_MARK, APLOG_CRIT, rc, r, - "httpauth: Can't connect to httpauthd at: %s", peername); - close (ctx->socket); - ctx->socket = -1; - return -1; - } - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: connected to daemon: %s", peername); - - return 0; -} - -static int -connect_socket(httpauth_context_t* ctx, request_rec* r) -{ - httpauth_shared_t shared; - struct sockaddr_any sany[16]; - int i, which, count = 0; - int rc = -1; - - disconnect_socket(ctx, r->server); - memset (&shared, 0, sizeof (shared)); - - /* Find out what everyone else is connected to */ - if (shared_get_if_changed (ctx, ctx->shared_version, &shared) && shared.version > 0) { - ap_log_rerror (APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: trying shared address..."); - rc = try_connect_socket (ctx, &shared.address, r); - } - - /* Now try to connect to all the other addresses */ - if (rc < 0) { - ap_log_rerror (APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: resolving daemon address(s)"); - - count = sock_any_pton_n (ctx->socketname, sany, 16, DEFAULT_PORT); - if (count < 0) { - ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, - "httpauth: Invalid socket name or ip: %s", ctx->socketname); - rc = -1; - } - - /* We know how many addresses we have to retry with */ - if (count > 0) - ctx->retries = count; - - for (i = 0; i != count; ++i) { - which = (i + ctx->address_seed) % count; - rc = try_connect_socket (ctx, &sany[which], r); - - /* Successful, then let others know we're connected here */ - if (rc >= 0) { - memcpy (&shared.address, &sany[which], sizeof (shared.address)); - break; - } - } - } - - /* Yay, successful */ - if (rc >= 0) { - shared_set_if_changed (ctx, &shared); - ctx->shared_version = shared.version; - apr_pool_cleanup_register(ctx->child_pool, (void*)(long)ctx->socket, - cleanup_socket, cleanup_socket); - errno = 0; - } - - return rc; -} - -int connect_httpauth(httpauth_context_t* ctx, request_rec* r) -{ - int ret = -1; - int code; - char* details; - const char* t; - - if(connect_socket(ctx, r) == -1) - goto finally; - - if(read_response(ctx, r, &code, NULL, &details, 0) == -1) - goto finally; - - if(code != 100) - { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: protocol error (Expected 100, got %d)", code); - goto finally; - } - - /* Check theversion number */ - details = trim_space(details); - - if(strcmp(details, "HTTPAUTH/1.0") != 0) - { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: Daemon speaking incompatible protocol version: %s", details); - goto finally; - } - - /* Send our handler */ - if(ctx->handler) - { - t = apr_pstrcat(r->pool, "SET Handler ", ctx->handler, "\n", NULL); - - if(write_data(ctx, r->server, t) == -1) - goto finally; - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: sent handler to daemon: %s", t); - - if(read_response(ctx, r, &code, NULL, NULL, 0) == -1) - goto finally; - - if(code != 202) - { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: protocol error: couldn't send handler to daemon (Expected 202, got %d)", code); - goto finally; - } - } - - /* Send any setup info we have */ - if(ctx->domain) - { - t = apr_pstrcat(r->pool, "SET Domain ", ctx->domain, "\n", NULL); - - if(write_data(ctx, r->server, t) == -1) - goto finally; - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: sent domains to daemon: %s", t); - - if(read_response(ctx, r, &code, NULL, NULL, 0) == -1) - goto finally; - - if(code != 202) - { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: protocol error: couldn't send domain to daemon (Expected 202, got %d)", code); - goto finally; - } - } - - /* We're cool! */ - ret = 0; - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "httpauth: handshake with daemon completed"); - -finally: - if(ret == -1 && ctx->socket >= 0) { - disconnect_socket(ctx, r->server); - ++ctx->address_seed; - } - - return ret; -} - -/* Make sure our connection identifier is unique */ -static apr_status_t connection_gone (void *data) -{ - conn_current = NULL; - conn_seen++; - return APR_SUCCESS; -} - -int write_request(httpauth_context_t* ctx, request_rec* r) -{ - char pidid[40]; - char connid[40]; - int i, c = 0; - const char* t; - const apr_array_header_t* hdrs_arr; - const apr_table_entry_t* elts; - - /* When the connection goes away, call our handler */ - if(conn_current != r->connection) - { - conn_current = r->connection; - apr_pool_cleanup_register(r->connection->pool, r, - connection_gone, apr_pool_cleanup_null); - } - - /* A unique per connection id */ - snprintf(connid, sizeof(connid), "0x%X-%X-%X", - (unsigned int)r->connection, conn_seen, (unsigned int)r->connection->id); - connid[sizeof(connid) - 1] = 0; - snprintf(pidid, sizeof(pidid), "%d", (unsigned int)getpid()); - pidid[sizeof(pidid) - 1] = 0; - t = apr_pstrcat(r->pool, pidid, ":", connid, NULL); - - /* Send the request header to httpauthd */ - t = apr_pstrcat(r->pool, "AUTH ", t, " ", r->method, - " ", r->unparsed_uri, "\n", NULL); - - if(write_data(ctx, r->server, t) == -1) - return -1; - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: sent auth request to daemon: %s", t); - - /* Now send the headers to httpauthd */ - - hdrs_arr = apr_table_elts(r->headers_in); - elts = (const apr_table_entry_t*)hdrs_arr->elts; - - for(i = 0; i < hdrs_arr->nelts; i++) - { - if(!elts[i].val) - continue; - - /* Filter out headers we don't want */ - if(strcasecmp(elts[i].key, r->proxyreq == PROXYREQ_PROXY ? - "Proxy-Authorization" : "Authorization") == 0) - { - t = trim_start(elts[i].val); - - if(strncasecmp(t, AUTH_PREFIX_BASIC, strlen(AUTH_PREFIX_BASIC)) == 0 && - !(ctx->types & AUTH_TYPE_BASIC)) - continue; - - else if(strncasecmp(t, AUTH_PREFIX_DIGEST, strlen(AUTH_PREFIX_DIGEST)) == 0 && - !(ctx->types & AUTH_TYPE_DIGEST)) - continue; - - else if(strncasecmp(t, AUTH_PREFIX_NTLM, strlen(AUTH_PREFIX_NTLM)) == 0 && - !(ctx->types & AUTH_TYPE_NTLM)) - continue; - - /* Only allow unknown if we don't have it */ - else if(!(ctx->types & AUTH_TYPE_ANY)) - continue; - - /* Extra blank line when at end */ - t = apr_pstrcat(r->pool, "Authorization: ", elts[i].val, "\n", NULL); - - if(write_data(ctx, r->server, t) == -1) - return HTTP_INTERNAL_SERVER_ERROR; - - c++; - } - } - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: sent %d headers to daemon", c); - - return write_data(ctx, r->server, "\n"); -} - -static int -write_needed_groups(httpauth_context_t *ctx, request_rec *r) -{ - const apr_array_header_t *reqs_arr = ap_requires(r); - require_line *reqs; - const char *groups = NULL; - const char *text; - char *word; - register int x; - int m = r->method_number; - int code, len; - - if(reqs_arr) { - reqs = (require_line*)reqs_arr->elts; - for (x = 0; x < reqs_arr->nelts; x++) { - if (!(reqs[x].method_mask & (AP_METHOD_BIT << m))) - continue; - - text = reqs[x].requirement; - word = ap_getword_white (r->pool, &text); - - /* Append all groups to the string */ - if (strcmp (word, "group") == 0 && text && text[0]) { - if (!groups) - groups = text; - else - groups = apr_pstrcat (r->pool, text, " ", groups, NULL); - } - } - } - - /* No groups, no need to send */ - if (!groups && !ctx->needed_groups) - return 0; - - if (!groups) - groups = ""; - - /* Equal groups, no need to send */ - if (ctx->needed_groups && strcmp (groups, ctx->needed_groups) == 0) - return 0; - - /* Groups changed, send to daemon */ - text = apr_pstrcat (r->pool, "SET Groups ", groups, "\n", NULL); - - if (write_data (ctx, r->server, text) < 0) - return -1; - - ap_log_rerror (APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: sent groups to daemon: %s", text); - - if (read_response (ctx, r, &code, NULL, NULL, 1) < 0) - return -1; - - if (code != 202) { - ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: couldn't send groups to daemon (Expected 202, got %d)", code); - /* Older versions of the daemon did not support the 'SET Groups' command */ - if (code != 400) - return -1; - } +typedef struct sid_session { + char *identifier; + time_t expiry; +} sid_session_t; - /* Save away the groups for next time */ - len = strlen (groups); - if (len >= ctx->alloced_groups) { - if (len < 512) - len = 512; - ctx->needed_groups = (char*)apr_pcalloc (ctx->child_pool, len * 2); - ctx->alloced_groups = len * 2; - } - strcpy (ctx->needed_groups, groups); - return 0; -} +/* Secret used to sign session cookies */ +static unsigned char session_secret[40]; -static httpauth_request_t* -setup_request_hreq (request_rec *r, char *user, char *groups) +static apr_status_t +session_initialize (apr_pool_t *p, server_rec *s) { - httpauth_request_t* hreq; + apr_status_t status; - hreq = (httpauth_request_t*)apr_pcalloc (r->pool, sizeof (*hreq)); - hreq->user = r->user; - hreq->groups = groups; - - if (groups) - apr_table_setn (r->subprocess_env, "HTTPAUTH_GROUPS", groups); - else - apr_table_unset (r->subprocess_env, "HTTPAUTH_GROUPS"); +#if APR_HAS_RANDOM + status = apr_generate_random_bytes (session_secret, sizeof (session_secret)); +#else +#error APR random number support is missing; you probably need to install the truerand library. +#endif - ap_set_module_config (r->request_config, &httpauth_module, hreq); + if (status != APR_SUCCESS) + ap_log_error (APLOG_MARK, APLOG_CRIT, status, s, + "auth-singleid: couldn't generate random secret"); - return hreq; + return status; } -#endif - -typedef struct session_info { - char *identifier; - time_t expiry; -} session_info_t; - static const char* session_cookie_value (request_rec *r, const char *name) { @@ -1192,7 +355,7 @@ session_create_sig (apr_pool_t *p, const char *value) apr_sha1_ctx_t ctx; apr_sha1_init (&ctx); - apr_sha1_update (&ctx, session_secret, strlen (session_secret)); + apr_sha1_update (&ctx, (const char*)session_secret, sizeof (session_secret)); apr_sha1_update (&ctx, "\0", 1); apr_sha1_update (&ctx, value, strlen (value)); apr_sha1_final (digest, &ctx); @@ -1209,10 +372,10 @@ session_validate_sig (apr_pool_t *p, const char *sig, const char *value) return strcmp (sig, valid) == 0; } -static session_info_t* +static sid_session_t* session_load_info (request_rec *r) { - session_info_t *sess; + sid_session_t *sess; const char *value; char *token, *sig, *end; char *identifier; @@ -1246,7 +409,7 @@ session_load_info (request_rec *r) if (!ap_is_url (identifier)) return NULL; - sess = apr_pcalloc (r->pool, sizeof (session_info_t)); + sess = apr_pcalloc (r->pool, sizeof (sid_session_t)); sess->expiry = expiry; sess->identifier = identifier; @@ -1254,7 +417,7 @@ session_load_info (request_rec *r) } static void -session_send_info (request_rec *r, session_info_t *sess) +session_send_info (request_rec *r, sid_session_t *sess) { char *cookie, *sig, *value; @@ -1267,53 +430,152 @@ session_send_info (request_rec *r, session_info_t *sess) apr_table_addn (r->headers_out, "Set-Cookie", cookie); } -static session_info_t* -session_copy_info (apr_pool_t *p, session_info_t *sess) +static sid_session_t* +session_copy_info (apr_pool_t *p, sid_session_t *sess) { - session_info_t *copy = apr_palloc (p, sizeof (*sess)); + sid_session_t *copy = apr_palloc (p, sizeof (*sess)); copy->expiry = sess->expiry; copy->identifier = apr_pstrdup (p, sess->identifier); return copy; } +/* --------------------------------------------------------------------------------------- + * REQUEST ABSTRACTIONS + */ + +struct sid_request { + int result; + request_rec *rec; +}; + + +void +sid_request_log_error (sid_request_t *req, const char *message, const char *detail) +{ + ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, req->rec, + "%s%s%s", message, + detail ? ": " : "", + detail ? detail : ""); + +} + +const char* +sid_request_qs (sid_request_t *req) +{ + return req->rec->args; +} + +const char* +sid_request_url (sid_request_t *req) +{ + /* function to determine if a connection is using https */ + static APR_OPTIONAL_FN_TYPE(ssl_is_https) *using_https = NULL; + static int using_https_inited = 0; + + const char *scheme; + const char *host; + const char *uri; + apr_port_t port; + int is_ssl; + + if (!using_https_inited) { + using_https = APR_RETRIEVE_OPTIONAL_FN (ssl_is_https); + using_https_inited = 1; + } + + is_ssl = using_https && using_https (req->rec->connection); + host = req->rec->hostname ? req->rec->hostname : ap_get_server_name (req->rec); + scheme = is_ssl ? "https" : "http"; + port = ap_get_server_port (req->rec); + uri = req->rec->uri ? req->rec->uri : ""; + + /* Default ports? */ + if ((port == 80 && !is_ssl) || (port == 443 && is_ssl)) + return apr_psprintf (req->rec->pool, "%s://%s%s", scheme, host, uri); + else + return apr_psprintf (req->rec->pool, "%s://%s:%d%s", scheme, host, port, uri); +} + +void +sid_request_respond (sid_request_t *req, int code, const char *reason, + const char *header, ...) +{ + const char *value; + va_list va; + + if (reason) + req->rec->status_line = apr_pstrdup (req->rec->pool, reason); + + va_start(va, header); + while (header) { + value = va_arg (va, const char*); + apr_table_set (req->rec->err_headers_out, header, value); + header = va_arg (va, const char*); + } + va_end(va); + + req->result = code; +} + static void -set_request_authenticated (request_rec *r, session_info_t *sess) +set_request_authenticated (request_rec *r, sid_session_t *sess) { r->user = sess->identifier; - r->ap_auth_type = SINGLEID_AUTHTYPE; + r->ap_auth_type = SID_AUTHTYPE; ap_set_module_config (r->request_config, &auth_singleid_module, sess); } +void +sid_request_authenticated (sid_request_t *req, const char *identifier) +{ + sid_session_t *sess; + + sess = apr_pcalloc (req->rec->pool, sizeof (sid_session_t)); + sess->identifier = apr_pstrdup (req->rec->pool, identifier); + sess->expiry = time (NULL) + 86400; + + set_request_authenticated (req->rec, sess); + session_send_info (req->rec, sess); +} + +/* --------------------------------------------------------------------------------------- + * MAIN HOOKS + */ + +static int +hook_initialize (apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) +{ + int rc; + + rc = shared_initialize (p, s); + if (rc != OK) + return rc; + + return session_initialize (p, s); +} + +static void +hook_child (apr_pool_t *p, server_rec *s) +{ + shared_child (p, s); +} + static int hook_authenticate (request_rec* r) { - session_info_t *sess; -#if 0 - httpauth_context_t* ctx; - httpauth_request_t* hreq; -#endif + sid_session_t *sess; + sid_context_t *ctx; + sid_request_t req; const char* authtype; -#if 0 - int code = 0; - int ccode = 0; - char *groups = NULL; - char* details = NULL; -#endif request_rec* mainreq; -#if 0 - int retried = 0; -#endif /* Make sure it's for us */ - if (!(authtype = ap_auth_type (r)) || strcasecmp (SINGLEID_AUTHTYPE, authtype) != 0) + if (!(authtype = ap_auth_type (r)) || strcasecmp (SID_AUTHTYPE, authtype) != 0) return DECLINED; -#if 0 - ctx = (httpauth_context_t*)ap_get_module_config(r->per_dir_config, &httpauth_module); - - if(!ctx->socketname || !ctx->handler) + ctx = (sid_context_t*)ap_get_module_config(r->per_dir_config, &auth_singleid_module); + if(ctx->identifier == NULL) return DECLINED; -#endif mainreq = r; @@ -1340,214 +602,23 @@ hook_authenticate (request_rec* r) return OK; } + req.result = OK; + req.rec = r; - /* Otherwise start a new openid authentication */ - return DECLINED; - -#if 0 - /* - * Check if we're in sync with the other processes, - * and connected to the same daemon - */ - if (ctx->socket != -1 && shared_get_if_changed (ctx, ctx->shared_version, NULL)) { - ap_log_rerror (APLOG_MARK, APLOG_INFO, 0, r, - "httpauth: syncing connection with other processes"); - disconnect_socket (ctx, r->server); - } - -/* For jumping to when a connection has been closed */ -retry: - - if (ctx->socket == -1) { - if (connect_httpauth (ctx, r) == -1) { - - if (ctx->socket == -1 && retried < ctx->retries) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, - "httpauth: trying to connect to daemon again"); - ++retried; - goto retry; - } - - return HTTP_INTERNAL_SERVER_ERROR; - } - } - - /* Make sure we're starting on a clean slate */ - read_junk (ctx, r); - - - - /* Send off a request, along with groups, and read response */ - if (write_needed_groups (ctx, r) == -1 || - write_request (ctx, r) == -1 || - read_response (ctx, r, &code, &ccode, &details, 0) == -1) { - - /* - * If our connection was closed by httpauthd then this - * is where we get the error. Just do one retry to - * try and reconnect. This happens often when restarting - * httpauthd. - */ - - if (ctx->socket == -1 && retried < ctx->retries) { - ap_log_rerror (APLOG_MARK, APLOG_WARNING, 0, r, - "httpauth: reconnecting to to httpauthd"); - ++retried; - goto retry; - } - - ap_log_rerror (APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(errno), r, - "httpauth: couldn't send request to httpauthd"); - - return HTTP_INTERNAL_SERVER_ERROR; - } - - if(code != 200) - { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: protocol error: unexpected code while authenticating: %d", code); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* Copy over other headers */ - if(read_process_headers(ctx, ccode, r, &groups) == -1) - return HTTP_INTERNAL_SERVER_ERROR; - - if (ccode == 200) { - ap_log_rerror (APLOG_MARK, APLOG_INFO, 0, r, - "httpauth: successful authentication for user: %s", details); - - r->user = apr_pstrdup (r->pool, details); - r->ap_auth_type = HTTPAUTH_AUTHTYPE; - - /* Mark request as successfully authenticated */ - hreq = setup_request_hreq (r, details, groups); - return OK; - } - - return ccode; -#endif -} - - -#if 0 - -static const char* -find_word_quoted (const char *all, const char *word) -{ - const char *at; - char before, after; - size_t len = strlen (word); - - at = all; - for (;;) { - at = strstr (at, word); - if (!at) - return NULL; - - before = (at == all) ? 0 : *(at - 1); - after = *(at + len); - - /* Beginning and end of a space delimited word */ - if ((!before || isspace (before)) && - (!after || isspace (after))) { - return at; - } - - /* Beginning and end of a quoted word */ - if ((before == '"' || before == '\'') && after == before) - return at; - - at += len; - } -} - -static int -httpauth_access(request_rec *r) -{ - httpauth_context_t *ctx; - httpauth_request_t *hreq; - const char* authtype; - char *user = r->user; - int m = r->method_number; - int method_restricted = 0; - register int x; - const char *text, *word; - const apr_array_header_t *reqs_arr = ap_requires (r); - require_line *reqs; - - /* Make sure it's for us */ - if (!(authtype = ap_auth_type (r)) || strcasecmp (HTTPAUTH_AUTHTYPE, authtype) != 0) - return DECLINED; - - if (!reqs_arr) - return OK; - - /* Dig out our configuration */ - ctx = ap_get_module_config (r->per_dir_config, &httpauth_module); - hreq = ap_get_module_config (r->request_config, &httpauth_module); - reqs = (require_line *)reqs_arr->elts; - - for (x = 0; x < reqs_arr->nelts; x++) { - if (!(reqs[x].method_mask & (AP_METHOD_BIT << m))) - continue; + /* Do the OpenID magic */ + sid_consumer_authenticate (&req, ctx->store, ctx->trust_root, ctx->identifier); - method_restricted = 1; - - text = reqs[x].requirement; - word = ap_getword_white(r->pool, &text); - - /* Any valid user */ - if (strcmp (word, "valid-user") == 0) { - return OK; - - /* Specific listed users */ - } else if (strcmp (word, "user") == 0) { - while (text[0]) { - word = ap_getword_conf (r->pool, &text); - if (strcmp (user, word) == 0) { - return OK; - } - } - - /* Specific groups */ - } else if (strcmp (word, "group") == 0) { - if (hreq && hreq->groups) { - while (text[0]) { - word = ap_getword_conf (r->pool, &text); - if (find_word_quoted (hreq->groups, word)) - return OK; - } - } - - /* What is this? */ - } else { - ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r, - "access to %s failed, reason: unknown require " - "directive:\"%s\"", r->uri, reqs[x].requirement); - } - } - - if (!method_restricted) - return OK; - - ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r, - "access to %s failed, reason: user %s not allowed access", - r->uri, user); - return HTTP_UNAUTHORIZED; + return req.result; } -#endif static void register_hooks(apr_pool_t *p) { ap_log_perror (APLOG_MARK, APLOG_ERR, 0, p, "mod_auth_singleid registering hooks"); -#if 0 - ap_hook_post_config (httpauth_initialize, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_child_init (httpauth_child, NULL, NULL, APR_HOOK_MIDDLE); + + ap_hook_post_config (hook_initialize, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_child_init (hook_child, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_check_user_id (hook_authenticate, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_auth_checker (httpauth_access, NULL, NULL, APR_HOOK_MIDDLE); -#endif } module AP_MODULE_DECLARE_DATA auth_singleid_module = { diff --git a/module/mod_auth_singleid.h b/module/mod_auth_singleid.h new file mode 100644 index 0000000..68b5490 --- /dev/null +++ b/module/mod_auth_singleid.h @@ -0,0 +1,81 @@ +#ifndef MOD_AUTH_SINGLEID_H_ +#define MOD_AUTH_SINGLEID_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void sid_shared_lock (void); + +void sid_shared_unlock (void); + +typedef struct sid_request sid_request_t; + +void sid_request_log_error (sid_request_t *req, + const char *message, + const char *detail); + +const char* sid_request_qs (sid_request_t *req); + +const char* sid_request_url (sid_request_t *req); + +void sid_request_respond (sid_request_t *req, + int code, + const char *reason, + const char *header, + ...); + +void sid_request_authenticated (sid_request_t *req, + const char *identifier); + +/* ----------------------------------------------------------------------------------- + * STORAGE: Actually, communications white-board between processes/threads. + */ + +typedef struct sid_storage sid_storage_t; + +typedef struct sid_assoc { + const char *server; + const char *handle; + const char *type; + const unsigned char *secret; + size_t n_secret; + time_t expires; +} sid_assoc_t; + +sid_storage_t* sid_storage_initialize (void *memory, + size_t n_memory); + +int sid_storage_check_nonce (sid_storage_t *storage, + const char *server, + const char *nonce); + +int sid_storage_store_assoc (sid_storage_t *storage, + const sid_assoc_t *assoc); + +int sid_storage_find_assoc (sid_storage_t *storage, + const char *server, + const char *handle, + sid_assoc_t *assoc); + +void sid_storage_invalidate_assoc (sid_storage_t *storage, + const char *server, + const char *handle); + +/* ----------------------------------------------------------------------------------- + * OPENID CONSUMER + */ + +void sid_consumer_authenticate (sid_request_t *req, + sid_storage_t *store, + const char *trust_root, + const char *identity); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* MOD_AUTH_SINGLEID_H_ */ diff --git a/module/request.h b/module/request.h deleted file mode 100644 index 6c63a25..0000000 --- a/module/request.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef REQUEST_H_ -#define REQUEST_H_ - -#ifdef __cplusplus -extern "C" { -#endif - - -typedef void sid_request_t; - - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* REQUEST_H_ */ diff --git a/module/storage.c b/module/storage.c index 3cb9cdd..cb1085d 100644 --- a/module/storage.c +++ b/module/storage.c @@ -1,8 +1,15 @@ +#include "mod_auth_singleid.h" + +#include +#include + +#include + /* Yes, this looks backwards. */ -typedef char nonce_t[40]; +typedef char sid_nonce_t[40]; -struct singleid_board { +struct sid_storage { /* The association with our server */ char server[256]; @@ -13,7 +20,7 @@ struct singleid_board { time_t expires; /* Book keeping for the records */ - nonce_t *records; + sid_nonce_t *records; size_t first; size_t total; size_t count; @@ -21,78 +28,78 @@ struct singleid_board { }; int -singleid_board_store_assoc (singleid_board_t *board, const singleid_assoc_t *assoc) +sid_storage_store_assoc (sid_storage_t *store, const sid_assoc_t *assoc) { - assert (board); + assert (store); assert (assoc); /* Check that we have enough space to store this information */ - if ((assoc->server && strlen (assoc->server) > sizeof (board->server)) || - (assoc->handle && strlen (assoc->handle) > sizeof (board->handle)) || - (assoc->n_secret && assoc->n_secret > sizeof (board->secret)) || - (assoc->type && strlen (assoc->type) > sizeof (board->type))) + if ((assoc->server && strlen (assoc->server) > sizeof (store->server)) || + (assoc->handle && strlen (assoc->handle) > sizeof (store->handle)) || + (assoc->n_secret && assoc->n_secret > sizeof (store->secret)) || + (assoc->type && strlen (assoc->type) > sizeof (store->type))) return 0; - strcpy (board->server, assoc->server ? assoc->server : ""); - strcpy (board->handle, assoc->handle ? assoc->handle : ""); - memcpy (board->secret, assoc->secret, assoc->n_secret); - strcpy (board->type, assoc->type ? assoc->type : ""); - board->expires = assoc->expires; + strcpy (store->server, assoc->server ? assoc->server : ""); + strcpy (store->handle, assoc->handle ? assoc->handle : ""); + memcpy (store->secret, assoc->secret, assoc->n_secret); + strcpy (store->type, assoc->type ? assoc->type : ""); + store->expires = assoc->expires; return 1; } int -singleid_board_find_assoc (singleid_board_t *board, const char *server, - const char *handle, singleid_assoc_t *assoc) +sid_storage_find_assoc (sid_storage_t *store, const char *server, + const char *handle, sid_assoc_t *assoc) { - assert (board); + assert (store); assert (assoc); - if (server && (strlen (server) > sizeof (board->server) || - strcmp (server, board->server) != 0)) + if (server && (strlen (server) > sizeof (store->server) || + strcmp (server, store->server) != 0)) return 0; - if (handle && (strlen (handle) > sizeof (board->handle) || - strcmp (handle, board->handle) != 0)) + if (handle && (strlen (handle) > sizeof (store->handle) || + strcmp (handle, store->handle) != 0)) return 0; - assoc->server = board->server; - assoc->handle = board->handle; - assoc->type = board->type; - assoc->secret = board->secret; - assoc->n_secret = board->n_secret; - assoc->expires = board->expires; + assoc->server = store->server; + assoc->handle = store->handle; + assoc->type = store->type; + assoc->secret = store->secret; + assoc->n_secret = store->n_secret; + assoc->expires = store->expires; return 1; } void -singleid_board_invalidate_assoc (singleid_board_t *board, const char *server, +sid_storage_invalidate_assoc (sid_storage_t *store, const char *server, const char *handle) { - singleid_assoc_t dummy; - assert (board); - - if (singleid_board_find_assoc (board, server, handle, &dummy)) { - board->server[0] = 0; - board->handle[0] = 0; - board->type[0] = 0; - memset (board->secret, 0, sizeof (board->secret)); - board->n_secret = 0; - board->expires = 0; - board->secret[0] = 0; + sid_assoc_t dummy; + assert (store); + + if (sid_storage_find_assoc (store, server, handle, &dummy)) { + store->server[0] = 0; + store->handle[0] = 0; + store->type[0] = 0; + memset (store->secret, 0, sizeof (store->secret)); + store->n_secret = 0; + store->expires = 0; + store->secret[0] = 0; } } #define nonce_compare(a, b) \ - memcmp (a, b, sizeof (nonce_t)) + memcmp (a, b, sizeof (sid_nonce_t)) static void -nonce_put (nonce_t rec, const char *nonce) +nonce_put (sid_nonce_t rec, const char *nonce) { size_t len = strlen (nonce); char *dst = (char*)rec; - /* If it's short enough, then just board. Fast */ + /* If it's short enough, then just store. Fast */ if (len < sizeof (rec)) { memcpy (dst, nonce, len); memset (dst + len, 0, sizeof (rec) - len); @@ -101,7 +108,7 @@ nonce_put (nonce_t rec, const char *nonce) } else { apr_sha1_ctx_t ctx; - assert (sizeof (nonce_t) == APR_SHA1_DIGESTSIZE + 20); + assert (sizeof (sid_nonce_t) == APR_SHA1_DIGESTSIZE + 20); assert (len > 20); /* The date prefix we just copy in */ @@ -110,65 +117,64 @@ nonce_put (nonce_t rec, const char *nonce) /* Hash the rest into the buffer */ apr_sha1_init (&ctx); apr_sha1_update (&ctx, nonce + 20, len - 20); - apr_sha1_final (dst + 20, &ctx); + apr_sha1_final ((unsigned char*)dst + 20, &ctx); } } static void -insert_nonce_record (singleid_board_t *board, nonce_t rec, size_t at) +insert_nonce_record (sid_storage_t *store, sid_nonce_t rec, size_t at) { - nonce_t *records = board->records; - size_t from, to, num; + sid_nonce_t *records = store->records; - assert (board->total > 2); - assert (at < board->total); - assert (at != board->first); + assert (store->total > 2); + assert (at < store->total); + assert (at != store->first); /* Insertion right after latest, either ancient, more likely top */ - if (at == board->first + 1 % board->total) { + if (at == store->first + 1 % store->total) { /* We can just copy in at this point */ /* Our ring has empty space in it, so always push forwards, but only until first */ - } else if (!board->wrapped) { - memmove (records + at + 1, records + at, sizeof (rec) * (board->first - at)); - board->first += 1; + } else if (!store->wrapped) { + memmove (records + at + 1, records + at, sizeof (rec) * (store->first - at)); + store->first += 1; /* Move data backwards to make space */ - } else if (board->first < at) { - memmove (records + board->first + 2, records + board->first + 1, - sizeof (rec) * (at - board->first)); + } else if (store->first < at) { + memmove (records + store->first + 2, records + store->first + 1, + sizeof (rec) * (at - store->first)); /* Move data forwards to make space simply */ } else { - memmove (records + at + 1, records + at, sizeof (rec) * (board->first - at - 1)); + memmove (records + at + 1, records + at, sizeof (rec) * (store->first - at - 1)); } memcpy (records[at], rec, sizeof (rec)); - ++board->count; + ++store->count; /* Track whether we have a full ring or not. */ - if (!board->wrapped && board->count > board->total) - board->wrapped = 1; + if (!store->wrapped && store->count > store->total) + store->wrapped = 1; } int -singleid_board_check_nonce (singleid_board_t *board, const char *nonce) +sid_storage_check_nonce (sid_storage_t *store, const char *server, const char *nonce) { - nonce_t *records; - nonce_t rec; + sid_nonce_t *records; + sid_nonce_t rec; size_t at, lower, upper, mid; int res; - assert (board); + assert (store); assert (nonce); - assert (board->records); - assert (board->first < board->total); + assert (store->records); + assert (store->first < store->total); nonce_put (rec, nonce); - records = board->records; + records = store->records; /* Best case scenario, new nonce is higher than our latest one */ - res = nonce_compare (rec, records[top]); + res = nonce_compare (rec, records[store->first]); /* Was the last nonce */ if (res == 0) { @@ -176,16 +182,16 @@ singleid_board_check_nonce (singleid_board_t *board, const char *nonce) /* Newer than anything, push on top */ } else if (res < 0) { - at = (board->first + 1) % board->total; - insert_nonce_record (board, rec, at); - board->first = at; + at = (store->first + 1) % store->total; + insert_nonce_record (store, rec, at); + store->first = at; return 0; } /* Do a binary search for the item */ - for (lower = 0, upper = board->total; lower < upper; ) { + for (lower = 0, upper = store->total; lower < upper; ) { mid = lower + ((upper - lower) / 2); // Note: not (low + high) / 2 !! - at = at + board->first % board->total; + at = at + store->first % store->total; res = nonce_compare (rec, records[at]); if (res == 0) return 1; /* Have the nonce */ @@ -195,6 +201,6 @@ singleid_board_check_nonce (singleid_board_t *board, const char *nonce) upper = mid; } - insert_nonce_record (board, rec, at); + insert_nonce_record (store, rec, at); return 0; /* Didn't find nonce */ } diff --git a/module/storage.h b/module/storage.h deleted file mode 100644 index 4c73da6..0000000 --- a/module/storage.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef BOARD_H_ -#define BOARD_H_ - -#include - -/* Communications white-board between processes/threads */ - -typedef struct sid_storage sid_storage_t; - -typedef struct sid_assoc { - const char *server; - const char *handle; - const char *type; - const unsigned char *secret; - const size_t n_secret; - time_t expires; -} sid_assoc_t; - -int singleid_board_check_nonce (sid_storage_t *storage, - const char *nonce); - -int singleid_board_store_assoc (sid_storage_t *storage, - const sid_assoc_t *assoc); - -int singleid_board_find_assoc (sid_storage_t *storage, - const char *server, - const char *handle, - sid_assoc_t *assoc); - -void singleid_board_invalidate_assoc (sid_storage_t *storage, - const char *server, - const char *handle); - -#endif /* BOARD_H_ */ -- cgit v1.2.3