add new login/password backend using Kerberos, rename KERBEROS_HASHER_SERVICE_PRINCIPAL to KERBEROS_SERVICE_PRINCIPAL
This commit is contained in:
parent
7896944e30
commit
2cb06046b8
26
README
26
README
|
@ -44,13 +44,25 @@ Whether to create user if no existing model can be found, default is `False`.
|
|||
A regular expression that the principal must match to get superuser privileges,
|
||||
default is `None`. A classic example could be `r'^.*/admin$'`.
|
||||
|
||||
`KERBEROS_HASHER_SERVICE_PRINCIPAL`
|
||||
`KERBEROS_SERVICE_PRINCIPAL`
|
||||
-----------------------------------
|
||||
|
||||
The service principal to user when checking a password against the
|
||||
The service principal to use when checking a password against the
|
||||
KDC, you don't need the secret key for this principal, it should
|
||||
just exist inside the Kerberos database as the check is done by
|
||||
trying to get ticket for this service.
|
||||
trying to get ticket for this service. Default is
|
||||
None. It's used only by the pseudo password haser
|
||||
and the login/password authentication backend.
|
||||
|
||||
`KERBEROS_KEEP_PASSWORD`
|
||||
------------------------
|
||||
|
||||
Does the KerbersoPasswordBackend store a hash of the
|
||||
checked password inside the user model each time a
|
||||
user log in. Default is False. It allows your
|
||||
website to provide a backup authentication if
|
||||
Kerberos is failing or if you ever need to detach
|
||||
from the realm.
|
||||
|
||||
Custom backend
|
||||
==============
|
||||
|
@ -101,3 +113,11 @@ The content of the password field must be `kerberos$<principal name>`.
|
|||
To create an user for a principal you can do::
|
||||
|
||||
User.objects.create(username=new_username, password='kerberos$' + principal)
|
||||
|
||||
Login/Password backend
|
||||
======================
|
||||
|
||||
If your users does not have their browser configured
|
||||
for SPNEGO HTTP authentication you can also provide
|
||||
a classic login/password form which check passwords
|
||||
using Kerberos.
|
||||
|
|
|
@ -5,9 +5,11 @@ class AppSettings(object):
|
|||
__DEFAULTS = {
|
||||
'BACKEND_CREATE': False,
|
||||
'BACKEND_ADMIN_REGEXP': None,
|
||||
'SERVICE_PRINCIPAL': None,
|
||||
'DEFAULT_REALM': None,
|
||||
'SERVICE_PRINCIPAL': '',
|
||||
'HOSTNAME': None,
|
||||
'KEYTAB': None,
|
||||
'KEEP_PASSWORD': False,
|
||||
}
|
||||
|
||||
def __getattr__(self, name):
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
import re
|
||||
|
||||
import logging
|
||||
|
||||
from . import app_settings
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.utils.encoding import force_bytes
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.backends import ModelBackend
|
||||
|
||||
import kerberos
|
||||
|
||||
class KerberosBackend(ModelBackend):
|
||||
def __init__(self):
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
@ -38,6 +42,9 @@ class KerberosBackend(ModelBackend):
|
|||
kwargs = {username_field: username}
|
||||
if app_settings.BACKEND_CREATE:
|
||||
user, created = User.objects.get_or_create(**kwargs)
|
||||
if created:
|
||||
user.set_unusable_password()
|
||||
user.save()
|
||||
else:
|
||||
try:
|
||||
user = User.objects.get(**kwargs)
|
||||
|
@ -47,9 +54,53 @@ class KerberosBackend(ModelBackend):
|
|||
return user
|
||||
|
||||
|
||||
def authenticate(self, principal=None):
|
||||
def authenticate(self, principal=None, **kwargs):
|
||||
if principal and self.authorize_principal(principal):
|
||||
return self.lookup_user(principal)
|
||||
|
||||
|
||||
class KerberosPasswordBackend(KerberosBackend):
|
||||
def default_realm(self):
|
||||
'''Default realm for usernames without a realm'''
|
||||
return app_settings.DEFAULT_REALM
|
||||
|
||||
def principal_from_username(self, username):
|
||||
realm = self.default_realm()
|
||||
if '@' not in username and realm:
|
||||
username = u'%s@%s' % (username, realm)
|
||||
return username
|
||||
|
||||
def keep_password(self):
|
||||
'''Do we save a password hash ?'''
|
||||
return app_settings.KEEP_PASSWORD
|
||||
|
||||
def service_principal(self):
|
||||
'''Service principal for checking password'''
|
||||
if not app_settings.SERVICE_PRINCIPAL:
|
||||
raise ImproperlyConfigured('Kerberos password backend needs '
|
||||
'the setting KERBEROS_SERVICE_PRINCIPAL to be '
|
||||
'set')
|
||||
return app_settings.SERVICE_PRINCIPAL
|
||||
|
||||
def authenticate(self, username=None, password=None, **kwargs):
|
||||
'''Verify username and password using Kerberos'''
|
||||
if not username:
|
||||
return
|
||||
|
||||
principal = force_bytes(self.principal_from_username(username))
|
||||
password = force_bytes(password)
|
||||
|
||||
try:
|
||||
if not kerberos.checkPassword(principal, password,
|
||||
self.service_principal(), self.default_realm()):
|
||||
return
|
||||
except kerberos.KrbError, e:
|
||||
logging.getLogger(__name__).error('password validation'
|
||||
'for principal %r failed %s', principal, e)
|
||||
return
|
||||
else:
|
||||
if principal and self.authorize_principal(principal):
|
||||
user = self.lookup_user(principal)
|
||||
if self.keep_password():
|
||||
user.set_password(password)
|
||||
return user
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import logging
|
||||
import kerberos
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.contrib.auth.hashers import BasePasswordHasher
|
||||
from django.utils.encoding import force_bytes
|
||||
|
||||
from django.contrib.auth.hashers import BasePasswordHasher
|
||||
|
||||
import kerberos
|
||||
|
||||
from . import app_settings
|
||||
|
||||
class KerberosHasher(BasePasswordHasher):
|
||||
|
@ -16,7 +18,7 @@ class KerberosHasher(BasePasswordHasher):
|
|||
algorithm, principal = encoded.split('$', 2)
|
||||
assert algorithm == self.algorithm
|
||||
principal = force_bytes(principal)
|
||||
password = force_bytes(principal)
|
||||
password = force_bytes(password)
|
||||
if not app_settings.SERVICE_PRINCIPAL:
|
||||
raise ImproperlyConfigured('Kerberos pseudo password hasher needs '
|
||||
'the setting KERBEROS_SERVICE_PRINCIPAL to be '
|
||||
|
|
Reference in New Issue