diff options
-rw-r--r-- | askbot/conf/ldap.py | 91 | ||||
-rw-r--r-- | askbot/deps/django_authopenid/backends.py | 80 |
2 files changed, 139 insertions, 32 deletions
diff --git a/askbot/conf/ldap.py b/askbot/conf/ldap.py index 00c8a5fc..ae916313 100644 --- a/askbot/conf/ldap.py +++ b/askbot/conf/ldap.py @@ -50,8 +50,27 @@ settings.register( settings.register( livesettings.StringValue( LDAP_SETTINGS, - 'LDAP_BASEDN', - description=_('LDAP BASE DN') + 'LDAP_ENCODING', + description = _('LDAP encoding'), + default = 'utf-8', + help_text = _( + 'This value in almost all cases is "utf-8". ' + 'Change it if yours is different. ' + 'This field is required' + ) + ) +) + +settings.register( + livesettings.StringValue( + LDAP_SETTINGS, + 'LDAP_BASE_DN', + description=_('Base DN (distinguished name)'), + help_text = _( + 'Usually base DN mirrors domain name of your organization, ' + 'e.g. "dn=example,dn=com" when your site url is "example.com".' + 'This value is the "root" address of your LDAP directory.' + ) ) ) @@ -62,7 +81,26 @@ settings.register( description = _('User search filter template'), default = '(%s=%s)', help_text = _( - 'Python string format template, must have two string placeholders' + 'Python string format template, must have two string placeholders, ' + 'which should be left in the intact format. ' + 'First placeholder will be used for the user id field name, ' + 'and the second - for the user id value. ' + 'The template can be extended to match schema of your ' + 'LDAP directory.' + ) + ) +) + +settings.register( + livesettings.StringValue( + LDAP_SETTINGS, + 'LDAP_LOGIN_NAME_FIELD', + description = _('UserID/login field'), + default = 'uid', + help_text = _( + 'This field is required. ' + 'For Microsoft Active Directory this value usually ' + 'is "sAMAccountName".' ) ) ) @@ -70,27 +108,51 @@ settings.register( settings.register( livesettings.StringValue( LDAP_SETTINGS, - 'LDAP_SEARCH_SCOPE', - description=_('LDAP Search Scope'), - default="subs" + 'LDAP_COMMON_NAME_FIELD', + description=_('"Common Name" field'), + help_text=_( + 'Common name is a formal or informal name ' + 'of a person, can be blank. ' + 'Use it only if surname and given names are not ' + 'available.' + ), + default = 'cn' + ) +) + +COMMON_NAME_FIELD_FORMAT_CHOICES = ( + ('first,last', _('First name, Last name')), + ('last,first', _('Last name, First name')), +) + +settings.register( + livesettings.StringValue( + LDAP_SETTINGS, + 'LDAP_COMMON_NAME_FIELD_FORMAT', + description = _('"Common Name" field format'), + default = 'first,last', + choices = COMMON_NAME_FIELD_FORMAT_CHOICES, + help_text = _('Use this only if "Common Name" field is used.') ) ) settings.register( livesettings.StringValue( LDAP_SETTINGS, - 'LDAP_USERID_FIELD', - description=_('LDAP Server USERID field name'), - default="uid" + 'LDAP_GIVEN_NAME_FIELD', + description = _('Given (First) name'), + default = 'givenName', + help_text = _('This field can be blank') ) ) settings.register( livesettings.StringValue( LDAP_SETTINGS, - 'LDAP_COMMONNAME_FIELD', - description=_('LDAP Server "Common Name" field name'), - default="cn" + 'LDAP_SURNAME_FIELD', + description = _('Surname (last) name'), + default = 'sn', + help_text = _('This field can be blank') ) ) @@ -98,8 +160,9 @@ settings.register( livesettings.StringValue( LDAP_SETTINGS, 'LDAP_EMAIL_FIELD', - description=_('LDAP Server EMAIL field name'), - default="mail" + description = _('LDAP Server EMAIL field name'), + default = 'mail', + help_text = _('This field is required') ) ) diff --git a/askbot/deps/django_authopenid/backends.py b/askbot/deps/django_authopenid/backends.py index 01a19e4d..5ff49c1b 100644 --- a/askbot/deps/django_authopenid/backends.py +++ b/askbot/deps/django_authopenid/backends.py @@ -15,6 +15,20 @@ from askbot.models.signals import user_registered log = logging.getLogger('configuration') +def split_name(full_name, name_format): + bits = full_name.strip().split() + if len(bits) == 1: + bits.push('') + elif len(bits) == 0: + bits = ['', ''] + + if name_format == 'first,last': + return bits[0], bits[1] + elif name_format == 'last,first': + return bits[1], bits[0] + else: + raise ValueError('Unexpected value of name_format') + def ldap_authenticate(username, password): """ @@ -26,8 +40,6 @@ def ldap_authenticate(username, password): import ldap user_information = None try: - import pdb - pdb.set_trace() ldap_session = ldap.initialize(askbot_settings.LDAP_URL) #set protocol version @@ -38,6 +50,8 @@ def ldap_authenticate(username, password): else: raise NotImplementedError('unsupported version of ldap protocol') + ldap.set_option(ldap.OPT_REFERRALS, 0) + #set extra ldap options, if given if hasattr(django_settings, 'LDAP_EXTRA_OPTIONS'): options = django_settings.LDAP_EXTRA_OPTIONS @@ -51,38 +65,68 @@ def ldap_authenticate(username, password): #add optional "master" LDAP authentication, if required master_username = getattr(django_settings, 'LDAP_USER', None) master_password = getattr(django_settings, 'LDAP_PASSWORD', None) + + login_name_field = askbot_settings.LDAP_LOGIN_NAME_FIELD + base_dn = askbot_settings.LDAP_BASE_DN + login_template = login_name_field + '=%s,' + base_dn + encoding = askbot_settings.LDAP_ENCODING + if master_username and master_password: - ldap_session.simple_bind_s(master_username, master_password) + login_dn = login_template % master_username + ldap_session.simple_bind_s( + login_dn.encode(encoding), + master_password.encode(encoding) + ) user_filter = askbot_settings.LDAP_USER_FILTER_TEMPLATE % ( - askbot_settings.LDAP_USERID_FIELD, - username - ) + askbot_settings.LDAP_LOGIN_NAME_FIELD, + username + ) - get_attrs = ( - str(askbot_settings.LDAP_EMAIL_FIELD), + email_field = askbot_settings.LDAP_EMAIL_FIELD + + get_attrs = [ + email_field.encode(encoding), + login_name_field.encode(encoding) #str(askbot_settings.LDAP_USERID_FIELD) #todo: here we have a chance to get more data from LDAP #maybe a point for some plugin - ) + ] + + common_name_field = askbot_settings.LDAP_COMMON_NAME_FIELD.strip() + given_name_field = askbot_settings.LDAP_GIVEN_NAME_FIELD.strip() + surname_field = askbot_settings.LDAP_SURNAME_FIELD.strip() + + if given_name_field and surname_field: + get_attrs.append(given_name_field.encode(encoding)) + get_attrs.append(surname_field.encode(encoding)) + elif common_name_field: + get_attrs.append(common_name_field.encode(encoding)) # search ldap directory for user user_search_result = ldap_session.search_s( - askbot_settings.LDAP_BASEDN, ldap.SCOPE_SUBTREE, user_filter, get_attrs + askbot_settings.LDAP_BASE_DN.encode(encoding), + ldap.SCOPE_SUBTREE, + user_filter.encode(encoding), + 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) #raises INVALID_CREDENTIALS + ldap_session.simple_bind_s(user_dn, password.encode(encoding)) #raises INVALID_CREDENTIALS ldap_session.unbind_s() - exact_username = user_information[askbot_settings.LDAP_USERID_FIELD][0] - - # Assuming last, first order - # --> may be different - #last_name, first_name = user_information[askbot_settings.LDAP_COMMONNAME_FIELD][0].rsplit(" ", 1) + exact_username = user_information[login_name_field][0] + email = user_information[email_field][0] - email = user_information[askbot_settings.LDAP_EMAIL_FIELD][0] + if given_name_field and surname_field: + last_name = user_information[surname_field][0] + first_name = user_information[given_name_field][0] + elif surname_field: + common_name_format = askbot_settings.LDAP_COMMON_NAME_FIELD_FORMAT + common_name = user_information[common_name_field][0] + first_name, last_name = split_name(common_name, common_name_format) + try: user = User.objects.get(username__exact=exact_username) # always update user profile to synchronize with ldap server @@ -95,7 +139,7 @@ def ldap_authenticate(username, password): # create new user in local db user = User() user.username = exact_username - user.set_password(password) + user.set_password(password)#copy password from LDAP locally #user.first_name = first_name #user.last_name = last_name user.email = email |