Forum OpenACS Q&A: LDAP authentication

Collapse
Posted by Oscar Bonilla on
I'm working on an LDAP Authentication module for the OpenACS. This is hard since AOLServer doesn't have an LDAP module. So step first was to write a nsldap module for AOLServer. I've finnished writing this module, but it still needs debugging. If you know something about LDAP and would like to help debugging this module please download it from http://www.galileo.edu/obonilla/software/nsldap.

Thanks,

-Oscar
Collapse
Posted by Talli Somekh on
Hey Oscar, that's great! Thanks!

And welcome to the community!

talli

Collapse
Posted by Roberto Mello on
Oscar, nice to have you around here.

Is there no LDAP module for Tcl? I've always wondered if, instead of writing AOLserver-specific modules, we should use loadable modules for Tcl instead.

Collapse
Posted by David Cohen on
Not to rain on Oscar's parade, but it looks like someone else did an AOLserver LDAP module back in Feb. 2000. Interesting that he found some conflict with it when AOLserver was also running the Oracle8 module (I assume that's not the aD driver--would similar issues apply?)

Read about it here

As far as LDAP in Tcl, well, this might be of some interest:

This is about adding a command to the Tcl interpreter so you can get access to the LDAP C library.

There's a Tcl shared library for LDAP on this page of LDAP software

And, just in case someone forgot about this, the ACS has an LDAP module too: see it here

(I don't know the licensing issues, etc., though this was done a while ago, so perhaps it would be GPL'd or whatever the original ACS license was?)

This message from openldap.org suggests that there is Tcl LDAP code from a guy at Neosoft (though when I looked through all the packages the LDAP packages seemed to be for Tcl 7.6, etc. and not the one this guy was talking about.

In any case, it does seem like there is some stuff out there to do LDAP with Tcl.

Collapse
Posted by Don Baccus on
The conflict's not with the aD Oracle driver, but with Oracle, which includes its own ldap library.  Oscar mentions this on his web page.

The note you refer to does mention that the person hacked together an ldap extention to AOLserver but it doesn't mention him releasing it.  Or documenting it. Or anything like that.

The aD acs-ldap-authentication package relies on Oracle's embedded ldap capabilities.  Not terribly useful for OpenACS 4.  Think Postgres.  Think future RDBMSs we might want to support.  Oscar may want to use this as a starting point, replacing the Oracle dependencies with calls to nsldap.  I've looked at the package and it's a hack, though.

An LDAP authentication package for OpenACS 4 that doesn't require Oracle would be welcome by some folks.  I have no doubt of that.

Collapse
Posted by Tom Jackson on

This looks like a very nice high level ldap api, with connection pooling as well. I better re-install openldap and give it a whirl. Thanks Oscar!

Collapse
Posted by David Cohen on
Thanks Don and Oscar (in private email) for explaining to me the relationship of the items I posted to Oscar's current efforts. In brief, it seems that there are issues with all of these things that make them less than ideal in one way or another, ranging from lack of availability of the code to needing to do surgery on AOLserver.

(Though I was wondering: how bad would it be to extend the AOLserver Tcl interpreter in order to incorporate, say, a Tcl LDAP module or some other feature that might only be available in straight Tcl?)

Anyway, I'm glad to hear that Oscar had checked all this stuff out before going to the trouble of writing his new module, which fulfills a need that apparently wasn't fulfilled before.

Collapse
Posted by Dan Wickstrom on
Extending the tcl interpreter is dead simple as there are hundreds of examples of how to do it in the aolserver source code, though you have to be careful that the underlying library that you're extending is thread-safe.  If the library is not thread-safe, there are work-arounds that have the unfortunate side-effect of limiting performance.
Collapse
Posted by Luke Pond on
Oscar, do you have a minute to post an example of how to use the nsldap API to look up passwords for a list of users?  I'm thinking that it would be really simple to synchronize OpenACS passwords on a network by writing a procedure that periodically searches the directory (via nsldap) for each of the users in the database, and updates their password if it has changed.  I haven't worked with LDAP before, so I want to be sure I'm going about this the right way.
Collapse
Posted by Oscar Bonilla on
This is (more or less) how I do it (note the ob_md5 proc which I wrote to be able to check FreeBSD's MD5 passwords from LDAP). I guess if you don't use encryption you can just stuff whatever the LDAP server gives you for userPassword into the db.
proc_doc -public ldap_auth_user { email password } {
    Returns 1 if the password field matches the password stored
    in the ldap directory and 0 otherwise.

    @param email is the users email address
    @param password is the users password
} {
    set lh [ns_ldap gethandle ldap]
    
    set result [ns_ldap search $lh -scope subtree "o=Universidad Galileo" "(mail=$email)" userpassword]

    # we don't need an ldap handle anymore
    ns_ldap releasehandle $lh

    set n [llength $result]

    if {$n != 1} {
        # multiple matches so can't authenticate
        return 0
    }

    set r [lindex $result 0]

    array set ra $r
    if [empty_string_p [array names ra "userpassword"]] {
        # no userpassword attribute so return false
        return 0
    }
    # now it's safe to do this
    set crypt_password [lindex $ra(userpassword) 0]

    regexp "{(.*)}(.*)" $crypt_password foo cypher ldap_password
    if ![string compare $cypher "crypt"] {
        if [regexp "$1$(.*)$(.*)" $ldap_password foo salt hash] {
            if ![string compare $ldap_password [ob_md5 $password $salt]] {
                return 1
            } else {
                # the passwords don't match
                return 0
            }
        } else {
            # if it doesn't look like FreeBSD's MD5 stuff it should
            # be standard crypt
            # the salt is in the first two letters
            if ![string compare $ldap_password [ns_crypt $password [string range $ldap_password 0 1]]] {
                # we have a winner
                return 1
            }
            return 0
        }
    } else {
        # unknown cypher (I only support crypt) so log it
        ns_log Notice "ldap-api: unknown cypher $cypher"
        return 0
    }
    # this should not be reached
    ns_log "ldap-api: end of function reached something funny going on"
    return 0
}
Collapse
Posted by Don Baccus on
Is periodic sync'ing really how we want to do it?  Any time delay after changing a password will be annoying to the user.
Collapse
Posted by Oscar Bonilla on
I would't do periodic sync'ing. I would change the login page
to check LDAP (for auth) and then look in the db if the user
already exists. If the user exists and his password from the
db is not the same as the LDAP password I would update the db
with the LDAP password (i.e. make the LDAP authoritative). If
the user doesn't exist in the db I would create it from the
info stored in LDAP.

I would write the code to do this (I think it's fairly simple)
but I've got a lot of other stuff to do right now. I guess in
a couple of weeks I could look into this.

Collapse
13: Re: LDAP authentication (response to 1)
Posted by Lars Pind on
Oscar,

This is very interesting for us (and Greenpeace).

Have you run this nsldap code in production?

Is it thread-safe, robust, production-quality?

If not, do you know what needs to happen?

/Lars

Collapse
14: Re: LDAP authentication (response to 13)
Posted by Oscar Bonilla on
Have you run this nsldap code in production?

Yes, it's been running on production machines since january 9 2002.

Is it thread-safe, robust, production-quality?

It is thread safe, robust and production-quality. The only weird thing is that it uses pools (like the db module) and thus it can't bind dynamically as a specific user. This could be a problem if people want to use ldap binding as an authentication method (as opposed to using a priviledged account on the LDAP and checking the users's password).

I have some ideas for implementing the ldap bind call as a user api, but haven't had time to implement it. If there's interest I could probably do it in a couple of days (but I can't start working on it for at least a couple of weeks since I'm in the process of relocating)...

Regards,

-Oscar

Collapse
15: Re: LDAP authentication (response to 1)
Posted by Lars Pind on
Oscar,

Does nsldap support connecting to the LDAP server over SSL, or should we look into other options, such as setting up a VPN connection between the box running OpenACS and the box running the LDAP server?

/Lars

Collapse
16: Re: LDAP authentication (response to 15)
Posted by Rocael Hernández Rizzardini on
Lars, if there is no SSL support I'll recomend you to use ssh port forwarding instead of setting up a VPN.
Collapse
17: Re: LDAP authentication (response to 1)
Posted by Lars Pind on
Oscar,

I get this error in my server error log from time to time (after calling nsldap about 10 times), and then the server restarts:

nsd: ../../../libraries/libldap/error.c:221: ldap_parse_result: Assertion `r != ((void *)0)' failed.

Have you ever seen that before?

/Lars

Collapse
18: Re: LDAP authentication (response to 1)
Posted by Lars Pind on
Wait, I think I know why ...

It happens when I've restarted the LDAP server :)

/Lars

Collapse
Posted by Georg Lehner on
Hello Oscar

Is the source of the ob_md5 proc available to the public?