viernes, 4 de junio de 2010

Realms(Dominios) en Glassfish y autenticación con formularios

Para este ejemplo estoy utilizando Netbeans 6.8, Glassfish V3, JDK1.6 y Ubuntu 9.10 Karmic Koala
Como primer paso, debemos crear un Realm(Dominio) en Glassfish:
Bajo Security damos click en Realms y damos click sobre New:
Ahi creamos el Realm con la siguiente informacion:
Realm Name:realmexample
Class Name:com.sun.enterprise.security.auth.realm.file.FileRealm
JAAS Context:fileRealm
Key File:${com.sun.aas.instanceRoot}/config/keyfile

y damos click en OK

Luego damos click en realmexample
y luego click en Manage Users

Ahi damos click en New y creamos un usuario con:
UserId:usuario
Group List:Users
y le damos una clave y damos click en OK

Con esto tenemos ya creado un dominio y un usuario.

Ahora vamos a Netbeans 6.8
Aqui tenemos que crear un nuevo proyecto Java EE al que llamaremos PracticaSeguridades



Luego, bajo el proyecto web creamos un Servlet llamado Cliente, bajo el paquete com.web
En la siguiente pantalla marcamos el checkbox "Add information to deployment descriptor" para que nos genere el descriptor web.xml.



Luego modificamos index.jsp al siguiente código:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!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=UTF-8">
<title>JSP Page</title>
</head>
<body>
<a href="Cliente">Datos Informativos</a><br/>
<a href="logout.jsp">Salir</a>
</body>
</html>


y agregamos tres páginas jsp llamadas error.jsp, login.jsp, logout.jsp, que deben tener el siguiente código:

error.jsp:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!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=UTF-8">
<title>JSP Page</title>
</head>
<body>
<h1>Nombre de usuario incorrecto <a href="javascript:history.back(1)">Regresar</a></h1>
</body>
</html>

login.jsp:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!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=UTF-8">
<title>Login de Usuario</title>
</head>
<body>
<form method=post action="j_security_check">
Usuario:<input type="text" name= "j_username"/><br/>
Clave:<input type="password" name= "j_password"/><br/>
<input type="submit" name="submit" value="Ingresar"/>
<input type="reset" name="reset" value="Cancelar"/>
</form>
</body>

</html>


logout.jsp:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!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=UTF-8">
<title>JSP Page</title>
</head>
<body>
<%session.invalidate();%>
<h1>Gracias por probar esta demo, visita <br/>
<a href="http://festintecnologico.blogspot.com/" target="_blank">Festín tecnológico</a></h1>
</body>
</html>


Hecho esto, tenemos que modificar los archivos sun-web.xml y web.xml para colocar las políticas de seguridades.
En este XML unimos el Perfil de usuario de Glassfish(Users) a uno que nosotros creamos en nuestra aplicación web (Usuarios)

en sun-web.xml agregamos las siguientes lineas antes de </sun-web-app>
<security-role-mapping>
<role-name>Usuarios</role-name>
<group-name>Users</group-name>
</security-role-mapping>

Con lo que el archivo sun-web.xml nos queda como:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 Servlet 2.5//EN" "http://www.sun.com/software/appserver/dtds/sun-web-app_2_5-0.dtd">
<sun-web-app error-url="">
<context-root>/PracticaSeguridades-war</context-root>
<class-loader delegate="true"/>
<jsp-config>
<property name="keepgenerated" value="true">
<description>Keep a copy of the generated servlet class' java code.</description>
</property>
</jsp-config>
<security-role-mapping>
<role-name>Usuarios</role-name>
<group-name>Users</group-name>
</security-role-mapping>
</sun-web-app>

En web.xml definimos que métodos(GET, POST, PUT, etc) se pueden realizar y sobre que recursos y que roles pueden usar esos recursos, para nuestro caso usaremos el rol de "Usuarios" que definimos en sun-web.xml. Tambien definimos que modo de autenticacion usaremos en nuestro caso, es de tipo Form usando la pagina login.jsp

Para web.xml agregamos las siguientes lineas antes de </web-app>
<security-constraint>
<display-name>Confirmacion Identidad</display-name>
<web-resource-collection>
<web-resource-name>PoliticasSeguridad</web-resource-name>
<description/>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>Usuarios</role-name>
</auth-constraint>

</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>realmexample</realm-name>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/error.jsp</form-error-page>
</form-login-config>
</login-config>

Con lo que el archivo nos queda:
<?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">
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<security-constraint>
<display-name>Confirmacion Identidad</display-name>
<web-resource-collection>
<web-resource-name>PoliticasSeguridad</web-resource-name>
<description/>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>Usuarios</role-name>
</auth-constraint>

</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>realmexample</realm-name>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/error.jsp</form-error-page>
</form-login-config>
</login-config>
</web-app>


Luego, para el proyecto EJB, vamos a crear un nuevo Bean de Session y lo llamaremos EjemploSeguridadBean bajo el paquete com.ejb y marcamos la interface remote de la siguiente manera:



damos click en Finish.

Modificamos los archivos
EjemploSeguridadBeanRemote.java

package com.ejb;

import javax.ejb.Remote;

@Remote
public interface EjemploSeguridadBeanRemote {
String probarSeguridadEJB();
}


EjemploSeguridad.java
En este archivo usamos las anotaciones @RolesAllowed y @DeclareRoles({"Usuarios"}) para indicar que Roles de usuario definidos en sun-web.xml pueden ejecutar esta rutina

package com.ejb;

import javax.annotation.Resource;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
@Stateless
@DeclareRoles({"Usuarios"})
public class EjemploSeguridadBean implements EjemploSeguridadBeanRemote {
@Resource
SessionContext ctx;
@RolesAllowed(value = {"Usuarios"})
public String probarSeguridadEJB() {
return "El nombre de usuario desde EJB es:" + ctx.getCallerPrincipal().getName();
}
}


Luego de esto, regresamos al proyecto web y cambiamos el servlet Cliente.java al siguiente código:

Cliente.java

De la misma manera que en el Bean, por medio de las anotaciones @DeclareRoles({"Usuarios"})
y
@ServletSecurity(@HttpConstraint(rolesAllowed={"Usuarios"}))
podemos definir que usuarios pueden ejecutar estas rutinas

package com.web;

import com.ejb.EjemploSeguridadBeanRemote;
import java.io.IOException;
import java.io.PrintWriter;
import javax.annotation.security.DeclareRoles;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.HttpConstraint;
import javax.servlet.annotation.ServletSecurity;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name="Cliente", urlPatterns={"/Cliente"})
@DeclareRoles({"Usuarios"})
@ServletSecurity(@HttpConstraint(rolesAllowed={"Usuarios"}))
public class Cliente extends HttpServlet {
@EJB private EjemploSeguridadBeanRemote bean;

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet Cliente1</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Informacion de Seguridad Desde WEB</h1>");
out.println("Usuario: " + request.getUserPrincipal().getName()+"<br/>");
out.println("Tipo de Autenticacion: " + request.getAuthType()+"<br/>");
out.println("Nombre Servidor: " + request.getServerName()+"<br/>");
out.println("<h1>Informacion de Seguridad Desde EJB</h1>");
out.println(bean.probarSeguridadEJB());
out.println("</body>");
out.println("</html>");

} finally {
out.close();
}

}
....


Con lo cual tenemos:

Si nos equivocamos en el usuario o clave, nos saldrá el siguiente mensaje:
Si ingresamos con usuario y la clave que definimos en Glassfish.

Se nos muestran las siguientes opciones:
Si damos click en datos informativos tenemos:
y al dar click en logout:

jueves, 3 de junio de 2010

Restful Server & Client

Para este ejemplo estoy utilizando Netbeans 6.8, Glassfish V3, JDK1.6 y Windows 7
Primeramente abrimos Netbeans
Luego creamos un nuevo proyecto web

Le damos el nombre RestfulServer
Seleccionamos Glassfish V3 como servidor y la versión Java EE 6 Web
Luego creamos una nueva clase java
Le llamaremos Restful
La clase tiene el código siguiente(Llaman la atención las anotaciones) para saber que path es que se usará y que función se ejecutará de acuerdo tipo de método llamado

package com.web.ws;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;


@Path("/mensaje")
public class Restful {
public Restful() {
}

@GET
@Produces("text/html")
public String getHtml() {
return "<html><body><h1>Hello World!</body></h1></html>";
}

@PUT
@Consumes("text/html")
public void putHtml(String nombre) {
System.out.println("Saludos(PUT):"+nombre);
}
}


En el momento de guardar la clase, se mostrará esta ventana. La misma que nos ayuda a configurar la información en el descriptor (web.xml) de manera automática
Existe otra manera de crear la clase Restful del servidor con anotaciones, esta es por medio de la opción RESTful Web Services from Patterns
Si seleccionamos esta via para crear el web service, crearemos una clase con las anotaciones antes mostradas de manera automática
Luego hagamos un "Test RESTful Web Services"
Nos hará una pregunta de seguridad y Aceptaremos
El explorador de internet, nos mostrará los métodos disponibles y podremos hacer pruebas sobre los mismos:
Para la creación del cliente, vamos a crear una aplicación Java
A la aplicación le daremos el nombre de Cliente

La variable URL debe ser cambiada al URL que se muestra en Resource. Podemos ver esta variable cuando probamos el servicio Restful tres pantallas atrás

El código es el siguiente:

package cliente;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;

public class Main {

private static String ruta="http://localhost:21405/RestfulServer/resources/mensaje";
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
get();
put();
}

public static void get() {
String respuesta = "";
BufferedReader buffer = null;
try {
URL url = new URL(ruta);
URLConnection conn = url.openConnection();
buffer = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = buffer.readLine()) != null) {
respuesta += line;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (buffer != null) {
try {
buffer.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
System.out.println(respuesta);
}

public static void put() {
String respuesta = "";
OutputStreamWriter wr = null;
BufferedReader rd = null;
try {
URL url = new URL(ruta);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("PUT");
conn.setDoOutput(true);
wr = new OutputStreamWriter(conn.getOutputStream());
wr.write("Santiago");
wr.flush();
rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = rd.readLine()) != null) {
respuesta += line;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (wr != null) {
wr.close();
}
if (rd != null) {
rd.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
System.out.println(respuesta);
}
}
Ejecutamos el servidor y luego el cliente
Con lo cual obtenemos las siguientes salidas:

Ejemplo rápido de Message Driven Beans

Para este ejemplo estoy usando Windows 7, Netbeans 6.8, JDK1.6 y Glassfish V3
Desde la consola de adminsitracion de Glassfish, creamos un JMS Connection Factory, con la siguiente información:

Luego creamos un JMS Destination Resource, con el siguiente código:




Posteriormente creamos un proyecto JEE llamado MDB




Luego creamos un servlet llamado Generador con el siguiente código:




Como variables de instancia, creamos
@Resource(mappedName="jms/QueueFactory")
javax.jms.QueueConnectionFactory queueConnection;
@Resource(mappedName="jms/Queue")
javax.jms.Queue queue;


protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try{
Connection connection=queueConnection.createConnection();
Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer=session.createProducer(queue);
MapMessage message=session.createMapMessage();
message.setString("nombre", "Carlos");
message.setString("apellido", "Marin");
message.setString("id", "A12311");
producer.send(message);
producer.close();
session.close();
connection.close();
}catch(Exception ex){
ex.printStackTrace();
}

}

Luego un creamos un message driven bean, en el asistente como Server Destinations seleccionamos jms/Queue.


Luego codificamos la clase generada, con el siguiente código, en la función onMessage:


public void onMessage(Message message) {
System.out.println("Saludos desde el MDB...");
try {
MapMessage msg = (MapMessage) message;
System.out.println("Nombre:" + msg.getString("nombre"));
System.out.println("Apellido:" + msg.getString("apellido"));
System.out.println("Id:" + msg.getString("id"));
} catch (Exception ex) {
ex.printStackTrace();
}
}

y ejecutamos el Servlet llamado Generador, que nos imprimirá la siguiente información en consola:

Saludos desde el MDB...

Nombre:Carlos
Apellido:Marin
Id:A12311