En uno de nuestros proyectos nos hemos encontrado con la situación de tener que unir dos federaciones PAPI, permitiendo que personas que pertenezcan a una federación puedan acceder a los recursos federados de otra federación.
La solución que hemos ideado ha llevado al desarrollo de un nuevo elemento en php que implementa el protocolo PAPI, al cual le hemos denominado ASProxy.
Este elemento permite conectar dos GPoAs, cada uno de una federación diferente. Para la federación que protege los recursos, el ASProxy actúa como un AS normal, pero para el GPoA de la federación a la que pertenece el usuario, el ASProxy se comporta como un PoA.
Cuando un ASProxy recibe un mensaje ATTREQ de un GPoA, traduce esa petición en un mensaje CHECK, almacenando en la sesión información necesaria para cuando esa petición sea contestada. En esa petición ATTREQ se envíará el parámetro PAPIHLI con el valor del AS de la federación 2 al que pertenece, pudiendo así evitar el paso de que el usuario tenga que seleccionar de nuevo en un WAYF a qué institución pertenece.
Cuando a un ASProxy le llega un mensaje CHECKED de respuesta proveniente del GPoA de la federación 2, éste deberá transformar este mensaje, descifrándolo con la clave pública del GPoA de la federación 2, modificando la información necesaria y cifrándolo con su clave privada para que el GPoA de la federación 1 pueda comprender la respuesta.
Esta será un mensaje CHECKED de tipo AS->GPoA, distinto del recibido anteriormente, de tipo GPoA->PoA.
Como una extensión futura a este componente, estamos pensando la forma más adecuada de enviar, dentro de la aserción obtenida, el AS de la federación 2 donde el usuario se ha autenticado para que así, en la federación 1, puedan realizar filtros con esta información.
Desde PRiSE seguiremos informando de cómo evoluciona este componente.
Recientemente hemos finalizado un proyecto que hemos llevado a cabo con la Universidad de Sevilla para actualizar y migrar a nuevas versiones su actual despliegue de PAPI en sus instalaciones.
Gracias a este proyecto y su apoyo hemos podido desarrollar dos nuevos componentes PAPI con licencia GPL. Estos son los siguientes:
Todavía no hay mucha documentación de ambos proyectos, y es que estamos trabajando en la nueva web de PAPI donde estamos escribiendo ya cómo instalarlos y cómo configurarlos, además de mucha más información del resto de los componentes.
Si quieres ir probándolos, puedes descargarlos utilizando los siguientes repositorios Mercurial:
El 20 de Abril del 2009 fue un mal día para las organizaciones (y el software libre en general, aunque es mi opinión personal y ya hablaré de esto en otro momento) que utilizaban OpenSSO: Oracle decidió comprar Sun Microsystems.
Uno de los problemas que han surgido a raíz de dicha compra es el estado “incierto” que están sufriendo aquellos usuarios de OpenSSO. ¿Ha dejado de ser un proyecto libre? O mejor dicho, ¿ha dejado de ser un proyecto en activo?
Ahora hay que registrarse en Oracle y solicitar una cuenta de cliente con ellos para descargarlo, mientras que los agentes de política (los módulos de openSSO que se instalaban en un servidor web para proteger una zona) han desaparecido misteriosamente sin comunicar nada en su página web.
Como muchos de sus usuarios están evaluando alternativas para migrar a otro producto, nosotros queremos proponerles que migren a PAPI. Gracias a OpenSSO2PAPI podrán migrar a una infraestructura basada en PAPI sin necesidad de cambiar la tecnología que usaban para proteger las aplicaciones.
OpenSSO2PAPI es un software a través del cual PAPI puede ofrecer la API que OpenSSO provee para gestionar la cesión de datos de identidad y atributos a las aplicaciones que estén protegidas con dicha tecnología, implementando el comportamiento y las APIs que dichas aplicaciones esperan.
Podemos dividir la arquitectura de OpenSSO en dos grandes bloques:
Hemos implementado en Opensso2PAPI un conjunto de pantallas y APIs tipo REST y hemos comprobado que funciona perfectamente con aplicaciones protegidas con OpenSSO.
La idea es que OpenSSO2PAPI utiliza un PoA (utilizando phpPoA) para obtener de una infraestructura PAPI, o de un Servidor de autenticación en concreto a través del parámetro PAPIHLI, la identidad del usuario y sus atributos. De esta forma, es como si el OpenSSO delegara en PAPI la gestión de la identidad del usuario.
Cambiando tan sólo las URLs que tenemos definidas en nuestras aplicaciones, la cual hemos protegido con OpenSSO, por la nueva dirección donde está desplegado OpenSSO2PAPI, habremos migrado a PAPI sin necesidad de realizar cambios en dichas aplicaciones con un coste elevado.
Ya está disponible la primera versión del conector PAPI para CAS. Éste es un sistema para autenticar usuarios en una institución desarrollado inicialmente por la Universidad de Yale y que posteriormente pasó a ser gestionado por la Jasig, un consortium de universidades norteamericanas.
Aunque CAS tiene su propio protocolo, ha sido diseñado de manera que pueda implementar otros protocolos, trayendo ya en la distribución oficial el interfaz de SAML 1.1, su única forma de emitir atributos, u OpenID.
Tras un acuerdo con la Valencian International University (VIU), PRiSE ha desarrollado un conector PAPI para CAS, con licencia GPL, para que un CAS pueda actuar como proveedor de identidad dentro de una infraestructura basada en PAPI.
La última versión está disponible en su página en la Forja y el código fuente está disponible en el repositorio de Mercurial http://www.prise.es/hg/papi-cas.
Apache, como consecuencia de la vulnerabilidad CVE-2003-0020, escapa todos los logs de errores, con el fin de evitar que un atacante pueda insertar secuencias de caracteres de escape, y provocar vulnerabilidades en emuladores de terminal.
Pues bien esto hace que todos los caracteres de control sean impresos en los ficheros de log de errores con su representación visual (i. e. ‘\n’, \t’, etc), en vez de actuar como tales. Por lo que depurar mensajes de error generados por cualquier componente externo a Apache, como por ejemplo aplicaciones PHP, scripts-cgi o handles mod_perl, es muy poco agradable, ya que te encuentras con mensajes de error de 10 o 15 líneas condensadas en una sola.
Como en mi día a día tengo que tratar con PAPI (desarrollado en mod_perl2) sufro bastante esta desconsideración de Apache al escribir los mensajes de debug que genera PAPI, vamos que tengo que manejar mensajes de debug de PAPI con el siguiente formato:
[Thu Mar 11 11:19:52 2010] [debug] ApachePoA.pm(105): [client 130.206.6.37]
PAPI-DEBUG#20069_1268302792_sirgpoa: Parameters initialized:$VAR1 = bless( {\n
'Filtered' => 1,\n 'Accept_File' =>
/aaaa/bbbb/cccc/dddd.ddddd/conf/papi/gpoa/shim.gif',\n
'String' => /GPoA',\n 'attrList' => [],\n 'filte
rs' => [],\n 'PxCkSize' => 320768,\n ApacheReq
uest' => bless( do{\\(my $o = 11921096)}, 'Apache2::RequestRec' ),\n 'useHcoo
k' => 0,\n 'Type' => 'Location',\n 'Hcook_Ha
ndler' => undef,\n 'registerKey' => '',\n 'MxNonc
eErr' => 3,\n 'PoARw' => [\n {\n
'value' => 'check=false,$1,',\n
Lo que como se puede ver es inmanejable. Por esto un día decidí hacer uso de la capacidad que tiene el Apache para enviar los logs a un programa externo que recibirá estos logs por entrada estándar. Siendo en este programa externo donde reemplazo los caracteres de control (i.e. su representación visual) por su valor. Con lo que consigo log de debug de PAPI con el siguiente formato:
[Wed Mar 10 15:51:52 2010] [debug] ApachePoA.pm(105): [client 130.206.6.51]
PAPI-DEBUG#29900_1268232712_simplepoa: Parameters initialized:
$VAR1 = bless( {
'Filtered' => 1,
'Accept_File' => '/etc/apache2/papi/global/images/image_ok.png',
'String' => '/simplePoA',
'attrList' => [],
'filters' => [
{
'reg' => '.*',
'act' => 'accept'
}
],
'PxCkSize' => 320768,
'ApacheRequest' => bless( do{\\(my $o = 155158008)},
'Apache2::RequestRec' ),
'useHcook' => '1',
'Type' => 'Location',
'registerKey' => '',
'Hcook_Handler' => '.*',
'MxNonceErr' => 3,
'URL_Timeout' => '600',
'PoARw' => [],
Una mejora considerable ¿no?
El truco que hay que hacer consiste en definir el ErrorLog así:
ErrorLog "|/usr/local/bin/splitApacheLog.pl /path/papi_error.log /path/error.log"
Donde el progrma Perl splitApacheLog.pl consiste en:
1 #!/usr/bin/perl
2
3 my $papi = shift @ARGV;
4 my $error = shift @ARGV;
5 my $line = '';
6 #$|=1;
7
8 open(PAPI_OUT,">>$papi")
9 or die("No se puede abrir el fichero $papi\n$!\n");
10 open(ERROR_OUT,">>$error")
11 or die("No se puede abrir el fichero $error\n$!\n");
12
13 while (defined($line = )){
14 if ($line =~ /PAPI/){
15 $line =~ s/\\n/\n/g;
16 do {
17 use bytes;
18 my $size=length($line);
19 syswrite(PAPI_OUT, $line, $size);
20 }
21 }else{
22 $line =~ s/\\n/\n/g;
23 do {
24 use bytes;
25 my $size=length($line);
26 syswrite(ERROR_OUT, $line, $size);
27 }
28 }
29 }
Con esto conseguimos dos ficheros de log, uno para PAPI y otro para Apache, como se puede ver discriminamos con la expresión regular de la línea 14 según la cual enviamos la salida al fichero PAPI o al fichero de Apache.
El código es muy simple y intuitivo, por lo que modificarlo para que se ajuste a las necesidades de cualquiera no debe ser muy complicado.
Por último comentar, que se puede compilar Apache sin esta característica tan molesta de los mensajes de log escapados. Para ello sólo debéis hacer uso de la directiva de compilación DAP_UNSAFE_ERROR_LOG_UNESCAPED, tal y como os muestro a continuación:
CFLAGS=-DAP_UNSAFE_ERROR_LOG_UNESCAPED ./configure
Obviamente no recomiendo esta práctica, sólo informo de ella.
El componente icGPoA de PAPI está experimentando un auge de popularidad en los últimos meses gracias a la labor de RedIRIS en su federación de identidad digital SIR.
Pero, ¿qué es un icGPoA?. Éste es un componente sencillo, extremadamente sencillo (y en cuanto se complique dejará de tener éxito), que permite actuar como GPoA o AS.

Así, el icGPoA sólo es capaz de responder a los siguientes mensajes:
Para generar estas respuestas, el icGPoA sólo necesita una lista de atributos del usuario y una clave privada para firmarla (sobre esto ya hablaremos otro día…). En PHP tiene la siguiente “complejidad”:
if (isset($_REQUEST["ACTION"])) {
$theRef = $_REQUEST["DATA"];
}
else {
$theRef = $_REQUEST["PAPIPOAREF"];
}
$assertion = “attrA=val1,attrB=val2|val3@ID_AS”;
$now = time();
$ext = $now + 3600;
$reply = $assertion . “:” . $ext . “:” . $now . “:” . $theRef;
$safe = openssl_encrypt($reply, $pKey);
Aunque ya está siendo utilizado por más de 30 organizaciones, no existe una versión “oficial” que descargarse. Esperemos que en breve podamos anunciar una URL en este blog.
En la comunidad de desarrolladores de PAPI estamos trabajando en la definición del protocolo PAPI v1.1, que traerá algunas mejoras sobre la versión inicial, que ya iremos desvelando poco a poco en este blog.
Una de estas mejoras es la inclusión del parámetro opcional PAPIOPOA en un mensaje ATTREQ, el cual corresponde a una petición de atributos por parte de un PoA o GPoA. Cuando un proveedor de identidad PAPI recibe este tipo de mensaje, en el caso de que el usuario no se hubiese autenticado previamente, necesitará realizar la autenticación del usuario antes de generar la respuesta al GPoA/PoA.
De esta forma, el mensaje ATTREQ queda definido con la siguiente URL:

Mensaje ATTREQ
Donde,
La principal utilidad de PAPIOPOA es facilitar la política de emisión de atributos de los proveedores de identidad. Consideremos el siguiente escenario:

Escenario PAPIOPOA
Como vemos, cada vez que el AS recibe un mensaje ATTREQ emitido por el GPoA, tendrá que emitir todos los atributos que podrían requerir cualquiera de los PoAs que están conectados con dicho GPoA.
Sin embargo, si en el mensaje ATTREQ recibe el parámetro PAPIOPOA, podremos saber cual fue el PoA que hizo la petición al GPoA y emitir sólo los atributos que dicho PoA necesita.
Además, este nuevo parámetro facilita enormemente la generación de unas estadísticas de acceso, ya que sabremos a qué recurso protegido intenta acceder un determinado usuario.
Últimamente me he visto envuelto en diferentes debates sobre si era seguro o no usar certificados con capacidades SSL, no sólo para asegurar conexiones TCP y/o autenticar servidores, sino también para firmar metadatos o aserciones.
El escenario en el que nos encontramos es el indicado en la figura, en el cual un cliente realiza conexiones HTTPS contra un IdP (Proveedor de Identidad) para acceder a un sistema SSO y por ende a recursos protegidos. Dónde al logarse el cliente con éxito, el IdP genera una aserción sobre quién es el cliente y qué atributos posee, el IdP firma esta aserción con el mismo certificado que se ha usado para establecer la conexión HTTPS.

Escenario
El problema, o mejor dicho, el origen de las inquietudes reside en el uso del mismo certificado para la conexión HTTPS y para la firma de la aserción o de cualquier otro tipo de metadatos, y en el cual confían los SPs (proveedor de servicio) que han establecido relaciones de confianza con el IdP.
Pues bien, estas inquietudes se basan en la creencia incierta de que un servidor web firmará alegremente cualquier cosa presentada por el cliente en el ‘random binary blob‘ durante el SSL-handshake. Si esto fuese cierto un atacante tendría la capacidad de enviar como ‘random binary blob‘ una aserción falsa, que al ser firmada por el certificado x509 en el que confían los SPs, le diese la capacidad de acceder a recursos a los cuales no tiene acceso.
Esto es totalmente falso, ya que bajo ninguna circunstancia un servidor web firmará datos arbitrarios presentados por un cliente. Para aclarar esto voy a explicar que datos presenta el cliente al servidor y que son susceptibles de ser firmados.
Durante el handshake del protocolo TLS/SSL se genera el master secret, el cual es un secreto compartido entre el cliente y el servidor, de 48 bytes y que es usado como clave simétrica para proteger la sesión. Este master secret, se genera mediante la siguiente función:
master_secret = PRF(pre_master_secret, "master secret",
ClientHello.random + ServerHello.random);
Donde PRF es la Pseudoroandom Function elegida de la cipher-suite- especificada en fases previas del handshake, la cual es una función basada en HMAC, que no usa en ningún momento la clave privada del certificado.
El pre_master_secret, es una cadena de 48 bytes enviada por el cliente al servidor y que es lo que nos interesa en este caso, ya que representa los únicos datos que el servidor cifra de forma “alegre”.
La cadena “master secret” es una constante con dicho valor.
Y por último las cadenas ClientHello.random y ServerHello.random son dos blob de 28 bytes, el primero enviado por el cliente en la fase ClientHello del handshake y el segundo enviado por el servidor en la fase ServerHello.
Como he dicho anteriormente, nos interesa el pre_master_secret, ya que esta cadena son 48 bytes, de los cuales 46 son generados aleatoriamente por el cliente y 2 indican el protocolo. Estos 48 bytes son cifrados con la clave pública del servidor. Y es este cifrado el punto que ha generado tanta controversia.
Pues bien, al cifrarse estos datos con la clave pública del servidor, es este servidor el único que puede descifrar y por tanto entender estos datos, ya que es el único en posesión de la clave privada correspondiente.
Con esto, si un cliente malintencionado en vez de generar 46 bytes aleatorios, introduce la aserción falsa, lo que obtendría es un mensaje cifrado que sólo puede leer quien posea la clave privada del servidor. La cual no está en posesión de los SPs, ya que estos sólo necesitan la clave pública, para comprobar la firma de las aserciones.
Como conclusión, decir que podemos estar seguros de usar el mismo certificado x509 tanto para asegurar sesiones con TLS/SSL como para firmar aserciones o metadatos ya que según la especificación del protocolo TLS los datos que un servidor cifra “alegremente”, sólo los puede descifrar él.
Por último decir que separar por roles el uso de claves privadas de los certificados x509, es decir, usar una para TLS y otra para firmar aserciones y/o metadatos, es una buena práctica de seguridad. Ya que aunque TLS ha sido diseñado para resistir ataques contra autenticación y firmado, la historia nos ha demostrado muchas veces que confiar en la calidad de un algoritmo o protocolo y en su implementación debería evitarse en la medida de lo posible.

Acabamos de finalizar el lanzamiento del repositorio Maven para los proyectos en Java que quieran trabajar con la tecnología de PAPI. Maven es una herramienta de software para la gestión de proyectos desarrollados en Java. Una de sus principales características es la posibilidad de definir dependencias de otras librerías Java externas, siendo capaz de instalarlas y utilizarlas en nuestros proyectos.
Para utilizar el repositorio Maven de PAPI, utilizaremos la siguiente configuración:
<repository>
<id>papimaven</id>
<name>papi maven repository</name>
<url>https://forja.rediris.es/svn/papi-ee/trunk/maven/</url>
</repository>
Como está bajo el protocolo https, tendréis que tener importado el certificado digital de su servidor web. Podéis hacerlo de la siguiente manera:
echo |openssl s_client -connect forja.rediris.es:443 2>&1 |sed -ne ‘/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p’ | keytool -import -trustcacerts -alias forja -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit -noprompt
Por ahora hay 4 módulos disponibles:
Nosotros ahora mismo lo estamos utilizando para nuevos desarrollos basados en PAPI que ya os iremos contando en otras entradas del blog…

PAPI es un software que provee a nuestras infraestructuras la capacidad de incorporar nuestra organización y sus aplicaciones en una federación o bien desplegar un sistema de Single Sign-On dentro de nuestro entorno.
Posiblemente el primer software que se publicó con estas capacidades (de hecho Shibboleth y otros proyectos posteriores tuvieron en mente el diseño de PAPI para su arquitectura), fue desarrollado por el equipo de Middleware de RedIRIS y su licencia abierta, GPLv2, permite que cualquier organización o desarrollador pueda colaborar en el proyecto.
PRiSE ha decidido dar soporte comercial de PAPI ya que está ampliamente desplegado en instituciones académicas y científicas. Además, colaborará activamente con el proyecto e incorporará desarrolladores al equipo de PAPI.
En este blog iremos informando de las novedades de este producto.