lunes, 15 de abril de 2013

RESTful parte 5: REST con autenticación

Hasta el momento hemos visto un CRUD usando RESTful, con un objeto y varios objetos.

Ahora, quiero mostrar el manejo de la seguridad en RESTful usando los estándares de Java EE6.


Para nuestro tutorial utilizaremos:
  1. GlassFish 3.1.2.2
  2. NetBeans 7.3
  3. JQuery, que lo obtendremos de la red directamente
  4. Chrome o Firefox + Firebug (aunque la última versión de Firefox ya viene con un depurador propio)
Para poder implementarlo necesitamos configurar en GlassFish los usuarios y los grupos. Luego, estos serán mapeados en nuestra aplicación. Para más información sobre Usuarios, Grupos y Roles, leer (en inglés)   "Working with Realms, Users, Groups and Roles de "The Java EE 6 Tutorial"

Configurando Realm del GlassFish (con usuarios y grupos)

Iniciamos el GlassFish, ya sea desde la línea de comandos (ejecutando $GLASSFISH_HOME\bin\asadmin start-domain) o desde el NetBeans en el panel "Services" (Ctrl+5) Nodo "Servers > GlassFish Server" clic derecho y seleccionando "Start"

Ahora, entramos a la consola web de GlassFish (http://localhos:4848) y seleccionamos "Configurations > server-config > Security > Realms > file" (File, porque usaremos - pare este ejemplo -una autenticación basada en archivo plano. Para producción podremos usar otro tipo de autenticación)


Hacemos clic en el botón superior  "Manage Users" y comenzaremos a crear usuarios:
  1. Clic en "New..."
  2. Escribimos los siguientes campo:
    • User ID: usuario1
    • Group List: usuario
    • New password: usuario1 (la misma contraseña para no olvidarnos)
    • Confirm New password: usuario1
  3. Clic en "Ok"
  4. Crearemos dos usuarios más (usuario2, usuario3) con el  mismo rol y dos usuarios (admin1, admin2) con el rol "admin".
En este caso, los grupos se crearán cada vez que es mencionado en los usuarios. Otros tipos de Realm - como el de base de datos - debe existir otra tabla con los grupos a considerar.
Usuarios creados en el realm "File" de GlassFish
Si crea otro Realm de tipo file, asegurarse de que el JAAS Context sea fileRealm.

Además, notar que este realm se llama "file". Este nombre lo usaremos cuando configuremos nuestra aplicación web.

Definiendo seguridad en una aplicación Web.

Ahora, crearemos una aplicación llamada "CalculadoraSeguraRestWeb" el cuál tendrá la clase CalculadoraService.
Lo nuevo en este código (en comparación del publicado en la Parte 1) es que se están declarando dos nuevas anotaciones.

  • @DeclareRoles, que - como su nombre lo dice - declara los roles para una aplicación. Esta anotación se define en una clase.
  • @RolesAllowed, que indica que roles son permitidos para acceder al método.
Ahora bien, vemos que aquí se definen roles (user,admin) pero en  GlassFish hemos definido grupos (usuario,admin)

Lo que necesitamos es mapearlo: tales roles de la Aplicación corresponde a tales usuarios del GF, o, tales roles de la aplicación corresponde a tales grupos de GF. ¿Cuál es la diferencia entre Roles y Grupos? Veámoslo así:
  • Los grupos son agrupaciones de usuarios, por ejemplo, agrupados por área de una empresa: Contabilidad, Finanzas, Sistemas, etc. Su alcance es solo organizacional.
  • El rol es lo que toma un usuario cuando ingresa a la aplicación. Tenemos, por ejemplo: gerentes, usuarios, usuarios para imprimir, usuarios nocturnos, etc. Su alcance es solo en la aplicación.
Para nuestro caso, vamos a mapear el rol "USER" con el grupo "usuario", y "ADMIN" con el grupo "admin".

Mapeando Grupos como Roles en una aplicación Web.

Entramos al archivo web.xml, y si no existe tal archivo, lo creamos con File > New (Ctrl+N), Categoría: Web, Tipo archivo: Standard Deployment Descriptor (web.xml) 

Seleccionamos la pestaña "Security" y en la sección "Login Configuration" seleccionamos "Basic" (esta es una autenticación muy genérica que le indica al navegador web abrir un formulario estándard)
Luego, en la entrada de texto "Realm Name" escribimos el nombre del realm que vamos a usar. Para este ejemplo colocaremos el nombre "file".



Luego, en la misma pestaña pero en la sección "Security Roles", agregar dos roles "USER" y "ADMIN".
Y para terminar con este archivo, en la sección "Security Contrstraints" hacemos clic en "Add Security Constraint", indicando el campo "Display Name" el valor "CalculadoraConstraint". Con esto estamos creando un conjunto de reglas de seguridad donde asignaremos un grupo de rutas de acceso con un roles que podrán accederlos.

En la subsección "Web Resource Collection" indicamos qué rutas son parte de este conjunto. Hacemos clic en "Add" y escribimos 
  • Resource Name: CalculadoraResource
  • URL Pattern(s): /webresources/calculadora/*  (Es el URL asociado al servicio que estamos protegiendo)
  • HTTP Method(s). All (Se puede especificar cualquier tipo dependiendo de nuestro criterio. Para este caso usaremos All)

Y activamos la opción "Enable Authenticacion Constraint" donde le indicaremos qué roles son permitidos para acceder al URL descrito arriba.

Esto es todo en el archivo web.xml Si revisamos el código fuente, debe quedar algo así.
Se pudo haber hecho directamente en el código fuente, pero con el IDE se hace más rápido y así hemos podido ver de qué trataba cada sección.

Ahora, abrimos el archivo de despliegue glassfish-web.xml Si no existe, lo creamos desde File> New (Ctrl+N) Categoria: GlassFish, Tipo de archivo: GlassFish Descriptor.

Y en la pestaña "Security" veremos que están declarados los roles "ADMIN" y "USER" pero con un signo de interrogación. Esto es porque ha detectado que se han declarado en el web.xml pero no están declarados en este archivo de contexto. Aquí es donde debemos mapear los Roles de la aplicación con los grupos que definimos en el Realm.


Abrimos el nodo"ADMIN" y hacemos clic en "Add Group". Escribiremos "admin" que es el grupo que definimos en el Realm.
Clic en OK y veremos que ya se ha asignado el grupo "admin" al rol "ADMIN". Veremos que el signo de interrogación del Rol ha desaparecido.


Ahora, haremos lo mismo para el rol "USER" pero le asignaremos el grupo "usuario".

Al final, esta pestaña debe lucir algo así


El archivo glassfish-web.xml luciría algo así

Definiendo el cliente

Para finalizar, haremos el cliente en el index.jsp de este proyecto. Lo haremos casi como el que se vió en la Parte 1 de este conjunto de tutoriales: usando jQuery. Pero, en lugar de usar el método jQuery.get() usaremos jQuery.ajax().
Ahora, ejecutemos la aplicación, y tratemos de darle un valor y calcular su factorial haciendo clic en el botón


Nos mostrará la autenticación del navegador para la aplicación. Este es el tipo "basic" que definimos en el web.xml, y es lo que queremos.


Le ponemos las credenciales que pedimos en el Realm: usuario: usuario1, contraseña: usuario1 Y si las credenciales son válidas, nos mostrará el resultado calculado.
Ahora bien, necesitamos que la autenticación sea transparente ¿cómo lo hacemos? Le pasamos el usuario y contraseña a la petición del jQuery.

Agregando autenticación el jQuery

He visto que la autenticación en la petición ajax de toolkit tipo jQuery Dojo es que permite pasar el usuario y contraseña en la misma petición, y así pasa la autenticación Basic.
Agregaremos un formulario de autenticación en el mismo .jsp.

Y modificaremos el script que llama al REST para obtener las credenciales y enviárselas al REST.


El completo, sería así Y cuando lo ejecutemos, bastará con que coloquemos el usuario y contraseña en el formulario respectivo, y listo... ya estamos usando la autenticación de REST con nuestro formulario.

Código fuente

Y a este post no le iba a faltar su código fuente. 


... y desde Mercurial, aquí: