Integrating EPrints with LDAP
Contents
Install Prerequisites
Install the Net::LDAP and IO::Socket::SSL modules.
Determine LDAP Setup
The first step is to get Perl talking to your LDAP server. Determine the following parameters:
- the LDAP server name
- if the server doesn't support anonymous binds, a distinguished name (e.g. OU=jsmith, OU=users, DC=somewhere, DC=edu) and password to bind with
- the base name of user accounts (e.g. OU=users, DC=somewhere, DC=edu)
- the name of the username field (e.g. samaccountname, cn)
The http://files.eprints.org/27/01/ldaplookup script should get you started. Add your LDAP parameters to the script.
When run with an username as its parameter, ldaplookup should dump all the information associated with that account:
$ ./ldaplookup jsmith Using LDAP protocol version 3 LDAP_EXTENSION_START_TLS supported ------------------------------------------------------------------------ dn:CN=jsmith,OU=users,DC=somewhere,DC=edu objectClass: top person organizationalPerson user cn: jsmith sn: Smith ...
You will probably need to tweak the LDAP parameters to suit your setup. See perldoc Net::LDAP.
Configure user authentication
The EPrints configuration lets you specify any number of user types (the defaults are "user", "editor" and "admin") each of which can be authorised in a different way. Suppose we want to have user, editor and admin accounts that are authorised by our LDAP server (i.e. internal staff) and also user, editor and admin accounts that are local to EPrints and authorised in the usual way (i.e. external users).
Create new user types
In /opt/eprints2/archives/ARCHIVEID/cfg/metadata-types.xml, copy and paste the existing user, editor, and admin types and change their names to ldapuser, ldapeditor and ldapadmin:
<dataset name="user"> <type name="ldapuser" > <field name="password" /> <field name="username" staffonly="yes"/> ... </type> <type name="ldapeditor" > <field name="password" /> <field name="username" staffonly="yes"/> ... </type> <type name="ldapadmin" > <field name="password" /> <field name="usertype" staffonly="yes" /> ... </type> <type name="user" > <field name="password" /> <field name="usertype" staffonly="yes"/> ... </type> <type name="editor" > <field name="password" /> <field name="usertype" staffonly="yes" /> ... </type> <type name="admin" > <field name="password" /> <field name="username" staffonly="yes" /> ... </type> </dataset>
Define user citation styles
Define citation styles for the new user types in /opt/eprints2/archives/ARCHIVEID/cfg/citations-en.xml:
Just copy and paste the citation types for user_user, user_editor and user_admin and rename them to user_ldapuser, user_ldapeditor and user_ldapadmin.
Define user typenames
Define typenames for the new user types in /opt/eprints2/archives/ARCHIVEID/cfg/phrases-en.xml:
Just copy and paste the phrases for user_typename_user, user_typename_editor and user_typename_admin and rename them to user_typename_ldapuser, user_typename_ldapeditor and user_typename_ldapadmin.
Then, adjust the three new phrases values, e.g., the phrase value for the user_typename_ldapuser could be changed from "User" to "LDAP User".
Configure user authentication
Now configure user authentication in /opt/eprints2/archives/ARCHIVEID/cfg/ArchiveConfig.pm:
my $LDAP = { handler => \&ldapauthen }; $c->{userauth} = { user => { auth => $CRYPTED_DBI, priv => [ "subscription", "set-password", "deposit", "change-email", "change-user" ] }, editor => { auth => $CRYPTED_DBI, priv => [ "subscription", "set-password", "deposit", "change-email", "change-user", "view-status", "editor", "staff-view" ] }, admin => { auth => $CRYPTED_DBI, priv => [ "subscription", "set-password", "deposit", "change-email", "change-user", "view-status", "editor", "staff-view", "edit-subject", "edit-user" ] }, ldapuser => { auth => $LDAP, priv => [ "subscription", "set-password", "deposit", "change-user","no_edit_own_record" ] }, ldapeditor => { auth => $LDAP, priv => [ "subscription", "set-password", "deposit", "change-user","no_edit_own_record", "view-status", "editor", "staff-view" ] }, ldapadmin => { auth => $LDAP, priv => [ "subscription", "set-password", "deposit", "change-user", "view-status", "editor", "staff-view", "edit-user" ] }, };
Here, the default user, editor and admin user types are still authenticated using the usual $CRYPTED_DBI construct, whereas ldapuser, ldapeditor and ldapadmin are authenticated by the $LDAP construct that we defined.
Define LDAP authentication function
Add the ldapauthen function to the end of ArchiveConfig.pm, filling in your LDAP settings:
use Net::LDAP; BEGIN { eval "use Apache::Const ':common'" || eval "use Apache2::Const ':common'"; } sub ldapauthen { my ($r) = @_; my ($key, $val, $dbh); return OK unless $r->is_initial_req; # only the first internal request my($res, $passwd_sent) = $r->get_basic_auth_pw; return $res if $res; # e.g. HTTP_UNAUTHORIZED # get username my ($user_sent) = $r->user; my $ldap = Net::LDAP->new ( "ldap.host.name", version=>3 ); $ldap->start_tls( sslversion=>'sslv2' ); unless( $ldap ) { print STDERR "$@"; return SERVER_ERROR; } # If the distinguished name of the user is not # computable from the username, perform a lookup # to determine the distinguished name my $mesg = $ldap->bind; # If your LDAP server doesn't allow anonymous binds # supply the dn/password of a valid account here # (e.g. an 'eprints' account created specially for # this purpose) #my $dn = ""; #my $pword = ""; #my $mesg = $ldap->bind( $dn, password=>$pword ); my $base = "ou=user, dc=somewhere, dc=edu"; my $result = $ldap->search ( base => "$base", scope => "sub", filter => "cn=$user_sent", attrs => ['DN'], sizelimit=>1 ); my $entr = $result->pop_entry; unless( defined $entr ) { $r->note_basic_auth_failure; return AUTH_REQUIRED; } # Bind with the distinguished name and password of the user # If the distinguished name of the user is computable, this # is the only step required my $mesg2 = $ldap->bind( $entr->dn, password=>$passwd_sent ); if( $mesg2->code ) { $r->note_basic_auth_failure; return AUTH_REQUIRED; } return OK; }
Reload configuration
Restart the apache server to reload the new configuration.
Import user accounts from LDAP
The final step is to import existing user accounts from the LDAP server.
The http://files.eprints.org/27/01/update_users script should get you started. Copy it to the /opt/eprints2/bin directory and add your LDAP settings.
Set $forreal to 1 to make changes to the database.
Notes
- If you see a "Sizelimit exceeded" error, you may need to import users in smaller batches, for example a faculty/dept at a time.
- update_users should be scheduled regularly using cron to keep EPrints in sync with the LDAP server
- For EPrints3 you will need to update two lines below;
- Line 3: use EPrints::DataObj::User; #use EPrints::User;
- Line 77: $user = EPrints::DataObj::User::create($session,"ldapuser"); #$user = EPrints::User::create_user( $session, "ldapuser" );