24 июня 2009 г.

Ldap авторизация в Django

Вопрос ldap авторизации в Python довольно хорошо рассмотрен. Теперь разберем, как привязать эту авторизацию к Django.
Первый вариант в рамках компании будет регистрация на сайте с django путем авторизации в ldap.
Другой вариант - полная интеграция авторизации ldap в джанго, но тогда все преимущества групп и контроля доступа теряются, если только не получать эту дополнительную информацию от ldap или других источников.
Третий, наиболее гибкий вариант. Отсутствие регистрации. Логиним пользователя - ищем его профиль в auth у Django - если его нет, создаем, если есть - то используем найденный профиль (если пароль в Django не совпадает с ldap паролем - обновляем его).

Давайте пойдем по третьему пути.

Для начала подготавливаем Django. У нас будет расширенный стандартный Django User, так как после авторизации пользователя в ldap мы еще получим его данные с корпоративной базы mssql.

Устанавливаем python-ldap:

$ sudo apt-get install python-ldap

Прописываем в settings.py:

LDAP_DOMAIN='mydomain.com'
LDAP_SERVER='ldaps://%s' % LDAP_DOMAIN #SSL connection

Правим файл auth.py:

# -*- coding: utf-8 -*-

from django.conf import settings
from django.contrib.auth.backends import ModelBackend
from django.core.exceptions import ImproperlyConfigured
from django.db.models import get_model
from social.models import CustomUser

class CustomUserModelBackend(ModelBackend):

def get_local_user(self, email, password=None):

try:
user = self.user_class.objects.get(email=email.lower())
if user.check_password(password):
return user
else:
self.exist_user=user#save user for refresh local data
except self.user_class.DoesNotExist:
return None

def get_ldap_refresh_create_user(self, username=None, password=None):
import ldap, sys

#create new local user
if '@' in username:
#user@domain
LDAP_USERNAME=username
username=username.split('@')[0]
else:
#user
LDAP_USERNAME='%s@%s' % (username, settings.LDAP_DOMAIN)

LDAP_PASSWORD=password

try:
# build a client
ldap_client = ldap.initialize(settings.LDAP_SERVER)
# perform a synchronous bind
ldap_client.simple_bind_s(LDAP_USERNAME, LDAP_PASSWORD)
except ldap.INVALID_CREDENTIALS, e:
return False
except ldap.SERVER_DOWN, e:
return False#@todo raise Validation error

#lpad auth succes:

#try to get local user
user=self.get_local_user(LDAP_USERNAME, password)

if user:#if we check user in localbase
return user
else:#else create new or refresh old pass
if hasattr(self, 'exist_user'):
#refresh local auth data from ldap in case of change pass
self.exist_user.set_password(password)
self.exist_user.save()#write new pass
user=self.exist_user
else:
user=CustomUser.objects.create_user(username,LDAP_USERNAME,password)

return user

def updape_user_info(self, user):
pass

def authenticate(self, username=None, password=None):
#try to auth with ldap
#and refresh user data in success or create new one if user does not exist
user=self.get_ldap_refresh_create_user(username, password)
if user:
self.updape_user_info(user)#get data from mssql
return user
else:
return None# error ldap auth

def get_user(self, user_id):
try:
return self.user_class.objects.get(pk=user_id)
except self.user_class.DoesNotExist:
return None

@property
def user_class(self):
if not hasattr(self, '_user_class'):
#self._user_class = get_model(*settings.CUSTOM_USER_MODEL.split('.', 3))
self._user_class = CustomUser
if not self._user_class:
raise ImproperlyConfigured('Could not get custom user model')
return self._user_class


Функция updape_user_info на самостоятельное написание, она должна дописывать необходимую расширенную информацию.

ps. прозрачная авторизация в принципе возможна, но только с IE, можете попробовать.

Комментариев нет:

Отправить комментарий