summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-07-17 20:36:21 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-07-17 20:36:21 -0400
commite59bf4a4b7acd6d1f06179777d9011fab7eb7147 (patch)
treefee3ffa0e1375d353931f583b31d48a349c3e229
parent3aa250dd29e10563f5a24a1f111b882b74b15402 (diff)
downloadaskbot-e59bf4a4b7acd6d1f06179777d9011fab7eb7147.tar.gz
askbot-e59bf4a4b7acd6d1f06179777d9011fab7eb7147.tar.bz2
askbot-e59bf4a4b7acd6d1f06179777d9011fab7eb7147.zip
added LDAP_AUTHENTICATE_FUNCTION and LDAP_AUTHENTICATE_FAILURE_FUNCTION
-rw-r--r--askbot/deps/django_authopenid/ldap_auth.py43
-rw-r--r--askbot/deps/django_authopenid/views.py45
-rw-r--r--askbot/doc/source/optional-modules.rst16
3 files changed, 76 insertions, 28 deletions
diff --git a/askbot/deps/django_authopenid/ldap_auth.py b/askbot/deps/django_authopenid/ldap_auth.py
index 109bfad7..79d05b44 100644
--- a/askbot/deps/django_authopenid/ldap_auth.py
+++ b/askbot/deps/django_authopenid/ldap_auth.py
@@ -1,10 +1,11 @@
import logging
from django.conf import settings as django_settings
from django.contrib.auth.models import User
-from django.forms import EmailField
+from django.forms import EmailField, ValidationError
from askbot.conf import settings as askbot_settings
-from askbot.models.signals import user_registered
from askbot.deps.django_authopenid.models import UserAssociation
+from askbot.models.signals import user_registered
+from askbot.utils.loading import load_module
LOG = logging.getLogger(__name__)
@@ -25,7 +26,7 @@ def split_name(full_name, name_format):
raise ValueError('Unexpected value of name_format')
-def ldap_authenticate(username, password):
+def ldap_authenticate_default(username, password):
"""
Authenticate using ldap.
LDAP parameter setup is described in
@@ -38,9 +39,19 @@ def ldap_authenticate(username, password):
* last_name
* ldap_username
* email (optional only if there is valid email)
-
+ * success - boolean, True if authentication succeeded
+
python-ldap must be installed
http://pypi.python.org/pypi/python-ldap/2.4.6
+
+ NOTE: if you are planning to implement a custom
+ LDAP authenticate function (python path to which can
+ be provided via setting `ASKBOT_LDAP_AUTHENTICATE`
+ setting in the settings.py file) - implement
+ the function just like this - accepting user name
+ and password and returning dict with the same values.
+ The returned dictionary can contain additional values
+ that you might find useful.
"""
import ldap
user_information = None
@@ -112,14 +123,14 @@ def ldap_authenticate(username, password):
askbot_settings.LDAP_BASE_DN.encode(encoding),
ldap.SCOPE_SUBTREE,
user_filter.encode(encoding),
- get_attrs
+ get_attrs
)
if user_search_result: # User found in LDAP Directory
user_dn = user_search_result[0][0]
user_information = user_search_result[0][1]
ldap_session.simple_bind_s(user_dn, password.encode(encoding)) #raises INVALID_CREDENTIALS
ldap_session.unbind_s()
-
+
if given_name_field and surname_field:
last_name = user_information.get(surname_field, [''])[0]
first_name = user_information.get(given_name_field, [''])[0]
@@ -131,7 +142,8 @@ def ldap_authenticate(username, password):
user_info = {
'first_name': first_name,
'last_name': last_name,
- 'ldap_username': user_information[login_name_field][0]
+ 'ldap_username': user_information[login_name_field][0],
+ 'success': True
}
try:
@@ -139,21 +151,22 @@ def ldap_authenticate(username, password):
user_info['email'] = EmailField().clean(email)
except ValidationError:
pass
-
- return user_info
else:
- return None
+ user_info['success'] = False
except ldap.INVALID_CREDENTIALS, e:
return None # Will fail login on return of None
+ user_info['success'] = False
except ldap.LDAPError, e:
LOG.error("LDAPError Exception")
LOG.exception(e)
- return None
+ user_info['success'] = False
except Exception, e:
LOG.error("Unexpected Exception Occurred")
LOG.exception(e)
- return None
+ user_info['success'] = False
+
+ return user_info
def ldap_create_user(user_info):
@@ -181,3 +194,9 @@ def ldap_create_user(user_info):
assoc.provider_name = 'ldap'
assoc.save()
return assoc
+
+LDAP_AUTH_FUNC_PATH = getattr(django_settings, 'LDAP_AUTHENTICATE_FUNCTION', None)
+if LDAP_AUTH_FUNC_PATH:
+ ldap_authenticate = load_module(LDAP_AUTH_FUNC_PATH)
+else:
+ ldap_authenticate = ldap_authenticate_default
diff --git a/askbot/deps/django_authopenid/views.py b/askbot/deps/django_authopenid/views.py
index 51f04df7..bea8ffe9 100644
--- a/askbot/deps/django_authopenid/views.py
+++ b/askbot/deps/django_authopenid/views.py
@@ -34,12 +34,13 @@ import datetime
from django.http import HttpResponseRedirect, get_host, Http404
from django.http import HttpResponse
from django.template import RequestContext, Context
-from django.conf import settings
+from django.conf import settings as django_settings
from askbot.conf import settings as askbot_settings
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.contrib.auth import authenticate
from django.core.urlresolvers import reverse
+from django.forms.util import ErrorList
from django.views.decorators import csrf
from django.utils.encoding import smart_unicode
from django.utils.html import escape
@@ -50,6 +51,7 @@ from recaptcha_works.decorators import fix_recaptcha_remote_ip
from askbot.skins.loaders import render_into_skin, get_template
from askbot.deps.django_authopenid.ldap_auth import ldap_create_user
from askbot.deps.django_authopenid.ldap_auth import ldap_authenticate
+from askbot.utils.loading import load_module
from urlparse import urlparse
from openid.consumer.consumer import Consumer, \
@@ -136,10 +138,10 @@ def ask_openid(
on_failure = on_failure or signin_failure
trust_root = getattr(
- settings, 'OPENID_TRUST_ROOT', get_url_host(request) + '/'
+ django_settings, 'OPENID_TRUST_ROOT', get_url_host(request) + '/'
)
if xri.identifierScheme(openid_url) == 'XRI' and getattr(
- settings, 'OPENID_DISALLOW_INAMES', False
+ django_settings, 'OPENID_DISALLOW_INAMES', False
):
msg = _("i-names are not supported")
logging.debug('openid failed because i-names are not supported')
@@ -287,7 +289,7 @@ def signin(request):
#1) url parameter "next" - if explicitly set
#2) url from django setting LOGIN_REDIRECT_URL
#3) home page of the forum
- login_redirect_url = getattr(settings, 'LOGIN_REDIRECT_URL', None)
+ login_redirect_url = getattr(django_settings, 'LOGIN_REDIRECT_URL', None)
next_url = get_next_url(request, default = login_redirect_url)
logging.debug('next url is %s' % next_url)
@@ -327,7 +329,7 @@ def signin(request):
else:
#try to login again via LDAP
user_info = ldap_authenticate(username, password)
- if user_info:
+ if user_info['success']:
if askbot_settings.LDAP_AUTOCREATE_USERS:
#create new user or
user = ldap_create_user(user_info).user
@@ -349,10 +351,21 @@ def signin(request):
redirect_url = next_url
)
else:
- request.user.message_set.create(
- _('Incorrect user name or password')
- )
- return HttpResponseRedirect(request.path)
+ auth_fail_func_path = getattr(
+ django_settings,
+ 'LDAP_AUTHENTICATE_FAILURE_FUNCTION',
+ None
+ )
+
+ if auth_fail_func_path:
+ auth_fail_func = load_module(auth_fail_func_path)
+ auth_fail_func(user_info, login_form)
+ else:
+ errors = login_form._errors.setdefault('__all__', ErrorList())
+ errors.append(
+ _('Login failed, were your password/login name correct?')
+ )
+ #return HttpResponseRedirect(request.path)
else:
if password_action == 'login':
user = authenticate(
@@ -845,10 +858,10 @@ def register(request, login_provider_name=None, user_identifier=None):
login_provider_name - as provider_name
this function may need to be refactored to simplify the usage pattern
-
+
template : authopenid/complete.html
"""
-
+
logging.debug('')
next_url = get_next_url(request)
@@ -909,7 +922,7 @@ def register(request, login_provider_name=None, user_identifier=None):
user.save()
user_registered.send(None, user = user)
-
+
logging.debug('creating new openid user association for %s')
UserAssociation(
@@ -921,7 +934,7 @@ def register(request, login_provider_name=None, user_identifier=None):
del request.session['user_identifier']
del request.session['login_provider_name']
-
+
logging.debug('logging the user in')
user = authenticate(method = 'force', user_id = user.id)
@@ -971,7 +984,7 @@ def register(request, login_provider_name=None, user_identifier=None):
data = {
'openid_register_form': register_form,
'email_feeds_form': email_feeds_form,
- 'default_form_action': settings.LOGIN_URL,
+ 'default_form_action': django_settings.LOGIN_URL,
'provider':mark_safe(provider_logo),
'username': username,
'email': email,
@@ -1062,7 +1075,7 @@ def signup_with_password(request):
# 'password': password,
#})
#message = message_template.render(message_context)
- #send_mail(subject, message, settings.DEFAULT_FROM_EMAIL,
+ #send_mail(subject, message, django_settings.DEFAULT_FROM_EMAIL,
# [user.email])
#logging.debug('new password acct created, confirmation email sent!')
return HttpResponseRedirect(next)
@@ -1175,7 +1188,7 @@ def _send_email_key(user):
}
template = get_template('authopenid/email_validation.txt')
message = template.render(data)
- send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [user.email])
+ send_mail(subject, message, django_settings.DEFAULT_FROM_EMAIL, [user.email])
def send_new_email_key(user,nomessage=False):
import random
diff --git a/askbot/doc/source/optional-modules.rst b/askbot/doc/source/optional-modules.rst
index 5db78f70..9e77eb02 100644
--- a/askbot/doc/source/optional-modules.rst
+++ b/askbot/doc/source/optional-modules.rst
@@ -125,6 +125,22 @@ There are three more optional parameters that must go to the ``settings.py`` fil
* ``LDAP_EXTRA_OPTIONS``, a list of two-item tuples - of names and values of
the options. Option names must be upper case strings all starting with ``OPT_``
as described in the `python ldap library documentation <http://www.python-ldap.org/doc/html/ldap.html#options>`_. An often used option is (`OPT_REFERRALS`, 0).
+* ``LDAP_AUTHENTICATE_FUNCTION`` - dotted python path to optional function that
+ can override the default `ldap_authenticate` function. This function allows to
+ completely customize the LDAP login procedure.
+ To see what is expected of this function (input parameters and the return value) -
+ look at the end of the doc string at
+ `askbot.deps.django_authopenid.ldap_auth.ldap_authenticate_default`.
+ One use case for the custom function is determining to which group
+ a user might belong or check any additional access rules that might be
+ stored in your LDAP directory. Another use case - is the case when
+ the default procedure just does not work for you.
+* ``LDAP_AUTHENICATE_FAILURE_FUNCTION`` - python dotted path to an additional function
+ that may be called after a unsuccessful authentication.
+ This function can be used to set custom error messages to the login form.
+ The function should take two parameters (in the following order): user_info, login_form.
+ user_info - is the same dictionary
+ that is returned by the `ldap_authenticate` function.
Use these when you have the "directory master passsword" -
for a specific user who can access the rest of the directory,