Vous êtes sur la page 1sur 8

Autenticacin y autorizacin de webservices con certificados en GlassFish

Copyright 2009 Juan Andrs Ghigliazza. Se concede permiso para copiar, distribuir y/o modificar este documento bajo los trminos de la Licencia de Documentacin Libre de GNU, Versin 1.3 o cualquier otra versin posterior publicada por la Free Software Foundation; sin Secciones Invariantes ni Textos de Cubierta Delantera ni Textos de Cubierta Trasera. Una copia de la licencia se puede ver aqu.

1 Introduccin
En este documento, se explica por medio de un ejemplo, como configurar el acceso seguro mediante certificados a un webservice de GlassFish. El ejemplo no solo utiliza certificados X.509 para autenticacin bi-direccional (tanto del servidor como del cliente), sino que tambin usa la informacin del certificado del cliente para autorizar el uso de determinados recursos. Algunos datos del software usado: IDE Servidor de aplicaciones OS Java NetBeans IDE 6.5 GlassFish (Sun Java System Application Server 9.1_02) Ubuntu 8.04.3 1.6.0_14 (Sun)

2 Caso de ejemplo
El ejemplo usado es un webservice muy simple, el cual recibe como parmetro un string, y devuelve otro string concatenado con el que recibi. En esta seccin veremos como implementar tanto el webservice, como un cliente.

2.1 Construccin del webservice


Crear un nuevo proyecto en NetBeans, del tipo "Jave EE" - "EJB Module"1. Llamarlo WebServiceSimple. Crear un nuevo webservice haciendo click derecho en el proyecto, "New" - "Web Service". Llamarlo ServicioSimple y al paquete prueba2. Dentro del nuevo webservice, crear el mtodo metodoSimple. El cdigo completo del webservice quedara de la siguiente forma:
package prueba; import javax.jws.WebService; import javax.ejb.Stateless; @WebService() @Stateless() public class ServicioSimple {

public String metodoSimple(String mensaje) { return "Mensaje recibido por el webservice: '" + mensaje + "'."; } }

Hacerle un deploy al proyecto. Se puede comprobar que fue instalado correctamente accediendo mediante un browser a su WSDL en la direccin (puede variar el puerto) http://localhost:8081/ServicioSimpleService/ServicioSimple?wsdl.

2.2 Creacin de un cliente


Creacin de una aplicacin JSE cliente del webservice:

Crear un nuevo proyecto "Java" - "Java Application". Llamarlo WebServiceSimpleCliente. Agregar un cliente del webservice en el proyecto. Para ello: o Hacer click derecho sobre el proyecto, y "New" - "Web Service Client". o Elegir "WSDL URL" e ingresar la direccin del WSDL antes vista. Luego, en el programa principal (clase generada por NetBeans, que es webservicesimplecliente.Main), agregar la llamada al webservice, desplegando sus resultados. Para ello: o En el cdigo, dentro del mtodo main hacer click derecho, "Web Service Client Resources" - "Call Web Service Operation". o Elegir el mtodo del webservice: "WebServiceSimpleCliente" "ServicioSimple" - "ServicioSimpleService" - "ServicioSimplePort" "metodoSimple". Luego modificar un poco la llamada generada para mandar un texto arbitrario, e imprimir el resultado. La clase quedara ms o menos de la siguiente forma:
package webservicesimplecliente; public class Main { public static void main(String[] args) throws Exception { prueba.ServicioSimpleService service = new prueba.ServicioSimpleService(); prueba.ServicioSimple port = service.getServicioSimplePort(); String result = port.metodoSimple("Envo texto al webservice."); System.out.println("Texto devuelto por el webservice = " + result); } }

Luego se puede correr el cliente; la salida debera ser algo como:


Texto devuelto por el webservice = Mensaje recibido por el webservice: 'Envo texto al webservice.'.

En este momento ya tenemos implementados tanto el webservice de prueba, como el cliente, y funcionando. De aqu en ms veremos como configurar los certificados.

3 Certificados
En esta seccin veremos como configurar los certificados tanto en el servidor como en el cliente. Los certificados usados sern para el servidor, el que genera automticamente GlassFish al momento de su instalacin, y para el cliente crearemos uno autofirmado; cada uno de ellos se copiar a los almacenes de claves (keystore) de confianza del otro. Est fuera del alcance de este artculo el uso de una PKI (Public Key Infrastructure).

3.1 Certificado del servidor


3.1.1 Configuracin del webservice Antes que nada, se configura el webservice para que haga uso de su certificado. El certificado generado por GlassFish al momento de instalarlo se encuentra en el almacn de claves config/keystore.jks dentro del directorio del dominio usado. Para hacer que el webservice sea accesible solamente mediante https usando este certificado debemos:

Crear dentro del proyecto WebServiceSimple un nuevo "GlassFish Deployment Descriptor", con los valores por defecto. En el archivo creado (que es un XML llamado sun-ejb-jar.xml dentro de Configuration Files), agregar un nuevo puerto y setear "transport-guarantee" con el valor "CONFIDENTIAL". Debera quedar de la siguiente forma3:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE sun-ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 EJB 3.0//EN" "http://www.sun.com/software/appserver/dtds/sun-ejb-jar_3_0-0.dtd"> <sun-ejb-jar> <enterprise-beans> <ejb> <ejb-name>ServicioSimple</ejb-name> <webservice-endpoint> <port-component-name>ServicioSimple</port-component-name> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </webservice-endpoint> </ejb> </enterprise-beans> </sun-ejb-jar>

Volver a hacer un deploy al webservice. Se puede comprobar que el webservice solamente puede ser accedido mediante https, ya que escribiendo la direccin http://localhost:8081/ServicioSimpleService/ServicioSimple?wsdl en un browser no se despliega nada. Ahora solamente se puede acceder al WSDL por https, por ejemplo a la direccin https://localhost:8181/ServicioSimpleService/ServicioSimple?wsdl. Claro que tambin podemos acceder al WSDL con el nombre del host en vez de localhost, y es esta forma la que se usar de aqu en ms. Esto es para evitar futuros problemas, ya

que el certificado generado por GlassFish usa como identificador el nombre del host y su dominio, y no localhost. La direccin entonces sera algo as como https://host.dominio:8181/ServicioSimpleService/ServicioSimple?wsdl. 3.1.2 Configuracin del cliente Si en este momento probamos correr el cliente del webservice, nos da un error "Premature end of file" y en el servidor GlassFish el error es "Invalid request scheme for Endpoint ServicioSimple. Expected https . Received http", lo que parece bastante lgico. Lo primero que hay que hacer es que el cliente acceda a la nueva direccin del webservice. La forma ms fcil de lograrlo es borrando el cliente del webservice dentro del proyecto, y recrendolo. Para ello:

Dentro del proyecto cliente, borrar "ServicioSimple" dentro de "Web Service References". Crear un nuevo cliente del webservice, como al principio (click derecho sobre el proyecto, "New" - "Web Service Client"), pero esta vez ingresar la nueva direccin del WSDL. En este momento el IDE nos pregunta si deseamos aceptar el certificado de GlassFish, lo que lgicamente tenemos que hacer. Recompilamos el proyecto cliente.

Ahora el proyecto cliente est listo para acceder al webservice mediante https. Sin embargo, si lo corremos da el error "unable to find valid certification path to requested target", lo que tambin es lgico, ya que el cliente desconoce el certificado del servidor, y no tiene forma de validarlo. Vale la apena aclarar que cuando recreamos el cliente del webservice y aceptamos el certificado, se acepta solamente para el uso del IDE (para generar las clases del cliente del webservice), y no para la ejecucin del proyecto. Lo que hay que hacer entonces, es copiar el certificado del servidor, a un keystore de confianza de la aplicacin cliente. Para ello:

Desde una consola, estando en el directorio config dentro del directorio del dominio de GlassFish, exportar el certificado del servidor a un archivo (el alias del certificado creado por defecto en GlassFish es s1as):
keytool -keystore keystore.jks -exportcert -alias s1as -rfc -file certificadoServidor

Este comando pedir la contrasea del keystore, que sino fue cambiada debera ser "changeit", y luego exportar el certificado al archivo certificadoServidor.

Moverse a otro directorio, que ser donde se crearn los almacenes de claves para la aplicacin cliente; mover el archivo certificadoServidor a este lugar tambin. Desde all, crear un nuevo almacn de claves para el cliente (llamado almacenConfianza.jks), que ser el almacn en donde estn los certificados en que el cliente confa, importando el certificado del servidor:

keytool -import -v -alias s1as -file certificadoServidor -keystore almacenConfianza.jks

En este momento nos pedir una contrasea para el nuevo almacn, y luego de ingresarla y repetirla, preguntar si confiar o no en el certificado importado, a lo se le debe decir que si.

Ahora se debe configurar en el proyecto cliente el almacn de confianza, as como su contrasea, para ello: o Click derecho en el proyecto, "Properties" "Run". o En la opcin "VM Options" ingresar lo siguiente:
Djavax.net.ssl.trustStore="$DIR_ALMACENES/almacenConfianza.jk s" -Djavax.net.ssl.trustStorePassword="passwordDelAlmacen"

Siendo $DIR_ALMACENES el directorio en donde creamos el almacn para el cliente. En este momento ya se puede recompilar la aplicacin cliente, y ejecutarla, lo que debera funcionar sin problemas. Lo que est faltando ahora, son las configuraciones del certificado del cliente.

3.2 Certificado del cliente


En esta subseccin se indica como crear y configurar el certificado del cliente para autenticacin y autorizacin. Primero se muestra como configurar el webservice para requerir autenticacin de los clientes con certificados, comprobando que luego de esto, el cliente no puede acceder nuevamente al mismo. Luego de esto se indica como crear un nuevo almacn de claves para el cliente (configurndolo en el mismo), junto con un certificado, y como copiar este ltimo al almacn de confianza del servidor. Finalmente se describe como hacer para que la identificacin que contiene el certificado del cliente, tambin sirva para autorizar o no su acceso a determinados recursos. 3.2.1 Configuracin del webservice para autenticacin del cliente con certificado

Modificar el archivo sun-ejb-jar.xml dejndolo de la siguiente manera (las lneas en gris son las agregadas):
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE sun-ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 EJB 3.0//EN" "http://www.sun.com/software/appserver/dtds/sun-ejb-jar_3_0-0.dtd"> <sun-ejb-jar> <enterprise-beans> <ejb> <ejb-name>ServicioSimple</ejb-name> <webservice-endpoint> <port-component-name>ServicioSimple</port-component-name> <login-config> <auth-method>CLIENT-CERT</auth-method>

<realm>certificate</realm> </login-config> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </webservice-endpoint> </ejb> </enterprise-beans> </sun-ejb-jar>

Despus hacer nuevamente un deploy al webservice, y ejecutar el cliente. El error del lado del servidor es algo as como "CLIENT CERT authentication error for ServicioSimple".

3.2.2 Creacin y configuracin del certificado del cliente

Crear un nuevo almacn de claves (almacen.jks) con un nuevo certificado del cliente (de alias cliente). Desde una consola en $DIR_ALMACENES ejecutar:
keytool -genkey -alias cliente -keystore almacen.jks

El comando pregunta una clave para el nuevo almacn, y los datos para el nuevo certificado. Para el ejemplo se us:
o o o o o o

"first and last name": nombre "organizational unit": informatica "organization": org "City or Locality": ciudad "State or Province": estado "two-letter country code for this unit": np

Luego pide confirmacin de que el identificador (CN=nombre, OU=informatica, O=org, L=ciudad, ST=estado, C=np) es correcto, y pregunta por una contrasea para el certificado, la cual no se ingres tomndose la misma que el almacn de datos.

Configurar el nuevo almacn de datos en el proyecto cliente. En el mismo lugar que se agregaron los parmetros para el almacn de claves de confianza, agregar:
-Djavax.net.ssl.keyStore="$DIR_ALMACENES/almacen.jks" Djavax.net.ssl.keyStorePassword="passwordDelAlmacen"

Con el comando keytool exportar el certificado recin creado a un archivo:


keytool -keystore almacen.jks -exportcert -alias cliente -rfc -file certificadoCliente

Moverse en la consola hasta el directorio config dentro del dominio de GlassFish, junto con el archivo certificadoCliente. Importar este al almacn de claves de confianza del servidor GlassFish:

keytool -importcert -alias cliente -file certificadoCliente keystore cacerts.jks

Reiniciar el servidor GlassFish, porque no toma el nuevo certificado inmediatamente. En este momento, el cliente ya puede acceder nuevamente al webservice sin problemas, habiendo autenticacin bi-direccional con certificados.

3.2.3 Autorizacin Se lleg a un punto en que la autenticacin bi-direccional con certificados est resuelta. Es momento de mostrar como usar la identificacin del certificado cliente, tambin para la autorizacin de acceso al webservice. Para ello:

Definir el rol rolPrueba en el archivo sun-ejb-jar.xml. Quedara como sigue:


<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE sun-ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 EJB 3.0//EN" "http://www.sun.com/software/appserver/dtds/sun-ejb-jar_3_0-0.dtd"> <sun-ejb-jar> <security-role-mapping> <role-name>rolPrueba</role-name> </security-role-mapping> <enterprise-beans> <ejb> <ejb-name>ServicioSimple</ejb-name> <webservice-endpoint> <port-component-name>ServicioSimple</port-component-name> <login-config> <auth-method>CLIENT-CERT</auth-method> <realm>certificate</realm> </login-config> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </webservice-endpoint> </ejb> </enterprise-beans> </sun-ejb-jar>

Anotar el mtodo metodoSimple del webservice, para que solamente el rol rolPrueba tenga autorizacin. Esto se logra con la anotacin @RolesAllowed({"rolPrueba"}). Hacerle un deploy nuevamente al webservice. Si en este momento se ejecuta el cliente, da el error "Client not authorized for invocation of public java.lang.String prueba.ServicioSimple.metodoSimple (java.lang.String)". Lo que hay que hacer entonces, es asociar al identificador del certificado del cliente, con el rol rolPrueba. Esto se logra agregando una lnea al archivo sun-ejb-jar.xml, que quedara como sigue:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE sun-ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 EJB 3.0//EN" "http://www.sun.com/software/appserver/dtds/sun-ejb-jar_3_0-0.dtd">

<sun-ejb-jar> <security-role-mapping> <role-name>rolPrueba</role-name> <principal-name>CN=nombre, OU=informatica, O=org, L=ciudad, ST=estado, C=np</principal-name> </security-role-mapping> <enterprise-beans> <ejb> <ejb-name>ServicioSimple</ejb-name> <webservice-endpoint> <port-component-name>ServicioSimple</port-component-name> <login-config> <auth-method>CLIENT-CERT</auth-method> <realm>certificate</realm> </login-config> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </webservice-endpoint> </ejb> </enterprise-beans> </sun-ejb-jar>

Por supuesto, que se podran agregar tantos elementos principal-name como fuera necesario.

En este momento, y haciendo un deploy nuevamente del proyecto, se puede comprobar que el cliente nuevamente puede acceder sin problemas al webservice. Tambin se podra obtener la identificacin del certificado del cliente desde dentro del cdigo del webservice, para realizar determinadas tareas dependiendo de esta. Esto se logra obteniendo los objetos de clase java.security.Principal del "usuario" autenticado4, ya que uno de estos objetos corresponde al certificado. En la construccin de este ejemplo, solo queda asociado un objeto de clase Principal, que es el del certificado. En general se podran ver todos estos objetos de la siguiente forma:
Subject subject = (Subject) PolicyContext.getContext("javax.security.auth.Subject.container"); for (Principal p : subject.getPrincipals()) { System.out.println("Principal del usuario: '" + p.getName() + "'."); }

Probablemente si hubiese ms de un objeto Principal se podra identificar el que corresponde al certificado, por medio del mtodo getClass de esta clase.

Vous aimerez peut-être aussi