Forum .LRN Q&A: External authentication with dotLRN (LDAP)

Hello,
I guess I need help setting up external authentication for dotLRN.

This is what I have:
AOLServer 4.0.10
dotLRN 2.1.1
Postgres 7.4.7

I wish to authenticate user logins to Active Directory handled by our Windows 2000 servers.

Following the instructions as per https://openacs.org/doc/openacs-5-1/install-ldap-radius.html

I installed Openldap
Then I installed ns_ldap

amended my config.tcl and added the following lines:

# LDAP authentication
ns_param nsldap ${bindir}/nsldap.so

#
# ldap pool ldap
#
ns_section "ns/ldap/pool/ldap"
ns_param user "cn=administrator, o=mycompany"
ns_param password "mypassword"
ns_param host "myserver:389"
ns_param connections 1
ns_param verbose on

#
# ldap pools
#
ns_section "ns/ldap/pools"
ns_param ldap ldap

#
# ldap default pool
#
ns_section ns/sever/${server}/ldap
ns_param Pools *
ns_param DefaultPool ldap

I then restarted everything and went into the dotLRN using a local admin account

Went into Control Panel, .LRN Site wide administration, OpenACS Site Wide Administration, Authentication
Created a new Authority
Shortname = myldap
Authentication = LDAP
Password Management = LDAP
Account registration = LDAP
USer Info = LDAP
Batch sync enabled = Yes
GetDocument implementation = Local Filesystem
Process Document = IMS enterprise 1.1

(The rest of the fields are left blank)

Under Configure Drivers for this authority, parameters are:
DNPattern = uid={username}, cn={screen_name}, mail={email}
UsernameAttribute = uid
Elements = username email first_names last_name url
SnapshotPath =
BaseDN = dc=ourdomain,dc=com
InfoAttributeMap = first_names=givenName;last_name=sn;email=mail
IncrementalPath =
Attributes =
PasswordHash = MD5

I have tried it with the PasswordHash set to SHA, SSHA and CRYPT but this doesn't make a difference.

Once all this is set I am now trying to log in using a uid and password that is set up on our Windows domain. But the login is refused as username or password invalid.

Where am I going wrong? Is there something else I need to change? Have I installed the correct drivers/packages?
How can I diagnose where the problem is and where it gets stuck? Is there any other documentation out there? Any help would be greatly appreciated.

Collapse
Posted by Shahid Butt on
I have managed to make some progress. My new amended config.tcl file is:

# LDAP authentication
ns_param nsldap ${bindir}/nsldap.so

#
# ldap pool ldap
#
ns_section "ns/ldap/pool/ldap"
ns_param user "CN=admin,OU=Users,DC=mydomain,DC=com"
ns_param password "mypassword"
ns_param host "ldap://x.x.x.x:389"
ns_param connections 1
ns_param verbose on

#
# ldap pools
#
ns_section "ns/ldap/pools"
ns_param ldap ldap

#
# ldap default pool
#
ns_section ns/server/${server}/ldap
ns_param Pools *
ns_param DefaultPool ldap

This at least loads up the ns_ldap module. But I am still unable to connect to the LDAP server and see any users.

Collapse
Posted by Shahid Butt on
I have made the default authentication as LDAP, new registrations are also set to be handled by LDAP.

Tried to create a new user and I am getting this message:

Error in include template "/var/lib/aolserver/nccedudotlrn/packages/acs-subsite/lib/user-new": Transaction aborted: could not allocate 1 handle from pool "ldap"

No doubt this means that my ldap is working properly yet. Does anyone know how I can narrow down where it is happening? Are there any tests I can do at the server?

Collapse
Posted by Shahid Butt on
Update.

I amended the file /etc/openldap/ldap.conf

It reads

#
# LDAP Defaults
#

# See ldap.conf(5) for details
# This file should be world readable but not world writable.

BASE dc=mydomain, dc=com

#SIZELIMIT 12
TIMELIMIT 15
#DEREF never
HOST IPaddress

I can now carry out ldapsearch commands at the command prompt.

dotLRN still not working. When I try to add a new user, which should go off and add it to the Active directory I am getting this message:
Error in include template "/var/lib/aolserver/nccedudotlrn/packages/acs-subsite/lib/user-new": Transaction aborted: nsldap [add]: No such object

If I leave the screen name blank then I get this message:
Error in include template "/var/lib/aolserver/nccedudotlrn/packages/acs-subsite/lib/user-new": Transaction aborted: nsldap [add]: Invalid DN syntax

Any ideas? I'm assuming its something to do with the 'Configure drivers for this authority' screen.

On the add user screen, if I fill in the screen name field the

Collapse
Posted by Shahid Butt on
I seem to be talking to myself here? :0
Collapse
Posted by Carl Robert Blesius on
I will see if I can get some documentation of our Active Directory Autosync setup over the next day or two Shahid (have to review, update, and contribute). Can not give you details now, but it does work, so do not give up because of the temporary silence. I will look for an older copy and send it to you by email.
Collapse
Posted by Malte Sussdorff on
No, you are not alone, but sadly a remote diagnosis is really hard without knowing about the setup in detail. E.g. you are saying that the create user statement fails. What is the exact error message in the error log? Does it come from LDAP or from OpenACS. If it is from OpenACS, there might be a problem with the code. If it comes from LDAP, most likely soething in the authority section is wrong. But without looking at the values you filled in it is hard to say.

Carl's documentation might help, but you should have gotten the email with the instructions already (I got them from Carl).

In general, we should find an *EASY* way for OpenACS to connect to LDAP directories (Moodle seems to make this considerably easier).

Collapse
Posted by Shahid Butt on
Contents of the Error Log

[07/Oct/2005:16:19:01][27638.4119059376][-conn:nccedudotlrn::2] Notice: Querying 'abort transaction;'
[07/Oct/2005:16:19:01][27638.4119059376][-conn:nccedudotlrn::2] Notice: Ns_PgExec: Rolling back transaction
[07/Oct/2005:16:19:01][27638.4119059376][-conn:nccedudotlrn::2] Notice: dbinit: sql(localhost::nccedudotlrn): 'abort transaction'
[07/Oct/2005:16:19:01][27638.4119059376][-conn:nccedudotlrn::2] Error: Error in include template "/var/lib/aolserver/nccedudotlrn/packages/acs-subsite/lib/user-new": Transaction aborted: nsldap [add]: No such object
nsldap [add]: No such object
while executing
"ns_ldap add nsldap0 {sAMAccountName=test2,cn=test,mail=test2.user@mydomain.com,cn=Users, dc=mydomain, dc=com} objectClass {top person user organizationalP..."
("eval" body line 1)
invoked from within
"eval [concat ns_ldap add [list $lh] [list $dn] $attributes]"
("uplevel" body line 3)
invoked from within
"uplevel $body "
("uplevel" body line 1)
invoked from within
"uplevel $on_error"
invoked from within
"with_catch errmsg {
ns_log Notice "LDAP: Adding user: [concat ns_ldap add [list $lh] [list $dn] $attributes]"
eval [concat ns_ldap add..."
(procedure "auth::ldap::registration::Register" line 34)
invoked from within
"auth::ldap::registration::Register $parameters $username $authority_id $first_names $last_name $screen_name $email
$url $password $secret_question $se..."
(procedure "AcsSc.auth_registration.register.ldap" line 1)
invoked from within
"AcsSc.auth_registration.register.ldap {BaseDN {cn=Users, dc=mydomain, dc=com} UsernameAttribute {sAMAccountNMame } PasswordHash N/A DNPattern sAMAccount..."
("uplevel" body line 1)
invoked from within
"uplevel $func_and_args"
(procedure "apply" line 3)
invoked from within
"apply $proc_name $arguments"
(procedure "acs_sc_call" line 6)
invoked from within
"acs_sc_call -error=$error_p $contract $operation $call_args $impl"
(procedure "acs_sc::invoke" line 17)
invoked from within
"acs_sc::invoke -error -impl_id $impl_id -operation Register -call_args [list $parameters $username $authority_id $first_names $last_name $scr..."
(procedure "auth::registration::Register" line 13)
invoked from within
"auth::registration::Register -authority_id $authority_id -username $username -password $password -first_names
$first_names -last_name $last_name ..."
invoked from within
"if { [string equal $creation_info(creation_status) "ok"] } {
# Need to find out which username was set
set username $creation_..."
("uplevel" body line 16)
invoked from within
"uplevel 1 $transaction_code "
(procedure "db_transaction" line 1)
invoked from within
"db_transaction {
array set creation_info [auth::create_local_account -user_id $user_id -authority_id $authority_id -username $username -ar..."
(procedure "auth::create_user" line 32)
invoked from within
"auth::create_user -user_id $user_id -verify_password_confirm -username $username -email $email -first_names $
first_names -last_name $last_name ..."
invoked from within
"array set creation_info [auth::create_user -user_id $user_id -verify_password_confirm -username $username -email $email -first_names $first_names..."
("uplevel" body line 2)
invoked from within
"uplevel 1 $transaction_code "
(procedure "db_transaction" line 39)
invoked from within
"db_transaction {
array set creation_info [auth::create_user -user_id $user_id -verify_password_confirm -username $username -email $email ..."
("uplevel" body line 3)
invoked from within
"uplevel #$level $on_submit"
("1" arm line 1)
invoked from within
"switch $errno {
0 {
# TCL_OK
}
1 {
# TCL_E..."
(procedure "ad_form" line 612)
invoked from within
"ad_form -extend -name register -on_request {
# Populate elements from local variables

} -on_submit {

db_transaction {
array set crea..."
("uplevel" body line 67)
invoked from within
"uplevel {
# Expects parameters:
#
# self_register_p - Is the form for users who self register (1) or
# for administrators who..."
(procedure "code::tcl::/var/lib/aolserver/nccedudotlrn/packages/acs-s..." line 2)
invoked from within
"code::tcl::$__adp_stub"
invoked from within
"if { [file exists $__adp_stub.tcl] } {

# ensure that data source preparation procedure exists and is up-to-date
adp_init tcl $__adp_stub
..."
("uplevel" body line 3)
invoked from within
"uplevel {

if { [file exists $__adp_stub.tcl] } {

# ensure that data source preparation procedure exists and is up-to-date
adp_init t..."
(procedure "adp_prepare" line 2)
invoked from within
"adp_prepare "
(procedure "template::adp_parse" line 30)
invoked from within
"template::adp_parse [template::util::url_to_file "/packages/acs-subsite/lib/user-new" "$__adp_stub"] [list next_ur
l "[lang::util::localize ${next_url}..."

Collapse
Posted by Carl Robert Blesius on
It is good to hear you got ldapsearch working Shahid, that is an important step.

I am assuming that you can do something like this now:

ldapsearch -h ad.yourdomain.com -D "CN=youruseraccount,CN=Users,DC=yourdomain,DC=com" -x -W -b "CN=Users,DC=yourdomain,DC=com" -t cn=youruseraccount

And it asks you for your password and spits out a lot of data.

Reference:
-h: Domain Controler NetBios Name/Fully Qualified Domain Name
-D: The Distinguished Name of the user account used to query Active Directory
-x: Simple authentication mechanism
-b: The Base Distinguished Name of the starting point for the search
-W: Prompt for simple authentication

If that works, then the backend pieces are working and you can use that info to fill in the driver .

Can you give me the details on what you are trying to do?

I just read through your posts in more detail and I am not sure what you are trying to do.

I assume your users are already in Active Directory?

If you got the ldapsearch working, see if you can get On-Demand Sync working next, with password management, account registration, and batch sync all disabled (because I can assure you that works).

I am also interested in which version of the code you are running. We made some minor fixes that are now in 5.2 and/or HEAD

Collapse
Posted by Shahid Butt on
Background Info

I have on Fedora Core 3
AOLServer 4.0.10
dotLRN 2.1.1
Postgres 7.4.7

Within dotLRN I have installed
Authentication 5.1.4
LDAP Authentication 1.0d2
nsldap v1.6
OpenLdap v2.2.26

What I want to do is to implement external authentication of the users when logging into the dotLRN. The user names and password are to be held in Active Directory on a Windows Server.

New Registrations must also be stored in the Active Directory.

The reasoning behind this is that we have a number of other systems installed on the network, which the users will also need access to and I'm sure you would agree with me, that no body wants to have 5 different logins to access 5 different systems. All the access rights will be held in Active Directory and once your logged in then the "system would know" where you were allowed to go and what access you had.

Collapse
Posted by Trenton Cameron on
I am experianceing a similar problem trying to authenticate against active directory. When I run the search
ldapsearch -h ad.yourdomain.com -D "CN=youruseraccount,CN=Users,DC=yourdomain,DC=com" -x -W -b "CN=Users,DC=yourdomain,DC=com" -t cn=youruseraccount

everything works fine. In fact when I run ethereal and try to authenticate from openacs it is giving a reply with the user information. Active directory does not return the password hash with this querry (As far as I know it will not return the password or hash) Is this what is causing my problems? If so is there another way around it? If not what am I missing. Thanks again.
-Trent

Collapse
Posted by Michael Steigman on
Trent,

You have hit upon your problem. AD will not return password information. You must attempt to bind as the user in question in order to authenticate. Malte added this support to nsldap and the LDAP driver. We subsequently modified that support on oacs-5-2 so that it is configurable via the authority admin pages. However, if you are not running from an oacs-5-2 checkout you will have to go in and edit auth-ldap-procs.tcl by hand to enable it. I posted some documentation (now out of sync with oacs-5-2 code) which Malte or Carl may have passed along already that should help you. It's located here: https://openacs.org/storage/view/miscellaneous/OpenACS_LDAP_Integration.doc. In particular, check out the section titled "Enabling bind support and FDN lookup".

Keep in mind that you also need to be running the version of nsldap with bind support. Since the modified module isn't yet in aolserver's CVS repository, it's currently available only from a few people in the community. If you don't have that code, let us know and we'll get it to you.

Collapse
Posted by Michael Steigman on
Actually, let me correct myself a bit - it does appear that Malte has updated the documentation (linked to in the original post) and has made the latest nsldap code available from his site, though there is a typo in the URL - an extra s in resources. I still think, though, the documentation I pointed you to will be a little more helpful in getting things going.
Collapse
Posted by Trenton Cameron on
Thanks for all of your help openacs is now authenticating against active directory! One more quick question. Is there a way to have this use ldaps or ldap over ssl instead of sending everything in clear text? Thanks again
-Trent
Congrats Trenton. Maybe you could help out Shahid. I'm not sure if he made progress.

We have not figured out how to do it over ldaps or over ssl yet, but it is on our todo list.

Our Active Directory setup allows GSSAPI and GSS-SPNEGO

I was able to find out using the following command:

ldapsearch -h ad.yourdomain.com -D "CN= youruseraccount,CN=Users,DC=yourdomain,DC=com" -x -W -b "" -s base -LLL supportedSASLMechanisms

I think GSSAPI uses Kerberos V to provide secure authentication services

I was able to get it working securely on my powerbook using ldapsearch and iirc I got it to work on debian after installing some Kerberos packages (although it has been awhile since I looked at this).

I am going to be traveling to conferences the next 10 days so I doubt I will have time to help out, but I hope to contribute to figuring this part out when I get back (if you haven't already figured it out with Michael).

Collapse
Posted by Patrick Giagnocavo on
In terms of LDAP over SSL, the simplest way might be to use the "stunnel" program, which will put a SSL wrapper around your traffic. You could also use SSH port forwarding as well.
Collapse
Posted by Trenton Cameron on
Thanks for the sugestion Stunnel works great. Because the LDAP server (active directory) supports LDAPS I only needed to run
stunnel -c -d ldap -r myserver:ldaps
Then in the config file I set ldap to send its queries to the local host. Thanks again for all of the help.
Collapse
Posted by Shahid Butt on
Great news, we have managed to get it working. And I've managed to replicate the solution onto our UAT server. As a summary this is what we did:

Install Openldap and ns_ldap
Installed OpenLDAP and ns_ldap as per instructions:
https://openacs.org/doc/openacs-5-1/install-ldap-radius.html
(NOTE: When installing ns_ldap, you must ensure that the environment vaiable AOLSERVER is set.)

Edit ldap.conf
Edited /usr/local/openldap/etc/openldap/ldap.conf
and /etc/ldap.conf

Added the lines:
host [IP Address]
base dc=[mydomain],dc=com

Test with ldapsearch
At this stage I was able to do an ldapsearch command, great!:
ldapsearch -x ""
or
ldapsearch -x -v -h [IP Address] "" -s base '(objectclass=*)'

dotLRN changes:
I Installed the following services in dotLRN:
Authentication 5.1.4
LDAP Authentication Driver 1.0d2

Downloaded auth-ldap-procs.tcl version 1.9.2.1 from here
http://cvs.openacs.org/cvs/*checkout*/openacs-4/packages/auth-ldap/tcl/auth-ldap-procs.tcl?rev=1.9.2.1

Edited the file:
Changed
from
set ldap_bind_p 0
to
set ldap_bind_p 1

(uncomment)
from
#set cn $username
to
set cn $username

(change)
from
if {[ns_ldap bind $lh "cn=$cn" "$password"]} {
to
set fdn [lindex [lindex [ns_ldap search $lh -scope subtree $params(BaseDN) "($params(UsernameAttribute)=$username)" dn] 0] 1]
ns_log Debug "FDN: $fdn"
if {[ns_ldap bind $lh $fdn $password]} {

(new line)
from
# We do not check LDAP account status
set result(account_status) ok

return [array get result]
to
# We do not check LDAP account status
set result(account_status) ok

ns_log Notice "FDN [array get result]"

return [array get result]

Edit the run file under
[dotlrn]/etc/daemontools
Before the exec command enter
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/openldap/lib
export LD_LIBRARY_PATH

Edit the config.tcl file

Remove the '#' in front of the line
ns_param nsldap ${bindir}/nsldap.so

Add the following to the end of the file:

ns_section "ns/ldap/pool/ldap"
ns_param user "cn=[user],ou=[AD Dir],dc=[mydomain],dc=com"
ns_param password "[password]"
ns_param host "[IP Address]"
ns_param connections 2
ns_param verbose On

#
# ldap pools
#
ns_section "ns/ldap/pools"
ns_param ldap ldap

#
# ldap default pool
#
ns_section ns/server/${server}/ldap
ns_param Pools *
ns_param DefaultPool ldap

Create new authority under http://[mydomain]/acs-admin/auth/

Change the users default Authority to LDAP

Hey presto LDAP authentication is working!

Phew!

Collapse
Posted by Shahid Butt on
I must be missing something. I thought I had it working, but the thing is that the system will let me log in using a valid username but with any password. Even if the password is wrong. It doesn't go back to authenticate the password. This can't be right. Truely an open source system.
Has anyone come across this before? Why isn't it going to Active Directory to check the password? Must be a parameter or something that I've missed...
Collapse
Posted by Trenton Cameron on
Well I haven't had time to look through what you did to figure out what you did wrong.  Here is what I did (I know it works)  maybe you can go through it and see what differences there are:

Setting up ldap bind for openACS

First the docs/files you will need

https://openacs.org/doc/openacs-5-1/install-ldap-radius.html <-instructions on setting up nsldap

http://www.sussdorff.de/ressources/nsldap.tgz <- latest version of nsldap

First set up ldap:  For RedHat you will need the openldap-devel openldap-clients and openldap packages.  Then edit the /etc/openldap/ldap.conf file
#SIZELIMIT      12
TIMELIMIT      15
#DEREF          never
HOST 127.0.0.1
BASE dc=xxxx, dc=xxx, dc=xxx
TLS_CACERTDIR /etc/openldap/cacerts

next run a query to make sure everything is working
ldapsearch -H ldap://localhost -D "CN=my name ,OU=xxxx_users,DC=xxxx,DC=xxx,DC=xxx" -x -W -b "OU=xxxx_users,DC=xxxx,DC=xxx,DC=xxx" sAMAccountName=myaccount

be sure to replace the CN and sAMAccountName

if you got a result after entering your windows password congrats you are now talking to ldap.

Now time to set up openACS

first get the module from http://www.sussdorff.de/ressources/nsldap.tgz
now expand it just like any other aolserver module.  Make sure that you AOLSERVER enviroment variable is set and make it on RedHat the command was

make LDAP=/usr/

if everything went well copy the ldap.so file into the bin directory

now edit the config file.  There are some examples in the README that came with the nsldap tarbal.  These are the changes I ended up making

in the modules section uncomment the
ns_param  nsldap            ${bindir}/nsldap.so

then at the end of the file insert

        ns_section "ns/ldap/pool/ldap"
        ns_param user "cn=my name,ou=xxxx_users, dc=xxxx, dc=xxx, dc=xxx"
        ns_param password "MyPassword"
        #Connection is to local host because stunnel will encrypt it and send it to the DC
        ns_param host "127.0.0.1"
        ns_param connections 1
        ns_param verbose On

        #
        # ldap pools
        #
        ns_section "ns/ldap/pools"
        ns_param ldap ldap

        #
        # ldap default pool
        #
        ns_section "ns/server/${server}/ldap"
        ns_param Pools *
        ns_param DefaultPool ldap

the CN in this case is the CN you have set up to query LDAP

Now install the latest versions of acs-authentication and auth-ldap and restart the server

the next steps come from the document
https://openacs.org/storage/view/miscellaneous/OpenACS_LDAP_Integration.doc

The following is a cut and paste from that document

Enabling bind support and FDN lookup

Now you’ve got your user database prepped and authority configured. The last step is to edit the tcl file /packages/auth-ldap/tcl/auth-ldap-procs.tcl. First, find the line that reads set ldap_bind_p 0 and change the 0 to a 1. Then, comment out the line:

set cn $username

and add the following:

set fdn [lindex [lindex [ns_ldap search $lh -scope subtree $params(BaseDN) "($params(UsernameAttribute)=$username)" dn] 0] 1]

Next, replace cn=$cn with $fdn in the ns_ldap bind call a few lines down, save and reload the file using the package manager or simply restart your server. This will change the default behavior and enable users to log in with their CN.

--End cut and paste
Quick comment on that ... The first time I did this I didn't understand the replace cn=$cn with $fdn.  You need to delete cn=$cn and replace the whole string whith $fdn.

you now need to restart/reload that tcl file.

Next we need to set up the authentication so under acs-admin/auth add an authority and configure it to use ldap.  Then configure the driver.  The settings I have are
UsernameAttribute sAMAccountName
BaseDN ou=xxxx_users,dc=xxxx,dc=xxx,dc=xxx
PasswordHash MD5 (I don't think this last one is necessary)

Almost done ...  Now we just need to modify our users to be under this authority

First in the database we need to find the authority_id
select authority_id, short_name from auth_authorities

now use that id and the AD username to update the accounts
update users set username = :new_username, authority_id =  'your_id' where user_id = :user_id

The last thing we need to do is edit the kernel parameter that has us user email for login we now want to use username.  Set UseEmailForLoginP to 0 instead of one.

That should do it ... log out and log back in as a user using there AD information.

As a last note ethereal was my friend.  Looking at the packets really helped me deduce what was going on behind the scenes.  Good luck
    -Trent

Collapse
Posted by Michael Steigman on
Thanks Patrick and Trent for sharing the stunnel tip. That's very helpful. Glad you've managed to get things working for the most part.

There are a couple of things to look out for at this point - first, I found a bug in the way I documented the FDN search and bind call. Basically, your call should look like this:

if { ![empty_string_p $fdn] && [ns_ldap bind $lh "$fdn" "$password"]} {
	    set result(auth_status) ok
}

Otherwise, if the FDN search returns nothing and anonymous binds are allowed, your attempt to bind will be successful regardless of the password and you will get a very confusing message stating that you have authenticated but don't have a local account. This is fixed in version 1.9.22 (oacs-5-2 branch). Shahid - this is where authentication takes place so make sure your auth-ldap-procs has that "ns_ldap bind" call in the right place.

Also, keep in mind that after you upgrade (and restart the server or reload the procs) to the as yet unreleased newer auth-ldap package, you will need to visit your auth admin pages and set your LDAP authority's BindAuthenticationP parameter to 1 in order to have things work as before. Might be easier just to grab 1.9.22 and set that up while you are tinkering with authentication.

Collapse
Posted by jyothi shekhar on
I am using Apache LDAP module.For that i need to register LDAP.
Collapse
Posted by jyothi shekhar on
If i give ldap://localhost/some description ,its giving the error like LDAP is not registered.Please reply.What i have to do the changes in the Apache configuration file or some changes in the browser?