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:
parent
d4d3b47ad1
commit
4a5a5b1d59
2
ietf/ietfauth/.gitignore
vendored
Normal file
2
ietf/ietfauth/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/*.swp
|
||||||
|
/*.pyc
|
0
ietf/ietfauth/__init__.py
Normal file
0
ietf/ietfauth/__init__.py
Normal file
42
ietf/ietfauth/auth.py
Normal file
42
ietf/ietfauth/auth.py
Normal 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
50
ietf/ietfauth/models.py
Normal 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
1
ietf/ietfauth/views.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
# Create your views here.
|
|
@ -57,6 +57,15 @@ MEDIA_URL = ''
|
||||||
# Examples: "http://foo.com/media/", "/media/".
|
# Examples: "http://foo.com/media/", "/media/".
|
||||||
ADMIN_MEDIA_PREFIX = '/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.
|
# List of callables that know how to import templates from various sources.
|
||||||
TEMPLATE_LOADERS = (
|
TEMPLATE_LOADERS = (
|
||||||
'django.template.loaders.filesystem.load_template_source',
|
'django.template.loaders.filesystem.load_template_source',
|
||||||
|
@ -92,6 +101,7 @@ INSTALLED_APPS = (
|
||||||
'ietf.announcements',
|
'ietf.announcements',
|
||||||
'ietf.idindex',
|
'ietf.idindex',
|
||||||
'ietf.idtracker',
|
'ietf.idtracker',
|
||||||
|
'ietf.ietfauth',
|
||||||
'ietf.iesg',
|
'ietf.iesg',
|
||||||
'ietf.ipr',
|
'ietf.ipr',
|
||||||
'ietf.liaisons',
|
'ietf.liaisons',
|
||||||
|
|
Loading…
Reference in a new issue