Difference between revisions of "CAS"

From EPrints Documentation
Jump to: navigation, search
(Install the lib: change version, 0.1 to 0.4)
(Create the database to store cookies: update schema and version)
Line 17: Line 17:
 
===Create the database to store cookies===
 
===Create the database to store cookies===
  
You should find this mysql schema on
+
You should find this schema on
http://search.cpan.org/src/JHITT/Apache2-AuthCAS-0.1/schemaPg.sql
+
http://search.cpan.org/src/JHITT/Apache2-AuthCAS-0.4/schemaPg.sql
  
 
<pre>
 
<pre>
 
-- Schema for use with PostgreSQL
 
-- 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 (
 
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     int(8)        not null
user_id varchar(32) not null,
+
    , user_id           varchar(32) not null
pgtiou varchar(64),
+
    , pgtiou           varchar(256)
pgt varchar(64)
+
    , pgt              varchar(256)
 +
    , service_ticket    varchar(256)
 
);
 
);
  
CREATE INDEX cas_sessions_id_index ON cas_sessions(id);
+
-- MySQL will create automatically the index for the primary key
 
CREATE INDEX cas_sessions_pgtiou_index ON cas_sessions(pgtiou);
 
CREATE INDEX cas_sessions_pgtiou_index ON cas_sessions(pgtiou);
 
</pre>
 
</pre>

Revision as of 13:30, 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"

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

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

Eprints::Session edit

Now edit the $EPRINTS_PATH/perl_lib/EPrints/Session.pm. First change the line:

use CGI qw(-compile);
use CGI qw(:standard -nph -compile);

Which enables you to use the raw_cookie fuction which returns variables stored in http cookie. 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:

$sql="SELECT uid FROM cas_sessions WHERE id='$user_ticket'";

Where $user_ticket is the variable stored in the AuthCAS http cookie.

my $user_ticket=raw_cookie('APACHECAS');

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:

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

  if( $self->{logged_out} )
  {
    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' );
        if( defined $ENV{HTTP_CAS_FILTER_USER})
        {           $username = $ENV{HTTP_CAS_FILTER_USER};
        }
        else
        {
          my $ticket = raw_cookie($cookie_name);
          if ($ticket ne '') {
            my $sql = "SELECT uid FROM cas_sessions where id='?'";
            my $sth = $self->get_database()->prepare( $sql );
            $self->get_database()->execute($sth,$ticket);
            my @info = $sth->fetchrow_array();
            my @list = split(":",$info[0]);
            $username = $list[0];
            $sth->finish;
          }
        }
        $self->{current_user} = EPrints::DataObj::User::user_with_username( $self, $username );
      }

      # Create user FROM LDAP server if needed
      if (not defined $self->{current_user})
      {
         my $session = $self;

         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 $@;

         # Connect to LDAP server
         my $ldap = Net::LDAP->new( $ldap_host ) or die "$@";
         my $mesg = $ldap->bind ( $ldap_bind_user,
               password => $ldap_bind_pass,
               version => $ldap_version,
         );

         # Search the user
         my $result = $ldap->search(
               base => $ldap_base,
               scope   => $ldap_scope,
               filter  => $ldap_search_string,
         );

         # Use only the first entry !
         my @entries = $result->entries();
         if (defined (my $ldap_entry = $entries[0])) {
            # Set user type
            my $usertype = "user";
            my $user = EPrints::User::create_user( $session, $usertype );

            # Set user name
            $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 );

            # 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"));
            $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};
}

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.

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 !