From: jordan Date: Mon, 2 Apr 2012 23:11:47 +0000 (+0000) Subject: OSQA-425, adding LDAP Based Authentication OSQA module to the core X-Git-Tag: live~76 X-Git-Url: https://git.openstreetmap.org/osqa.git/commitdiff_plain/f57a5fec7dc10c8ae8dba6327c6850ecc0594f99 OSQA-425, adding LDAP Based Authentication OSQA module to the core git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@1241 0cfe37f9-358a-4d5e-be75-b63607b5c754 --- diff --git a/forum_modules/ldapauth/__init__.py b/forum_modules/ldapauth/__init__.py new file mode 100644 index 0000000..e6591f0 --- /dev/null +++ b/forum_modules/ldapauth/__init__.py @@ -0,0 +1,5 @@ +try: + import ldap + CAN_USE = True +except: + CAN_USE = False diff --git a/forum_modules/ldapauth/authentication.py b/forum_modules/ldapauth/authentication.py new file mode 100644 index 0000000..68f366b --- /dev/null +++ b/forum_modules/ldapauth/authentication.py @@ -0,0 +1,65 @@ +from forum.authentication.base import AuthenticationConsumer, ConsumerTemplateContext, InvalidAuthentication +from forum.models import User +from forum.actions import UserJoinsAction +from django.utils.translation import ugettext as _ +from forum import settings + +class LDAPAuthConsumer(AuthenticationConsumer): + + def process_authentication_request(self, request): + username = request.POST['username'].strip() + password = request.POST['password'] + uid = str(settings.LDAP_USER_MASK) % username + + #an empty password will cause ldap to try an anonymous bind. This is picked up here + if not password: + raise InvalidAuthentication(_('Login failed. Please enter valid username and password (both are case-sensitive)')) + + ldapo = ldap.initialize(str(settings.LDAP_SERVER)) + if(settings.LDAP_USE_TLS): + ldapo.start_tls_s() + ldapo.set_option(ldap.OPT_PROTOCOL_VERSION, 3) + try: + ldapo.simple_bind_s(str(settings.LDAP_BIND_DN), str(settings.LDAP_BIND_SECRET)) + search = ldapo.search_s(str(settings.LDAP_BASE_DN), ldap.SCOPE_SUBTREE, uid) + except ldap.LDAPError: + #could not bind using credentials specified in ldap config + raise InvalidAuthentication(_('Login failed - LDAP bind error. Please contact your system administrator')) + + ldapo.unbind_s() + + if not search: + #could not find user + raise InvalidAuthentication(_('Login failed. Please enter valid username and password (both are case-sensitive)')) + + #now try to bind as selected user; should raise exception if bind fails + ldapo = ldap.initialize(str(settings.LDAP_SERVER)) + if(settings.LDAP_USE_TLS): + ldapo.start_tls_s() + ldapo.set_option(ldap.OPT_PROTOCOL_VERSION, 3) + try: + ldapo.simple_bind_s(search[0][1][str(settings.LDAP_DN)][0],password) + except ldap.LDAPError: + #could not bind as user - password is incorrect + raise InvalidAuthentication(_('Login failed. Please enter valid username and password (both are case-sensitive)')) + ldapo.unbind_s() + + try: + return User.objects.get(username=username) + except User.DoesNotExist: + userinfo = search[0][1] + _user = User( username = userinfo[str(settings.LDAP_UID)][0], + email = userinfo[str(settings.LDAP_MAIL)][0], + real_name = userinfo[str(settings.LDAP_NAME)][0] ) + _user.email_isvalid = True + _user.set_unusable_password() + _user.save() + UserJoinsAction(user=_user, ip=request.META['REMOTE_ADDR']).save() + return _user + +class LDAPAuthContext(ConsumerTemplateContext): + mode = 'STACK_ITEM' + weight = 1000 + human_name = 'LDAP authentication' + stack_item_template = 'modules/ldapauth/loginform.html' + show_to_logged_in_user = False diff --git a/forum_modules/ldapauth/settings.py b/forum_modules/ldapauth/settings.py new file mode 100644 index 0000000..f3ce670 --- /dev/null +++ b/forum_modules/ldapauth/settings.py @@ -0,0 +1,54 @@ +from forum.settings.base import Setting, SettingSet +from django.utils.translation import ugettext_lazy as _ + +LDAP_SET = SettingSet('ldap', _('LDAP settings'), _("LDAP configuration for OSQA"), 4) + +LDAP_SERVER = Setting('LDAP_SERVER', '', LDAP_SET, dict( +label = _("LDAP Server"), +help_text = _("The hostname of your organization's LDAP server"), +required = False)) + +LDAP_USE_TLS = Setting('LDAP_USE_TLS', False, LDAP_SET, dict( +label = _("Use TLS"), +help_text = _("Check to use TLS"), +required = False)) + +LDAP_BIND_DN = Setting('LDAP_BIND_DN', '', LDAP_SET, dict( +label = _("DN for binding"), +help_text = _("Enter the DN to use to bind to the LDAP server (leave blank for anonymous bind)"), +required = False)) + +LDAP_BIND_SECRET = Setting('LDAP_BIND_SECRET', '', LDAP_SET, dict( +label = _("Password for binding"), +help_text = _("Password for binding DN above"), +required = False)) + +LDAP_BASE_DN = Setting('LDAP_BASE_DN', '', LDAP_SET, dict( +label = _("Base DN"), +help_text = _("The Base DN used to search for users"), +required = False)) + +LDAP_USER_MASK = Setting('LDAP_USER_MASK', 'UID=%s', LDAP_SET, dict( +label = _("User Mask"), +help_text = _("The mask to query for a User"), +required = False)) + +LDAP_UID = Setting('LDAP_UID', 'uid', LDAP_SET, dict( +label = _("uid field"), +help_text = _("ldap field that holds the uid (sAMAccountName in AD)"), +required = False)) + +LDAP_NAME = Setting('LDAP_NAME', 'cn', LDAP_SET, dict( +label = _("Name field"), +help_text = _("ldap field that holds the full name (displayName in AD)"), +required = False)) + +LDAP_DN = Setting('LDAP_DN', 'dn', LDAP_SET, dict( +label = _("DN field"), +help_text = _("ldap field that holds the distinguished name (distinguishedName in AD)"), +required = False)) + +LDAP_MAIL = Setting('LDAP_MAIL', 'mail', LDAP_SET, dict( +label = _("email field"), +help_text = _("ldap field that holds the email"), +required = False)) diff --git a/forum_modules/ldapauth/templates/loginform.html b/forum_modules/ldapauth/templates/loginform.html new file mode 100644 index 0000000..a702e63 --- /dev/null +++ b/forum_modules/ldapauth/templates/loginform.html @@ -0,0 +1,28 @@ +{% load i18n %} + +
+

{% trans 'Enter your LDAP user name and password' %}

+ + + + + + + + + + + + +
+ + + +
+ + + +
+ +
+