Difference between revisions of "CAS"

From EPrints Documentation
Jump to: navigation, search
(I'm a busy man, give me a patch!)
(Eprints::Session edit: wrong function, wrong query, wrong package)
 
(37 intermediate revisions by 6 users not shown)
Line 3: Line 3:
 
==Install a secure host==
 
==Install a secure host==
  
The first thing you'll have to do is to [[HTTPS|install a secure host]].
+
The first thing you'll have to do is to [[Https3|install a secure host]].
  
==Apache::AuthCAS==
+
==Apache2::AuthCAS==
 
This perl library allows you to easily communicate with a CAS sever.
 
This perl library allows you to easily communicate with a CAS sever.
  
Line 11: Line 11:
  
 
This can be done with the command:
 
This can be done with the command:
perl -MCPAN -e 'install Apache::AuthCAS'
+
perl -MCPAN -e 'install Apache2::AuthCAS'
  
More infomartion are available on [http://search.cpan.org/~dcastro/Apache-AuthCAS-0.4/lib/Apache/AuthCAS.pm CPAN]
+
More infomartion are available on http://search.cpan.org/~jhitt/Apache2-AuthCAS-0.4/lib/Apache2/AuthCAS.pm
  
===Make few changes to AuthCAS.pm (if using mysql)===
+
===Create the database to store cookies===
  
The Apache::AuthCAS module use a database to store cookies. You can use Postgres or MySQL, as you wish.
+
You should find this schema on
 +
http://search.cpan.org/src/JHITT/Apache2-AuthCAS-0.4/schemaPg.sql
  
Most probably, you will use mysql, as eprints use it. Unfortunately AuthCAS.pm is coded with the "Pg" driver in hard, even if a variable ($DB_DRIVER) exists, it is not used. So you will have to edit your AuthCAS.pm file and change each "Pg" with "mysql".
 
 
===Create the database to store cookies===
 
 
You should find this mysql schema in /root/.cpan/build/Apache-AuthCAS-0.4/schema.sql
 
 
<pre>
 
<pre>
-- schema that has been used with PostgreSQL and may need to be altered for
+
-- Schema for use with PostgreSQL
-- another DBMS
 
 
 
 
CREATE TABLE cas_sessions (
 
CREATE TABLE cas_sessions (
        id                             varchar(32) not null primary key,
+
      id               varchar(32) not null primary key
        last_accessed   int8 not null,
+
    , last_accessed     int8       not null
        uid                            varchar(32) not null,
+
    , user_id          varchar(32) not null
        pgtiou                  varchar(64) not null
+
    , pgtiou            varchar(256)
 +
    , pgt              varchar(256)
 +
    , service_ticket    varchar(256)
 
);
 
);
 +
CREATE INDEX cas_sessions_id_index ON cas_sessions(id);
 +
CREATE INDEX cas_sessions_pgtiou_index ON cas_sessions(pgtiou);
  
CREATE TABLE cas_pgtiou_to_pgt (
+
-- Schema for use with MySQL
        pgtiou          varchar(64) not null primary key,
+
CREATE TABLE cas_sessions (
        pgt                    varchar(64) not null,
+
      id                varchar(32) not null primary key
        created        int8 not null
+
    , last_accessed    int(8)        not null
 +
    , user_id          varchar(32) not null
 +
    , pgtiou            varchar(256)
 +
    , pgt              varchar(256)
 +
    , service_ticket    varchar(256)
 
);
 
);
  
--example PostgreSQL indeces
+
-- MySQL will create automatically the index for the primary key
--CREATE INDEX cas_sessions_id_index ON cas_sessions(id);
+
CREATE INDEX cas_sessions_pgtiou_index ON cas_sessions(pgtiou);
--CREATE INDEX cas_pgtiou_to_pgt_pgtiou_index ON cas_pgtiou_to_pgt(pgtiou);
 
--CREATE INDEX cas_sessions_last_accessed_index ON cas_sessions(last_accessed);
 
 
</pre>
 
</pre>
  
 
===Configure your secure host===
 
===Configure your secure host===
 
You must provide some information like the CAS host. You can provide it in your virtual host, or in AuthCAS.pm.
 
You must provide some information like the CAS host. You can provide it in your virtual host, or in AuthCAS.pm.
Read the [http://search.cpan.org/~dcastro/Apache-AuthCAS-0.4/lib/Apache/AuthCAS.pm module page on CPAN] to know more about it.
+
Read the [http://search.cpan.org/~jhitt/Apache2-AuthCAS-0.4/lib/Apache2/AuthCAS.pm module page on CPAN] to know more about it.
 +
 
 +
Edit $EPRINTS_ROOT/archives/$ARCHIVE_ID/var/manual-secure.conf and add the lines:
  
Also edit $EPRINTS_ROOT/archives/$ARCHIVE_ID/cfg/auto-secure.conf and make the following changes:
+
<pre>
 +
  PerlLoadModule Apache2::AuthCAS::Configuration
 +
  PerlLoadModule Apache2::AuthCAS
 +
  <Directory "/opt/eprints3/cgi/users">
 +
    AuthName "User Area"
 +
    AuthType Apache2::AuthCAS
 +
    AuthName "CAS"
 +
    PerlAuthenHandler Apache2::AuthCAS->authenticate
  
Remove lines:
+
    CASHost "HOST"
 +
    CASPort "443"
 +
    CASErrorURL "https://HOST/cas/error/"
 +
    CASDbDataSource "dbname=DATABASE_NAME"
 +
    CASDbDriver "mysql"
 +
    CASDbUser "DATABASE_USERNAME"
 +
    CASDbPass "DATABASE_PASSWORD"
 +
    CASSessionCookieName "COOKIE_NAME"
 +
    CASSessionTimeout "1800"
 +
    CASLogLevel "0"
 +
    CASRemoveTicket "true"
 +
    CASPretendBasicAuth "true"
  
    AuthType "Basic"
+
#  CASLoginUri "/cas/login"
     PerlAuthenHandler EPrints::Auth::authen
+
#  CASLogoutUri "/cas/logout"
 +
 
 +
     PerlAuthzHandler EPrints::Apache::Auth::authz
 +
    Require valid-user
 +
 
 +
    SetHandler perl-script
 +
    PerlHandler ModPerl::Registry
 +
    PerlSendHeader Off
 +
    Options ExecCGI FollowSymLinks
 +
  </Directory>
 +
</pre>
 +
 
 +
==Eprints::Repository edit==
 +
Now edit the $EPRINTS_PATH/perl_lib/EPrints/Repository.pm.
 +
(( previously, a modification to the CGI module declaration was suggested, it works without this modification on my instance ))
 +
 
 +
Here is the complete current_user function with English/French comments
 +
<pre>
 +
sub current_user
 +
{
 +
my( $self ) = @_;
  
 +
if( $self->{offline} )
 +
{
 +
return undef;
 +
}
  
 +
if( $self->{logged_out} )
 +
{
 +
return undef;
 +
}
  
and add:
+
# info : $self->log loggue dans error.log d'Apache, même pas celui lié à l'instance ...
 +
# info : $self->log logs in Apache's error.log not the one defined for eprints vhost ...
  
 
+
if( !defined $self->{current_user} ) {
    AuthType Apache::AuthCAS
+
# 1ère vérification, par cookie car il s'agit du fonctionnement standard et que même CAS fixe ce cookie. Il est important de ne pas passer dans le processus CAS/LDAP à chaque appel à la méthode
    AuthName "CAS"
+
# 1st check, cookie check because it's eprints standard, even CAS sets this cookie. It's important not to go through the CAS/LDAP process at each method call
    PerlAuthenHandler Apache::AuthCAS->authenticate
+
if ($self->get_archive->get_conf("cookie_auth")) {
    PerlSetVar CASProduction "1"
+
$self->{current_user} = $self->_current_user_auth_cookie;
 +
 +
# pas de cookie avec l'utilisateur, il faut passer via le process CAS s'il est activé
 +
# no user cookie, must go through the CAS process if defined
 +
if (! defined($self->{current_user})) {
 +
my $username = undef;
 +
if ($self->get_archive->get_conf('cas_auth')) {
 +
my $cookie_name = $self->get_archive->get_conf('cas_cookie_name');
 +
 +
# la query (objet CGI) n'est pas initialisé lors des 1ers passages dans cette méthode
 +
# the query (CGI object) is not set at the first calls of this method
 +
if (defined($self->{query})) {
 +
my $ticket = $self->{query}->cookie($cookie_name);
 +
# récupération du nom d'utilisateur via la base de données mise à jour par le module CAS chargé par Apache
 +
# get the username from database updated by the CAS module from Apache mod_perl
 +
if ($ticket ne '') {
 +
my $sql="SELECT user_id FROM cas_sessions WHERE id='$ticket'";
 +
my $sth = $self->get_database()->prepare($sql);
 +
$self->get_database()->execute($sth,$ticket);
 +
my @info = $sth->fetchrow_array();
 +
# my @list = split(":",$info[0]);
 +
$username = $info[0];
 +
$sth->finish;
 +
}
 +
}
 +
$self->{current_user} = EPrints::DataObj::User::user_with_username($self, $username);
 +
}
  
===Load the module===
+
# la méthode au-dessus ne créé pas l'utilisateur si celui n'est pas déjà présent dans l'application, à faire via le LDAP
Finally, don't forget to load Apache::AuthCAS!
+
# the previous method doesn't create user if he doesn't exist in the database, we'll do this with an LDAP
 +
if (defined($username) && ! defined($self->{current_user})) {
 +
# récupération de tous les paramètres de connexion et recherche dans l'annuaire LDAP
 +
# get every parameter to set the connection and search the user in the LDAP directory
 +
my $ldap_host = $self->get_archive()->get_conf('ldap_host');
 +
my $ldap_version = $self->get_archive()->get_conf('ldap_version');
 +
my $ldap_bind_user = $self->get_archive()->get_conf('ldap_bind_user');
 +
my $ldap_bind_pass = $self->get_archive()->get_conf('ldap_bind_pass');
 +
my $ldap_base = $self->get_archive()->get_conf('ldap_base');
 +
my $ldap_scope = $self->get_archive()->get_conf('ldap_scope');
 +
my $ldap_search_string = $self->get_archive()->get_conf('ldap_search_string');
 +
$ldap_search_string =~ s/!!USERNAME!!/$username/g;
 +
 +
# récupération des valeurs par défaut que le LDAP ne renverra pas (sauf email)
 +
# get all default values, except email because we don't need it in our instance
 +
my $ldap_default_email = $self->get_archive()->get_conf('ldap_default_email');
 +
my $ldap_default_country = $self->get_archive()->get_conf('ldap_default_country');                                       
 +
my $ldap_default_org = $self->get_archive()->get_conf('ldap_default_org');
 +
my $ldap_conforms_supann = $self->get_archive()->get_conf('ldap_conforms_supann');
 +
 +
# connexion à l'annuaire LDAP
 +
# LDAP directory connection
 +
my $ldap = Net::LDAP->new( $ldap_host ) or die "$@";
 +
my $mesg = $ldap->bind ( $ldap_bind_user, password => $ldap_bind_pass, version => $ldap_version);
  
==Eprints::Session edit==
+
# recherche de l'utilisateur
 +
# user search
 +
my $result = $ldap->search(base => $ldap_base, scope  => $ldap_scope, filter  => $ldap_search_string);
  
Now edit the $EPRINTS_PATH/perl_lib/EPrints/Session.pm.
+
# les entrées sont censées être uniques, on prend la 1ère entrée
First add this line:
+
# user entry is meant to be unique, we take the first
<pre>
+
my @entries = $result->entries();
use CGI qw(:standard -nph);
+
if (defined (my $ldap_entry = $entries[0])) {
</pre>
+
# récupération du type d'utilisateur par défaut
Which enables you to use the raw_cookie fuction which returns variables stored in http cookie.
+
# get the default user type
Then go to the current_user function definition where you have to put the uid provided by AuthCAS module in $username. To do it, you just have to make a sql query which looks like that:
+
my $usertype = $self->config("default_user_type");
<pre>
+
$sql="SELECT uid FROM cas_sessions WHERE id='$user_ticket'";
+
my $ds = $self->dataset("user");
</pre>
+
my $user = $ds->create_object( $self, { username => $username, usertype => $usertype } );
Where $user_ticket is the variable stored in the AuthCAS http cookie.
+
$self->log(Dumper($user));
<pre>
+
# the previous version was using create_user, deprecated and non-working
my $user_ticket=raw_cookie('APACHECAS');
+
# my $user = EPrints::User::create_user($self, $usertype);
</pre>
 
Note that 'APACHECAS' is the default name for the AuthCAS cookie but you may have change it.
 
  
Here is a code that should work if you have installed your Apache::AuthCAS sql tables in the same database where you store your eprints tables:
+
my $name = {};
<pre>
+
$name->{family} = $ldap_entry->get_value("sn");
sub current_user
+
$name->{given} = $ldap_entry->get_value("givenName");
{
+
$user->set_value("name", $name);
        my( $self ) = @_;
 
  
        my $user = undef;
+
# Set Email
 +
my $email = defined $ldap_entry->get_value("mail") ? $ldap_entry->get_value("mail") : $ldap_default_email;
 +
$user->set_value("email", $email);
  
        # If we've already done this once, no point
+
if ($ldap_conforms_supann) {
        # in doing it again.
+
$user->set_value("org", $ldap_entry->get_value("supannEtablissement"));
        unless( defined $self->{currentuser} )
+
}
        {
+
else {
                my $username ="";
+
$user->set_value("org", $ldap_default_org);
                my $user_ticket="";
+
}
                if( defined $ENV{HTTP_CAS_FILTER_USER})#just connected with cas, no cookie set
 
                {
 
                        $username = $ENV{HTTP_CAS_FILTER_USER};
 
                }
 
                elsif ( defined $self->{archive}->get_conf("cassessioncookiename") )#cas auth seems configured...
 
                {
 
                        $user_ticket=raw_cookie($self->{archive}->get_conf("cassessioncookiename"));
 
                        if( $user_ticket ne "" )#Indeed we've get a cookie :)
 
                        {
 
                                my $sql = "SELECT uid FROM cas_sessions where id='$user_ticket'";
 
                                my $sth = $self->{database}->prepare( $sql );
 
                                $self->{database}->execute( $sth, $sql );
 
  
                                while( my @info = $sth->fetchrow_array ) {
+
# Set Address
                                        my @list = split(":",$info[0]);
+
# my $address = $ldap_entry->get_value("postalAddress")
                                        foreach( @list ) {$username=$_;}
+
# . "\n"
                                }
+
# . $ldap_entry->get_value("postalCode")
                                $sth->finish;
+
# . " "
                        }
+
# . $ldap_entry->get_value("l");
                }
+
# $user->set_value("address", $address);
                else#using default eprints authentication
+
$user->set_value("country", $ldap_default_country);
                {
 
                        $username = $ENV{'REMOTE_USER'};
 
                }     
 
  
                if( $username ne "" )
+
# Set URL
                {
+
# $user->set_value("url", $ldap_entry->get_value("labeledURI"));
                        $self->{currentuser} =
+
                        EPrints::User::user_with_username( $self, $username );
+
# save the information into the database and gives the user an id
                }
+
$user->commit();
               
 
        }
 
  
        return $self->{currentuser};
+
$self->{current_user} = $user;
 +
}
 +
}
 +
# la fonction est aussi appelée avant tout procédé d'authentification, même si l'on accède à la page de login
 +
# en fait, elle est appelée très souvent, d'où le test qui suit
 +
# the method is also called before any authentication process, need to check again at this point
 +
if (defined($self->{current_user})) {
 +
# création d'un ticket de login interne à l'appli et connexion de l'utilisateur (méthode trouvée dans le package Register.pm où un utilisateur est connecté après avoir été créé)
 +
# Create a login ticket and log the user in
 +
EPrints::DataObj::LoginTicket->expire_all( $self );
 +
$self->dataset( "loginticket" )->create_dataobj({
 +
userid => $self->{current_user}->id,
 +
})->set_cookies();
 +
}
 +
}
 +
}
 +
else {
 +
# custom auth
 +
if( $self->get_repository->can_call( 'get_current_user' ) )
 +
{
 +
$self->{current_user} = $self->get_repository->call( 'get_current_user', $self );
 +
}
 +
# basic auth
 +
if( !defined $self->{current_user} )
 +
{
 +
$self->{current_user} = $self->_current_user_auth_basic;
 +
}
 +
}
 +
$self->{already_in_current_user} = 0;
 +
}
 +
$self->{processor}->{user} = $self->{current_user};
 +
return $self->{current_user};
 
}
 
}
 
</pre>
 
</pre>
This code assumes CASAuth SQL tables are stored with the rest of the Eprints server. It won't work if you use a Postgres database or even if you stored your CASauth tables on an other MySQL database. If you have any good reason to use a seperated database, you will have to change some lines in order to make it work.
+
In this method, I have commented some stuff around addresses because I had no need. By the way, you can use/add every useful information from your LDAP that has a place to go in the user object.
  
==I'm a busy man, give me a patch!==
+
This code assumes Apache2::AuthCAS SQL tables are stored with the rest of the Eprints server. It won't work if you use a Postgres database or even if you stored your Apache2::AuthCAS tables on an other MySQL database. If you have any good reason to use a separated database, you will have to change some lines in order to make it work.
  
Okay, here is a patch which includes changes to files:
+
==Configure your archive==
*Config.pm
+
Add the following lines into cfg/cfg.d/misc.pl:
*configure_archive
+
<pre>
*generate_apacheconf
+
$c->{cas_auth} = 1;
*Session.pm
+
$c->{cas_cookie_name} = 'COOKIE_NAME'; # The same as in manual-secure.conf
It was made with Eprints version 2.3.13.
 
[http://files.eprints.org/00000011/01/eprints_CAS.patch CAS Authentication patch for Gnu eprints]
 
  
Once your eprints gets patched, you have to:
+
$c->{ldap_host} = 'LDAP_HOST_NAME';
*install Apache::AuthCAS module and create associated tables in your eprints database ([[#Apache::AuthCAS|see above]])
+
$c->{ldap_version} = 3;
*run configure_archive (answer yes to «configure secure host» and «use CAS authentication»)
+
$c->{ldap_bind_user} = 'ou=admin,dc=DOMAIN,dc=com';
*run generate_apacheconf
+
$c->{ldap_bind_pass} = 'SECRET_PASS';
*restart your webserver
+
$c->{ldap_base} = 'dc=DOMAIN,dc=com';
 +
$c->{ldap_scope} = 'sub';
 +
$c->{ldap_search_string} = '(uid=!!USERNAME!!)';
 +
$c->{ldap_default_email} = 'A VALID EMAIL';
 +
$c->{ldap_default_country} = 'USA';
 +
$c->{ldap_default_org} = 'YOUR ORGANISATION';
  
You should now be able to login through your CAS server.
+
</pre>
  
Once CAS is working, you may need to copy the user entry from an LDAP server.
+
==Test your archive==
This can be done as describe [[LDAP|in the LDAP entry of this Wiki]] or like this :
 
  
==our LDAP Configuration==
+
You should now be able to login through your CAS server.
  
in the file perl_lib/EPrints/User.pm, go to the user_with_username function and edit it.
+
==LDAP Configuration==
After the line
 
  
<code>
+
Once CAS is working, you may need to copy the user entry from an LDAP server.
my @records = $searchexp->get_records;
+
EPrints3 comes with example code in archives/ARCHIVEID/cfg/cfg.d/user_login.pl. Just use it !
</code>
 
 
 
add this:
 
  
<code>
+
[[Category:Authentication]]
      #if no record was found and that there is an ldap host set, try to add a new record
 
        if ( $records[0] eq "" and $session->{archive}->get_conf("ldaphost") ne ""){
 
                #bring back data from ldap server
 
                my $ldap = Net::LDAP->new ( $session->{archive}->get_conf("ldaphost") ) or die "$@";
 
                my $userToAuthenticate=$session->{archive}->get_conf("ldapuser");
 
                my $passwd= $session->{archive}->get_conf("ldappass");
 
                my $base=$session->{archive}->get_conf("ldapbase");
 
                my $additionalCriteria=$session->{archive}->get_conf("ldapsearchstring");
 
                my $searchString="uid=$username";
 
                if ($additionalCriteria ne ""){
 
                        $searchString="& ($additionalCriteria) ($searchString)";
 
                }
 
                my @Attrs = ( );
 
                my $mesg = $ldap->bind ( "$userToAuthenticate",
 
                                      password => "$passwd",
 
                                      version => 3 );
 
                my $result = $ldap->search ( base    => "$base",
 
                                scope  => "sub",
 
                                filter  => "$searchString",
 
                                attrs  =>  @Attrs
 
                              );
 
                my @entries = $result->entries;
 
                my $email = "'".@entries[0]->get_value ( "mail" )."'";
 
                my $name_honourific = "'".@entries[0]->get_value ( "supannCivilite" )."'";
 
                my $name_given = "'".@entries[0]->get_value ( "givenName" )."'";
 
                my $name_family = "'".@entries[0]->get_value ( "sn" )."'";
 
                my $password = "NULL";
 
                my $usertype = "user";
 
                my $newemail = "NULL";
 
                my $newpassword = "NULL";
 
                my $pin = "NULL";
 
                my $pinsettime = "NULL";
 
                my $joined = "NULL";
 
                my $lang = "'fr'";
 
                my $frequency = "'never'";
 
                my $mailempty = "'FALSE'";
 
                my $name_lineage = "NULL";
 
                my $dept = "NULL";
 
                my $org = "'".@entries[0]->get_value ( "supannEtablissement" )."'";
 
                my $address = "'".@entries[0]->get_value ("postalAddress")." ".@entries[0]->get_value ("postalCode")." ".@entries[0]->get_value ("l")."'";
 
                my $country = "'FRANCE'";
 
                my $hideemail = "'TRUE'";
 
                my $os = "NULL";
 
                my $url = "'".@entries[0]->get_value ("labeledURI")."'";
 
                #my $userid="''";
 
                #create this user
 
                my $new_user = EPrints::User::create_user( $session, $usertype);
 
                my $sql=
 
                "UPDATE `users` SET
 
                `username`='$username',
 
                `password`=$password,
 
                `newemail`=$newemail,
 
                `newpassword`=$newpassword,
 
                `pin`=$pin,
 
                `pinsettime`=$pinsettime,
 
                `joined`=$joined,
 
                `email`=$email,
 
                `lang`=$lang,
 
                `frequency`=$frequency,
 
                `mailempty`=$mailempty,
 
                `name_honourific`=$name_honourific,
 
                `name_given`=$name_given,
 
                `name_family`=$name_family,
 
                `name_lineage`=$name_lineage,
 
                `dept`=$dept,
 
                `org`=$org,
 
                `address`=$address,
 
                `country`=$country,
 
                `hideemail`=$hideemail,
 
                `os`=$os,
 
                `url`=$url
 
                WHERE `userid` =".$new_user->get_value( "userid" )." LIMIT 1
 
                ";
 
                my $sth = $session->{database}->prepare( $sql );
 
                $session->{database}->execute( $sth, $sql );
 
                $sth->finish;
 
                $searchexp->add_field(
 
                        $user_ds->get_field( "username" ),
 
                        $username, "EX"
 
                );
 
                $searchid = $searchexp->perform_search;
 
                @records = $searchexp->get_records;
 
        }
 
</code>
 

Latest revision as of 14:01, 30 October 2015

This page explains how to use a CAS server to authenticate user in eprints.

Install a secure host

The first thing you'll have to do is to install a secure host.

Apache2::AuthCAS

This perl library allows you to easily communicate with a CAS sever.

Install the lib

This can be done with the command: perl -MCPAN -e 'install Apache2::AuthCAS'

More infomartion are available on http://search.cpan.org/~jhitt/Apache2-AuthCAS-0.4/lib/Apache2/AuthCAS.pm

Create the database to store cookies

You should find this schema on http://search.cpan.org/src/JHITT/Apache2-AuthCAS-0.4/schemaPg.sql

-- Schema for use with PostgreSQL
CREATE TABLE cas_sessions (
      id                varchar(32) not null primary key
    , last_accessed     int8        not null
    , user_id           varchar(32) not null
    , pgtiou            varchar(256)
    , pgt               varchar(256)
    , service_ticket    varchar(256)
);
CREATE INDEX cas_sessions_id_index ON cas_sessions(id);
CREATE INDEX cas_sessions_pgtiou_index ON cas_sessions(pgtiou);

-- Schema for use with MySQL
CREATE TABLE cas_sessions (
      id                varchar(32) not null primary key
    , last_accessed     int(8)        not null
    , user_id           varchar(32) not null
    , pgtiou            varchar(256)
    , pgt               varchar(256)
    , service_ticket    varchar(256)
);

-- MySQL will create automatically the index for the primary key
CREATE INDEX cas_sessions_pgtiou_index ON cas_sessions(pgtiou);

Configure your secure host

You must provide some information like the CAS host. You can provide it in your virtual host, or in AuthCAS.pm. Read the module page on CPAN to know more about it.

Edit $EPRINTS_ROOT/archives/$ARCHIVE_ID/var/manual-secure.conf and add the lines:

  PerlLoadModule Apache2::AuthCAS::Configuration
  PerlLoadModule Apache2::AuthCAS
  <Directory "/opt/eprints3/cgi/users">
    AuthName "User Area"
    AuthType Apache2::AuthCAS
    AuthName "CAS"
    PerlAuthenHandler Apache2::AuthCAS->authenticate

    CASHost "HOST"
    CASPort "443"
    CASErrorURL "https://HOST/cas/error/"
    CASDbDataSource "dbname=DATABASE_NAME"
    CASDbDriver "mysql"
    CASDbUser "DATABASE_USERNAME"
    CASDbPass "DATABASE_PASSWORD"
    CASSessionCookieName "COOKIE_NAME"
    CASSessionTimeout "1800"
    CASLogLevel "0"
    CASRemoveTicket "true"
    CASPretendBasicAuth "true"

#   CASLoginUri "/cas/login"
#   CASLogoutUri "/cas/logout"

    PerlAuthzHandler EPrints::Apache::Auth::authz
    Require valid-user

    SetHandler perl-script
    PerlHandler ModPerl::Registry
    PerlSendHeader Off
    Options ExecCGI FollowSymLinks
  </Directory>

Eprints::Repository edit

Now edit the $EPRINTS_PATH/perl_lib/EPrints/Repository.pm. (( previously, a modification to the CGI module declaration was suggested, it works without this modification on my instance ))

Here is the complete current_user function with English/French comments

sub current_user
{
	my( $self ) = @_;

	if( $self->{offline} )
	{
		return undef;
	}

	if( $self->{logged_out} )
	{	
		return undef;
	}

	# info : $self->log loggue dans error.log d'Apache, même pas celui lié à l'instance ...
	# info : $self->log logs in Apache's error.log not the one defined for eprints vhost ...

	if( !defined $self->{current_user} ) {
		# 1ère vérification, par cookie car il s'agit du fonctionnement standard et que même CAS fixe ce cookie. Il est important de ne pas passer dans le processus CAS/LDAP à chaque appel à la méthode
		# 1st check, cookie check because it's eprints standard, even CAS sets this cookie. It's important not to go through the CAS/LDAP process at each method call
		if ($self->get_archive->get_conf("cookie_auth")) {
			$self->{current_user} = $self->_current_user_auth_cookie;
			
			# pas de cookie avec l'utilisateur, il faut passer via le process CAS s'il est activé
			# no user cookie, must go through the CAS process if defined
			if (! defined($self->{current_user})) {
				my $username = undef;
				if ($self->get_archive->get_conf('cas_auth')) {
					my $cookie_name = $self->get_archive->get_conf('cas_cookie_name');
					
					# la query (objet CGI) n'est pas initialisé lors des 1ers passages dans cette méthode
					# the query (CGI object) is not set at the first calls of this method
					if (defined($self->{query})) {
						my $ticket = $self->{query}->cookie($cookie_name);
						# récupération du nom d'utilisateur via la base de données mise à jour par le module CAS chargé par Apache
						# get the username from database updated by the CAS module from Apache mod_perl
						if ($ticket ne '') {
							my $sql="SELECT user_id FROM cas_sessions WHERE id='$ticket'";
							my $sth = $self->get_database()->prepare($sql);
							$self->get_database()->execute($sth,$ticket);
							my @info = $sth->fetchrow_array();
							# my @list = split(":",$info[0]);
							$username = $info[0];
							$sth->finish;
						}
					}
					$self->{current_user} = EPrints::DataObj::User::user_with_username($self, $username);
				}

				# la méthode au-dessus ne créé pas l'utilisateur si celui n'est pas déjà présent dans l'application, à faire via le LDAP
				# the previous method doesn't create user if he doesn't exist in the database, we'll do this with an LDAP
				if (defined($username) && ! defined($self->{current_user})) {
					# récupération de tous les paramètres de connexion et recherche dans l'annuaire LDAP
					# get every parameter to set the connection and search the user in the LDAP directory
					my $ldap_host = $self->get_archive()->get_conf('ldap_host');
					my $ldap_version = $self->get_archive()->get_conf('ldap_version');
					my $ldap_bind_user = $self->get_archive()->get_conf('ldap_bind_user');
					my $ldap_bind_pass = $self->get_archive()->get_conf('ldap_bind_pass');
					my $ldap_base = $self->get_archive()->get_conf('ldap_base');
					my $ldap_scope = $self->get_archive()->get_conf('ldap_scope');
					my $ldap_search_string = $self->get_archive()->get_conf('ldap_search_string');
					$ldap_search_string =~ s/!!USERNAME!!/$username/g;
					
					# récupération des valeurs par défaut que le LDAP ne renverra pas (sauf email)
					# get all default values, except email because we don't need it in our instance
					my $ldap_default_email = $self->get_archive()->get_conf('ldap_default_email');
					my $ldap_default_country = $self->get_archive()->get_conf('ldap_default_country');                                         
					my $ldap_default_org = $self->get_archive()->get_conf('ldap_default_org');
					my $ldap_conforms_supann = $self->get_archive()->get_conf('ldap_conforms_supann');
					
					# connexion à l'annuaire LDAP
					# LDAP directory connection
					my $ldap = Net::LDAP->new( $ldap_host ) or die "$@";
					my $mesg = $ldap->bind ( $ldap_bind_user, password => $ldap_bind_pass, version => $ldap_version);

					# recherche de l'utilisateur
					# user search
					my $result = $ldap->search(base => $ldap_base, scope   => $ldap_scope, filter  => $ldap_search_string);

					# les entrées sont censées être uniques, on prend la 1ère entrée
					# user entry is meant to be unique, we take the first
					my @entries = $result->entries();
					if (defined (my $ldap_entry = $entries[0])) {
						# récupération du type d'utilisateur par défaut
						# get the default user type
						my $usertype = $self->config("default_user_type");
						
						my $ds = $self->dataset("user");
						my $user = $ds->create_object( $self, { username => $username, usertype => $usertype } );
						$self->log(Dumper($user));
						# the previous version was using create_user, deprecated and non-working
						# my $user = EPrints::User::create_user($self, $usertype);

						my $name = {};
						$name->{family} = $ldap_entry->get_value("sn");
						$name->{given} = $ldap_entry->get_value("givenName");
						$user->set_value("name", $name);

						# Set Email
						my $email = defined $ldap_entry->get_value("mail") ? $ldap_entry->get_value("mail") : $ldap_default_email;
						$user->set_value("email", $email);

						if ($ldap_conforms_supann) {
							$user->set_value("org", $ldap_entry->get_value("supannEtablissement"));
						}
						else {
							$user->set_value("org", $ldap_default_org);
						}

						# Set Address
						# my $address = $ldap_entry->get_value("postalAddress")
						# . "\n"
						# . $ldap_entry->get_value("postalCode")
						# . " "
						# . $ldap_entry->get_value("l");
						# $user->set_value("address", $address);
						$user->set_value("country", $ldap_default_country);

						# Set URL
						# $user->set_value("url", $ldap_entry->get_value("labeledURI"));
						
						# save the information into the database and gives the user an id
						$user->commit();

						$self->{current_user} = $user;
					}
				}
				# la fonction est aussi appelée avant tout procédé d'authentification, même si l'on accède à la page de login
				# en fait, elle est appelée très souvent, d'où le test qui suit
				# the method is also called before any authentication process, need to check again at this point
				if (defined($self->{current_user})) {
					# création d'un ticket de login interne à l'appli et connexion de l'utilisateur (méthode trouvée dans le package Register.pm où un utilisateur est connecté après avoir été créé)
					# Create a login ticket and log the user in
					EPrints::DataObj::LoginTicket->expire_all( $self );
					$self->dataset( "loginticket" )->create_dataobj({
						userid => $self->{current_user}->id,
					})->set_cookies();
				}
			}
		}
		else {
			# custom auth
			if( $self->get_repository->can_call( 'get_current_user' ) )
			{
				$self->{current_user} = $self->get_repository->call( 'get_current_user', $self );
			}
			# basic auth
			if( !defined $self->{current_user} )
			{
				$self->{current_user} = $self->_current_user_auth_basic;
			}
		}
		$self->{already_in_current_user} = 0;
	}
	$self->{processor}->{user} = $self->{current_user};
	return $self->{current_user};
}

In this method, I have commented some stuff around addresses because I had no need. By the way, you can use/add every useful information from your LDAP that has a place to go in the user object.

This code assumes Apache2::AuthCAS SQL tables are stored with the rest of the Eprints server. It won't work if you use a Postgres database or even if you stored your Apache2::AuthCAS tables on an other MySQL database. If you have any good reason to use a separated database, you will have to change some lines in order to make it work.

Configure your archive

Add the following lines into cfg/cfg.d/misc.pl:

$c->{cas_auth} = 1;
$c->{cas_cookie_name} = 'COOKIE_NAME'; # The same as in manual-secure.conf

$c->{ldap_host} = 'LDAP_HOST_NAME';
$c->{ldap_version} = 3;
$c->{ldap_bind_user} = 'ou=admin,dc=DOMAIN,dc=com';
$c->{ldap_bind_pass} = 'SECRET_PASS';
$c->{ldap_base} = 'dc=DOMAIN,dc=com';
$c->{ldap_scope} = 'sub';
$c->{ldap_search_string} = '(uid=!!USERNAME!!)';
$c->{ldap_default_email} = 'A VALID EMAIL';
$c->{ldap_default_country} = 'USA';
$c->{ldap_default_org} = 'YOUR ORGANISATION';

Test your archive

You should now be able to login through your CAS server.

LDAP Configuration

Once CAS is working, you may need to copy the user entry from an LDAP server. EPrints3 comes with example code in archives/ARCHIVEID/cfg/cfg.d/user_login.pl. Just use it !