Jaime Pérez Crespo <jaime.perez@urjc.es>
PAPI es un sistema que permite la autenticación y autorización de usuarios a través de una red de servicios web. Sus principales bazas, en las que nos centraremos aquí, son la implementación del concepto single-sign-on (sólo es necesario autenticarse una vez para acceder a todos los servicios ofrecidos) y la capacidad de actuar como proxy de reescritura transparente al usuario, de forma que permite anteponerse a políticas de acceso de filtrado por IP de origen mediante una autenticación previa.
La arquitectura de PAPI utiliza una serie de conceptos que es necesario tener claros en todo momento a la hora de implantar un servicio con él.
A continuación se proporcionan algunas consideraciones básicas para la instalación de todos los elementos que componen un servicio PAPI. Como convención, los comandos se indicarán precedidos del prompt del usuario root (#).
En primer lugar configuramos un servidor web en el que instalaremos nuestro servidor de autenticación. Lo mejor es redirigir todas las peticiones que reciba dicho servidor web a la URL del AS y utilizar SSL. En nuestro caso vamos a utilizar un virtual host de apache, que configuraremos de la siguiente manera:
NameVirtualHost 192.168.84.92:443
<VirtualHost 192.168.84.92:80>
ServerName www.papi.urjc.es
RedirectMatch (.*)
https://www.papi.urjc.es/cgi-bin/AuthServer
</VirtualHost>
<VirtualHost 192.168.84.92:443>
ServerName www.papi.urjc.es
ErrorDocument 404
https://www.papi.urjc.es/cgi-bin/AuthServer
RedirectMatch /index.html
https://www.papi.urjc.es/cgi-bin/AuthServer
<IfModule mod_ssl.c>
SSLEngine on
SSLCertificateFile /etc/apache/ssl.crt/server.crt
SSLCertificateKeyFile /etc/apache/ssl.key/server.key
SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
</IfModule>
</VirtualHost>
# wget ftp://ftp.rediris.es/rediris/papi/PAPI-AS.1.4.0.tar.gz
# tar xzvf PAPI-AS.1.4.0.tar.gz
# cd PAPI-1.4.0
# apt get install libconvert-asn1-perl liburi-perl
# apt get install libmd5-perl libmime-perl libdb-file-lock-perl
# cd /usr/share/perl/5.8.4/CGI/
# wget http://search.cpan.org/src/SMYLERS/CGI-Lite-2.02/Lite.pm
# cd /root/PAPI-1.4.0/
# perl Makefile.PL
You must provide a location for installing the PAPI
Authentication Server software. It must be a directory
configured to hold CGI programs in your Apache
installation [/usr/local/apache/cgi-bin]
/usr/lib/cgi-bin
The Authentication Server CGI will be in
/usr/lib/cgi-bin/AuthServer
The configuration file will be /usr/lib/cgi-bin/AuthServer.cf
Other data files will be installed under /usr/lib/cgi-bin/etc/
[...]
The program was not able to determine a location for your
OpenSSL installation, required to build PAPI. Please type the
full path to the OpenSSL directory [/usr/local/ssl]
/usr/lib/ssl
[...]
# make
# make install
# mkdir -p /usr/local/PAPI/AS
# cp -r AS/etc /usr/local/PAPI/AS/
# file that essentially contains asignments to a hash named
# PAPI::AuthServer::cfgVar.
use LWP::UserAgent;
# Include here the modules referenced by the elements
# inside the configuration
#use PAPI::BasicAuth;
#use PAPI::POPAuth;
#use PAPI::IMAPAuth;
use PAPI::LDAPAuth;
#use PAPI::CertAuth;
# Just convenience
#
$cfg = \%PAPI::AuthServer::cfgVar;
# The definition of the working directory should be the first
# configuration assignment
#
$$cfg{workingDirectory} = '/usr/local/PAPI/AS/etc';
# This variable will allow the selection of the authentication methods
#
# Uncomment for using basic PAPI authentication
#my $authType = "basic";
# Uncomment for using POP-based authentication
#my $authType = "pop";
# Uncomment for using IMAP-based authentication
#my $authType = "imap";
# Uncomment for using LDAP-based authentication
my $authType = "ldap";
# Uncomment for using X509 certificate authentication
#my $authType = "cert";
# Admin data (included in the HTML templates)
#
$$cfg{adminContact} = '<b>papi@urjc.es</b>';
# HTML templates
#
$$cfg{loginTemplate} = fromFile("login.html");
$$cfg{acceptTemplate} = fromFile("accept.html");
$$cfg{testTemplate} = fromFile("test.html");
$$cfg{logoutTemplate} = fromFile("logout.html");
$$cfg{rejectTemplate} = fromFile("reject.html");
$$cfg{siteInfoTemplate} =
'<tr>
<td>*</td>
<td><a href="<papi var="poa"/><papi var="location"/>
<papi var="accessURI"/>"
target="<papi var="service"/>">
<strong><papi var="desc"/></strong></a>
</td>
</tr>';
# Properties of this AS, to be sent to the PoA(s)
#
$$cfg{asLocation} = 'https://www.papi.urjc.es/cgi-bin/AuthServer';
$$cfg{serverID} = 'URJCAS';
$$cfg{privateKey} = 'privkey.pem';
$$cfg{publicKey} = 'pubkey.pem';
# Comment these if you do not require split (thus SSL-capable) mode
#
#$$cfg{splitModeURL} = '';
#$$cfg{splitModeParamList} = '';
#
# These parameters make PoAs redirect accept/reject responses to
# locally controlled URLs
#
#$$cfg{acceptURL} = 'http://www.papi.urjc.es/accept-file';
#$$cfg{rejectURL} = 'http://www.papi.urjc.es/reject-file';
#
# Values for the authentication cookie
# Comment them if you do not require its use
#
$$cfg{authCookie} = 'PAPIuid,username,password';
$$cfg{authCookieDB} =
'/usr/local/PAPI/AS/etc/PAPIAuthenCookies';
$$cfg{authCookieTimeToLive} = 7200;
#
# Value of the AS symmetric key
# Used in split mode and for en-/de-crypting the authentication cookie
# It is highly advisable that you change this value
#
#$$cfg{symKey} = 'ca1813914a25b12a14ca121516e26180';
#
# The connection variable holding user id (for TEST and LOGOUT)
$$cfg{uidVar} = 'username';
# Default values for the PoA(s)
#
$$cfg{defTimeToLive} = 7200;
$$cfg{defLocation} = '/';
$$cfg{defService}= '';
$$cfg{defPoA} = '';
$$cfg{defDescription} = '';
$$cfg{defAuthURI} = '/cookie_handler.cgi';
$$cfg{defAccessURI} = '';
#
# Default assertion about users to be sent to PoA(s)
$$cfg{defAssertion} = '';
# Hooks and hook config. By default, "basic" authentication is used
#
if ($authType eq "pop") {
[...]
elsif ($authType eq "imap") {
[...]
elsif ($authType eq "ldap") {
$$cfg{authenticationHook} = \&PAPI::LDAPAuth::VerifyUser;
$$cfg{credentialHook} = \&PAPI::LDAPAuth::UserCredentials;
$$cfg{attrRequestHook} = \&PAPI::LDAPAuth::UserAttributes;
$$cfg{LDAPserver} = "dagobah.urjc.es";
$$cfg{LDAPport} = 389;
$$cfg{LDAPUSERtemplate} = 'uid=<papi var="username"/>';
$$cfg{LDAPAuthSearchBase} = 'ou=gente,dc=urjc,dc=es';
$$cfg{LDAPAuthScope} = 'sub';
$$cfg{LDAPsearchBase} = 'ou=papiSite,dc=urjc,dc=es';
# Uncomment these to use simple authentication when binding
# to the LDAP server
$$cfg{LDAPbindDN} =
'uid=managerid,ou=admin,dc=urjc,dc=es';
$$cfg{LDAPbindPassword} = 'contraseña';
# Uncomment these to use a TLS connection and verify server identity
# $$cfg{LDAPS} = 1;
# $$cfg{LDAPSverify} = 'require';
# $$cfg{LDAPScafile} = '/etc/PAPI/CAs/MyRoot.pem';
}
elsif ($authType eq "cert") {
[...]
else {
[...]
$$cfg{logHook} = undef;
[...]
# openssl genrsa 1024 -out privkey.pem
# openssl rsa -in privkey.pem -pubout -out pubkey.pem
La configuración aquí seguida implica que tanto el AS como los PoAs perl que actúan en modo proxy se instalan en el mismo servidor, al igual que los GPoAs. De este modo, nuestros PoAs serán hosts virtuales del servidor. Lo mejor en este caso es crear un archivo separado de configuración para los puntos de acceso, por ejemplo, /etc/apache/conf.d/papi. Dicho fichero debe ir encabezado por la configuración general de PAPI para sus puntos de acceso:
# Configuración general de PAPI
#
PerlModule PAPI::Conf
<PAPI_Main>
Service_ID poa_generico
HKEY_File /usr/local/PAPI/PoA/hkey
LKEY_File /usr/local/PAPI/PoA/lkey
Lcook_Timeout 86400
CRC_Timeout 1800
URL_Timeout 1800
Debug 0
Auth_Location /cookie_handler.cgi
# en caso de utilizar el mecanismo de las ``bolitas'',
# debemos descomentar las siguientes líneas
# Accept_File /usr/local/PAPI/PoA/yes.gif
# Reject_File /usr/local/PAPI/PoA/no.gif
Pubkeys_Path /usr/local/PAPI/PoA/KEYS
Hcook_DB /usr/local/PAPI/PoA/hcook.db
PAPI_AS URJCAS
https://www.papi.urjc.es/cgi-bin/AuthServer AuthServer URJC
</PAPI_Main>
# wget ftp://ftp.rediris.es/rediris/papi/PAPI-PoA.1.4.0.tar.gz
# tar xzvf PAPI-PoA.1.4.0.tar.gz
# apt get install libio-socket-ssl-perl libmldbm-perl
# apt get install liburi-perl libmldbm-sync-perl
# apt-get install libhtml-tokeparser-simple-perl
# apt-get install libapache-authcookie-perl
# apt-get install libdata-dumper-simple-perl
# apt-get install libnet-ldap-perl
# cd
# wget http://.../HTTP-Request-Form-0.952.tar.gz
# tar xzvf HTTP-Request-Form-0.952.tar.gz
# cd HTTP-Request-Form-0.952
# perl Makefile.PL
# make
# make install
# perl Makefile.PL
You must provide a location for installing the PAPI
Authentication Server software. It must be a directory
configured to hold CGI programs in your Apache
installation [/usr/local/apache/cgi-bin]
/usr/lib/cgi-bin
The Authentication Server CGI will be in
/usr/lib/cgi-bin/AuthServer
The configuration file will be /usr/lib/cgi-bin/AuthServer.cf
Other data files will be installed under /usr/lib/cgi-bin/etc/
[...]
The program was not able to determine a location for your
OpenSSL installation, required to build PAPI. Please type the
full path to the OpenSSL directory [/usr/local/ssl]
/usr/lib/ssl
[...]
# make
# make install
ServerName poa.papi.urjc.es
ErrorDocument 404 https://poa.papi.urjc.es/index.html
</VirtualHost>
<VirtualHost 192.168.84.92:443>
ServerName poa.papi.urjc.es
ErrorDocument 403 https://www.papi.urjc.es/cgi-bin/AuthServer
<Location /app>
PerlSendHeader On
PerlAccessHandler PAPI::Main
<PAPI_Local>
Service_ID poa
Req_DB /usr/local/PAPI/PoA/req_poa
GPoA_URL wayf:built-in
</PAPI_Local>
</Location>
</VirtualHost>
Los puntos de acceso en modo proxy se configuran exactamente igual que cualquier otro punto de acceso, con la particularidad de que debemos indicar la URL o el dominio al que redirigir las peticiones entrantes. Por ejemplo:
ServerName proxy.papi.urjc.es
RedirectMatch /index.html https://proxy.papi.urjc.es
ErrorDocument 404 https://proxy.papi.urjc.es/index.html
</VirtualHost>
<VirtualHost 192.168.84.92:443>
ServerName proxy.papi.urjc.es
ErrorDocument 403 https://www.papi.urjc.es/cgi-bin/AuthServer
<Location />
PerlSendHeader On
PerlAccessHandler PAPI::Main
<PAPI_Local>
Service_ID proxy
Req_DB /usr/local/PAPI/PoA/req_proxy
GPoA_URL wayf:built-in
Remote_URL http://www.urjc.es
Eval_Proxy_Redirects 1
</PAPI_Local>
</Location>
</VirtualHost>
Por último, podemos utilizar las directivas PAPI_Redirect, Rewrite_URL y Redirect_All para definir las sustituciones de URLs en los documentos HTML servidos, hacerlo incluso en contenidos no HTML (como código javascript) y evaluar todas las URLs encontradas en el documento en modo agresivo, respectivamente. Para información detallada sobre todas estas y otras directivas adicionales es conveniente consultar la guía para principiantes de PAPI.
El autocompletado de formularios es una vuelta de tuerca sobre la configuración de un PoA en modo proxy. Básicamente consiste en utilizar la directiva From_Processor para configurar el módulo de PAPI que se encargará de los formularios. Por ejemplo:
ServerName proxy.papi.urjc.es
RedirectMatch (.*) https://proxy.papi.urjc.es/
</VirtualHost>
<VirtualHost 192.168.84.92:443>
ServerName proxy.papi.urjc.es
<Location />
PerlSendHeader On
PerlAccessHandler PAPI::Main
<PAPI_Local>
Service_ID proxy
Req_DB /usr/local/PAPI/PoA/req_proxy
GPoA_URL wayf:built-in
Remote_URL https://www.urjc.es
Redirect_All 1
PAPI_Redirect www.urjc.es(.*?) proxy.papi.urjc.es$1
Eval_Proxy_Redirects 1
Form_Processor urle=>^/.* \
form=>login buttonName=>action_login \
field=>(password,$r->notes('PAPIAttr-password')) \
field=>(usuario,$r->notes('PAPIAttr-username'))
</PAPI_Local>
</Location>
En primer lugar debemos descargar la última versión del phpPoA del sitio FTP de RedIris: ftp://ftp.rediris.es/rediris/papi/. Descomprimimos el archivo a algún lugar en nuestro sistema, por ejemplo, /usr/local/phpPoA:
# wget ftp://ftp.rediris.es/rediris/papi/phpPoA.1.1.tar.gz
# tar -xzvf phpPoA.1.1.tar.gz
phpPoA_ini_file = "/usr/local/phpPoA/etc/phpPoA.ini"
; localización de la base de datos de peticiones
; el directorio DB debe ser propiedad del usuario
; que ejecuta apache y tener permisos de escritura
Request_DB = /usr/local/phpPoA/var/DB/request_db.db4
DB_Type = db4
; al igual que el directorio DB, el directorio logs
; debe tener permisos suficientes para que el usuario
; de apache pueda escribir en él
error_log = /usr/local/phpPoA/var/logs/papi_error.log
; si se usa el modo automático, se debe proporcionar
; la url de los posibles documentos de error
Not_Auth_Error_File = https://foo.urjc.es/NotAuthorized.html
Cookie_Error_File = https://foo.urjc.es/CookieError.html
System_Error_File = https://foo.urjc.es/SystemError.html
; definición de aserciones que se permiten
PAPI_Filter_accept = ".*"
; definición de aserciones que se deniegan
PAPI_Filter_reject = ".*"
; Cookie_Domain is Optional
Cookie_Domain = papi.urjc.es
; clave compartida con el GPoA
LKEY_File = /usr/local/phpPoA/KEYS/lkey
; clave pública del GPoA
GPoA_Pub_Key = /usr/local/phpPoA/KEYS/_GPoA_pubkey.pem
; la url completa del GPoA, debe coincidir con la
; definida por la directiva Auth_Location en el GPoA
GPoA_URL = https://gpoa.papi.urjc.es/cookie_handler.cgi
[admin]
Location = /papi/admin
; Cookie_Domain is Optional
Cookie_Domain = papi.urjc.es
LKEY_File = /usr/local/phpPoA/KEYS/lkey
GPoA_Pub_Key = /usr/local/phpPoA/KEYS/_GPoA_pubkey.pem
GPoA_URL = https://gpoa.papi.urjc.es/cookie_handler.cgi
PAPI_Filter_accept = ".*"
PAPI_Filter_reject = ".*"
Lcook_Timeout = 86400
Request_DB = /usr/local/phpPoA/var/DB/request_db.db4
DB_Type = db4
error_log = /usr/local/phpPoA/var/logs/papi_error.log
Not_Auth_Error_File = https://foo.urjc.es/NotAuthorized.html
Cookie_Error_File = https://foo.urjc.es/CookieError.html
System_Error_File = https://foo.urjc.es/SystemError.html
$AS = "https://www.papi.urjc.es/cgi-bin/AuthServer";
$BASE = "https://sympa.papi.urjc.es/";
$YES = $BASE."yes.gif";
$NO = $BASE."no.gif";
$_SERVER['HTTPS'] = "on"; // only if we use https
include('PoA.php');
// check PAPI auth
$auto = 0; // do not use papi auto mode
$poa = new PoA('scheme',$auto);
list($res,$userAssertion) = $poa->check_Access();
// show image according to auth status
if ($res == 0)
// GPoA doesn't know user
header("Location: $NO");
else
header("Location: $YES");
?>
La configuración de un grupo de puntos de acceso o GPoA es idéntica al de un PoA convencional, salvo por la inclusión de algunas directivas propias del GPoA. A continuación se muestra una posible configuración con hosts virtuales de Apache de un GPoA:
ServerName gpoa.papi.urjc.es
RedirectMatch (.*) https://gpoa.papi.urjc.es/
</VirtualHost>
<VirtualHost 192.168.84.92:443>
ServerName gpoa.papi.urjc.es
ErrorDocument 403 https://www.papi.urjc.es/cgi-bin/AuthServer
DocumentRoot /var/www/gpoa/
<Location />
PerlSendHeader On
PerlAccessHandler PAPI::Main
<PAPI_Local>
Service_ID gpoa
Req_DB /usr/local/PAPI/PoA/req_gpoa
GPoA_Priv_Key /usr/local/PAPI/AS/etc/privkey.pem
GPoA_Hash_User_Data 0
GPoA_URL wayf:built-in
</PAPI_Local>
</Location>
</VirtualHost>
Por último, si queremos que el GPoA no aparezca como opción en la lista de PoAs disponibles para un usuario, bastará con que modifiquemos su configuración en el LDAP, dejando el campo papiSiteService vacío (con uno o más espacios).
A continuación se encuentran detalladas las implementaciones concretas para cada aplicación integrada en el sistema PAPI de la universidad.
Safari es un servicio online de O'Reilly mediante el cual se pueden consultar publicaciones desde cualquier dirección IP de la universidad. Nuestra intención es poder utilizar dicho servicio desde cualquier ubicación (no sólo desde la universidad) mediante una autenticación previa. Para ello instalamos un servidor que actuará como proxy PoA, y lo configuramos de la siguiente manera:
ServerName safari.papi.urjc.es
RedirectMatch /index.html
https://safari.papi.urjc.es/index.html
ErrorDocument 404 https://safari.papi.urjc.es/index.html
</VirtualHost>
<VirtualHost 192.168.84.92:443>
ServerName safari.papi.urjc.es
ErrorDocument 403 https://www.papi.urjc.es/cgi-bin/AuthServer
<Location />
PerlSendHeader On
PerlAccessHandler PAPI::Main
<PAPI_Local>
Service_ID safari
Req_DB /usr/local/PAPI/PoA/req_safari
GPoA_URL wayf:built-in
Remote_URL http://safari.oreilly.com
</PAPI_Local>
</Location>
</VirtualHost>
En esta aplicación el método de autenticación consistía en un usuario y contraseña con los que se creaba una sesión que se comprobaba el resto del tiempo. En su lugar, crearemos un index.php que compruebe las credenciales de PAPI y haga lo necesario para autenticar al usuario en caso de que no lo esté ya (en este caso, redirigirle al GPoA asociado). Cuando las credenciales sean las esperadas, se le creará una sesión que servirá para identificarle hasta que cierre la aplicación, de modo que no es necesario tocar ningún código de la misma, sino que basta con incluir un index.php similar al que sigue:
$AS = "https://www.papi.urjc.es/cgi-bin/AuthServer";
session_start();
include('/var/www/include/dbconnectv2.php');
include('/var/www/clases/c_log.php');
include'PoA.php';
//logs
$log->seccion = "autenticacion";
$log->operador = $correo;
$poa = new PoA('lapa');
list($res, $userAssertion) = $poa->check_Access();
if ($res == 0) {
// el GPoA no autentica
header("Location: $AS");
exit;
}
list($mail,$set) = split(",",$userAssertion,2);
list($login,$domain) = split("@",$mail,2);
$consulta = mysql_query("select * from operadores where login='$login'");
if (mysql_num_rows($consulta) == 0) {
//No esta en la tabla de operadores
header("Location: $AS");
exit;
}
// autenticado con éxito por PAPI, y es operador
if (session_is_registered("SESSION"))
session_unregister("SESSION");
session_register("SESSION");
$SESSION["login"] = $login;
$log->descripcion = "Exito en la autenticacion";
$log->putlog();
header("Location: /main.php");
exit;
?>
Horde es el sistema de correo web utilizado en la universidad. Permite la utilización de diferentes servidores IMAP y por tanto dar acceso a varios dominios de correo. Partiendo de la base de que tenemos Horde configurado y que utilizamos IMP para la autenticación, lo único que tenemos que hacer es sustituir el fichero index.php de Horde por uno ligeramente modificado. Encontraremos el original en /usr/share/horde3/index.php. Realizamos una copia de seguridad y editamos su contenido:
# vi /usr/share/horde3/index.php
/**
* $Horde: horde/index.php,v 2.105.4.3 2005/03/02 07:10:35 chuck Exp $
*
* Copyright 1999-2005 Charles J. Hagenbuch <chuck@horde.org>
* Copyright 1999-2005 Jon Parise <jon@horde.org>
*
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
*/
@define('AUTH_HANDLER', true);
@define('HORDE_BASE', '/usr/share/horde3');
$horde_configured =
(@file_exists(HORDE_BASE . '/config/conf.php') &&
@file_exists(HORDE_BASE . '/config/mime_drivers.php') &&
@file_exists(HORDE_BASE . '/config/nls.php') &&
@file_exists(HORDE_BASE . '/config/prefs.php') &&
@file_exists(HORDE_BASE . '/config/registry.php'));
if (!$horde_configured) {
require HORDE_BASE . '/lib/Test.php';
Horde_Test::configFilesMissing('Horde', HORDE_BASE, 'prefs.php',
array('conf.php' => 'This is the main Horde configuration file. It\
contains paths and basic items that apply to the core\
framework and all Horde applications.',
'mime_drivers.php' => 'This file controls the global set of\
MIME drivers for the Horde framework, allowing applications\
to make use of programs such as enscript or mswordview to\
render content into HTML for viewing in a browser.',
'nls.php' => 'This file provides localisation support for the\
Horde framework.',
'registry.php' => 'The registry is how Horde applications find\
out how to talk to each other. You should list any installed\
Horde applications that you have here.'));
}
require_once HORDE_BASE . '/lib/base.php';
// añadimos la biblioteca criptográfica de Horde
require_once HORDE_BASE . '/lib/Horde/Secret.php';
if ($browser->isMobile()) {
require HORDE_BASE . '/services/portal/mobile.php';
exit;
}
$main_page = Util::getFormData('url');
if (!$main_page) {
$main_page = Horde::initialPage();
}
// autenticamos mediante PAPI
$AS = "https://www.papi.urjc.es/cgi-bin/AuthServer";
$_SERVER['HTTPS'] = "on"; // sólo si usamos https
include('PoA.php');
$poa = new PoA('horde');
list($res,$userAssertion) = $poa->check_Access();
// si no está autenticado, redirigimos al AS
if ($res == 0) {
header("Location: $AS");
exit;
}
// parseo de la asercion
list($mail,$other) = split(",",$userAssertion,2);
list($imapuser,$server) = split("@",$mail,2);
list($pass,$AS) = split("@",$other,2);
if ($imapuser == '' || $pass == '') {
header("Location: $AS");
exit;
}
// rellenamos las variables post del formulario de login
$_POST['imapuser'] = $imapuser;
$_POST['pass'] = $pass;
$_POST['autologin'] = "0";
$_POST['mailbox'] = "INBOX";
$_POST['load_frameset'] = "1";
$_POST['actionID'] = "";
$_POST['folders'] = "INBOX.";
$_POST['url'] = "index.php";
$_POST['new_lang'] = "es_ES";
/* codigo específico para los servidores de correo configurados
habría que cambiarlo! */
if ($server == "alumnos.urjc.es")
$server = "imapALUMNOS";
if ($server == "urjc.es")
$server = "imapURJC";
$_POST['server'] = $server;
if (!Util::getFormData('frameset_loaded') &&
($conf['menu']['always'] ||
(Auth::getAuth() && $prefs->getValue('show_sidebar')))) {
if ($browser->hasQuirk('scrollbar_in_way')) {
$scrollbar = 'yes';
} else {
$scrollbar = 'auto';
}
/* nos aseguramos de mantener la password en la variable de
sesion en caso de que no sea nuestro primer acceso */
$_SESSION['imp']['pass'] = Secret::write(
Secret::getKey('imp'), $pass);
require HORDE_TEMPLATES . '/index/frames_index.inc';
} else {
// tras rellenar a mano el formulario, lo "enviamos"
require HORDE_BASE . '/imp/redirect.php';
}
?>
En el caso del gestor de listas de correo no se puede utilizar el phpPoA, pero si un PoA convencional, con la particularidad de que es necesario adaptar Sympa para que utilice dicho PoA como sistema single-sign-on. Para ello es necesario modificar el código del propio Sympa y crear conectores que se encarguen de enlazar con la funcionalidad proporcionada por PAPI.
En nuestro caso, por sencillez, es preferible configurar un proxy de reescritura que utilice el autocompletado de formularios para rellenar el mismo automáticamente. Es necesario modificar la plantilla principal de Sympa ya que no incluye nombre en sus formularios. Para ello, editamos el archivo /usr/share/sympa/wws_templates/loginbanner.es.tpl y en la línea 17 añadimos el atributo NAME=login. Configuramos adicionalmente un virtual host de apache para nuestro proxy, del siguiente modo:
ServerName sympa.papi.urjc.es
RedirectMatch (.*) https://sympa.papi.urjc.es/
</VirtualHost>
<VirtualHost 192.168.84.92:443>
ServerName sympa.papi.urjc.es
<Location />
PerlSendHeader On
PerlAccessHandler PAPI::Main
<PAPI_Local>
Service_ID sympa
Req_DB /usr/local/PAPI/PoA/req_sympa
GPoA_URL wayf:built-in
Remote_URL https://listas.urjc.es
Redirect_All 1
PAPI_Redirect listas.urjc.es(.*?) sympa.papi.urjc.es$1
Eval_Proxy_Redirects 1
Form_Processor urle=>^/wws.* form=>login
buttonName=>action_login
field=>(passwd,$r->notes('PAPIAttr-password'))
field=>(email,$r->notes('PAPIAttr-username'))
</PAPI_Local>
</Location>
</VirtualHost>
Gente es la aplicación de directorio utilizada en la universidad, y se utiliza adicionalmente para que el personal modifique sus datos personales, entre los que se encuentran, por ejemplo, el nombre de usuario y la contraseña que utilizará PAPI para autenticar. Es por tanto una aplicación un poco especial, ya que acepta dos formas de autenticación a través del mismo formulario. Cuando un usuario no tiene un nombre de usuario y una contraseña, deberá hacer login con su NIF y su fecha de nacimiento, ambos valores almacenados en una base de datos. Tras identificarse por primera vez y elegir un nombre de usuario y contraseña, esta forma de acceso no volverá a permitirse para este usuario. Por si fuera poco, sólo se permite el acceso autenticado (de cualquier forma) a través de la propia red de la universidad, lo cual complica aún más la implementación.
Las implicaciones directas de este modelo son que la aplicación debe mantener su formulario, en vez de delegar absolutamente la autenticación en PAPI. Deberá recoger los datos del usuario y realizar los análisis pertinentes (como verificar si se ha introducido un nombre de usuario o un DNI y si se conecta desde la red corporativa), y proceder de forma adecuada. En particular, si se recibe un DNI la aplicación deberá autenticar por su cuenta contra la base de datos, y si recibe un nombre de usuario deberá delegar la autenticación en un phpPoA. Al introducir un phpPoA como forma de autenticación se elimina la necesidad de acceder exclusivamente desde la red de la universidad, ya que PAPI proporciona las garantías de seguridad necesarias para que los usuarios accedan a la aplicación desde otras localizaciones.
La implementación de este sistema no es en absoluto trivial. Una forma más sencilla de implementar el acceso autenticado a la aplicación a través de PAPI consiste en implementar un fichero PHP aparte, por ejemplo, papi.php, al que se accederá desde la lista de aplicaciones del servidor de autenticación, y que básicamente realizará un POST manual al formulario de gente. De esta forma podemos acceder una vez autenticados en PAPI, pero perdemos la capacidad de hacerlo directamente, viéndonos obligados a hacerlo obligatoriamente a través del AS.
$AS = "https://www.papi.urjc.es/cgi-bin/AuthServer";
include'PoA.php';
$poa = new PoA('gente');
list($res, $userAssertion) = $poa->check_Access();
// comprobamos si el usuario está autenticado
if ($res == 0) {
// el GPoA no autentica
header("Location: $AS");
exit;
}
// verificamos la aserción
if (!strpos($userAssertion,',')) {
header("Location: $AS");
exit;
}
// obtenemos las variables de la aserción
list($mail,$other) = split(",",$userAssertion,2);
list($usuario,$server) = split("@",$mail,2);
list($clave,$AS) = split("@",$other,2);
// rellenamos manualmente las variables del formulario
@$_REQUEST['accion'] = "entrar";
@$_REQUEST['usuario'] = $usuario;
@$_REQUEST['clave'] = $clave;
@$_REQUEST['submit'] = "Aceptar";
// invocamos manualmente a la autenticación
require ("login.php");
?>
El caso de WebCT es relativamente sencillo, ya que basta con instalar un proxy de reescritura que rellene automáticamente el formulario de autenticación. Ya que la aplicación se distribuye con su propio servidor web y es propietaria, utilizar otros métodos de integración con PAPI se complica considerablemente. A continuación se muestra una configuración de ejemplo:
ServerName campusvirtual.papi.urjc.es
RedirectMatch /index.html https://campusvirtual.papi.urjc.es
ErrorDocument 404 https://campusvirtual.papi.urjc.es/index.html
</VirtualHost>
<VirtualHost 192.168.84.92:443>
ServerName campusvirtual.papi.urjc.es
ErrorDocument 403 https://www.papi.urjc.es/cgi-bin/AuthServer
<Location />
PerlSendHeader On
PerlAccessHandler PAPI::Main
<PAPI_Local>
Service_ID campusvirtual
Req_DB /usr/local/PAPI/PoA/req_campusvirtual
GPoA_URL wayf:built-in
Remote_URL http://www.campusvirtual.urjc.es
Eval_Proxy_Redirects 1
Form_Processor urle=>.*/webct/ticket/ticketLogin\?\
action=print_login&request_uri=/webct/homearea/homearea.* \
form=>authenticate buttonName=>submitbutton \
field=>(Password,$r->notes('PAPIAttr-password')) \
field=>(WebCT_ID,$r->notes('PAPIAttr-username'))
</PAPI_Local>
</Location>
</VirtualHost>
El caso de la secretaría virtual es un poco más delicado. Su formulario de identificación utiliza distintos parámetros dependiendo del tipo de usuario. En caso de que el usuario sea PAS o PDI utilizará el nombre de usuario y contraseña que se utiliza en el resto de servicios, mientras que los alumnos deberán utilizar su DNI (sin letra) y su contraseña. Instalaremos un proxy de reescritura con autocompletado de formulario, con la particularidad de que necesitaremos hacer uso de la directiva Hcook_Generator para modificar la aserción emitida por el AS atendiendo al tipo de usuario. De este modo comprobaremos si el usuario tiene perfil de alumno, y en tal caso sustituiremos su nombre de usuario por su DNI sin letra.
A continuación se muestra una configuración muy básica de un proxy PAPI que rellenará el formulario correspondiente, sin modificar la cookie, de modo que sólo permitirá identificarse al personal universitario:
ServerName gestion.papi.urjc.es
RedirectMatch /index.html https://gestion.papi.urjc.es
ErrorDocument 404 https://gestion.papi.urjc.es/index.html
</VirtualHost>
<VirtualHost 192.168.84.92:443>
ServerName gestion.papi.urjc.es
ErrorDocument 403 https://www.papi.urjc.es/cgi-bin/AuthServer
<Location />
PerlSendHeader On
PerlAccessHandler PAPI::Main
<PAPI_Local>
Service_ID gestion
Req_DB /usr/local/PAPI/PoA/req_gestion
GPoA_URL wayf:built-in
Remote_URL https://gestion.urjc.es
Redirect_All 1
PAPI_Redirect gestion.urjc.es(.*?) gestion.papi.urjc.es$1
Eval_Proxy_Redirects 1
Form_Processor urle=>^/Redcampus/acceso.htm$ \
form=>formAcceso buttonName=>image \
field=>(TXT_CLAVE,$r->notes('PAPIAttr-password')) \
field=>(TXT_USUARIO,$r->notes('PAPIAttr-username'))
</PAPI_Local>
</Location>
</VirtualHost>