CAS REST: Cómo logarnos en CAS sin ir a la pantalla de login por defecto

4
16358

CAS REST: Cómo logarnos en CAS sin ir a la pantalla de login por defecto

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
  • Maven 2.2.1
  • Eclipse 3.6 (Helios) con M2Eclipse
  • CAS Server 3.4.2.1

2. Introducción

En ocasiones nuestros clientes nos piden que implementemos un SSO para integrar sus aplicaciones en un único punto de entrada. Para este caso siempre tenemos la misma respuesta, hacerlo con CAS, pero la mayor parte de ellos ven «rara» la redirección que hay que hacer para logarte en la página de login que CAS trae por defecto.

Lo primero que le proponemos es customizar la apariencia de esta página principal para integrarla con el aspecto de su portal como ya vimos en este tutorial: CAS: Personalización de la interfaz

Pero en ocasiones esto no es suficiente para el cliente porque quiere utilizar una página de login propia, por ejemplo, un formulario que se muestra en la cabecera de todas las páginas del portal, y que por tanto no cabe redirección a ninguna otra página.

Pues bien en este tutorial vamos a darle solución a esta problemática utilizando el API de REST que nos ofrece CAS y que presentamos junto con un ejemplo, a continuación.

Antes de continuar con este tutorial se recomienda haber leído al menos el tutorial Introducción a CAS y para seguir el ejemplo práctico antes tendrán que completar este otro tutorial: Implementando SSO con CAS: ejemplo práctico

3. Vamos al lío

Lo primero va a ser crear un proyecto web con Maven o aprovechar uno que ya tengáis creado. Vamos a añadirle las siguientes dependencias:

  
    org.jasig.cas  
    cas-server-core  
    3.4.2.1  
  
  
    org.jasig.cas  
    cas-server-integration-restlet  
    3.4.2.1  
    jar  
  
  
    commons-httpclient  
    commons-httpclient  
    3.1  

A fin de poder acceder al servicio de RESTlet de CAS necesitamos habilitarlo, para ello vamos a editar el fichero CAS_WEBAPP_HOME/WEB-INF/web.xml para añadir el servlet que nos proporciona el servicio:

  
    restlet  
    com.noelios.restlet.ext.spring.RestletFrameworkServlet  
    1  
  
  
  
    restlet  
    /v1/*  

Además de este servlet tenemos que añadir a nuestro servidor de CAS (CAS_WEBAPP_HOME/WEB-INF/lib) las siguientes dependencias:

  • cas-server-integration-restlet-3.4.2.1.jar
  • com.noelios.restlet-1.1.1.jar
  • com.noelios.restlet.ext.servlet-1.1.1.jar
  • com.noelios.restlet.ext.spring-1.1.1.jar
  • org.restlet.ext.spring-1.1.1.jar
  • org.restlet-1.1.1.jar
  • cglib-2.2.jar

La mayoría de estas librerías se pueden encontrar en la distribución de CAS.

Ahora la idea es crear nuestro propio formulario de login para introducir las credenciales del usuario, comprobar la veracidad de esas credenciales con el validador de CAS y crear la cookie necesaria para que el resto de aplicaciones del portal se den cuenta a través de Spring Security que ya existe la cookie de CAS y que por tanto ese usuario ya está validado en todas las aplicaciones en las que tenga permiso

Vamos a crear un formulario de login muy sencillo con un servlet que es el que va a recibir las credenciales y llamar a CAS a través del servicio REST.

Para crear el formulario simplemente editamos el fichero index.jsp de nuestro proyecto (o el que consideremos oportuno) y creamos el formulario con el siguiente contenido:

Usuario:

Contraseña:

Usuario:

Contraseña:

Ahora vamos a registrar el servlet que va a recibir las credenciales y se va a encargar de realizar la lógica.

  
    LoginServlet  
    LoginServlet  
      
    com.autentia.servlets.LoginServlet  
   
   
    LoginServlet  
    /login  
  

El siguiente paso es crear la clase LoginServlet con el siguiente contenido.


package com.autentia.servlets;

import java.io.IOException;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.PostMethod;

import com.autentia.Client;

/**
 * Servlet implementation class LoginServlet
 */
public class LoginServlet extends HttpServlet {
	
	private static final long serialVersionUID = 1L;
	
	private static final Logger LOG = Logger.getLogger(LoginServlet.class.getName());

	public LoginServlet() {
		super();
	}

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		doPost(request, response);
	}

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		String usuario = request.getParameter("user");
		String pass = request.getParameter("password");

		LOG.info("USUARIO:  " + usuario + " -- CONTRASEÑA: " + pass);

		String ticketGrantingTicket = getTicketGrantingTicket("https://raguilera.com:8443/cas/v1/tickets", usuario, pass);

		LOG.info("Este es el ticket que recupero: " + ticketGrantingTicket);

		Cookie cookie = new Cookie("CASTGC", ticketGrantingTicket);
		cookie.setSecure(false);
		cookie.setPath("/cas");
		cookie.setMaxAge(-1);

		response.addCookie(cookie);
	}

	private String getTicketGrantingTicket(final String server,
			final String username, final String password) {
		final HttpClient client = new HttpClient();

		final PostMethod post = new PostMethod(server);

		post.setRequestBody(new NameValuePair[] {
				new NameValuePair("username", username),
				new NameValuePair("password", password) });

		try {
			client.executeMethod(post);

			final String response = post.getResponseBodyAsString();

			switch (post.getStatusCode()) {
			case 201: {
				final Matcher matcher = Pattern.compile(".*action=\".*/(.*?)\".*").matcher(response);

				if (matcher.matches()){
					return matcher.group(1);
				}
				LOG.info("Successful ticket granting request, but no ticket found!");
				LOG.info("Response (1k): " + response.substring(0, Math.min(1024, response.length())));
				break;
			}

			default:
				LOG.info("Invalid response code (" + post.getStatusCode() + ") from CAS server!");
				LOG.info("Response (1k): " + response.substring(0,Math.min(1024, response.length())));
				break;
			}
		} catch (final IOException e) {
			LOG.info(e.getMessage());
		} finally {
			post.releaseConnection();
		}

		return null;
	}

}

El servlet recupera las credenciales que le proporciona el usuario y a través de una llamada POST con la librería HttpClient, llama al servicio web de CAS que se encarga de la gestión de los tickets y que se encuentra en la url «https://raguilera.com:8443/cas/v1/tickets», en caso de que las credenciales sean válidas, devuelve un ticket válido y en caso contrario null.

Con este ticket creamos la cookie de CAS que es consultada por todas las aplicaciones gestionadas y determina si el usuario ya ha realizado el login para no volver a pedírselo.

4. Lo probamos

Para probar esta funcionalidad lo mejor que podemos hacer es utilizar una extensión de Firebug llamada Firecookie que permite visualizar las cookies del navegador. La url es: https://addons.mozilla.org/es/firefox/

Arrancamos el servidor con la aplicación desplegada y accedemos a la url http://raguilera.com:8080/cas-restlet/ con lo que se mostrará el siguiente formulario:

Introducimos las credenciales y si son correctas deberemos que la cookie se ha creado con un contenido similar a este.

5. Conclusiones

Como veis hay solución para esta situación más que satisfactoria gracias a que trabajamos con una herramienta que expone su lógica a través de servicios web. Este mismo mecanismo se puede utilizar para securizar las aplicaciones de escritorio de nuestra empresa y poder utilizar el mismo sistema de autenticación que el resto de aplicaciones.

Cualquier duda o sugerencia en la zona de comentarios.

Saludos.

4 COMENTARIOS

  1. Ey! Rubén, muy bueno el tutorial, sin embargo tengo algunas dudas que espero me pueda ayuda. Mis dudas van sobre el logout y como obtener el usuario remoto… chequeando la wiki http://goo.gl/gu5i9 no entiendo el apartado #Logout of the Service# si tiene algún ejemplo o como se pueda implementar este servicio me seria de gran ayuda Y como obtener el usuario. El log que genera el servidor cas cuando se hace getServiceTicket dice el nombre de logueo pero no se como retornarlo. Ah y por ultimo, aunque envio pass y user distintos me genera una ticket, si implemento lo de tu otro tutorial CASValidadorPersonalizado debería servir?

    Gracias de antemano…

  2. Hola

    Están excelentes los tutoriales sobre CAS, Tengo una duda, la licencia para la utilización de esta solución es free o tiene licencia comercial y hay que pagar para ser utilizado.

    Muchas Gracias.

  3. Hola, muy buen tutorial, me ha gustado la claridad de explicación. Tengo un problema en el que no sé si puedas ayudarme. Necesito acceder a una aplicación que tiene SSO con CAS. Gracias a tu tutorial pude configurar los RESTLETS en CAS e hice un código Java con el que ya obtengo el TicketGrantingTicket y el ServiceTicket. Pero lo que a mi me interesa es recuperar el contenido html del servicio que quiero invocar. Si ya tengo el ServiceTicket que puedo hacer? Todo debe ser a través de código, ya que no es una aplicación que tenga interacción directa con el usuario. Estoy usando HttpClient y PostMethod. Espero puedas ayudarme. Gracias.

  4. Hola,
    me parece excelente, pero tengo la misma pregunta que ivan2car, una vez que tenemos tanto el TGC como el ST ¿como recuperamos la información del usuario que está logado? he intentado varios códigos y no he sido capaz.

    Gracias!

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad