EPrints Technical Mailing List Archive

Message: #03617


< Previous (by date) | Next (by date) > | < Previous (in thread) | Next (in thread) > | Messages - Most Recent First | Threads - Most Recent First

[EP-tech] Eprints CAS Authentification


Hello,

I have some problems in the developpement of a CAS Auth for EPrints.

My first approach was using the documentation on the page : http://wiki.eprints.org/w/CAS

This documentation is good to start, but i have some problems finishing it. It's not accurate enough for eprints 3.x . In fact it doesn't work if we use it like it is explained.
the first problem i ran into was that apache did not restart after modifying the sub current_user() routine. The $username variable isn't defined in the line
$ldap_search_string =~ s/!!USERNAME!!/$username/g;

I resolved this problem, but then i ran into another problem, the cookie isn't found and can't be fetched. So before using raw_cookie() i tested if the cookie existed or not.

As for now, the CAS page is visible, when i click on Login, but i have another problem, when the user is created in the eprints Database ( right after CAS Auth ), the user creation
method is looping like hell, and creates a bunch of first null users, then a bunch of users with my LDAP credentials. This is not what is expected, i expect to see only one user created with LDAP Credentials.

On another hand, when the user is already in the database, the connection is made with the CAS, but the users can't logout. Here is my sub current_user() routine :

sub current_user
{
    my( $self ) = @_;
    if( $self->{offline} ) { return undef; }

    if( !defined $self->{current_user} ){
        if( $self->get_archive->get_conf( "cookie_auth" ) ){
            if ( $self->get_archive->get_conf( 'cas_auth' ) ){
                my $username;
                my $cookie_name = $self->get_archive->get_conf( 'cas_cookie_name' );
                $self->{current_user} = undef;
                if( defined $ENV{'HTTP_CAS_FILTER_USER'}){          
                    $username = $ENV{'HTTP_CAS_FILTER_USER'};
                    $self->{current_user} = EPrints::DataObj::User::user_with_username( $self, $username ); # undef si le user n'existe pas         
                }
                elsif ( defined $ENV{'HTTP_COOKIE'}) {
                    # Vérification de l'existence du cookie APACHECAS
                    my @cookie1 = split("=",$ENV{'HTTP_COOKIE'}); #cookie1 = array('APACHECAS', ticket)
                    my $ticket = $cookie1[1];
                    my $sql = "SELECT user_id FROM cas_sessions where id='".$ticket."'";
                    my $sth = $self->get_database()->prepare( $sql );
                    $self->get_database()->execute($sth);
                    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 ); # undef si le user n'existe pas
                }
                else {
                    $self->{current_user} = undef;
                }

                # Create user FROM LDAP server if needed
                if (not defined $self->{current_user}) {
                    my $session = $self;
                    # Verification de l'existence des cookies
                    # Si le cookie est trouvé, on défini le username  
                    if( defined $ENV{'HTTP_COOKIE'}){
                        my $ticket = raw_cookie('APACHECAS');
                        my $sql = "SELECT user_id FROM cas_sessions where id='".$ticket."'";
                        my $sth = $self->get_database()->prepare( $sql );
                        $self->get_database()->execute($sth);
                        my @info = $sth->fetchrow_array();
                        $username = $info[0];
                        $sth->finish;                                
                        my $utilisateur = EPrints::DataObj::User::user_with_username( $self, $username );
                   
                        if(!defined $utilisateur && ($username != '' || $username != undef) ){
                            # Si l'utilisateur n'existe pas dans la bdd eprints et que le username est bien défini
                            # On va le chercher dans le LDAP
                            # et l'enregistrer dans la BDD Eprints
             
              # Récupération des parametres LDAP
                            my $ldap_host = $session->get_archive()->get_conf('ldap_host');
                            my $ldap_version = $session->get_archive()->get_conf('ldap_version');
                            my $ldap_bind_user = $session->get_archive()->get_conf('ldap_bind_user');
                            my $ldap_bind_pass = $session->get_archive()->get_conf('ldap_bind_pass');
                            my $ldap_base = $session->get_archive()->get_conf('ldap_base');
                            my $ldap_scope = $session->get_archive()->get_conf('ldap_scope');
                            my $ldap_search_string = $session->get_archive()->get_conf('ldap_search_string');
                            $ldap_search_string =~ s/username/$username/g;

                            my $ldap_default_email = $session->get_archive()->get_conf('ldap_default_email');
                            my $ldap_default_country = $session->get_archive()->get_conf('ldap_default_country');                                        
                            my $ldap_default_org = $session->get_archive()->get_conf('ldap_default_org');
                            my $ldap_conforms_supann = $session->get_archive()->get_conf('ldap_conforms_supann');

                            eval "use Net::LDAP;";
                            die "Cannot load Net::LDAP: $@" if $@;

                            # Connexion au serveur LDAP
                            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
                            my $result = $ldap->search(    base => $ldap_base, scope => $ldap_scope, filter => $ldap_search_string, );

                            # Utiliser seulement la première entrée
                            my @entries = $result->entries();
                            if (defined (my $ldap_entry = $entries[0])) {
                                # Attribuer le type de l'utilisateur
                                my $usertype = "user";
                                my $user = EPrints::DataObj::User::create( $session, $usertype );

                                # Attribuer le nom de l'utilisateur
                                $user->set_value( "username" , $username );
                                my $name = {};
                                $name->{family} = $ldap_entry->get_value( "sn" );
                                $name->{given} = $ldap_entry->get_value( "givenName" );
                                $user->set_value("name", $name );

                                # Attribuer l'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);
                                }

                                # Attribuer l'adresse de l'utilisateur
                                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);

                                # Attribuer L'URL
                                $user->set_value("url", $ldap_entry->get_value("labeledURI"));
                               
                                # Enregistrement des infos utilisateurs
                                $user->commit();
                 
                                $self->{current_user} = $user;
                            }
                        }   
                    }
                }
            }
            else {
                $self->{current_user} = $self->_current_user_auth_cookie;
            }
        }
        else {
            $self->{current_user} = $self->_current_user_auth_basic;
        }
    }
    return $self->{current_user};
}



I have used a second method for the CAS Auth, using the mod_auth_cas, but it also doesn't work :
in mod_cas.conf :
<IfModule mod_auth_cas.c>
CASVersion 2
CASDebug On
CASValidateServer Off
CASLoginURL https://[myCasHOST]/login
CASValidateURL https://
[myCasHOST]/serviceValidate
CASCookiePath /var/cache/apache2/mod_auth_cas/
</IfModule>


in apachevhost.conf
<Directory "/opt/eprints3/cgi/cas">
AuthType CAS
require valid-user
</Directory>


in archives/<archiveId>/cfg/cfg.d/cas.pl
$c->{get_login_url} = sub {
    my( $session, $target ) = @_;
    my $uri = $session->get_request->uri;
    if( defined $uri && $uri eq '/cgi/users/login' ){
        return undef;
    }
    my $url = "" $session->get_repository->get_conf( "http_url" ) . "/cgi/cas/login" );
    $url->query_form( target => $target );
    return "$url";
};

$c->{on_logout} = sub {
    my( $session ) = @_;
    my $username = '';
    $username = $session->current_user->get_value( "username" ) if( defined $session->current_user );
    # redirect to CAS logout
    $session->redirect( "https://<myCasHOST>/cas/logout" ) unless( $username eq 'admin' );
}


in cgi/cas/login
use EPrints;
use strict;
my $session = new EPrints::Session;
exit( 0 ) unless( defined $session );
my $page=$session->make_doc_fragment();
if( $session->get_repository->can_call( 'on_logout' ) ){
    $session->get_repository->call( 'on_logout', $session );
}

# to allow CAS to work with local admin account:
my $username = '';
$username = $session->current_user->get_value( "username" ) if(defined $session->current_user );
my $ticketid = EPrints::Apache::AnApache::cookie( $session->get_request, "eprints_session" );
my $dataset = $session->get_repository->get_dataset( "loginticket" );
$session->get_database->delete_from(
    $dataset->get_sql_table_name(),
    ["code"],
    [$ticketid],
);
$session->logout;

# to allow CAS logout to work
exit unless($username eq 'admin');;
$page->appendChild( $session->render_message(
    "message",
    $session->make_text( "Logout OK!" ) ) );
$page->appendChild( $session->html_phrase( "general:frontpage_link" ) );
my $title = $session->make_text( "Logout" );
$session->build_page( $title, $page, "login" );
$session->send_page();
$session->terminate;
exit;


Hoping to have an answer soon...

Thank you

Matthieu