Try fast search NHibernate

16 April 2017

API-APP server-to-server through Azure Active Directory

In the previous post you see how register your API app in the AAD and how register a client app to then access using RESTful AAD api. The work to do to access your API is not so much using any langue, btw is even more easy using .NET.

The POC

Creates a new Console project and then add Microsoft.IdentityModel.Clients.ActiveDirectory package.

Client01

Now add this class to your project

using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;

namespace ClientFor1MApi
{
  public class ActiveDirectoryAuthHandler : DelegatingHandler
  {
    private const int maxAuthRetry = 3;
    private readonly AuthenticationContext authContext;
    private readonly ClientCredential clientCredential;
    private readonly string appIdUri;

    public ActiveDirectoryAuthHandler(AuthenticationContext authContext
      , ClientCredential clientCredential
      , string appIdUri
      , HttpMessageHandler innerHandler) : base(innerHandler)
    {
      this.authContext = authContext ?? throw new ArgumentNullException(nameof(authContext));
      this.clientCredential = clientCredential ?? throw new ArgumentNullException(nameof(clientCredential));
      this.appIdUri = appIdUri ?? throw new ArgumentNullException(nameof(appIdUri));
    }

    public ActiveDirectoryAuthHandler(AuthenticationContext authContext
      , ClientCredential clientCredential
      , string appIdUri) : base(new HttpClientHandler())
    {
      this.authContext = authContext ?? throw new ArgumentNullException(nameof(authContext));
      this.clientCredential = clientCredential ?? throw new ArgumentNullException(nameof(clientCredential));
      this.appIdUri = appIdUri ?? throw new ArgumentNullException(nameof(appIdUri));
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
      var authResult = await GetAuth();
      if (authResult != null)
      {
        request.Headers.Authorization = new AuthenticationHeaderValue(authResult.AccessTokenType, authResult.AccessToken);
      }
      return await base.SendAsync(request, cancellationToken);
    }

    private async Task<AuthenticationResult> GetAuth()
    {
      int retryCount = 0;
      bool mustRetry;

      do
      {
        mustRetry = false;
        try
        {
          // ADAL includes an in memory cache, so this call will only send a message to the server if the cached token is expired.
          return await authContext.AcquireTokenAsync(appIdUri, clientCredential);
        }
        catch (AdalException ex) when (ex.ErrorCode == "temporarily_unavailable")
        {
          mustRetry = true;
          retryCount++;
          await Task.Delay(3000);
        }
      } while ((mustRetry == true) && (retryCount < maxAuthRetry));

      return null;
    }
  }
}

We will use the implementation of HttpMessageHandler for the pipeline of the instance of HttpClient we will use to access to our API.

The HtppMessageHandler needs three parameters: AuthenticationContext, ClientCredential and appIDUri. To create each one we needs some information we have seen in the previous post and to be consistent I will reuse the same images.

The AuthenticationContext

To create an instance of the AuthenticationContext we need only the URL of the AAD where our API-app and our client are registered. It should look something like this:

Client02

The ClientCredential

To create an instance of ClientCredential we need the “Application ID” and the “Key” of our client registered un our AAD:

the Application ID is

AadPanel15

the key is

AadPanel14

The appIDUri

The App ID URI is the value we give to our API-app registered in our AAD

AadPanel02

The usage of ActiveDirectoryAuthHandler

  public class Program
  {
    static void Main(string[] args)
    {
      var aadInstance = "https://login.microsoftonline.com/yourAaadDomain.onmicrosoft.com";
      var clientAppId = "1e852e38-2ef9-439b-b696-dccaa811562c";
      var clientAppKey = "vRSDlEOAFrYi59zoVQyuamJv0ZPRegZTd87ugngD8aU=";
      var apiAppIdUri = "https://The1MApi.azurewebsites.net";

      var httpClient = new HttpClient(new ActiveDirectoryAuthHandler(
        new AuthenticationContext(aadInstance)
        , new ClientCredential(clientAppId, clientAppKey)
        , apiAppIdUri
        ))
      {
        BaseAddress= new Uri("https://The1MApi.azurewebsites.net")
      };

      var _ = httpClient.PostAsync("api/values"
        , new FormUrlEncodedContent(new Dictionary<string, string> { { "value", "a new value from client" } })).Result;

      var response = httpClient.GetAsync("api/values").Result;

      Console.Write(response.Content.ReadAsStringAsync().Result);

      Console.ReadLine();
    }
  }

Just remember that the instance of the HttpClient should be a singleton with the same lifecycle of your application.

Web API access through Azure Active Directory

In the past year I realized that is not so clear that any request arrive to our Web app or API app was analyzed by a Gateway; after deliver an API the question was the same: “Nice! the API is the opened to the world, how we can protect the access to our API ?”

The picture

WepAppAad01
As you can see the gateway is already there; is you don’t activate the authentication it just send, to your app, all requests.

Start protecting your API with Azure Active Directory (AAD)

I’m assuming you having your 1M USD API already deployed in your Azure subscription and you can access to it. Now follow this steps.
1. Go to the Azure portal, select your WebApp and select the authentication option. You should see something like this:
 AzureAuthPanel01
2. Turn On the Authentication button
AzureAuthPanel02
3. select the Azure Active Directory option to configure it.
NOTE: for this step you need “Global Admin” access to the AAD associated to the azure-subscription where your API was deployed. If you don’t have needed permissions don’t worry, somebody else can register the app for you and you can select it in the follow panel.
AzureAuthPanel03
After select “Express”, what you need is just give a name, to recognize it in AAD, to your app.
4. back to the panel of step 2 you will see the AAD configured and you have to change the action to take when a request come to your app and then Save the configuration.
AzureAuthPanel04
That’s all; without touch a single line of you API now, your API, is protected by AAD. If you try to access to your API you will see Azure asking you a login following the OAuth2 flow.

What happened in AAD

Because, sometimes, you don’t have permission to register an app in the AAD, is important to see what happened there and what is really important for us (poor tovarishch developers).
1. We having a new application registered
AadPanel01
2. The “Express” process (point 3 of previous section) have configured some properties of our new App and you have to know it because someone are important to access to your API from another application and some others are important if you need to explain how register the app in the AAD.
AadPanel02
AadPanel03
AadPanel04
In the “Properties” panel you have the name and home-page but from there you, as developer, have to know the “App ID URI”. For the “Reply URLs” you have to provide the URL of your API (not so much important for web-API). To allow users (developers) of your AAD to access to your API you must be sure on what is the configuration of “Required permissions”.

Allow access your Web-API from server-app (no web frontend)

With the previous steps we having a Web-app or an API-app where user have to login that can be enough for a web-app, or any web-enabled app, but a disaster if we need to consent access to a server unattended application. To consent access to a server application we need some others steps.
1. Add appRole to our API manifest
AadPanel05
the result of our modification should look something like this:
AadPanel06
The properties “description”, “displayName”, “id”, “value” are up to you (IIRC the id have to be a GUID).
2. Save the manifest
3. Back to our AAD register a trusted server application to consent access to you API
AadPanel07
AadPanel08
The name of the application is should be something that help you to recognize it and the “Sign-on URL” is whatever sound as a valid URL even if you know that the server app has no endpoints.






4. Back to the AAD you should see the new registered app and we can start configuring it
AadPanel09
In this case there are two things really important.
5. Add a new Required Permission
AadPanel10
take care to not trust what you see in the first list; you have to search your registered app and Select it (button at bottom).
6. Then add the real required permission
AadPanel11
The permission we are adding here is the same we have added to the Manifest of our API app. Check it, Select it, and “Done” it.
7. If the permission was added successfully you should see something like this
AadPanel12
8. The last step is set the key piece to access your API (aka client-secret, aka app-secret)
AadPanel13
After select the expiry you have to save the configuration and REMEMBER to copy the key value or you will have to create a new one.
AadPanel14
9. We need another piece to give to our API client: the Application ID.
AadPanel15

The state

At this point we having:
  1. Our API app registered and protected by AAD; if you want access to your API-app you have to login, with the credential registered in your AAD, following the OAuth2 flow.
  2. A client-application, whos have access to out our API-app, with its Application-ID and its Application-Key (step 8)
Our “Client application” can access to our API-app using REST in two steps (if your client is implemented with .NET then wait a little bit for the next post).

Access your Web-API from server-app

To test our access grant from REST I will use POSTMAN
AccessAadPostman01
  • the URL is the AAD Auth server to obtain a token for our API (the same used for lot of Microsoft’s services… scusate se é poco)
  • the client_id header is the “Application ID” of the API client (step 9)
  • the client_secret is the “key” of the API client (step 8)
  • the resource is the “App ID URI”of our API-app (point 2 of “What happened in AAD”)
The content of the response is what our API-Client have to use to authenticate itself accessing to our API-app.
AccessAadPostman02
When we try to access our API-app we have to add the Authorization header with the previous obtained token_type and access_token. The client application can use the same access_token for the expiration time (3600 = 3600 seconds) and then it have to request a new access_token in the same way. Because the request of the access_token is time-expensive the client application should retain the obtained token for the time specified in expires_in property. The process to access our API-app is RESTful and so it can be implemented from lot of languages.

16 January 2017

Azure queues by convention

El codigo que voy a mostrar hoy viene corriendo, con pocas variaciones a lo largo del tiempo, desde el 2009 cuando Azure era CTP así que somos ya varios que lo tenemos a mano (algo había compartido en el medio del camino).

Las interfaces

Como siempre es buena norma, por lo menos cuando se trata de servicios, empezar por las interfaces; más aún si terminan involucrados en varios proyectos que trabajan con Azure y/o onPremises o son hibridos en fase de metamorfosis (de monolitica oruga come recursos a espledida mariposa que vuela en las nubes).
La primer interfaz es la que uso normalmente para inicializar culquier cosa que tenga a que ver con lo storage (queues, blobs, tables, servicebus etc.):
  public interface IStorageInitializer
  {
    void Initialize();
    void Drop();
  }
Ya que estamos con queues vamos a tener un par de bichos más:
  public interface IEnqueuer<in TMessage> where TMessage : class
  {
    Task Enqueue(TMessage message);
  }

  public interface IDequeuer<out TMessage> where TMessage : class
  {
    TMessage Dequeue(int timeoutMilliseconds);
  }
En realidad en la mayoría de los casos, dificilmente uso el IDequeuer ya que quien usamos el WebJob SDK aprovechamos todo el sistema de polling que viene OOTB (out-of-the-box).

El template de VisualStudio “Azure WebJob” instiga a usar una clase static con una serie de metodos para consumir queues. Personalmente ese enjendro me gusta muy poco aunque entiendo el esfuerzo de hacer parecer siempre “las cosas” muy simples. Yo prefiero definir clases de Consumers de queues que puedo testear, inyectar, registrar y distribuir en varios workers según la evolución de la app lo necesite en su historia. Por ese motivo esta inteface:
  public interface IQueueMessageConsumer<in TMessage> where TMessage : class
  {
    Task ProcessMessage(TMessage message);
  }

 Convention over configuration

En lugar de lidiar con decenas de parametros de configuración, o las notorias “magic strings”, prefiero una simple convención para nombrar las queues.
  public class QueueNaming
  {
    private static readonly string[] queueMessageTypePostfixSequence = { "Message", "Event" };

    public static string AsQueueStorageName<TMessage>() where TMessage: class
    {
      return AsQueueStorageName(typeof(TMessage));
    }

    public static string AsQueueStorageName(Type messageType)
    {
      var typeName = messageType.Name;
      return ConvertToTableName(queueMessageTypePostfixSequence
        .Select(x => TrucateQueueName(x, typeName))
        .FirstOrDefault(x => x != null) ?? typeName);
    }

    private static string TrucateQueueName(string postfix, string typeName)
    {
      return typeName.EndsWith(postfix) ? typeName.Substring(0, typeName.Length - postfix.Length) : null;
    }

    public static string ConvertToTableName(string candidateName)
    {
      if (string.IsNullOrWhiteSpace(candidateName))
      {
        return null;
      }
      /* QueueName 3-63 lowercase alphanumeric and dash */
      return new string(candidateName.Where(x=> char.IsLetterOrDigit(x) || x == '-').Select(char.ToLowerInvariant).ToArray());
    }
  }
En practica uso el nombre de la clase (purgado si necesario) que representa el mensaje para nombrar la queue. Las limitaciones actuales de los nombres para algunos de los servicios de Azure Storage las pueden encontrar resumidas en este post : https://blogs.msdn.microsoft.com/jmstall/2014/06/12/azure-storage-naming-rules/

Implementaciones para Queue Storage

Vamos con el initializer que, en el caso de las queues, uso en el startup de la app
  /// <summary>
  ///   Initialize a queue storage specific for a message type.
  /// </summary>
  /// <typeparam name="TMessage">The type of the message</typeparam>
  public class QueueStorageInitializer<TMessage> : IStorageInitializer where TMessage : class
  {
    private readonly CloudStorageAccount account;
    private readonly string queueName = GetName();

    public QueueStorageInitializer(CloudStorageAccount account)
    {
      if (account == null)
      {
        throw new ArgumentNullException(nameof(account));
      }
      this.account = account;
    }

    public void Initialize()
    {
      var queueClient = account.CreateCloudQueueClient();
      var queue = queueClient.GetQueueReference(queueName);
      queue.CreateIfNotExists();
    }

    public void Drop()
    {
      var queueClient = account.CreateCloudQueueClient();
      var queue = queueClient.GetQueueReference(queueName);
      queue.DeleteIfExists();
    }

    public static string GetName() => QueueNaming.AsQueueStorageName<TMessage>();
  }
que uso de esta forma en la app Web y/o en los workers
      new QueueStorageInitializer<MyEntityChangedEvent>(account).Initialize();
y el Enqueuer
  public class QueueMessageEnqueuer<TMessage> : IEnqueuer<TMessage> where TMessage : class
  {
    private readonly CloudStorageAccount account;
    private readonly string queueName = QueueNaming.AsQueueStorageName<TMessage>();

    public QueueMessageEnqueuer(CloudStorageAccount account)
    {
      if (account == null)
      {
        throw new ArgumentNullException(nameof(account));
      }
      this.account = account;
    }

    public Task Enqueue(TMessage message)
    {
      if (message == null)
      {
        throw new ArgumentNullException(nameof(message));
      }
      var queueClient = account.CreateCloudQueueClient();
      var queueRef = queueClient.GetQueueReference(queueName);
      var serializedMessage = JsonConvert.SerializeObject(message);
      var qmessage = new CloudQueueMessage(serializedMessage);
      return queueRef.AddMessageAsync(qmessage);
    }
  }

 Implementaciones para Azure ServiceBus

El initializer
  /// <summary>
  ///   Initialize a servicebus queue specific for a message type.
  /// </summary>
  /// <typeparam name="TMessage">The type of the message</typeparam>
  public class ServiceBusQueueInitializer<TMessage> : IStorageInitializer where TMessage : class
  {
    private readonly string queueName = GetName();
    private readonly string serviceBusConnectionString;

    public ServiceBusQueueInitializer(string serviceBusConnectionString)
    {
      if (string.IsNullOrWhiteSpace(serviceBusConnectionString))
      {
        throw new ArgumentNullException(nameof(serviceBusConnectionString));
      }
      this.serviceBusConnectionString = serviceBusConnectionString;
    }

    public void Initialize()
    {
      var namespaceManager = NamespaceManager.CreateFromConnectionString(serviceBusConnectionString);
      if (!namespaceManager.QueueExists(queueName))
      {
        namespaceManager.CreateQueue(queueName);
      }
    }

    public void Drop()
    {
      var namespaceManager = NamespaceManager.CreateFromConnectionString(serviceBusConnectionString);
      if (namespaceManager.QueueExists(queueName))
      {
        namespaceManager.DeleteQueue(queueName);
      }
    }

    public static string GetName() => QueueNaming.AsQueueStorageName<TMessage>();
  }
y el Enqueuer
  public class ServiceBusEnqueuer<TMessage> : IEnqueuer<TMessage> where TMessage : class
  {
    private readonly string queueName = QueueNaming.AsQueueStorageName<TMessage>();
    private readonly string serviceBusConnectionString;

    public ServiceBusEnqueuer(string serviceBusConnectionString)
    {
      if (string.IsNullOrWhiteSpace(serviceBusConnectionString))
      {
        throw new ArgumentNullException(nameof(serviceBusConnectionString));
      }
      this.serviceBusConnectionString = serviceBusConnectionString;
    }

    public async Task Enqueue(TMessage message)
    {
      var client = QueueClient.CreateFromConnectionString(serviceBusConnectionString, queueName);
      var serializedObject = SerializeObjectAsString(message);
      using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(serializedObject), false))
      {
        var bmessage = new BrokeredMessage(stream)
        {
          ContentType = "application/json"
        };
        await client.SendAsync(bmessage);
      }
    }

    protected virtual string SerializeObjectAsString(TMessage message)
    {
      return JsonConvert.SerializeObject(message);
    }
  }

 May the Force be with me

Si este año no caigo en lado oscuro de la fuerza voy a seguir agregando codigo a este proyecto (GIT) con otras utilidades y, tal vez, ejemplos para Azure.