icono_twiter icono LinkedIn
Rubén Aguilera Díaz-Heredero

Consultor tecnológico de desarrollo de proyectos informáticos.

Ingeniero en Informática, especialidad en Ingeniería del Software

Puedes encontrarme en Autentia: Ofrecemos servicios de soporte a desarrollo, factoría y formación

Somos expertos en Java/J2EE

Ver todos los tutoriales del autor

Fecha de publicación del tutorial: 2011-06-21

Tutorial visitado 12.503 veces Descargar en PDF
CRUD con Spring MVC Portlet

Implementando SSO con CAS: ejemplo práctico

0. Índice de contenidos.

1. Entorno

Este tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil Mac Book Pro 17" (2,6 Ghz Intel Core i7, 8 GB DDR3)
  • Sistema Operativo: Mac OS X Snow Leopard 10.6.4
  • Spring MVC Portlet 3.0.4
  • Maven 2.2.1
  • Eclipse 3.6 (Helios) con M2Eclipse
  • CAS Server 3.4.2.1
  • CAS Client 3.2.0

2. Introducción

Ya vimos hace tiempo las bondades de CAS en el tutorial Introducción a CAS donde veíamos también como se instalaba y su funcionamiento más básico.

En esta oportunidad vamos a ver cómo podemos securizar dos aplicaciones web distintas con CAS, permitiendo que al logarnos en una el acceso a la otra no solicite nuevamente las credenciales.

3. Creación de las aplicaciones web a securizar

Lo primero que vamos a hacer es crear dos aplicaciones web muy sencillitas gracias a la ayuda de Maven. Para ello como de costumbre escribimos en un terminal mvn archetype:generate, seleccionamos el arquetipo web (TIP: suele estar 3 más abajo del de por defecto, es decir, si por defecto sale el 109 pues suele ser el 112, pero mejor comprobadlo) e introducimos los siguientes datos para la primera aplicación:

  • Versión del arquetipo: 1.0
  • groupId: com.autentia
  • artifactId: cas-example-1
  • versión: 1.0-SNAPSHOT
  • package: com.autentia

Y lo mismo para la segunda pero cambiando el artifactId por cas-example-2.

Ahora importamos los proyectos a Eclipse gracias al plugin de m2Eclipse, y simplemente editamos el fichero index.jsp que se crea por defecto, para poner un texto que diga "Esto es cas-example-1" en el caso de la primera aplicación y "Esto es cas-example-2" en el caso de la segunda aplicación, a fin de distinguirlos cuando los despleguemos. Además cada uno de ellos va a llevar una sentencia que recupera el usuario logado de la request, este es el contenido para el primer ejemplo:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Cas Example 1
</head>
<body>

<p>Esto es el ejemplo de CAS número 1</p>

<p>Este es el usuario logado: <%=request.getRemoteUser() %></p>

</body>
</html>

Venga ahora vosotros el ejemplo 2.

4. Configuración del servidor de CAS para permitir el SSO

Una de las primeras cosas que deben quedar claro en la implementación de un SSO con CAS es que sólo puede funcionar a través de un canal seguro, es decir, que tendremos que configurar nuestro Tomcat para habilitar el protocolo HTTPS.

Para ello antes de nada necesitamos un certificado. Para este tutorial nos valdrá con un "dummy" el cual vamos a crear abriendo un terminal y siguiendo los siguientes pasos:

  1. Situarnos en el directorio JAVA_HOME/bin

  2. Generar la key de nuestro certificado, para ello ejecutar: sudo keytool -genkey -alias tomcat -keyalg RSA

    NOTA: La keypass changeit es la de por defecto para Mac

    Esto hace que el sistema pregunta una serie de datos:

    • Enter keystore password: changeit (Válido para Mac)
    • What is your first and last name?: raguilera.com (Aquí lo que pide realmente es un nombre de dominio, no pongais vuestro nombre y dos apellidos porque va a ser un dominio muy largo ;-). Tampoco es aconsejable poner localhost, siempre podéis mapear un nombre de dominio con la dirección 127.0.0.1 en el fichero /etc/hosts de vuestras máquinas).
    • What is the name of your organizational unit?: Desarrollo (Se refiere al departamento)
    • What is the name of your organization? Autentia (Se refiere al nombre de la empresa)
    • What is the name of your City or Locality?: Alcalá de Henares (Capital del imperio español cuando no se ponía el sol)
    • What is the name of your State or Province?: Madrid
    • What is the two-letter country code for this unit?: ES
    • En este momento aparece un resumen con los datos introducidos al que tendremos que responder afirmativamente para que la creación de la key tenga éxito.
  3. Exportar el certificado a un fichero, para ello ejecutamos: sudo keytool -export -alias tomcat -file server_cas.crt. Nos pedirá la contraseña que es changeit y si todo es correcto nos responderá afirmativamente a la creación del fichero.

  4. Importamos el certificado al almacén de certificados de Java, asegurándonos de que estamos situados en la versión de Java que está utilizando nuestro Tomcat. Para ello ejecutamos: sudo keytool -import -alias tomcat -file server_cas.crt -keystore ../lib/security/cacerts. Nos pregunta si queremos confiar en este certificado, le decimos que si y ya está.

El siguiente paso es editar el fichero TOMCAT_HOME/conf/server.xml para descomentar las líneas que se refieren al HTTPS y dejarlas de esta forma:


Lo más importante de esta configuración es definir el puerto y la localización del fichero .keystore, que en general se crea como un archivo oculto dentro de la carpeta del usuario.

5. Configuración de las aplicaciones web

La única configuración que requiere CAS es editar el fichero web.xml para incluir los siguientes filtros:


		CAS Authentication Filter
		org.jasig.cas.client.authentication.AuthenticationFilter
		
			casServerLoginUrl
			https://raguilera.com:8443/cas/login
		
		
			service
			http://raguilera.com:8080/cas-example-1
		
	

	
		CAS Validation Filter
		org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter
		
			casServerUrlPrefix
			https://raguilera.com:8443/cas/
		
		
			service
			http://raguilera.com:8080/cas-example-1
		
	

	
		CAS HttpServletRequest Wrapper Filter
		org.jasig.cas.client.util.HttpServletRequestWrapperFilter
	

	
		CAS Authentication Filter
		/*
	

	
		CAS Validation Filter
		/*
	

	
		CAS HttpServletRequest Wrapper Filter
		/*
	

Esta es la explicación de cada uno de los filtros:

  • CAS Authentication Filter: se encarga de detectar si el usuario está logado, en caso contrario redirecciona el flujo a la URL especificada en el parámetro "casServerLoginUrl". En el parámetro "service" le indicamos la URL donde queremos redireccionar el flujo una vez el usuario haya sido correctamente autenticado por CAS. En resumen, este filtro le asigna un ticket al usuario correctamente logado.
  • CAS Validation Filter: se encarga de validar que el ticket que aporta el usuario es válido es decir que lo tiene asignado y no ha expirado. Para ello requiere que especifiquemos el sufijo por el que empieza nuestro CAS en el parámetro "casServerUrlPrefix" y le indiquemos el mismo "service" que en la autenticación si no queremos que nos de un error de que el ticket proporcionado no corresponde con el servicio.
  • CAS HttpServletRequest Wrapper Filter: una vez el ticket es validado este filtro se encarga de "actualizar" la request con los datos de usuario logado para que podamos recuperarlos interrogando a la request con la sentencia request.getRemoteUser()

Cada aplicación tiene que hacer referencia a las dependencias cas-client-core-3.2.0.jar y commons-logging-1.1.1.jar o si no introducidlas dentro de la carpeta TOMCAT_HOME/lib.

6. Probando el resultado

En mi caso las dos aplicaciones van a correr en el mismo Tomcat que el servidor de CAS, por lo que para probar el resultado tenemos que desplegar las dos aplicaciones en este servidor y arrancarlo.

Lo siguiente será abrir un navegador y poner la siguiente URL: http://raguilera.com:8080/cas-example-1. Tendremos que ver como haciendo esto el navegador nos redirecciona a la URL de login de CAS para que introduzcamos unas credenciales correctas, por defecto que el usuario y la password sean iguales.

Cuando nos hayamos logado correctamente veremos que el navegador nos redirecciona a la URL que le hemos indicado en "service" y que nos muestra el contenido y el nombre del usuario que está logado.

Ahora en el mismo navegador (o en otro pestaña del mismo navegador) abrimos la URL: http://raguilera.com:8080/cas-example-2 y tendremos que ver que sin logarnos aparece el contenido con el nombre del usuario logado.

Podéis probar a hacerlo al revés, pero no sin antes eliminar la cache y las cookies del navegador.

7. Conclusiones

A mi este tipo de herramientas "satelites" me encantan, te permiten modularizar tu aplicación sin tener que cambiar ni una línea de código sólo a través de filtros o listener de Tomcat. En este caso esta herramienta nos resuelve el problema concreto de tener que implementar un SSO para todas nuestras aplicaciones, e incluso centralizar la seguridad tanto de aplicaciones web como de aplicaciones de escritorio. Ya os digo yo que los mayores problemas para seguir este tutorial los vais a encontrar a la hora de crear el certificado.

Cualquier duda o sugerencia en la zona de comentarios.

Saludos.

A continuación puedes evaluarlo:

Regístrate para evaluarlo

Por favor, vota +1 o compártelo si te pareció interesante

Share |
Anímate y coméntanos lo que pienses sobre este TUTORIAL:

Fecha publicación: 2014-10-25-13:05:01

Autor: js

Hola, estoy intentando utilitza SSO con CAS utilizando nginx como reverse proxy, pero no es posible hacer lo funcionar. Hay poco o ninguna información al respecto de como utilitzar cas con nginx. Cualquier información al respecto sera de utilidad, la que la verdad despues de un sin fin de intentos no hemos encontrado la solución.

Muchisimas Gracias.

Fecha publicación: 2014-01-17-17:38:08

Autor: crisocean

Hola Vega,

la solucion a tu problema esta en
http://bluefoot.info/howtos/how-to-avoid-java-security-cert-certificateexception-no-name-matching-localhost-found/

luego posiblemente te saldra otro error que podras solucionar con lo siguiente:

http://www.mkyong.com/webservices/jax-ws/suncertpathbuilderexception-unable-to-find-valid-certification-path-to-requested-target/

un saludo.

Fecha publicación: 2013-10-20-23:58:09

Autor: rubenagui

Hola Caromeva,

Ese error hace pensar que el puerto 8443 de tu Tomcat no está habilitado. Comprueba la configuración del server.xml y verifica que la línea referente al puerto SSL está habilitada.

Espero haberte sido de ayuda.

Saludos

Fecha publicación: 2013-10-19-00:42:48

Autor: Caromeva

Hola Ruben,

He realizado el tutorial, no tengo errores, sin embargo cuando ingreso a la siguiente URL:

http://localhost:8080/CasWebAppUno

que es una de las dos aplicaciones web del ejemplo, efectivamente veo un cambio en la URL apuntando a :

https://localhost:8443/cas/login?service=http%3A%2F%2Flocalhost%3A8080%2FCasWebAppUno

He indica lo siguiente:

Firefox no puede establecer una conexión con el servidor en localhost:8443.

Me puedes ayudar para determinar cual es el problema?.

Muchas gracias.

Saludos.

Fecha publicación: 2013-09-25-10:40:30

Autor: Kamigui

Buenas, He montado un cas en suse que se valida contra un DA en windows 2008, permitiendo al usuario que está en el directorio activo acceder a la aplicacion, la duda que tengo es cuando hay un apache por delante del tomcat con otra url, cas no valida al usuario, hay alguna manera de poder hacerlo?
Muchas Gracias.

Un saludo

Fecha publicación: 2013-05-29-00:42:46

Autor: crueda

Muchas gracias Ruben,

Necesito tu ayuda, estoy montando un CAS para un desarrollo que estoy haciendo.
Despues de seguir tus pasos me sale esto en el browser:


An error occurred during a connection to localhost:8080.

SSL received a record that exceeded the maximum permissible length.

(Error code: ssl_error_rx_record_too_long)

Fecha publicación: 2013-04-24-18:35:50

Autor: Vega

Hola,

Al validarme en la página del CAS, al redirigirme a la aplicación web sale el siguiente error:

type Informe de Excepción

mensaje javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching localhost found

descripción El servidor encontró un error interno que hizo que no pudiera rellenar este requerimiento.

excepción

java.lang.RuntimeException: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching localhost found
org.jasig.cas.client.util.CommonUtils.getResponseFromServer(CommonUtils.java:341)
org.jasig.cas.client.util.CommonUtils.getResponseFromServer(CommonUtils.java:305)
org.jasig.cas.client.validation.AbstractCasProtocolUrlBasedTicketValidator.retrieveResponseFromServer(AbstractCasProtocolUrlBasedTicketValidator.java:50)
org.jasig.cas.client.validation.AbstractUrlBasedTicketValidator.validate(AbstractUrlBasedTicketValidator.java:207)
org.jasig.cas.client.validation.AbstractTicketValidationFilter.doFilter(AbstractTicketValidationFilter.java:169)
org.jasig.cas.client.authentication.AuthenticationFilter.doFilter(AuthenticationFilter.java:116)

¿Por qué puede generarse este error?

Saludos y gracias,

P.D.: Felicidades por la página.

Fecha publicación: 2012-07-19-16:29:31

Autor: titobundy

Hola,
Estoy siguiendo el ejemplo descrito pero al levantar el tomcat me da un error, tengo la siguiente configuracion del server.xml

<Connector port="8443" protocol="org.apache.coyote.Http11NioProtocol" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="C:UsersHector.keystore"
keystorePass="changeit"
/>

Y el error al levantar el tomcat es

19-07-2012 10:27:51 AM org.apache.catalina.core.StandardService start
GRAVE: Failed to start connector [Connector[org.apache.coyote.Http11NioProtocol-
8443]]
LifecycleException: service.getName(): "Catalina"; Fall¾ el arranque del manej
ador de protocolo: java.lang.NullPointerException
at org.apache.catalina.connector.Connector.start(Connector.java:1129)
at org.apache.catalina.core.StandardService.start(StandardService.java:5
40)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:754
)
at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
19-07-2012 10:27:51 AM org.apache.coyote.ajp.AjpAprProtocol start

¿Alguna ayuda por fa? Estoy usando apache-tomcat-6.0.35 en Win 7 64bits