Publishing ASP.NET Core 3 Web API to Azure App Service with Http/2

Publishing ASP.NET Core 3 Web API to Azure App Service with Http/2

In my previous post I was testing a new ASP.NET Core 3 Web API that I’d created that simply returns header and http information about the request. Having got everything working locally I decided that I should push it into an Azure App Service to make it accessible from anywhere (this seemed to be easier than attempting to connect to my locally running service from a Xamarin.Forms application). Here’s the process:

Right-click on the ASP.NET Core project and select Publish.

image

In this case we’re going to select App Service (ie a Windows host) and Create New, followed by the Publish button. Next we need to give the new App Service a name and specify both a Resource Group and an App Service Plan – in this case I’m going to create all of these as part of the publishing process

image

Hitting Create will firstly create the necessary Azure resources and then it will proceed with publishing the ASP.NET Core project into the App Service. Unfortunately, once this process has finished you’ll see that the launched url doesn’t load correctly:

image

And secondly, when you return to Visual Studio you’ll see a warning prompt indicating that ASP.NET Core 3 isn’t supported in Azure App Service right now.

image

Luckily Microsoft documentation has you covered. If you go to the main documentation on publishing to Azure App Service there is a link of to deploying preview versions of ASP.NET Core applications. This document covers two different ways to fix this issue – you can either install the preview site extensions for ASP.NET Core 3, or you can simply change your deployment to be a self-contained application. In this case we’re going to go with deploying a self-contained application, since this reduces any external dependencies which seems sensible to me.

After returning to Visual Studio and dismissing the above version warning, you’ll see the Publish properties page with the default publish configuration (you can get back to this page by right-clicking your ASP.NET Core project and selecting Publish in the future).

image

We’re going to click the pencil icon along side any of the summary properties to launch the Publish dialog and change the Deployment Mode to Self-Contained, and the Target Runtime to win-x86. You may be tempted to select win-x64 but only do this if the Platform setting on your App Service is set to 64 Bit, otherwise your service won’t start and you’ll see a 503 service error.

image

Click Save and then the Publish button to publish the application using the updated publishing properties. Note that if you’re on a network that has a slow uplink (eg ADSL) this might take a while, so you might consider jumping on a fast network (eg 4G mobile) to do the upload (and yes, this does make Australia sound like an under-developed nation when it comes to access to the internet – sigh!).

Without any further messing around, the ASP.NET Core application launches correctly:

image

Hmmm, but wait, shouldn’t it be reporting HTTP/2, after all that’s what the browser was reporting when I ran the same service on Kestrel. There’s a couple of pieces to this answer but before we do, I want to remove any element on confusion as to what’s going on here by switching across to using curl – this way we have both control over what protocol we’re requesting but also detailed logging on what protocol is being used (you’ll see why this is important in a minute). Executing the following:

curl https://headerhelper.azurewebsites.net/api/values -v

image

As you can see from the image, the response was indeed done over Http/1.1, which is consistent with the Http protocol listed by the service. Ok, so let’s try requesting Http/2

curl https://headerhelper.azurewebsites.net/api/values –http2 –v

image

This call is successful but again returns Http/1.1 – this is because curl is attempting to request an upgrade to http/2 but the service isn’t willing/able to upgrade the connection.

curl https://headerhelper.azurewebsites.net/api/values –http2-prior-knowledge -v

image

This call fails because curl is forcing the use of Http/2 when in fact the service isn’t able to communicate using Http/2. So, how do we fix this? Well the good news is that Azure App Service has a simple configuration setting that can be used to enable Http/2. Here I’m just setting the HTTP version in the Configuration page for the Azure App Service.

image

This can also be set via the resource explorer, as covered by a number of other people (eg this post). After making your change, don’t forget to Save changes and then give the service 30-60seconds for it to be restarted – if you attempt to request the service immediately you’ll still get Http/1.1 responses.

After the change has been applied, here’s what we see when we use the same curl commands as above:

curl https://headerhelper.azurewebsites.net/api/values –http2 –v

curl https://headerhelper.azurewebsites.net/api/values –http2-prior-knowledge –v

image

Note that it doesn’t matter whether we attempt to negotiate the http/2 upgrade (–http2 flag) or force the point (–http2-prior-knowledge), in both cases the connection reports HTTP/2. However, what’s not cool is that the Http protocol returned by the service is HTTP/1.1 – this is what is seen by the ASP.NET Core Web API.

What we’re seeing here is that Azure is terminating the Http/2 connection and then communicating to the underlying ASP.NET Core application using Http/1.1. This is consistent with the way that SSL support is done – Azure terminates the SSL connection, meaning that your ASP.NET Core application doesn’t need to worry about fronting a secure service. This is awesome for developers that want to add SSL or HTTP/2 to their existing services – you just enable the option in the configuration page of your App Service. However, the down side is that it makes leveraging some of the underlying capabilities of HTTP/2 impossible – for example, it’s currently impossible to host a GRPC service in an App Service as this relies on HTTP/2 to function.

The question still remains – when I request the service from the browser, what protocol is being used? The response returns HTTP/1.1 because that’s what our ASP.NET Core application sees. However, if we look at the browser debugging tools, we can see that the response is indeed being handled over a HTTP/2 connection. Note that this isn’t exposed in the UI of the debugging tools but if you save the request you can see the full details:

image

Opening the HAR file in VS Code:

image

And there you have it – deploying an ASP.NET Core 3 application to Azure App Service and exposing it using HTTP/2.

Deploying ASP.NET Core 3 to Linux Azure App Service with Docker

Deploying ASP.NET Core 3 to Linux Azure App Service with Docker

In my earlier post I covered creating and debugging an ASP.NET Core service using Docker Desktop. I’m going to build on that and look at how you then push the service into an Azure App Service. Normally I’d simply use the publish option that would allow me to push the service directly into an Azure App Service – this would run the service in much the same way as it runs locally if I was debugging on IISExpress. However, since I’m debugging via a docker container I figured it’d be great to push to Azure in a way that it continues to run in a container. Actually the reason I explored this in the first place was that I’ve been experimenting with GRPC and currently this doesn’t seem to be able to be supported on a regular Azure App Service. I figured if I could run my code in a container there would be less restrictions so I would be able to get GRPC to work (this is work in progress still).

What I did notice in Visual Studio is that when I right-clicked on my ASP.NET Core project and selected Publish, one of the options I saw was to Create new App Service for Containers.

image

Clicking Publish started the wizard to allow me to create the appropriate resources in Azure.

image

Clicking Create will trigger the creation of the selected Azure resources and then proceed to publish the application.

Note: My initial attempt to published failed with an error

“The system cannot find the file specified. In the default daemon configuration on Windows, the docker client must be run elevated to connect. This error may also indicate that the docker daemon is not running.”

Turns out I didn’t have Docker Desktop running (I have so many apps like Slack, Teams, Skype etc that run in background that I force quit most of them each day to try to retain some semblance of a reasonable battery life on my laptop).

Once I realised that I needed to start Docker Desktop, the publish process kicked off and I saw the Docker deployment console appear with quite a detailed breakdown of the upload status – seriously why can’t Visual Studio’s build progress window be this useful. I really need to hand it to the Docker team as their uploading was super resilient. I started off uploading off our standard wifi connection which is based on an ADSL connection, so minimal upload bandwidth. I got impatient so switched mid-upload across to my mobile hotspot – after a second or two delay, the upload retried and continued without missing a beat.

image

Once publishing has completed, the Azure App Service should be all setup and ready to go with your code already published. You can use the Site URL in the publish information pane to launch the service for testing. Since my application was a web api, I’ve appended the /api/values so that I get a valid response from the Get request.

image

One of the thing that continue to amaze me about Visual Studio is the ability to create and publish new projects to Azure. Of course, for production apps, you wouldn’t follow this process at all but it does make spinning up end to end prototype applications a walk in the park.

Deploying Uno Wasm using Blob Storage

Deploying Uno Wasm using Blob Storage

Earlier today I posted about deploying Uno on Wasm to an Azure App Service (to which the Uno team replied on Twitter with an updated web.config). I was thinking a bit more about how I would deploy a real Uno Wasm app and I realised that of course, there’s no server side logic, so I could just go host it off Blob Storage.

I ran up the Azure Storage Explorer and created a new container within an existing Blob Storage account

image

As I’m going to be serving up content directly from Blob Storage I need to make sure that I enable public read access on the individual blobs (the default is that there’s no public read access on the container or blobs). Right-click on the container and select Set Public Access Level

image

Set access to Public read access for blobs only

image

Now you can simply copy the Uno Wasm application into the container by dragging the files from File Explorer into the right pane of the Azure Storage Explorer. I found that the best folder to copy is the folder that Visual Studio uses to deploy files when you do a Publish. For my project this is found at FirstUnoProject.WasmobjReleasenetstandard2.0PubTmpOutFirstUnoProject.WasmdistbinReleasenetstandard2.0dist.

And that’s it – now I can run my Uno Wasm application by clicking the Copy URL from the tool bar and then switching to my browser and launching the corresponding URL.

image

The Uno Wasm application runs without any further configuration required.

image

Publishing Uno WebAssembly (Wasm) to Azure App Service

Publishing Uno WebAssembly (Wasm) to Azure App Service

I figured that since I had Uno working in WebAssembly locally on my machine that I’d try publishing it out to an Azure App Service. I mean, how hard could it be since Visual Studio recognises that the Wasm project is a web project (nice job there team Uno!) and even gives me the option to Publish.

image

Stepping through the publish wizard I decided to create a new Azure App Service

image

I made use of an existing Resource Group and App Service Plan that I had lying around.

image

After hitting Create and publish Visual Studio went off thinking for what seemed like a long time with nothing happening. I knew it was probably busy packaging and deploying but I didn’t see anything appear in the Output window…… not surprisingly because Visual Studio pushes all the logging for the publish operation to the Web Publish Activity window.

image

Once it was done Visual Studio launches a browser window displaying the root of the newly created App Service. Unfortunately, this is not my Uno project.

image

After investigating a little I realised that the publish operation was uploading the Wasm project to a sub folder of the wwwroot folder within the App Service (eg  wwwrootFirstUnoProject.WasmbinReleasenetstandard2.0distindex.html). I validated this by using the Advanced Tools from the Azure portal.

image

From the Advanced Tools, select Files

image

Browsing the files you can locate the index.html that gets published with the Wasm project. This is the file that hosts the wasm

image

Unfortunately just adding the appropriate path to the index.html to the site url doesn’t seem to work (ie this doesn’t work: https://firstunoproject.azurewebsites.net/FirstUnoProject.Wasm/dist/bin/Release/netstandard2.0/dist/index.html). However, you can easily set up a new application to point to the dist folder. Go to Application Settings and under the section Virtual  applications and directories, create a new mapping. In this case I’ve mapped /uno to the sitewwwrootFirstUnoProject.WasmdistbinReleasenetstandard2.0dist folder (you can get the folder from the “path” shown in the Kudo – Files explorer) and I’ve made it an Application.

image

If you now attempt to go to the index.html page in your new mapped folder (eg https://firstunoproject.azurewebsites.net/uno/index.html) you’ll find that you’ll see the “Loading…” text that comes with the Uno project template but your application won’t load. If you spin up the Chrome debugging tool you’ll see that it’s not able to find the mono.wasm file with a 404 being raised. Don’t bother trying to work out whether the file exists or not because the issue is that whilst the file exists, the Azure App Service isn’t going to serve it because it’s not a known file type. Luckily there’s a simple solution. Add the following Web.config to your Wasm project and publish your application again.

<?xml version=”1.0″ encoding=”UTF-8″?>
<configuration>
   <system.webServer>
     <staticContent>
       <remove fileExtension=”.clr” />
       <remove fileExtension=”.dll” />
       <remove fileExtension=”.json” />
       <remove fileExtension=”.wasm” />
       <remove fileExtension=”.woff” />
       <remove fileExtension=”.woff2″ />
       <mimeMap fileExtension=”.dll” mimeType=”application/octet-stream” />
       <mimeMap fileExtension=”.clr” mimeType=”application/octet-stream” />
       <mimeMap fileExtension=”.json” mimeType=”application/json” />
       <mimeMap fileExtension=”.wasm” mimeType=”application/wasm” />
       <mimeMap fileExtension=”.woff” mimeType=”application/font-woff” />
       <mimeMap fileExtension=”.woff2″ mimeType=”application/font-woff” />
     </staticContent>
     <httpCompression>
       <dynamicTypes>
         <add mimeType=”application/octet-stream” enabled=”true” />
         <add mimeType=”application/wasm” enabled=”true” />
       </dynamicTypes>
     </httpCompression>
   </system.webServer>
</configuration>

Now you should be able to launch your Uno wasm-based application hosted in Azure App Service

image

Connecting Flutter to Azure at MS Ignite | The Tour – Sydney

Flutter at MS Ignite | The Tour – Sydney

This year I was lucky enough to be able to present at Microsoft’s Ignite | The Tour, which has just concluded here in Sydney. What amazed me was that I got to present on a fledgling technology recently released by Google, Flutter. Of course, this by itself wouldn’t have been sanctioned at a Microsoft event, so the important part was that I was presenting on connecting Flutter to Azure, and highlighting just how powerful the Azure options are for mobile app developers on any platform.

Using Flutter to develop cloud enabled mobile applications

Flutter is one of the newest cross-platform mobile application development frameworks and brings with it the ability to generate high-fidelity applications that look amazing on every device. This session begins with a very brief overview of Flutter, covering the tools and resources required to get started. The remainder of the session connects a Flutter application to key Azure services such as Identity and App Center. The key takeaway from this session is how Azure accelerates the development of mobile applications irrespective of what technology or framework the app is developed with.

In this post I’m going to walk through the demo portion of the session, which revolved around the creation of a very simple task style application.

Getting Started – New Project

Let’s get started by creating a new project in VS Code (If you haven’t already got the Flutter SDK installed, go to https://flutter.io and follow the Get Started button in top right corner). In VS Code in you press Ctrl+Shift+P and type Flutter you’ll see all the available options.

image

Select “Flutter: New Project” and you’ll be prompted to give your project a name – I was short on inspiration for a name for the project, hence “World’s Best Flutter App”. Note that the name of your project needs to be all lowercase, no spaces or special characters.

image

You’ll need to select a folder to put your new project in, and then VS Code will generate a default application that consists of a basic UI which includes a button that increments a counter on the screen. We’re going to start by removing most of this and replacing it with:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'World\'s Best Flutter App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'World\'s Best Flutter App'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
    );
  }
}

As with all new projects, at this point I’d highly recommend running the application to make sure everything has been correctly created and that you have a running application – there’s nothing worse than investing hours into crafting an amazing solution only to have to debug it for hours because of some issue that happened early in the process. At this point there’s not too much to the application other than the title bar

image

Basic Task List

The first piece of functionality we’re going to add is the ability to enter a tasks and see them appear in a list. To do this we need a text entry (TextField widget) and a list (ListView widget) and we’re going to present them with the text entry above the list in a vertical stack (Column widget). Before adding the widgets I’m going to add a couple of instance variables to the _MyHomePageState class (note that this is the state that goes with the MyHomePage stateful widget):

class _MyHomePageState extends State<MyHomePage> {
  //// Controller for TextField and List of tasks ////
  final TextEditingController eCtrl = new TextEditingController();
  List<String> tasks = [];

Now we can add our widgets to the body property on the Scaffold widget:

return Scaffold(
  appBar: AppBar(title: Text(widget.title)),
  ////  Body of the app is made up of a single column ////
  body: new Column(
    children: <Widget>[
      ////  TextField to capture input ////
      new TextField(
        controller: eCtrl,
        onSubmitted: (text) {
          tasks.add(text);
          eCtrl.clear();
          setState(() {});
        },
      ),

      ////  Expand ListView to remaining space ////
      new Expanded(
        child: new ListView.builder(
          itemCount: tasks.length,
          itemBuilder: (BuildContext ctxt, int index) {
            return Padding(
              padding: EdgeInsets.fromLTRB(10, 10, 5, 5),
              child: Text(tasks[index]),
            );
          },
        ),
      ),
    ],
  ),
);

A couple of things to note here:

  • It appears that I’ve added a couple of trailing commas – this is by design and lets the auto formatter know to position things on new lines. This is really important as Flutter code can get really messy if you don’t keep an eye on the layout of the code
  • Pressing Shift+Alt+F in VS Code will apply the auto formatter and makes the code much more readable – take a look at the following image to see how VS Code presents the above code
image

At this point we have a working app where a user can enter a task and it’s added to a list of tasks that is presented in the lower area of the screen. There are plenty of online tutorials etc that talk about layout and how setState works so I’m not going to cover that here. If you’re unfamiliar with Flutter/Dart code I would suggest at this point taking the time to go and understand what’s going on in the code – we’re going to build on it, so it’s important you understand how things work before we move on.

Visual Studio App Center

Before adding any more functionality to the app, I want to first take a side step to discuss the use of Visual Studio App Center which has been specifically created by Microsoft to support app developers, providing capabilities for building, testing, distributing apps, along with services such as analytics, crash reporting and push notifications. Currently support for Flutter is via a third party plugin which only provides analytics and crash reporting but we can expect this to grow as more developers take on Flutter and put pressure back onto Microsoft to provide official support, similar to what’s already provided for React Native and other cross platform technologies.

For our tasks app we’re going to make use of the analytics and crash reporting, as well as the support for distributing the application via App Center. To do this we first need to go to App Center and register two applications: one for iOS and one for Android. Got to either https://mobile.azure.com or https://appcenter.ms and sign in using your preferred credentials – my preference is to use my Office 365 (ie Azure Active Directory) account as this plays nicely into the way I sign into the rest of Azure and makes things like billing etc really easy. After creating your account, if you locate the apps list, then in the top right corner you should see an Add new button, which gives you the option to Add new app

image

In the Add new app flyout, you need to provide an App name and provide information about the OS and Platform – these are more important if you’re going to use App Center to build the application but is also relevant to the distribution process, so it’s important that you set these correctly (Note: Adam Pedley has a great walk-through of using App Center for build and distribution of Flutter apps). Since the App name needs to be unique within your App Center instance, it makes sense to use some sort of platform identifier as part of the name so it’s easy to identify the iOS and Android apps in the list.

image

After creating the app, you’ll be presented with some platforms specific getting started documentation. Most of this can be ignored as it’s not relevant to our Flutter application. However, you do need to extract the id that’s been assigned to your application. This can be found as part of the code samples eg:

image

After creating the app registrations in App Center, we now need to add in the Flutter plugin into our application and initialize it with the app id. Note that because App Center issues a different app id for each platform, you need to include some conditional platform logic to determine which app id to use. There are three plugins you need to add to your pubspec.yaml file under the dependencies section:

All packages are based on the source code at https://github.com/aloisdeniel/flutter_plugin_appcenter developed by Aloïs Deniel and Damien Aicheh

dependencies:
  flutter:
    sdk: flutter
  appcenter_analytics: ^0.2.1
  appcenter_crashes: ^0.2.1
  appcenter: ^0.2.1

After adding in the packages, we also need to import the relevant types to the top of our main.dart file:

////  Imports for platform info ////
import 'package:flutter/foundation.dart' show defaultTargetPlatform;
import 'package:flutter/foundation.dart' show TargetPlatform;

////  Imports for App Center ////
import 'package:appcenter/appcenter.dart';
import 'package:appcenter_analytics/appcenter_analytics.dart';
import 'package:appcenter_crashes/appcenter_crashes.dart';

Next we need to initialise the App Center plugin but adding code to the _MyHomePageState class

class _MyHomePageState extends State<MyHomePage> {
  ////  Identifier used for initialising App Center ////
  String _appCenterIdentifier = defaultTargetPlatform == TargetPlatform.iOS
      ? "3037d80f-XXXXXXXXXXX-adb968c67880"
      : "f6737675-XXXXXXXXXXX-be38b29b0f89";

And then a call to the AppCenter.start method when the class initialises – we’re overriding the initState method to call this logic when the instance of the _MyHomePageState is first created:

////  Override Initialise State ////
@override
void initState() {
  super.initState();
  initAppCenter();
}

////  Initialise AppCenter ////
void initAppCenter() async {
// Initialise AppCenter to allow for event tracking and crash reporting
  await AppCenter.start(
      _appCenterIdentifier, [AppCenterAnalytics.id, AppCenterCrashes.id]);
}

The last thing we’re going to do is to add a call to the trackEvent method for when an item is added to the tasks list. For this we’re going to modify the onSubmitted callback on the TextField

onSubmitted: (text) {
  ////  Tracking event ////
  AppCenterAnalytics.trackEvent("Adding item", {"List Item": text});

Now when you launch the app, and start adding tasks you’ll see some tracking of app related activity appear within the Analytics tab of App Center:

Note: If you get errors at this point, you may need to stop and restart your application to make sure the newly added packages are correctly built and deployed as part of your application. Hot reload doesn’t always handle this well.

image

You can see information about events raised by the app

image

Including the ability to drill down into the event and see more information, in this case you can see the List item that were added to the task list – note that this is an application specific key-value combination specified as part of the call to trackEvent.

image

 

Build and Release Automation

Before we can start distributing our app via App Center we typically setup a build and release (aka a DevOps) pipeline for our application – at Built to Roam this is one of the first things we encourage all our clients to do as it significantly cuts down on the manual steps involved, resulting in fewer errors and less wasted time. For this, we rely on Azure DevOps, and again a big shout out to Aloïs Deniel who’s created an extension for Azure DevOps – https://marketplace.visualstudio.com/items?itemName=aloisdeniel.flutter

image

After adding this extension to your Azure DevOps tenant, you can easily setup a build and release pipeline – there are a few steps involved in this, so I’ll keep this for a follow up post. The build steps involve tasks for Installing Flutter, Building the app with Flutter, Copying the generated app to the artefacts folder and the Publishing the artefacts. The release steps simply involves uploading the generated app to App Center. You can of course adjust these to add functionality and perhaps target different environments for testing, and of course uploading to the relevant stores directly from your release pipeline.

Update 22/9/2019: There are two other extensions for Azure DevOps for working with Flutter. The first simply makes it easier to install the Flutter SDK. The second is an update to the extension Aloïs created that adds AAB support – if you want to use this extension, make sure you uninstall the original extension Aloïs created because the two conflict and appear as a duplicate.

Once you have your build and release pipelines in place, you should start to see your releases appear in the Distribute / Releases tab in App Center

image

If you open App Center on your iOS or Android device you can install each release for testing.

Azure App Service

Right now we actually have a pretty useless app since all it does is record tasks in memory. When you restart the app, your list of tasks will be gone. Plus there’s no way to have your list of tasks appear on another device etc. We’re not going to complete the entire app in the blog post but what we do want to do is show how easily you can connect a Flutter app to some backend services hosted in Azure.

First up, let’s take a look at the backend service we’re going to connect to. In the demo I used an ASP.NET Core application that was published to an Azure App Service but I could just have easily used a Functions app. The application consistent of a single controller that currently only supports a Get operation to retrieve a list of tasks, which for the moment are hardcoded.

[Route("api/[controller]")]
[ApiController]
public class TasksController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public ActionResult<IEnumerable<Task>> Get()
    {
        return new[]
        {
            new Task {Title = "Task 1", Completed = true, },
            new Task {Title = "Task 2", Completed = false,},
            new Task {Title = "Task 3", Completed = true, },
            new Task {Title = "Task 4", Completed = false,},
            new Task {Title = "Task 5", Completed = true, },
        };
    }
}

public class Task
{
    public string Title { get; set; }
    public bool Completed { get; set; }
}

 Swagger

It’s also worth noting that in the Startup.cs of this application I added in the logic to generate Swagger information for the service (You need to add a NuGet reference to Swashbuckle.AspNetCore.Swagger, Swashbuckle.AspNetCore.SwaggerGen and Swashbuckle.AspNetCore.SwaggerUi):

public class Startup
{
    …
    public void ConfigureServices(IServiceCollection services)
    {
        …
        services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new Info { Title = "Simple ToDo", Version = "v1" });
            });
        …
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        …
        app.UseSwagger();
        app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "Simple ToDo V1");
            });
        …
    }
}

Update 12/11/2019: If you’re using .NET Core 3 preview, you’ll need to upgrade to the preview of Swashbuckle NuGet packages and change the Info class reference to OpenApiInfo. Although at time of writing, there is an issue with the Dart code generator based on the swagger generated by .NET Core 3 preview, so perhaps best to stick with .NET Core 2.2 until v3 is officially released.

This application was published to a new Azure App Service which meant that both the /api/tasks endpoint, as well as the swagger endpoints were publically available. We’ll come back to securing these in a bit. To be able to call the tasks endpoint we could have gone ahead and created a raw http request and then have to worry about decoding the returned json into a series of entities, for which we’d have to write, or generate, the decoding logic. Instead, I went over to SwaggerHub and imported the swagger endpoint:

image

After selecting “Import and Document API” I entered the url for the swagger endpoint on the Azure App Service eg https://simpletodonick.azurewebsites.net/swagger/v1/swagger.json

image

After hitting Import SwaggerHub will convert your json formatter swagger into YAML – we’re not really interested in this piece, since what we’re after is some generated Dart code. However, before we can go ahead and generate the Dart code we first have to configure the generator options for Dart. Click on the Export button in the top right of the SwaggerHub page, followed by Codegen Options.

image

Locate “dart” in the left hand tree, and then set the browserClient property to false – by default the Dart generator creates code suitable for Dart being used for web development. For Flutter you need to set this property to false.

image

Going back to the Export menu, now select “dart” from under the Client SDK option.

image

This will automatically generate and download a package that will include a strongly typed set of classes for accessing the tasks endpoint. I extract this folder and place the contents of the generated zip file into a new sub-folder called “tasks” at the root of the Flutter application.

image

After adding the files into the folder, I then needed to update the pubspec.yaml file for my application to include the package as a dependency, as well as the http package:

dependencies:
  flutter:
    sdk: flutter
  appcenter_analytics: ^0.2.1
  appcenter_crashes: ^0.2.1
  appcenter: ^0.2.1
  http: '>=0.11.1 <0.12.0'
  swagger: 
    path: tasks 

(note that “swagger” correlates to the name of the imported package which is defined with the pubspec.yaml file within the tasks folder)

Update 22/9/2019: There’s an incompatibility between a new Flutter project and the generated Dart code. To fix it you need to update the pubspec.yaml inside the tasks folder to include the same environment value as the pubspec.yaml for your application.

Now to make use of the generated code in our application, I also needed to add a imports statement to the main.dart file.

////  Import for Swagger ////
import 'package:swagger/api.dart';

As we’re going to be using the Task entity described by the Swagger I need to update the list variable from a List<string> to List<Task>. I also added the base url for the app service.

////  Change List to use Task ////
List<Task> tasks = [];

////  Base url for the Simple ToDo service ////
final _baseUrl = 'https://simpletodonick.azurewebsites.net';

At this point I also needed to fix up the existing task list functionality which expected a string, to use a Task entity. This was in two places, firstly when creating a new task I needed to create a new Task:

tasks.add(
  Task()..title = text,
);

And then when displaying the tasks in the list

child: Text(tasks[index].title),

Now with the app back up and running, we can go ahead and call the service in order to retrieve the tasks when the app launches.

void loadData() async {
  ////  Calling App Service ////

  // Setup api client with base url and token returned by auth process
  var client = ApiClient(basePath: _baseUrl);

  var tasksApi = new TasksApi(client);

  var downloadedTasks = await tasksApi.callGet();
  setState(() {
    tasks = downloadedTasks;
  });
}

The loadData method should be called from the initState method, just after calling initAppCenter. Running the app at this point should return a list of tasks on startup and then allow subsequent tasks to be added (of course at the moment those tasks aren’t saved anywhere!)

Authentication with Azure B2C

Currently there is no security applied to the app service, which is clearly not only bad practice, it also means that it is impossible to personalise the task list to the individual user, since everyone will be returned the same list of tasks. The good new is that we can add authentication to our service without writing a single line of code. To do this we’re going to choose to use Azure B2C. However, Azure App Services can also use a variety of different social credential providers to authenticate the user.

For this application I created a new instance of Azure B2C and setup the default B2C_1_signupandin user flow (aka policy). After creating the instance and the user flow, you still need to associate the Azure B2C instance with the app service and vice versa. To do this, start by creating a new application registration within the Azure B2C portal – go to Applications tab and click Add button.

image

In creating the application registration we want to enable both web app/api and native client. You’ll notice that under the Native Client area there is a Custom Redirect URI specified. To do authentication using the flutter_appauth plugin (which I’ll come to in a second) the Custom Redirect URI should be in a similar format ie <reverse domain>://oauthredirect.

After creating the application registration, take note of the Application ID – you’ll need this when we update the Authentication on the App Service that requires a Client Id.

The next thing to do, also in the Azure B2C portal is to navigate to the User flows (policies) tab and then click the Run user flow button.

image

From the Run user flow dialog, copy the link at the top (eg https://worldsbestflutterapp.b2clogin.com/worldsbestflutterapp.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=B2C_1_signupandin)

Now we need to switch across to the App Service in the Azure Portal and click on the Authentication tab. Initially App Service Authentication will be set to Off and there is a warning that anonymous access is permitted.

image

Switch the App Service Authentication to On and under Authentication Providers, click through on the Azure Active Directory settings.

image

Use the Application Id captured when setting up the Azure B2C as the Client ID. Use the link recorded from the Run user flow dialog as the Issuer Url. Click OK to commit the Azure Active Directory settings.

Back in the Authentication / Authorization settings, make sure that the “Action to take when request is not authenticated” dropdown is set to “Log in with Azure Active Directory” – this will enforce sign in if no Authorization token is presented.

image

After hitting Save, if you attempt to access the app service you’ll find that you get a security exception (if sending raw requests), or redirected to the sign in prompt if attempting to load the endpoint in a browser.

 Authentication in Flutter using Flutter_AppAuth

After setting up authentication on the app service, if you attempt to run the application it won’t be able to retrieve the list of tasks as the requests are unauthenticated. In order to create a request that is authenticated (ie supplies a validate Authorization header in this case) we need to get the user to sign into the application. Luckily there is a Flutter plugin, flutter_appauth (source code), that has been created by Built to Roam colleague Michael Bui, that wraps AppAuth iOS and Android libraries.

image

There are a few steps involved in getting our application setup to use flutter_appauth. We’ll start by adding the package reference to the pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter
  flutter_appauth:
  ...

Next, we need to upgrade the Android application to use the AndroidX libraries instead of the older support libraries. To do this we need to open the Android part of the flutter application in Android Studio. Right-click on the android folder in VS Code and select the Open in Android Studio option.

image

When prompted to “Import Project from Gradle” you can accept the defaults and click Ok. The application may take a few minutes to open in Android Studio and you’ll need to allow a bit of extra time for Android Studio to finish processing the application before the Migrate to AndroidX option becomes enabled in the Refactor menu:

image

Side note: The first couple of times I tried this whilst preparing this demo Android Studio kept saying that there was nothing to update. It turns out that there was an update to the Flutter plugin to Android Studio that was waiting to be installed – I did this, which resulted in Android Studio reloading. After reloading the folder structure under Project expanded to show the referenced flutter plugins as well as any external libraries. At this point running Migrate to AndroidX worked.

When Migrate to AndroidX does work for you it’s not immediately obvious that something has changed…. which is because it hasn’t. Instead Android Studio will have opened up a tool window at the bottom of the screen, prompting you to confirm the Refactoring Preview. Click Do Refactor to complete the migration.

image

If you look in the /android/app/build.gradle file you should see that the dependencies list at the end of the file have been updated.

dependencies {
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.0-alpha'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha'
}

At the point of writing this post the migration process references alpha versions. You can update this to reference the stable versions now:

dependencies {
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
}

Whilst in the build.gradle file the compiledSdkVersion and targetSdkVersion should be increased to at least 28. Lastly, update the defaultConfig element to include manifestPlaceholder

defaultConfig {
    applicationId "com.example.worldsbestflutterapp"
    minSdkVersion 16
    targetSdkVersion 28
    ...
    manifestPlaceholders = [
            'appAuthRedirectScheme': 'com.builttoroam.simpletodo'
    ]
}

Note that the appAuthRedirectScheme should match the reverse domain part of the Custom Redirect URI property set when setting up Azure B2C earlier.

For iOS open the /ios/Runner/Info.plist file and add the CFBundleURLTypes key/value as follows.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	...
	<key>CFBundleURLTypes</key>
	<array>
		<dict>
			<key>CFBundleTypeRole</key>
			<string>Editor</string>
			<key>CFBundleURLSchemes</key>
			<array>
				<string>com.builttoroam.simpletodo</string>
			</array>
		</dict>
	</array>
</dict>
</plist>

We’re now ready to write the code to authenticate the user within the application. Start by adding an imports to bring in flutter_appauth

////  Import for Flutter_AppAuth ////
import 'package:flutter_appauth/flutter_appauth.dart';

Next, add in some constants that are needed for the authentication process to the beginning of the _MyHomePageState class, as well as an instance of the FlutterAppAuth class.

class _MyHomePageState extends State<MyHomePage> {
  ////  Attributes required for authenticating with Azure B2C ////
  final _clientId = '7c57c3a6-bedb-41d6-9dcd-318224013a26';
  final _redirectUrl = 'com.builttoroam.simpletodo://oauthredirect';
  final _discoveryUrl =
      'https://worldsbestflutterapp.b2clogin.com/worldsbestflutterapp.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=B2C_1_signupandin';
  final List<String> _scopes = [
    'openid',
    'offline_access',
  ];

  ////  Instance of FlutterAppAuth ////
  FlutterAppAuth _appAuth = FlutterAppAuth();

At the beginning of the loadData method we created earlier, add a call to the authorizeAndExchangeCode method on the _appAuth instance.

void loadData() async {
////  Authenticate with Azure B2C ////
  var result = await _appAuth.authorizeAndExchangeToken(
      AuthorizationTokenRequest(_clientId, _redirectUrl,
          discoveryUrl: _discoveryUrl, scopes: _scopes));

Now, the only thing left to do is to pass in the token that gets returned from the authentication process into the call to retrieve the tasks. To do this we actually need to make a minor change to the swagger generated code to tell it to use OAuth credentials. Locate the api_client.dart file, which for my project is at /tasks/lib/api_client.dart and change the ApiClient constructor as follows:

ApiClient({this.basePath: "https://localhost"}) {
  // Setup authentications (key: authentication name, value: authentication).
  _authentications['Bearer'] = new OAuth();
}

This sets the ApiClient to use OAuth which means that you can then call the setAccessToken method on the instance of the ApiClient, which should be the code that immediately follows the call to authorizeAndExchangeCode.

var client = ApiClient(basePath: _baseUrl);
client.setAccessToken(result.idToken);

And there you have it, your application should be good to go. When you launch the application, it will redirect to the Azure B2C sign in page. After authenticating it will redirect back to the application and load the task list.

image

Big shout out to the community for rolling so many great plugins for Flutter. The world of cross platform development is progressively becoming easier to make high quality applications through frameworks such as Xamarin.Forms and Flutter.


Contact Built to Roam for more information on building cross-platform applications


Getting Started with Xamarin.Forms and Authenticating with ADAL

Getting Started with Xamarin.Forms and Authenticating with ADAL

Previous posts in this sequence:
Getting Started with Xamarin.Forms and Multi-Targeting in Visual Studio
Getting Started with Xamarin.Forms and SDK Versions
Getting Started with Xamarin.Forms with MvvmCross

Now that we’ve got the basics of an application, we’re going to add some authentication using the Azure Active Directory Authentication Library. We’re going to start with registering an application with Azure Active Directory (AAD) (the docs do cover this here but I figured I’d cover it again anyway). Start by heading over to the Azure portal and selecting Azure Active Directory from the set of tabs on the left.

image

In the list of tabs for the AAD, find the App Registrations tab

image

Click “New application registration” and fill in the details for the new app

image

Note that the Sign-on URL doesn’t have to be a real URL, just one that both the portal and the app know about – we’ll use this later! After you’re done creating the app registration you should be able to retrieve the Application ID. Save this information for later as we’ll need it when we’re authenticating the user within our application.

image

The pieces of information you’ll need in order to use ADAL within your application are:

clientId – This is the Application ID that was displayed after you created the app registration in the Azure portal. This is a GUID

redirectUri – This is the Redirect URI that you specified when creating the app registration. If you didn’t write this down, or you want to double check, or change it, you can do so by clicking the Redirect URIs tab under Settings for the app registration. This is a URL (e.g. https://stratapark)

resourceId – This is the identifier of the resource you want to access. In this case we just want to authenticate the user, so we’re going to use the default resource, which is the AAD directory itself, https://graph.windows.net/. This can be a URL or a GUID depending on the type of resource you’re referencing

tenantId – This is the identifier of the tenant that you’re authenticating against. This can be the URL or GUID of your tenant.

To retrieve the tenantId you need to select the Properties tab of the Azure Active Directory and copy the Directory ID

imagehttps://www.nuget.org/packages/Microsoft.IdentityModel.Clients.ActiveDirectory/

Now that we’ve setup the app registration, we’re good to start writing some code. Firstly, we need to add a reference to the ADAL library from NuGet – search for Microsoft.IdentityModel.Clients.ActiveDirectory

image

Add the ADAL library to all projects.

Let’s start with the UI and add a button to the MainPage.

<Button Text=”Authenticate” Command=”{Binding AuthenticateCommand}” />

And of course we need a command within the MainViewModel. In fact we’ll add the bulk of the authentication code to the MainViewModel too:

private IMvxCommand authenticateCommand;
public IMvxCommand AuthenticateCommand => authenticateCommand ?? (authenticateCommand = new MvxAsyncCommand(Authenticate));


private const string AuthEndpoint = “https://login.microsoftonline.com/{0}/oauth2/token”;


private const string ResourceId= “https://graph.windows.net/”;

private const string TenantId = “[your tenantId]”;
private const string ClientId = “[your clientId]”;
private const string RedirectURI = “[your redirectUri]”;


public async Task Authenticate()
{
     string authority = string.Format(CultureInfo.InvariantCulture, AuthEndpoint, TenantId);
     var authContext = new AuthenticationContext(authority);


    var result = await authContext.AcquireTokenAsync(ResourceId, ClientId, new Uri(RedirectURI), PlatformParameters);
     Debug.WriteLine( result.AccessToken);
}

The only thing missing is the PlatformParameters (bolded in the code above). As the name suggests, these are platform specific parameters required by the ADAL library. For each platform we need to expose a property that returns an IPlatformParameters within the MainViewModel.Platform.cs for each platform.

Android

private IPlatformParameters PlatformParameters => new PlatformParameters(CurrentActivity, true, PromptBehavior.Auto);
public Activity CurrentActivity
{
     get
     {
         var top = Mvx.IoCProvider.Resolve<IMvxAndroidCurrentTopActivity>();
         return top.Activity;
     }
}

iOS

private IPlatformParameters PlatformParameters => new PlatformParameters(GetTopViewController(),true, PromptBehavior.Auto);
public static UIViewController GetTopViewController()
{
     var window = UIApplication.SharedApplication.KeyWindow;
     var vc = window.RootViewController;
     while (vc.PresentedViewController != null)
         vc = vc.PresentedViewController;


    if (vc is UINavigationController navController)
         vc = navController.ViewControllers.Last();


    return vc;
}

UAP

private IPlatformParameters PlatformParameters => new PlatformParameters(PromptBehavior.Always, false);

NetStandard

private IPlatformParameters PlatformParameters => null;

Note: you need to provide the NetStandard implementation otherwise the NetStandard target won’t build.

There is one more thing we need to add. Android requires an additional piece of code within the Activity that hosts the Xamarin.Forms application

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
     base.OnActivityResult(requestCode, resultCode, data);
     AuthenticationAgentContinuationHelper.SetAuthenticationAgentContinuationEventArgs(requestCode, resultCode, data);
}

If your Android application authenticates but doesn’t ever return the access token, chances are that your OnActivityResult override is either missing, or on the wrong Activity – I spent a bit of time trying to work out why iOS and UWP worked but Android would just hang; turns out I was missing this override.

There you have it – you’re good to go with using ADAL to authenticate your users within your Xamarin.Forms application

Good-bye HipChat, and don’t let the door hit you on the way out!

Good-bye HipChat, and don’t let the door hit you on the way out!

It was interesting to see this week that Atlassian doomed the future of HipChat and its successor, Stride, with an aggressive wrap up schedule, with the services set to be discontinued on February 15, 2019. At Built to Roam, as a consulting company, we use a number of messaging tools including Messenger, Skype, Skype for Business / Microsoft Teams, Slack, HipChat and a few others. The upshot is that none of these tools do a great job of even their primary function (i.e. chat conversation between two or more parties), as I’ve posted about previously.

As a couple of posts have indicated, the messaging market has become over populated – for a while it felt like I was installing a new messaging app every second day. When Teams first came to the market, there was a lot of criticism aimed at it because it was a primitive offering in comparison to both Slack and HipChat but it’s rapid growth has started to put pressure on other players in the market. I think a rationalisation of the market was due, and I’m not sorry to see the back of HipChat. As one of the older products in the market, it never quite understood the need for users to belong to multiple organisations and to be able to switch between them.

There are some posts that are talking up the closure of HipChat/Stride as an attempt by Slack and Atlassian to team up in the fight against Microsoft Teams. So the question is, will this make a difference? Will it slow the growth of Microsoft Teams? Will it help Slack win over the corporate space?

Recently, Microsoft Teams announced a free tier, which was one of the things that held a lot of smaller companies and teams from using Microsoft Teams. This move in itself has weakened Slack’s position in the market. However, the true hook for Microsoft Teams and in my opinion the sole reason for its wide adoption (because let’s be honest, it’s far from being a great product!), is that it allows users to sign in using their Office 365 / Microsoft 365 account. In other words, if your company has made, or is moving, to Office 365, you can use your existing credentials to sign into Microsoft Teams. And of course, once you do, you can see and communicate with all the other users in your organisation. Can do you do this with Slack? The short answer is no. The long answer is yes but you need to do a bunch of stuff, including pay a ton of money for stuff that should be out of the box (seriously like what the? https://get.slack.help/hc/en-us/categories/200122103-Workspace-Administration#configure-access-security).

The ridiculous thing is that integration into Azure Active Directory (i.e. use Office 365 and Microsoft 365 credentials) is pretty straight forward. Is there something that Slack can do to get the jump on Microsoft Teams? Yes, provide out of the box support to sign in using either G-Suite or Office 365 credentials. In the future there will be two types of organisation, those that use Office 365, and those that don’t. Most of those in the latter group will probably use some form of G-Suite, so providing out of the box support for G-Suite should be on the radar of any enterprise software.

I know this post has gone on a bit but my last point is that I wish services would stop charging a premium for improving the security of their service. Integration with Azure Active Directory and G-Suite should be include in the cheapest tier of any offering. Why would you compromise the security of your service and the data of your users by not providing this.

Authentication Redirection Loop with Angular Application and Azure Active Directory

Authentication Redirection Loop with Angular Application and Azure Active Directory

Recently we ran in to some difficulty with an Angular application that was being retrofitted into a different environment. During the initial development the Angular application had been pushed to Azure for testing. However, the final resting place for the application was on a on-premises sever. Whilst the switch was relatively painless, with the only major change being to a persistent file storage instead of blob storage, we also had to shift from our development Azure AD tenant (the Angular application, and the associated services, uses Azure AD to authenticate and authorize users), to the client’s Azure AD tenant. This shift required creating two new application registrations within the client’s Azure AD tenant.

Unfortunately after creating the new registrations, and updating the Angular application (and the corresponding services), any attempt to log in with valid credentials resulted in a continual loop between the Angular application and the Azure AD login prompt. In this case we were only using Azure AD to authenticate users and other than controlling access to the application services there weren’t any other permissions that users would have to agree to.

In the past I’ve posted about how administrators have to grant permission to users within their tenant to access an application (see https://nicksnettravels.builttoroam.com/post/2017/01/24/Admin-Consent-for-Permissions-in-Azure-Active-Directory.aspx). Usually there is an Azure AD login error when users attempt to sign in. In this case, for some reason we either missed the error message or it was being obscured by the automatic redirection between the Angular application and the Azure AD login prompt.

We did end up finding the solution, thanks to the Azure AD team at Microsoft, who quickly identified the error in our Fiddler trace. The critical request/response was:

Request

GET https://login.microsoftonline.com/<tenantid>/oauth2/authorize?response_type=token&client_id=<clientid>&resource=<resourceid>&redirect_uri=<uri>&prompt=none&login_hint=admin


Response

HTTP/1.1 302 Found
Location: <uri>
<html><head><title>Object moved</title></head><body>
<h2>Object moved to <a href=”<uri>/#error=interaction_required&amp;error_description=AADSTS65001%3a+The+user+or+administrator+has+not+consented+to+use+the+application+with+ID+%27.+Send+an+interactive+authorization+request+for+this+user+and+resource

The important part is that the error indicates that either the user or administrator has not consented to use of the application, and that there should be an interactive authorization request. This is a little cryptic but going back to my previous post we can simply add “prompt=admin_consent” to the login request – assuming an administrator logs in, they can then grant access to the application to all users in the tenant.

There is actually a much easier way for single tenant applications, which this is. Instead of waiting for an administrator to log in, permission can be granted via the Azure portal:

– Select the Directory where the application is registered (drop down in top right cornert of the Azure portal where the signed in user is listed)

– Select Azure Active Directory from the sidebar menu

– Select App Registrations

– Select the application registration you want to grant access to

– From All settings, click on the Required Permissions link

– Click “Grant Permissions”

image

This will give all users access to the application. If you have multiple registrations (eg one for the web site and one for the corresponding services), don’t forget to grant permission to both registrations.

Again, big thanks to the team at Microsoft for pointing us to the solution

Call out to the ADAL team! – Authenticate Using External Browser

Call out to the ADAL team! – Authenticate Using External Browser

In my post, Authorizing Access to Resources using Azure Active Directory, I talk about authenticating using the built in browser on the device, rather than authenticating via a webview, which is all too common. Unfortunately despite being fully supported by Azure Active Directory, the team responsible for ADAL haven’t, as far as I can tell, provided support for using an external browser to authenticate.

I was super impressed when I just downloaded the Facebook app on Windows, that it supports “Log in with Browser”.

image

In my opinion, this not only represents a more secure form of authentication (since I can validate the website I’m signing into), it is also a better experience, since I’m already logged into Facebook in the browser anyhow.

I definitely encourage developers to consider using the external browser, rather than supporting SDKs and libraries that us the in-app browser.

UseWindowsAzureActiveDirectoryBearerAuthentication v’s UseJwtBearerAuthentication for Authorization with Azure Active Directory for an ASP.NET Web API

UseWindowsAzureActiveDirectoryBearerAuthentication v’s UseJwtBearerAuthentication for Authorization with Azure Active Directory for an ASP.NET Web API

In my previous post, Securing a Web API using Azure Active Directory and OWIN, I covered how to authorize requests against Azure Active Directory using the UseWindowsAzureActiveDirectoryBearerAuthentication extension method in the OWN startup class. This extension method has been designed specifically for Azure Active Directory but if you think about it, the Authorization token is just a JWT token, so in theory you could take a much more generic approach to authorizing access by validating the JWT. This can be done using the UseJwtBearerAuthentication extension method.

There are a couple of steps to using the UseJwtBearerAuthentication extension method. Firstly, in order to validate the signature of the JWT, we’re going to need the public certificate that matches the key identifier contained in the JWT. In my post on Verifying Azure Active Directory JWT Tokens I cover how to examine the JWT using https://jwt.io in order to retrieve the kid, retrieve the openid configuration, locate the jwks uri, retrieve the keys and save out the key as a certificate. In the post I used the certificate (ie wrapping the raw key in —BEGIN—, —END— markers) to validate the JWT; in this case I’ve copied the contents into a text file which I’ve named azure.cer and added it to the root of my web project (making sure the build action is set to Content so it is deployed with the website).

The next thing to do is to remove the UseWindowsAzureActiveDirectoryBearerAuthentication extension method, replacing it with the following code.

var fileName = HostingEnvironment.MapPath(“~/”) + “azure.cer”;
var cert = new X509Certificate2(fileName);
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
    AllowedAudiences = new[] {ConfigurationManager.AppSettings[“ida:Audience”]},
    IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
    {
        new X509CertificateSecurityTokenProvider(ConfigurationManager.AppSettings[“ida:IssuerName”], cert)
    }
});

This code uses the azure.cer certificate file combined with the Audience and IssuerName which I’ve added to the web.config.

<add key=”ida:Audience” value=”a07aa09e-21b9-4e86-b269-a18903b5fe54″ />
<add key=”ida:IssuerName” value=”https://sts.windows.net/55cc17b5-7d2a-418e-86a6-277c54462485/” />

The Audience is the application id (aka client id) of the Azure application registration. The IssuerName needs to match to what appears in the JWT. Opening one of the tokens in https://jwt.io it’s the ISS value that you want to use as the IssuerName.
image

Now you can run the project and see that again the requests are validated to ensure they’re correctly signed.

Securing a Web API using Azure Active Directory and OWIN

Securing a Web API using Azure Active Directory and OWIN

In this post we’re going to look at how to use Azure Active Directory to secure a web api built using ASP.NET (full framework – we’ll come back to .NET Core in a future post). To get started I’m going to create a very vanilla web project using Visual Studio 2017. At this point VS2017 is still in RC and so you’ll get slightly different behaviour than what you’ll get using the Visual Studio 2015 templates. In actual fact the VS2015 templates seem to provide more in the way of out of the box support for OWIN. I ran into issues recently when I hadn’t realised what VS2015 was adding for me behind the scenes, so in this post I’ll endeavour not to assume anything or skip any steps along the way.

image

After creating the project, the first thing I always to is to run it and make sure the project has been correctly created from the template. In the case of a web application, I also take note of the startup url, in this case http://localhost:39063/. However, at this point I also realised that I should do the rest of this post following some semblance of best practice and do everything over SSL. Luckily, recent enhancements to IIS Express makes it simple to configure and support SSL with minimal fuss. In fact, all you need to do is select the web project node and press F4 (note, going to Properties in the shortcut menu brings up the main project properties pane, which is not what you’re after) to bring up the Properties window. At the bottom of the list of properties is the SSL Enabled and SSL URL, which is https://localhost:44331/. Take note of this url as we’ll need it in a minute.

image

To setup the Web API in order to authorize requests, I’m going to create a new application registration in Azure Active Directory. This time I need to select Web app / API from the Application Type dropdown. I’ll give it a Name (that will be shown in the Azure portal and when signing into use this resource) and I’ll enter the SSL address as the Sign-on URL. This URL will also be listed as one of the redirect URIs used during the sign in process. During debugging you can opt to do this over HTTP but I would discourage this as it’s no longer required.

image

After creating the application, take note of the Application Id of the newly created application. This is often referred to as the client id and will be used when authenticating a user for access to the web api.

Application Id (aka Client Id): a07aa09e-21b9-4e86-b269-a18903b5fe54

We’re done for the moment with Azure Active Directory, let’s turn to the web application we recently created. The authorization process for in-bound requests involves extracting the Authorization header and processing the bearer token to determine if the calling party should have access to the services. In order to do this for tokens issues by Azure AD I’ll add references to both the Microsoft.Own.Security.ActiveDirectory and Microsoft.Own.Host.SystemWeb packages.

image

Note: Adding these references takes a while! Make sure they’re completely finished before attempting to continue.

Depending on the project template, you may, or may not, already have a Startup.cs file in your project. If you don’t, add a new item based on the OWIN Startup class template

image

The code for this class should be kept relatively simple:

[assembly: OwinStartup(typeof(SampleWebApp.Startup))]
namespace SampleWebApp
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);
        }
    }
}

Additionally, you’ll want to add another partial class file Startup.Auth.cs in the App_Start folder.

namespace SampleWebApp
{
    public partial class Startup
    {
        public void ConfigureAuth(IAppBuilder app)
        {
        }
    }
}

And now we get to adding the middleware that will be used to process the authorization header

public void ConfigureAuth(IAppBuilder app)
{
    app.UseWindowsAzureActiveDirectoryBearerAuthentication(
        new WindowsAzureActiveDirectoryBearerAuthenticationOptions
        {
             Tenant = ConfigurationManager.AppSettings[“ida:Tenant”],
             TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
             {
                 ValidAudience = ConfigurationManager.AppSettings[“ida:Audience”]
             }
        });
}

This uses the configuration manager to extract the Tenant and Audience settings from the web.config (and subsequently the Azure portal settings when you publish to the cloud):

<add key=”ida:Audience” value=”a07aa09e-21b9-4e86-b269-a18903b5fe54″ />
<add key=”ida:Tenant” value=”nicksdemodir.onmicrosoft.com” />

The tenant is the Id, or in this case, the domain of the tenant where the application is registered. The Audience is the application Id of the application registered in Azure AD.

Warning: If you run the application now and get an error relating to a missing type, you may have to revert the Microsoft.Owin.Security.ActiveDirectory to the most recent v4 package. At the time of writing this post there seems to be an incompatibility between v5 and Owin.

Reference to type ‘TokenValidationParameters’ claims it is defined in ‘System.IdentityModel.Tokens.Jwt’, but it could not be found

Ok, we’re ready to try making requests. I’m going to use Fiddler but you can use any other tool that’s able to generate and send HTTP requests. The first attempt will be a GET request to https://localhost:44331/api/values which is one of the default controllers that was created from the project template. Depending on what your project template included, the valuescontroller may, or may not, have the Authorize attribute applied to it. If, like me, you didn’t have the Authorize attribute applied to the valuecontroller, you should get a valid response back to your HTTP request. In this case, you’re going to want to add security to the valuecontroller by adding the Authorize attributes:

[Authorize]
public class ValuesController : ApiController
{

Now, try making the request again – you should now get a 401 Unauthorized error. The body of the response should say:

{“Message”:”Authorization has been denied for this request.”}

Clearly this is the case since we didn’t send the Authorization header. This time, let’s add an Authorization header, with the word “Bearer” and a token consisting of random text:

Authorization: Bearer abcdefg

This should generate the same response. However, let’s start to look into this further. To get more diagnostic information, add the following to the web.config file for the project

<system.diagnostics>
  <switches>
    <add name=”Microsoft.Owin” value=”Verbose” />
  </switches>
</system.diagnostics>

Now when you make the request you should see more diagnostic information in the Output window in Visual Studio:

Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationMiddleware Error: 0 : Authentication failed
System.ArgumentException: IDX10708: ‘System.IdentityModel.Tokens.JwtSecurityTokenHandler’ cannot read this string: ‘abcdefg’.
The string needs to be in compact JSON format, which is of the form: ‘<Base64UrlEncodedHeader>.<Base64UrlEncodedPayload>.<OPTIONAL, Base64UrlEncodedSignature>’.

As we should have predicted, the token we passed in isn’t a value Jwt – it’s not even valid JSON. Let’s fix this by generating an actual access token for this Web API. In a previous post I walked through manually the process of authenticating, retrieving an authorization code and then exchanging it for an access token. I’ll do the same here.

First I’m going to launch an authorization url in the browser and sign in using credentials from the nicksdemodir.onmicrosoft.com tenant:

https://login.microsoftonline.com/nicksdemodir.onmicrosoft.com/oauth2/authorize?client_id=a07aa09e-21b9-4e86-b269-a18903b5fe54&response_type=code&redirect_uri=https://localhost:44331/

The authorization url is made up of various components:

nicksdemodir.onmicrosoft.com – This is the domain name of the tenant where the web application is registered with Azure AD. You can also use the tenant Id (guid format)

a07aa09e-21b9-4e86-b269-a18903b5fe54 – This is the application id of the application registration in Azure AD

code – This indicates that the response should be an authorization code

https://localhost:44331/  – This is the uri that the browser will be redirected back to, passing with it the code in the query string.

Make sure you have the web application running, otherwise the redirect uri won’t resolve at it may be hard to extract the code from the query string (depending on the browser). After signing in, you’ll be redirected back to your web application with a URL similar to (the code has been shortened for brevity):

https://localhost:44331/?code=zvrs_zz0…….05B_ggAA&session_state=ef2986b8-75bd-484a-b9b9-68f0e46ab569

The next thing to do is to prepare a POST request in your http tool of choice with the following:

URL: https://login.microsoftonline.com/nicksdemodir.onmicrosoft.com/oauth2/token

Body: grant_type=authorization_code&client_id=a07aa09e-21b9-4e86-b269-a18903b5fe54&client_secret=c06kP0Q9ENGpZGbiZTqB1QQaZUWNe190mCittRMr&redirect_uri=https://localhost:44331/&code=zvrs_zz0…….05B_ggAA&resource=a07aa09e-21b9-4e86-b269-a18903b5fe54

The Body parameters are broken down as:

a07aa09e-21b9-4e86-b269-a18903b5fe54 – This is the application id of the application registration in Azure AD. It’s required as both the client_id and the resource, since we’re using the access token to access the web application itself.

c06kP0Q9ENGpZGbiZTqB1QQaZUWNe190mCittRMr – This is a private key (aka client secret) issued by the Azure AD application to ensure the security of token requests. I’ll come back to this in a second and show how to create one for your application.

https://localhost:44331/ – The redirect uri for the application – required here to verify the calling party as it has to align with what’s in Azure AD

zvrs_zz0…….05B_ggAA – This is the authorization code returned in the previous step

To generate the client secret in Azure AD simply click on the Keys tab within the details of the application registration. You can then create a new key by entering a description. The description is only seen by you, so give it a name that’s meaningful to you. Note that once you save the new key, you will only be shown the value of the key once. Once you leave the page, the value of the key will never been shown again.

image

The key created in the Azure AD should be used as the client secret when doing the authorization code to access token exchange.

The response to this POST should return JSON which includes and access token value. Add the access token to the authorization header:

Authorization: Bearer G1ZsPGjPF6qJO8Sd5HctnKqNk_8KDc-………Lpy9P8sDWdECziihaPWyseug9hgD119keoZuh4B

This should give you a 200 response with data. And there you have it – you’ve successfully secured your web api so that it requires the user to be authenticated using Azure Active Directory.

Improving the Azure Active Directory Sign-on Experience

Improving the Azure Active Directory Sign-on Experience

I was talking to a customer the other day and had to log into the Azure portal. Normally when I launch the portal I’m already signed in and I’m not prompted but for whatever reason this time I was prompted to authenticate. Doing this in front of the customer lead to three interesting discussions:

– Use of two factor authentication to secure sign in
– Separate global administrator account for primary organisation tenant
– Company branding for Azure AD sign in

Firstly, the use of two factor authentication (TFA) is a must requirement for anyone who is using the Azure portal – if you are an administrator of your organisation, please make sure you enforce this requirement for anyone accessing your tenant/directory/subscription. This applies to staff, contractors, guests etc who might be using your Azure portal or the Office 365 portal. In fact, in this day in age, I would be enforcing two factor authentication for all employees – note that Outlook and Skype for Business are still stuck in the dark-ages and don’t access TFA sign in. For these you’ll need to generate an application password (go to https://myapps.microsoft.com, click on your profile image in top right corner and select “Profile”, click through to “Additional security verification,” click on the “app passwords” tab and then click “Create” to generate an app password.

Ok, next is the use of a separate global administrator account – this is in part tied to the previous point about using TFA. If you’re a global administrator of your tenant and you enable TFA, you won’t be able to generate app passwords. This is essentially forcing you down the path of best practice, which is to have a separate account which is the global administrator for your tenant. If other people in your organisation need administrative permissions, you can do this on a user or role basis within the Azure portal – our preference is to assign permissions to a resource group but there is enough fidelity within the portal to control access at the level you desire.

The other thing we’ve also enforced is that we do not host any Azure resources in our primary tenant (ie in our case builttoroam.com). Given the importance of Office365 based services we felt it important that we isolate off any resources we create in Azure to make sure they’re completely independent of our primary tenant. The only exception to this is if we are building internal LOB applications (ie only apps for Built to Roam use) – for these we include the app registrations within the builttoroam.com tenant so that we can restrict sign in and at the same time deliver a great sign in experience for our employees. For example we’re using Facebook Workplace (https://workplace.fb.com/) – we configured this within the builttoroam.com tenant in Azure AD to allow for a SSO experience.

Now, onto the point of this post – the last thing that came out of signing into the portal in front of the customer was that they were startled when we went to sign into the portal and our company branding appeared. To illustrate, when you first land on the portal sign in page you see:

image

After entering my email address, the sign in page changes to incorporate the Built to Roam branding

image

This not only improves the perception (for internal and external users), it also gives everyone a sense of confidence that they’re signing into a legitimate Built to Roam service.

In order to set this up, you need to navigate to the Active Directory node in the Azure portal and click on the Company branding. If you’re using Office 365 you should already have access to this tab. However, if you’re not, you may need to sign up for Active Directory Premium – you can get started using the Premium trial:

image

Once you’ve opened the Company branding tab (if you have just activated the trial, you may need to wait a few minutes and/or sign out and back in again in order for the Company branding tab to open) you can click on the link to “Configure company branding now”

image

There are a number of options and images that you can configure:

image

After saving the changes, if you attempt to sign in, you’ll notice the new images/colours etc appear. In this case, you can see that the welcome text at the bottom of the sign in page has been changed to what I entered in the company branding tab. Unfortunately because I didn’t set the sign in page image, the default is used, so you can’t see the red (#FF0000) background I set – you can see glimpses of it if you resize the page. This can be fixed by simply uploading a transparent image.

image

The ability to customise the sign in experience is just one way to improve the experience for you staff and customers.

Useful OAuth, OpenID Connect, Azure Active Directory and Google Authentication Links

Useful OAuth, OpenID Connect, Azure Active Directory and Google Authentication Links

Over the past couple of weeks I’ve been assisting with the development work of an enterprise system that uses both Azure Active Directory (Azure AD) and Google to authenticate users. It’s a cross platform solution which means we need code that works across both authentication platforms, and the three mobile platforms. Unfortunately this is easier said than done – The Azure AD team have done a reasonable job with the ADAL library but it’s not like we can repurpose that library for authenticating against Google. This is a tad annoying since both Azure AD and Google both use OAuth and OpenID Connect, so you’d expect there to be a good library that would work across both.

In trying to find a workable solution I can across a number of links that I want to bookmark here for future reference:

OAuth 2

Home – https://oauth.net/2/

The OAuth home page is a good starting point if you want to get more links and information about OAuth (1 and 2) but I actually found it’s main use for me was to point at the OAuth 2.0 Framework RFC

OAuth 2.0 Framework RFC – https://tools.ietf.org/html/rfc6749

You can think of the OAuth 2.0 Framework RFC as being the specification for OAuth 2.0. There are some extensions and other standards that relate to OAuth 2.0 but this is a must read if you want to understand what OAuth 2.0 is all about. You may need to refer back to this when reading other blogs/tutorials as it can help clarify what each of the roles and responsibilities are in the process.

Simple overview of OAuth 2 – https://aaronparecki.com/2012/07/29/2/oauth2-simplified

This overview provides a quick summary of the various flows for OAuth 2.0. However, I disagree with the use of the implicit workflow for mobile applications. Whilst mobile applications are not “trusted,” which would normally imply the use of the implicit workflow, the reality is that the implicit workflow can’t issue refresh tokens. This means that unless you want your users to have to log in each time they use your mobile application, you need to use the Authorization Code workflow (the client secret shouldn’t be required when requesting access tokens for mobile apps – this depends on which authentication provider you’re using).

 

OpenID Connect

Home – http://openid.net/connect/

The OpenID Connect home page is again a good starting point as it links to the many different parts of the OpenID Connect standard. OpenID Connect builds on top of OAuth 2.0 in order to provide a mechanism for users to be authenticated as well as authorized for resource access. In addition to the creation of access tokens, OpenID Connect defines an id_token which can be issued in absence of any resource that is just used to identify the user that has authenticated.

OpenID Connect Core 1.0 – http://openid.net/specs/openid-connect-core-1_0.html

This is the core specification of OpenID Connect. Similar to the specification for OAuth, this is worth both a read and to be used as a reference when working with OpenID Connect implementations.

OpenID Connect Session Management 1.0 – http://openid.net/specs/openid-connect-session-1_0.html

Whilst still in draft this standard covers how implementers are supposed to handle log out scenarios, which is useful as your application can’t simply delete it’s access tokens when a user opts to log out. Ideally when a user logs out, you’d want to make sure both cached tokens are cleared, along with invalidating any access or refresh tokens.

 

Google

OAuth 2.0 Overview – https://developers.google.com/identity/protocols/OAuth2

OpenID Connect – https://developers.google.com/identity/protocols/OpenIDConnect

Google’s documentation isn’t too bad but does require you to read all of the pages as the OAuth and OpenID Connect implementation details seem to be scattered across the pages. The assumption is that for any given type of application you can simply read the one page – unfortunately, if you want to get an understanding of the Google implementation, you really need to read everything. Authenticating/authorizing with Google is significantly simpler than with Azure AD as there is no notion of linking your application registration with specific permissions to other applications registered with Azure AD. This is a significant limitation of using Google sign in, as you can really only use it to authenticate and then use the token to access various Google APIs.

 

Azure Active Directory

Azure AD Developer’s Guide – https://docs.microsoft.com/en-au/azure/active-directory/develop/active-directory-developers-guide

Authentication Scenarios for Azure AD – https://docs.microsoft.com/en-au/azure/active-directory/develop/active-directory-authentication-scenarios

Azure AD is a much longer read, and it’s very easy to get lost in the world of application configuration and settings. My recommendation is to start with something simple, and then grow from that. For examples, start by authenticating a use to sign into your mobile app, then extend it so that you can use the access token to connect to a Web API, and then on to retrieve information from other Microsoft services within the Web API, and then perhaps make it all multi-tenanted (that’s one for another post!).

Microsoft Partner, Office 365 and Visual Studio Online

Microsoft Partner, Office 365 and Visual Studio Online

This is a somewhat off-topic post which only applies to Microsoft Partners who happen to use Office 365 and Visual Studio Online. As a Microsoft Silver Partner we have a number of licenses which we’re able to use internally. This includes a number of MSDN subscriptions which can be assigned to staff and Office 365 seats.

Over the last couple of weeks we have migrated across to Office 365 (this was actually done over a 24 hour period as it was relatively simple to move from one hosted exchange account to Office 365). One of the awesome things about Office 365 is that users belong to the Azure AD tenant (ie we have builttoroam.com set up as a tenant and all Office 365 users with an email address of ***@builttoroam.com belong to that tenant).

We’ve been using Azure for development for a long time but as Azure AD is still in its infancy we were originally just adding staff in based on their Microsoft Account. We also did the same for Visual Studio Online. All in all this was quite messy and felt very disconnected. Well today we took the plunge and connected Visual Studio Online to our Azure AD account. To make sure the transition went smoothly we have temporarily added the Microsoft Account for each staff member to our Azure AD tenant – this will mean that in the short term they can continue to access VSO using their Microsoft Account. Going forward we would expect that everyone will start to use their workplace account (ie their ***@builttoroam.com Azure AD account) to sign into both the Azure portal and Visual Studio Online.

Here’s where the issue is. Currently in Visual Studio 2013 you can online sign in using a Microsoft Account (this is fixed in Visual Studio 2015 where you can both sign in with a workplace account, and you can have multiple accounts signed in). The upshot is that the staff will have to sign into VS2013 with their Microsoft Account, and then connect to VSO using their workplace account – this seems simple enough, right! wrong! well partially right. Firstly, we still need to assign the MSDN subscriptions to the staff. After being assigned a license, the staff simply go to MSDN and activate the subscription. This gives them a license to use Visual Studio 2013 which is automatically picked up when they sign in using their Microsoft Account.

The issue is that if they then go to Visual Studio 2015 and sign in with their workplace account, they won’t have access to the MSDN subscription (since it’s associated with their workplace account). The solution is to go to their MSDN subscription details (signing into msdn.microsoft.com with their Microsoft Account) and under the Visual Studio Online section, click the Link workplace account option and enter their workplace email address. After doing this, Visual Studio 2015 will pick up the linked MSDN subscription and license, as well as picking up the Visual Studio Online projects in the Team Explorer window.

The upshot is that after doing all this, staff should be able to sign into Visual Studio Online, Office 365, Azure Portal and Visual Studio 2015 using their workplace account. It’s only Visual Studio 2013 where they will have to sign in with their Microsoft Account, and then connect to VSO using their workplace account.

Fix Login Failures to Azure Mobile Services with Enhanced Users Features for Javascript Backends

Fix Login Failures to Azure Mobile Services with Enhanced Users Features for Javascript Backends

One of the applications that we’ve been working on that leverages the older javascript backend version of Azure Mobile services was seeing some cases where users couldn’t login. For a while we put it down to incidental issues with our application but we then detected a pattern where it was related to Microsoft Accounts that belonged to one of the domains associated with outlook.com (eg live.com, outlook.com, outlook.com.au, hotmail.com). I don’t know exactly which domains it does affect, nor whether it was all email addresses on those domains. However, what I do know is that in order to fix the issue we had to follow the instructions that Carlos had posted a while ago on the Enhanced Users Feature. We hadn’t done this previously as I wasn’t confident that it wouldn’t break our production application but it turns out the only change we needed to do, as per his instructions, was change to use the asynchronous getIdentities method (which is also an update we were supposed to do a while ago!).

Source Code for Real Estate Inspector Sample on GitHub

Source Code for Real Estate Inspector Sample on GitHub

I’ve got around to publishing the current source code pieces to GitHub. It’s currently very hotch-potch as I’ve been focussing on demonstrating/fleshing out a lot of the concepts for my blog posts. Over the coming weeks I’ll be extending out the actual functionality and will periodically update the code on GitHub. For now, it’s a good place to pick through the various code I’ve been talking about over the last couple of months

Using a Refresh Token to Renew an Expired Access Token for Azure Active Directory

Using a Refresh Token to Renew an Expired Access Token for Azure Active Directory

Currently my application attempts to acquire the access token silently which equates to looking to see if there is a current (ie not expired) token in the token cache. However, tokens don’t live for very long, so it’s quite likely that a token won’t be found. This unfortunately leads to a poor user experience as the user will quite often be prompted to sign in. There is an alternative, which is to use the refresh token, returned as part of initially acquiring the access token, to silently request a new access token. This of course is on the assumption that the refresh token hasn’t expired.

Here is a quick summary, as at the time of writing, of the different tokens and their expiry rules (a good explanation here):

  • Azure AD access tokens expire in 1 hour (see the expires_on attribute that is returned when acquiring an access token).
  • Refresh tokens expires in 14 days (see the refresh_token_expires_in attribute that is returned when acquiring an access token).
  • Access tokens can be refreshed using the refresh-token for a maximum period of time of 90 days, from the date that the access token was acquired by prompting the user.

The authentication logic can be amended to retrieve the list of refresh tokens, attempt to acquire token silently, followed by an attempt to acquire token via the refresh token. Failing that the user would be prompted to sign in.

var authContext = new AuthenticationContext(Configuration.Current.ADAuthority);

var tokens = authContext.Tokens();
var existing = (from t in tokens
                where t.ClientId == Configuration.Current.ADNativeClientApplicationClientId &&
                        t.Resource == Configuration.Current.MobileServiceAppIdUri
                select t).FirstOrDefault();
if (existing != null)
{
    try
    {
        var res = await authContext.AcquireTokenSilentAsync(
            Configuration.Current.MobileServiceAppIdUri,
            Configuration.Current.ADNativeClientApplicationClientId);
        if (res != null && !string.IsNullOrWhiteSpace(res.AccessToken))
        {
            return res.AccessToken;
        }
    }
    catch (Exception saex)
    {
        Debug.WriteLine(saex);
    }

    try
    {
        var res = await
            authContext.AcquireTokenByRefreshTokenAsync(existing.RefreshToken,
                Configuration.Current.ADNativeClientApplicationClientId);
        if (res != null && !string.IsNullOrWhiteSpace(res.AccessToken))
        {
            return res.AccessToken;
        }
    }
    catch (Exception saex)
    {
        Debug.WriteLine(saex);
    }

}

Azure Active Directory with Mobile Services without Prompting Every Time the Application Starts

Azure Active Directory with Mobile Services without Prompting Every Time the Application Starts

Currently, every time the application is run the user is prompted to sign into Azure Active Directory, and then the AD issued token is then used to login to Azure Mobile Service. Not only is this a pain for the user (for example if they’ve only just been in the application, to have to sign in again feels somewhat unnecessary), it also adds latency on startup as well as preventing the application from running when offline. In the next couple of posts I’ll look at a couple of techniques to consider in order to improve this sign on experience.

Firstly, it’s worth noting that there was an update posted for the Azure Active Directory Authentication library (ADAL) on NuGet – it’s still prerelease but worth updating to if you’re using v3 of the library. More info on NuGet, here.

One of the nice things about ADAL is that it provides a cache for tokens. In addition to being able to query what tokens are in the cache (for example in order to then login to the Mobile Service) it also wraps the check to determine if a token is still valid. To do this, I can call AcquireTokenSilentAsync to authenticate silently ie without prompting the user. If a valid access token is found in the token cache it will be returned. In the case that no valid token is found and exception is raised and I then need to invoke AcquireTokenAsync as I did previously.

var authContext = new AuthenticationContext(Configuration.Current.ADAuthority);
try
{
    var res = await authContext.AcquireTokenSilentAsync(
        Configuration.Current.MobileServiceAppIdUri,
        Configuration.Current.ADNativeClientApplicationClientId);
    if (res != null && !string.IsNullOrWhiteSpace(res.AccessToken))
    {
        return res.AccessToken;
    }
}
catch (Exception saex)
{
    Debug.WriteLine(saex);
}

As Windows Phone 8.0 isn’t supportedyet by v3 of ADAL, I also need to update my custom implementation of the AuthenticationContext. Firstly, to add a static list of previously acquired tokens:

private static readonly List<AuthenticationResult> Tokens = new List<AuthenticationResult>();  

Next, I need to update my AuthenticationResult option to decode more than just the access and refresh tokens:

public class AuthenticationResult
{
    private static DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime();

    public string ClientId { get; set; }

    [JsonProperty(“access_token”)]
    public string AccessToken { get; set; }

    [JsonProperty(“refresh_token”)]
    public string RefreshToken { get; set; }

    [JsonProperty(“resource”)]
    public string Resource { get; set; }

        [JsonProperty(“expires_on”)]
    public long ExpiresOnSeconds { get; set; }

    public DateTime ExpiresOn
    {
        get { return epoch.AddSeconds(ExpiresOnSeconds); }
    }

    private long refreshTokenExpiresInSeconds;
    [JsonProperty(“refresh_token_expires_in”)]
    public long RefreshTokenExpiresInSeconds
    {
        get { return refreshTokenExpiresInSeconds; }
        set
        {
            refreshTokenExpiresInSeconds = value;
            RefreshTokensExpiresOn = DateTime.Now.AddSeconds(refreshTokenExpiresInSeconds);
        }
    }

    public DateTime RefreshTokensExpiresOn { get;private set; }

}

At the end of the AcquireTokenAsync method I need to set the ClientId property on the AuthenticationResult (so I know which AAD client id it was returned for as this isn’t returned in the response) and add the result to the Tokens list:

var result = JsonConvert.DeserializeObject<AuthenticationResult>(await data.Content.ReadAsStringAsync());
result.ClientId = ClientId;
Tokens.Add(result);
return result;

Finally I need to implement the AcquireTokenSilentAsync method – although it doesn’t require async/Task I’ve kept the method consistent with ADAL to avoid conditional code when calling the method

public async Task<AuthenticationResult> AcquireTokenSilentAsync(
    string resource,
    string clientId)
{
   

    var result = (from t in Tokens
                        where t.ClientId == clientId &&
                                   t.Resource == resource &&
                                   t.ExpiresOn > DateTime.Now
                        select t).FirstOrDefault();

    return result;
}

Note that this implementation doesn’t persist the access token beyond the current session. However, it will avoid the need to reauthenticate if the user does happen to do something that would otherwise require authentication.

Custom Domains for Azure Mobile Services

Custom Domains for Azure Mobile Services

As packaging a cloud based solution one of the tasks is to change the configuration of the services so that they have a application specific domain. In the case of Azure websites this feature has been available for quite a while in the form of custom domains. However, it was only recently that this capability was added to Azure Mobile Services. This enables me to change the Mobile Service url from https://realestateinspector.azure-mobile.net to https://realestate.builttoroam.com. This capability is only available to Mobile Services running in Standard mode, which can be quite a costly commitment if custom domains are the only reason to upgrade.

Here’s a quick run through of setting up a custom domain. Note that this doesn’t include setting up SSL for your custom domain, which is highly recommended. There is more information here that includes using wildcard SSL certificates, which might be useful if you are packaging multiple services (eg Mobile Service and a Website) off the same base domain.

The first thing to do is to setup a CName record (alternatively you can setup an A record using these instructions) – this needs to be done with the name service that hosts the DNS records for your domain.

image

If you simply try to browse to the new URL you’ll see quite a useful 404 message. The first option is exactly the scenario I now face – I have to configure the Mobile Service to know about the custom domain.

image

Currently there is no UI in the Azure portal for managing custom domains for Mobile Services, unlike for Azure Websites where it can all be configured in the portal. Instead, I need to use the Azure CLI. Before doing this, make sure you are using v0.8.15 or higher (v0.8.15 is current at time of writing). Note that I ran into some issues upgrading the Azure CLI – docs online suggest using npm (eg npm update azure-cli, or npm update azure-cli –g depending on whether you installed the azure-cli globally or not). However, I found that this wasn’t working – the output suggested it had updated to 0.8.15 but when I queried azure –v I saw an earlier version. Turns out that I’d installed the azure-cli via the Web Platform Installer – in this case you either need to uninstall the azure-cli via the platform installer, or simply install the new version via the platform installer (which is what I did).
Adding a custom domain is then relatively straight forward: azure mobile domain add <mobileservicename> <customdomain> eg

image

Now when you browse to the new url you see the typical Mobile Service status homepage.

image

When I run my client applications I need to update the Mobile Service Client URL to point to the new url. I can then see in Fiddler that the traffic is indeed going to the new custom domain.

image

Database Migrations with Package Manager Console and Azure Mobile Services

Database Migrations with Package Manager Console and Azure Mobile Services

I was caught out recently after I published an incorrect database migration into my cloud base Azure Mobile Service (I created a second controller based on the RealEstateProperty entity instead of the PropertyType entity). The upshot is that I only noticed this when all the properties of the entities I was synchronizing down from the cloud came back with null for most of their properties. Initially I thought my issue was with the migration I had performed on the database, so I thought I’d roll back to a previous version. My most recent migration was “201502260615263_Added proeprty type entity” and I wanted to roll it back to the previous migration, “201501061158375_AddedInspections”. To do this you can simply call the update-database method in the Package Manager Console:

update-database –TargetMigration “201501061158375_AddedInspections”

However, I wanted to invoke this only the database for the Mobile Service running in the cloud. To do this I need to add the –ConnectionString and –ConnectionProviderName attributes. The latter is easy as it needs to be the static value “System.Data.SqlClient” but the former requires two steps:

– In the Azure Management Portal go to the SQL Databases tab and then select the database that correlates to the Mobile Service. With the database selected, click “Manage” from the toolbar – this will prompt to add a firewall rule allowing access from your computer (this only happens the first time or again if your ip address changes). You need to add this firewall rule as Visual Studio will be attaching directly to the database to run the code-first migration on the database.

image

– From the Dashboard pane of the SQL Server database, select Connection Strings from the right link menu, and copy the contents of the ADO.NET connection string.

image

Now I can add the connection string to the update-database method:

update-database –TargetMigration “201501061158375_AddedInspections” –ConnectionString “Server=tcp:p7zzqmjcmf.database.windows.net,1433;Database=realestateinspector;User ID={my username};Password={your_password_here};Trusted_Connection=False;Encrypt=True;Connection Timeout=30;” –ConnectionProviderName “System.Data.SqlClient”

I checked that this had removed the PropertyType table (which was part of the migration I just reversed) and then removed the old migration file, “201502260615263_Added proeprty type entity.cs”, and then regenerated the new migration by calling add-migration again:

add-migration ‘Added proeprty type entity’

Given that the Mobile Service itself hadn’t changed at that point I figured that I’d simply call update-database without the TargetMigration parameter but with the ConnectionString that points to my actual Mobile Service. This seemed to go ok but then when I ran my Mobile Service and attempted to synchronize my PropertyType entities – this caused an exception because I’d discovered the root of my issue, which was I had two controllers both referencing the RealEstateProperty entity. I fixed that and republished my Mobile Service. Now synchronization worked, but mainly because there were no entities in the PropertyType table in the database, so I then attempted to add a PropertyType using the direct access (rather than synchronizing entities) in the MobileServiceClient (using GetTable instead of GetSyncTable) – this caused some weird exception as it seemed to require that the CreatedAt property be set. I’ve never had to do this on previous inserts, so I sensed something was wrong. Using the Visual Studio 2015 CTP I connected directly to the SQL Server database and sure enough on my PropertyType table there were no triggers for insert/update. Usually this is where the CreatedAt column is updated.

So, feeling a little puzzled I decided to undo my migration on my Mobile Service database once more. But this time, instead of attempting to change any of the migration scripts, all I did was republish my Mobile Service. Now when I attempted to add a PropertyType it worked, no problems. Checking with Visual Studio 2015, the trigger on the PropertyType table had been successfully created. At this point I’m not sure what exactly happens when the Mobile Service runs but it seems to do more than just applying the code-first migrations. It definitely seems to me that updating the cloud database using the package manager console seemed to skip the validation step that Mobile Services does in order to add the appropriate triggers, and thus should be avoided.