lunes, 21 de octubre de 2013

Postgresql y Sprin Security

Decidí migrar algunas aplicaciones que tengo en base a spring framework 3.1.4 y MySQL hacia PostgreSQL como base de datos, entre las dificultades que encontré es que los manuales de Spring no son muy claro respecto a la migración a una base de datos en particular y por otro lado (sin ser experto en PostgreSQL), no hay mucha informacion realmente util en donde te entreguen los "tips" en la web.

Si necesitan saber de como montar una aplicacion con Spring Framework + Security favor vean este articulo   En caso contrario manos a la obra:

Esquemas de base de datos Spring Security para PostgreSQL

primero es necesario que creen la base de datos en post, en mi caso utilice pgAdmin III para hacerlo gráficamente.

Crear base de datos "secframework"  <-- o el nombre que prefieran.


 CREATE DATABASE secframework   WITH OWNER = secuser        ENCODING = 'UTF8'        TABLESPACE = pg_default        LC_COLLATE = 'en_US.UTF-8'        LC_CTYPE = 'en_US.UTF-8'        CONNECTION LIMIT = -1;

notar que el dueño del a base de datos es un 'secuser' , en mi caso cree un usuario llamado 'secuser', esto lo pueden reemplazar por el usuario que quiera.

para crear el usuario pueden usar algo como


CREATE ROLE secuser LOGIN   ENCRYPTED PASSWORD 'md5e24a75ddb6858a5f53aa2f5a169a2f28'   NOSUPERUSER INHERIT NOCREATEDB NOCREATEROLE NOREPLICATION;

esto creara un usuario sin mayores privilegios y con el password 'secuser'

luego crear un esquema


CREATE SCHEMA sec; ALTER SCHEMA sec OWNER TO secuser; CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';

luego de que este creado el esquema seria bueno ejecutar las siguientes instrucciones:


ALTER SCHEMA sec OWNER TO secuser; ALTER ROLE secuser   SET search_path = sec; SET search_path = sec, pg_catalog;

con esto le estamos diciendo al postgresql que los objetos deben ser buscados dentro del esquema 'sec' y así podemos evitar el tener que poner como prefijo el nombre del esquema a las tablas, en otras palabra ahora se pueden ejecutar querys como  'select * from user' en vez de 'select * from sec.user'

Esquemas Spring Security.

se deben crear las siguientes tablas (esta el modelo completo, aunque en la practica basta con la tabla de user y authorities)

Tablas Usuarios


 create table users(       username varchar(50) not null primary key,       password varchar(50) not null,       enabled boolean not null);   create table authorities (       username varchar(50) not null,       authority varchar(50) not null,       constraint fk_authorities_users foreign key(username) references users(username));       create unique index ix_auth_username on authorities (username,authority);
Tablas Grupos

create table groups (

  id bigserial  primary key,

  group_name varchar_ignorecase(50) not null);



create table group_authorities (

  group_id bigint not null,

  authority varchar(50) not null,

  constraint fk_group_authorities_group foreign key(group_id) references groups(id));



create table group_members (

  id bigserial primary key,

  username varchar(50) not null,

  group_id bigint not null,

  constraint fk_group_members_group foreign key(group_id) references groups(id));


Tabla de persistencia para el login

create table persistent_logins (

  username varchar(64) not null,

  series varchar(64) primary key,

  token varchar(64) not null,

  last_used timestamp not null);


 Tablas para el ACL

create table acl_sid(

  id bigserial not null primary key,

  principal boolean not null,

  sid varchar(100) not null,

  constraint unique_uk_1 unique(sid,principal));



create table acl_class(

  id bigserial not null primary key,

  class varchar(100) not null,

  constraint unique_uk_2 unique(class));



create table acl_object_identity(

  id bigserial primary key,

  object_id_class bigint not null,

  object_id_identity bigint not null,

  parent_object bigint,

  owner_sid bigint,

  entries_inheriting boolean not null,

  constraint unique_uk_3 unique(object_id_class,object_id_identity),

  constraint foreign_fk_1 foreign key(parent_object) references acl_object_identity(id),

  constraint foreign_fk_2 foreign key(object_id_class) references acl_class(id),

  constraint foreign_fk_3 foreign key(owner_sid) references acl_sid(id));



create table acl_entry(

  id bigserial primary key,

  acl_object_identity bigint not null,

  ace_order int not null,

  sid bigint not null,

  mask integer not null,

  granting boolean not null,

  audit_success boolean not null,

  audit_failure boolean not null,

  constraint unique_uk_4 unique(acl_object_identity,ace_order),

  constraint foreign_fk_4 foreign key(acl_object_identity)

      references acl_object_identity(id),

  constraint foreign_fk_5 foreign key(sid) references acl_sid(id));



luego para efectos de prueba se puede ingresar la siguiente data

INSERT INTO authorities VALUES ('admin', 'ROLE_ADMIN');

INSERT INTO authorities VALUES ('admin', 'ROLE_USER');

INSERT INTO authorities VALUES ('user', 'ROLE_USER');



INSERT INTO users VALUES ('admin', '21232f297a57a5a743894a0e4a801fc3', true);

INSERT INTO users VALUES ('user', 'ee11cbb19052e40b07aac0ca060c23ee', true);

esto generará el usuario admin (pass: admin) y el usuario user (pass: user)

finalmente en el spring-security.xml deben editar la URL de conexion para que quede algo asi:
jdbc:postgresql://localhost:5432/secframework"    localhost lo reemplazan por la maquina en donde este instalado el postgress

viernes, 12 de julio de 2013

Pasar datos desde JSP hacia SiteMesh decorators


Buscando la forma de pasar parametros y contenido entre JSP y los decoradores de SiteMesh encontre lo siguiente aquí

Básicamente consta en crear contenido en el JSP y ponerlo dentro dle tag <content>.

<content tag="pageName">
    Login Page
</content>
<content tag="siteSection">
    Administration
</content

arriba se declarna dos contenidos, luego en el JSP del decorador la info se extrae mediante

<decorator:getProperty property="page.pageName"/>
<decorator:getProperty property="page.siteSection"/>

eso hará que al aplicar el decorador, traiga todo lo que contenga el tag <contentent> identificado por pageName y siteSection.


miércoles, 10 de julio de 2013

Test Dev

// Comment
public class Testing {
public Testing() {
}
 
public void Method() {
/* Another Comment
on multiple lines */
int x = 9;
}
}

Tutorial primeros pasos con Netbeans + Spring MVC 3 + Spring Security 3 + SiteMesh


El siguiente tutorial tiene como objetivo desarrollar un proyecto básico paso a paso utilizando el IDE Netbeans 7.3, el Framework de Spring MVC 3, Spring Security 3 y SiteMesh 2.4.2


Herramientas y librerías



  • Netbeans 7.3
  • Spring MVC 3 (agregado desde Netbeans)
  • Spring Security 3.1.4  Bajado Desde acá
  • JAR asm-all-3.1.2.jar
  • JAR cglib-2.2.jar
  • SiteMesh 2.4.2 Bajado desde acá
  • JAR com.springsource.org.aopalliance-1.0.0.jar
  • Ejemplo en Netbeans bajar de acá  <-- no olviden bajar Spring Framework Security y agregarlo en librerias. 
  • Ejemplo en GitHub bajar de aqui



1- Crear Proyecto en NetBeans. 



Primero seleccionamos nuevo proyecto desde el menú principal de Netbeans, buscamos la categoría Java Web y seleccionamos el project "Web Application" 


En los siguientes pasos se elige el servidor embebido para testear el proyecto, en este caso probaremos con GlasshFish Server 3.1.2. De forma adicional se puede setear el "Context Path" (URL del proyecto), si es que no les gusta el que tira por defecto el IDE (en base al nombre del proyecto).

Luego le damos siguiente.


En este paso se eligen los frameworks a utilizar, por lo cual marcamos la casilla de "Spring Web MVC", incluimos los JSTL y la versión del Spring Framework 3.1.1 RELEASE, esto hará que el IDE automáticamente incluya dentro de las librerías del proyecto los componentes de Spring MVC 3.


La estructura final del proyecto al ser creado se ve la siguiente forma:




Las librerías del proyecto quedan así: 























Si echamos a correr el proyecto (RUN) debería verse lo siguiente: 





2- Agregar Librerías adicionales. 




Agregamos las librerías de Spring Scurity 3, SiteMesh y el resto declaradas anteriormente. Esto lo podemos hacer vía propiedades del proyecto.



El resultado debiese ser de la siguiente forma:



por un tema practico simplemente agregue todas los JAR de Spring Security.

3- Configuración SiteMesh 


Ahora pasaremos a generar la configuración y archivos básicos para utilizar SiteMesh.

Primero creamos la carpeta "decorators" dentro de WEB-INF. (puede ser en otra ruta). Dentro de decorators crearemos nuestro primer decorador "basic-theme.jsp" de momento no pondremos código adicional al JSP.

La estructura se debería ver así:
























Ahora debemos modificar el web.xml de nuestro proyecto para agregar el filtro correspondiente a SiteMesh. De manera que las solicitudes hacia nuestra aplicación sean filtradas por SiteMesh y decoradas según sea el caso.

nota: la primera linea de los .xml debe partir con "<?xml version="1.0" encoding="UTF-8"?>" si hay un espacio antes, al tratar de correr la aplicacion obtendrán un error de parseo.

Web.xml: 
  

    
     sitemesh
     
     com.opensymphony.sitemesh.webapp.SiteMeshFilter
     
    

    
     sitemesh
     /*
 FORWARD
 REQUEST     
         


    
        contextConfigLocation
        /WEB-INF/applicationContext.xml
    
    
        org.springframework.web.context.ContextLoaderListener
    
    
        dispatcher
        org.springframework.web.servlet.DispatcherServlet
        2
    
    
        dispatcher
        *.htm
    
    
        
            30
        
    
    
        redirect.jsp
    


Ahora debemos crear un archivo "decorator.xml" dentro de /WEB-INF/




Dentro de decorator.xml ponemos lo siguiente:


    
    
        /exclude.jsp
        /exclude/*
    

    
        /*
    


En el tag decorators indicamos cual sera el directorio por defecto para nuestros decoradores, en este caso seteamos "defaultdir="/WEB-INF/decorators".  Por esta razon el decorador base "basic-theme.jsp" fue creado dentro de WEB-INF/decorators, esta es una variable que debe ser seteada según la regla que se defina para el proyecto.

Además dentro de este xml de definición, indicamos los path a excluir, es decir, archivos que no deben ser decorados por sitemesh, por ejemplo estilos CSS, Javascript, Ajax, etc... Los path hacia esos archivos deben ser agregados dentro de las exclusiones.

Este xml también permite definir patrones, ne este caso toda URL que cumpla con "/*" será decorada.

Ahora volvamos a basic-theme.jsp en donde incluimos el siguiente código:


<?xml version="1.0" encoding="UTF-8" ?>
<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <decorator:head />
</head>
<body>
    <h1>Header</h1>
    <p><b>Navigation</b></p>
    <hr />
    <decorator:body />
    <hr />
    <h1>Footer</b></h1>
</body>
</html>

En este decorador, se indica a SiteMesh mediando TAGs que debe tomar los que encuentre dentro del TAG <head> y <body> de las paginas a decorar, y ponerlo (incrustarlo) dentro de basic-theme.jsp. En otras palabra sitemesh extrae objetos desde otras paginas y las redenderiza con el tema o layout especificado.

Si le damos RUN a la aplicacion deberiamos ver lo siguiente:


Como se aprecia en la imagen, el contenido de index.jsp, visto al principio de este tutorial, fue "decorado" en base a lo que se definió en el decorador basic-theme.jsp.


4- Spring Security 3 y MVC 3


Ahora nos dedicaremos a configurar los XMLs necesario para dotar de la capa de seguridad a nuestro proyecto, para esto primero debemos crear un XML en donde se definan los parametros y reglas de seguridad, lo llamaremos spring-security.xml y lo crearemos bajo /WEB-INF/  junto a los otros xml de configuración

spring-security.xml:

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

    <!-- enable support for Expression-based annotations in Spring Security secured-annotations="enabled"  -->
    <security:global-method-security pre-post-annotations="enabled" secured-annotations="enabled" />
    
    <!--
    <security:http auto-config="true" use-expressions="true" access-denied-page="/accessdenied" >
        
        <security:form-login />
 
        <security:logout />
 
    </security:http>
    -->
    
     <security:http auto-config="true" use-expressions="true" access-denied-page="/accessdenied">
  <security:intercept-url pattern="/welcome*" />
  <security:form-login login-page="/login" default-target-url="/welcome"
   authentication-failure-url="/loginfailed" />
  <security:logout logout-success-url="/logout" />
 </security:http>
   
    <!-- Declare an authentication-manager to use a custom userDetailsService -->
    <security:authentication-manager>
        <security:authentication-provider user-service-ref="userDetailsService">
            <security:password-encoder ref="passwordEncoder"/>
        </security:authentication-provider>
    </security:authentication-manager>
 
    <!-- Use a Md5 encoder since the user's passwords are stored as Md5 in the database -->
    <bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/>
  <!-- An in-memory list of users. No need to access an external database layer.
      See Spring Security 3.1 Reference 5.2.1 In-Memory Authentication -->
  <!-- john's password is admin, while jane;s password is user  -->
    <security:user-service id="userDetailsService">
        <security:user name="admin" password="21232f297a57a5a743894a0e4a801fc3" authorities="ROLE_USER, ROLE_ADMIN" />
        <security:user name="user" password="ee11cbb19052e40b07aac0ca060c23ee" authorities="ROLE_USER" />
    </security:user-service>
    
    
</beans>

Notar que los schemlocation apunta a la version 3.1 de spring security, en muchos casos los ejemplos que vienen dentro de la distribución vienen con XML apuntando a versiones anteriores.

Dentro de este XML se define la pagina de login, la página de acceso denegado y la pagina de exito en logout o en caso de error.

Ahora debemos modificar el archivo "applicationContext.xml", este archivo es generado automaticamente por Netbeans, en principio se ve asi:

applicationContext.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">

    <!--bean id="propertyConfigurer"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
          p:location="/WEB-INF/jdbc.properties" />

<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource"
    p:driverClassName="${jdbc.driverClassName}"
    p:url="${jdbc.url}"
    p:username="${jdbc.username}"
    p:password="${jdbc.password}" /</script>

    <!-- ADD PERSISTENCE SUPPORT HERE (jpa, hibernate, etc) -->
</beans>

y debemos reemplazarlo por lo siguiente:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:p="http://www.springframework.org/schema/p"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context-3.1.xsd
                http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
<!-- Activates various annotations to be detected in bean classes -->
<context:annotation-config/>
<!-- Scans the classpath for annotated components that will be auto-registered as Spring beans. For example @Controller and @Service. Make sure to set the correct base-package-->
<context:component-scan base-package="com.ozdev"/>
<!-- Configures the annotation-driven Spring MVC Controller programming model. Note that, with Spring 3.0, this tag works in Servlet MVC only! -->
<mvc:annotation-driven/>
</beans>

Aquí hemos indicado que se habilitan las anotaciones en el framework y la ruta al package base que contendrá nuestras clases con anotaciones.
en construcción.

De manera análoga generamos el siguiente contenido para dispatcher-servlet.xml

dispatcher-servlet.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:p="http://www.springframework.org/schema/p"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context-3.1.xsd
                http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
    
    
    <bean id="jspViewResolver"
            class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="viewClass"
                    value="org.springframework.web.servlet.view.JstlView" />
            <property name="prefix" value="/WEB-INF/jsp/" />
            <property name="suffix" value=".jsp" />
    </bean>
    
</beans>

Ahora debemos indicarle a nuestro web.xml que debe utilizar el filtro de spring-security para eso debemos añadir los correspondientes filtros en web.xml y además como parámetro de contexto agregamos a spring-security.xml. El archivo web.xml final debiese quedar asi:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
         xmlns="http://java.sun.com/xml/ns/javaee" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

    <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>  

    <filter>
     <filter-name>sitemesh</filter-name>
     <filter-class>
     com.opensymphony.sitemesh.webapp.SiteMeshFilter
     </filter-class>
    </filter>

    <filter-mapping>
     <filter-name>sitemesh</filter-name>
     <url-pattern>/*</url-pattern>
 <dispatcher>FORWARD</dispatcher>
 <dispatcher>REQUEST</dispatcher>     
    </filter-mapping>     


    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/applicationContext.xml
            /WEB-INF/spring-security.xml
        </param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>redirect.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Ahora creamos nuestro primer controlador, en este caso nos interesa que se maneje el login de acceso, primero crearemos la clase JAVA LoginController, luego generaremos los JSP faltantes (login y accessdenied).

LoginController.java:
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.ozdev.controllers;

/**
 *
 * @author ozdev
 */
import java.security.Principal;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
 
@Controller
public class LoginController {
 @Secured("ROLE_ADMIN")
 @RequestMapping(value="/welcome", method = RequestMethod.GET)
 public String printWelcome(ModelMap model, Principal principal ) {
 
  String name = principal.getName();
  model.addAttribute("username", name);
  model.addAttribute("message", "Spring Security Custom Form example");
  return "hello";
 
 }
 
 @RequestMapping(value="/login", method = RequestMethod.GET)
 public String login(ModelMap model) {
 
  return "login";
 
 }
        
 @RequestMapping(value="/", method = RequestMethod.GET)
 public String loginRaiz(ModelMap model) {
 
  return "login";
 
 } 
        
 
 @RequestMapping(value="/loginfailed", method = RequestMethod.GET)
 public String loginerror(ModelMap model) {
 
  model.addAttribute("error", "true");
  return "login";
 
 }
 
 @RequestMapping(value="/logout", method = RequestMethod.GET)
 public String logout(ModelMap model) {
 
  return "login";               
 }
        
                
  @RequestMapping(value="/accessdenied", method = RequestMethod.GET)
 public String accessdenied(ModelMap model) {
 
  return "accessdenied";        
        }
 
}

En las notaciones de spring framework utilizamos el @RequestMapping para indicar la URL que nos interesa interceptar y en el return indicamos la página (JSP) la cual será la vista.

Por el lado de la seguridad indicamos que la pagina /welcome solo tendra acceso el rol admin con lo siguiete:  @Secured("ROLE_ADMIN") .

Ahora generamos los JSP faltantes

accessdenied.jsp:

<%-- 
    Document   : accessdenied
    Created on : Jul 27, 2012, 11:50:54 AM
    Author     : ozdev
--%>

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        Access is denied
    </body>
</html>

login.jsp:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>Login Page</title>
<style>
.errorblock {
 color: #ff0000;
 background-color: #ffEEEE;
 border: 3px solid #ff0000;
 padding: 8px;
 margin: 16px;
}
</style>
</head>
<body onload='document.f.j_username.focus();'>
 <h3>Login with Username and Password (Custom Page)</h3>
 
 <c:if test="${not empty error}">
  <div class="errorblock">
   Your login attempt was not successful, try again.<br /> Caused :
   ${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}
  e</div>
 </c:if>
 
 <form name='f' action="<c:url value='${pageContext.request.contextPath}/j_spring_security_check' />"
  method='POST'>
 
  <table>
   <tr>
    <td>User:</td>
    <td><input type='text' name='j_username' value=''>
    </td>
   </tr>
   <tr>
    <td>Password:</td>
    <td><input type='password' name='j_password' />
    </td>
   </tr>
   <tr>
    <td colspan='2'><input name="submit" type="submit"
     value="submit" />
    </td>
   </tr>
   <tr>
    <td colspan='2'><input name="reset" type="reset" />
    </td>
   </tr>
  </table>
 
 </form>
</body>
</html>

hello.jsp:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<body>
 <h3>Message : ${message}</h3> 
 <h3>Username : ${username}</h3> 
 
 <a href="<c:url value="/j_spring_security_logout" />" > Logout</a>
 
</body>
</html>

Si le damos RUN al proyecto entraremos a la siguiente página:



si nos logeamos como user: admin pass: admin veremos esto:



en cambio si entramos como user/user veremos esto:


Con esto concluimos el levantamiento de un proyecto con Spring MVC 3, SiteMesh y Spring Security 3