Return-Path: Delivered-To: apmail-httpd-modules-dev-archive@minotaur.apache.org Received: (qmail 50449 invoked from network); 2 Nov 2009 09:16:11 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 2 Nov 2009 09:16:11 -0000 Received: (qmail 69805 invoked by uid 500); 2 Nov 2009 09:16:09 -0000 Delivered-To: apmail-httpd-modules-dev-archive@httpd.apache.org Received: (qmail 69577 invoked by uid 500); 2 Nov 2009 09:16:08 -0000 Mailing-List: contact modules-dev-help@httpd.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: modules-dev@httpd.apache.org Delivered-To: mailing list modules-dev@httpd.apache.org Received: (qmail 69558 invoked by uid 99); 2 Nov 2009 09:16:08 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 02 Nov 2009 09:16:08 +0000 X-ASF-Spam-Status: No, hits=-2.6 required=5.0 tests=BAYES_00 X-Spam-Check-By: apache.org Received-SPF: pass (athena.apache.org: domain of margol@beamartyr.net designates 199.203.54.245 as permitted sender) Received: from [199.203.54.245] (HELO hector.mirimar.net) (199.203.54.245) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 02 Nov 2009 09:16:05 +0000 Received: from [95.35.232.70] ([95.35.232.70]) (authenticated bits=0) by mail1.mirimar.net (8.13.4/8.13.4/Debian-3sarge3) with ESMTP id nA29FWi7013989 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 2 Nov 2009 11:15:34 +0200 Message-ID: <4AEEA324.4010206@beamartyr.net> Date: Mon, 02 Nov 2009 11:15:16 +0200 From: Issac Goldstand User-Agent: Thunderbird 2.0.0.23 (Windows/20090812) MIME-Version: 1.0 To: dev@httpd.apache.org CC: modules-dev@httpd.apache.org Subject: Re: Visiting mod_authn_cache References: <4AED52C4.5050609@beamartyr.net> In-Reply-To: <4AED52C4.5050609@beamartyr.net> X-Enigmail-Version: 0.96.0 OpenPGP: url=http://www.beamartyr.net/pubkey.asc Content-Type: multipart/mixed; boundary="------------070404090605020108060106" X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on hector.mirimar.net X-Old-Spam-Status: No, score=-1.5 required=4.0 tests=AWL,BAYES_00,RDNS_NONE, SPF_SOFTFAIL autolearn=no version=3.2.5 --------------070404090605020108060106 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Issac Goldstand wrote: > Paul (or anyone else interested), > Any interested in visiting mod_authn_cache over the hackathon? I > won't be there physically but have been working on the template that was started at the mod-auth project @ sourceforge. [snip] I've actually gotten everything working except for the timeout thing. I'm probably missing something obvious in C, but this is what I'm doing... I've got a timeout period set as a apr_short_interval_time_t, a timestamp on each cache entry set as an apr_time_t, and I populate the latter with apr_time_now() when I add the cache entry and compare if (cache timestamp + the timeout < apr_time_now()) then use the cached credentials, otherwise delete the old cache entry. The odd thing is that I *never* get the else to run. Ever. I've attached the codebase as I've modified it so far (no commit access to mod-auth @ SF), and a sample config that I'm using is: LogLevel debug AuthType Basic AuthName "Test" AuthBasicProvider file cache AuthnCacheTimeout 1 AuthnCacheProvider pam AuthUserFile /root/test.htpasswd require valid-user This results in log entries like the following: [Mon Nov 02 08:34:29 2009] [debug] mod_authn_cache.c(184): [client 10.1.1.92] No entry for user issacg [Mon Nov 02 08:34:29 2009] [info] [client 10.1.1.92] Creating new cache entry for user issacg 0 [Mon Nov 02 08:34:29 2009] [debug] mod_authn_cache.c(162): [client 10.1.1.92] Found entry for user issacg [Mon Nov 02 08:34:29 2009] [info] [client 10.1.1.92] Entry for user issacg matches cached password. Authenticating. [Mon Nov 02 08:34:29 2009] [debug] mod_authn_cache.c(162): [client 10.1.1.92] Found entry for user issacg If I wait a few seconds and try again, the same repeats (it says "No entry for..." and never shows the "Entry for user timed out" Any ideas? Issac --------------070404090605020108060106 Content-Type: text/plain; name="mod_authn_cache.c" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="mod_authn_cache.c" /* ==================================================================== * Copyright 2003-2004 Paul Querna * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ /* * mod_authn_cache * */ #include "apr_lib.h" #define APR_WANT_STRFUNC #include "apr_want.h" #include "apr_strings.h" #include "apr_time.h" #include "apr_pools.h" #include "apr_hash.h" #include "ap_provider.h" #include "httpd.h" #include "http_config.h" #include "http_core.h" #include "http_log.h" #include "http_protocol.h" #include "http_request.h" #include "mod_auth.h" module AP_MODULE_DECLARE_DATA authn_cache_module; static apr_hash_t* authn_cache; static apr_pool_t* authn_cache_pool; typedef struct authn_cache_conf_t { authn_provider_list *providers; apr_short_interval_time_t timeout; } authn_cache_conf_t; typedef struct authn_cache_entry_t { apr_pool_t *p; char *user; char *password; apr_time_t atime; } authn_cache_entry_t; static void *create_authn_cache_dconfig(apr_pool_t * p, char *d) { authn_cache_conf_t *conf; if (d == NULL) { return NULL; } conf = (authn_cache_conf_t *) apr_pcalloc(p, sizeof(authn_cache_conf_t)); if (conf) { conf->providers = NULL; conf->timeout = 0; } return conf; } static const char *set_cache_timeout_interval(cmd_parms *cmd, void *config, const char *arg) { authn_cache_conf_t *conf = (authn_cache_conf_t*)config; conf->timeout = (apr_short_interval_time_t) atol(arg); return NULL; } static const char *add_authn_provider(cmd_parms *cmd, void *config, const char *arg) { authn_cache_conf_t *conf = (authn_cache_conf_t*)config; authn_provider_list *newp; const char *provider_name; if (strcasecmp(arg, "cache") == 0) { /* hey, recursively cache`ing auth requests is bad.. mmmmkay? */ return NULL; } provider_name = apr_pstrdup(cmd->pool, arg); newp = apr_pcalloc(cmd->pool, sizeof(authn_provider_list)); newp->provider_name = provider_name; /* lookup and cache the actual provider now */ newp->provider = ap_lookup_provider(AUTHN_PROVIDER_GROUP, newp->provider_name, "0"); if (newp->provider == NULL) { /* by the time they use it, the provider should be loaded and registered with us. */ return apr_psprintf(cmd->pool, "Unknown Authn provider: %s", newp->provider_name); } if (!newp->provider->check_password) { /* if it doesn't provide the appropriate function, reject it */ return apr_psprintf(cmd->pool, "The '%s' Authn provider doesn't support " "Basic Authentication", provider_name); } /* Add the provider to the list now. */ if (!conf->providers) { conf->providers = newp; } else { authn_provider_list *last = conf->providers; while (last->next) { last = last->next; } last->next = newp; } return NULL; } static const command_rec authn_cache_cmds[] = { /* per auth section */ AP_INIT_TAKE1("AuthnCacheProvider", add_authn_provider, NULL, OR_AUTHCFG, "The name of the configuration to use for this section"), AP_INIT_TAKE1("AuthnCacheTimeout", set_cache_timeout_interval, NULL, OR_AUTHCFG, "The time before cached credentials are discarded or 0 to cache forever"), /* global config */ {NULL} }; module AP_MODULE_DECLARE_DATA authn_cache_module; static authn_status check_cache_pw(request_rec * r, const char *user, const char *password) { apr_pool_t *p; authn_cache_entry_t* cache; authn_status auth_result; authn_provider_list *current_provider; authn_cache_conf_t *conf = ap_get_module_config(r->per_dir_config, &authn_cache_module); /** Lookup entry */ cache = (authn_cache_entry_t *)apr_hash_get(authn_cache, user, APR_HASH_KEY_STRING); if (cache != NULL) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Found entry for user %s", user); if (cache->atime + conf->timeout < apr_time_now()) { /** DO NOT UPDATE cache->atime - we want it to timeout * to force revalidate */ if (apr_strnatcmp(cache->password, password) == 0) { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Entry for user %s matches cached password. " "Authenticating.", user); return AUTH_GRANTED; } } else { /** Force-release the memory, or we'll leak like a boat * with a hole... */ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Entry for user %s timed out. Destroying.", user); apr_hash_set(authn_cache, cache->user, APR_HASH_KEY_STRING, NULL); apr_pool_destroy(cache->p); } } else { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "No entry for user %s", user); } current_provider = conf->providers; do { const authn_provider *provider; if (!current_provider) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "No Cache Authn provider configured"); auth_result = AUTH_GENERAL_ERROR; break; } else { provider = current_provider->provider; } if(!provider->check_password) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "The '%s' Cache Authn provider doesn't support Basic Authentication", current_provider->provider_name); auth_result = AUTH_GENERAL_ERROR; break; } auth_result = provider->check_password(r, user, password); /* Something occured. Stop checking. */ if (auth_result != AUTH_USER_NOT_FOUND) { break; } /* If we're not really configured for providers, stop now. */ if (!conf->providers) { break; } current_provider = current_provider->next; } while (current_provider); if(auth_result == AUTH_GRANTED) { /** Add cache entry */ if (apr_pool_create(&p, authn_cache_pool) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Error allocating memory for authentication cache"); return AUTH_GRANTED; } cache = apr_pcalloc(p, sizeof(authn_cache_entry_t)); cache->p = p; cache->user = apr_pstrdup(cache->p, user); cache->password = apr_pstrdup(cache->p, password); cache->atime = apr_time_now(); apr_hash_set(authn_cache, cache->user, APR_HASH_KEY_STRING, cache); ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Creating new cache entry for user %s %d", user, apr_time_now() - cache->atime); } else { } return auth_result; } static authn_status get_cache_realm_hash(request_rec * r, const char *user, const char *realm, char **rethash) { return AUTH_USER_NOT_FOUND; } static int init_authn_cache(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { void *data; const char *userdata_key = "mod_authn_cache_init"; apr_pool_userdata_get(&data, userdata_key, s->process->pool); if (!data) { apr_pool_userdata_set((const void *) 1, userdata_key, apr_pool_cleanup_null, s->process->pool); return OK; } ap_add_version_component(p, "mod_authn_cache/0.1"); return 0; } static const authn_provider authn_cache_provider = { &check_cache_pw, &get_cache_realm_hash }; static void register_hooks(apr_pool_t * p) { /** pconf is around for long enough... right?) */ if (apr_pool_create(&authn_cache_pool, p) != APR_SUCCESS) { return; } authn_cache = apr_hash_make(authn_cache_pool); ap_hook_post_config(init_authn_cache, NULL, NULL, APR_HOOK_MIDDLE); ap_register_provider(p, AUTHN_PROVIDER_GROUP, "cache", "0", &authn_cache_provider); } module AP_MODULE_DECLARE_DATA authn_cache_module = { STANDARD20_MODULE_STUFF, create_authn_cache_dconfig, /* dir config creater */ NULL, /* dir merger --- default is to override */ NULL, /* server config creator */ NULL, /* merge server config */ authn_cache_cmds, /* command apr_table_t */ register_hooks /* register hooks */ }; --------------070404090605020108060106--