Las ventajas que te ofrece Microsoft Azure y el mundo.NET

Cómo securizar tus apps con Identity Server y .NET Core (Parte I)

Muchas veces recurrimos a servicios en el Cloud para mejorar nuestros desarrollos, uno de los que más se utiliza es es el  Azure Active Directory. No obstante, hay situaciones en las éste servicio no se adapta a los requerimientos del cliente, bien porque todavía no ha migrado a la Nube, o bien porque tiene el software en sus infraestructuras.

Hoy veremos un sistema que se encarga de autenticar, autorizar y securizar tanto las aplicaciones como los usuarios en nuestros desarrollo. La solución se llama Identity Server.

Son pocos los casos en los que no encaja (desde el punto de vista técnico), pero también tenemos que considerar a esa empresa que  quiere que el dominio de su página de Login sea www.suempresa.com y no  www.suempresa.microsoft.com con redirección a un sitio fuera de sus infraestructuras…

Para estos casos, solemos recurrir a un sistema de autenticación propio para dicha aplicación.

No obstante, esta solución tiene un problema. Conforme se van desarrollando más aplicaciones, cada una de ellas tiene un sistema de usuarios propio (o en el mejor de los casos está centralizado la tabla de usuarios). Otro de los problemas es que para dar permisos a aplicaciones de terceros, se suele dar de alta esta aplicación como un usuario más de la misma,  y cualquiera con pocas nociones de hacking podría acceder sin mucha dificultad.

Entonces ¿cómo podemos estandarizar este proceso y tener un único sistema que se encargue de autenticar, autorizar y securizar tanto las aplicaciones como los usuarios en nuestros desarrollo?. La solución se llama Identity Server.

Identity Server podemos definirlo como la parte que se encarga de gestionar las identidades en nuestros desarrollos. De la misma forma se encarga de implementar los protocolos comunes, tener nuestras aplicaciones seguras y seguir los estándares más comunes: OpenId y OAuth2.0.

¿Cómo empezamos a utilizar Identity Server?

Vamos a crearnos una solución .NET Core-> Con el proyecto Vacío. Tal y como se muestra en la siguiente pantalla:

Proyecto Asp NET

Nota: el seleccionar el proyecto vacío es debido a que como ASP NET Core es muy modular, podemos seleccionar qué cosas vamos a utilizar. De esta forma evitamos tener en nuestra solución elementos que no se van a utilizar, mejorando el tamaño de nuestra solución y evitando errores ajenos a nuestra aplicación.

Un vez tenemos el proyecto creado, añadiremos el Nuget de Identity Server.

nuget identity server

Los creadores de esta proyecto también han publicado otros paquetes de Nuget, para utilizar EntityFramewok, AspNET Identiy y un validador de Token entre otros. Más adelante veremos en qué casos los podemos utilizar.

El primer paso es identificar qué Resources vamos a securizar. Podemos definir  dichos «Recursos» como por ejemplo «API Empleados», «API Customers» etc..  Para ello, en nuestro Identity Server deberemos hacer uso del objeto APIResources. Creamos  una clase Config.cs con el siguiente código:

  public class Config
  {
    public static IEnumerable<ApiResource> GetApiResources()
    {
      return new List<ApiResource>
    {
        new ApiResource("APICustomer", "API de los customers de ENCAMINA"),
        new ApiResource("APIEmployee", "API de los empleados de ENCAMINA")
    };
    }
  }

A continuación crearemos los «clientes» que van a consumir dicha API. Pensad, por ejemplo, en la Aplicación MyEncamina . Dentro de esta aplicación hay una parte donde se muestra la información de los empleados de ENCAMINA. Por este motivo crearemos el siguiente método:

public static IEnumerable<Client> GetClients()
    {
      return new List<Client>
    {
        new Client
        {
            ClientId = "MyEncamina",
            // no interactive user, use the clientid/secret for authentication
            AllowedGrantTypes = GrantTypes.ClientCredentials,
            // secret for authentication
            ClientSecrets =
            {
                new Secret("++++++".Sha256())
            },
            // scopes that client has access to
            AllowedScopes = { "APIEmployee" }
        }
    };
    }

Dependiendo del tipo de acceso hay que pasar credenciales, o bien un client secret, esto sería similar a lo que en Azure Active Directory hacemos (ya sea montar una autenticación por usuario o autenticar una aplicación). Ya veremos ambos casos, en este caso lo que vamos a autenticar es una aplicación, a pesar de que sea una aplicación en la que no hace falta el login, tampoco es de recibo tener una API abierta a todo el mundo y que la pueda consumir 🙂

Una vez ya hemos implementado los Resources, vamos a securizar y definir qué clientes vamos a tener. El siguiente paso es configurar en el arranque de nuestra aplicación el middleware correspondiente de Identity Server. Para ello en el Startup.cs tenemos que poner lo siguiente:

 public void ConfigureServices(IServiceCollection services)
        {
       services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryApiResources(Config.GetApiResources())
        .AddInMemoryClients(Config.GetClients());
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
      app.UseIdentityServer();
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("Hello World!");
            });
        }

Si ahora arrancamos nuestra aplicación y nos posicionamos en la siguiente URL/: .well-known/openid-configuration, nos mostrará si tenemos correctamente configurado nuestro Identity Server, así como los endPoints disponibles y los Resources que va a tener. Como podéis ver, ya tenemos nuestros «resources»:

OpenID

Añadiendo a nuestra API el uso de Identity Server

Una vez ya tenemos nuestro servidor de Identity Server funcionando y listo, vamos a indicarle a nuestra API que se autentifique contra él. Para ello lo que vamos a hacer en primer lugar, es crear una WebAPI de .NET Core. Dentro de ésta añadiremos el paquete de Nuget IdentityServer4.AccessTokenValidation y dentro de nuestro proyecto añadiremos el siguiente código en el Startup:

  public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvcCore()
               .AddAuthorization()
            .AddJsonFormatters();

      services.AddAuthentication("Bearer")
          .AddIdentityServerAuthentication(options =>
          {
            options.Authority = "http://localhost:1907";
            options.RequireHttpsMetadata = false;

            options.ApiName = "APIEmployee";
          });
    }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
      app.UseAuthentication();
      app.UseMvc();
        }

Una vez hemos indicado que nuestra API va a tener autenticación y que estará delegada en nuestro servidor de autenticación, tenemos que poner en nuestro controlador al atributo Autorize. En nuestro caso puede quedar un código como el siguiente:

 [Route("api/[controller]")]
  [Authorize]
  public class EmployeeController : Controller
  {
    private IEnumerable<Employee> Employee;
    public EmployeeController()
    {
      var fakeEmployee = new Faker<Employee>()
        .RuleFor(x => x.LastName, x => x.Person.LastName)
        .RuleFor(x => x.Name, x => x.Person.FullName)
        .RuleFor(x => x.Country, x => x.Person.Address.City)
        .RuleFor(x => x.Email, x => x.Person.Email);
      this.Employee= fakeEmployee.Generate(10);

    }
    [HttpGet]
    public IEnumerable<Employee> Get()
    {
      return this.Employee;
    }

    [HttpGet("{id}")]
    public Employee Get(int id)
    {
      return this.Employee.ToList().Where(x => x.Id == id).FirstOrDefault();
    }
  }

¿Cómo consumimos nuestra API?

Para consumir nuestra API lo que tendremos es obtener un token según el estandar OAuth2.0. Para ello tenemos dos opciones:

1.- Una aplicación en .NET añadiendo un paquete Nuget que nos abstrae de esta comunicación.
2.- Mediante una aplicación tipo Postman, Fiddler en la que le enviamos las peticiones y bajamos a un nivel inferior.

En mi caso prefiero la segunda opción (y así tener el conocimiento de lo que está ocurriendo y ver el flujo de autenticación). Para obtener el Token hay que hacer una petición POST a nuestro servidor de Identity Server en la endpoint /connect/token y pasarle en el cuerpo de la petición el ClientID, el Client Secret y el Scope.
Esto por ejemplo, haciendo uso de un herramienta como Postman lo tiene implementado de una forma simple para evitar pedirnos el token cada vez. Para ello cuando seleccionamos dentro de Postman el Typo de Authorización OAuth2.0,  nos sale un botón para solicitar el token. Al pulsar dicho botón, nos muestra una pantalla donde tenemos que rellenar los datos indicados.

Indicaremos utilizar dicho Token y con el mismo, ya podremos hacer peticiones a la API sin ningún tipo de problemas.

Resumiendo y siguientes pasos

Hemos visto cómo poder utilizar una autenticación simple en nuestros desarrollos sin necesidad de implementar nada.

Ahora que ya hemos empezado a utilizar Identity Server, vamos a empezar a sacarle todo su jugo, es decir, vamos a añadir cómo autenticar usuarios mediante usuario y contraseña, y cómo podemos construir nuestras API’s empresariales y  separarlas de una forma similar a la API Graph.

Éste ejemplo lo podéis descargar desde nuestro repositorio de GitHub
Git Hub

 

mm

Sobre Adrián Díaz

Adrián Díaz es Ingeniero Informático por la Universidad Politécnica de Valencia. Es MVP de Microsoft en la categoría Office Development desde 2014, MCPD de SharePoint 2010, Microsoft Active Profesional y Microsoft Comunity Contribuitor 2012. Cofundador del grupo de usuarios de SharePoint de Levante LevaPoint. Lleva desarrollando con tecnologías Microsoft más de 10 años y desde hace 3 años está centrado en el desarrollo sobre SharePoint. Actualmente es Software & Cloud Architect Lead en ENCAMINA.
Esta entrada ha sido publicada en .NET, seguridad. Enlace permanente.
Suscríbete a Piensa en Sofware desarrolla en Colores

Suscríbete a Piensa en Sofware desarrolla en Colores

Recibe todas las actualizaciones semanalmente de nuestro blog

You have Successfully Subscribed!

ENCAMINA, piensa en colores