12
8

Hello continuing on the question posted OSQA & LDAP Authentication first I tried to create a module suggested by Hernani Cerqueira that inherits from forum.authentication.base.AuthenticationConsume but then after struggling with django (I was unable to create a simple "login box") I gave up and decided to to use the code by Russell Ballestrini slightly modified in localauth (decided to make use of the pretty login box already there) but I'm getting 500's (I believe it is expecting a "user" instead of whatever l.search_s() returns.) I am a total newbie to this, could somebody explain me what module calls LocalAuthConsumer (so I can figure out how to implement ldapauth)? If not that maybe the basics of how modules get used by the website?

Any pointer in the right direction is greatly appreciated!

Thanks for you time!

Wallace

Begin Edit:

This is a VERY simplistic ldap authentication module it is suitable for internal use in a organization. This overwrites authentication.py (in localauth) so you can use the login "local user login" box as you ldap login! Thank you so much Hernani for the help =DDD

import ldap
from forum.authentication.base import  AuthenticationConsumer, InvalidAuthentication, ConsumerTemplateContext
from forms import ClassicLoginForm
from forum.models import User

# ACTIVE DIRECTORY SETTINGS
AD_DNS_NAME = 'example.com'
AD_LDAP_URL = 'ldap://%s' % (AD_DNS_NAME) #no port specified, default port use

class LocalAuthConsumer(AuthenticationConsumer):
    def process_authentication_request(self, request):
        try:
            # Autenticate user in LDAP
            con = ldap.initialize(AD_LDAP_URL)
            username = request.POST.get('username', None)
            password = request.POST.get('password', None)
            if not (username and password):
                raise InvalidAuthentication("Invalid data")
            dn = "%s@%s" % (username, AD_DNS_NAME)
            con.simple_bind_s(dn, password)
            con.unbind_s()
            try:# If user is in datatbase carry on
                _user = User.objects.get(username=username)
            except User.DoesNotExist:# not in the database add user to database
                _user =  User(username=username, email=username + '@example.com')
                _user.email_isvalid = True
                _user.set_unusable_password()
                _user.save()
                UserJoinsAction(user=_user, ip=request.META['REMOTE_ADDR']).save()
            return _user
        # Case the user is not authentic or something goes wrong
        except ldap.NO_SUCH_OBJECT, e:
            con.unbind_s()
            raise InvalidAuthentication("The user does not exist")
        except ldap.INVALID_CREDENTIALS, e:
            con.unbind_s()
            raise InvalidAuthentication("Invalid username or password")
        except ldap.LDAPError, e:
            con.unbind_s()
            raise InvalidAuthentication("LDAP error")

class LocalAuthContext(ConsumerTemplateContext):
    mode = 'STACK_ITEM'
    weight = 1000
    human_name = 'AD authentication'
    stack_item_template = 'modules/localauth/loginform.html'
    show_to_logged_in_user = False

asked 01 Jun '10, 17:04

segfault's gravatar image

segfault
3258913
accept rate: 50%

edited 13 Jul '10, 14:25

1

This looks fantastic. We've got a little OSQA site set up inside of an Active Directory domain and are looking to implement something like this. Is there a simple way to have an email variable that searches the users LDAP "mail" attribute rather than assuming it will be the same as $dn?

(09 Jun '10, 23:14) blooty
3

Follow-on from above comment: Here is the same code as you posted but with the email attribute looked up from LDAP. I'm sure there's a nicer way to implement this, but I'm new to the language! http://pastebin.com/raw.php?i=TkCYKtH9

(10 Jun '10, 02:00) blooty

@blooty, your code on pastebin worked with me with slight changes. I had to separate variables for AD path and Domain path (to construct email address). Just so that someone else might want to try, I have pasted my code at http://pastebin/f61e9eea7 ... Now only 3. things that remains is: 1. I have to figure out how to make this logging thing SSL based.... 2. I want to remove the other providers like facebook, google and openid.... 3. Now since its LDAP based, I can't login with my OSQA Administrator account. How can I make an LDAP user an Administrator in OSQA?

(24 Apr '11, 20:07) bits

bits - might I suggest that you pose the 3 questions in your comment as 3 new questions in their own right on this site, so that each gets suitable exposure? By all means include a link back to this question, as context. I think your question about suppressing logins for facebook, openid etc has already been answered - either here on meta, or on the wiki

(03 May '11, 12:42) Andrew_S ♦
2

Hi, As I posted earlier, we got OSQA configured with LDAP in our company internally (unofficially). Now we are encouraging users to use it. So now there will be more people posting bugs and contributing at meta.osqa.net. I realized that if this option of "LDAP integration + disabling other login methods" could be officially integrated into OSQA code. If we have out of the box intranet friendly option, then this OSQA can be widely adopted in software companies and the user base would shoot up (which definitely helps in different ways). Is some OSQA developer working on this? Code is already on pastebin (3rd comment), all we need is config options for integrating easily. And Config options to remove other login methods. Thanks.

(18 May '11, 22:40) bits

Hey segfault, the process_authentication_request method must return either a full user object or some string that can be used as a key to associate a user to a certain login method.

You have to consider a couple of things, will LDAP be your only authentication provider. Do you want your users to skip the registration part (when they are prompted for a username) when they visit the site for the first time using the LDAP authentication?

After answering this, your implementation may vary a little, then if the code is not to big, just edit your question and post your code and I'll be glad to help you finish that out.

link

answered 01 Jun '10, 19:53

Hernani%20Cerqueira's gravatar image

Hernani Cerq... ♦♦
17.6k76784
accept rate: 53%

Edited my answer. Thanks for the insight!

(02 Jun '10, 11:10) segfault

Guys, first of all congratulations and thanks for your comments on this topic. I got a demand to integrate a testing instance of OSQA to LDAP, and I found here very good materials to work with.

I just would like to share some changes I did in the original code posted by @segfault. The reason for the chances is that all the records of employees in our LDAP is spread across a lot of branches and leafs of the LDAP tree. So, I had to add an additional step to query the user registry's full path. I also fixed a missing import in the original code.

import ldap
from forum.authentication.base import  AuthenticationConsumer, InvalidAuthentication, ConsumerTemplateContext
from forms import ClassicLoginForm
from forum.actions import UserJoinsAction
from forum.models import User

# ACTIVE DIRECTORY SETTINGS
AD_LDAP_URL = 'ldap://host_name_or_ip:port/' #no port specified, default port use

class LocalAuthConsumer(AuthenticationConsumer):
    def process_authentication_request(self, request):
        try:
        # Tests the input (we need both an username and a plain password)
        username = request.POST.get( 'username', None )
        password = request.POST.get( 'password', None )
        if not (username and password):
            raise InvalidAuthentication( "Invalid data" )

        # Open a connection to LDAP
        con = ldap.initialize(AD_LDAP_URL)
    con.protocol_version = ldap.VERSION3

    # Searches the complete path of the user record
    baseDN = "ou=Organization,dc=gov,dc=br" # This is the root of the search
    searchScope = ldap.SCOPE_SUBTREE
    retrieveAttributes = ['']
    searchFilter = "uid=%s" % (username)

    ldap_result_id = con.search( baseDN, searchScope, searchFilter, retrieveAttributes )
    result_type, result_data = con.result(ldap_result_id, 0)
    if (result_data == []):
    raise InvalidAuthentication("The user does not exist")
    else:
    if result_type == ldap.RES_SEARCH_ENTRY:
        dn = str(result_data)[3:][:-7]

    # Validates user credentials
        con.simple_bind_s(dn, password)
        con.unbind_s()
        try:# If user is in datatbase carry on
            _user = User.objects.get(username=username)
        except User.DoesNotExist:# not in the database add user to database
            _user =  User(username=username, email=username + '@organization.gov.br')
            _user.email_isvalid = True
            _user.set_unusable_password()
            _user.save()
            UserJoinsAction(user=_user, ip=request.META['REMOTE_ADDR']).save()
        return _user
    # Case the user is not authentic or something goes wrong
    except ldap.NO_SUCH_OBJECT, e:
        con.unbind_s()
        raise InvalidAuthentication("The user does not exist")
    except ldap.INVALID_CREDENTIALS, e:
        con.unbind_s()
        raise InvalidAuthentication("Invalid username or password")
    except ldap.LDAPError, e:
        con.unbind_s()
        raise InvalidAuthentication("LDAP error. Cause: " + e)

class LocalAuthContext(ConsumerTemplateContext):
    mode = 'STACK_ITEM'
    weight = 1000
    human_name = 'AD authentication'
    stack_item_template = 'modules/localauth/loginform.html'
    show_to_logged_in_user = False

Hope this topic keep helping people out there.

PS: Apologize me for my smelly python code and misused LDAP terms. I'm not a python programmer and just took contact with LDAP some hours ago...

link

answered 20 Jun '12, 17:26

Loreno%20Oliveira's gravatar image

Loreno Oliveira
5626
accept rate: 0%

When literally copying and pasting in segfault's code, I was getting a "exception ldap.NO_SUCH_OBJECT" error that was not being caught. Googling around, the modification that seemed to fix it was similar to Loreno's searching first and connecting with a more verbose dn:

dn = "uid=%s,ou=People,dc=exampledomain,dc=com" % username con.simple_bind_s(dn, password)

I'm guessing that could be because I haven't bothered to figure out which protocol to use, or some other laziness.

Anyways, thanks both Loreno and Segfault! Works great!

(14 Sep '12, 11:56) kdoran

I had to change this a little bit for my LDAP setup:

AD_LDAP_URL = 'ldap://sfosrv01/' # just the LDAP server
....
dn = "uid=%s,cn=users,dc=MYCOMPANY,dc=com" % username # bind info in the dn
con.simple_bind_s(dn, password)

Took a while to figure out, but now it's working perfectly!

link

answered 16 Jul '10, 14:47

Adam%20Derewecki's gravatar image

Adam Derewecki
161
accept rate: 0%

I had to add in con.set_option(ldap.OPT_REFERRALS, 0) to get it to work with the active directory ldap at work, due to it having multiple domain controllers.

link

answered 03 Aug '10, 02:38

pellet's gravatar image

pellet
311
accept rate: 0%

Kedar: The local login dissapeared for me when I hadn't installed the python-ldap package. Also to disable the external login capabilities you can disable them on the module level (think its in local_settings.py)

link

answered 10 Aug '10, 04:47

pellet's gravatar image

pellet
311
accept rate: 0%

Hi Pellet,

Thanks for the revert. Do I have to make any change in any other file for enabling ldap. Say for example, I had to edit, apache2 in php folder and add a line 'extension=ldap.so' for the ldap authentication to work properly. Similarly, do I have to make any change in any of the file by adding some line somewhere?

Best Kedar

(23 Aug '10, 02:32) kedar_apte

The only thing I had to do to install LDAP for Python was to download the installer for Windows, it took care of everything and added itself to the python site-packages. I would have used easy_install to install the ldap module for python but it didnt work. You can get installers for all distros here http://www.python-ldap.org/download.shtml

(25 Aug '10, 02:01) pellet

A bit more context for people who jump into adding LDAP support, as I did this week.

Authentication is done by modules in the "forum_modules" subdirectory. There are modules for authenticating via Facebook, via OpenID, via a local username/password account, and so on. All of these modules, except those listed in the DISABLED_MODULES settings, are imported during startup by code in forum/modules/__init__.py . This is how OSQA allows plugins.

What @segfault wrote is a modification of the "localauth" package. I tried that but found it a bit more complicated to understand because it has to let people be able to create new accounts. Take a look also at the facebookauth system to see a more minimal system.

In ldapauth/ you of course need the the __init__.py so the module can be imported. You'll need an authentication.py which contains "class LDAPAuthConsumer(AuthenticationConsumer):" as well as an "class LDAPAuthContext(ConsumerTemplateContext):". The first is structured as in @segfault 's example. It implements the process_authentication_request method and returns either a User or raises an InvalidAuthentication. The InvalidAuthentication payload is displayed as an error message in the login form error.

Do notice that the localauth does a UserJoinsAction(user=user\\_, ip=request.META['REMOTE_ADDR']).save() when a new user is registered. I haven't yet figured out what it's good for.

The ConsumerTemplateContext says where and how to display the authentication information, eg, as a BIGICON like Facebook or STACK_ITEM like localauth. For LDAP I chose STACK_ITEM. I also tell it a form name which contains the HTML to insert for asking for the username/password.

(Some people may need to add domain, but as we have only one, I didn't worry about it.)

All in all, it wasn't that hard. The biggest problems were 1) finding out that the authentication was done through extension modules and 2) that OSQA isn't using Django's authentication system.

link

answered 26 Nov '10, 15:24

dalke's gravatar image

dalke
3872512
accept rate: 18%

I had a bit of an issue with UserJoinsAction, mainly it was never being imported: http://meta.osqa.net/questions/5684/500-error-with-localauth-ldap-modification

So the app was 500'ing on the call, but the users were never being officially created (my db primary key grew though). It must do something or else it wouldn't be necessary.

Nice alternative method though.

(28 Nov '10, 11:26) azurewraith

Some patches (modules) at: http://jira.osqa.net/browse/OSQA-425

link

answered 09 Apr '11, 22:23

askvictor's gravatar image

askvictor
8634
accept rate: 33%

(02 Feb '12, 11:28) bosch

I have the bitnami osqa setup on Ubuntu 12.04.

Is this the right file/path to be editing? I have other authentication.py files found. Just want to make sure.

/opt/osqa/forum/forum_modules/localauth/authentication.py

Also, is this a simple copy and paste into this file with all my server config info?

Thanks! Ray

link

answered 28 Mar '13, 14:00

rayray519's gravatar image

rayray519
412613
accept rate: 0%

-2

Guys - Some help needed

I am trying to use this ldap login (Microsoft ADS integration). When I use the above code in the authentication.py file, the local login section disappears from the page.I only see external login capabilities.

Also I want to make the external login capabilities to disappear. Do you know where the login page template is stored?

Environment: Ubuntu 10.04, OSQA downloaded on 4th Augus from the SVN. MY SQL 5.1

Best Regards Kedar E:kedar.apte@citiustech.com

link

answered 06 Aug '10, 00:44

kedar_apte's gravatar image

kedar_apte
74125
accept rate: 0%

Kedar, sorry for the downvote, but this section is for answers rather than questions.

(18 Aug '11, 21:49) Catskul
Your answer
toggle preview

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Markdown Basics

  • *italic* or _italic_
  • **bold** or __bold__
  • link:[text](http://url.com/ "Title")
  • image?![alt text](/path/img.jpg "Title")
  • numbered list: 1. Foo 2. Bar
  • to add a line break simply add two spaces to where you would like the new line to be.
  • basic HTML tags are also supported

Tags:

×17
×1

Asked: 01 Jun '10, 17:04

Seen: 6,227 times

Last updated: 28 Mar '13, 14:00

powered by OSQA