Ignorante

27/04/2012

Conceptos Básicos de Spring Security

Archivado en: computacion,Java,Programación,software,Tecnología — ignorante @ 17:13
Tags: , , , ,

Spring Security es el framework de autenticación y control de acceso de Spring.

Autenticación en el caso más usual es determinar que el usuario que accede al sistema es quien dice ser. Spring soporta muchísimas formas de hacer la autenticación y van desde la más básica que es un simple formulario HTML hasta otras como OpenID, CAS, LDAP, Kerberos, JAAS, etc.

Control de acceso es determinar si un usuario puede realizar una determinada acción dentro del sistema. En muchos casos no tiene sentido realizar el control de acceso usuario por usuario sino agrupando a todos los usuarios que pueden realizar las mismas acciones dentro del sistema. Es decir, no se define “María y Roberto pueden imprimir facturas” sino, “todos los usuarios que sean vendedores pueden imprimir facturas”. Si hoy Juan es encargado de limpieza entonces no puede imprimir facturas, pero el día de mañana, Juan podría ser ascendido a área de ventas y ser vendedor, por lo que entonces sí podrá imprimir facturas. La forma de agrupar a “todos los usuarios que sean vendedores” es mediante roles. Entonces en un momento sólo María y Roberto tienen el rol “ROLE_VENDEDOR” y posteriormente se agregará Juan a ese grupo asignándole dicho rol.

Entender que un rol no es otra cosa que un conjunto de usuarios es muy importante.

Spring permite controlar el acceso en tres niveles

  1. URLs de una aplicación WEB,
  2. métodos de un Bean de Spring.
  3. objetos del dominio.

La única diferencia entre las tres es qué operación es la que se está controlando.

En el primer caso, se busca controlar el acceso a un grupo de recursos que son identificables mediante una URL. Por ejemplo si nuestra aplicación web tiene una página que sólo debe ser accedida por un gerente y no por todos los demás empleados, una estrategia sería que la URL de esa página fuera por ejemplo “/gerencia/index.jsp” y se configurara Spring Security para que sólo usuarios con rol “ROLE_GERENTE” pudieran acceder a URLs que empezaran con “/gerencia”.

El segundo caso busca controlar la ejecución de un método en particular. Se usa en situaciones donde no se trata de una aplicación web, cuando no es posible tener URLs distintas para diferenciar el acceso o cuando independientemente de qué URL fue solicitada desde el cliente queremos asegurarnos de que no se ejecute un método si no se trata del usuario que tiene el permiso. Los métodos que pueden ser controlados son métodos de objetos que sean Beans de Spring, no cualquier objeto.

El tercer caso busca controlar el acceso a objetos de dominio. El ejemplo más claro es para extraer dinero de una cuenta bancaria. Se debe verificar que el usuario sea el dueño de esa cuenta en particular y la relación de quién es dueño de qué cuenta puede ir variando en el tiempo por ejemplo a medida que se agregan o quitan titulares. En este caso los objetos que se desean controlar no tienen que ser Beans de Spring, puede ser cualquier objeto.

Para resolver el tercer caso se usa un módulo de Spring Security que se llama Domain Object Security o Spring ACLs.

Con Spring ACLs se define para cada objeto (instancias individuales) del dominio que se necesite controlar una lista de usuarios y roles que pueden accederlo. Como un rol no es otra cosa que un conjunto de usuarios, en verdad lo que se indica para cada objeto del dominio es directa o indirectamente una lista de usuarios.

Gráficamente lo que se tiene es un objeto del dominio, como por ejemplo una cuenta bancaria:

{Cuenta 123541500542}

y asociada al objeto una lista de usuarios que están autorizados a sacar dinero de esa cuenta

{Cuenta 123541500542} -> {“Juan”, “Pedro”, “Susana”}

Cuando la aplicación está por realizar la operación de débito sobre esa cuenta debemos indicarle a SpringSecurity que verifique que el usuario que está realizando la operación esté en la lista de usuarios de la cuenta sobre la que se está operando.

¿Cómo sería esto con la intervención de roles? Supongamos que existiera en el sistema un rol “ROLE_GERENTE_DE_CUENTAS” y que de acuerdo a las reglas del banco un usuario con ese rol está autorizado a realizar débitos sobre cualquier cuenta. La ACL quedaría así

{Cuenta 123541500542} -> {“Juan”, “Pedro”, “Susana”, “ROLE_GERENTE_DE_CUENTAS”}

Spring Security verificará en el momento que le sea indicado si el usuario que está intentando realizar la operación es Juan, Pedro, Susana, o algún usuario que tenga asignado el rol “ROLE_GERENTE_DE_CUENTAS”. Nuevamente,  como un rol no es otra cosa que un conjunto de usuarios en la lista la presencia de un rol es sólo una forma indirecta de referirnos a usuarios.

Si en cambio se define a los roles como un conjunto de “operaciones” o un conjunto de “permisos” es más difícil entender qué hace el rol en la lista de usuarios autorizados y por lo tanto entender cómo adaptar Spring ACLs a nuestra aplicación.

Spring ACLs es muy flexible y potente ya que permite manejar varios permisos como lectura, escritura, borrado y además permite otorgar y revocar permisos. Por ejemplo si le otorgamos permiso al rol “ROLE_GERENTE” y se lo revocamos al usuario “Juan” que  tiene ese rol, lo que logramos es definir que todos los gerentes menos “Juan” tienen otorgado el permiso. También podría ser a la inversa y definiríamos que ningún gerente tenga permiso a excepción de “Juan”. Si vemos los roles  como conjuntos de usuarios, es simplemente quitar elementos del conjunto.

Para aprender más en detalle cómo usar Spring ACLs, se pueden consultar estos dos artículos

30/11/2011

SportsTracker 5.3.0

SportsTracker 5.3.0

SportsTracker 5.3.0

SportsTracker es una aplicación muy completa para registrar las actividades deportivas y hacer un seguimiento. Permite crear diagramas y sacar estadísticas.

Descargar SportTracker 5.3.0 Para Windows

Descargar SportTracker 5.3.0 Para Windows

29/11/2011

Formato de Números y Fechas con Spring Web MVC

Archivado en: computacion,Java,Programación,software,Tecnología — ignorante @ 20:00
Tags: , ,

import java.math.BigDecimal;
import java.util.Date;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import javax.validation.constraints.Digits;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Size;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.NumberFormat;

// ...
    @DateTimeFormat(pattern = "dd/MM/yyyy")
    private Date control;

    @NumberFormat(style = NumberFormat.Style.NUMBER)
    @Digits(integer = 5, fraction = 5)
    private BigDecimal distantVisualAcuity;

    @Max(100)
    @Min(10)
    @NumberFormat(style = NumberFormat.Style.NUMBER)
    private BigDecimal totalInterpupilaryDistance;

    @NotNull
    @Past
    @DateTimeFormat(pattern = "dd/MM/yyyy")
    private Date date;

Spring Web MVC convierte los datos ingresados por el usuario al tipo de dato del Bean que respalda el formulario. No es necesario escribir una sola línea de código para convertir la enorme mayoría de los valores que se ingresan. Basta con usar algunas annotations muy sencillas. En el caso de números se puede establecer, por ejemplo, la cantidad de dígitos enteros y fraccionarios, sin tener que recurrir a una máscara de entrada.

Para poder usar la annotation DateTimeFormat hay que incorporar joda-time como dependencia.

La conversión funciona tanto para el ingreso de texto como para el formateo a la hora de editar el formulario.

Las annotations así usadas son además documentación del sistema. Cualquier persona que vea cómo está anotada la variable sabe el tipo de valores de entrada que admite sin tener que mirar otra cosa.

25/11/2011

Por Qué Usar Spring Web MVC Framework

Archivado en: computacion,Java,Programación,software,Tecnología — ignorante @ 8:00
Tags: ,

1.- Porque la asignación de qué método se ejecuta cuando se carga una URL se puede hacer con una annotation en forma directa y simple.

@Controller
public class User {
    @RequestMapping("/admin/user")
    public String listUsers(Model model) {
        model.addAttribute("users", this.userService.listAll());
        return "userList";
    }
}

Con sólo usar la annotation  @RequestMapping Spring sabe que cuando se ingrese la URL /admin/user hay que ejecutar el método listUsers de la clase User.

2.- Porque los controllers no son más que un objeto cualquiera que lleva una annotation.
En el ejemplo, la clase User no tiene nada en particular. No implementa ninguna interfaz ni hereda de ninguna clase en particular. Sólo se requiere anotarla con @Controller.

3.- Porque todas las validaciones se pueden hacer con annotations usando Bean Validation (JSR 303).

@ScriptAssert(
    lang = "Groovy",
    script = "_this.password.equals(_this.password2)",
    message="{password.confirm}")
public class UserDTO extends PersonDTO {

    @NotEmpty
    @Size(min=5,max=20)
    private String login;

    @Size(max=40)
    private String password;

    @Size(max=40)
    private String password2;
}

En este ejemplo, la clase UserDTO es el respaldo del formulario de alta de usuarios. En el caso del campo login, se valida que esté presente y que sea de entre 5 y 20 caracteres. El caso de la password, que sea como máximo de 40 y para verificar que coincidan ambas contraseñas ingresadas, se usa la annotation @ScriptAssert que permite realizar validaciones más complejas ejecutando código mediante un lenguaje de scripting (en este caso Groovy) sin tener que recurrir a codificar un validador propio.

Cuando el script fuera muy complejo se puede directamente invocar un método del objeto anotado de esta forma:

@ScriptAssert.List({
    @ScriptAssert(lang = "Groovy",
        script = "_this.checkQuery()",
        message = "{report.enterQuery}"),
    @ScriptAssert(lang = "Groovy",
        script = "_this.checkParameterCount()",
        message = "{report.paramCount}")})
public class ReportDTO extends EntityDTO {

    /* ... resto del código de la clase ... */

 public boolean checkParameterCount() {
        return this.parameters.size() == this.getExpectedParameters();
    }

    public boolean checkQuery() {
        return this.query != -1 || (this.sql != null && this.sql.length() > 10);
    }
}

Así se puede escribir en el mismo objeto que respalda el formulario uno o varios métodos que realicen validaciones y se los invoca desde la annotation usando un lenguaje de scripting directamente. En el ejemplo se ve cómo ejecutar varias validaciones cada una con su propio mensaje de error y su script.

4.- Porque permite manejar distintos tipos de request (GET, POST, PUT, DELETE, HEAD y OPTIONS) en forma individual o todos juntos.


// ...

    @RequestMapping(value = "/admin/report/edit", method = RequestMethod.GET)
    public ModelAndView editReportForm(
            @RequestParam(required = true, value = "id") int id) {
// ...
    @RequestMapping(value = "/admin/report/edit", method = RequestMethod.POST)
    public String editReport(
            @ModelAttribute("reportDto") @Valid ReportDTO report,
            BindingResult result,
            SessionStatus status) {
// ...

En el ejemplo, la misma URL, /admin/report/edit, es manejada por diferentes métodos del controller según que annotation se use. Típicamente en el GET se devolvería el formulario de edición con los datos cargados y en el POST se haría la edición según las modificaciones ingresadas por el usuario.

24/11/2011

Launch4j: Crear Ejecutable de Windows para una Aplicación Java

Archivado en: computacion,Java,linux,Programación,software,Tecnología,ubuntu,windows — ignorante @ 19:00
Tags: ,
Launch4j

Launch4j

Para simplificar la ejecución en Windows de un programa hecho en Java, launch4j permite transformar un archivo JAR en un archivo EXE con un enorme grado de flexibilidad.

No hace falta ni siquiera tener Windows; se puede generar el archivo EXE desde otro sistema operativo como Ubuntu. Simplemente hay que bajar la versión de launch4j correspondiente al sistema operativo que estemos usando.

Hay que tener en cuenta que si se está usando la versión de Ubuntu de 64 bits hay que instalar la biblioteca libc de 32 bits. En Ubuntu 11.10 (Oneiric Ocelot) el paquete es libc6:i386 y se puede instalar desde Synaptic o con este comando:

sudo apt-get install libc6:i386

El resultado es muy bueno. Se genera un archivo ejecutable nativo de Windows que funciona en todas las versiones de ese sistema y detecta solo si está instalada la máquina virtual Java en la PC del usuario.

Ejemplos de ejecutables generados con esta herramienta:

28/10/2011

NetBeans: el IDE que se Autoanaliza

Archivado en: computacion,Java,Programación,software — ignorante @ 1:03
Tags: , , ,
Botón para que Netbeans se autoanalice

Botón para que Netbeans se autoanalice

En los últimos a años el entorno de desarrollo NetBeans respondió a la competencia que representa Eclipse y mejoró en muchísimos aspectos, entre los que se destaca el soporte para diferentes lenguajes (hoy PHP, C/C++, Ruby y Groovy están perfectamente integrados a NetBeans). Pero un aspecto clave para muchos es el rendimiento y para lograr mejoras es fundamental identificar dónde hay margen para mejorar.

Así que NetBeans se puede autoanalizar (realizar un sampling profiling de si misma al vuelo) y mostrar los resultados desde su propia interfaz mientras la usamos. ¡Cuántas veces quisiera hacer eso mientras uso otros programas!

Resultado del Profiling de NetBeans

Resultado del Profiling de NetBeans

Realmente en las últimas versiones se han notado mejoras en rendimiento. Más tareas se realizan en segundo plano sin interferir al usuario y hay menos operaciones que tomen mucho tiempo.

Además el profiler que viene integrado con NetBeans es excelente. Lo he usado para analizar código que nunca antes había visto  y en nada de tiempo me permitió detectar los tres o cuatro métodos donde había mucho margen para hacer optimizaciones.

Incluso muchas veces importo proyectos de Eclipse con el único objetivo de pasarlos por el profiler de NetBeans.

23/10/2011

Evitar que se Cierre una Aplicación Java / Swing

Archivado en: computacion,Java,Programación,Tecnología — ignorante @ 8:00
Tags: , ,

A veces es necesario evitar que el usuario cierre la aplicación mientras se está realizando un procesamiento o simplemente queremos que confirme que es verdaderamente si intención salir en ese momento


public class MyApp extends JFrame {
    public MyApp() {
        super("MyApp");
        this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                if(!model.isProcessing()){
                    setVisible(false);
                    dispose();
                }else{
                    JOptionPane.showMessageDialog(
                            MyApp.this, "Espere a que terminemos de procesar..."));
                }
            }
        });
    }
}

En el ejemplo  suponemos que hay una variable de instancia “model” que nos permite saber si la aplicación está en condiciones de ser cerrada o no.

El salir de la aplicación ocurre al hacer dispose() del último o único JFrame que está visible siempre y cuando estén dadas las demás condiciones para que la aplicación termine. Es importante asignar DO_NOTHING_ON_CLOSE como operación de cerrado por defecto para poder definir nosotros qué pasa cuando el usuario quiere cerrar.

21/10/2011

Algunas de las Razones del Éxito de Java

Archivado en: computacion,Java,Programación,software — ignorante @ 8:00
Tags: , , ,

Java es un lenguaje muy criticado desde todos los ángulos. Que es lento, que no sirve para cierta tarea, que no soporta tal cosa o que es el nuevo COBOL. Muchas críticas más. Sin embargo, con todos sus defectos es uno de los lenguajes de programación más exitosos. Pero, ¿por qué?

No hay un solo motivo, claro está, pero pienso que uno de los más importantes es retrocompatibilidad. Un programa hecho para la versión de Java 1.0 requiere ningún cambio para ejecutarse en una versión posterior de Java. Esto contrasta fuertemente con otros lenguajes que introducen cambios incompatibles con cada nueva versión, obligando a tener que ejecutarse con una determinada versión de su intérprete o máquina virtual.

Python

Python es un ejemplo. En este artículo se detallan algunas de las cuestiones que se deben tener en cuenta a la hora de escribir código que se piensa algún día migrar a Python 3.0. Esto hace que muchas bibliotecas de funciones queden atadas a cierta versión de Python, creando una situación muy poco deseada: para usar cierta biblioteca debo usar yo la versión de Python compatible o esperar a que migren la biblioteca.

PHP

PHP es el ejemplo más patético de este problema. Introdujeron varios cambios incompatibles de la versión 3 a la 4, de la 4 a la 5 y de la 5 a la 6. Y como cada nueva versión de PHP requiere que se escriba el código de otra forma, los frameworks tampoco se esfuerzan en mantener compatibilidad. Un programa hecho con Symfony 1.0 no funciona en ninguna versión posterior. En general un programa hecho con Symfony N va a requerir que se tenga instalada la versión N de Symfony (y la de PHP correspondiente) para siempre mientras esté en uso. Existe la posibilidad (desde Symfony 1.2) de migrar el proyecto, pero se requiere volver a probarlo, revisar que haya quedado todo bien y en general tener mucha suerte de no haber hecho nada que no esté contemplado por el migrador.

La clave para que Java haya podido lograr esa compatibilidad está en que los cambios que se introducen (que han sido muchísimos a lo largo de los años) son propuestos, analizados y aprobados por expertos en el área.

Otra ventaja de dar participación a expertos en las decisiones sobre el lenguaje favorece a que no se meta la pata tan seguido. Por ejemplo, Java desde el día 0 soporta Unicode. Esto facilitó su adopción en el mundo y le ahorró a todos los programadores innumerables problemas. Hoy, a más de 15 años de su primera versión,  Python 3.0 y PHP 6 finalmente están incorporando Unicode, claro que sumando una nueva incompatibilidad.

20/10/2011

Finalizar Aplicación Java / Swing sin Recurrir a System.exit()

Archivado en: computacion,Java,Programación,software — ignorante @ 8:00
Tags: , ,

La máquina virtual Java termina su ejecución cuando todos los threads que están corriendo son demonios. En particular el thread main (en el que corre nuestro programa apenas arranca) no es un demonio, por lo que mientras se ejecuta, la JVM sigue corriendo.

Cuando abrimos un JFrame de Swing arranca el EDT que es otro thread que no es demonio.

Ningún thread creado por nuestro código es demonio a menos que se lo indique explícitamente con el método setDaemon(true).

Entonces cuando el usuario nos indica que quiere salir de nuestra aplicación o por cualquier circunstancia deseamos terminar la ejecución nos basta con hacer que tanto el thread main, el EDT y todos los thread que creamos terminen.

En general el thread main ya no se está ejecutando cuando arrancamos el EDT (ya se ejecutó la última instrucción del método main). Los thread que creamos deben llegar la última instrucción del método run (habrá que revisar la lógica de cada uno si es que hay algún bucle o está esperando recursos).

Pero ¿cómo finalizar el EDT, si es el thread que está permanentemente esperando los eventos del usuario?

El EDT finaliza cuando se destruye el último componente visual de nivel superior (JFrame o  JDialog) de Swing. Entonces, por ejemplo si nuestra aplicación es un JFrame, basta con hacer

this.setVisible(false);
this.dispose();

Si ese JFrame es el último (o único), entonces el EDT termina y la JVM también. Si hay más instancias de JFames o JDialog abiertas por ahí, habrá que hacerlo con cada una.

Recurrir a System.exit() para salir de la aplicación de escritorio es como usar el administrador de tareas del sistema operativo para cerrar los programas.

Si pensamos un poco en el flujo natural del control de nuestra aplicación, no lo necesitaremos ni siquiera para salir en caso de errores fatales.

La desventaja es que si tenemos varios System.exit() diseminados por todo el código no tenemos forma de asegurarnos que antes de salir, se haga determinada tarea (borrar archivos temporales, imprimir algún mensaje, pedir confirmación al usuario, etc.) Habrá que hacerla en cada punto donde se quiera salir.

19/10/2011

Swing y el EDT

Archivado en: Java,Programación — ignorante @ 8:00
Tags: , ,

Una de las primeras cosas que hay que saber al empezar a programar aplicaciones de escritorio en Java con Swing es que el thread main que arranca cuando se ejecuta el método main de nuestra aplicación no es el mismo thread en el que se ejecutan los eventos que dispara el usuario al interactuar con nuestra aplicación.

De hecho, si en tu aplicación haces algo así:

public static void main(String args[]){
    new MyApp().setVisible(true);
}

entonces el thread main termina inmediatamente después de poner visible el JFrame.  Al hacerlo queda corriendo el thread de Swing, también conocido como EDT (por Event Dispatch Thread). La aplicación continuará corriendo mientras quede ese thread activo independientemente de que el thread main ya esté finalizado.

El tema es que los objetos de Swing no admiten ser manipulados desde otro thread que no sea el EDT, entonces llamar al método setVisible(true) desde el thread main es incorrecto. Para ejecutar código en el thread de Swing tenemos que hacerlo indirectamente:

public static void main(String args[]){
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            new MyApp().setVisible(true);
        }
    });
}

De esa forma el método run() del objeto Runnable que creamos se va a ejecutar en el EDT, tal como se ejecutan los eventos que dispara el usuario.

Hay que estar siempre atentos para evitar manipular objetos de Swing en threads que no sean el EDT, ya sea el thread main o en otro thread que hayamos creado nosotros.

Página siguiente »

Tema Rubric. Blog de WordPress.com.

Seguir

Get every new post delivered to your Inbox.

Únete a otros 28 seguidores