[mod_python] PythonAuthenHandler issues

Brad Anderson brad at sankatygroup.com
Fri Jul 20 17:30:02 EDT 2007


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
  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?

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.

What bonehead thing am I doing?

Thanks,
BA







More information about the Mod_python mailing list