Introduce initial authentication/authorization linkage. This has a

couple of aspects:

 - ietfauth.auth.EmailBackEnd is a django.contrib.auth backend to allow
   two modified authentication methods:

   - using email address (stored in django user table) as login username

   - using htpasswd-style "crypt" passwords (for compatability with
     existing user database).  On the first successful login, the
     password will be re-hashed to the django-hash style password.

 - ietfauth.models.UserMap: a mapping from django user to IETF
   person.  This is configured as the profile table, meaning
   that if you have a django user (e.g., from the RequestContext),
   you can use user.get_profile.person to get to the IETF person.

 - ietfauth.models has models for the "legacy" username/person mapping
   tables (LiaisonUser aka "users" and WgPassword aka "wg_password").
   This is to allow mapping of legacy permissions to django permissions
   by walking these tables and applying permissions to users.  The plan
   is to discard these tables eventually.
 - Legacy-Id: 155
This commit is contained in:
Bill Fenner 2007-05-23 16:10:32 +00:00
parent d4d3b47ad1
commit 4a5a5b1d59
6 changed files with 105 additions and 0 deletions

2
ietf/ietfauth/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/*.swp
/*.pyc

View file

42
ietf/ietfauth/auth.py Normal file
View file

@ -0,0 +1,42 @@
from django.contrib.auth.backends import ModelBackend
from django.core.validators import email_re
from django.contrib.auth.models import User
def crypt_check_password(user, raw_password):
"""
Returns a boolean of whether the raw_password was correct. Handles
crypt format only, and updates the password to the hashed version
on first use. This is like User.check_password().
"""
enc_password = user.password
algo, salt, hsh = enc_password.split('$')
if algo == 'crypt':
import crypt
is_correct = ( salt + hsh == crypt.crypt(raw_password, salt) )
if is_correct:
user.set_password(raw_password)
user.save()
return is_correct
return user.check_password(raw_password)
# Based on http://www.djangosnippets.org/snippets/74/
# but modified to use crypt_check_password for all users.
class EmailBackend(ModelBackend):
def authenticate(self, username=None, password=None):
try:
if email_re.search(username):
user = User.objects.get(email=username)
else:
user = User.objects.get(username=username)
except User.DoesNotExist:
return None
if crypt_check_password(user, password):
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None

50
ietf/ietfauth/models.py Normal file
View file

@ -0,0 +1,50 @@
from django.db import models
from django.contrib.auth.models import User
from ietf.idtracker.models import PersonOrOrgInfo
class UserMap(models.Model):
"""
This is effectively a many:1 mapping of django-user -> IETF user.
It'd ideally be 1:1, but for testing some users have multiple
accounts with different privilege levels.
"""
user = models.ForeignKey(User, raw_id_admin=True, core=True, unique=True)
person = models.ForeignKey(PersonOrOrgInfo, edit_inline=models.STACKED, max_num_in_admin=1)
def __str__(self):
return "Mapping django user %s to IETF person %s" % ( self.user, self.person )
######################################################
# legacy per-tool access tables.
# ietf.idtracker.models.IESGLogin is in the same vein.
class LiaisonUser(models.Model):
person = models.ForeignKey(PersonOrOrgInfo, db_column='person_or_org_tag', primary_key=True, raw_id_admin=True)
login_name = models.CharField(maxlength=255)
password = models.CharField(maxlength=25)
user_level = models.IntegerField(null=True, blank=True)
comment = models.TextField(blank=True)
def __str__(self):
return self.login_name
class Meta:
db_table = 'users'
ordering = ['login_name']
class Admin:
pass
class WgPassword(models.Model):
person = models.ForeignKey(PersonOrOrgInfo, db_column='person_or_org_tag', primary_key=True, raw_id_admin=True)
password = models.CharField(blank=True, maxlength=255)
secrete_question_id = models.IntegerField(null=True, blank=True)
secrete_answer = models.CharField(blank=True, maxlength=255)
is_tut_resp = models.IntegerField(null=True, blank=True)
irtf_id = models.IntegerField(null=True, blank=True)
comment = models.TextField(blank=True)
login_name = models.CharField(blank=True, maxlength=100)
def __str__(self):
return self.login_name
class Meta:
db_table = 'wg_password'
ordering = ['login_name']
class Admin:
pass

1
ietf/ietfauth/views.py Normal file
View file

@ -0,0 +1 @@
# Create your views here.

View file

@ -57,6 +57,15 @@ MEDIA_URL = ''
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/media/'
# Link django user to IETF user
AUTH_PROFILE_MODULE = 'ietfauth.UserMap'
# Allow specification of email address as username,
# and handle htpasswd crypt() format passwords.
AUTHENTICATION_BACKENDS = (
"ietf.ietfauth.auth.EmailBackend",
)
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.load_template_source',
@ -92,6 +101,7 @@ INSTALLED_APPS = (
'ietf.announcements',
'ietf.idindex',
'ietf.idtracker',
'ietf.ietfauth',
'ietf.iesg',
'ietf.ipr',
'ietf.liaisons',