From 135ebc93e644dc42f4c8d7fe8d556d728acd2043 Mon Sep 17 00:00:00 2001 From: Shirlei Chaves <shirlei@gmail.com> Date: Mon, 16 Nov 2015 23:51:27 -0200 Subject: [PATCH] Add ldap auth --- helios_auth/auth_systems/__init__.py | 4 + helios_auth/auth_systems/ldapauth.py | 113 ++++++++++++++++++ .../auth_systems/ldapbackend/__init__.py | 0 .../auth_systems/ldapbackend/backend.py | 28 +++++ helios_auth/media/login-icons/ldap.png | Bin 0 -> 4758 bytes helios_auth/tests.py | 41 +++++++ helios_auth/urls.py | 5 + requirements.txt | 1 + settings.py | 30 ++++- 9 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 helios_auth/auth_systems/ldapauth.py create mode 100644 helios_auth/auth_systems/ldapbackend/__init__.py create mode 100644 helios_auth/auth_systems/ldapbackend/backend.py create mode 100644 helios_auth/media/login-icons/ldap.png diff --git a/helios_auth/auth_systems/__init__.py b/helios_auth/auth_systems/__init__.py index 5a0e923..aaaddb5 100644 --- a/helios_auth/auth_systems/__init__.py +++ b/helios_auth/auth_systems/__init__.py @@ -2,6 +2,9 @@ AUTH_SYSTEMS = {} import twitter, password, cas, facebook, google, yahoo, linkedin, clever +import ldapauth + + AUTH_SYSTEMS['twitter'] = twitter AUTH_SYSTEMS['linkedin'] = linkedin AUTH_SYSTEMS['password'] = password @@ -10,6 +13,7 @@ AUTH_SYSTEMS['facebook'] = facebook AUTH_SYSTEMS['google'] = google AUTH_SYSTEMS['yahoo'] = yahoo AUTH_SYSTEMS['clever'] = clever +AUTH_SYSTEMS['ldap'] = ldapauth # not ready #import live diff --git a/helios_auth/auth_systems/ldapauth.py b/helios_auth/auth_systems/ldapauth.py new file mode 100644 index 0000000..4e201f9 --- /dev/null +++ b/helios_auth/auth_systems/ldapauth.py @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- +""" +LDAP Authentication +Author : shirlei@gmail.com +Version: 1.0 +Requires libldap2-dev +django-auth-ldap 1.2.7 +LDAP authentication relies on django-auth-ldap (http://pythonhosted.org/django-auth-ldap/), +which considers that "Authenticating against an external source is swell, but Django’s +auth module is tightly bound to a user model. When a user logs in, we have to create a model +object to represent them in the database." +Helios, originally, does not rely on default django user model. Discussion about that can be +found in: +https://groups.google.com/forum/#!topic/helios-voting/nRHFAbAHTNA +That considered, using a django plugin for ldap authentication, in order to not reinvent the +wheel seems ok, since it does not alter anything on original helios user model, it is just +for authentication purposes. +However, two installed_apps that are added when you first create a django project, which were +commented out in helios settings, need to be made available now: +django.contrib.auth +django.contrib.contenttypes' +This will enable the native django authentication support on what django-auth-ldap is build upon. +Further reference on +https://docs.djangoproject.com/en/1.8/topics/auth/ +""" + +from django import forms +from django.conf import settings +from django.core.mail import send_mail +from django.core.urlresolvers import reverse +from django.http import HttpResponseRedirect + + +from helios_auth.auth_systems.ldapbackend import backend + + +# some parameters to indicate that status updating is possible +STATUS_UPDATES = False + + +LOGIN_MESSAGE = "Log in with my LDAP Account" + +class LoginForm(forms.Form): + username = forms.CharField(max_length=250) + password = forms.CharField(widget=forms.PasswordInput(), max_length=100) + + +def ldap_login_view(request): + from helios_auth.view_utils import render_template + from helios_auth.views import after + + error = None + + if request.method == "GET": + form = LoginForm() + else: + form = LoginForm(request.POST) + + request.session['auth_system_name'] = 'ldap' + + if request.POST.has_key('return_url'): + request.session['auth_return_url'] = request.POST.get('return_url') + + if form.is_valid(): + username = form.cleaned_data['username'].strip() + password = form.cleaned_data['password'].strip() + + auth = backend.CustomLDAPBackend() + user = auth.authenticate(username, password) + + if user: + request.session['ldap_user'] = { + 'user_id': user.email, + 'name': user.first_name + ' ' + user.last_name, + } + return HttpResponseRedirect(reverse(after)) + else: + error = 'Bad Username or Password' + + return render_template(request, 'password/login', { + 'form': form, + 'error': error, + 'enabled_auth_systems': settings.AUTH_ENABLED_AUTH_SYSTEMS, + }) + + +def get_user_info_after_auth(request): + return { + 'type': 'ldap', + 'user_id' : request.session['ldap_user']['user_id'], + 'name': request.session['ldap_user']['name'], + 'info': {'email': request.session['ldap_user']['user_id']}, + 'token': None + } + + +def get_auth_url(request, redirect_url = None): + return reverse(ldap_login_view) + + +def send_message(user_id, name, user_info, subject, body): + send_mail(subject, body, settings.SERVER_EMAIL, ["%s <%s>" % (name, user_id)], fail_silently=False) + + +def check_constraint(constraint, user_info): + """ + for eligibility + """ + pass + +def can_create_election(user_id, user_info): + return True + diff --git a/helios_auth/auth_systems/ldapbackend/__init__.py b/helios_auth/auth_systems/ldapbackend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/helios_auth/auth_systems/ldapbackend/backend.py b/helios_auth/auth_systems/ldapbackend/backend.py new file mode 100644 index 0000000..ef1930d --- /dev/null +++ b/helios_auth/auth_systems/ldapbackend/backend.py @@ -0,0 +1,28 @@ +from django.conf import settings + +from django_auth_ldap.backend import LDAPBackend +from django_auth_ldap.config import LDAPSearch +from django_auth_ldap.backend import populate_user + + +class CustomLDAPBackend(LDAPBackend): + def authenticate(self, username, password): + """ + Some ldap servers allow anonymous search but naturally return just a set + of user attributes. So, here we re-perform search after user is authenticated, + in order to populate other user attributes. + For now, just in cases where AUTH_LDAP_BIND_PASSWORD is empty + """ + user = super(CustomLDAPBackend, self).authenticate(username, password) + + if user and settings.AUTH_LDAP_BIND_PASSWORD == '' : + search = self.settings.USER_SEARCH + if search is None: + raise ImproperlyConfigured('AUTH_LDAP_USER_SEARCH must be an LDAPSearch instance.') + results = search.execute(user.ldap_user.connection, {'user': user.username}) + if results is not None and len(results) == 1: + (user.ldap_user._user_dn, user.ldap_user.user_attrs) = results[0] + user.ldap_user._load_user_attrs() + user.ldap_user._populate_user_from_attributes() + user.save() + return user diff --git a/helios_auth/media/login-icons/ldap.png b/helios_auth/media/login-icons/ldap.png new file mode 100644 index 0000000000000000000000000000000000000000..86f7807cbcf9f8d5add2c9450a1cf74b30ff1cb6 GIT binary patch literal 4758 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 b^?ly_RmK;MOI;Wk7#KWV{an^LB{Ts5JLw`^ literal 0 HcmV?d00001 diff --git a/helios_auth/tests.py b/helios_auth/tests.py index f07f309..9b097cc 100644 --- a/helios_auth/tests.py +++ b/helios_auth/tests.py @@ -13,6 +13,7 @@ from django.test import TestCase from django.core import mail from auth_systems import AUTH_SYSTEMS +from helios_auth import ENABLED_AUTH_SYSTEMS class UserModelTests(unittest.TestCase): @@ -128,3 +129,43 @@ class UserBlackboxTests(TestCase): self.assertEquals(len(mail.outbox), 1) self.assertEquals(mail.outbox[0].subject, "testing subject") self.assertEquals(mail.outbox[0].to[0], "\"Foobar User\" <foobar-test@adida.net>") + + +import auth_systems.ldapauth as ldap_views + + +class LDAPAuthTests(TestCase): + """ + These tests relies on OnLine LDAP Test Server, provided by forum Systems: + http://www.forumsys.com/tutorials/integration-how-to/ldap/online-ldap-test-server/ + """ + + def setUp(self): + """ set up necessary django-auth-ldap settings """ + self.password = 'password' + self.username = 'euclid' + + def test_backend_login(self): + """ test if authenticates using the backend """ + if 'ldap' in ENABLED_AUTH_SYSTEMS: + from helios_auth.auth_systems.ldapbackend import backend + auth = backend.CustomLDAPBackend() + user = auth.authenticate(self.username, self.password) + self.assertEqual(user.username, 'euclid') + + def test_ldap_view_login(self): + """ test if authenticates using the auth system login view """ + if 'ldap' in ENABLED_AUTH_SYSTEMS: + resp = self.client.post(reverse(ldap_views.ldap_login_view), { + 'username' : self.username, + 'password': self.password + }, follow=True) + self.assertEqual(resp.status_code, 200) + + def test_logout(self): + """ test if logs out using the auth system logout view """ + if 'ldap' in ENABLED_AUTH_SYSTEMS: + response = self.client.post(reverse(views.logout), follow=True) + self.assertContains(response, "not logged in") + self.assertNotContains(response, "euclid") + diff --git a/helios_auth/urls.py b/helios_auth/urls.py index e4dca39..810d4f8 100644 --- a/helios_auth/urls.py +++ b/helios_auth/urls.py @@ -9,6 +9,8 @@ from django.conf.urls import * from views import * from auth_systems.password import password_login_view, password_forgotten_view from auth_systems.twitter import follow_view +from auth_systems.ldapauth import ldap_login_view + urlpatterns = patterns('', # basic static stuff @@ -28,4 +30,7 @@ urlpatterns = patterns('', # twitter (r'^twitter/follow', follow_view), + + #ldap + (r'^ldap/login', ldap_login_view), ) diff --git a/requirements.txt b/requirements.txt index 2cc4eb8..eb774f3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -22,3 +22,4 @@ boto==2.27.0 django-ses==0.6.0 validate_email==1.2 oauth2client==1.2 +django-auth-ldap==1.2.7 diff --git a/settings.py b/settings.py index f1e2ab2..2f440d5 100644 --- a/settings.py +++ b/settings.py @@ -1,6 +1,7 @@ - +import ldap import os, json +from django_auth_ldap.config import LDAPSearch, GroupOfNamesType # a massive hack to see if we're testing, in which case we use different settings import sys TESTING = 'test' in sys.argv @@ -133,8 +134,8 @@ TEMPLATE_DIRS = ( ) INSTALLED_APPS = ( -# 'django.contrib.auth', -# 'django.contrib.contenttypes', + 'django.contrib.auth', + 'django.contrib.contenttypes', 'djangosecure', 'django.contrib.sessions', #'django.contrib.sites', @@ -206,7 +207,7 @@ HELIOS_VOTERS_EMAIL = True HELIOS_PRIVATE_DEFAULT = False # authentication systems enabled -#AUTH_ENABLED_AUTH_SYSTEMS = ['password','facebook','twitter', 'google', 'yahoo'] +#AUTH_ENABLED_AUTH_SYSTEMS = ['password','facebook','twitter', 'google', 'yahoo','ldap'] AUTH_ENABLED_AUTH_SYSTEMS = get_from_env('AUTH_ENABLED_AUTH_SYSTEMS', 'google').split(",") AUTH_DEFAULT_AUTH_SYSTEM = get_from_env('AUTH_DEFAULT_AUTH_SYSTEM', None) @@ -242,6 +243,27 @@ CAS_ELIGIBILITY_REALM = get_from_env('CAS_ELIGIBILITY_REALM', "") CLEVER_CLIENT_ID = get_from_env('CLEVER_CLIENT_ID', "") CLEVER_CLIENT_SECRET = get_from_env('CLEVER_CLIENT_SECRET', "") +# ldap +# see configuration example at https://pythonhosted.org/django-auth-ldap/example.html +AUTH_LDAP_SERVER_URI = "ldap://ldap.forumsys.com" # replace by your Ldap URI +AUTH_LDAP_BIND_DN = "cn=read-only-admin,dc=example,dc=com" +AUTH_LDAP_BIND_PASSWORD = "password" +AUTH_LDAP_USER_SEARCH = LDAPSearch("dc=example,dc=com", + ldap.SCOPE_SUBTREE, "(uid=%(user)s)" +) +# Populate the Django user from the LDAP directory. +AUTH_LDAP_USER_ATTR_MAP = { + "first_name": "givenName", + "last_name": "sn", + "email": "mail", +} +AUTH_LDAP_GROUP_TYPE = GroupOfNamesType(name_attr="cn") +AUTH_LDAP_FIND_GROUP_PERMS = True +AUTH_LDAP_BIND_AS_AUTHENTICATING_USER = True +AUTH_LDAP_CACHE_GROUPS = True +AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600 +AUTH_LDAP_ALWAYS_UPDATE_USER = False + # email server EMAIL_HOST = get_from_env('EMAIL_HOST', 'localhost') EMAIL_PORT = int(get_from_env('EMAIL_PORT', "2525")) -- GitLab