lunes, 6 de septiembre de 2010

Spring Security y SSO

RESUMEN:
Configuraremos una aplicación web para añadirle seguridad  usando Spring Security.
Posteriormente configuraremos la aplicación para autenticarnos mediante Single Sign On ( Usando el servidor CAS de jasig )

1. - Añadimos seguridad a una aplicación web ( sin CAS )


Primero descargaremos la aplicación demo de Loom. que nos servirá de base para nuestro ejemplo:

Accedemos a la página de descargas  y nos descargamos la demo:

$ wget http://downloads.sourceforge.net/project/loom/loom/2.1/loomdemo.war

Una vez hayamos descargado el fichero, necesitamos expandirlo para poder modificar la aplicación.

$ mkdir loomdemo
$ cd loomdemo
$ jar xvf ../loomdemo.war 


La aplicación loomdemo está basada en Spring y no viene con seguridad implementada.
Necesitaremos descargar y añadir las librerías relativas a Spring Security


$ cd WEB-INF/lib
$ wget http://www.jarvana.com/jarvana/archive-details/org/springframework/security/spring-security-acl/3.0.3.RELEASE/spring-security-acl-3.0.3.RELEASE.jar http://www.jarvana.com/jarvana/archive-details/org/springframework/security/spring-security-config/3.0.3.RELEASE/spring-security-config-3.0.3.RELEASE.jar http://www.jarvana.com/jarvana/archive-details/org/springframework/security/spring-security-core/3.0.3.RELEASE/spring-security-core-3.0.3.RELEASE.jar http://www.jarvana.com/jarvana/archive-details/org/springframework/security/spring-security-taglibs/3.0.3.RELEASE/spring-security-taglibs-3.0.3.RELEASE.jar http://www.jarvana.com/jarvana/archive-details/org/springframework/security/spring-security-web/3.0.3.RELEASE/spring-security-web-3.0.3.RELEASE.jar

El siguiente paso es modificar el fichero web.xml de la aplicación para añadirle seguirdad. Editamos el fichero WEB-INF/web.xml y añadimos al parámetro contextConfigLocation otro fichero de configuración de Spring ( que crearemos a continuación ) spring-security-config.xml

<context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>
   classpath:spring-config.xml
   classpath:spring-security-config.xml
 </param-value>
</context-param>

No nos debemos de olvidar de añadir también el filtro de seguridad Spring en el web.xml
<filter>
 <filter-name>springSecurityFilterChain</filter-name>
 <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
 <filter-name>springSecurityFilterChain</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>



Crearemos primero un fichero de configuración de seguridad básico, para comprobar que todo funciona correctamente. Aseguraremos los accesos a /mortgages/create con el rol ROLE_USER y a /support/** con el rol ROLE_ADMIN. De paso solicitaremos que cualquier acceso se haga a través de https

$ vim WEB-INF/classes/spring-security-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:security="http://www.springframework.org/schema/security"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="
      http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      http://www.springframework.org/schema/security
      http://www.springframework.org/schema/security/spring-security-3.0.xsd"
   default-autowire="byName">

 <security:http auto-config="true" path-type="ant">
   <security:intercept-url pattern="/mortgages/create" access="ROLE_USER"/>
   <security:intercept-url pattern="/support/**" access="ROLE_ADMIN"/>
   <security:intercept-url pattern="/**" requires-channel="https" />
   <security:logout logout-url="/logout" />
 </security:http>

 <security:authentication-manager>
   <security:authentication-provider>
     <security:user-service properties="/WEB-INF/user.properties"/>
   </security:authentication-provider>
 </security:authentication-manager>

</beans>

Los usuarios, roles y contraseñas los especificamos en el fichero user.properties
$ vim WEB-INF/user.properties

admin=admin,ROLE_ADMIN,ROLE_USER
user=user,ROLE_USER

Si todo ha ido correctamente, podemos desplegar la aplicación en Tomcat (copiamos la carpeta loomdemo a $CATALINA_HOME/webapps)

Una vez arrancado el Tomcat, podemos acceder a la aplicación : http://localhost:8080/loomdemo. Lo primero que vemos es que, tal y como le hemos especificado al requerir un canal seguro ( 8443 a través de https), nos hace automáticamente una redirección:



El siguiente paso es comprobar que funciona la seguridad. Para ello intentamos acceder a una URL protegida https://localhost:8443/loomdemo/mortgages/create Si todo está correcto, nos aparecerá una ventana solicitándonos el usuario y la contraseña:


Especificando un usuario definido previamente en el fichero user.properites (admin/admin) obtendremos el acceso:



Para poder hacer logout, añadiremos al menú lateral un enlace en donde además mostraremos el username.

Modificamos el fichero leftColumn.tag que se encuentra en WEB-INF/tags:

$ vim WEB-INF/tags/leftColumn.tag

<authz:authorize ifAnyGranted="ROLE_ADMIN,ROLE_USER">         
  Logged as :  <authz:authentication property="principal.username" />
  <ul>
    <li><l:url href="/logout" >logout</l:url></li>
  </ul>
</authz:authorize>

2. - Añadimos SSO - Autentificación por CAS a la aplicación:


El proceso para validar usuarios usando CAS, requiere de un servidor CAS, que es el encargado de comprobar las credenciales que aporta el usuario.




Para nuestro ejemplo, descargamos el servidor CAS de la página de Jasig y creamos el war usando maven

$ wget http://downloads.jasig.org/cas/cas-server-3.4.2.1-release.zip
$ unzip cas-server-3.4.2.1-release.zip
$ cd cas-server-3.4.2.1/cas-server-webapp/
$ mvn package
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 42 seconds
[INFO] Finished at: Mon Sep 06 10:39:11 WEST 2010
[INFO] Final Memory: 32M/58M
[INFO] ------------------------------------------------------------------------

Una vez creado el war, lo desplegamos en Tomcat:
$ target/cas.war $CATALINA_HOME/webapp/.

Comprobamos que se haya desplegado correctamente accediendo a http://localhost:8080/cas



Este servidor es una demo que autentifica a cualquier usuario siempre que el password sea igual al username. Introducimos admin/admin y validamos:


(*) Para hacer logout, accedemos a http://localhost:8080/cas/logout


En este punto ya tenemos arrancada nuestra aplicación a la que le hemos añadido seguridad y un servidor CAS. El siguiente paso es configurar nuestra aplicación para que se autentifique con el servidor.

Para no modificar el fichero anterior, creamos un fichero de configuración para la autentificación mediante CAS: spring-security-config-CAS.xml :

Nota: En lugar de usar localhost usaremos el nombre del servidor; en este caso myserver

$ vim WEB-INF/classes/spring-security-config-CAS.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:sec="http://www.springframework.org/schema/security"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/security
       http://www.springframework.org/schema/security/spring-security-3.0.xsd">
 
<sec:http entry-point-ref="casEntryPoint" auto-config="true" path-type="ant">
  <sec:custom-filter before="CAS_FILTER" ref="casSingleSignOutFilter"/>
  <sec:custom-filter after="CAS_FILTER"  ref="casFilter"/>
  <sec:intercept-url pattern="/mortgages/create" access="ROLE_USER"/>
  <sec:intercept-url pattern="/support/**" access="ROLE_ADMIN"/>
  <sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
  <sec:logout logout-success-url="https://myserver:8443/cas/logout" invalidate-session="true" logout-url="/logout" />
</sec:http>
 
<!-- which application am I authenticating -->
<bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
    <property name="service" value="https://myserver:8443/loomdemo/j_spring_cas_security_check"/>
    <property name="sendRenew" value="false"/>
</bean>
    
<!-- where do I go when I need authentication -->
<bean id="casEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
    <property name="loginUrl" value="https://myserver:8443/cas/login"/>
    <property name="serviceProperties" ref="serviceProperties"/>
</bean>
 
<bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder"/>
<bean id="casSingleSignOutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter" />
<bean id="casFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter">
    <property name="authenticationManager" ref="authenticationManager"/>
</bean>
    
<sec:authentication-manager alias="authenticationManager">
    <sec:authentication-provider ref="casAuthenticationProvider" />
</sec:authentication-manager>
    
    
<bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
  <property name="userDetailsService" ref="userServices"/>
  <property name="serviceProperties" ref="serviceProperties"/>
  <property name="ticketValidator">
    <bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
       <constructor-arg index="0" value="https://myserver:8443/cas"/>
    </bean>
  </property>
  <property name="key" value="my_password_for_this_auth_provider_only"/>
</bean>
   
<sec:user-service properties="/WEB-INF/user.properties" id="userServices"/>

</beans>

Ya solo nos queda especificar este fichero en lugar del anterior en el web.xml
<context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>
   classpath:spring-config.xml
   classpath:spring-security-config-CAS.xml
 </param-value>
</context-param>

Listo !!! .... ahora cuando intentemos acceder a una URL protegida, en lugar de redirigirnos a la antigua página de Login :


Nos redirigirá al servidor CAS :

3 comentarios:

  1. buenos días,
    muy bien explicado :D, pero tengo una duda. Seria posible saltarse la pantalla de login del CAS pasando el usuario y la contraseña por parámetro? estoy pensando en una aplicación que tenga un usuario invitado por ejemplo, que no tenga que identificarse para entrar

    ResponderEliminar
  2. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  3. Hola! soy nueva en cas, en estos momentos hago mi tesis de grado en función de esto y necesito ayuda urgentemente! Bien, ya tengo Cas3.5.2 en tomcat7 (SO linux mint), una estructura de directorio con phpLDAPadmin, una aplicación en php y lo ultimo que hice fue instalar por consola phpCAS y la versión que está en los repositorios es la 1.3.2 (no tiene el example_simple.php). Tengo muchas dudas como ¿los archivos a incluir en la app son todos los que trajo la instalación de phpCAS? ¿que archivos debo modificar y cual es la modificacion exacta?. Tambien habia descargado php-cas1.3.4.tgz de https://developer.jasig.org/cas-clients/php/current/ (y este si trajo example_simple.php) ahora estoy confundida, o sea no se exactamente cuales son los archivos que deben incluirse en la aplicacion que se quiere proteger y tampoco se en que parte de la aplicacion se almacenan estos archivos. Necesito ayuda, necesito que funcione lo antes posible.

    Gracias!

    ResponderEliminar