]> git.openstreetmap.org Git - osqa.git/commitdiff
OSQA-425, adding LDAP Based Authentication OSQA module to the core
authorjordan <jordan@0cfe37f9-358a-4d5e-be75-b63607b5c754>
Mon, 2 Apr 2012 23:11:47 +0000 (23:11 +0000)
committerjordan <jordan@0cfe37f9-358a-4d5e-be75-b63607b5c754>
Mon, 2 Apr 2012 23:11:47 +0000 (23:11 +0000)
git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@1241 0cfe37f9-358a-4d5e-be75-b63607b5c754

forum_modules/ldapauth/__init__.py [new file with mode: 0644]
forum_modules/ldapauth/authentication.py [new file with mode: 0644]
forum_modules/ldapauth/settings.py [new file with mode: 0644]
forum_modules/ldapauth/templates/loginform.html [new file with mode: 0644]

diff --git a/forum_modules/ldapauth/__init__.py b/forum_modules/ldapauth/__init__.py
new file mode 100644 (file)
index 0000000..e6591f0
--- /dev/null
@@ -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 (file)
index 0000000..68f366b
--- /dev/null
@@ -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 (file)
index 0000000..f3ce670
--- /dev/null
@@ -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 (file)
index 0000000..a702e63
--- /dev/null
@@ -0,0 +1,28 @@
+{% load i18n %}
+
+<fieldset id='ldap_login_fs'>
+  <p><span class='big strong'>{% trans 'Enter your LDAP user name and password' %}</span><br/></p>
+  <table>
+    <tr>
+        <td>
+             <label for="id_username">{% trans 'Login name' %}</label>
+        </td>
+        <td>
+             <input id="id_username" type="text" class="required login" name="username" maxlength="30" />
+        </td>
+    </tr>
+    <tr>
+        <td>
+              <label for="id_password">{% trans 'Password' %}</label>
+        </td>
+        <td>
+             <input id="id_password" type="password" class="required login" name="password" maxlength="128" />
+        </td>
+    </tr>
+    <tr>
+        <td>
+            <input id="blogin" name="blogin" type="submit" value="{% trans 'Login' %}" />
+        </td>
+    </tr>
+  </table>
+</fieldset>