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

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.

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.

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.

03/01/2011

Crear un JAR ejecutable autosuficiente

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

Maven permite crear un jar ejecutable autosuficiente, es decir con todas las dependencias incluidas en su interior.
En el POM hay que incluir este plugin:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>myPackage.MyMainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>

Luego ejecutar el comando:

mvn assembly:assembly

El jar obtenido se puede ejecutar haciendo doble click en él en Windows, o con

java -jar myJar.jar

Tema Rubric. Blog de WordPress.com.

Seguir

Get every new post delivered to your Inbox.

Únete a otros 28 seguidores