You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@subversion.apache.org by Kyle George <kg...@tcpsoft.com> on 2007/04/20 01:47:31 UTC

[contrib] mod_authrewrite.c

Dev,

The subversion repository I maintain had to change authentication schemes 
and usernames due to an acquisition.  This would mean that future 
revisions would show up with the new usernames.  This would break some 
management tools, stats, and general consistency.  Instead of going back 
and resetting the svn:author property to the new usernames historically, I 
wrote this apache module that sits in between the authn provider and 
mod_authz_svn/mod_dav_svn and maps the new usernames to the old usernames 
for me.  It was written primarily for fun (it would have been much easier 
to write a script to reset svn:author).

I'd like to contribute it to anyone else who might find it useful.  Read 
the comments below for details.

I'll admit not being an apache module expert, so patches are welcome from 
anyone who is.

Regards,

-- 
Kyle George

mod_authrewrite.c:

/*
  * Copyright (c) 2007 Kyle George <kg...@tcpsoft.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */

/*
  * mod_authrewrite.c: An apache2 module that sits between mod_authz_svn,
  * other auth(n|z) modules, and the subversion dav backend (mod_dav_svn).
  * It rewrites the auth'ed usernames for case and translates them using
  * simple map lookup.
  *
  * It's useful if you change authentication schemes where users must use
  * new usernames and you want the svn:author prop to stay consistent, or
  * if your users can't type their names in a single case.  It will also
  * keep you from having to change your mod_authz_svn conf file.
  *
  * Example: You go from using basic authentication using first initial +
  * last name to integrating with an LDAP directory where users will now
  * authenticate with their full email address.  The email address is what
  * will now show up to mod_dav_svn.  If you want to keep your repository
  * svn:author consistent and/or keep from having to change your
  * mod_authz_svn configuration, use this module to map the email
  * addresses to the old usernames.
  *
  * Use this module with:
  *
  *   AuthRewriteCase "lower"|"upper"
  *   AuthRewriteMapEntry <from> <to>
  *
  * TODO: Eventually, it'd be cool if it supported mod_rewrite-like
  * options like:
  *
  *   AuthRewriteEngine "on"|"off"
  *   AuthRewriteMap <mapname> <maptype>:<source>
  *   AuthRewriteCond <teststring> <condpattern> <flags>
  *   AuthRewriteLogLevel <level>
  *   AuthRewriteOptions <options>
  *   AuthRewriteRule <pattern> <substitution> <flags>
  *
  *   ... or at least an external map file, but it doesn't do that now.
  *
  * To compile and install:
  *
  *   1) # /path/to/apache2/bin/apxs -c mod_authrewrite.c
  *   2) # cp .libs/mod_authrewrite.so /path/to/apache2/modules
  *   3) Put "LoadModule authrewrite_module modules/mod_authrewrite.so"
  *      in your httpd.conf (or appropriate).
  *   4) Configure directives
  *   5) Restart apache2
  */

#include "apr.h"
#include "apr_lib.h"
#include "apr_pools.h"
#include "apr_general.h"
#include "apr_strings.h"

#include "ap_config.h"

#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_request.h"
#include "http_log.h"

/*
  * Decls/defs
  */

module AP_MODULE_DECLARE_DATA authrewrite_module;

typedef struct {
#define REWRITE_CASE_OFF   0
#define REWRITE_CASE_LOWER 1
#define REWRITE_CASE_UPPER 2
   int rewrite_case;
   apr_table_t *rewrite_memmap;
} authrewrite_config;

/*
  * Utils
  */

/*
  * Convert s to lower case in place
  */
static char *strlwr(char *s)
{
   char *r = s;

   while (s && *s) {
     *s++ = apr_tolower(*s);
   }

   return (r);
}

/*
  * Convert s to upper case in place
  */
static char *strupr(char *s)
{
   char *r = s;

   while (s && *s) {
     *s++ = apr_toupper(*s);
   }

   return (r);
}

/*
  * Per-directory config
  */

/*
  * Create per-directory config
  */
static void *authrewrite_config_create(apr_pool_t *p, char *dummy)
{
   authrewrite_config *new = NULL;

   new = apr_pcalloc(p, sizeof(authrewrite_config));
   new->rewrite_case = REWRITE_CASE_OFF;
   new->rewrite_memmap = apr_table_make(p, 1);

   return ((void *)new);
}

/*
  * Hooks
  */

/*
  * Fixup username
  */
static int authrewrite_fixup(request_rec *r)
{
   const char *s = NULL;
   const char *u = NULL;
   authrewrite_config *c = NULL;

   c = (authrewrite_config *)
     ap_get_module_config(
       r->per_dir_config,
       &authrewrite_module
     );

   if (c == NULL) {
     return (DECLINED);
   }

   /* dup original username */

   u = apr_pstrdup(r->pool, r->user);

   /* rewrite case */

   switch (c->rewrite_case) {
   case REWRITE_CASE_LOWER: r->user = strlwr(r->user); break;
   case REWRITE_CASE_UPPER: r->user = strupr(r->user); break;
   }

   /* rewrite map */

   if ((s = apr_table_get(c->rewrite_memmap, r->user)) != NULL) {
     r->user = (char *)apr_pstrdup(r->pool, s);
   }

   /* preserve original username */

   apr_pool_userdata_set(u, "mod_authrewrite", NULL, r->pool);

   return (DECLINED);
}

/*
  * Reset username
  */
static int authrewrite_reset(request_rec *r)
{
   void *data = NULL;

   if (apr_pool_userdata_get(&data, "mod_authrewrite", r->pool) !=
         APR_SUCCESS) {
     return (DECLINED);
   }

   if (data) {
     r->user = (char *)data;
   }

   return (DECLINED);
}

/*
  * Register callbacks
  */
static void authrewrite_register_hooks(apr_pool_t *p)
{
   static const char * const pre[] = { "mod_ssl.c", NULL };
   static const char * const post[] = { "mod_authz_svn.c", NULL };
   ap_hook_access_checker(authrewrite_fixup, NULL, post, APR_HOOK_LAST);
   ap_hook_access_checker(authrewrite_reset, post, NULL, APR_HOOK_LAST);
   ap_hook_check_user_id(authrewrite_fixup, pre, post, APR_HOOK_FIRST);
   ap_hook_check_user_id(authrewrite_reset, post, NULL, APR_HOOK_FIRST);
   ap_hook_auth_checker(authrewrite_fixup, NULL, post, APR_HOOK_FIRST);
   ap_hook_auth_checker(authrewrite_reset, post, NULL, APR_HOOK_FIRST);
   ap_hook_fixups(authrewrite_fixup, NULL, NULL, APR_HOOK_FIRST);
}

/*
  * Commands
  */

/*
  * Handle AuthRewriteCase
  */
static const char *authrewrite_command_case(cmd_parms *cmd, void *d,
   const char *arg)
{
   authrewrite_config *c = d;

   if (strcasecmp(arg, "lower") == 0) {
     c->rewrite_case = REWRITE_CASE_LOWER;
   } else
   if (strcasecmp(arg, "upper") == 0) {
     c->rewrite_case = REWRITE_CASE_UPPER;
   } else {
     c->rewrite_case = REWRITE_CASE_OFF;
   }

   return (NULL);
}

/*
  * Handle AuthRewriteMapEntry
  */
static const char *authrewrite_command_mapentry(cmd_parms *cmd, void *d,
   const char *arg0, const char *arg1)
{
   char *key = NULL;
   char *value = NULL;

   authrewrite_config *c = d;
   key = apr_pstrdup(cmd->pool, arg0);
   value = apr_pstrdup(cmd->pool, arg1);
   apr_table_setn(c->rewrite_memmap, key, value);

   return (NULL);
}

/*
  * Command table
  */
static const command_rec authrewrite_commands[] =
{
   AP_INIT_TAKE1("AuthRewriteCase", authrewrite_command_case,
     NULL, OR_OPTIONS, "Lower or upper"),
   AP_INIT_TAKE2("AuthRewriteMapEntry", authrewrite_command_mapentry,
     NULL, OR_OPTIONS, "Add a from --> to entry to the map"),
   { NULL }
};

/*
  * Module definition
  */
module AP_MODULE_DECLARE_DATA authrewrite_module =
{
   STANDARD20_MODULE_STUFF,
   authrewrite_config_create,
   NULL,
   NULL,
   NULL,
   authrewrite_commands,
   authrewrite_register_hooks
};

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [contrib] mod_authrewrite.c

Posted by Kyle George <kg...@tcpsoft.com>.
On Fri, 20 Apr 2007, C. Michael Pilato wrote:

> ...especially since said script has already been written.  (See
> contrib/server-side/svn-tweak-author.py.)

Yeah, I guess you did this relatively recently (Jan 29, 2007).  However, 
svn-tweak-author.py won't catch the case of mapping/rewriting usernames 
before it hits mod_authz_svn and/or mod_dav_svn, which is the primary 
purpose for mod_authrewrite (see the comments in the source).  If you want 
to change svn:author historically and change your authz conf file, then 
your script does the trick.  mod_authrewrite lets you rewrite usernames 
without having to change svn:author historically, change your authz conf 
file, or install a commit hook.  It can also normalize usernames to all 
lower or upper case before it hits the authz_svn or dav layers.

Regards,

-- 
Kyle George

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [contrib] mod_authrewrite.c

Posted by "C. Michael Pilato" <cm...@collab.net>.
Kyle George wrote:

[...]

> I wrote this apache module that sits in between the authn
> provider and mod_authz_svn/mod_dav_svn and maps the new usernames to the
> old usernames for me.  It was written primarily for fun (it would have
> been much easier to write a script to reset svn:author).

...especially since said script has already been written.  (See
contrib/server-side/svn-tweak-author.py.)

-- 
C. Michael Pilato <cm...@collab.net>
CollabNet   <>   www.collab.net   <>   Distributed Development On Demand