Playing with JerseyTest (Jersey 2.5.1 and DI)

I’m going to try explaining a trivial REST example. The idea is building a basic schema to start playing with Jersey. When I begin to use some framework, I usually develop a test enviroment for failing fast, and that is what I’m going to do.

The next example has these features:

  • Jersey 2.5.1
  • Dependency Injection
  • JUnit for testing

Classes:

  • Resource: it will attend the HTTP calls.
  • Service: it’s an interface with two implementations, Impl1 and Impl2.
  • ServiceProvider: it will give the apropiate implementation of Service per each request call in runtime.
  • TestBinder: it set the bindings into the Resource.

 


import static org.junit.Assert.assertEquals;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Response;

import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;

public class JerseyInjectionTest extends JerseyTest {

	private static final String EXPECTED_CONTENT = "any string :P";

	/**
	 * Checks that the Resource uses Impl1.class
	 */
	@Test
	public void invokeImpl1(){
		invoke(Impl1.class);
	}
	
	/**
	 * Checks that the Resource uses Impl2.class
	 */
	@Test
	public void invokeImpl2(){
		invoke(Impl2.class);
	}
	
	/**
	 * Checks that Resource.anyContent has always the value of EXPECTED_CONTENT
	 */
	@Test
	public void checkContent(){
		Response response = target("example/content").request().get();
		assertEquals(EXPECTED_CONTENT, response.readEntity(String.class));
	}
	
	private <T extends Service> void invoke(Class<T> service){
		final String serviceName = service.getName();
		Response response = target("example/"+serviceName).request().get();
		assertEquals(service.getName(), response.readEntity(String.class));
	}
	
	/**
	 * Register the Resource and TestBinder in the Application
	 */
	@Override
	protected Application configure() {
		return new ResourceConfig() {
			{
				register(new TestBinder());
				register(Resource.class);
			}
		};
	}

	@Path("/example")
	public static class Resource {

		@Inject
		Service service;
		@Inject
		String anyContent;

		/**
		 * Returns the name of the Service's implementation
		 */
		@GET
		@Path("/{serviceClass}")
		public Response getDynamicInvokedService() {
			return Response.ok(service.getClass().getName()).build();
		}

		/**
		 * Returns always the value of anyContent
		 */
		@GET
		@Path("/content")
		public Response getStaticContent() {
			return Response.ok(anyContent).build();
		}

	}
	
	/**
	 * This class will help Resource to set the @Inject fields.
	 */
	public static class TestBinder extends AbstractBinder{

		@Override
		protected void configure() {
			bindFactory(ServiceProvider.class).to(Service.class);
			bind(EXPECTED_CONTENT).to(String.class);
		}
		
	}

	/**
	 * This class will instance a Services's implementation
	 * per each time that the Resource is called.
	 */
	@RequestScoped
	public static class ServiceProvider implements Factory<Service> {

		private final String serviceName;

		public ServiceProvider(@PathParam("serviceClass") String serviceName) {
			this.serviceName = serviceName;
		}

		@Override
		public void dispose(Service arg0) {}

		@Override
		public Service provide() {
			try {
				return (Service) Class.forName(serviceName).newInstance();
			} catch (Exception e) {
				return null;
			}
		}

	}

	/**
	 * Dummy services
	 */
	public static interface Service {}
	public static class Impl1 implements Service {}
	public static class Impl2 implements Service {}

}

Now we can try new features easily.

I hope that helps.

Detecting and Fixing XSS using OWASP tools

Much have been written about XSS vulnerabilities scanning. In this article we will try to go a little further and show how to fix them.

To illustrate the whole process, going from initial detection to providing a fix, we will use a very simple app consisting of two JSP pages: one is a payment form for credit card transactions and contains some XSS exploitable code. The other one has such code fixed: the later is just a patched version of the former. We will see how an attacker could trick users, exploiting the present XSS vulnerability, to collect their credit card data.

(Download vulnerable app)

XSS Attacks

 

The goal of XSS attacks is to have a injected script executed by the user web browser. In most cases, user is not even aware of what is going on. For further information about XSS please have a look at OWASP XSS Attack Description.

Let us have a look at our sample app. The vulnerable JSP (xss_html.jsp) contains the following code fragment:


<% 
final String amount = request.getParameter("amount"); 
Enumeration pNames = request.getParameterNames(); 
while (pNames.hasMoreElements()){     
   final String pName = pNames.nextElement();     
   final String pVal = request.getParameter(pName);     
%>
    <input type="hidden" name="<%=pName%>" />" value="" />;</pre>
<table>
<tbody>
<tr>
<td>Credit card</td>
<td><input type="text" maxlength="16" name="cc" size="16" value="" /></td>
</tr>
<tr>
<td>Exp Date (mm/yy)</td>
<td><input type="text" maxlength="2" name="expMonth" size="2" value="" />
/<input type="text" maxlength="2" name="expYear" size="2" value="" /></td>
</tr>
<tr>
<td>CVV2</td>
<td><input type="text" maxlength="2" name="expMonth" size="2" value="" />
/<input type="text" maxlength="2" name="expYear" size="2" value="" /></td>
</tr>
<tr>
<td colspan="2"><input id="button1" type="submit" name="button1" value="Pay" /></td>
</tr>
</tbody>
</table>

The form receives amount to charge as an HTTP Request parameter, collects credit card data form user and them charges her (of course, such last step is not included, you can try with any non-real credit card data). Users could be redirected here from any ecommerce site using a URL such as http://……/XSS_Vulnerable/xss_html.jsp?amount=12.25 (again, nobody would choose such a path for a payment gateway pretending to be a trusted one). But let us see what happens if an attacker tricks someone into loading a malicious URL as the one included in index.jsp instead when the user press Pay button (Firefox 24.0 for Linux):

firefox_vulnerable

Just an alert, but injected Javascript code could have created an image or some other kind of link, so the attacker would have been able to collect the data by just looking at Apache access logs. Indeed, some browsers are able to identify such threats and will not execute injected scripts, as shown (Chromium 28.0 for Linux).

chrome_refuses_exec_script

XSS Detection

 

Fortunately, there are a lot of tools that perform XSS threats scanning so, for the most common issues, there is no need to look at every line of code in every web page when trying to locate such vulnerabilities. One of those tools is OWASP Zed Attack Proxy Object (ZAP). Although it would not be fair to say it is just a XSS scanner, as it provides many many more interesting features.

ZAP can be used as a proxy (indeed, it is based on older Paros Proxy) being able to scan all pages accesed during the session. However, we are just going to introduce the URL( http://……/XSS_Vulnerable/xss_html.jsp?amount=12.25) and press the Attack button (we are using ZAP 2.2.2). To avoid several warnings and making scanning faster we disabled all scan types except for XSS.

ZAP_XSS_vulnerable

Starting from provided URL ( http://……/XSS_Vulnerable/xss_html.jsp?amount=12.25) ZAP has made several checks adding javascript code to be injected.

The tab at the bottom shows one successful attempt of a XSS attack. ZAP has replaced the numeric value of amount parameter by and URL encoded javascript code (as seen in URL field) which is just “><script>alert(1);</script> in plain text (as seen in Evidence field).

Moreover, in the tab above, where HTTP response is shown, the result of the XSS attack is clearly shown: the injected code in amount parameter first closes the double quotes (“) around value for amount field and closes HTML input (>). Afterwards, it adds the script alert(1); (<script>alert(1);</script>). The resulting HTML code to be executed by web browser contains:

<input type="hidden" name="amount" value=""><script>alert(1);</script>" />

XSS Fix

 
Although there is not a single fix for all XSS attacks, all of them are based on input validation, where “input” could be any from HTTP Request parameters, HTTP Headers values or even names… all depends on what the code uses as input.

In our sample app, a HTTP Request parameter is being used to write HTML code.

OWASP provides OWASP Enterprise Security API (ESAPI) in several languages, including, of course Java. ESAPI includes much more functionality related to security, from XSS and CSRF to crypto.

To fix our XSS vulnerability, we are just using a ESAPI encoder (ESAPI 2.1.0). The fix is based on writing the received amount parameter HTML encoded instead of as just received. This way, the user web browser will not execute the javascript code, as it will be seen as the value of the amount parameter.

The fix requires just HTML encoding the amount parameter (see xss_html_esapi.jsp) as follows:

<form method="POST" name="sendForm" id="sendForm" onsubmit="return sendPaymentRequest()">

<%
final String amount = request.getParameter("amount");
Enumeration<String> pNames = request.getParameterNames();
while (pNames.hasMoreElements()){
    final String pName = pNames.nextElement();
    final String pVal = request.getParameter(pName);

    final org.owasp.esapi.Encoder esapiEnc = DefaultEncoder.getInstance();
    final String encPVal = esapiEnc.encodeForHTML(pVal);

    %>
    <input type="hidden" name="<%=pName%>" value="<%=encPVal%>" />
    <%
}
%>

<table>

Running ZAP against fixed JSP (xss_html_esapi.jsp) does not report XSS Vulnerabilities.

Sustainable peace with database changes into a Java environment

12/08/2013 Leave a comment

Sustainable peace for us is remove uncertainty. In this case over database changes the idea Active Record Migrations of Ruby was welcomed.

And what does migration means for us?. Well, it is a convenient way to alter our database schema overtime in a consistent and easy way that removes a lot of uncertainty about database changes in our software development process.

Goal

Our goal will be maintaining the lifecycle of the database according to the development and evolution of the project with an absolute control over the changes.

For this we have to look for a simple tool with a basic group of characteristics as the following ones:

  • Works with any database although now our database is MySQL.
  • Enable concurrent developers to work independently.
  • Enable different development environments.
  • Able to integrate with any version control system.
  • Able to integrate easily migration tasks into Apache Ant.
  • Allow forward and backward migrations and conflicts easily manageable.

We select MyBatis Migrations tool as the best solution for us and a GitHub repository Ant Script to run MyBatis Migrations’ commands as a start line.

Let’s go to the point: How we work with migrations

With these tools we think that a lifecycle of migration may be like this one

The first time
  • Create a migrations directory into our project directory.
  • Download MyBatis Schema migrations file mybatis-migrations-3.1.1-bundle.zip.
  • Create a lib directory and copy mybatis-3.2.3.jar and mybatis-migrations-3.1.1.jar files.
  • Download Ant tasks build.properties and build.xml files from mybatis-migrations-anttasks-master.zip and rename it as migrations.properties/xml for clearer goals.
  • Obviously, this files define ant tasks and basic properties for migrations tool while migrations.properties (comments are included for clearly) defines
    
    # Default environment
    mybatis.default.environment=development
    
    mybatis.dir=migrations
    mybatis.lib.dir=${mybatis.dir}/lib
    
    mybatis.repository.dir=${mybatis.dir}/db
    
    # This directory contains your migration SQL files. These are the files 
    # that contain your DDL to both upgrade and downgrade your database 
    # structure. By default, the directory will contain the script to 
    # create the changelog table, plus one empty example migration script. 
    mybatis.scripts.dir=${mybatis.repository.dir}/scripts
    
    # Place your JDBC driver .jar or .zip files in this directory.
    # Upon running a migration, the drivers will be dynamically loaded.
    mybatis.drivers.dir=${mybatis.repository.dir}/drivers
    
    # In the environments folder you will find .properties files that 
    # represent your database instances. By default a development.properties 
    # file is created for you to configure your development time database 
    # properties.
    # You can also create test.properties and production.properties 
    # files. The properties file is self documented.
    mybatis.env.dir=${mybatis.repository.dir}/environments
    
    

    and migrations.xml defines ant tasks as you can see in the original documentation. Of course, you must rename it as xml file descriptor property to load it

    <?xml version="1.0" encoding="UTF-8"?>
    <project name="MyBatis Migrations" basedir="." 
             default="db:migrate:status">
    
    	<property file="migrations/migrations.properties" />
    
    .....
    </project>
    
  • But, how to install it … It’s easy, basically we have to execute:
    $ ant -f migrations.xml db:migrate:init
    

    It creates directories and the initial files as they were defined in migrations.properties as you can see in this output log

    Buildfile: /wpr/myproject/migrations/migrations.xml
    
    db:migrate:init:
         [echo] ** Executing "migrate init" on "development" environment **
         [java] ------------------------------------------------------------
         [java] -- MyBatis Migrations - init
         [java] ------------------------------------------------------------
         [java] Initializing: db
         [java] Creating: environments
         [java] Creating: scripts
         [java] Creating: drivers
         [java] Creating: README
         [java] Creating: development.properties
         [java] Creating: bootstrap.sql
         [java] Creating: 20131123174059_create_changelog.sql
         [java] Creating: 20131123174100_first_migration.sql
         [java] Done!
         [java] 
         [java] ------------------------------------------------------------
         [java] -- MyBatis Migrations SUCCESS
         [java] -- Total time: 2s
         [java] -- Finished at: Sat Nov 23 18:41:00 CET 2013
         [java] -- Final Memory: 1M/117M
         [java] ------------------------------------------------------------.
    
    BUILD SUCCESSFUL
    Total time: 3 seconds
    

    while

    • environments, scripts and drivers are directories (as seen before).
    • README, that explains directories contents as the name suggests.
    • bootstral.sql, in which you have to include the database actual schema. You need to start from a known state.
    • 20131123174059_create_changelog.sql contains a default control table for migration tool. It’s a price that you have to pay.
    • 20131123174100_first_migration.sql will be your first SQL migration file. You can delete it or rename it for clearly although you must keep the format as yyyymmddHHMMss_.
  • Keep migrations/db/environment/development.properties database properties for development environment
    ## JDBC connection properties. 
    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/<databaseName>
    username=root
    password=root
    
  • Add others environment properties files to each migrations/db/environment/<environment>.properties if you need.
  • As last step, put your actual database schema into bootstrap.sql file.
Day by day

Among all migrate commands we normally use

Optional steps included:

  • Revert migrations if necessary to solve conflicts. Any mistake has an easy solution with db:migrate:down .. but remember that it is by single steps.
  • Apply pending migrations out of order if it’s safe to do so with db:migrate:pending or db:migrate:version. Actually, if you want to execute those tasks you will have to add the code belong into migrations.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <project name="MyBatis Migrations" basedir="." default="db:migrate:status">
    ....
    
    	<!-- $ migrate pending -->
    	<target name="db:migrate:pending" description="Runs all pending migrations regardless of their order or position in the status log">
    		<migrate command="pending" environment="${environment}" />
    	</target>
    
    	<!-- $ migrate version -->
    	<target name="db:migrate:version" description="Migrate the schema to any specific version">
    		<input addproperty="specific.version" message="Specific version to migrate:" />
    		<migrate command="version" environment="${environment}">
    			<extraarguments>
    				<arg value="${specific.version}" />
    			</extraarguments>
    		</migrate>
    	</target>
    
    </project>
    
  • Generate migration scripts to be run “offline” in environments that are beyond your control.
  • Get the status of the system at any time doing db:migrate:status.

We hope you find useful our solution, all comments are welcomed and apologies for my english.

Hacer un proxy de un objeto

Estaba ojeando la parte de reflexión de Guava y he descubierto lo facil que es hacer un Proxy de un Objeto. El inconveniente es que solo se pueden hacer proxys de una interfaz, pero hay forma de poderlo apañar.

Por ejemplo, Date no es ninguna interfaz, y quiero hacer fechas que tengan los milisegundos a cero. Para ello me hago una interfaz Proxy que voy a rellenar con mi nuevo codigo.


import static org.junit.Assert.assertEquals;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;

import org.junit.Test;

import com.google.common.reflect.Reflection;

public class ProxyTest {

	@Test
	public void dateZeroMillis() {
		Date withMillis = new Date();
		@SuppressWarnings("unchecked")
		Proxy<Date> proxyObject = Reflection.newProxy(Proxy.class,
				new RemoveMillis(withMillis));
		Date date = proxyObject.get();
		System.out.println("Date was: " + withMillis.getTime()
				+ " but now is: " + date.getTime());
		assertEquals(0, date.getTime() % 1000);
	}

	public static class RemoveMillis implements InvocationHandler {

		private Date date;

		public RemoveMillis(Date date) {
			this.date = date;
		}

		@Override
		public Object invoke(Object proxy, Method method, Object[] args)
				throws Throwable {
			return new Date((date.getTime() / 1000) * 1000);
		}

	}

	public static interface Proxy<T> {
		T get();
	}
}

La salida del test es esta:
Date was: 1383914151227 but now is: 1383914151000

Categories: Uncategorized

Chain of responsibility eventbus

Hoy vengo a hablar de una nueva librería java que resuelve una limitación del patrón Cadena de responsabilidad:

http://es.wikipedia.org/wiki/Chain_of_Responsibility_%28patr%C3%B3n_de_dise%C3%B1o%29

Haciendo un breve resumen, con este patrón podemos modularizar nuestro código. Esto es bueno, porque obligamos a desarrollar el contenido en pequeñas partes, para luego ser reutilizado, eliminado y añadido mas facilmente. Estas pequeñas partes se ejecutarán en un orden, una detrás de otra, hasta que la cadena termine o un eslabón decida que no quiere continuar con la cadena.

Los eslabones no deberian tener referencias a otros eslabones concretos, porque estariamos rompiendo la modularidad. Generalmente, tienen una referencia al siguiente eslabón, pero se maneja en forma de interfaz.

El problema es el siguiente

Este patrón funciona muy bien cuando hay que desarrollar una serie de acciones aisladas, que poco tienen que ver unas con otras, ¿pero que pasa si algun eslabón necesita de un objeto que ya ha sido recuperado previamente por otro eslabón?. Con la habitual implementación habría que volverlo a recuperar. Esto puede ser lento y se puede repetir en muchas ocasiones a lo largo de toda la cadena.

Esta nueva librería aporta una solución sencilla a este problema. Consiste en la posibilidad de que las diferentes cadenas puedan postear cualquier objeto a un bus de eventos. El propio bus de eventos se encargará de asignar esos objetos al resto de eslabones que esten suscritos a objetos de ese tipo.

Os dejo el link:

https://code.google.com/p/chain-of-responsibility-eventbus/

Categories: Uncategorized

Programación orientada a aspectos con Guice

Me gusta la programación orientada a aspectos por la cantidad de ifs que te quita. Ademas son ifs que tienes que ir repitiendo a lo largo del código.
Se me ha ocurrido hacer un pequeño ejemplo con JUnit. Vamos a hacer las tipicas comprobaciones de:

Las vamos a hacer de las dos formas, con aspectos y sin aspectos, demostrando que el resultado es el mismo, pero con aspectos queda mas limpio.

Antes de empezar con el Test, hay que configurar Shiro. Explicandolo por encima, tenemos un fichero que se llama shiro.ini, donde he definido los usuarios con su rol.

[users]
root = secret, admin
guest = guest, guest

[roles]
admin = *

También hay que configurar el modulo de Shiro para Guice, donde se le dice que se configure en base al contenido de shiro.ini:

package com.tododev.shiro;

import org.apache.shiro.config.Ini;
import org.apache.shiro.guice.ShiroModule;
import org.apache.shiro.realm.text.IniRealm;

import com.google.inject.Provides;

public class MyShiroModule extends ShiroModule{

	protected void configureShiro() {
        try {
            bindRealm().toConstructor(IniRealm.class.getConstructor(Ini.class));
        } catch (NoSuchMethodException e) {
            addError(e);
        }
    }

    @Provides
    Ini loadShiroIni() {
        return Ini.fromResourcePath("classpath:shiro.ini");
    }

}

Ahora vamos ya con el test. Este test contiene 4 metodos de test, que comprueban lo siguiente sobre el método de la interfaz Interface.doSomething:

  • Si no estas autenticado lanza una UnauthenticatedException.
  • Si no tienes el rol de “admin” lanza una UnauthorizedException.
  • Si le pasas el parámetro a nulo lanza una ConstraintViolationException.
  • Si estas autenticado, con el rol de “admin” y no pasas el parámetro a nulo, no lanza excepciones.

La gracia es que el test lo vamos a hacer con dos implementaciones diferentes de Interface.class:

  • Aop.class
  • NoAop.class

Es decir, se van a hacer 2 x 4 = 8 tests. El resultado tiene que se el mismo.


package com.tododev.shiro;

import static org.junit.Assert.fail;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.constraints.NotNull;

import org.apache.bval.guice.Validate;
import org.apache.bval.guice.ValidationModule;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.guice.aop.ShiroAopModule;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;

/**
 * Vamos a hacer que el test se ejecute con la clase Parameterized. Esta clase
 * nos ejecutara 2 veces todos los tests, insertando en el constructor los
 * valores del metodo data().
 * 
 * @author jorge
 * 
 */
@RunWith(Parameterized.class)
public class GuiceAopTest {

	private final static String ADMIN_ROLE = "admin";
	private final UsernamePasswordToken ADMIN = new UsernamePasswordToken(
			"root", "secret");
	private final UsernamePasswordToken GUEST = new UsernamePasswordToken(
			"guest", "guest");
	private final Injector injector;

	/**
	 * Cuando se crea la instancia de GuiceAopTest.class, se le inserta uno de
	 * los valores del metodo data().
	 * 
	 * @param injector
	 */
	public GuiceAopTest(Injector injector) {
		this.injector = injector;
	}

	/**
	 * Devuelve una coleccion que contiene un inyector con AOP y otro que no. La
	 * idea es demostrar que los tests pasan satisfactoriamente de las dos
	 * formas posibles.
	 * 
	 * @return
	 */
	@Parameters
	public static Collection<Object[]> data() {
		Injector withAop = Guice.createInjector(new ShiroAopModule(),
				new MyShiroModule(), new ValidationModule(),
				new AbstractModule() {
					@Override
					protected void configure() {
						bind(Interface.class).to(Aop.class);
					}
				});
		Injector noAop = Guice.createInjector(new MyShiroModule(),
				new AbstractModule() {
					@Override
					protected void configure() {
						bind(Interface.class).to(NoAop.class);
					}
				});

		Object[][] data = { { noAop }, { withAop } };
		return Arrays.asList(data);
	}

	public static interface Interface {
		void doSomething(String value);
	}

	/**
	 * Implementacion preparada para tener aspectos.
	 * 
	 * @author jorge
	 * 
	 */
	public static class Aop implements Interface {

		@Validate
		@RequiresRoles(ADMIN_ROLE)
		@Override
		public void doSomething(@NotNull String value) {
			System.out.println(getClass() + ": " + value);
		}

	}

	/**
	 * Hace lo mismo que hace Aop, pero esta no usara aspectos.
	 * 
	 * @author jorge
	 * 
	 */
	public static class NoAop implements Interface {

		@Override
		public void doSomething(String value) {
			if (value != null) {
				Subject currentUser = SecurityUtils.getSubject();
				if (currentUser.isAuthenticated()) {
					if (currentUser.isPermitted(ADMIN_ROLE)) {
						System.out.println(getClass() + ": " + value);
					} else {
						throw new UnauthorizedException();
					}
				} else {
					throw new UnauthenticatedException();
				}
			} else {
				throw new ConstraintViolationException(
						new HashSet<ConstraintViolation<?>>());
			}
		}

	}

	/**
	 * Preparamos Shiro para ser usado.
	 */
	@Before
	public void before() {
		SecurityManager securityManager = injector
				.getInstance(SecurityManager.class);
		SecurityUtils.setSecurityManager(securityManager);
	}

	/**
	 * Deslogueamos al usuario si estuviera logueado.
	 */
	@After
	public void after() {
		Subject currentUser = SecurityUtils.getSubject();
		currentUser.logout();
	}

	/**
	 * Vefirica que si no estas logueado salta una UnauthenticatedException
	 */
	@Test(expected = UnauthenticatedException.class)
	public void unauthenticated() {
		Interface classToTest = injector.getInstance(Interface.class);
		classToTest.doSomething("any value");
		fail("Unreachable code");
	}

	/**
	 * Verifica que si no tienes los permisos adecuados salta una
	 * UnauthorizedException
	 */
	@Test(expected = UnauthorizedException.class)
	public void unauthorized() {
		Subject currentUser = SecurityUtils.getSubject();
		currentUser.login(GUEST);
		Interface classToTest = injector.getInstance(Interface.class);
		classToTest.doSomething("any value");
		fail("Unreachable code");
	}

	/**
	 * Verifica que si llamas al metodo con el String nulo, salta una
	 * ConstraintViolationException
	 */
	@Test(expected = ConstraintViolationException.class)
	public void constraintViolation() {
		Subject currentUser = SecurityUtils.getSubject();
		currentUser.login(ADMIN);
		Interface classToTest = injector.getInstance(Interface.class);
		classToTest.doSomething(null);
		fail("Unreachable code");
	}

	/**
	 * Verifica el caso de que todo es correcto y no hay excepciones
	 */
	@Test
	public void allowed() {
		Subject currentUser = SecurityUtils.getSubject();
		currentUser.login(ADMIN);
		Interface classToTest = injector.getInstance(Interface.class);
		classToTest.doSomething("any value");
	}

}


El resultado de los test es este:


Los 8 tests han pasado bien.

Este es el resultado que se muestra en la consola:

class com.tododev.shiro.GuiceAopTest$NoAop: any value
class com.tododev.shiro.GuiceAopTest$Aop$$EnhancerByGuice$$4ee6b586: any value

Os podeis fijar que la clase Aop “ha sido mejorada” por Guice, añadiendole los aspectos de Shiro y BVal. Lo curioso es que en las clases compiladas vemos lo siguiente:


La clase que aparece señalada debería llamarse GuiceAopTest$Aop$$EnhancerByGuice$$4ee6b586, pero se llama GuiceAopTest$Aop. Esto es porque Guice no hace los aspectos en tiempo de compilación, sino en ejecución. Esto tiene algunas limitaciones, pero en muchos casos resulta ser suficiente.

En conclusión:

Se puede comprobar lo limpio que queda el código usando aspectos. Así es mas fácil ver qué es lo que hace el método doSomething(). Además, esas anotaciones las podemos aprovechar y llevar a otros métodos que requieran esas comprobaciones.

Problema con Singletons y patron estrategia

El patron estrategia es uno de los que mas “ifs” te pueden quitar en el codigo. Un ejemplo sencillo de como funciona seria imaginar una partida de ajedrez. Sin el patron estrategia, cada vez que un jugador moviese una ficha, el programa tendria que comprobar de que ficha se trata para calcular sus posibles movimientos. Usando el patron estrategia, es la propia ficha la que sabe como moverse y asi nos ahorramos hacer las comprobaciones (ifs).

El problema es que hay veces que las diferentes estrategias cuestan mucho instanciarlas. Por ejemplo porque hace alguna llamada HTTP, o tiene que ir a base de datos a recuperar informacion al levantarse, etc. Este tipo de clases tan costosas suele ser buena idea hacerlas Singleton. El problema de los singleton, es que tienen que ser inmutables (no deberiamos modificar su contenido) o podriamos tener problemas de concurrencia. En nuestro ejemplo del ajedrez, esto supondria que tendriamos que pasar por parametros de metodo las coordenadas a donde queremos mover, en vez de por constructor. Esto seria la solucion definitiva en una partida de ajedrez, ya que solo se necesitan 2 coordenadas para posicionar una figura en el espacio, pero si se tratase del parchis necesitariamos solo 1, ya que es unidireccional. Este detalle no parece importante, pero imagina que estas en un proyecto bastante grande y tienes que estar ignorando parametros del metodo en funcion de si se trata de ajedrez o parchis.

Estaba interesado en dar una solucion flexible al problema del patron estrategia con singletons. La idea del siguiente ejemplo, es hacer que las estrategias sean lo mas limpias posibles, sin exceso de parametros y que sean singletons.

El ejemplo consiste en una interfaz, con dos implementaciones. Cada implementacion es singleton y maneja un objeto de datos diferente (DTO). He usado Guice para ello:

package com.tododev.guice;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.util.logging.Logger;

import javax.inject.Inject;
import javax.inject.Singleton;
import javax.servlet.http.HttpServletRequest;

import org.junit.Test;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Provider;
import com.google.inject.Provides;

public class StrategySingletonTest {

	private static final Logger log = Logger.getLogger(StrategySingletonTest.class.getName());
	private final Injector injector = Guice.createInjector(new MyModule());
	private final static String PARAM_1 = "paramDto1";
	private final static String PARAM_2 = "paramDto2";
	
	@Test
	public void test(){
		Logic<?> logicDto1 = injector.getInstance(LogicDto1.class);
		logicDto1.watchDto();
		
		// Comprobamos que aunque son singletons, los DTO's que instancian son diferentes
		assertNotSame(logicDto1.getInstance(), logicDto1.getInstance());
		
		Logic<?> logicDto1SameInstance = injector.getInstance(LogicDto1.class);
		
		// Comprobamos que son la misma instancia
		assertEquals(logicDto1, logicDto1SameInstance);
		
		
		Logic<?> logicDto2 = injector.getInstance(LogicDto2.class);
		logicDto2.watchDto();
		
	}
	
	
	// Dto que manejara la implementacion LogicDto1
	private static class Dto1{
		private final String field;
		public Dto1(String field) {
			this.field = field;
		}
	}
	
	// Dto que manejara la implementacion LogicDto2
	private static class Dto2{
		private final int integer;
		public Dto2(int integer) {
			this.integer = integer;
		}
	}
	
	// Definimos la forma de instanciarse Dto1
	private static class Dto1Provider implements Provider<Dto1>{

		private final HttpServletRequest request;
		
		@Inject
		public Dto1Provider(HttpServletRequest request){
			this.request=request;
		}
		
		@Override
		public Dto1 get() {
			return new Dto1(request.getParameter(PARAM_1));
		}
		
	}
	
	// Definimos la forma de instanciarse Dto2
	private static class Dto2Provider implements Provider<Dto2>{

		private final HttpServletRequest request;
		
		@Inject
		public Dto2Provider(HttpServletRequest request){
			this.request=request;
		}
		
		@Override
		public Dto2 get() {
			return new Dto2(Integer.parseInt(request.getParameter(PARAM_2)));
		}
		
	}
	
//	Decimos que los DTOs se consiguen a traves de los providers y
//	 introducimos las implementaciones de las interfaces
//	 para que guice sepa que existen
	private static class MyModule extends AbstractModule{

		@Override
		protected void configure() {
			bind(Dto1.class).toProvider(Dto1Provider.class);
			bind(Dto2.class).toProvider(Dto2Provider.class);
			bind(LogicDto1.class);
			bind(LogicDto2.class);
		}
		
//		Devuelve un mock de HttpServletRequest, que es con lo que
//		 formaremos los DTOs
		@Provides
		public HttpServletRequest getRequest(){
			HttpServletRequest request = mock(HttpServletRequest.class);
			when(request.getParameter(PARAM_1)).thenReturn("Jorge");
			when(request.getParameter(PARAM_2)).thenReturn("28");
			return request;
		}
		
	}
	
	private static interface Logic<DTO> {
		void watchDto();
		DTO getInstance();
	}
	
	@Singleton
	private static class LogicDto1 implements Logic<Dto1>{

		@Inject
		private Provider<Dto1> provider;
		
		@Override
		public void watchDto() {
			Dto1 dto = getInstance();
			log.info("I'm "+dto+" and my name is: "+dto.field);
		}

		@Override
		public Dto1 getInstance() {
			return provider.get();
		}
		
	}
	
	@Singleton
	private static class LogicDto2 implements Logic<Dto2>{

		@Inject
		private Provider<Dto2> provider;
		
		@Override
		public void watchDto() {
			Dto2 dto = getInstance();
			log.info("I'm "+dto+" and I am: "+dto.integer);
		}

		@Override
		public Dto2 getInstance() {
			return provider.get();
		}
		
	}
	
}

Esta es la salida que obtendremos:
I’m com.tododev.guice.StrategySingletonTest$Dto1@6ae441ee and my name is: Jorge
I’m com.tododev.guice.StrategySingletonTest$Dto2@5ef4f91d and I am: 28

Este es el grafo de las dependencias que tiene el inyector:

example

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: