Buscando a Nemo y a Dory con Katana

Anda que no estoy buscando pececillos. Que estoy buscando puertos y misterios.

Los puertos es sencillo si Owin/Katana son un clon de  Node quiero saber quien abre esos puertos. Con lo cual ya tenemos a Nemo localizado.

Lo otro es un poco más complicado pero encontrando a Dory vamos a encontrar a Nemo.

Que maravilla de la ciencia!!! que crees una clase llamada Startup y que tenga un método con una firma determinada y entonces pases de tener una web pesada a una fluida y alegre tiene que esconder algo.

Firma del Metodo.

public void Configuration(IAppBuilder app)
{
}

Vamos a ver que creo que algo se nos está olvidando , es que nos acordáis del ViewState.

Tu sabes WinForms pues corriendo que haces Web. Lo mismo te acabas de dar un golpe en la nuca que te deja como a Dory(con la memoria fuera de juego).

Que no señores, que no son velocípedos simplemente son menos pesadas y por tanto al cumplir con el patrón “engañabobos” dan la sensación de ir fluidas y  por tanto es de agradecer.

Pues la misma sensación tengo con Katana, pero esta vez va a ser peor, cuidado con el que se olvide de instalar un módulo porque el susto va a ser gordo, seguridad, etc, etc….

Bueno como siempre menos royos y vamos a encontrar a Dory que a la postre es nuestra iniciadora.

¿Porque Startup y Configuration?

La primera de las deducciones es sencilla, si esto lo hago correr en Selft Host. Lo mismo entro en colisión con un Main.

La segunda es más sencilla, porque me apetece y me parecen nombres lo suficientemente significativos como para que alguien se acuerde, buena impresión.

Pero como todo esto sale a la luz?

Pues mirando nuestro magnífico Visual Studio y concretamente el Stack Trace.

Stack

Bueno pues ya tenemos un Main y un Configuration Sonrisa.

Pero vemos un MakeDelegate, hablamos de nuevo de Reflection?

Yo creo que sí.

Vamos a irnos a este código que ya sabéis de donde lo saco….

 

Configuration

Que si señores, que se puede ver que por defecto siempre es este y sino al Xml del WebConfig. Y a lidiar con el post del más listo.

http://www.variablenotfound.com/2013/10/owin-y-katana-iv-startup-y-configuration.html

http://www.asp.net/aspnet/overview/owin-and-katana/owin-startup-class-detection

Así que ya hemos sacando a Dory  de su escondite Sonrisa.

Ahora vamos con el pez payaso y veréis que tiene capa sobre capa y más capa alguien sabe lo que es un wrapper pues cuidado que sino te duchas lo más normal es que alguna vez te llamen eso…Casposo….

Listener

Madre mía si el Owin corre sobre el System.Net.HttpListner

HttpListener

Versión del Framework 2.0 y mientras tanto yo jugando con binarios y con WCF RestFull.

Ya lo dije en mi post anterior.

http://geeks.ms/blogs/phurtado/archive/2013/12/12/la-casta-241-a-con-gusanos.aspx

WebServices

Que ocurre que todo lo que corra en Owin  a fecha de hoy sobre IIS y si alguno está interesado se lo puedo explicar corre sobre HttpApplication.

De lo que puedo deducir que no me la quito ni queriendoSonrisa y mira que tengo ganas….

Os paso ahora unas pruebas en #Node,#Go y C#.

Ojo a los test que no es lo que yo quería pero me gusta jugar en campo neutral..

Node.

var http = require(‘http’);
http.createServer(function (req, res) {
  res.writeHead(200, {«Content-Type»: «application/json»});
  res.end(JSON.stringify({Id:1,Name:’Pedro Hurtado’}));
}).listen(3000, ‘localhost’);

Test.

Node

Go.

package main
import (
    «encoding/json»
    «net/http»
)
type customer struct {
    Id   int
    Name string
}
func Get(w http.ResponseWriter, req *http.Request) {
    w.Header().Set(«Content-Type», «application/json»)
    b, _ := json.Marshal(customer{1, «Pedro Hurtado»})
    w.Write(b)
    return
}
func main() {
    http.HandleFunc(«/api/test», Get)
    http.ListenAndServe(«localhost:4000», nil)
}

Test

Go

 

Owin

Controlador.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;

namespace ClassLibrary2.Controllers
{
    public class TestController:ApiController
    {
        public HttpResponseMessage Get()
        {          
            return Request.CreateResponse(HttpStatusCode.Ok, new { Id = 1, Name = «Pedro Hurtado» });
        }

    

    }
}

Configuration(Dory).

using Microsoft.Owin.Hosting;
using Owin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Owin;

namespace ClassLibrary2
{
    public class Program
    {
        public static void Main()
        {
            using (WebApp.Start<Startup>(«
http://localhost:5000″))
            {
                Console.WriteLine(«Server startet»);
                Console.ReadLine();
            }
           
        }
    }
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();
            config.Routes.MapHttpRoute(
                name: «DefaultApi»,
                routeTemplate: «api/{controller}/{id}»,
                defaults: new { id = RouteParameter.Optional }
            );
            app.UseWebApi(config);
        }
    }
}

Test.

c#

Así que señores en unos combates bastante ajustados creo que podemos hablar de tablas entre Go,NodeWebApi(Ya no cuento lo que puede pasar si Owin se hostea en IIS).

Ojo que no tengo ni idea de que va esto de los gráficos, me estoy ciñendo a las alturas y a “Pages/Sec” corroborado con esta otra herramienta Apache HTTP server benchmarking tool donde los resultados eran parecidos y tras esta referencia he pedido el favor a un Visual Studio Ultimate para las pruebas,

What is concurrent request (-c) in Apache Benchmak?

Y de este otro magnifica entrada

Should I use Threads or Tasks – Multiple Client Simulation.

Donde os prometo que yield return no entra en mi reducida cabeza….

Así que si cualquiera quiere opinar es libre y todo es sabiduría para la comunidad.

Conclusiones.

Que si sobre caspa somos capaces de no llevarnos todas las leches en el mismo lado, sino que nos mantenemos en pie hasta el último asalto, que está pasando?

Seguimos ocultando conocimientos al resto, donde todos piensan que las versiones actuales son la final four (eso dice nuget).

!==pre.

Pues no señores. Queda mucho por llegar y estoy convencido de que vamos a ganar.

Pero si a esto le sumas, que ciertas herramientas solo están disponibles para….

Y que cierta información no es pública y lo entiendo.

Al final todo el mundo corre en torno a unas corrientes que no nos llevan a otra cosa que por muchos intentos de Open Source, no se traducen en más que en un constante Tira Códigos(Esa es mi opinión a fecha de hoy. Otro más y hasta cuando.

Coincido  con este post del amigo @r_corral. no al 100% sino en más del 120%.

¿Hasta donde podemos llegar?.

Ahora no coincido con estás otras cosas cosas

 No hace falta renovar Geeks. 

Pienso que estamos montados sobre un Dodge Negro que voló hace 40 años(La Cía  me persigue).

No discuto visitas ni números, discuto una cosa sencilla.

Hace tiempo quizás no mucho me hubiese sentido cómodo con un coche viejo pero en la actualidad estamos acostumbrados a cambiar de coche o que nos digan.

No te montes más que te cuesta más el arreglo que uno nuevo. cc @wasat.

Veis que sencillas son mis quejas. Claras y concisas y creo que las entiende toda la comunidad que para eso estamos……

Ahora hoy uno del Barça declarado le acaba de meter en el Bernabeu a uno del Madríd un 0-5( que ya es costumbre).

Quieres que te meta el 6 pues este es seudónimo de un gas ligero que tiene un peso atómico de 4,0026 y que se encuentra en la misma fila que el

Neon ,Argon, Kripton, Xenon y Radon.

Te voy a explicar lo que pasa con los Routes. Que si están optimizados de aquella manera en WebApi 2.0 Sonrisa

Que les falta un campo un string[] ExcludeRoutes. Atento que este es el 0-7 y ya se convierte en Historia, pero en situaciones extremas sigue arrastrandose.

No es lo mismo guardar un Dictionary<string,object> donde string es el path y object el metodo como lo hace Node y Go que descubrir e invocar el Object con ….

Recuperar información almacenada en atributos.

Con lo cual no me retes que te meto el 0-8 Lengua fuera.

Edu cual prefieres este https://github.com/Bobris/Nowin o el gas ligero xDDDDD.

P.D. Ahora si que es FELIZ NAVIDAD Y PROSPERO AÑO NUEVO. Que lo mismo no puedo volverSonrisa  Pero las dudas de Owin y WebApi creo que han quedado claras y es que lo mejor está por llegar .

 

La castaña con gusanos

Una de las cosas que más me gusta de estas fechas es poder pasear con un cucurucho de castañas. Por tres cosas principalmente

  1. Se me calientan las manos.
  2. Se me llena la barriga.
  3. Me sale barato y en tiempos de crisis no hay nada como algo barato y bueno.

 

castañas

 

En contra tiene una pega y es que alguna puede llevar premio en forma de gusano.

Sí a estás alturas no has cerrado el post, vas a ver que es lo que para mí es una “castaña con gusanos”.

Si señores las routas de mvc y WebApi por lo menos con la versión con la cual yo estoy trabajando(4.0).

Mientras que los métodos en WebApi se llamán Get,Post,Put,Delete, todo es perfecto, ahora cuando en un mismo controlador necesitas otra cosa, ponte a llorar.

Bueno pues dicho esto ya sabéis de que va el post. Los otros días tras esta entrada en twitter.

TwitterRutas

Para los que quieran la conversación completa os paso la url

https://twitter.com/_PedroHurtado/status/410525801314938881.

Mi buen amigo @nicolocodev me recomendó que utilizase Attribute Routing in Web API 2. Aunque ya había leído sobre esto se me planteaba algún que otro problema y es que yo no tenía mi proyecto en 2.0. Lo típico te vas a Nuget, buscas y te lleva a este sitio http://attributerouting.net/ la verdad que es un proyecto de lo más interesante y se puede ejecutar en mi escenario, pero…. Que veo!!!

Un símbolo rojo en WebApi y este cartel más bien llamativo.

Performance

Con lo cual al leer algo de performance como que se me activan las neuronas y de una conversación de las muchas que mantengo por twitter nace todo lo que vais a ver.

Si hablamos de performance, porque no creamos 1000 controladores con un método “GET” que simplemente devuelva una cadena y vemos si es verdad lo que dicen.

Manos a la obra.

1. Vía Nuget o bien desde el Pakage Manager Console instalas AttributeRouting.

2. Una vez que se instala se crea una clase en la carpeta App_Start con nombre AttributeRoutingHttpConfig. Donde rápidamente puedes ver que cuando la web se activa se ejecuta el método Start.

[assembly: WebActivator.PreApplicationStartMethod(typeof(MvcApplication18.AttributeRoutingHttpConfig), "Start")] 

3. Pero como creo yo 1000 controladores sin T4 y sin copiar ni pegar. Sencillo pero misterioso. De esas cosas que dan miedo hasta que no las pruebas. Os presento a …. Don Reflection Emit.

En esa misma clase voy a crear un método llamado CreateManyControladores con el siguiente código.

   1: private static Assembly  CreateManyControladores()

   2: {

   3:    AppDomain ad = AppDomain.CurrentDomain;

   4:    AssemblyName am = new AssemblyName();

   5:    am.Name = "TestAttributeRouting";

   6:    AssemblyBuilder ab = ad.DefineDynamicAssembly(am, AssemblyBuilderAccess.RunAndSave,"c:\mvc");

   7:    ModuleBuilder mb = ab.DefineDynamicModule("testmod", "TestAttributeRouting.dll");

   8:    Type t = null;

   9:    for (int i = 0; i < 1000; i++)

  10:    {

  11:        var controllerName = string.Format("Type{0}Controller", i);

  12:        var routeUrl = string.Format("/Hello{0}", i);

  13:        var returnMessage = string.Format("This is a string from method {0}", i);

  14:  

  15:        var typeBuilder = mb.DefineType(controllerName, TypeAttributes.Public, typeof(ApiController));

  16:  

  17:        var methodBuilDer = typeBuilder.DefineMethod("Get", MethodAttributes.Public, typeof(string), null);

  18:        var constructor = typeof(GETAttribute).GetConstructor(new Type[] { typeof(string) });

  19:        methodBuilDer.SetCustomAttribute(new CustomAttributeBuilder(constructor, new object[] { routeUrl }));

  20:  

  21:        ILGenerator il = methodBuilDer.GetILGenerator();

  22:        il.Emit(OpCodes.Ldstr, returnMessage);

  23:        il.Emit(OpCodes.Ret);

  24:        t = typeBuilder.CreateType();

  25:    }

  26:    

  27:    ab.Save("TestAttributeRouting.dll");

  28:    return t.Assembly;

  29: }

No te asustes que te lo explico.

    1. Crear un AssemblyBuilder y le dices que es para ejecutar y guardar e indicas una ruta donde guardar la dll, en mi caso c:mvc.
    2. Creamos un modulo que es donde vamos a compilar todos nuestros tipos.
    3. Creamos 1000 controladores con nombre Type000Controller, 001,002,3 etc,etc con el Atributo “GET”  y  con la ruta “Hello0,1,2,3”
    4. Devolvemos una cadena que nos indica que método se está ejecutando.
    5. Por último guardamos la dll “TestAttributeRouting.dll” y devolvemos el Assembly.

¿Que no te lo crees?

Pues mira si existe el archivo y con ILSpy descompílalo y vas a obtener esto.

ilspy

Hay Dios, “dichoso del que cree sin ver” Sonrisa.

Y ahora vamos con la confirmación de una mala “performance”.

Para ello en el método RegisterRoutes de la clase AttributeRoutingHttpConfig vamos a agregar el siguiente código y a tomar tiempos.

   1: public static void RegisterRoutes(HttpRouteCollection routes) 

   2: {    

   3:     // See http://github.com/mccalltd/AttributeRouting/wiki for more options.

   4:     // To debug routes locally using the built in ASP.NET development server, go to /routes.axd

   5:  

   6:    

   7:     routes.MapHttpAttributeRoutes();

   8:     

   9:     //Create assembly

  10:     var stopwatch = Stopwatch.StartNew();            

  11:     var assembly = CreateManyControladores();

  12:     stopwatch.Stop();

  13:     var miliseconds = stopwatch.ElapsedMilliseconds;

  14:  

  15:     //Compile routes

  16:     stopwatch.Start();

  17:     routes.MapHttpAttributeRoutes(c => c.AddRoutesFromAssembly(assembly));

  18:     stopwatch.Stop();

  19:     miliseconds = stopwatch.ElapsedMilliseconds;

  20:     

  21:     

  22: }

Creación de la dll dinámica.

Assembly

 

Compilación de rutas.

CompileRutes

Efectivamente hemos confirmado que existe en esta dll un serio problema de rendimiento. No os voy a explicar más de esto puesto que tenemos que pasar a otra cosa, pero yo me he bajado el código fuente de AttributeRouting y si que tiene alguna que otra sentencia rara, yo creo que desconocimiento de Reflectión como el siguiente de los protagonista.

Debería decir lo que es, pero lo dejo para otro capítulo o mejor para que investigues tú Sonrisa.

Si ya tenemos todo esto. Es el momento de ejecutar desde nuestro explorador cada una de las rutas y ver lo que pasa.

Response

Pín,Pín,Pum!!! algo raro está pasado. Venga ánimo que vamos a ver lo que es.

Dentro de todo lo que pasa en WebApi hay una serie de Servicios que se encargan de algunas cosas y concretamente el problema lo tenemos en el servicio DefaultHttpControllerTypeResolver.

En este servicio hay bajo mi punto de vista un problema y es que una dll dynamica no devuelve los tipos con esta instrucción.

assembly.GetExportedTypes();

Y claro el señor que escribió esta clase por lo visto no conocía,no recuerda o tuvo un lapsus para saber como obtener los tipos públicos de un ensamblado dinámico.

assembly.GetTypes();  

Es por eso por lo que escribió el siguiente código.

Código malo

O lo mismo estaba en la especificación y entonces el no es el culpable sino otro.

No permitir definir 1000 controladores al vuelo y tampoco ejecutar dll’s dinámicas de serie cosa que se hace una y otra vez con las vistas. Pero bueno… Vamos con la solución.

Crea una clase con el siguiente código.

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Reflection;

   5: using System.Web;

   6: using System.Web.Http.Dispatcher;

   7:  

   8: namespace MvcApplication18.Handler

   9: {

  10:     public class MyDefaultTypeResolver : DefaultHttpControllerTypeResolver

  11:     {

  12:         public MyDefaultTypeResolver()

  13:             :base()

  14:         {

  15:         }

  16:         public override ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver)

  17:         {

  18:             List<Type> result = new List<Type>();

  19:             var assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();

  20:             

  21:             foreach (var assembly in assemblies)

  22:             {

  23:                 

  24:                 Type[] exportedTypes = null;

  25:                 if (assembly == null)

  26:                 {

  27:                     // can't call GetExportedTypes on a dynamic assembly

  28:                     continue;

  29:                 }

  30:  

  31:                 try

  32:                 {

  33:                     if (assembly.IsDynamic)

  34:                     {

  35:                         exportedTypes = assembly.GetTypes();

  36:                     }

  37:                     else

  38:                     {

  39:                         exportedTypes = assembly.GetExportedTypes();

  40:                     }

  41:                 }

  42:                 catch (ReflectionTypeLoadException ex)

  43:                 {

  44:                     exportedTypes = ex.Types;

  45:                 }

  46:                 catch

  47:                 {

  48:                     // We deliberately ignore all exceptions when building the cache. If 

  49:                     // a controller type is not found then we will respond later with a 404.

  50:                     // However, until then we don't know whether an exception at all will

  51:                     // have an impact on finding a controller.

  52:                     continue;

  53:                 }

  54:                

  55:                 if (exportedTypes != null)

  56:                 {

  57:                     result.AddRange(exportedTypes.Where(x => IsControllerTypePredicate(x)));

  58:                 }

  59:             }

  60:  

  61:             return result;

  62:            

  63:         }

  64:  

  65:            

  66:     }

  67: }

Y en el archivo Global.asax en el método Application_Start incluir esta línea de código.

GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerTypeResolver),

                new MyDefaultTypeResolver());

Como podéis ver en el código, yo si permito ensamblados dinámicos y luego cargo los tipos correctos, queréis que  todos vuestros controladores sean privados, pues otra cosa para investigar.

Assembly.GetTypes()

Ves que sencilloSonrisa.

Ahora puedo ejecutar desde el explorador estás dos rutas, pero no le des que fallaSonrisa.

http://localhost:50150/Hello999

http://localhost:50150/api/type999

Claro esto pone en favor de “AttributeRouting” otro problema y es que nuestra api ahora responde a dos rutas con lo que plantéate problemas de auditoría y me dices por donde te están llamando.

Que es? un todo o nada. Me obliga a decorar todos mis métodos con un atributo.

Hemos vuelto a

mvc restfull webservices o no hemos salido aún

Conclusiones.

1. Si esto pasa en WebApi20 es para llorar, no lo he probado.

2. Ten claro que hasta que no llega la llamada a tu controlador todo es Reflection que puede ser optimo si lo haces bien o poco optimo si lo haces mal y en este caso esta mal hecho.

3. Que no inventes lo ya inventado que todo el mercado funciona con una convención de rutas y que se ha demostrado que funciona.

4. Que no os hago una demo en #nodejs y en #go porque se está haciendo pesado.

Pero repito menos papas, guardianes ,que  funcione bien y se testee para escenarios de este tipo que con dos controladores todo funciona y tener 1000 controladores es fácil (200 entidades x 5 Métodos).

Hasta la próxima, que dada las fechas será para 2014.

FELIZ NAVIDAD Y PROSPERO AÑO NUEVO!!!

P.D. Me despido desde el blog porque desde el twitter aún os quedan aprox. unos 15 de días de guerra.

Go que no Goto

Hace aproximadamente un año, si recordáis os empecé a dar el follón con Node.

Todo vino por un twitter de @0GiS0 que no recuerdo muy bien que decía algo así como “hoy toca probar nodejs” y después este post.

Node.js & Windows Azure – ¿Qué es realmente Node.js? ¿Por dónde empiezo? Creando mi Web server

Eso hizo que se me abriera el gusanillo y demostraros que no fui el primero, ahora sí fui el más pesado e insistente hasta convencer a muchos que lo probasen y dio sus frutos y no pocos Sonrisa.

Como todos sabéis tuve el gusto de haceros alguna que otra demostración y charla a lo largo del año, la más apoteósica de todas la podéis leer y ver en este post del amigo Sergio León.

GUSENET, un EVENTO mayúsculo.

Luego fui invitado al gran evento de

http://www.geek-a-paloozaaa.com/speakers/

Organizado por mi gran e incondicional amigo Don Lluis Franco’s Corner, con lo cual si este año me vuelve a invitar más la invitación que tengo garantizada al #yonodetuxaml con el permiso de Pin y Pooooon , os quiero hablar de algo no tan nuevo pero si novedoso The Go Programming Language, aquí tenéis una pequeña introducción en la wiki, que no me gusta copiar y pegarSonrisa.

El 23 de noviembre tuve el gusto de asistir a una charla de este lenguaje en el GCG Murcia y me entro el gusanillo.

Y yo pensando de que iba a hablar a lo largo del 2014 Lengua fuera.

Bueno vamos con una pequeña demo y verás como os gusta que es bastante fácil.

1. Descarga del nuevo juguete Download the Go distribution.

2. Una vez descargado e instalado yo concretamente en la carpeta c:go voy a crear una carpeta nueva con el nombre jugando con go.

3. Te sitúas en esta carpeta y abres el magnifico ide de desarrollo tecleando notepad, a mi cuando empiezo me gusta este que es el más rápido, pero podéis mirar alguno más en este link.

Comparison of IDEs for Google Go

4. Copias el siguiente fragmente de código en el editor.

package main

import (
    "io"
    "net/http"
    "log"
)

// hello world, the web server
func HelloServer(w http.ResponseWriter, req *http.Request) {
    io.WriteString(w, "hello, world mi niño!n")
}

func main() {
    http.HandleFunc("/hello", HelloServer)
    err := http.ListenAndServe("localhost:4000", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

Y lo guardas con el nombre HelloWord.go acuérdate de la extensión go que después no puedes compilar ni ejecutar.

5. Para ejecutar simplemente tienes que teclear “go run HelloWorld.go” y vas a obtener este resultado.

utf8

¿Que pasa? que no funciona en Windows. No señores que me ha pasado lo mismo que a mi amigo del alma Carrillo en su primer estreno a lo grande Primeros pasos dentro de Visual Studio Online “Monaco”, solo que el pudo compilar y yo ni he podido una buena cosa a favor de “Go”.

Será un lenguaje tipado Sonrisa ?.

Amigo Carrillo que  como fecha máxima 28 de Noviembre de 2014 te veo publicando un post de “Go” en el flamante Visual Studio "Monaco". Ya sabes lo que dice @2Flores de mi :

“Pedro es un visionario y se mete en tus sueños”.

Solución.

Tienes que guardar como UTF-8 que por defecto “Notepad” lo hace como “ANSI” y en honor a Carrillo he escrito en el response.

“hello, world mi niño”, para recordarle que arregle el postSonrisa.

6. Si haces todas estás cosas y te vas al explorar puedes ver el resultado.

hellogo

7. No pienses que solamente puedes ejecutar un programa “Go” con la instrucción “go run HelloWorld.go” sino que puedes crear un ejecutable e imagino que se puede alojar en Azure. Pero eso lo dejaremos para el próximo capítulo. Para ello tienes que teclear la siguiente instrucción.

“go build HelloWorld.go” y en este momento puedes ver como 378 bytes se convierten en un .exe que puedo desplegar y ejecutar en diferentes plataformas ,simplemente como todos sabéis tecleando.

“HelloWorld”

Eso si con un crecimiento considerable tal y como os muestro.

Y yo “luchando por un byte

gordito

Para los amantes de c# donde me incluyo voy a hacer una pequeña comparativa.

Go c#
package main namespace main{}
import (etc.etc.) using etc;

El resto como podéis observar se parece al “Hello World” de Node con lo cual ya todos sabéis interpretar lo que hace.

Una cosa que me tiene trastocado del lenguaje es que no hay clases pero si interfaces y sobre todo como podéis observar punteros, pero sin aritmética.

El mismo ejemplo pero con interfaces lo podéis ver en este link.

http://tour.golang.org/#57

Conclusiones.

Que prometo no ser muy pesado el próximo año. Pero al ver que era un binario sin dependencias y que puedo hacer correr en diferentes plataformas.He aparcado de momento la idea de aprender phyton en detrimento de Go. Ves Eduard como paso de la recluta del Linkedin Sonrisa.

En este último link podéis hacer un tour introductorio que yo por las noches ejecuto y estudio desde mi flamante Nokia Lumia 8210, vamos que no necesito para estudiar y estar en el sofá ningún IPad Sonrisa.

Se me olvidaba lo más importante, este año en el #yonodetuxaml voy a hacer la demo del año pasado pero este año funciona, que ya no tengo instalado el IE9 por suerte y ningún listillo me va a poder decir “ejecútalo en IE9”.

Los gordos,los flacos y los generosos

Que no os parezca una película de los años 20, simplemente con esto quiero dar mi visión de oauth y hacer que cada uno se sienta identificado según vaya leyendo.

Faltan en el título cinco protagonistas importantes y que vais a ver a lo largo de la historia y el papel tan importante que juegan en nuestras vidas

Pero solo voy a darles el placer del título a los verdaderamente protagonistas “Gordo,Flaco y Generoso”.

Al resto de personajes los catalogo. Como especies a extinguir, pero que actualmente ruedan sobre nuestras cabezas, con todos mis respetos a todos.

-(1) El de la poltrona

-(2) El jefe del flaquito

-(3) El lacayo del jefe del flaquito.

-(4) El lacayo del señor de la poltrona.

-(5) Después un quinto que vais a descubrir. quien a capa y espada defiende la producción  de los gorditos y según que circunstancias ….. las cosas son una forma u otra.

Como siempre voy a empezar por un orden ilógico, lo primero es describir al 4 de los protagonistas y así en orden descendente hasta el primero, para que el quinto se califique solo.

4). lacayo del señor de la poltrona.

Este es el más fácil de describir propone ideas como estás:

Ley de cookies

LOPD

Por lo visto el consejero delegado del señor de la poltrona esta lejos de pensar en la propuesta de ley oauth, pero bien cerca de los buenos cheques y de leyes absurdas.

Pensáis que se entera, flacos?.

Bastante más que nosotros(soy flaquito y generoso). El cobra y nosotros malgastamos nuestros conocimientos===800€ y datos===GB.

Yo creo que más bien piensa en los euros de cada mes “que no son pocos”.

No os sintáis ofendidos, responsables de informática, de centros ineficientesTriste.

Me voy a permitir calificaros

Os empiezo a contar, algunas de vuestras decisiones.

DNI-Electrónico

https://lexnet.justicia.es

Madre mía donde os habéis metido. Pero en el fondo os justifico (por el plato de comida de vuestros hijos).

Estáis al servicio de la poltrona o de los gordos y lo más triste es que estáis al servicio de los gordos sin saberlo.

En los 90 y refiriéndonos a informática, pocos había mejor que vosotros, pero tristemente estáis directamente o indirectamente colaborando  con cosas como esta Angel Custodio === Ignorantes (falta de conocimiento o sentados en la pseudo-poltrona).

Los hay más graves los que piensan que esto es un cargo vitalicio y por tanto no me pueden mover, es decir los que  pasan sus vidas de compras y repartiendo contratos al tercero de los protagonistas, menos mal que nos queda poco que repartir Triste.

La semana pasada en la prensa escrita de nuestro periódico local “http://www.laverdad.es/”, me veo en primera página lo siguiente:

“Los médicos y enfermeros tienen que fichar”.

Que injurias, una profesión tan honesta y al servicio de la sociedad.

“Lacayo del señor de la poltrona” vas a hacer algo para que el reconocimiento de identidad sea algo como  “huella digital o parecido” o les vas a dar una tarjetita?

Uno de estos señores intocables puede decir a uno de sus alumnos, pásame la tarjeta que esta mañana llego tarde, por lo menos que se corte el dedo. Me has entendido Sonrisa.

3). El lacayo al servicio de jefe del flaquito.

Un señor llamado consultor y capaz de convencer a un cliente con sus habilidades,  no hace más que vender motos  o zanahorias largas y duras.

Le propone al cliente una autenticación/autorización #oauth (la competencia lo hace), casi nada.

Las preguntas desde la perspectiva de los flaquitos son obvias.

-¿Sabes lo que dices?

-¿En que mundo vives?

¿Cuanto te cuesta?

¿Cuanto vas a cobrar? pero mejor no me aprietes en el 2015.

Sentencia el flaquito del sillón azul.

Narrador:  El flaquito susurra, pero sin que se oiga que mañana tiene reunión con el que le ingresa la nómina.

-Yo ya te lo he dicho, total vas a hacer lo que te plazca.

Pero tío, te has pasado, sabes lo que estas proponiendo?”.

Este personaje es capaz de hacerse amigo del más listo de la cuadrilla de los flacos, os lo prometo.

Pero “colegui, si esto ya lo hiciste en el proyecto con “referencia 2013/45”.

Automáticamente el flaquito se queda fuera de juego, no es su trabajo pelear con el padre de todos los males, pero en su mente reina la confusión.

Bueno lo último que hace el personaje es llevar al flaquito a tomar unas cañas y decirle algo como esto.

Con este proyecto vamos a “triunfar”.

Memos mal que la mujer del flaquito juega un papel importante y le dice “Es que eres tonto, te sigues fiando del lacayo”, otra larga temporada sin acurrucarme.

Primeras sospechas infundadas del flaquito, que feliz llegue anoche a casa y me lo fastidiaron,le dice al otro flaquito del sillón rojo.

2).  El jefe del flaquito y del lacayo.

Al día siguiente el que te invito a cervezas. Y ante el cual dadas sus habilidades has dicho poco más o menos  “si bwana”.

Se presenta ante otro del circulo del mal y le cuenta el proyecto.

Lacayo del jefe: tengo un proyecto que nos puede salvar el mes y el AÑO!!.

El primer personaje me ha aprobado el proyecto y es un 1.000.000 de €. Ya sabes que es amigo de mi primo Onofre.  Cuidado Jefe que posiblemente no los cobres y lo vas a ver.

Lacayo del jefe: Me ha costado un montón firmar este proyecto, en la reunión había un flaquito que me ha puesto las cosas difíciles con oauth( mi primo ya sabes ese que es muy listo, me ha dicho que eso lo monta el en un par de semanas) .

Jefe ya sabes que soy capaz de vender motos. Y más cuando se trata de un proyecto que nos permite salvar el año.

Lacayo del jefe:  Anoche me lleve al flaquito de la silla azul a tomar unas cerveza y me ha dicho lo mismo  que mi primo, que en un par de semanas el tema lo tiene listo. Gran error flaquito.

Narrador. flaquito que ya te lo dijo tu mjuer. Otra vez te esta engañando. El flaquito sospecha que le liaron con #oauth

“Me Liaron com===#oauth”. Triste Dos noches sin dormir y sin acurrucarse.

Narrador: El resto  os lo podéis imaginar (llega el 30 de Noviembre del año siguiente y aparece el jefe y dos lacayos (aparece RR.HH)  preguntan…).

-Has terminado?

-Es que tu me dijiste!!!

En definitiva flaquito que te ha tocado el gordo de navidad de 2015Sonrisa.

1) El de la poltrona. Ni se enteraSonrisa

-Dice a su lacayo.

A mi no me hables de cosas raras, dime donde tengo que firmar que he quedado con unos amigos y por un millón de euros no me vas a j….r una comida.

 

La historia real

Después de todo esto, alguien no se siente autenticado, autorizado e identificado?

Pues es justo el momento de dejar de leer o bien seguir con la historia  del  “FLAQUITO” en la que sin más conocimientos el generoso colabora y el  gordito se frota las manos a costa de todos,recauda información.

El 5 personaje esta a punto de aparecer. 

–En resumen empieza la parte técnica de #oauth 2.0.

Lo primero es dejar claro que yo soy partidario de tener una sola contraseña para todo, pero regulada y en estos momentos ese tipo de cosas están en el limbo.

Lo primero es dejar claro que todos aparte de flaquitos somos generosos. Os hago varias preguntas.

¿Quien no es Facebook,Twitter,Google o Microsoft?

Por tanto quien no se ha registrado en las siguientes páginas:

https://www.facebook.com/

https://twitter.com/

https://accounts.google.com/SignUp

https://signup.live.com/signup.aspx

Bueno pues ya os he descrito al primero de los personajes,todos ellos tienen sus mecanismos de privacidad y demás. Si queréis flaquitos que vuestras páginas se autentiquen con más,  solo tenéis que ir a esta página OAuth 2.0 y mirar por ejemplo que twitter no soporta Oauth 2.0, o por lo menos yo no lo veoSonrisa.

Y es en este punto donde se va a describir al 5 de los personajes(el incondicional) que normalmente es la empresa del tercero “el jefe del flaquito”, si señores el que dice que esto es buenísimo,fácil y maravilloso, autenticarse con mvc 4 y oauth es una línea de código.

Vamos a ver si después de esto sigue diciendo lo mismoSonrisa.

Para ello vas a seguir los pasos detenidamente que te voy a mostrar a continuación.

1. Creas un nuevo proyecto mvc4.

2. Te vas a la capeta App_Start y abres el archivo AuthConfig y quitas los comentarios a esta línea.

OAuthWebSecurity.RegisterGoogleClient();

No es que yo tenga un amor incondicional por Google sino que es una forma rápida de ver la demo puesto que no te obliga a registrar ninguna app en su sistema, La autenticación se hace mediante OpenId.

3. Una vez que has hecho esto si pulsas F5 puedes ver que claramente ya me puedo autenticar con Google, pulsando en tu página “iniciar sesión”

Inicio sesión

4. Ahora antes de acceder con tu cuenta de Google a tu app quiero que abras el archivo “AccountController” de la carpeta “Controller” y pongas dos puntos de interrupción en los siguientes métodos.

ExternalLogin.

ExternalLoginCallback.

Con lo cual puedes observar rápidamente que el primero es un POST y el segundo un GET, pero fíjate en el atributo AllowAnonymous, vamos que aunque tu controlador esta decorado con “Autorize” esos dos métodos son públicos.

Por otra parte es lógico puesto que si no fuese así quien se podría autenticar y como pretendes que en este caso Google te envié un token y tu puedas comprobar que lo que te esta enviando es correcto, mediante un nuevo POST a Google, básicamente en este párrafo hemos descrito una gran parte de oauth.

En definitiva que te tiene que quedar claro que para realizar la autenticación con oauth en este caso es con OpenID, se hacen los siguientes pasos.

1. Un POST a tu página o si quieres puedes hacer GET y lidiar con XSRF CSRF tu mismo nadie te lo impide Guiño.

2. Rediriges a tu proveedor oauth/openid.

Es este paso pueden pasar dos cosas si no estás autenticado el proveedor te debe de pedir que te autentiques y una vez que te autenticas debes de autorizar a tu app. Si ya estás autenticado y autorizaste a tu app directamente el proveedor te va a redirigir al método ExternalLoginCallback.

3. Haces un post al servidor de oauth/openid “Server to Server” y este  valida  tu código de autorización y obtienes el token definitivo.

4. Si miras la lógica de este método ves un comentario con este texto.

         “// El usuario es nuevo, solicitar nombres de pertenencia deseados”

Pues gracias a las maravillas de MVC4 lo que se esta haciendo es guardar en una bb.dd información del usuario que se ha autenticado, con lo cual el generoso acaba de compartir parte de sus datos con dos sitios, ahora es por lo que empiezo a entender porque tengo mi bandeja de entrada en este estado.

 

Generoso

Por ser vago y muy generosoSonrisa.

5. Abre tu explorador de bb.dd desde visual studio y céntrate en las dos entidades que tengo desplegadas (me gusta un poco más definirlas como tablas) .

Membership

 

En la primera de ellas mira el campo UserName y verás un correo electrónico, te suena?.

El la segunda mira el campo Provider y ProviderUserId y empieza a acojonarte porque por los tiempos de los tiempos en esta web es tu usuario y password.

Y porque me tendría que acojonar te pongo el siguiente escenario.

En el proceso de desarrollo tu tienes que ir al cliente y la aplicación ya esta desplegada, con lo cual para sacar pecho delante del cliente no se te ocurre decir al cliente autenticate tu. Sino que lo haces tu  en Google con tu usuario y password. El cliente se queda súper contento y ve que esa parte esta terminada, que tíos más rápidos y más eficientes.

Sales del cliente y te vas a rendir cuentas al lacayo y al jefe , vas que no cabes en ti mismo, vamos que este día vas a tener una discusión con la mujer, porque es una mal pensada y tu un tío muy listo. En ese momento tu jefe factura 300.000 € que es 1/3 del valor del proyecto y que muy gustosamente el cliente paga.

Trascurridos los días suena el teléfono de tu mesa “rin,rin”.

Flaquito:Diga.

Cliente: Hola Flaquito.

Flaquito: Te funciona todo correcto no?.

Cliente:Si funciona también que hemos observado que la competencia tiene información de la página que estamos haciendo.

Flaquito:  Eso no puede ser, si la página esta toda protegida, si hemos diseñado  un controlador base del que heredamos al que le hemos puesto el atributo “Autorize”.

Cliente: Bueno pásame con el lacayo que esto hay que solucionarlo.

Flaquito: Venga te paso.

Narrador: En ese momento el sillón azul se empieza a mojar de un sudor frio y el flaquito no es capaz de concentrarse, se le ve nervioso, inquieto y sobre todo asustado, no entiende lo que ha podido pasar.

Pues te lo voy a empezar a contar que lo mismo te suena, por tener mucho cariño a tu cliente o presionado por el lacayo diciendo este, que eso no lo podemos hacer ahora que ya le hablaremos al cliente de https Triste.

Has hecho un despliegue en un sitio http y no https con lo cual mientras tu disfrutabas enseñando tu trabajo otro disfrutaba haciendo esto Ataque Man-in-the-middle.

Otro error que cometiste es que acabada la demo no te fuiste a la página de revocación de permisos de google y quitaste la app.

Y por último y más grave como estabas eufórico no pensaste que te habías dejado la sesión con Google abierta en el cliente del pc ,con lo cual cualquiera podía entrar en tu nombre a esa página.

Otra cosa que se te olvido fue advertir al cliente que tal y como estaba la página cualquier usuario con una cuenta Google o bien con una cuenta propia podría ver el contenido privado y por tanto tendrías que haber parado el sitio después de la demo, o mejor haber luchado por no hacer estas cosas,sin advertírselas al cliente.

 

Login asp.net

De que te esta protegiendo MVC4 de un ataque Cross Site Request Forgery,  pero  de lo que no te protege es de un JANUS.

Después de todo esto, tienes que hacer lo siguiente ver todo lo que ocurre con esa autenticación en tu sitio, para ello te recomiendo que sigas los siguientes pasos.

Si no conoces Fiddler descárgatelo y miras lo que pasa en todo este circo. Una herramienta recomendable, al igual que también lo es SQL Server Profiler  para cuando gratis en todas las versiones.

Una vez capturado todo el flujo de tu página cuando autenticas con Google te vas a encontrar con esto.

fiddler

Olvídate del Tunel to y vamos a analizar  todas las llamadas que no son HTTPS y que muy gustosamente alguien que no conoces ha podido leer por ti.

Vamos a elegir la primera la quinta y la última y como siempre siguiendo mi orden ilógico de las cosas voy a explicaros la última.

Para ello voy a pulsar en la carpeta cookies y me voy a quedar con una muy bonitaSonrisa .ASPXAUTH.

Después de “cerrar sesión”  vamos a ver lo que pasa si alguien te captura esto.

Vamos a la  carpeta Composer y voy a confeccionar esta llamada.

image

 

Estoy viendo al “flaquitoazul” y he cerrado sesión como puede ser Sonrisa

1. No estás convencido de utilizar https incluso en tus desarrollos?.

2. Has revisado alguna vez esto en tu webconfig

   1: <authentication mode="Forms">

   2:      <forms loginUrl="~/Account/Login" timeout="2880" />

   3: </authentication>

Esos 2880 son segundos o minutosSonrisa. Pero claro aún siendo segundos que no lo son(tiempo de vida igual a 48 horas) el atacante tiene las suficientes armas como expiar completamente tu web.

2. Vamos a centrarnos en la primera llamada del flujo, pero no en el request(llama a ExternalLogin) sino en el response.

Para ello quiero que te centres en “Location” y en “Set Cookie” vas a ver un par de cosas misteriosas.

__sid"__ : Identificador de sesión generado con este algoritmo

Guid.NewGuid().ToString(“N”).

__csid__": Cookie de sesion generada de forma un poco más seria pero que vive por el resto de nuestras vidas.

Como casi seguro que no te lo crees, vas a utilizar otra herramienta ILSPY y con esta vas a explorar lo que hace el método

“OAuthWebSecurity.RequestAuthentication” Pulsa F12 en el constructor de este código. Otra vez una sola línea era necesaria, que maravilla y que facil.Sonrisa

   1: [HttpPost]

   2: [AllowAnonymous]

   3: [ValidateAntiForgeryToken]

   4: public ActionResult ExternalLogin(string provider, string returnUrl)

   5: {

   6:   return new ExternalLoginResult(provider, Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));

   7: }

Bueno menos rollos y con toda esta información eres capaz de llegar al código fuente de este método

   1: // DotNetOpenAuth.AspNet.OpenAuthSecurityManager

   2: /// <summary>

   3: /// Requests the specified provider to start the authentication by directing users to an external website

   4: /// </summary>

   5: /// <param name="returnUrl">

   6: /// The return url after user is authenticated. 

   7: /// </param>

   8: public void RequestAuthentication(string returnUrl)

   9: {

  10:     Uri uri;

  11:     if (!string.IsNullOrEmpty(returnUrl))

  12:     {

  13:         uri = UriHelper.ConvertToAbsoluteUri(returnUrl, this.requestContext);

  14:     }

  15:     else

  16:     {

  17:         uri = this.requestContext.Request.GetPublicFacingUrl();

  18:     }

  19:     uri = uri.AttachQueryStringParameter("__provider__", this.authenticationProvider.ProviderName);

  20:     string text = Guid.NewGuid().ToString("N");

  21:     uri = uri.AttachQueryStringParameter("__sid__", text);

  22:     byte[] input = MachineKeyUtil.Protect(Encoding.UTF8.GetBytes(OpenAuthSecurityManager.GetUsername(this.requestContext)), new string[]

  23:     {

  24:         "DotNetOpenAuth.AspNet.AntiXsrfToken.v1",

  25:         "Token: " + text

  26:     });

  27:     HttpCookie httpCookie = new HttpCookie("__csid__", HttpServerUtility.UrlTokenEncode(input))

  28:     {

  29:         HttpOnly = true

  30:     };

  31:     if (FormsAuthentication.RequireSSL)

  32:     {

  33:         httpCookie.Secure = true;

  34:     }

  35:     this.requestContext.Response.Cookies.Add(httpCookie);

  36:     this.authenticationProvider.RequestAuthentication(this.requestContext, uri);

  37: }

Aquí tienes el __sid__ y el __csid__ y puedes comprobar si me estoy inventando algoSonrisa.

Después de todo el flujo  Google porque alguien se lo ha indicado, tu guardian, te devuelve la llamada al método “ExternalLoginCallback” que es donde verificamos haciendo un post a Google que lo que nos ha llegado el lo aprueba, si a Google le envías dos peticiones con la tercera de las llamadas te la va a rechazar porque para ello utiliza un “nonce”, es decir se preocupa .

Para ello con la herramienta ILSPY vas a llegar según lo que has podido leer hasta el método“ValidateRequestAgainstXsrfAttack” del que gustosamente te voy a enseñar el código.

   1: private bool ValidateRequestAgainstXsrfAttack(out string sessionId)

   2: {

   3:     sessionId = null;

   4:     string text = this.requestContext.Request.QueryString["__sid__"];

   5:     Guid guid;

   6:     if (!Guid.TryParse(text, out guid))

   7:     {

   8:         return false;

   9:     }

  10:     HttpCookie httpCookie = this.requestContext.Request.Cookies["__csid__"];

  11:     if (httpCookie == null || string.IsNullOrEmpty(httpCookie.Value))

  12:     {

  13:         return false;

  14:     }

  15:     string b = null;

  16:     try

  17:     {

  18:         byte[] protectedData = HttpServerUtility.UrlTokenDecode(httpCookie.Value);

  19:         byte[] bytes = MachineKeyUtil.Unprotect(protectedData, new string[]

  20:         {

  21:             "DotNetOpenAuth.AspNet.AntiXsrfToken.v1",

  22:             "Token: " + text

  23:         });

  24:         b = Encoding.UTF8.GetString(bytes);

  25:     }

  26:     catch

  27:     {

  28:         return false;

  29:     }

  30:     string username = OpenAuthSecurityManager.GetUsername(this.requestContext);

  31:     bool flag = string.Equals(username, b, StringComparison.OrdinalIgnoreCase);

  32:     if (flag)

  33:     {

  34:         HttpCookie cookie = new HttpCookie("__csid__", string.Empty)

  35:         {

  36:             HttpOnly = true,

  37:             Expires = DateTime.Now.AddYears(-1)

  38:         };

  39:         this.requestContext.Response.Cookies.Set(cookie);

  40:     }

  41:     sessionId = text;

  42:     return flag;

  43: }

Revísalo bien que no tiene desperdicio, sobre todo la comprobación que controla si estás autenticado y entonces  la cookie de sesión se establece a un año después de la fecha actual, buena táctica para ahorrar tráficoSonrisa.

Guardián te cuesta tanto poner en  la “DotNetOpenAuth.AspNet.dll” un parámetro que indique si el __SID__ es de un solo uso y que lo guardes con tu magnífico sistema SimpleMembershipProvider. Lo mismo a partir de ese momento me planteo utilizar tu mecanismo de oauth, de momento y por culpa de no haber escritos dos if más.

Yo no lo voy a utilizar, y por tanto tampoco lo voy a recomendar.

Esa mezcla de __SID__ Y __CSID__ es una caja de bombas y que con un ataque del tipo MitM existe un gran agujero de seguridad, cada día me fio menos de la eficiencia de https y nuestros señores de la poltrona preocupados por la ley de cookies Triste. Realmente quien te esta salvando es que al intentar reproducir el flujo, siempre te pide que te autentiques con Google, excepto que también te hayan robado las cookies de este.

Vamos con la quinta de las llamadas.

Aquí pueden pasar una cosa que por un error x tu no seas capaz de conectar con Google y verificar esa llamada con lo cual alguien que esta muy feliz tiene esta información mas la cookie __CSID__.

Si lo quieres reproducir en el método “ExternalLoginCallback” pon esta línea de código al principio del método para simular un posible error.

if (null==Request.QueryString["exception"])

                throw new Exception();

Analicemos esta llamada.

Error 500

Redirect desde Google a tu Web

   1: http://localhost:64324/Account/ExternalLoginCallback?

   2: __provider__=google&

   3: __sid__=84b05c1bcc0e4ab19c0abb60aea4dd64&

   4: dnoa.userSuppliedIdentifier=https://www.google.com/accounts/o8/id&

   5: openid.ns=http://specs.openid.net/auth/2.0&

   6: openid.mode=id_res&

   7: openid.op_endpoint=https://www.google.com/accounts/o8/ud&

   8: openid.response_nonce=2013-12-02T09:42:14ZNQdlYw60CWoxIg&

   9: openid.return_to=http://localhost:64324/Account/ExternalLoginCallback?__provider__=google&__sid__=84b05c1bcc0e4ab19c0abb60aea4dd64&

  10: dnoa.userSuppliedIdentifier=https%3A%2F%2Fwww.google.com%2Faccounts%2Fo8%2Fid&

  11: openid.assoc_handle=1.AMlYA9VFrtR0V1W4MTd_MnFq5lR-xeOYnhk5NjkMlxwVh4gtY6K3xLsbmwBycWiT&

  12: openid.signed=op_endpoint,claimed_id,identity,return_to,response_nonce,assoc_handle,ns.ext1,ext1.mode,ext1.type.alias1,ext1.value.alias1&

  13: openid.sig=EcSZxHAYCD7AxJOy+oiR6a/9OMQ=&

  14: openid.identity=https://www.google.com/accounts/o8/id?id=AItOawlA27JaQxHU_0iJ0VL4tPnWqqZgd00uo88&

  15: openid.claimed_id=https://www.google.com/accounts/o8/id?id=AItOawlA27JaQxHU_0iJ0VL4tPnWqqZgd00uo88&

  16: openid.ns.ext1=http://openid.net/srv/ax/1.0&

  17: openid.ext1.mode=fetch_response&

  18: openid.ext1.type.alias1=http://axschema.org/contact/email&

  19: openid.ext1.value.alias1=flaquitoazutl@gmail.com

Fíjate que de nuevo tienes el __sid__ , __csid__ y algún que otro dato interesante.

openid.identity que puedes comparar con el campo ProviderUserId que hay en la tabla OauthMemberShip y contarnos si no es el mismoSonrisa

Y otro parámetro interesante

openid.ext1.value.alias1=flaquitoazutl@gmail.com

Alguien más es conocedor de tu email y según se haga la petición posiblemente de algún dato más,sexo,nombre,apellidos,idioma.

Una vez capturado esto y quitada la línea que provocaba la excepción vamos con la consumación del acto.

Vamos a realizar una llamada a nuestro servidor componiendo con fiddler el siguiente request.

   1: GET http://localhost:64324/Account/ExternalLoginCallback?

   2: __provider__=google&

   3: __sid__=51b1d2614111410f8ff573088435ceaf&

   4: exception=1&

   5: dnoa.userSuppliedIdentifier=https%3A%2F%2Fwww.google.com%2Faccounts%2Fo8%2Fid&

   6: openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&

   7: openid.mode=id_res&

   8: openid.op_endpoint=https%3A%2F%2Fwww.google.com%2Faccounts%2Fo8%2Fud&

   9: openid.response_nonce=2013-12-02T11%3A43%3A39ZUv5SlO_0gY_TaQ&

  10: openid.return_to=http%3A%2F%2Flocalhost%3A64324%2FAccount%2FExternalLoginCallback%3F__provider__%3Dgoogle%26__sid__%3D51b1d2614111410f8ff573088435ceaf%26dnoa.userSuppliedIdentifier%3Dhttps%253A%252F%252Fwww.google.com%252Faccounts%252Fo8%252Fid&

  11: openid.assoc_handle=1.AMlYA9VV738T0nHJ2Sv9UxlUA4tL4dDgKavmu_zRka3MvccGoushjWDTJEbM87J5&

  12: openid.signed=op_endpoint%2Cclaimed_id%2Cidentity%2Creturn_to%2Cresponse_nonce%2Cassoc_handle%2Cns.ext1%2Cext1.mode%2Cext1.type.alias1%2Cext1.value.alias1&openid.sig=tf1%2BIuqIeqIoC2nrJD%2FxhbAbMc0%3D&

  13: openid.identity=https%3A%2F%2Fwww.google.com%2Faccounts%2Fo8%2Fid%3Fid%3DAItOawlA27JaQxHU_0iJ0VL4tPnWqqZgd00uo88&

  14: openid.claimed_id=https%3A%2F%2Fwww.google.com%2Faccounts%2Fo8%2Fid%3Fid%3DAItOawlA27JaQxHU_0iJ0VL4tPnWqqZgd00uo88&openid.ns.ext1=http%3A%2F%2Fopenid.net%2Fsrv%2Fax%2F1.0&

  15: openid.ext1.mode=fetch_response&

  16: openid.ext1.type.alias1=http%3A%2F%2Faxschema.org%2Fcontact%2Femail&

  17: openid.ext1.value.alias1=flaquitoazutl%40gmail.com HTTP/1.1

  18: User-Agent: Fiddler

  19: Cookie: __csid__=tARvCFSW5-uh8MQ_PTrmDdNz1pje0HMEjrbj7-w74yiVbqaUSMne8XHbWtw5kzKYzlKEZdscLyAZ1bRM8OV-Lg2

  20: Host: localhost:64324

Observa que después del __sid__ he puesto el parámetro exception esta vez con un valor para que nuestro servidor complete todo el flujo. Junto con la cookie __csid__

Y ahora observa el response

Response

Esto es difícil que se produzca por muchas cosas, pero se puede. Con lo cual otra cosa más para no utilizar el sistema de oauth de MVC4 .

1. Se tiene que dar que el usuario este logeado en Google o que te hayan robado las cookies de este.

2. Esto solo se puede ejecutar una vez puesto que Google controla.

openid.response_nonce=2013-12-02T11%3A43%3A39ZUv5SlO_0gY_TaQ

Una vez que esto llegue a Google ya no lo vas a poder enviar más, recibes una respuesta de este tipo.

HTTP/1.1 200 OK

Cache-Control: no-cache, no-store, max-age=0, must-revalidate

Pragma: no-cache

Expires: Fri, 01 Jan 1990 00:00:00 GMT

Date: Mon, 02 Dec 2013 11:46:01 GMT

Content-Type: text/plain; charset=UTF-8

X-Content-Type-Options: nosniff

X-Frame-Options: SAMEORIGIN

X-XSS-Protection: 1; mode=block

Server: GSE

Alternate-Protocol: 443:quic

Connection: close

is_valid:true

ns:http://specs.openid.net/auth/2.0

pero con “is_valid:false”.

Como puedes observar difícil  es pero tampoco imposible.

Todo esto lo he analizado gracias a una implementación que he tenido que hacer de oauth e integrar con:

SkyDrive

Rechazado por tener una api de juguete.

Google Drive

Nuestra herramienta de oficina para esa aplicación. Nos parece bastante mejor la api sin ser perfecta y las herramientas de usuario superan con creces a las de SkyDrive.

Para ello quiero que leáis con detalle estas dos entradas

http://msdn.microsoft.com/en-us/library/live/hh243647.aspx

https://developers.google.com/accounts/docs/OAuth2Login?hl=es

y que os centréis en ver el parámetro “state” si alguno se aburre le voy a pasar otro link a la especificación para que le quede claro el significado.

Primero os copio el texto.

state

         RECOMMENDED.  An opaque value used by the client to maintain

         state between the request and callback.  The authorization

         server includes this value when redirecting the user-agent back

         to the client.  The parameter SHOULD be used for preventing

         cross-site request forgery as described in Section 10.12.

No dejéis de leer la especificación y sobre todo no olvidar pasar por la section 10.12, lo mismo alguien descubre que lo que intenta hacer es lo mismo que “__SID__” Y “__CSID__”, Lo que no me gusta es que Micro me remita a la especificación sin mas explicaciones y lo que me gusta de Google es que por lo menos me copie el texto.

Ahora después de ver esto, tenemos que ver si “__CSID__” cumple con la ley de cookies que no me he leído y que por tanto desconozco. De antemano no me parece más que una causa recaudatoria y que poco soluciona el problemas de los flacos y de los generosos.

Otra cosa que se nos ocurrió fue disminuir el tráfico de nuestros servidores(se gestionan muchos documentos y descargarlos a tu servidor para después devolverlos sube la factura).

Para ello según  la especificación tu puedes pasar  en la url como parametro un  “acess_token” que es lo mismo que enviar Authorization en la cabecera de cada request, ni se te ocurra enviarlo en la url Sonrisa.

Lo  que hacemos es hacer una autenticación “Server to Server”  con JWT  y Google permite hacer Perform Google Apps Domain-wide Delegation of Authority (para cuando en  Office365) con lo cual si un administrador me autoriza a una serie de scopes el usuario no tiene que hacer dos login uno en nuestra app y otro en Google, no hace falta que se haga login en Google, simplemente conocer un usuario de Google y que el administrador haya autorizado tu app.

También puedes obviar el prn o sub de la  especificación JWT y tienes unas 15GB para almacenar documentos en tu app y los gdoc me parece que no cuentanSonrisa.

Pero porque digo que ni se te ocurra, sencillo el administrador me ha autorizado con lo cual en esa parte ando cubierto.

Pero la que no puedo cubrir es la de que un usuario malintencionado de tu propia organización pueda enviar la url a la competencia para que durante una hora pueda hacer uso de ella, tampoco solucionas mucho con el Authorization Request Header Field.

Si es mal intencionado y con un poquito de idea puede copiar el token simplemente con las developers tools del explorador, pero aún es mas malo.

No lo hace desde su ordenador sino que espera a que te vayas a tomar café y lo hace desde el tuyo, con lo cual sin comerlo y sin beberlo generoso inocente se te ha caído el pelo. El generoso malo por tu no haber cerrado sesión ha aprovechado tu momento de relax para limpiarse las manos.

Tenemos un registro de auditoría de los token generados por terceros y para cada usuario.

Solución Patata.

   1: var token = BuildToken("mi usuario en google");              

   2:  

   3: using (var client = new HttpClient())

   4: {

   5:     client.BaseAddress = new Uri("https://accounts.google.com");

   6:     var pairs = new List<KeyValuePair<string, string>>

   7: {

   8:     new KeyValuePair<string, string>("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"),               

   9:     new KeyValuePair<string,string>("assertion",token),                

  10:  

  11: };

  12:  

  13:     var result = client.PostAsync("/o/oauth2/token", new FormUrlEncodedContent(pairs)).Result;

  14:     var json = result.Content.ReadAsStringAsync().Result;

  15:     JToken tokenobject = JObject.Parse(json);

  16:  

  17:     string url = "No se muestra por motivos de seguridad"

  18:  

  19:     Task.Run(() =>

  20:     {

  21:         System.Threading.Thread.Sleep(2000);

  22:         using (var wcl = new HttpClient())

  23:         {

  24:             wcl.BaseAddress = new Uri("https://accounts.google.com");

  25:             var x = wcl.GetAsync(string.Format("o/oauth2/revoke?token={0}", tokenobject["access_token"].ToString())).Result;

  26:         }

  27:     });

  28:  

  29:     return Redirect(url);

  30: }

No he visto por ningún sitio la posibilidad en la especificación que esto se pueda hacer.

Que ocurre que unos gordos se reunieron para hacer esto y por lo visto no vieron una solución al “Authorization Request Header Field”

Authorization: Bearer XXXXXX.

Que pasa que no interesa hacer un Set-Autorization(Cambiar los browser cuesta dinero) en el que especifiques.

-El tipo “Bearer”

-El Token” XXXXX

-El dominio a quien va dirigido.

-La url para refrescar el token si se puede.

Vamos algo asi en el Response.

Set-Autorization: Bearer XXXXX;www.google.com;/oauth/refresch

Y que de una vez las dev tools  se puedan activar o no dependiendo de algo que envía tu página, es decir que puedas utilizarlas para desarrollo pero no cuando despliegas, muchos de los males se inician simplemente con esto.

Le doy un beso al primero que securize un <a href=””> de un sitio externo, que además me ha autorizado. Sin hacer chapuzas como la que nosotros hemos montado. Limitar el token a un solo uso. Hacemos revoque del token emitido, trascurrido unos segundos, Google solo emite token de 1 hora, posible errorSonrisa.

Mucho trafico “server to server” y poco usable para el usuario, si refresca la página le va a aparecer un 401.

Que andamos con pies de tortuga y mientras que los señores de la poltrona no intervengan y dejen de hacer leyes absurdas y se dediquen a lo que hacen, seguiremos igual.

Vamos que al final voy a proponer “Oauth 3.0” nombre en clave “El Oauth de la Onu”

El Oauth de la Onu.

1. Yo no soy ni Microsoft,Google,Twitter,Facebook soy de España al igual que “Sir Charles Spencer Chaplin” era de Inglaterra con lo cual ni sus datos ni los míos tienen que estar en EE.UU. o donde Dios quiera.

2. Que todo el que exponga el protocolo oauth y por tanto api o bien los consumidores(nosotros) nos registremos en un sitio oficial para poder trabajar, eso si que nos permita “el localhost” mientras desarrollamos(Micro revisa tu registro de app’s).

3. Que los fabricantes de apis no solo hagan herramientas de este tipo https://developers.google.com/oauthplayground/ sino que cada scope lo registren documentado para el developper y para el usuario, es decir que el generoso tenga muy claro que es lo que autoriza.

Creo que estoy defendiendo el principio de Oauth que es el no tener que estar pasando tu login y password a cada web, sino que cada país sea el responsable de sus ciudadanos.

Lo mismo te das cuenta señor de la poltrona que en vez de recaudar con leyes absurdas, estoy proponiendo que regules y nos des servicios.

4. Que te preocupes tu de regular los certificados y que sean gratis. Verás como nadie más utiliza http y se pasa a https  aunque ya se empiezan a tener dudas sobre su fiabilidad.

5. Una ley de Browser que cumpla con el w3c y el que no lo haga que automáticamente se le multe y no con 25000 €, lo mismo te cuesta menos esfuerzos y recaudas más.

5. Que no te quedes con estas 4 letras sino que hagas algo productivo que veo cerca la revolución de los generosos y flaquitos. La última vez que recuerdo  una de estas la  Poltrona se quedo vacía. Veo muchos Luises y alguna María Antonieta en la Wiki.

Conclusiones

Que me he hecho muy pesado y seguro que desde el punto de vista de algunos incluso me he pasado, pero he intentado describir cosas con las que me encuentro casi todos los días.

-Flaquito si cobramos 800 € es porque los hemos aceptado con lo cual, que los cobres no quiere decir que tu profesión y por eso la elegiste, no sea exclusivamente tu trabajo. Hay que estudiar y entonces puede ser que no cobres 800 ni tampoco te fíes de la mitad de lo que ves y te cuentan.

-Lacayos menos comisiones y menos primos Onofre y no vendas más motos ni zanahorias.

-Jefe hay que pagar y ganar dinero pero creo, por lo que he demostrado en el post, que tu afán por ello te ha llevado quizá a una demanda y no ha devolver los 300.000 € sino a pagar alguno más, En resumen tu sabrás si quieres seguir pagando 800€ y tratarnos como lomo al corte.

-Partner y demás no es necesario acumular personas con títulos emitidos por los gordos para no poder expresar cosas como estas “Todo no es genial”. 

-Gordos decir claramente que lo que estáis mostrando no es más que una demo y que no se utilice. Es decir menos templates en Visual Studio con agujeros y mejor documentación.

Menos clases internal y más código libre, quizá atraigas a más personas.

Plantéate que no si existe la posibilidad que desde nuget se pueda descargar el código fuente de las librerías y lo mismo la gente aporta cosas interesantes, con tanto ocultismo solo estás a expensas de que alguien lo diga. Piensa en la cantidad de gente que no habla, sabe de estos errores y los está aprovechando.

En definitiva que no utilices templates generadas que te pueden traer disgustos y que sirven para eso, para guiarte, pero nunca como el medio perfecto de hacer las cosas.

Y por último gorditos que no hagáis protocolos para tener cuentas e información en vuestro poder, que tanta política de privacidad me abruma.

Con lo cual flaquito por tu afán de hacer las cosas rápido, ahora estás paseando por la calle y los demás repuestos, pero se cometieron muchos errores que por otra parte te los pusieron a huevoSonrisa .