REMOTE_USER authentication to 'Admin'?

1,245 views
Skip to first unread message

Jeff Blaine

unread,
May 17, 2011, 2:31:53 PM5/17/11
to django...@googlegroups.com
Hi folks,

I'm successfully using Apache with mod_authnz_ldap, WSGI, Django 1.3.  If I hit
'/admin', I get asked to authenticate (BasicAuth done through LDAP).  I succeed.
However, this just results in me then seeing the Django admin login screen instead
of logging me in to Admin.

What am I missing?

Apache relevant portion
=======================

    # If this directive is set, the value of the REMOTE_USER environment variable will be set
    # to the value of the attribute specified.
    AuthLDAPRemoteUserAttribute uid

Django
======

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.RemoteUserMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
)

# Try django auth first, failover to LDAP
AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'django.contrib.auth.backends.RemoteUserBackend',
)

Jacob Kaplan-Moss

unread,
May 17, 2011, 2:45:31 PM5/17/11
to django...@googlegroups.com
On Tue, May 17, 2011 at 1:31 PM, Jeff Blaine <cjbl...@gmail.com> wrote:
> Hi folks,
> I'm successfully using Apache with mod_authnz_ldap, WSGI, Django 1.3.  If I
> hit
> '/admin', I get asked to authenticate (BasicAuth done through LDAP).  I
> succeed.
> However, this just results in me then seeing the Django admin login screen
> instead
> of logging me in to Admin.
> What am I missing?

It's hard to be certain, but I'm fairly sure that you need to make
sure that the user in question (i.e. the one authenticated via
mod_authnz_ldap) has the "is_staff" flag set on the Django user
object.

Django requires that there be a User object in the database for each
user, so RemoteUserBackend creates missing User objects on demand (see
http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/backends.py#L68
for the code). However, these automatically-created users won't have
any permissions or the "is_staff" flag set, so they won't be allowed
to log into the admin.

The solution is to subclass RemoteUserBackend and override the
"configure_user" method, setting permissions and staff/superuser flags
appropriately (perhaps via an LDAP query?) This is briefly mentioned
in the documentation (see
http://docs.djangoproject.com/en/dev/howto/auth-remote-user/#remoteuserbackend)
which has a few other details in case you need 'em.

Jacob

Jeff Blaine

unread,
May 17, 2011, 3:00:10 PM5/17/11
to django...@googlegroups.com
[ *sigh* - I wish the web UI to google groups had an 80-column marker. ]
[ Sorry for the formatting in the previous message.  I'm used to hitting ]
[ enter. ]

Thanks for the reply, Jacob.

That gets us somewhere, because authenticating to Apache/LDAP as jblaine
did NOT make a Django user jblaine.

So that's one part of the problem.

The second is that creating jblaine by hand, and setting it is_staff and also
superuser, did not then do anything.  I authenticate to Apache/LDAP fine
then see the Django 'Admin' login screen with empty username/password
form fields.

Here's the whole Apache Directory section for the WSGI, in case something
jumps out:

  <Directory "/rcfwebapps/apps/hostdb/rcfhostdb/apache">
    AuthType Basic
    AuthName "G06A Host Database: Secure"
    AuthBasicProvider ldap
    AuthzLDAPAuthoritative off
    AuthLDAPRemoteUserAttribute uid
    AuthLDAPUrl "ldap://ldap-prod.our.org:389/o=our.org"
    Require ldap-attribute departmentname=RCF
    Order allow,deny
    Allow from all
  </Directory>

Any clever ideas for where to shim some debugging code to see what is
happening in the native Django stuff?

Jacob Kaplan-Moss

unread,
May 17, 2011, 3:10:03 PM5/17/11
to django...@googlegroups.com
On Tue, May 17, 2011 at 2:00 PM, Jeff Blaine <cjbl...@gmail.com> wrote:
> That gets us somewhere, because authenticating to Apache/LDAP as jblaine
> did NOT make a Django user jblaine.

That's interesting - perhaps LDAP is reporting a different username?
You could check in the auth_user table to see what's getting created
when you authenticate; you should see a entry get created the first
time you authenticate as a given user.

> Any clever ideas for where to shim some debugging code to see what is
> happening in the native Django stuff?

I'd start by subclassing RemoteUserBackend and throwing some logging
code into the configure_user (and perhaps clean_username) callbacks.
After that you could try subclassing RemoeUserMiddleware and again
adding some logging callbacks (in process_request, I think).

Jacob

Jeff Blaine

unread,
May 17, 2011, 4:16:10 PM5/17/11
to django...@googlegroups.com
On Tuesday, May 17, 2011 3:10:03 PM UTC-4, Jacob Kaplan-Moss wrote:
On Tue, May 17, 2011 at 2:00 PM, Jeff Blaine <cjbl...@gmail.com> wrote:
> That gets us somewhere, because authenticating to Apache/LDAP as jblaine
> did NOT make a Django user jblaine.

That's interesting - perhaps LDAP is reporting a different username?
You could check in the auth_user table to see what's getting created
when you authenticate; you should see a entry get created the first
time you authenticate as a given user

I guess I'll start the debugging then, because:

DELETE FROM auth_user WHERE username != 'admin';
Query OK, 1 row affected (0.00 sec)

Auth to Apache/LDAP as jblaine, get Admin login screen.

mysql> SELECT username FROM auth_user;
+----------+
| username |
+----------+
| admin    |
+----------+
1 row in set (0.00 sec)

mysql>

Jeff Blaine

unread,
May 17, 2011, 4:22:28 PM5/17/11
to django...@googlegroups.com
Also, FWIW, the REMOTE_USER is definitely getting set to 'jblaine'

1xx.xx.xx.231 - jblaine [17/May/2011:16:12:41 -0400] "GET /static/admin/img/admin/nav-bg.gif HTTP/1.1" 200 273 "http://rcf-hostdb.our.org/admin/" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)"

Jeff Blaine

unread,
May 18, 2011, 7:54:31 PM5/18/11
to django...@googlegroups.com
I'm failing so far.

I copied backends.py to my project root as mybackends.py

I edited it and renamed ModelBackend to MyModelBackend

I changed RemoteUserBackend(ModelBackend)
to MyRemoteUserBackend(MyModelBackend)

I changed settings.py to:

AUTHENTICATION_BACKENDS = (
    'mybackends.MyRemoteUserBackend',
)

"validate" showed 0 errors

I restarted Apache

Authenticating to Apache/LDAP does not trigger any of my debugging
code in MyRemoteUserBackend, I get no errors/exceptions, and I
still just see the Admin login screen at the end.

In fact, I have the following to log that mybackends.py even gets
imported:

import os

fd = open('/tmp/auth.log', 'w')
fd.write('imported file at least\n')
fd.flush()
os.fsync()
fd.close()

Yet, /tmp/auth.log is still sitting empty just as I made it and
chown()ed it:

rcfhostdb:rcfwebapps> ls -ld /tmp/auth.log
-rw-r--r-- 1 apache wheel 0 May 18 19:36 /tmp/auth.log
rcfhostdb:rcfwebapps>

Jeff Blaine

unread,
May 19, 2011, 5:02:19 PM5/19/11
to django...@googlegroups.com
I'm kind of at the point where I consider this a bug in some fashion, regardless
of my specific problem (which persists).

AUTHENTICATION_BACKENDS = (
    'mybackends.MyRemoteUserBackend',
)

If I define AUTHENTICATION_BACKENDS in settings, no default fallen
back on.  If my hand-specified stuff doesn't work, the site should fail to run.
It would appear that Django is just blindly ignoring
mybackends.MyRemoteUserBackend with zero error/log information,
then proceeding to use its own.

rcfhostdb:rcfwebapps> python -c "import mybackends"
Loaded settings.      # from print to sys.stderr in settings.py
In mybackends.      # from print to sys.stderr in mybackends.py
rcfhostdb:rcfwebapps>

When I visit /admin with a browser, authenticate to Apache/LDAP and then
get the normal Admin login screen, error_log shows the following:

[Thu May 19 16:55:54 2011] [error] Loaded settings.

Ramiro Morales

unread,
May 19, 2011, 6:23:02 PM5/19/11
to django...@googlegroups.com
On Thu, May 19, 2011 at 6:02 PM, Jeff Blaine <cjbl...@gmail.com> wrote:
> I'm kind of at the point where I consider this a bug in some fashion,
> regardless
> of my specific problem (which persists).

Well the auth application has a rather large set of tests that exercises
both creating, specifying (in the AUTHENTICATION_BACKENDS setting) and
using custom auth backends:

http://code.djangoproject.com/browser/django/tags/releases/1.3/django/contrib/auth/tests/auth_backends.py#L162

and using django.contrib.auth.backends.RemoteUserBackend plus custom
subclasses of it that perform assorted extra actions using the provided
hooks:

http://code.djangoproject.com/browser/django/tags/releases/1.3/django/contrib/auth/tests/remote_user.py

So it would be surprising if things were in such a broken state.

I'd suggest to use that code as a guidance and try to play with what you
have, drilling down until you get some change in behavior that gives
some hint of the actual problem at hand.

Some ideas:

Specify an empty AUTHENTICATION_BACKENDS setting and see if your project
fails to start both with the development server and with you Apache
setup.

Make sure the string with which your specify your custom backend in
AUTHENTICATION_BACKENDS is a valid one considering the python module
search path available under you Apache setup

Change the strategy you use to really subclass from
django.contrib.auth.backends.ModelBackend, etc.

Regards,

--
Ramiro Morales

Jeff Blaine

unread,
May 19, 2011, 11:38:13 PM5/19/11
to django...@googlegroups.com
Thanks Jacob and Ramiro.

I finally figured it out, and unfortunately it was, of course, something stupid :(

I had changed the directory name holding my WSGI app and had not changed the
Apache config's path reference in *both* places (ScriptAlias and Directory).  SIGH.
That was causing the static file requests to show up in access_log as from 'jblaine',
which made me think all auth was working properly, when in fact it wasn't.  It just
took me to finally notice that there were requests from '-' and 'jblaine' in the same
session full of requests.  I'm a little surprised I even noticed finally.

Additionally, as Jacob pointed out, I needed my own configure_user to
set default permissions to get any login access to Admin for auto-created
users.

Sweet:

[Thu May 19 23:31:36 2011] [error] in MyRemoteUserBackend.authenticate()
[Thu May 19 23:31:36 2011] [error] Remote user is jblaine
[Thu May 19 23:31:36 2011] [error] Remote user cleaned is jblaine
[Thu May 19 23:31:36 2011] [error] Trying to create jblaine
[Thu May 19 23:31:36 2011] [error] Created jblaine
[Thu May 19 23:31:36 2011] [error] in MyRemoteUserBackend.configure_user()
[Thu May 19 23:31:37 2011] [error] Set jblaine is_staff and is_superuser True

Now I have the problem where "Logout" from Admin actually does not do
much of anything because REMOTE_USER is still set in the browser and all
someone has to do is revisit /admin with the same browser instance and they
get automatically logged right back in without a password.

But I'll take that after this victory.  Thanks Jacob and Ramiro!

thiru

unread,
Jun 27, 2011, 3:17:15 PM6/27/11
to Django users
Hi

I have a problem in my application, we are implementing oracle single
sign on to our existing django application, I managed to implement SSO
for the application, but I can able use the same information to login
into Django admin.

I like to know how to use the SSO login User information to log into
django admin.

Regards
Thiru

Jeff Blaine

unread,
Jun 27, 2011, 4:28:27 PM6/27/11
to django...@googlegroups.com
Sorry, I have no knowledge of Oracle SSO, what it allows, how it works, etc.

thiru

unread,
Jun 28, 2011, 8:43:36 AM6/28/11
to Django users
HI I just like to know how to login to the django admin using remote
data (wherever it may be from)

Jeff Blaine

unread,
Jun 28, 2011, 9:57:33 AM6/28/11
to django...@googlegroups.com
It's all right here:


and other details in the mailing list thread you are reading/posting to (this one!)
Reply all
Reply to author
Forward
0 new messages