TIP: DebuggerDisplay

Muy buenas! Acabo de leer el post de Luis Ruiz Pavon sobre sobre el sobreescribir .ToString() para mejorar la información del modo de depuración de VS.

Y ya puestos, para complementar su post, quería comentar un truco que no se si conoce mucha gente y que permite algo parecido sin necesidad de sobreescribir ToString (que se usa para otras cosas además de para mostrar la información en la ventana de depuración) y que es el uso del atributo DebuggerDisplay.

En este caso un ejemplo vale más que mil palabras:

  1.    [DebuggerDisplay ("Product {Name} ({Code}): {Description}")]
  2.     public class Product
  3.     {
  4.         public string Code { get; set; }
  5.         public string Name { get; set; }
  6.         public string Description { get; set; }
  7.         public Product(string code, string name, string description)
  8.         {
  9.             Code = code;
  10.             Name = name;
  11.             Description = description;
  12.         }
  13.         public override string ToString()
  14.         {
  15.             return String.Format("Code – {0}", Code);
  16.         }
  17.     }

Y el resultado en la ventana de watches es:

image

Podemos conseguir cosas más interesantes utilizando las propiedades Name y TargetTypeName que modifican los valores de las columnas “Name” y “Type”. Así si uso el siguiente [DebuggerDisplay]:

  1. [DebuggerDisplay ("({Code}): {Description}", Name = "Product {Name}", Type ="Producto")]

Veo lo siguiente en la ventana de watches:

image

Y en la ventana de Locals veo, ahora, lo siguiente:

image

El uso de DebuggerDisplay tiene sus limitaciones si se compara con redefinir ToString() (este último es un método y puede contener código como el que mostraba Luis en su post para convertir a JSON), mientras que DebuggerDisplay tan solo puede generar una pequeña cadena a partir de las propiedades.

Si una clase tiene tanto ToString() redefinido como DebuggerDispay este último tiene precedencia para el depurador.

¡Y… eso es todo! 🙂

Saludos!

Sirviendo ASP.NET vNext con Nowin

Nota: Este post está realizado sobre la CTP de VS2014 y la alfa de ASP.NET vNext. Todo lo dicho puede cambiar cuando salgan las versiones RTM…

¿Conoces Nowin? Es un servidor web OWIN, es decir si construimos nuestra aplicación web basándonos en middleware OWIN (p. ej. WebApi 2 o NancyFx) podemos usar este servidor web para servirla a los clientes. Ya he hablado de OWIN varias veces antes, ya que OWIN ha sido la penúltima revolución en desarrollo de aplicaciones web en tecnología Microsot (la última es vNext, claro). Microsoft hizo un esfuerzo implementando middleware OWIN y permitiendo su integración con ASP.NET (el proyecto Katana), pero ahora sale ASP.NET vNext y es lógico preguntarse… ¿en qué queda todo?

Básicamente la pregunta es si ASP.NET vNext es compatible con OWIN y si lo es, en que terminos: ¿podemos añadir componentes OWIN al pipeline de vNext y podemos usar componentes vNext como si fuesen componentes OWIN?

La respuesta rápida a las tres preguntas es sí. ASP.NET vNext es compatible con OWIN y podemos tanto añadir componentes OWIN a nuestro pipeline de ASP.NET vNext como usar un componente vNext como si fuese middleware OWIN. De hecho cualquier otra respuesta sería totalmente incomprensible.

La idea de modularización de la aplicación en componentes que tiene ASP.NET vNext está sacada directamente de OWIN (en Katana se usa IAppBuilder lo que generó un interesantísimo debate en la comunidad).

Bueno, vayamos al tajo… intentemos ver como podemos servir una aplicación ASP.NET vNext (MVC6) pero usando un servidor OWIN como Nowin para ello. Lo primero es crear una “ASP.NET vNext Console Application” usando VS2014 CTP… Eso nos permitirá ver como hospedar ASP.NET vNext en una aplicación de consola 😉

El siguiente paso será instalar MVC6 en nuestra aplicacion. No usaremos NuGet para ello, en su lugar editaremos el fichero project.json que trae VS2104 y añadiremos las siguientes líneas en la sección dependencies:

  1. "Microsoft.AspNet.Mvc": "0.1-alpha-build-*"

Por suerte VS2014 nos ofrece intellisense al editar project.json (aunque parecen no salir todas las referencias de paquetes NuGet):

image

Ahora añade un controlador de MVC a tu aplicación (HomeController) con una acción Index que simplemente retorne la vista asociada:

  1. using Microsoft.AspNet.Mvc;
  2.  
  3. namespace NowinDemo.Controllers
  4. {
  5.     public class HomeController : Controller
  6.     {
  7.         public IActionResult Index()
  8.         {
  9.             return View();
  10.         }
  11.     }
  12. }

Una vez hecho esto añade (en la carpeta /Views/Home) la vista Index.chstml:

  1. <html>
  2. <head><title>Nowin Test</title></head>
  3. <body>
  4.     <p>Running on Nowin… @DateTime.Now.ToShortDateString()</p>
  5. </body>
  6. </html>

Ya tenemos el controlador y la vista de MVC. Tan solo nos falta “configurar” nuestra aplicación para que use ASP.NET MVC. Para ello nos creamos una clase llamada Startup:

  1. public class Startup
  2. {
  3.     public void Configure(IBuilder app)
  4.     {
  5.  
  6.         app.UseServices(services =>
  7.         {
  8.             services.AddMvc();
  9.         });
  10.  
  11.         app.UseMvc();
  12.  
  13.     }
  14. }

El siguiente paso es añadir las referencias necesarias para hospedar nuestra aplicación web y a Nowin. Para ello editamos el archivo project.json para añadir en la sección “dependencies”:

  1. "Nowin" :  "0.11.0",
  2. "Microsoft.AspNet.Owin": "0.1-alpha-build-*",
  3. "Microsoft.AspNet.Hosting": "0.1-alpha-build-*"

(Fíjate que al guardar el fichero project.json y al compilar te saldrán ya las referencias en VS2014)

Ya tenemos Nowin agregado, ahora toca configurarlo todo. Lo primero es cargar nuestra clase Startup. Eso es necesario porque es una aplicación de consola. En este caso debemos añadir el siguiente código a Program.cs:

  1. public class Program
  2. {
  3.     private readonly IServiceProvider _hostServiceProvider;
  4.  
  5.     public Program(IServiceProvider hostServiceProvider)
  6.     {
  7.         _hostServiceProvider = hostServiceProvider;
  8.     }
  9.  
  10.     public Task<int> Main(string[] args)
  11.     {
  12.         return Task.FromResult(0);
  13.     }
  14. }

Sí: es un código un poco raro para ser un programa de consola, verdad? Por un lado Program tiene un constructor que recibe un IServiceProvider y por otro el método Main no es estático si no que devuelve una Task<int>. Y esto? Esto es porque la aplicación de consola se pone en marcha a través de KRE (el runtime de ASP.NET vNext).

Bien, ahora vamos a colocar código en Main para inicializar nuestr aplicación ASP.NET vNext:

  1. var serviceCollection = new ServiceCollection();
  2. serviceCollection.Add(HostingServices.GetDefaultServices());
  3. var services = serviceCollection.BuildServiceProvider(_hostServiceProvider);

Bien, ahora que ya lo tenemos todo configurado, nos queda poner en marcha el host. Antes que nada, un pequeño recordatorio, sobre como establecíamos el servidor web usando OWIN y Katana en una aplicación de consola. En Katana usábamos el paquete Microsoft.Owin.Hosting, que define una clase llamada WebApp<T> y usábamos un código parecido a:

var options = new StartOptions
{
    ServerFactory = "Nowin",
    Port = 8080
};
using (WebApp.Start<Startup>(options))
{
    Console.WriteLine("Running a http server on port 8080");
    Console.ReadKey();
}

En este contexto la clase Startup (parámetro genérico de WebApp) era la clase de configuración de la aplicación (lo equivalente a nuestra clase Startup). Lo interesante es la la StartOptions que permitía establecer el ensamblado que contiene el servidor web (en este caso Nowin).

En vNext la idea es muy similar (cambian clases y propiedades) pero es la misma idea:

  1. var context = new HostingContext()
  2. {
  3.     Services = services,
  4.     ServerName= "Nowin",
  5.     ApplicationName = "NowinDemo",
  6. };
  7. var engine = services.GetService<IHostingEngine>();
  8. using (engine.Start(context))
  9. {
  10.     Console.WriteLine("Server waiting… ");
  11.     Console.ReadLine();
  12. }

Nota: NowinDemo es el nombre de mi ensamblado (el que contiene la clase Startup) y Nowin es obviamente el nombre del ensamblado de Nowin.

Directamente establezco que el servidor está en el ensamblado Nowin. No obstante esto no funciona:

image

La razón es que, efectivamente ASP.NET vNext intenta ir a este ensamblado para obtener un servidor, pero ahora espera un servidor vNext y no uno OWIN como Nowin. En concreto espera que haya una clase que implemente IServerFactory (interfaz de vNext).

Bueno, por suerte, no es excesivamente complejo crear dicha clase. Así pues añadimos una clase que implemente IServerFactory:

  1.     public class NowinServerFactory : IServerFactory
  2.     {
  3.         public IServerInformation Initialize(IConfiguration configuration)
  4.         {
  5.         }       
  6.         public IDisposable Start(IServerInformation serverInformation, Func<object, Task> application)
  7.         {
  8.   
  9.         }
  10.     }

El método Initialize se llama una vez al principio de la aplicación y debemos devolver una clase que implemente IServerBuilder. Dicha interfaz tan solo define una propiedad llamada Name. Vamos a crearnos una clase que nos implemente dicha interfaz:

  1. class NowinServerInformation : IServerInformation
  2. {
  3.     public string Name { get { return "Nowin"; } }
  4. }

En el método Initialize debemos instanciar el servidor Nowin y devolver un objeto IServerInformation:

  1. public IServerInformation Initialize(IConfiguration configuration)
  2. {
  3.     var builder = ServerBuilder.New()
  4.         .SetAddress(IPAddress.Any)
  5.         .SetPort(8080)
  6.         .SetOwinApp(HandleRequest);
  7.     return new NowinServerInformation();
  8. }

Nos falta el método HandleRequest (un Func<IDictionary<string, object>, Task> que espera SetOwinApp:

  1. private Task HandleRequest(IDictionary<string, object> env)
  2. {
  3.     return _callback(new OwinFeatureCollection(env));
  4. }

La variable _callback es un Func<object, Task>. Lo interesante es el uso de la clase OwinFeatureCollection (definida en Microsoft.AspNet.Owin) que ofrece un “envoltorio” tipado al diccionario de entorno de Owin.

Ahora en el método Start del objeto IServerFactory debemos devolver el componente que es el servidor. Este método recibe el IServerInformation y la definición de aplicación (es decir el conjunto de componentes del pipeline vNext) como una Func<object, Task>.  El problema ahora lo tenemos en el hecho de que debemos obtener el servidor Nowin (INowinServer) a partir del objeto IServerInformation… pero allí no lo hemos guardado. Así pues debemos redefinir dicha clase, para que nos guarde la información necesaria para ello. La idea es que la clase que implementa IServerFactory debe ser, como su nombre indica, la factoría para permitir crear el servidor a cada petición. Así pues el código final queda como sigue:

  1. public class NowinServerFactory : IServerFactory
  2. {
  3.     private Func<object, Task> _callback;
  4.  
  5.     private Task HandleRequest(IDictionary<string, object> env)
  6.     {
  7.         return _callback(new OwinFeatureCollection(env));
  8.     }
  9.  
  10.     public IServerInformation Initialize(IConfiguration configuration)
  11.     {
  12.         var builder = ServerBuilder.New()
  13.             .SetAddress(IPAddress.Any)
  14.             .SetPort(8080)
  15.             .SetOwinApp(HandleRequest);
  16.         return new NowinServerInformation(builder);
  17.     }
  18.             
  19.     public IDisposable Start(IServerInformation serverInformation, Func<object, Task> application)
  20.     {
  21.         var information = (NowinServerInformation)serverInformation;
  22.         _callback = application;
  23.         INowinServer server = information.Builder.Build();
  24.         server.Start();
  25.         return server;
  26.     }
  27.  
  28.  
  29.     private class NowinServerInformation : IServerInformation
  30.     {
  31.         public NowinServerInformation(ServerBuilder builder)
  32.         {
  33.             Builder = builder;
  34.         }
  35.  
  36.         public ServerBuilder Builder { get; private set; }
  37.  
  38.         public string Name
  39.         {
  40.             get
  41.             {
  42.                 return "Nowin";
  43.             }
  44.         }
  45.     }
  46. }

Nota: El código de esta clase es mérito de David Fowler y lo tenéis en este Gist.

Ahora ya tan solo nos queda modificar el HostContext puesto que el ensamblado que contiene el IServerFactory ya no es Nowin sino nuestra propia aplicación (NowinDemo en mi caso):

  1. var context = new HostingContext()
  2. {
  3.     ServerName= "NowinDemo",
  4.     ApplicationName = "NowinDemo",
  5.     Services = services,
  6. };

¡Y con esto ya hemos terminado! Tenemos una aplicación ASP.NET vNext MVC6 servida desde línea de comandos y usando un servidor web OWIN como Nowin para servirla (en lugar del clásico Microsoft.AspNet.Server.WebListener de ASP.NET vNext).

¿Donde está el código compilado?

Si compilas el proyecto en VS2014 CTP verás que en la carpeta Bin/Debug… no hay nada! No hay un NowinDemo.exe ni nada parecido. Las aplicaciones ASP.NET vNext, incluso si son de consola, se ponen en marcha a través del runtime de ASP.NET. Para ello se usa el comando K run “path_de_la_aplicación”.

El fichero K.cmd está donde tengas instalado el KRE. Por defecto está en %HOME%.krepackagesKRE-svrc50-x86.0.1-alpha-build-0446bin

Si no lo tienes debes añadir al path este directorio, irte donde tienes el proyecto de VS2014 (en el path raíz del proyecto donde tienes el project.json) y teclear:

K run

¡Y listos! Tu aplicación de consola ASP.NET vNext ya está en marcha!

ASP.NET vNext – IBuilder

Muy buenas! Esos días he estado jugando con VS2014 CTP. Esta versión no puede instalarse side by side con cualquier versión anterior de VS, así que la he instalado en una máquina virtual en Azure… La verdad es que es el mecanismo más rápido para probarlo, puesto que ha hay una plantilla de MV en Azure que contien VS2014 CTP. Vamos, que en cinco minutos pasas de no tener nada a estar ya trasteando con el VS2014. ¡Genial!

Una de las grandes novedades de este VS2014 es el tooling para ASP.NET vNext. Si bien ya hace algunos días que se podía descargar ASP.NET vNext y juguetear con ella, no era posible usar VS para ello, teniendo que recurrir a las herramientas de líneas de comandos.

Para ver de que se compone una aplicación ASP.NET vNext he abierto el VS2014 y he creado una nueva ASP.NET vNext web Application.

La diferencia más importante respecto a una web clásica es que ya no existen ni global.asax ni web.config. Ahora tanto los elementos de configuración que se incluían dentro de web.config como la inicialización de la aplicación que se realizaba en global.asax se unifican en un mismo archivo (que por defecto se llama Startup.cs).

Dicho archivo contiene una clase (llamada Startup) que es invocada automáticamente por el runtime de ASP.NET vNext para realizar la inicialización de la aplicación. Nos encontramos ante un nuevo ejemplo de convention over configuration. No es necesario configurar nada: crea una clase llamada Startup y esa pasará a ser la clase que inicialice toda tu aplicación. Eso no es nuevo de vNext, ya en Katana ocurría algo muy similar.

Dicha clase Startup debe contener un método llamado Configure que espera un parámetro de tipo IBuilder. Dicha interfaz está definida de la siguiente manera:

    public interface IBuilder
    {
        IServiceProvider ApplicationServices { get; set; }
        IServerInformation Server { get; set; }

        RequestDelegate Build();
        IBuilder New();
        IBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);
    }

El método importante es el método Use que permite "enchufar" un componente al pipeline de tu aplicación. Ten presente que ASP.NET vNext es totalmente modular de forma que el primer paso al configurar una aplicación es enchufar todos los componentes. Así ahora, ASP.NET MVC6 es un componente, al igual que lo es WebApi 3 y al igual que lo es un sistema para autenticarnos con cookies. Si conoces Katana es exactamente la misma idea.

El método Use es muy genérico pero raras veces lo usarás directamente: lo normal es quc cada componente proporcione un método de extensión sobre IBuilder para enchufar dicho componente. Así para enchufar ASP.NET MVC usarás el método UseMvc. Pero al final todos esos métodos de extensión terminan llamando al genérico Use.

Creación de un componente (middleware) ASP.NET vNext

Vamos a ver como crear un componente (también se les llama middleware) ASP.NET vNext. Para ello agrega una clase cualquiera a tu proyecto y añádele el siguiente código:

public class UfoMiddleware
{
    private readonly RequestDelegate _next;

    public UfoMiddleware(RequestDelegate next)
    {
        this._next = next;
    }

    public async Task Invoke(HttpContext ctx)
    {
        Debug.WriteLine("UfoMiddleware::Entrada");
        await _next(ctx);
        Debug.WriteLine("UfoMiddleware::Salida");
    }
}

Eso es todo lo que necesitas para crear un middleware (componente) de ASP.NET vNext. El parámetro next del constructor te lo mandará ASP.NET vNext (y es el componente siguiente a invocar). En el método Invoke realizas las acciones que quieras y luego llamas de forma asíncrona al middleware siguiente. Por supuesto puedes colocar código cuando el middleware siguiente ha terminado su ejecución (pero ten presente que el middleware siguiente llamará al siguiente y así sucesivamente). Así, si tienes 3 componentes (A, B y C) encadenados en este orden se ejecutará:

  1. El código de A de antes del await
  2. El código de B de antes del await
  3. El código de C de antes del await
  4. El código de C de después del await
  5. El código de B de después del await
  6. El código de A de después del await

Si te preguntas en qué orden se ejecutan los componentes, pues es en el orden el que estén registrados en IBuilder. Es decir el orden en que se llamen los métodos Use.

Para añadir nuestro componente en el pipeline de ASP.NET vNext podemos llamar al método Use de IBuilder:

 app.Use(next => new UfoMiddleware(next).Invoke);

Aunque lo más habitual sería que UfoMiddleware proporcionase un método de extensión sobre IBuilder:

public static IBuilder UseUfo(this IBuilder builder)
{
    return builder.Use(n => new UfoMiddleware(n).Invoke);
}

Y así podríamos llamar a app.UseUfo() en el Startup. La otra gran ventaja de los métodos de extensión es que permiten pasar parámetros de configuración a nuestro middleware. Así que bueno, lo normal es que cada componente venga con su método de extensión.

Ahora podemos modificar el método Invoke de nuestro UfoMiddleware para que haga "visible":

public async Task Invoke(HttpContext ctx)
{
    var path = ctx.Request.Path;
    if (ctx.Request.Path.Value == "/Help.ufo")
    {
        using (StreamWriter outfile = new StreamWriter(ctx.Response.Body))
        {
            outfile.Write("Generated by Ufo Middleware");
        }
    }
    await _next(ctx);
}

Si ahora ejecutamos de nuevo nuestra aplicación y vamos a la URL /Help.ufo (ojo, que esa url es case-sensitive) veremos que por el navegador nos sale "Generated by Ufo Middleware". Perfecto! Ya hemos hecho un middleware de ASP.NET vNext funcional (vale, no es muy útil, pero funcional es).

En siguientes posts iré desgranando distintos aspectos de ASP.NET vNext porque la verdad… ¡es apasionante!

Sobre WebApi, cookies y CSRF

Buenas! Hace poco Pedro Hurtado ha escrito un post titulado “Una evidencia, una frikada y un despropósito”. En él habla de varias cosas, relacionadas con la seguridad de aplicaciones web, pero quiero centrarme en un solo punto (el despropósito). Básicamente lo que dice Pedro es que si usas autenticación por cookies en WebApi eres vulnerable a ataques CSRF.

Vayamos por partes…

Antes que nada debemos aclarar que es un ataque CSRF. No es sencillo de definir, pero básicamente se trata de una vulnerabilidad que explota la confianza que un sitio web tiene en un usuario (previamente autenticado en dicho sitio web). La explicación de la wikipedia no está nada mal (aunque mejor la entrada inglesa).

El ejemplo que pone Pedro es el siguiente, suponiendo que tenemos habilitada la autenticación por cookies y que el usuario se haya logado en la aplicación web (es decir, por lo tanto que la cookie esté emitida), una página web maliciosa puede hacer un ataque CSRF con algo tan simple como:

  1. <p>[FROM ATTACKER] You have been hacked??? Who knows…</p>
  2.  
  3. <div style=«display:none»>
  4.     <form id=«attacker» method=«post» action=«http://localhost:35815/api/prueba»>
  5.         <input type=«hidden» name=«valor» value=«hacked» />
  6.         <input type=«hidden» name=«valor2» value=«csrf» />
  7.     </form>
  8. </div>
  9.  
  10. @section scripts {
  11.     <script>
  12.         $(«#attacker»).submit();
  13.     </script>
  14. }

Este código estará en cualquier vista de otra aplicación web distinta a la que define el controlador web api. En mi caso en mi proyecto tengo:

image

El proyecto web CSRFVictim define el controlador WebApi llamado Prueba con el método Post. Tengo pues las dos aplicaciones ejecutándose en IISExpress:

image

La aplicación CSRFAttacker es la que tiene la vista anterior. Cuando navego a http://localhost:35594/Home/Attack (una URL de CSRFAttacker) se termina ejecutando el método Post del controlador Prueba de CSRFVictim. ¡Ojo! Con la condición de que ANTES el usuario se haya autenticado en la aplicación CSRFVictim.

Esto tiene toda la lógica del mundo: al autenticarse en CSRFVictim se genera una cookie de autenticación. Cuando luego se navega a CSRFAttacker desde el mismo navegador se hace el POST hacia CSRFVictim, el navegador envía la cookie de autenticación… Para el controlador WebApi es, a todos los efectos, como si la petición viniese de CSRFVictim. Es una petición válida: tiene la cookie de autenticación. Porque el navegador la envía. Insisto: es necesario que el usuario esté autenticado antes en CSRFVictim.

De esto podemos desprender un par de cosillas:

  1. Intenta estar logado en cualquier sitio web el mínimo tiempo posible. Y mientras estés logado en un sitio evita visitar otras URLs (especialmente las no confiables). Evita siempre el uso de opciones tipo “remember me”. Son cookies que carga el demonio.
  2. Vigila con las llamadas POST a tu aplicación. Si te autenticas por cookies eres vulnerable a CSRF. Con independencia de si usas WebApi, un controlador MVC o cualquier otra cosa. Si no haces nada más, eres por defecto vulnerable.

Si en lugar de un controlador WebApi usas un controlador MVC que responde a un POST, que se origina en un formulario HTML (p. ej. un formulario de login) puedes protegerte utilizando HtmlHelper.AntiForgeryToken(). Mira este post para los detalles: http://blog.stevensanderson.com/2008/09/01/prevent-cross-site-request-forgery-csrf-using-aspnet-mvcs-antiforgerytoken-helper/

Pero si usas WebApi no puedes usar la técnica de AntiForgeryToken, porque esa se basa en generar un input hidden… eso funciona para vistas HTML pero no para controladores que están pensados para ser llamados programáticamente. Esto nos lleva a otro consejo:

  • Evita, siempre que puedas, la autenticación por cookies en tus servicios web api.

La autenticación basada en cookies es la causa de la vulnerabilidad. Pero muchas veces se generan controladores web api para ser usados desde dentro de una aplicación web (p. ej. para soporte de llamadas Ajax). En este caso es muy útil que la misma cookie que autentique el usuario en la aplicación web, nos sirva para los servicios web api, ya que estos están pensados para ser llamados (via javascript) desde la propia aplicación web. En este caso, deberías añadir al menos algún mecanismo de seguridad adicional.

P. ej. podrías usar algo parecido a lo siguiente:

  1.   public class AntiCSRFHandler : DelegatingHandler
  2.   {
  3.       protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
  4.       {
  5.  
  6.           var referrer = request.Headers.Referrer;
  7.           var uri = request.RequestUri;
  8.  
  9.             if (referrer != null && uri != null &&referrer.Port == uri.Port && referrer.Host == uri.Host)
  10.           {
  11.  
  12.               return base.SendAsync(request, cancellationToken);
  13.           }
  14.           var response = request.CreateResponse(HttpStatusCode.InternalServerError);
  15.           response.ReasonPhrase = «Invalid referrer»;
  16.           return Task.FromResult<HttpResponseMessage>(response);
  17.  
  18.       }
  19.   }

Esto crea un message handler que analiza todas las peticiones web a los servicios web api y si el referrer no es el mismo (port y host) que la url del servicio web, devuelve un HTTP 500.

Por supuesto tenemos que añadir el message handler a la configuración de Web Api:

  1. GlobalConfiguration.Configuration.MessageHandlers.Add(new AntiCSRFHandler());

Ahora si la página atacante intenta realizar el POST recibirá un HTTP 500:

image

Eso es porque el referrer contiene la URL que genera la petición (la url de la página Home/Attack de CSRFAttacker (en mi caso es http://localhost:35594/Home/Attack que es de distinto host y/o port que la URL del servicio web (http://localhost:35815/api/prueba).

Con eso tan simple ya estamos protegidos de una página atacante. Por supuesto, esa protección no es infalible, pero es relativamente segura: Mediante código HTML no se puede establecer el referrer de una página y mediante JavaScript (usando XMLHttpRequest) en principio tampoco. E incluso si se pudiese mediante XMLHttpRequest no sería un problema muy grave ya que entonces la llamada fallaría por CORS (a menos que habilites CORS en WebApi lo que no debes hacer nunca en el caso de un servicio web api que tan solo se utiliza desde la propia aplicación web).

Así pues recuerda: solo debes permitir autenticación por cookies en tus servicios web api si y solo si, son servicios web api pensados para ser usados tan solo desde la propia aplicación web. Y si lo haces asegúrate de establecer algún mecanismo adicional de seguridad para evitar CSRF.

Como siempre digo, debemos ser responsables de lo que hacemos y debemos entender lo que sucede. Es nuestro código y por lo tanto nuestra responsabilidad.

Un saludo!

ASP.NET MVC–Recibir contenido en mayúsculas

Imagina que estás desarrollando un proyecto, con ASP.NET MVC y cuando llevas digamos unas, no sé, cincuenta pantallas, todas llenas con sus formularios, algunos que hacen peticiones AJAX, otros que no… bueno, imagina que cuando llevas ya bastantes vistas hechas, aparece un nuevo requisito, de aquellos que están agazapados, esperando el momento propicio para saltate a la yugular: Todos los datos que entre el usuario, deben ser guardados y mostrados en mayúsculas.

Hay varias técnicas que puedes empezar a usar: Podríamos usar text-transform de CSS para transformar lo que ve el usuario en mayúsculas. Pero eso no sirve porque los datos que el servidor recibiría serían tal y como los ha entrado el usuario (text-transform cambia solo la representación pero no el propio texto).

Otra opción, claro está, es modificar todos los viewmodels porque al enlazar las propiedades las conviertan en mayúsculas. Así, si el usuario entra “edu” en la propiedad Name de un viewmodel, el viewmodel lo convierte a EDU y listos. Pero claro… si tienes muchos viewmodels ya hechos, eso puede ser muy tedioso. Y si no los tienes, pero vas a tenerlos, pues también…

En este dilema estaba un compañero de curro, cuando me planteó exactamente dicho problema. La cuestión era si había una manera que no implicase tener que tocar todos los viewmodels, para asegurar que recibíamos los datos siempre en mayúsculas. Y por suerte, la hay.

Si conoces un poco como funciona ASP.NET MVC internamente, sabrás que hay dos grupos de objetos que cooperan entre ellos para traducir los datos de la petición HTTP a los parámetros de la acción del controlador (que suele ser un viewmodel en el caso de una acción invocada via POST). Esos dos grupos de objetos son los value providers y los model binders.

La idea es muy sencilla: Los value providers recogen los datos de la petición HTTP y los dejan en un “saco común”. Los model binders recogen los datos de ese “saco común” y con esos datos recrean los valores de los parámetros de los controladores. De esa manera los value providers tan solo deben entender de la petición HTTP y los model binders solo deben entender como recrear los parámetros del controlador. Separación de responsabilidades.

Hay varios value providers porque cada uno de ellos se encarga de una parte de la petición HTTP. Así uno se encarga de los datos en la query string, otro de los form values (datos en el body usando application/x-www-form-urlencoded), otro de los datos en json… Y hay varios model binders, porque clases específicas pueden tener necesidades específicas de conversión. Aunque el DefaultModelBinder que viene de serie puede con casi todo, a veces es necesario crearse un model binder propio para suportar algunos escenarios.

En este caso la solución pasa por usar un value provider nuevo. Un value provider que recogerá los datos de la petición HTTP y los convertirá a maýsuculas antes de enviarlos a los model binders. Con eso los model binders recibirán los datos ya en mayúsculas, como si siempre hubiesen estado así. Solucionado el problema.

Veamos el código brevemente.

Lo primero es crear la factoría que cree el nuevo value provider. Los value providers se crean y se eliminan a cada petición, y el responsable de hacerlo es una factoría, que es el único objeto que existe durante todo el ciclo de vida de la aplicación:

  1. public class ToUpperValueProviderFactory : ValueProviderFactory
  2. {
  3.     private readonly ValueProviderFactory _originalFactory;
  4.     public ToUpperValueProviderFactory(ValueProviderFactory originalFactory)
  5.     {
  6.         _originalFactory = originalFactory;
  7.     }
  8.     public override IValueProvider GetValueProvider(ControllerContext controllerContext)
  9.     {
  10.         var provider = _originalFactory.GetValueProvider(controllerContext);
  11.         return provider != null ? new ToUpperProvider(provider) : null;
  12.     }
  13. }

La idea es muy sencilla: dicha factoría delega en la factoría original para obtener el value provider. Y luego devuelve un ToUpperProvider que va a ser nuestro value provider propio:

  1. public class ToUpperProvider : IValueProvider
  2. {
  3.     private readonly IValueProvider _realProvider;
  4.     public ToUpperProvider(IValueProvider realProvider)
  5.     {
  6.         _realProvider = realProvider;
  7.     }
  8.     public bool ContainsPrefix(string prefix)
  9.     {
  10.         return _realProvider.ContainsPrefix(prefix);
  11.     }
  12.     public ValueProviderResult GetValue(string key)
  13.     {
  14.         var result = _realProvider.GetValue(key);
  15.         if (result == null)
  16.         {
  17.             return null;
  18.         }
  19.         var rawString = result.RawValue as string;
  20.         if (rawString != null)
  21.         {
  22.             return new ValueProviderResult(rawString.ToUpperInvariant(),
  23.                 result.AttemptedValue.ToUpperInvariant(),
  24.                 result.Culture);
  25.         }
  26.         var rawStrings = result.RawValue as string[];
  27.         if (rawStrings != null)
  28.         {
  29.             return new ValueProviderResult(
  30.                 rawStrings.Select(s => s != null ? s.ToUpperInvariant() : null).ToArray(),
  31.                 result.AttemptedValue.ToUpperInvariant(),
  32.                 result.Culture);
  33.         }
  34.         return result;
  35.     }
  36. }

La clase ToUpperProvider implementa la interfaz IValueProvider, pero delega en el value provider original.

Lo único que hace es, en el método GetValue, una vez que tiene el valor original obtenido por el value provider original convertirlo a mayúsculas. Tratamos dos casuísticas: que el valor sea una cadena o un array de cadenas.

¡Y listos!

El último paso es configurar ASP.NET MVC. P. ej. para hacer que todos los datos enviados via POST usando form data (es decir, un submit de form estándard) se reciban en mayúsculas basta con hacer (en el Application_Start de Global.asax.cs):

  1. var old = ValueProviderFactories.Factories.OfType<FormValueProviderFactory>().FirstOrDefault();
  2. if (old != null)
  3. {
  4.     ValueProviderFactories.Factories.Remove(old);
  5.     ValueProviderFactories.Factories.Add(new ToUpperValueProviderFactory(old));
  6. }

Con eso sustituimos la factoría original que devuelve el value provider que se encarga de los datos en el form data por nuestra propia factoría.

Para probarlo basta con crear una vista con un formulario y hacer un post normal y corriente… y verás que todos los datos que se entren se pasarán a mayúsculas automáticamente 🙂

Saludos!

ASP.NET MVC–Descargar ficheros con soporte para continuación – ii

En el post anterior vimos todo la parte teórica de HTTP que nos permite realizar descargas de ficheros, pausarlas y continuarlas. Pero ahora viene lo bueno… Vamos a implementar el soporte en el servidor para soportar dichas descargas.

Dado que nuestro amado FileStreamResult no soporta la cabecera Range, nos va a tocar a nostros hacer todo el trabajo. Pero, la verdad… no hay para tanto.

Nota importante: Todo, absolutamente todo el código que pongo en este blog está para que hagas con él lo que quieras. Pero del mismo modo, el código que hay en este blog NO ES CÓDIGO DE PRODUCCIÓN. En muchos casos no está suficientemente probado y en otros, para simplificar, no se tienen en cuenta todas las casuísticas o no hay apenas control de errores. Si quieres hacer copy/paste eres totalmente libre de hacerlo, pero revisa luego el código. Entiéndelo y hazlo tuyo.

Bien, el primer paso va a ser crearnos un ActionResult nuevo, en este caso una clase llamada RangeFileActionResult y que herederá pues de ActionResult. En dicho ActionResult vamos a obtener el valor del campo Range y a parsearlo. Empecemos por el constructor:

  1. public RangeFileActionResult(string filename, string contentType)
  2. {
  3.     _stream = new FileStream(filename, FileMode.Open, FileAccess.Read);
  4.     _length = _stream.Length;
  5.     _contentType = contentType;
  6.  
  7.     byte[] hash;
  8.     using (var md5 = MD5.Create())
  9.     {
  10.         hash = md5.ComputeHash(_stream);
  11.     }
  12.     _etag = Convert.ToBase64String(hash);
  13.     _stream.Seek(0, SeekOrigin.Begin);
  14. }

Siplemente nos guardamos el stream al fichero y calculamos el MD5. Vamos a usar el MD5 como ETag del fichero.

Ahora, el siguiente paso es implementar el método ExecuteResult, que es donde se procesa toda la petición:

  1. public override void ExecuteResult(ControllerContext context)
  2. {
  3.     using (_stream)
  4.     {
  5.         var ranges = ParseRangeHeader(context.HttpContext.Request);
  6.         if (ranges == null || ranges.Empty)
  7.         {
  8.             new FileStreamResult(_stream, _contentType).ExecuteResult(context);
  9.             return;
  10.         }
  11.         if (ranges.Multiple)
  12.         {
  13.             ProcessMultipleRanges(context, ranges);
  14.         }
  15.         else
  16.         {
  17.             ProcessSingleRange(context, ranges.Values.Single());
  18.         }
  19.     }
  20. }

Básicamente:

  • Miramos el valor de la cabecera Range. Si no existe o no lo sabemos interpretar, creamos un FileStreamResult tradicional y lo ejecutamos. Es decir, nos saltamos todo lo de los rangos y devolvemos una descarga de fichero tradicional.
  • En caso de que haya más de un rango vamos a generar la respuesta multipart, con el método ProcessMultipleRanges.
  • En el caso de que haya un solo rango vamos a generar la respuesta con el método ProcessSingleRange.

El método ParseRangeHeader se encarga de parsear el valor de la cabecera Range:

  1. private Ranges ParseRangeHeader(HttpRequestBase request)
  2. {
  3.     var rangeHeader = request.Headers["Range"];
  4.     if (string.IsNullOrEmpty(rangeHeader)) return null;
  5.     rangeHeader = rangeHeader.Trim();
  6.  
  7.     if (!rangeHeader.StartsWith("bytes="))
  8.     {
  9.         return Ranges.InvalidUnit();
  10.     }
  11.  
  12.     return Ranges.FromBytesUnit(rangeHeader.Substring("bytes=".Length));
  13.  
  14. }

Se apoya en unas clases llamadas Ranges (que es básicamente una coleccion de objetos Range) y Range que representa un rango (origen, destino). El método importante de Ranges es el FromBytesUnit que es el que realmente parsea una cadena (sin el prefijo bytes=):

  1. public static Ranges FromBytesUnit(string value)
  2. {
  3.     var tokens = value.Split(',');
  4.  
  5.     var ranges = new Ranges();
  6.     foreach (var token in tokens)
  7.     {
  8.         ranges.Add(new Range(token));
  9.     }
  10.  
  11.     return ranges;
  12. }

Y la otra parte del trabajo la realiza el constructor de Range. Así si tenemos la cadena “0-100, 101-200” se llamará dos veces al constructor de Range pasándole primero la cadena “0-100” y luego “101-200”.

  1. public Range(string value)
  2. {
  3.     if (!value.Contains("-"))
  4.     {
  5.         _from = long.Parse(value);
  6.         _to = 1;
  7.     }
  8.     else if (value.StartsWith("-"))
  9.     {
  10.         _from = 1;
  11.         _to = long.Parse(value.Substring(1));
  12.     }
  13.     else
  14.     {
  15.         var idx = value.IndexOf('-');
  16.         _from = long.Parse(value.Substring(0, idx));
  17.         _to = idx == value.Length 1 ? 1 :
  18.             long.Parse(value.Substring(idx + 1));
  19.     }
  20. }

Sirviendo rangos

Empecemos por el caso más sencillo: Tenemos un solo rango. En este caso el método ProcessSingleRange toma el control:

  1. private void ProcessSingleRange(ControllerContext context, Range range)
  2. {
  3.     var response = context.HttpContext.Response;
  4.     response.StatusCode = 206;
  5.     response.AddHeader("Content-Range", new ContentRange(range, _length).ToString());
  6.     response.AddHeader("ETag", _etag);
  7.     response.ContentType = _contentType;
  8.     FlushRangeDataInResponse(range, response);
  9. }

Este método es muy sencillo. Establece el código de respuesta (206) y crea las cabeceras Content-Range, ETag y Content-Type. Luego llama al método FlushRangeDataInResponse. Dicho método va leyendo los bytes del fichero y los va escribiendo en el buffer de respuesta. Para evitar cargar todo el rango en memoria del servidor (un rango puede ser todo lo largo que desee el cliente), los datos se van leyendo en bloques de 1024 bytes y se van escribiendo en el buffer de salida:

  1. private void FlushRangeDataInResponse(Range range, HttpResponseBase response)
  2. {
  3.     var creader = new ChunkReader(_stream);
  4.     ChunkResult result = null;
  5.     var startpos = 0;
  6.     do
  7.     {
  8.         result = creader.GetBytesChunk(range, startpos);
  9.         startpos += result.BytesRead;
  10.         if (result.BytesRead > 0)
  11.         {
  12.             response.OutputStream.Write(result.Data, 0, result.BytesRead);
  13.         }
  14.         response.Flush();
  15.     } while (result.MoreToRead);
  16. }

Aquí el que hace el trabajo de verdad es la clase ChunkReader. Esta clase es la que va leyendo un stream, por “trozos” y devuelve después de cada trozo si hay “más trozos por leer”:

  1. public class ChunkReader
  2. {
  3.     private readonly Stream _stream;
  4.     public ChunkReader(Stream stream)
  5.     {
  6.         _stream = stream;
  7.     }
  8.  
  9.  
  10.     public ChunkResult GetBytesChunk(Range range, int startpos)
  11.     {
  12.         var chunk = new ChunkResult();
  13.         var reader = new BinaryReader(_stream);
  14.         var remainingLen = range.Length != 1 ? range.Length startpos : 1;
  15.         if (remainingLen == 0)
  16.         {
  17.             return new ChunkResult();
  18.         }
  19.                 
  20.         var bytesWanted = remainingLen != 1 ? Math.Min(1024, remainingLen) : 1024;
  21.         reader.BaseStream.Seek(range.FromBegin ? startpos : range.From + startpos, SeekOrigin.Begin);
  22.         var buffer = new byte[bytesWanted];
  23.         chunk.BytesRead = reader.Read(buffer, 0, (int)bytesWanted);
  24.         chunk.Data = buffer;
  25.         chunk.MoreToRead = remainingLen != 1
  26.             ? chunk.BytesRead != remainingLen
  27.             : chunk.BytesRead != 0;
  28.  
  29.         return chunk;
  30.     }
  31. }

El objeto ChunkResult contiene los bytes leídos, el número real de bytes leídos y un booleano que indica si hay “más datos” que leer.

Vayamos ahora al soporte para múltiples rangos. La idea es exactamente la misma, salvo que entre cada rango hay que generar el boundary correspondiente en la respuesta. Y eso es exactamente lo que hace el método ProcessMultipleRanges:

  1. private void ProcessMultipleRanges(ControllerContext context, Ranges ranges)
  2. {
  3.     var response = context.HttpContext.Response;
  4.     response.StatusCode = 206;
  5.     response.AddHeader("ETag", _etag);
  6.     response.AddHeader("Content-Type", "multipart/byteranges; boundary=THIS_STRING_SEPARATES");
  7.     foreach (var range in ranges.Values)
  8.     {
  9.         AddRangeInMultipartResponse(context, range);
  10.     }
  11. }

Primero añadimos los campos comunes (es decir el código de respuesta, el ETagm el content-type con el boundary). Y luego para cada rango llamamos al método AddRageInMultipartResponse, que simplemente coloca el boundary, luego el content-range y el content-type correspondiente y finalmente volca los datos del rango en el buffer de respuesta:

  1. private void AddRangeInMultipartResponse(ControllerContext context, Range range)
  2. {
  3.     var response = context.HttpContext.Response;
  4.     response.Write("– THIS STRING SEPARATES\x0D\x0A");
  5.     response.Write(string.Format("Content-Type: {0}\x0D\x0A", _contentType));
  6.     var contentRange = new ContentRange(range, _length);
  7.     if (contentRange.IsValid)
  8.     {
  9.         response.Write("Content-Range: " + contentRange + "\x0D\x0A\x0D\x0A");
  10.     }
  11.  
  12.     FlushRangeDataInResponse(range, response);
  13.     response.Write("\x0D\x0A");
  14. }

¡Y ya estamos! Algunos ejemplos de lo que vemos. La imagen de la izquierda contiene un solo rango y la de la derecha dos:

imageimage

Con esto hemos visto como añadir soporte para rangos desde el servidor. Por supuesto no está del todo pulido, faltaría añadir el soporte para el If-Range pero bueno… los mimbres vendrían a ser eso.

Nota: Si lo pruebas y colocas un valor de Range inválido (p. ej. Range: bytes=100) recibirás un HTTP 400. Este 400 es generado por IIS incluso antes de que la petición llegue a ASP.NET MVC.

Saludos!

He subido todo el código del POST en un repositorio de GitHub: https://github.com/eiximenis/PartialDownloads. La aplicación web de demo simplemente tiene el siguiente código en Home/Index:

  1. public ActionResult Index()
  2. {
  3.     return this.RangeFile("~\\Content\\test.png", "image/png");
  4. }

Por lo tanto si navegas con un navegador a /Home/Index deberás ver o descargarte la imagen entera. Pero usando fiddler o cURL puedes generar una petición con rangos para ver como funciona.

Para usar cURL te basta con la opción –header:

curl –header "Range: bytes=0-100" http://localhost:39841/

Saludos!

ASP.NET MVC–Descargar ficheros con soporte para continuación – i

Muy buenas! El objetivo de esta serie posts es ver como podemos implementar en ASP.NET MVC descargas de ficheros con soporte para “pausa y continuación”.

En este primer post veremos (por encima) que cabeceras HTTP están involucradas en las peticiones y las respuestas para permitir continuar una descarga.

Dicho soporte debe estar implementado en el cliente, pero también en el servidor. En el cliente porque ese tiene que efectuar lo que se llama una range request, es decir pasar en la petición HTTP que “parte” del archivo quiere. Y el servidor debe tener soporte para mandar solo esta parte.

En ASP.NET MVC usamos un FileActionResult para soportar descargas de archivos. Es muy cómodo y sencillo pero no tiene soporte para range requests. En esta serie posts veremos como podemos crearnos un ActionResult propio para que soporte este tipo de peticiones!

En el apartado range de la definición de HTTP1.1. se encuentra la definición de la cabecera Range que es la madre del cordero.

De hecho, básicamente hay dos cabeceras involucradas en una range request (que envía el cliente y que el servidor debe entender):

  1. Range: Especifica el rango que desea obtener el cliente
  2. If-Range: Especifica que se haga caso de “Range” solo si los datos no se han modificado desde xx (xx se especifica en la cabecera If-Range). Si los datos se han modificado, olvida Range y envía todos los datos.

Formato de Range

El formato de Range es muy sencillo. Oh sí, leyendo la especificación parece que es super complejo, pero para eso son las especificaciones… 😛

A la práctica Range tiene el siguiente formato:

  • Range: bytes=x-y: El cliente quiere los bytes desde x hasta y (ambos inclusivos). P. ej. Range 0-499: Devuelve los 500 primeros bytes.

Si y no aparece entonces significa “dame desde el byte x hasta el final”:

  • Range: bytes=9000: El cliente quiere desde el byte 9000 (inclusive) hasta el finak

Si x no aparece entonces significa “dame los últimos y bytes”. P. ej:

  • Range: bytes=-500: El cliente quiere los últimos 500 bytes.

La cabecera admite distintos rangos separados por comas:

  • Range: bytes=100-200,400-500, –800: Dame los bytes del 100 al 200. Y del 400 al 500 y los últimos 800.

Si los rangos se solapan esto no debe generar un error:

  • Range: bytes=500-700, 601-999: El cliente quiere los bytes del 500 al 700 y del 601 al 999.

Nota: Que la cabecera Range empiece por bytes= no es superfluo. El estándard es extensible y permite que se puedan definir otras unidades además de bytes para especificar los rangos. De ahí que deba especificarse la unidad usada en la cabecera Range. De hecho el servidor puede usar la cabecera Accept-Ranges para especificar que unidades de rangos soporta (p. ej. Accept-Ranges: bytes). Nosotros nos centraremos única y exclusivamente en rangos de bytes.

Respuesta del servidor

Si el cliente solo pide un rango, la respuesta del servidor es una respuesta normal, salvo que en lugar de usar el código 200, devuelve un 206 (Partial content) y con la cabecera Content-Range añadida.

El formato de la cabecera Content-Range es el rango servido, seguido por la longitud total del elemento separado por /. P. ej:

  • Content-Range: bytes 100-200/5000 –> Se están sirviendo los bytes 100 a 200 (ambos inclusives) de un recurso cuya longitud es de 5000 bytes.
  • Content-Range: bytes 100-200/* –> Se están sirviendo los bytes 100 a 200 de un recurso cuya longitud es desconocida.

Sí, en Content-Range no hay el símbolo = entre bytes y el valor de rango. Mientras que en la cabecera Range si que existe dicho símbolo…

Por otra parte, si el cliente ha pedido más de un rango la respuesta del servidor pasa a ser una multipart, es decir, dado que el cliente nos envía varios rangos, en la respuesta debemos incluirlos todos por separado. Hay varias cosas a tener presente.

  1. El código de retorno no es 200, es 206 (Como en el caso anterior)
  2. El content-type debe establecerse a multipart/byteranges y debe indicarse cual es la cadena separadora (el boundary).
  3. Cada subrespuesta viene precedida del boundary y tiene su propio content-type y content-range indicados.

Un ejemplo sería como sigue (sacado de http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p5-range-latest.html#status.206):

HTTP/1.1 206 Partial Content
Date: Wed, 15 Nov 1995 06:25:24 GMT
Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
Content-Length: 1741
Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES

--THIS_STRING_SEPARATES
Content-Type: application/pdf
Content-Range: bytes 500-999/8000

...the first range...
--THIS_STRING_SEPARATES
Content-Type: application/pdf
Content-Range: bytes 7000-7999/8000

...the second range
--THIS_STRING_SEPARATES--

Si el servidor no puede satisfacer la petición del cliente debido a que los rangos pedidos son inválidos o hay demasiados que se solapan o lo que sea, puede devolver un HTTP 416 (Range not Satisfiable). Si lo hace deberia añadir una cabecera Content-Range inválida con el formato:

Content-Range: bytes */x (siendo x el número de bytes totales del recurso).

Otra opción si los rangos son inválidos es devolver el recurso entero usando un HTTP200 tradicional (muchos servidores hacen esto, ya que si un cliente usa rangos debe estar siempre preparado por si el servidor no los admite).

Cabecera If-Range

Nos falta mencionar la cabecera If-Range. La idea de dicha cabecera es que el cliente pueda decir algo como “Oye, tengo una parte del recurso descargado pero es de hace 3 días. Si no ha cambiado, pues me mandas los rangos que te indico en Range, en caso contrario, pues que le vamos a hacer me lo mandas todo con un 200 tradicional”.

El valor de If-Range puede ser, o bien un ETag que identifique el recurso o bien una fecha. Si no sabes lo que es un ETag, pues bueno es simplemente un identificador del contenido (o versión) del recurso. Puede ser un valor de hash, un valor de revisión, lo que sea. No hay un estándar definido, pero la idea es que si el cliente sabe el ETag de un recurso y lo manda, el servidor puede indicarle al cliente si dicho recurso ha cambiado o no. El cliente manda el ETag que tiene para dicho recurso (en la cabecera If-Range o bien en la If-None-Match si no hablamos de rangos).

Oh, por supuesto, uno podría crear un servidor que devolviese un ETag único cada vez que el cliente no le pasa un ETag previo y devolver siempre ETag recibido por el cliente en caso contrario. En este caso, se podría asegurar que cada cliente tendría un ETag distinto. ¿Ves por donde vamos, no? Un mecanismo sencillo y barato para distinguir usuarios únicos. Mucho mejor que todas esas maléficas cookies y además para usar ETags no es necesario colocar ningún popup ni nada parecido. Además, a diferencia de las cookies que se eliminan borrando las cookies (lo que mucha gente hace), los ETags se borran generalmente vaciando la cache del navegador (lo que hace mucha menos gente). Por supuesto, he dicho que uno podría hacer esto… no que se haya hecho 😛

Bueno… Hasta ahí el primer post. Rollo teórico, pero bueno, siempre es importante entender como funcionan las cosas ¿no?… en el siguiente post pasaremos a la práctica!!! 😀

Reflexiones del #programadorIO: Tipados vs no tipados

Esta noche he tenido el placer de participar en el marco de un #programadorIO en un debate sobre los lenguajes tipados vs los no tipados. Puedes ver el debate en youtube: https://www.youtube.com/watch?v=sxOM6sYgn5U

Nota: En el contexto de este post “no tipado” significa débilmente tipado o de tipado dinámico. Y tipado significa fuertemente tipado o de tipado estático.

Mi opinión es que los lenguajes no tipados son muy adecuados para prototipados, por que las herramientas suelen ser más ágiles y porque te permiten “saltarte” en primera instancia una fase mucho más formal de diseño (fase que luego tarde o temprano tiene que venir, pero en un lenguaje tipado tiene que realizarse al principio para, precisamente, poder diseñar los tipos). De todos modos mi experiencia profesional versa mayoritariamente en los lenguajes tipados (C++, Java y C#). También he mencionado que creo que el auge de JavaScript no es tanto por el lenguaje en sí, si no que viene de la mano del auge del desarrollo web. Si desarrollas para la web, debes hacerlo casi si o si, en JavaScript. Hubiese estado bien la opinión de alguien que hubiese desarrollado tan solo en un lenguaje dinámico que no sea JavaScript (p. ej. Ruby) porque dentro de pequeñas diferencias creo que todos compartíamos mucho en común y que estábamos más del lado de los tipados que de los no tipados.

Bien, aclarado esto, yo he hecho bastante incapié, o lo he intentado al menos, en que a veces un sistema estático de tipos es un “corsé” no deseado y que para ciertas tareas un lenguaje no tipado es mejor o te permite realizarlas de forma mucho más natural o productiva. Y voy a poner algunos ejemplos concretos usando C# (casi todo lo que diré es aplicable a Java también).

Ejemplo 1: Deserialización de datos dinámicos

Este es el ejemplo que apuntaba Pedro. En el fondo es muy simple, puesto que si los datos son dinámicos ¿qué mejor que un lenguaje dinámico para deserializarlos?

Imagina que tienes que consumir una api REST que te puede devolver un objeto (da igual el formato, JSON, XML o lo que sea) que tiene 150 campos posibles, todos ellos opcionales. Pueden aparecer o no pueden aparecer. Si tienes que deserializarlo en un lenguaje tipado, que haces: crear una clase con 150 miembros? Y si alguno de los miembros es un int y vale 0… este 0 es porque no ha aparecido o bien porque realmente he llegado un 0. Si claro, puedes usar Nullable<int> pero… bonito y divertido no es.

¿Y si en lugar de ser campos simples son compuestos? ¡Terminas teniendo una jerarquía enorme de clases tan solo para deserializar las respuestas!

El mismo problema te lo encuentras si eres el que crea la API REST por supuesto. Pero incluso peor… porque igual no puedes usar la clase con 150 miembros porque a lo mejor los miembros vacíos o con el valor por defecto se serializarían también y no quieres eso. Vas a terminar igual: con un numero enorme de clases tan solo para serializar los datos.

Si los datos con los que trabajas tienen una naturaleza dinámica, un lenguaje dinámico es lo mejor para tratarlos.

Por supuesto podrías trabajar con algo parecido a un Dictionary<string, object> y serializar el diccionario con el formato de datos esperado. Si, pero haciendo esto estás haciendo un workaround, te estás enfrentando al sistema de tipos. Estás simulando un tipo dinámico en un lenguaje estático. Todas las ventajas del tipado estático desaparecen (el compilador no te ayudará si te equivocas en el nombre de una clase), las herramientas de refactoring no pueden ayudarte en nada (incluso menos que en el caso de un lenguaje dinámico), tu código queda “sucio” (lleno de dictionarios, llamadas a métodos .Add) y además… tardas más.

Ejemplo 2: Jerarquías de clases distintas autogeneradas

Imagina que tienes dos servicios WCF distintos que te devuelven datos muy parecidos. En ambos casos son datos de productos. En ambos casos siempre hay un nombre, un precio y un id. Los nombres de los campos y los tipos SOAP asociados son los mismos (imagina que eso lo puedes definir o imponer).

Si generas los proxies para acceder a los servicios vas a terminar con dos clases diferentes (una por cada servicio). Pero incluso aunque los miembros para el nombre, precio e id se llamasen igual no podrías intercambiar esos proxies en código. Vas a tener dos clases iguales (ambas tendrán un string nombre, un decimal precio y un int id) pero para el compilador son dos clases distintas. Cualquier función que opere sobre uno de los proxies no puede operar con el otro. A pesar de que el aspecto de ambas clases es “idéntico”, a pesar de que representan el “mismo” concepto, para el compilador tienen la mismo parecido que el de un perro con una manzana.

Sí: el problema principal está en que tienes dos clases distintas para lo mismo, pero eso ocurre en la vida real cuando hay herramientas que autogeneran código. ¿Qué soluciones tienes? Pues crear una tercera clase que sea tu “producto” y “transformar” cada uno de los objetos proxy a un objeto de tu clase “producto” que será con la que trabaje tu código. Sí, es posible que los lenguajes tipados tengan un rendimiento superior a los no tipados, pero si empiezas a tener que copiar objetos muchas veces…

¿No estaría bien que tu código que trabaja con un producto pudiese trabajar directamente con cualquiera de los dos proxies? Aunque sean de clases “distintas”. Aunque no haya ninguna interfaz en común. A fin de cuenta tu código tan solo necesita un nombre, un id y un precio. Estaría bien que pudiese funcionar con cualquier objeto que tiene esos tres campos no? Eso se llama duck typing y viene “de serie” con los lenguajes no tipados.

¡Ojo! Que el hecho de que un lenguaje sea tipado no le impide tener algo muy parecido (a efectos prácticos idéntico) al duck typing: P. ej. este problema de los proxies se podría solucionar en C++ con el uso de templates. El uso de templates en C++ es un ejemplo de lo que conoce como structural typing (que es, básicamente, duck typing en tiempo de compilación). Pero no, ni Java ni C# tienen soporte para structural typing.

Ejemplo 3: Generics

Podría poner muchos ejemplos parecidos al de los proxies, incluso cuando no hay código generado. Un ejemplo rápido. Tengo cuatro clases mías, independientes entre ellas.

Ahora quiero crear una colección propia, que implemente IEnumerable<T> pero que internamente use un diccionario, ya que continuamente se estarán buscando elementos por nombre.

Por supuesto las 4 clases tienen una propiedad string Name para guardar el nombre.

Pues bien, para crear esas cuatro colecciones, tienes dos opciones:

  1. Crearte cuatro clases colección idénticas que solo cambian el tipo de datos que aceptan / devuelven. Si, eso suena muy .NET 1.0
  2. Usar generics… Salvo que no puedes.

Y no puedes usar generics porque dentro del código de la clase genérica no puedes acceder a la propiedad Name del tipo genérico. Porque el tipo genérico es “object” por defecto. Por supuesto si las 4 clases implementasen una interfaz común, que se llamase INamedItem (p. ej.) y que definiese la propiedad Name, podrías poner una restricción de generics para que el tipo genérico implementase INamedItem y entonces podrías usar generics para crear tu colección propia. Pero realmente la interfaz INamedItem no representa ningún concepto real. Está tan solo para permitirte usar generics en este caso. Este es otro caso donde duck typing vendría bien: tu colección propia debería funcionar con cualquier objeto que tenga la propiedad Name. Pero el sistema de tipos de C# (con el de Java pasa lo mismo) es incapaz de dar soporte a esta situación.

Ejemplo 4: delegados

Tengo una función que devuelve un bool y acepta un int. Tengo un delegado de tipo Func<int, bool> que “apunta” a dicha función.

Quiero pasar este delegado a otra función… que espera un Predicate<int>.

Conceptualmente Func<T, bool> es lo mismo que Predicate<T> pero para el compilador son totalmente distintos. Por suerte en este caso la solución es muy sencilla, convertir un Func a un Predicate es muy sencillo, pero tienes que hacerlo igualmente.

Nota: Por cierto, aprovechando, no uses nunca Predicate<T> en tu código. Está obsoleto. Func<T,bool> es lo que se debe usar.

Ejemplo 5: Instanciación de tipos dinámica

Este es muy sencillo: quieres instanciar un tipo cuyo nombre no conoces en tiempo de compilación. Da igual la razón: el método puede venirte de un fichero, BBDD o lo que sea.

Cierto, en C# y en Java puedes usar reflection (p. ej. Activator.CreateInstance en C#) para crear la instancia. El problema es que usar reflection elimina todas las ventajas del tipado estático y además el código queda muy “sucio”. Pasar de reflection a tipado estático otra vez no siempre es posible (si sabes que cualquiera de las posibles clases implementa el mismo interfaz puedes convertir el resultado al interfaz y a partir de allí recuperar el tipado estático). Y si tienes que hacer varias cosas usando reflection el código queda “sucio”, dificil de entender y ninguna herramienta de refactorización puede ayudarte.

En un lenguaje no tipado en cambio, la creación del objeto puede requerir una sintaxis distinta pero una vez creado el objeto invocar los métodos será con la misma sintaxis de siempre.

En resumen

Todos los ejemplos presentados (y hay más de posibles), se resumen en dos grandes tipos: comportamiento dinámico (ejemplos 1 y 5) y “objetos semánticamente compatibles pero incompatibles a la práctica” (el resto de ejemplos).

¿Justifican esos casos usar un lenguaje dinámico para todos tus proyectos? No. Pero si que justifican que los lenguajes estáticos añadan opciones para facilitar la programación dinámica. Por ejemplo el dynamic de C# es un paso en esa dirección. Los templates de C++ son otro (los genérics de .NET o de Java ni de lejos).

Entonces… ¿tienes que usar un lenguaje estático para todos tus proyectos? Pues no. Puedes hacer grandes proyectos tanto en lenguajes tipados como en no tipados. Y puedes hacer aberraciones en ambos.

Aunque yo personalmente prefiero un lenguaje estático a uno dinámico, me siento cómodo en estos y a veces cuando estoy en C# si que me gustaría tener toda la flexibilidad que estos me ofrecen. De hecho, cuanto más me he acostrumbrado a JavaScript más echo en falta ciertas cosas en C#. Pero no siempre, no continuamente. Solo “cuando yo quiero”.

Ahora sí, lo que tengo claro es que desarrollar bien en un lenguaje no tipado requiere mayor disciplina que en un lenguaje tipado y que cualquier desarrollador que se precie debería conocer los conceptos de orientación a objetos clásicos (de hecho yo creo que cualquier desarrollador debería aprender C++, pero esa es otra batalla :P).

Bueno… si has llegado hasta aquí… gracias por leer este tostón! Y por supuesto, siéntete libre de dejar un comentario con tu opinión!

Un saludo!

Visibilidades en JavaScript

Una de las cosas que se argumentan en contra de JavaScript cuando se habla de orientación a objetos es que no soporta la visibilidad de métodos o propiedades. Es decir, todo es público por defecto.

Mucha gente hoy en día cuando programa en JavaScript adopta alguna convención tipo “lo que empiece por guión bajo es privado y no debe ser invocado”. Como chapuza para ir tirando, pues bueno, pero en JavaScript hay maneras de simular una visibilidad privada y de que realmente el creador de un objeto no pueda invocar algunos métodos. En este post veremos un método rápido y sencillo. Por supuesto no es el único ni tiene porque ser el mejor…

Empecemos por la declaración de una función constructora que me permite crear objetos de tipo Foo:

  1. var Foo = function () {
  2.     this.count = 0;
  3.     this.inc = function() {
  4.         this._addToCount(1);
  5.     };
  6.  
  7.     this._addToCount = function (a) {
  8.         this.count += a;
  9.     };
  10. }
  11.  
  12. var foo = new Foo();
  13. console.log(foo.count);
  14. foo.inc();
  15. // Esto debera ser privado
  16. foo._addToCount(100);
  17. console.log(foo.count);
  18. // count no debera poder accederse
  19. foo.count = 10;
  20. console.log(foo.count);

Estoy usando la convención de que los métodos privados empiezan por un guión bajo. Pero es esto: una convención. Para el lenguaje no hay diferencia. De hecho si ejecuto este código el resultado es el siguiente:

image

El desarrollador que crea un objeto Foo puede acceder tanto a inc, como a addToCount como a count. Como podemos solucionar eso?

La solución pasa por no devolver a quien crea el objeto Foo entero si no un “subobjeto” que tan solo contenga las funciones publicas:

  1. var Foo = function () {
  2.     this.count = 0;
  3.     this.inc = function() {
  4.         this._addToCount(1);
  5.     };
  6.  
  7.     this._addToCount = function (a) {
  8.         this.count += a;
  9.     };
  10.  
  11.     return {
  12.         inc : this.inc
  13.     };
  14. }
  15.  
  16. var foo = new Foo();
  17. console.log(foo);

Si ejecuto este código parece que vamos por el buen camino:

image

Ahora el objeto foo contiene tan solo el método inc. Pero, que ocurre si ¿lo ejecutamos? Pues eso:

image

JavaScript se queja que el método _addToCount no está definido! Que es lo que ha ocurrido? Lo ocurrido tiene que ver con el contexto de JavaScript o el valor de this. El método inc que invocamos es el método inc del objeto anónimo que devolvemos al final de la función constructora de Foo. Dentro de este método el valor de this es el valor del objeto anónimo que, por supuesto, no tiene definido _addToCount. Parece que estamos en un callejón sin salida, verdad?

Aquí es cuando entra en escena la función bind: bind es un función que se llama sobre una función. El resultado de aplicar bind a una función es otra función pero atada permanentemente al contexto que se pasa como parámetro a bind. Dicho de otra manera cuando devolvemos el objeto anónimo, tenemos que modificar el contexto del método inc para que sea el objeto Foo entero. Así modificamos el return para que quede como:

  1. return {
  2.     inc: this.inc.bind(this)
  3. };

Cuando se ejecuta este return el valor the this es el objeto Foo entero así que lo que estamos devolviendo es un objeto anónimo, con una función inc (que realmente es this.inc es decir la función inc del objeto Foo entero), pero que está bindeada a this (el objeto Foo entero), es decir que cuando se ejecute este método inc del objeto anónimo el valor de this no será el objeto anónimo si no el propio objeto Foo.

Con esto hemos terminado! Ahora cuando llamamos a new Foo(), lo que obtenemos es un objeto solo con el método inc. Cuando invocamos inc todo funciona ahora correctamente. Y ya no podemos invocar el método privado _addToCount ni acceder a la propiedad count.

Esto es tan solo un mecanismo, hay varias maneras distintas de hacer lo mismo pero todas se basan en este mismo principio.

Saludos!

PD: Os dejo el código de un método, que he llamado _publicInterface. Dicho método lo que hace es, a partir de un objeto, crear otro objeto que contenga tan solo aquellas funciones que NO empiezan por guión bajo:

  1. this._publicInterface = function() {
  2.     var keys = Object.keys(this);
  3.     var protocol = {};
  4.     for (var idx = 0; idx < keys.length; idx++) {
  5.         var key = keys[idx];
  6.         if (key.charAt(0) !== ‘_’ && typeof (this[key]) === «function») {
  7.             protocol[key] = this[key].bind(this);
  8.         }
  9.     }
  10.  
  11.     return protocol;
  12. };

Así podéis definir en vuestros objetos funciones públicas y privadas (que empiecen por guión bajo) y en el return final hacer: return this._publicInterface();

ASP.NET MVC, [Authorize] y jQuery.load

Muy buenas! Estreno el blog este 2014… dios a finales de Febrero! A ver, si empezamos a retomar el ritmo…

Este es un post sencillito, por si os encontráis con ello. La situación es la siguiente: Tenéis controladores que devuelven vistas parciales, las cuales desde JavaScript incluís dentro de vuestro DOM a través de una llamada Ajax, usando p. ej. el método load de jQuery.

Todo funciona correctamente, hasta que un día el usuario entra en el site, se va a comer y cuando vuelve pulsa uno de esos enlaces (o botones o lo que sea) que incluyen una de esas llamadas Ajax… Y ocurre que en lugar de aparecer la vista parcial, aparece la página de Login allí incrustada.

La razón, obviamente, es que la acción que devuelve la vista parcial está protegida con [Authorize] y al haber caducado la cookie de autorización, este atributo manda un HTTP 401 (no autorizado). Hasta ahí bien. Entonces entra en juego nuestro amigo FormsAuthentication, que “captura” este 401 y lo convierte en un 302 (redirección) que es lo que recibe el navegador. Desde el punto de vista del navegador, lo que llega es un 302 por lo que este, obendientemente, se redirige a la página de Login. Las peticiones Ajax hacen caso del HTTP 302 y por lo tanto el resultado de la redirección (la página de Login) se muestra.

Una alternativa sencilla y rápida para solucionar esto consiste en modificar la petición modificada por FormsAuthentication, de forma que cambiamos todos los 302 que sean resultado de una petición Ajax por un 401 y así revertir lo que FormsAuthentication hace.

  1. protected void Application_EndRequest()
  2. {
  3.     var context = new HttpContextWrapper(this.Context);
  4.     if (FormsAuthentication.IsEnabled && context.Response.StatusCode == 302
  5.         && context.Request.IsAjaxRequest())
  6.     {
  7.         context.Response.Clear();
  8.         context.Response.StatusCode = 401;
  9.     }
  10. }

Con esto convertimos todos los 302 en 401 cuando sean peticiones Ajax y estemos bajo FormsAuthentication. Ojo, que los convertimos todos, incluso aquellos 302 legítimos que podrían haber.

Ahora ya solo queda actualizar nuestro código JavaScript y comprobar que no recibimos un 402 😉

Postdata 1: .NET Framework 4.5

Si usas .NET Framework 4.5 (VS2012), ya no es necesario que hagas este truco. En su lugar puedes usar la propiedad SuppressFormsAuthenticationRedirect de HttpResponse y ponerla a true. Si el valor de esa propiedad es true, pues FormsAuthentication no convierte los 401 en 302.

Es una propiedad que debes establecer cada vez, por lo que lo puedes hacer de nuevo en el Application_EndRequest de Global.asax si lo deseas.

Si alguien me pregunta porque narices esa propiedad es a nivel de Response (ya me dirás tu porque el objeto Response tiene que “entender” del framework de autorización), pues no lo sé… pero no me termina de gustar, la verdad.

Postdata 2: Katana Cookie Middleware

Ya lo decía el bueno de Andrés Montes: La vida puede ser maravillosa. Si en FormsAuthentication arreglaron esta situación con la propiedad SuppressFormsAuthenticationRequest en el middleware de autenticación por cookies de Katana volvemos a la situación anterior. Y si usas VS2013 o los nuevos templates de ASP.NET en VS2012 no estarás usando FormsAuthentication si no el middleware de Katana.

Por suerte Katana está mejor pensado que FormsAuthentication y podemos configurar mucho mejor el middleware de autenticación basada en cookies.

Buscad donde se configura el middleware basado en cookies de Katana, que por defecto es en el fichero App_Start/StartupAuth.cs y sustutís:

  1. app.UseCookieAuthentication(new CookieAuthenticationOptions
  2. {
  3.     AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
  4.     LoginPath = new PathString("/Account/Login")
  5. });

por:

  1. app.UseCookieAuthentication(new CookieAuthenticationOptions
  2. {
  3.     AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
  4.     LoginPath = new PathString("/Account/Login"),
  5.     Provider = new CookieAuthenticationProvider
  6.     {
  7.         OnApplyRedirect = ctx =>
  8.         {
  9.             if (!IsAjaxRequest(ctx.Request))
  10.             {
  11.                 ctx.Response.Redirect(ctx.RedirectUri);
  12.             }
  13.         }
  14.     }
  15. });

De esta manera tomamos el control del redirect por 401 y lo hacemos solo si la request no es Ajax. Bueno, bonito y barato.

Ah si! El método IsAjaxResponse… Este método no es el método IsAjaxResponse clásico (ctx.Request es una IOwinRequest) así que os lo tendréis que crear vosotros. Aquí os pongo una implementación:

  1. public static bool IsAjaxRequest(IOwinRequest request)
  2. {
  3.     IReadableStringCollection query = request.Query;
  4.     if (query != null)
  5.     {
  6.         if (query["X-Requested-With"] == "XMLHttpRequest")
  7.         {
  8.             return true;
  9.         }
  10.     }
  11.  
  12.     IHeaderDictionary headers = request.Headers;
  13.     if (headers != null)
  14.     {
  15.         if (headers["X-Requested-With"] == "XMLHttpRequest")
  16.         {
  17.             return true;
  18.         }
  19.     }
  20.     return false;
  21. }

No,  no me deis las gracias… Si el método IsAjaxRequest os funciona las dais al equipo de Katana, ya que está copiado del código fuente de Katana (concretamente de aquí). Si, si… yo también me pregunto porque es privado este método y no un método de extensión público.

En fin… eso es todo! Espero que os sea útil!

Saludos!

Fuentes usadas: