[mod_python] PythonAuthenHandler issues

Jim Gallacher jpg at jgassociates.ca
Sat Jul 21 20:54:46 EDT 2007


Hi Brad,

It's been awhile since I've messed with aaa, but I may have a spark of 
an idea.

Brad Anderson wrote:
> Hi,
> 
> I'm trying to tie into Django's auth subsystem for http authn/authz in
> front of Subversion, as seen here:
> http://www.djangoproject.com/documentation/apache_auth/
> 
> So, my Apache 2.0.59 conf looks like this (with some mod_macro voodoo):
> 
> #####################################################################
> 
> <Macro ProjectClosed $PROJ>
>  <Location /projects/$PROJ>
>   DAV svn
>   SVNPath /var/svn/$PROJ
>   AuthType Basic

Try changing your AuthType to something else. Heck, you could even use:

AuthType somethingelse

but you'll likely want something a little clearer - dsource-auth might 
be a good choice. You can retrieve this string in your handler with 
req.auth_type(). Likewise req.auth_name() will get you the AuthName setting.

As I recall the AuthType Basic will cause the default authentication 
mechanism to fire, and that's the thing that is generating the 
"couldn't check access.  No groups file?" verbiage in your log.

>   AuthName "dsource-$PROJ"
> 
>   SetEnv DJANGO_SETTINGS_MODULE dsource.settings
>   PythonOption DJANGO_SETTINGS_MODULE dsource.settings
>   PythonOption PROJECT $PROJ
>   PythonPath "['/home/brad/dev/python'] + sys.path"
> 
>   PythonAuthenHandler dsource.web.modpython
>   AuthAuthoritative Off
>   Require dsource-group project_admin developer
> #  Require valid-user
> 
>   SetHandler None
>  </Location>
> </Macro>
> 
> #####################################################################
> 
> 
> 
> And the dsource.web.modpython handler function looks like this:
> 
> #####################################################################
> from mod_python import apache
> import os
> 
> def authenhandler(req, **kwargs):
>     """
>     Authentication handler that checks against Django's auth database.
>     """
> 
>     # mod_python fakes the environ, and thus doesn't process SetEnv.
>     # This fixes that so that the following import works
>     os.environ.update(req.subprocess_env)
> 
>     # check for PythonOptions
>     _str_to_bool = lambda s: s.lower() in ('1', 'true', 'on', 'yes')
> 
>     options = req.get_options()
>     permission_name = options.get('DjangoPermissionName', None)
>     staff_only = _str_to_bool(options.get('DjangoRequireStaffStatus', "on"))
>     superuser_only =
> _str_to_bool(options.get('DjangoRequireSuperuserStatus', "off"))
>     settings_module = options.get('DJANGO_SETTINGS_MODULE', None)
>     if settings_module:
>         os.environ['DJANGO_SETTINGS_MODULE'] = settings_module
> 
>     from django.contrib.auth.models import User
>     from django import db
>     db.reset_queries()
> 
>     username = req.user
>     password = req.get_basic_auth_pw()
>     requires = req.requires()
>     proj = options['PROJECT']
> 
>     # check that the username is valid
>     kwargs = {'username': username, 'is_active': True}
>     if staff_only:
>         kwargs['is_staff'] = True
>     if superuser_only:
>         kwargs['is_superuser'] = True
>     try:
>         try:
>             user = User.objects.get(**kwargs)
>         except User.DoesNotExist:
>             return apache.HTTP_UNAUTHORIZED
> 
>         # check the password and any permission given
>         if user.check_password(password):
> 
>             if requires:
>                 # check dsource groups
>                 required_groups = _get_required_groups(req, requires)
>                 req.log_error("required_groups : %s" % required_groups)
> 
>                 if required_groups:
>                     from tracdsource.perm import get_groups
>                     user_groups = get_groups(username, proj, db.connection)
>                     req.log_error("user_groups     : %s" % user_groups)
> 
>                     for group in required_groups:
>                         if group in user_groups:
>                             req.log_error("w00t - match    : %s" % group)
>                             return apache.OK  # WTF? working?
>             else:
>                 req.log_error("no requires")
>                 return apache.OK
> 
>         else:
>             # password check failed
>             return apache.HTTP_UNAUTHORIZED
> 
>     finally:
>         db.connection.close()
> 
> 
> def _get_required_groups(req, requires):
>     groups = []
>     group_token = 'dsource-group '
> 
>     for require in requires:
>         if require.startswith(group_token):
>             try:
>                 group_list = require[len(group_token):].split(' ')
>                 for group in group_list:
>                     groups.append(group)
> #                    req.log_error("group: %s" % group)
>             finally:
>                 pass
>         else:
>             try:
>                 user_list = require.split(' ')
>                 for user in user_list:
>                     if user == "valid-user":
>                         groups.append('registered_user')
> #                    req.log_error("group: %s" % group)
>             finally:
>                 pass
> 
>     return groups
> #####################################################################
> 
> When I activate 'Require valid-user' things are fine (in error_log):
> 
>  required_groups : ['registered_user']
>  user_groups     : ['anonymous', 'registered_user', 'project_admin']
>  w00t - match    : registered_user
> 
> 
> But when I activate 'Require dsource-group project_admin developer' I
> get an error:
> 
>  required_groups : ['dsource', 'project_admin', 'developer']
>  user_groups     : ['anonymous', 'registered_user', 'project_admin']
>  w00t - match    : project_admin
>  configuration error:  couldn't check access.  No groups file?:
> /projects/test
> 
> I've been looking at
> http://www.modpython.org/pipermail/mod_python/2006-April/020959.html and
> it's caused me to add 'AuthAuthoritative Off' to httpd.conf, but it says
> 'group' and 'valid-user' are a no-no, but that's all I can get to work.
>  Maybe this is an Apache 2.2.4 thing?

Nope. AuthAuthoritative disappears in 2.2, along with mod_auth. There 
was a reorganization of the aaa stuff for 2.2 with a bunch of new 
modules being added such as mod_auth_basic and mod_auth_digest.

> Search for WTF? in the Python handler code - that return apache.OK
> doesn't seem to return 200 even though we found a match (in error_log).
>  It's as if the handler function returns None or 0.

For some reason I can't seem to parse that paragraph. Hopefully the 
change to AuthType I suggested will take care of the problem.

On the other hand the value of apache.OK *is* 0 and this is perfectly 
fine. Don't confuse the value your handler returns to apache with the 
status value that apache eventually sets in the response header. There 
is obviously a relationship but it's not a 1:1 mapping. For example your 
handler could return apache.DECLINED, which would cause the next 
authenhandler in the chain to be called.

> What bonehead thing am I doing?

You think you're boneheaded? I read the thread from April '06 you quoted 
and I don't remember any of it. The only way I know I participated is 
that I recognize the typos I typically mak. :)

Jim





More information about the Mod_python mailing list