Nick's .NET Travels

Continually looking for the yellow brick road so I can catch me a wizard....

Refactoring SignalR Feedback for Cross Platform with AutoFac and CommonServiceLocator for Simple Dependency Injection

At this point I’m starting to think about “real application” problems such as how services/components/view models are located and how navigation between view models is going to work. For anyone following this series of posts I currently have Universal (Windows/Windows Phone), Xamarin Forms (iOS (broken), Android and Windows Phone 8.0) and WPF clients. So far I’ve been covering how to handle accessing data (Mobile Services) and authentication (Azure Active Directory) and to a lesser degree data binding (XAML, Data binding and View Models) but I haven’t looked at how the client applications are going to be architected. There are some core issues which need to be solved in a general way so that it will work across all client applications, such as how view models are located (created and supplied to corresponding view) and how navigation can be triggered within a view model that will correlate to a page/view change in the UI layer. This issue I’ll leave to another day as it generally involves either picking an existing framework (MvvmCross, Mvvmlight etc) or rolling your own – and I’m still undecided on what to do.

What I do know is that in order to refactor my SignalR implementation, which is currently done within the WPF Window codebehind, so that it will work on all platforms I’m going to need to define a set of interfaces in the Core library (PCL) which is implemented by each platform. I should be able to reuse the same code on all platforms for the implementation so the code can go into the Shared.Client project – it just needs to reference the platform specific implementation of SignalR.

Before we get onto the refactoring, I’m going to add a couple of NuGet packages which will give use an IoC that we can call on to resolve dependencies. I was initially going to jump forward and include MvvmLight but I went looking for the navigation support and was a little disappointed – I’ll come back and do a full evaluation when I get to dealing with navigation but for now I’ve opted to go for Autofac. However, just in case I want to change IoC provider at a later stage I’ve also opted to include the CommonServiceLocator so as to provide a bit of an abstraction from any given library when it comes to resolving dependencies.

I’ve added the following NuGet packages to the Core and all client projects

Autofac

CommonServiceLocator

Autofac Extras: Microsoft Common Service Locator

Both Autofac and the CommonServiceLocator require logic to be run on application startup. There is both platform independent and platform specific code to be run. For this reason I’ve added the ClientApplicationCore class to the Shared.Client project and the ApplicationCore class to the Core library, with the following implementation:

public class ClientApplicationCore
{
    public static ClientApplicationCore Default { get; set; }

    static ClientApplicationCore()
    {
        Default=new ClientApplicationCore();
    }

    public ClientApplicationCore()
    {
        CoreApplication=new ApplicationCore();
    }

    public ApplicationCore CoreApplication { get; set; }

    public void ApplicationStartup()
    {
        CoreApplication.Startup(builder => builder.RegisterType<SignalRFactory>().As<ISignalR>());
    }
}

 

public class ApplicationCore
{
    public void Startup(Action<ContainerBuilder> dependencyBuilder)
    {
        var builder = new ContainerBuilder();
        dependencyBuilder(builder);
        // Perform registrations and build the container.
        var container = builder.Build();

        // Set the service locator to an AutofacServiceLocator.
        var csl = new AutofacServiceLocator(container);
        ServiceLocator.SetLocatorProvider(() => csl);
    }
}

You’ll notice that at this stage all I’m registering is SignalRFactory as an implementation of the ISignalR interface. This interface is one of two that I’ve defined within the Core library to assist with the refactored SignalR support:

public interface ISignalR
{
    Task<ICommunicationHub> Connect<THub>(IMobileServiceClient mobileService);
}

public interface ICommunicationHub:IDisposable
{
    string ConnectionId { get; }

    IDisposable Register<TMessageType>(string eventName, Action<TMessageType> handler);
}

The implementation is placed in the Shared.Client project so that it is reused across all client platforms:

internal class SignalRFactory : ISignalR
{
    public async Task<ICommunicationHub> Connect<THub>(IMobileServiceClient mobileService)
    {
        var hubConnection = new HubConnection(MainViewModel.MobileService.ApplicationUri.AbsoluteUri);

        hubConnection.Headers["x-zumo-application"] = MainViewModel.MobileService.ApplicationKey;

        IHubProxy proxy = hubConnection.CreateHubProxy(typeof(THub).Name);
        await hubConnection.Start();

        return new CommunicationHub { Connection = hubConnection, Hub = proxy };
    }
}

internal class CommunicationHub : ICommunicationHub
{
    public string ConnectionId { get { return Connection.ConnectionId; } }
    public HubConnection Connection { get; set; }
    public IHubProxy Hub { get; set; }
    public IDisposable Register<TMessageType>(string eventName, Action<TMessageType> handler)
    {
        return Hub.On(eventName, handler);
    }

    public void Dispose()
    {
        if (Connection != null)
        {
            Connection.Dispose();
            Connection = null;
            Hub = null;
        }

    }
}

The implementation of the GenerateReport method on the MainViewModel can now be refactored to look up the ISignalR implementation:

public async void GenerateReport()
{
    string message;
    try
    {
        var signalr = ServiceLocator.Current.GetInstance<ISignalR>();
        var hub= await signalr.Connect<LongRunningFeedbackHub>(MobileService);
        hub.Register<string>("Progress", msg => Debug.WriteLine(msg));

        var result = await MobileService.InvokeApiAsync<string>("Reporter", HttpMethod.Get, new Dictionary<string, string>{{"id", hub.ConnectionId}});
        message = result;
    }
    catch (MobileServiceInvalidOperationException ex)
    {
        message = ex.Message;
    }
    Debug.WriteLine(message);
}

And that’s it – this should work without modification on each of the client platforms….

Long Running Azure Mobile Service Call With Feedback using SignalR

I’ve been thinking a little more about alternative mechanisms for sending feedback to the client applications when a long running mobile service call is executing. In my previous post on Long Running Custom API Calls in Azure Mobile Service I discussed returning immediately to the client application whilst continuing to process a long running task. Unfortunately this means there is no way to provide feedback. In this post I’m going to add in SignalR to provide that real time communications link.

 

 

image

I’ll define a class that in herits from Hub and exposes a Services property – this will be populated automatically by the Mobile Service.

public class LongRunningFeedbackHub : Hub
{
    public ApiServices Services { get; set; }
}

Next I’ll amend the Get service method to a) take a parameter (which is the connection id of signalr on the client) and b) provide feedback during the long running task via the hub object. Note the use of the dynamic Progress method which will correlate to the client side proxy method that it subscribes to.

public async Task<string> Get(string id)
{
    var host = new ReportHost();
    host.DoWork(async (cancel) =>
    {
        try
        {
            var hub = Services.GetRealtime<LongRunningFeedbackHub>();

            var max = 5;
            for (int i = 0; i < max; i++)
            {
                await Task.Delay(TimeSpan.FromSeconds(5), cancel);

                hub.Clients.
                    Client(id)
                    .Progress(string.Format("{0}% complete",100*i/5));
            }
        }
        catch (Exception ex)
        {
            // Don't bubble the exception - do something sensible here!
            Debug.WriteLine(ex.Message);
        }
    });
    Services.Log.Info("Hello from custom controller!");
    return "Hello";
}

I added the initialization logic for the SignalR to the Register method of the WebApiConfig.cs file, as well as providing an explicit route to support the id parameter

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{action}/{id}",
    defaults: new { action = RouteParameter.Optional, id = RouteParameter.Optional }
);

SignalRExtensionConfig.Initialize();

On the client side I add the SignalR .NET Client library from NuGet

image

And then add a ConnectToSignalR method to establish the hub connection and return a connectionId, which will then be passed into the view model via the GenerateReport method.

private async void GenerateReportClick(object sender, RoutedEventArgs e)
{
    var connectionId=await  ConnectToSignalR();
    CurrentViewModel.GenerateReport(connectionId);
}

private async Task<string> ConnectToSignalR()
{
    var hubConnection = new HubConnection(MainViewModel.MobileService.ApplicationUri.AbsoluteUri);
    //if (user != null)
    //{
    //    hubConnection.Headers["x-zumo-auth"] = user.MobileServiceAuthenticationToken;
    //}
    //else
    //{
    hubConnection.Headers["x-zumo-application"] = MainViewModel.MobileService.ApplicationKey;
    //}
    IHubProxy proxy = hubConnection.CreateHubProxy("LongRunningFeedbackHub");
    await hubConnection.Start();

    //string result = await proxy.Invoke<string>("Send", "Hello World!");
    //var invokeDialog = new MessageDialog(result);
    //await invokeDialog.ShowAsync();

    proxy.On<string>("Progress",
        msg => Debug.WriteLine(msg));

    return hubConnection.ConnectionId;
}

The only change to the GenerateReport method is for it to accept an id parameter and for this parameter to be passed into the custom api

var result = await MobileService.InvokeApiAsync<string>("Reporter", HttpMethod.Get, new Dictionary<string, string>{{"id",connectionId}});

When this is run and the GenerateReport method is invoked, the current percentage complete is passed back to the client and appears in the handler for the Progress message.

Long Running Custom API Calls in Azure Mobile Service

As I pointed out in my previous post a common scenario for custom apis in a Mobile Service is to hand off tasks that aren’t easily done on a mobile device, or are better suited to being done server side (eg report creation). Quite often these tasks can take longer than the default timeout of most service requests (typically 60seconds) which means the mobile app ends up raising an exception which is not very useful. A better approach is to queue the work somehow and then to periodically check on it’s progress. In this post I’m just going to demonstrate one way to allow the service to respond immediately, whilst continuing to carry out the task in the background. Note that the ReportHost is based on the JobHost class described in Phil Haack’s post on the dangers of background tasks

public async Task<string> Get()
{
    var host = new ReportHost();
    host.DoWork(async (cancel) =>
    {
        try
        {
            await Task.Delay(TimeSpan.FromMinutes(2), cancel);
        }
        catch (Exception ex)
        {
            // Don't bubble the exception - do something sensible here!
            Debug.WriteLine(ex.Message);
        }
    });
    Services.Log.Info("Hello from custom controller!");
    return "Hello";
}

And the ReportHost class

public class ReportHost : IRegisteredObject
{
    private readonly ManualResetEvent reportLock = new ManualResetEvent(false);
    private readonly CancellationTokenSource cancellation=new CancellationTokenSource();

    public ReportHost()
    {
        HostingEnvironment.RegisterObject(this);
    }

    public void Stop(bool immediate)
    {
        cancellation.Cancel();
        reportLock.WaitOne();
        HostingEnvironment.UnregisterObject(this);
    }

    public void DoWork(Func<CancellationToken,Task> work)
    {
        Task.Run(async () =>
        {
            await work(cancellation.Token);
            reportLock.Set();
        });
    }
}

I haven’t shown any client side code for the timebeing because it remains the same (although it won’t timeout now!). The next step is to provide some way that the client can check on the progress of the work item.

Invoking a Custom API in Azure Mobile Service

The full scenario is that we have a task that needs to be performed by the Mobile Service that might take a while to complete. The first step is to define a custom api which will invoke the task (alternatively you could hijack a table controller to launch the task as part of one of the CRUD actions) and to have this called from the client applications. However, this alone is not sufficient for long running tasks as the call to the service may timeout before the task completes. I’ll come back to that in a future post but for now, let’s look at creating a custom api.

The first step is to add a new controller based on the Microsoft Azure Mobile Services Custom Controller template.

image

I’ll give the new controller a name

image

For the time being the only change I’ll make is to include the AutorizeLevel and AuthorizeInspector attributes to enforce the security policies required for accessing our services:

[AuthorizeLevel(AuthorizationLevel.User)]
[AuthorizeInspector]
public class ReporterController : ApiController
{
    public ApiServices Services { get; set; }

    // GET api/Reporter
    public async Task<string> Get()
    {
        Services.Log.Info("Hello from custom controller!");
        return "Hello";
    }

}

Invoking this from the client can easily be done from within the MainViewModel:

public async void GenerateReport()
{
    string message;
    try
    {
        var result = await MobileService.InvokeApiAsync<string>("Reporter", HttpMethod.Get, null);
        message = result;
    }
    catch (MobileServiceInvalidOperationException ex)
    {
        message = ex.Message;
    }
    Debug.WriteLine(message);
}

Easy done – a simple api that we can invoke within our Mobile Service to do work. Note that in this case it’s a Get requrest with no parameters and a simple string return type. We can adjust this to be a Post, accept parameters and return a complex object by adjusting both the controller method definition (ie change Get to Post, or even just add a Post method) and invokeapiasync call.

Handling MobileServiceConflictException with Azure Mobile Service with Offline Sync

Whenever you do offline sync, there is a risk of conflicts emerging between client and server updates. Of course the data architecture should be done to minimise this (eg guid based primary keys) but this won’t always eliminate the issue. One example of where this might happen is if the client gets cut off midway through pushing changes to the server. For example if I were to insert a new record on the client, push the changes but before the changes had been confirmed back to the client, the network connection was terminated. The server now has the new record but the client thinks it still needs to send the record – when it does, a conflict arises where both server and client have records with the same primary key. Let’s replicate this and then look at solving it.

I’ll create an AddProperty method into my MainViewModel:

public async Task AddProperty()
{
    var table=MobileService.GetSyncTable<RealEstateProperty>();
    var prop = new RealEstateProperty
    {
        Address = "New Random Property"
    };
    await table.InsertAsync(prop);
    await MobileService.SyncContext.PushAsync();
}

Run this, and insert a breakpoint after the InsertAsync but before the PushAsync. At this point inspect the prop object and retrieve the Id. Next, using either Sql Server Management Studio or Visual Studio 2015, connect to the SQL Server instance and run the following query (replacing the Id with the one retrieved in previous step).

insert into realestateinspector.RealEstateProperties (Id,Address,Deleted) Select '0a1f8994-4a4b-4548-921a-4da0186b3f6c','Not created on client',0

Now, if I let the PushAsync continue it will fail, causing an exception to be raised.

image

There are a couple of places that this can be handled. The first is where the call to PushAsync is made – this isn’t great as pushing to the remove service won’t necessarily happen at this point. For example you might insert a record but not push immediately. In this case when you next issue a pull request the push will be done prior to doing the pull. A better way to handle it is to supply a custom MobileServiceSyncHandler as part of the initialization of the sync context:

 

await MobileService.SyncContext.InitializeAsync(data, new CustomMobileServiceSyncHandler());

The sync handler could look like the following (this is very basic and just drops any conflicts)

public class CustomMobileServiceSyncHandler : MobileServiceSyncHandler
{
    public async override Task<JObject> ExecuteTableOperationAsync(IMobileServiceTableOperation operation)
    {
        try
        {
            return await base.ExecuteTableOperationAsync(operation);
        }
        catch (MobileServiceConflictException cex)
        {
            Debug.WriteLine(cex.Message);
            throw;
        }
    }

    public override Task OnPushCompleteAsync(MobileServicePushCompletionResult result)
    {
        foreach (var error in result.Errors)
        {
            if (error.Status == HttpStatusCode.Conflict)
            {
                error.CancelAndUpdateItemAsync(error.Result);
                error.Handled = true;
            }
        }
        return base.OnPushCompleteAsync(result);
    }
}

Restricting Access to Azure Mobile Service Base on Azure Active Directory Group

In my previous post I controlled access to the GetAll method on my base controller by determining whether the authenticated (from AAD) user was a member of the Inspectors AAD group. This is actually quite a slow process and not something you really want to do every session. Ideally I’d like this check to be done once when the user authenticates against the mobile service (which happens after they authenticate against AAD) and for the IsInspector claim to be added to the user identity. Unfortunately for the life of me I can’t work out how to force OWIN into accepting an additional claim – I’m sure there’s a way, but I ended up settling for an alternative approach.

My approach actually improves on two aspects over what I was previously doing. The first is that I implement the checking logic as an attribute which can then be applied to the root controller. The second is that by storing a cookie in the response, I can reduce the need to re-query AAD for the group membership. This solution is based on a couple of great blog posts:

http://www.acupofcode.com/2014/04/general-roles-based-access-control-in-the-net-backend/

http://www.acupofcode.com/2014/03/roles-based-access-control-in-mobile-services-and-azure-active-directory/

The AuthorizeInspector attribute looks as follows:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class AuthorizeInspector : AuthorizationFilterAttribute
{
    public static ActiveDirectoryClient RetrieveActiveDirectoryClient(string token)
    {
        var baseServiceUri = new Uri(Microsoft.Azure.ActiveDirectory.GraphClient.Constants.ResourceId);
        var activeDirectoryClient =
            new ActiveDirectoryClient(new Uri(baseServiceUri, Constants.ADTenant),
                async () => token);
        return activeDirectoryClient;
    }

    public async override Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        await base.OnAuthorizationAsync(actionContext, cancellationToken);

        var cookie = HttpContext.Current.Request.Cookies["IsInspector"];
        var isInspector = cookie != null ? cookie.Value : null;
        if (isInspector != null)
        {
            if (!(bool.Parse(isInspector)))
            {
                actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);
            }
            return;
        }

        var controller = actionContext.ControllerContext.Controller as ApiController;
        if (controller == null)
        {
            return;
        }
        var user = controller.User as ServiceUser;

        //var user = User as ServiceUser;
        var aadCreds = (await user.GetIdentitiesAsync()).OfType<AzureActiveDirectoryCredentials>().FirstOrDefault();
        Debug.WriteLine(aadCreds.AccessToken);

        var token = actionContext.Request.Headers.GetValues(Constants.RefreshTokenHeaderKey)
            .FirstOrDefault();

        var auth = new AuthenticationContext(Constants.ADAuthority, false);
        var newToken = await auth.AcquireTokenByRefreshTokenAsync(token,
                Constants.ADNativeClientApplicationClientId, "
https://graph.windows.net");

        var client = RetrieveActiveDirectoryClient(newToken.AccessToken);
        var grps = await client.Groups.ExecuteAsync();
        var moreGroups = grps.CurrentPage;

        while (moreGroups != null)
        {
            foreach (var grp in grps.CurrentPage)
            {
                if (grp.DisplayName == "Inspectors")
                {
                    if ((await client.IsMemberOfAsync(grp.ObjectId, aadCreds.ObjectId)) ?? false)
                    {
                        HttpContext.Current.Response.Cookies.Add(new HttpCookie("IsInspector", true.ToString()));

                        return;
                    }
                }
            }
            if (grps.MorePagesAvailable)
            {
                grps = await grps.GetNextPageAsync();
                moreGroups = grps.CurrentPage;
            }
            else
            {
                grps = null;
                moreGroups = null;
            }
        }
        HttpContext.Current.Response.Cookies.Add(new HttpCookie("IsInspector", false.ToString()));
    }
}

As you can see this follows roughly the same logic for querying AAD group membership. However, this time I’m adding a cookie based on whether the user is an Inspector or not.This attribute can now be applied to the RealEstateBaseTableController.

[AuthorizeInspector]
public class RealEstateBaseTableController<TEntity> : TableController<TEntity>
    where TEntity : class, ITableData
{

One thing to be aware of is that this cookie will persist even if the user logs out. As such, we need some way of associating the cookie with the current user session. It may be that an additional cookie is used to associate the access token with the IsInspector cookie. For example:

public override async Task OnAuthorizationAsync(HttpActionContext actionContext,
    CancellationToken cancellationToken)
{
    await base.OnAuthorizationAsync(actionContext, cancellationToken);

    var controller = actionContext.ControllerContext.Controller as ApiController;
    if (controller == null)
    {
        return;
    }
    var user = controller.User as ServiceUser;

    //var user = User as ServiceUser;
    var aadCreds = (await user.GetIdentitiesAsync()).OfType<AzureActiveDirectoryCredentials>().FirstOrDefault();
    Debug.WriteLine(aadCreds.AccessToken);

    var cookie = HttpContext.Current.Request.Cookies["IsInspector"];
    var isInspector = cookie != null ? cookie.Value : null;
    var accessTokenCookie = HttpContext.Current.Request.Cookies["IsInspectorAccessToken"];
    var access_token = accessTokenCookie != null ? accessTokenCookie.Value : null;
    if (isInspector != null && access_token == aadCreds.AccessToken)
    {
        if (!(bool.Parse(isInspector)))
        {
            actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);
        }
        return;
    }

    var token = actionContext.Request.Headers.GetValues(Constants.RefreshTokenHeaderKey)
        .FirstOrDefault();

    var auth = new AuthenticationContext(Constants.ADAuthority, false);
    var newToken = await auth.AcquireTokenByRefreshTokenAsync(token,
        Constants.ADNativeClientApplicationClientId, "
https://graph.windows.net");

    var client = RetrieveActiveDirectoryClient(newToken.AccessToken);
    var grps = await client.Groups.ExecuteAsync();
    var moreGroups = grps.CurrentPage;

    try
    {
        while (moreGroups != null)
        {
            foreach (var grp in grps.CurrentPage)
            {
                if (grp.DisplayName == "Inspectors")
                {
                    if ((await client.IsMemberOfAsync(grp.ObjectId, aadCreds.ObjectId)) ?? false)
                    {
                        HttpContext.Current.Response.Cookies.Add(new HttpCookie("IsInspector", true.ToString()));

                        return;
                    }
                }
            }
            if (grps.MorePagesAvailable)
            {
                grps = await grps.GetNextPageAsync();
                moreGroups = grps.CurrentPage;
            }
            else
            {
                grps = null;
                moreGroups = null;
            }
        }
        HttpContext.Current.Response.Cookies.Add(new HttpCookie("IsInspector", false.ToString()));
    }
    finally
    {
        HttpContext.Current.Response.Cookies.Add(new HttpCookie("IsInspectorAccessToken", aadCreds.AccessToken));

    }
}

Augmenting Mobile Service Response with Azure Active Directory Group Membership

In the previous post we saw how you can query Azure Active Directory after authenticating a Mobile Service client against Azure Active Directory. Now I’m going to use this knowledge to restrict access to data based on group membership. In this case the user has to belong to a group with the name “Inspectors”. One thing you’ll notice is that this process is quite slow, so we’ll have to look for a better way to enforce security, without having to query AAD with each service request. The full GetAll method is as follows:

public async Task<IQueryable<TEntity>> GetAll()
{
    var user = User as ServiceUser;
    var aadCreds = (await user.GetIdentitiesAsync()).OfType<AzureActiveDirectoryCredentials>().FirstOrDefault();
    Debug.WriteLine(aadCreds.AccessToken);

    var token = this.ActionContext.Request.Headers.GetValues(Constants.RefreshTokenHeaderKey)
        .FirstOrDefault();

    var auth = new AuthenticationContext(Constants.ADAuthority, false);
    var newToken = await auth.AcquireTokenByRefreshTokenAsync(token,
        Constants.ADNativeClientApplicationClientId, "
https://graph.windows.net");

    var client = RetrieveActiveDirectoryClient(newToken.AccessToken);
    var grps = await client.Groups.ExecuteAsync();
    var moreGroups = grps.CurrentPage;
    while (moreGroups != null)
    {
        foreach (var grp in grps.CurrentPage)
        {
            if (grp.DisplayName == "Inspectors")
            {
                if ((await client.IsMemberOfAsync(grp.ObjectId, aadCreds.ObjectId)) ?? false)
                {
                    return Query();
                }
            }
            Debug.WriteLine(grp != null);
        }
        if (grps.MorePagesAvailable)
        {
            grps = await grps.GetNextPageAsync();
            moreGroups = grps.CurrentPage;
        }
    }

    return null;
}

Accessing Active Directory Graph API from Azure Mobile Service using Azure Active Directory Authentication

After getting local debugging to work with my Azure AD protected Mobile Service I’m now ready to start querying Azure Active Directory for information about the authenticated user, which can then be used to control what data is returned (being a better approach than allowing the client to determine what information it queries for). However, this turned out to be slightly harder than I thought it would be.

Having taken a look at various blogs/articles that talk about accessing AAD they all referred to the Graph API and there’s a NuGet package that can easily be installed into my service project which will make it easy for me to access the various aspects of AAD.

image

After installing this NuGet package when you run the Mobile Service project you may experience an error where it can’t resolve certain assemblies. To resolve this issue, look in the web.config file and ensure the assemblyBinding section has been correctly updated to point to the version of assemblies referenced by the Mobile Service project, and ensure there are no duplicates.

There appears to be two ways to use the graph client library. The older, and now deprecated, way is to use the GraphConnection class; the new way, which we’ll look at, is using the ActiveDirectoryClient class. This can be instantiate as follows:

public static ActiveDirectoryClient RetrieveActiveDirectoryClient(string token)
{
    var baseServiceUri = new Uri(Microsoft.Azure.ActiveDirectory.GraphClient.Constants.ResourceId);
    var activeDirectoryClient =
        new ActiveDirectoryClient(new Uri(baseServiceUri, Constants.ADTenant),
            async () => token);
    return activeDirectoryClient;
}

Now, my initial assumption was that I could simply pass in the access token that I can extract from the claims passed into the Mobile Service. This isn’t the case but should you need this information, it can easily be retrieved by accessing the User property that’s made available within the base TableController class.

var user = User as ServiceUser;
var aadCreds = (await user.GetIdentitiesAsync()).OfType<AzureActiveDirectoryCredentials>().FirstOrDefault();
Debug.WriteLine(aadCreds.AccessToken);

Of course, what I was trying to do would never work, since the claims I have in my access token are for the Mobile Service endpoint, not for Azure Active Directory (even though AAD authenticated the user). What I need to do is to request an access token with the AAD Graph API as the resource that I’m requesting access to. Luckily I don’t need to go through the whole authentication process, as I can use the RefreshToken that was returned along with the initial access token to request a different access token with permission to access a different resource. But first, I need to go into the Native Client application in AAD and give it permissions to access Windows Azure Active Directory. This might seem a little counter intuitive since we’re going to be accessing AAD from within the Mobile Service but if you think about the access token that will be used, it was issued via the native client application within AAD, so it’s here that we need to control the permission set.

image

The challenge I now faced is that within the Mobile Service I don’t have access to the refresh token; I only have the objectId of the authenticated user in AAD, the tenantId and the access token – this isn’t enough for me to gain access via the graph api. I have two options 1) the native client could use the refresh token it has to request another access token with access to the graph api and then to pass this through with the Mobile Service request, or 2) for the refresh token to be passed through into the Mobile Service and let it request the refresh token. I opted for the option 2 as I’m a bit reluctant to have access tokens out in the wild that can access the graph api and I’d prefer to have that work shielded behind the service facade. In fact, with either option I needed to find a way to pass an additional token through to the Mobile Service – as you can imagine this is easily done if I were manually creating the requests. Luckily the Mobile Service client library allows for a delegatinghandler to be specified that will give me access to the raw requests before they’re sent. So, here are the changes I need to make:

I created a MobileServiceHttpHandler which will insert the refresh token as a header into all requests. The name of the header is somewhat arbitrary so long as you use the same header on the client and server sides. I have RefreshTokenHeaderKey = “X-RefreshToken”

public class MobileServiceHttpHandler : DelegatingHandler
{
    public static string RefreshToken { get; set; }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (!string.IsNullOrWhiteSpace(RefreshToken))
        {
            request.Headers.Add(Constants.RefreshTokenHeaderKey, RefreshToken);
        }

        return base.SendAsync(request, cancellationToken);
    }
}

I then updated the declaration of my Mobile Service client to use this new delegatinghandler

public static MobileServiceClient MobileService = new MobileServiceClient(
    Constants.MobileServiceRootUri,
    "wpxaIplp-----------------------XiVlZAPYQEBcg12",
    new MobileServiceHttpHandler()
    );

In the AuthenticationHelper, before returning the access token, I’m going to assign the refresh token to the delegatinghandler:

Debug.WriteLine(authResult != null);
MobileServiceHttpHandler.RefreshToken = authResult.RefreshToken;
return authResult.AccessToken;

In my Mobile Service I have a simple method to create an instance of the ActiveDirectoryClient:

public static ActiveDirectoryClient RetrieveActiveDirectoryClient(string token)
{
    var baseServiceUri = new Uri(Microsoft.Azure.ActiveDirectory.GraphClient.Constants.ResourceId);
    var activeDirectoryClient = new ActiveDirectoryClient(new Uri(baseServiceUri, Constants.ADTenant), async () => token);
    return activeDirectoryClient;
}

In one of the methods, I’m going to use the GetAll method, of my RealEstateBaseTableController (in the Mobile Services project), I’m going to add the following code:

var token = this.ActionContext.Request.Headers.GetValues(Constants.RefreshTokenHeaderKey).FirstOrDefault();

var auth = new AuthenticationContext(Constants.ADAuthority, false);
var newToken = await auth.AcquireTokenByRefreshTokenAsync(token, Constants.ADNativeClientApplicationClientId, "
https://graph.windows.net");

var client = RetrieveActiveDirectoryClient(newToken.AccessToken);
var grps = await client.Groups.ExecuteAsync();

Here you can see that I’m retrieving the groups that are defined in this tenant within AAD. I also had to update the method signature to make it async and return a Task:

public async Task<IQueryable<TEntity>> GetAll()

If you simply run this, you’re unlikely to see any results unless you have at least one group defined in your AAD. To create a group, go to the tenant within AAD and select the Groups tab. Create a new group by assigning it a name and description:

image

In the next post we’ll take this a step further an use this knowledge to control what the user can access.

Debugging Azure Active Directory Authentication with Azure Mobile Service .NET Backend When Running Locally

In a recent project one of the more challenging things was to debug the Azure Mobile Services (AMS) when running locally. For the most part it was pretty straight forward as a lot of the requests, whilst they required a user to be authenticated, the returned data wasn’t contingent on who the user was. When you run Azure Mobile Services locally, which you can with the .NET backend but not with the Node.js backend, by default it doesn’t enforce any of the security requirements. This makes it easy to debug scenarios where it doesn’t matter who the user is but very hard for those scenarios where the data needs to be altered based on who the user is, particularly if the user is being authenticated using Azure Active Directory (AAD). In this post I’ll walk through getting debugging to run locally.

The first thing I need to do is to configure the Mobile Service to enforce the same security when running locally, as if it were running in Azure. I do this by adding the following immediately following the ServiceConfig.Initialize line:

// This tells the local mobile service project to run as if it is being hosted in Azure,
// including honoring the AuthorizeLevel settings. Without this setting, all HTTP requests to
// localhost are permitted without authentication despite the AuthorizeLevel setting.
config.SetIsHosted(true);

Side Note (feel free to skip over this section if you’re not interested on how I attempted to get this to work)

My initial approach was to use what I new about the way AAD connects with AMS which involves an application within AAD that defines the relationship between the native client (which is authenticating) and the AMS (which is the resource it is requesting access to). As my AMS is running locally it is hosted at http://localhost:51539/ I thought that I needed to create another AAD Web application pointing at http://localhost:51539/login/aad eg

image

And then in the Native Client AAD application I had to delegate permissions to the new AAD Web application eg

image

In the native application, in this case my WPF application, I changed both the resource url for the AAD authentication and the mobile services url to use http://localhost:51539/ ie http://localhost:51539/login/aad for the resource url and just http://localhost:51539/ for the mobile services url. This seemed to work correctly initially as it displayed the sign in prompt, I could sign in and get back an AAD access token. Unfortunately when this was passed to the AMS it failed miserably with an unauthorised exception.

Note: I actually feel what I did here was correct that that the Mobile Services team are incorrectly validating the claims based on the illusion that the local services is being hosted in the cloud. This means you actually need to authenticate with AAD as if you were requesting access to the resource https://realestateinspector.azure-mobile.net/login/aad and then actually connect to the locally running mobile service.

End of Side Note – Here’s how you really do it

Ok, so you DON’T need to change the url that is being specified as the resource when signing into AAD. However, you DO need to change the url that is used when creating the instance of the mobile service client. My constants file now looks like this:

#if DEBUG
#define DEBUGLOCAL
#endif

public static class Constants
{
    public const string ADTenant = "realestateinspector.onmicrosoft.com";
    public const string ADAuthority="
https://login.windows.net/" + ADTenant;

    public const string ADNativeClientApplicationClientId = "a5a10ee9-f871-4bde-997f-3f1c323fefa5";

    public const string ADRedirectUri = "http://builttoroam.com";

#if DEBUGLOCAL
    public const string ActualMobileServiceRootUri = "
https://realestateinspector.azure-mobile.net/";
    public const string MobileServiceRootUri = "http://localhost:51539/";
    public const string MobileServiceAppIdUri = ActualMobileServiceRootUri + "login/aad";
#else
    public const string MobileServiceRootUri = "
https://realestateinspector.azure-mobile.net/";
    public const string MobileServiceAppIdUri = MobileServiceRootUri + "login/aad";
#endif
}

Note that I’ve used an inline compilation constant to allow me to switch from debugging against the local services versus those hosted in the cloud.

If you attempt to run this, the user will be directed to authenticate using the AAD signin with a resource https://realestateinspector.azure-mobile.net/login/aad and then the application will attempt to login to the Mobile Service running locally at http://localhost:51539/ (Note – I typically set both the native client project (in this case the WPF application) and the Mobile Service project as start projects). However, you’ll still get an unauthorized exception because the Mobile Service actual does verify that the claims in the access token returned from AAD match the settings of the Mobile Services (excluding the base url that the service is being run from - see my early argument why this imho is the wrong approach). Let’s first take a look at the access token using the site http://jwt.io.

image 

If you look in the Web.config file for the Mobile service you’ll see that there is a list of Mobile Service settings in the appSettings section. The first of which is typically the MS_MobileServiceName and I’m guessing it’s this setting that is being used to validate that the claim in the token is for the right mobile serivce – in the token you can see that the resource is https://realestateinspector.azure-mobile.net/login/aad where the only piece that varies between Mobile Services is the service name.

<add key="MS_MobileServiceName" value="realestateinspector" />
The next thing to look at is in the actual login request that the mobile service client library makes:

POST: https://realestateinspector.azure-mobile.net/login/aad
X-ZUMO-INSTALLATION-ID: c2ac49d1-af97-472b-af61-bfb06663f137
X-ZUMO-APPLICATION: wpxaIplpeXtknXQhqXiVlZAPYQEBcg12
X-ZUMO-AUTH: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ1cm46bWljcm9zb2Z0OndpbmRvd3MtYXp1cmU6enVtbyIsImF1ZCI6InVybjptaWNyb3NvZnQ6d2luZG93cy1henVyZTp6dW1vIiwibmJmIjoxNDIyMDkxOTY3LCJleHAiOjE0MjIwOTU0OTYsInVybjptaWNyb3NvZnQ6Y3JlZGVudGlhbHMiOiJ7XCJ0ZW5hbnRJZFwiOlwiZTY4OGQ1OTQtODY0My00YmRmLTllNGMtMGJlOGJjYmM2NDVmXCIsXCJvYmplY3RJZFwiOlwiYWJkNzc5MjgtNDFkMS00YzNjLThmNmYtMmE1NmQ4NDRkMDVlXCIsXCJhY2Nlc3NUb2tlblwiOlwiZXlKMGVYQWlPaUpLVjFRaUxDSmhiR2NpT2lKU1V6STFOaUlzSW5nMWRDSTZJbXR5YVUxUVpHMUNkbmcyT0hOclZEZ3RiVkJCUWpOQ2MyVmxRU0o5LmV5SmhkV1FpT2lKb2RIUndjem92TDNKbFlXeGxjM1JoZEdWcGJuTndaV04wYjNJdVlYcDFjbVV0Ylc5aWFXeGxMbTVsZEM5c2IyZHBiaTloWVdRaUxDSnBjM01pT2lKb2RIUndjem92TDNOMGN5NTNhVzVrYjNkekxtNWxkQzlsTmpnNFpEVTVOQzA0TmpRekxUUmlaR1l0T1dVMFl5MHdZbVU0WW1OaVl6WTBOV1l2SWl3aWFXRjBJam94TkRJeU1Ea3hOalUyTENKdVltWWlPakUwTWpJd09URTJOVFlzSW1WNGNDSTZNVFF5TWpBNU5UVTFOaXdpZG1WeUlqb2lNUzR3SWl3aWRHbGtJam9pWlRZNE9HUTFPVFF0T0RZME15MDBZbVJtTFRsbE5HTXRNR0psT0dKalltTTJORFZtSWl3aVlXMXlJanBiSW5CM1pDSmRMQ0p2YVdRaU9pSmhZbVEzTnpreU9DMDBNV1F4TFRSak0yTXRPR1kyWmkweVlUVTJaRGcwTkdRd05XVWlMQ0oxY0c0aU9pSnBibk53WldOMGIzSkFjbVZoYkdWemRHRjBaV2x1YzNCbFkzUnZjaTV2Ym0xcFkzSnZjMjltZEM1amIyMGlMQ0p6ZFdJaU9pSm5WMlJUY0VwbllqSnBUbkpyWm5wbVlUQlViWGhPTFZGeU0yMXFhamhoY0ZoZlYxbG5lVGRrVDNOUklpd2libUZ0WlNJNklrbHVjM0JsWTNSdmNpSXNJblZ1YVhGMVpWOXVZVzFsSWpvaWFXNXpjR1ZqZEc5eVFISmxZV3hsYzNSaGRHVnBibk53WldOMGIzSXViMjV0YVdOeWIzTnZablF1WTI5dElpd2lZWEJ3YVdRaU9pSmhOV0V4TUdWbE9TMW1PRGN4TFRSaVpHVXRPVGszWmkwelpqRmpNekl6Wm1WbVlUVWlMQ0poY0hCcFpHRmpjaUk2SWpBaUxDSnpZM0FpT2lKMWMyVnlYMmx0Y0dWeWMyOXVZWFJwYjI0aUxDSmhZM0lpT2lJeEluMC5IVEhlUEFEcW5XYjE2ZTdwYTQ1VkppdFlTV2pvanZzaEwyZ3I4cTR3S1k2QkpWNF9INXBoQklmQ1p3RUtGeU05MlpQWkpza1NDVkl5QlNvNnU0eTgyUlJKcWxmVW9NN3hjRG1zZ0dOVlNYZzhoOGhJWm56X1ZIcGg4ZUp4TXRvZ0VrR2tZWXFld0R5Wi1zWlVTaVZ5ckhpZWlCd2Qzd2M4T0hQaDRXeGUwbUh6OHItekZoOGtmY2lQWW9KRkJ3aGczVGFaZ3hMQWJnaWVMUG83V1ZBUFpIUjV5SG1UaW02RXhQOGdUejQ0WmFiYTI3QnpISUI1dV9oa1F2QWlmU2M2blBXcVZwcC1CamZQM25mbXQwai0xemkwb1RHMVlvMjZNQzNXSHhCTUdKbGpKcVg3UmhBenV4anZESDFyRG5PeE9YaldSVk1qV2gyNzRXUjdXa0YwM0FcIn0iLCJ1aWQiOiJBYWQ6Z1dkU3BKZ2IyaU5ya2Z6ZmEwVG14Ti1RcjNtamo4YXBYX1dZZ3k3ZE9zUSIsInZlciI6IjIifQ.s6fjFOzFhdvvYgL3yD3lUEiUcxALg-avOvwJb1gILDU
Accept: application/json
User-Agent: ZUMO/1.3 (lang=Managed; os=Windows; os_version=6.2.0.9200; arch=Win32NT; version=1.3.21121.0)
X-ZUMO-VERSION: ZUMO/1.3 (lang=Managed; os=Windows; os_version=6.2.0.9200; arch=Win32NT; version=1.3.21121.0)
Content-Type: application/json; charset=utf-8
Host: localhost:51539
Cookie: ARRAffinity=0289d9a2e779a2431db31b4a154e84828a77f89dbbe1fe391d5fe9794f54f970
Content-Length: 1237
Expect: 100-continue
Accept-Encoding: gzip
Connection: Keep-Alive

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImtyaU1QZG1Cdng2OHNrVDgtbVBBQjNCc2VlQSJ9.eyJhdWQiOiJodHRwczovL3JlYWxlc3RhdGVpbnNwZWN0b3IuYXp1cmUtbW9iaWxlLm5ldC9sb2dpbi9hYWQiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9lNjg4ZDU5NC04NjQzLTRiZGYtOWU0Yy0wYmU4YmNiYzY0NWYvIiwiaWF0IjoxNDIyMDkxNjU2LCJuYmYiOjE0MjIwOTE2NTYsImV4cCI6MTQyMjA5NTU1NiwidmVyIjoiMS4wIiwidGlkIjoiZTY4OGQ1OTQtODY0My00YmRmLTllNGMtMGJlOGJjYmM2NDVmIiwiYW1yIjpbInB3ZCJdLCJvaWQiOiJhYmQ3NzkyOC00MWQxLTRjM2MtOGY2Zi0yYTU2ZDg0NGQwNWUiLCJ1cG4iOiJpbnNwZWN0b3JAcmVhbGVzdGF0ZWluc3BlY3Rvci5vbm1pY3Jvc29mdC5jb20iLCJzdWIiOiJnV2RTcEpnYjJpTnJrZnpmYTBUbXhOLVFyM21qajhhcFhfV1lneTdkT3NRIiwibmFtZSI6Ikluc3BlY3RvciIsInVuaXF1ZV9uYW1lIjoiaW5zcGVjdG9yQHJlYWxlc3RhdGVpbnNwZWN0b3Iub25taWNyb3NvZnQuY29tIiwiYXBwaWQiOiJhNWExMGVlOS1mODcxLTRiZGUtOTk3Zi0zZjFjMzIzZmVmYTUiLCJhcHBpZGFjciI6IjAiLCJzY3AiOiJ1c2VyX2ltcGVyc29uYXRpb24iLCJhY3IiOiIxIn0.HTHePADqnWb16e7pa45VJitYSWjojvshL2gr8q4wKY6BJV4_H5phBIfCZwEKFyM92ZPZJskSCVIyBSo6u4y82RRJqlfUoM7xcDmsgGNVSXg8h8hIZnz_VHph8eJxMtogEkGkYYqewDyZ-sZUSiVyrHieiBwd3wc8OHPh4Wxe0mHz8r-zFh8kfciPYoJFBwhg3TaZgxLAbgieLPo7WVAPZHR5yHmTim6ExP8gTz44Zaba27BzHIB5u_hkQvAifSc6nPWqVpp-BjfP3nfmt0j-1zi0oTG1Yo26MC3WHxBMGJljJqX7RhAzuxjvDH1rDnOxOXjWRVMjWh274WR7WkF03A"
}

The X-ZUMO-APPLICATION header specified in the request needs to match the MS_ApplicationKey setting specified in the Web.config file. Most of these settings have a default value of “Overridden by portal settings” which, as it implies, is because they are overridden when the Mobile Service is hosted in the cloud. However, when running locally some of these settings need to be specified in order to get authentication to work. In this case it’s both the MS_ApplicationKey and MS_AadTenants:

<add key="MS_ApplicationKey" value="wpxaIplpeXtknXQhqXiVlZAPYQEBcg12" />
<add key="MS_AadTenants" value="realestateinspector.onmicrosoft.com" />

With this in place, running the native application again and you can login, retrieve the AAD access token, and then when the mobile service client attempts to login it will do successfully. When you then make a call to one of the controllers, you can set a break point and access the User property to retrieve information about the current user and their claims. This image shows the AAD claim for this user.

 

image

Xamarin.Forms, Windows Phone, Azure Active Directory and iOS

In my previous post I thought that there was an issue with using the Azure Active Directory Authentication Library (ADAL) and the updated Xamarin for iOS. This has been confirmed by the team at Microsoft responsible for ADAL with a view that it will be resolved in a future version (no specifics on which version or when). This is unfortunate as it means my iOS version will have to be put on hold for the timebeing.

On a different note I saw a mention in the forums that apparently Xamarin.Forms 1.4 will support Windows Phone 8.1 (and I hope as part of a universal app, also supporting Windows 8.1). Of course, there’s no timing on this one but does pose the question as to whether I should wait for the next iteration of Xamarin.Forms before proceeding with the sample apps. For the timebeing I’ll continue and see how far I get.

Active Directory Authentication with iOS with Xamarin.Forms

Essentially this doesn’t appear to currently work. Due to the alignment of iOS projects to the Unified APIs I think there is currently a compatibility issue between the ADAL prerelease library and the Xamarin.Forms implementation. I’ll come back to this once we have a resolution for this.

Adding WPF Client with Azure Active Directory Authentication and Azure Mobile Service

In today’s post I was going to cover adding Azure AD authentication to my iOS project but I don’t have my Mac build machine handy so there’s a bit of a change of plans. Today I’m going to add a WPF desktop application to my solution and catch it up to where the other client applications are up to. I’ll start by creating the WPF Application.

image

At this point I realised that I missed setting the framework in the Add New Project dialog, so I opened the Properties pane of the application and on the Application tab I set the Target framework to .Net Framework 4.5.

image

Next we need to add references to the following solution projects:

- RealEstateInspector.Core

- RealEstateInspector.Shared.Client

And then add reference to both the ADAL and Mobile Service SqliteStore packages. From the downloads page on sqlite.org you’ll also need to download the “32-bit DLL (x86) for SQLite” which is under the Precompiled Binaries for Windows heading. Unblock and Extract the zip file and add the sqlite3.dll file to the new WPF project, setting the Build Action to Content and setting the Copy to Output Directory to Copy always.

I also need to check the Prefer 32-bit checkbox and define the DESKTOP compilation symbol for All Configurations.

image

I’ll add the following XAML markup to the MainWindow.xaml

<Window x:Class="RealEstateInspector.Desktop.MainWindow"
        xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.Resources>
            <DataTemplate
                x:Key="PropertyItemTemplate">
                <TextBlock
                    Text="{Binding Address}"
                    FontSize="30"
                    Foreground="WhiteSmoke" />
            </DataTemplate>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition
                Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Button
            Content="Authenticate"
            Click="AuthenticateClick" />
        <ListView
            ItemTemplate="{StaticResource PropertyItemTemplate}"
            Grid.Row="1"
            ItemsSource="{Binding Properties}" />
    </Grid>
</Window>

And the following code to the MainWindow.xaml.cs

public partial class MainWindow : IWin32Window
{
    public IntPtr Handle
    {
        get
        {
            var interopHelper = new WindowInteropHelper(this);
            return interopHelper.Handle;
        }
    }
    public MainWindow()
    {
        InitializeComponent();

        Loaded += MainWindow_Loaded;
    }
    public MainViewModel CurrentViewModel
    {
        get { return DataContext as MainViewModel; }
    }
    void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        var vm = new MainViewModel();
        DataContext = vm;
    }

    private async void AuthenticateClick(object sender, RoutedEventArgs e)
    {
        var token = await AuthenticationHelper.Authenticate(Handle);
        await CurrentViewModel.LoadPropertyData(token);
    }
}

I also had to make some minor changes to the AuthenticationHelper

public static class AuthenticationHelper
{

    public static async Task<string> Authenticate(
#if DROID
    Android.App.Activity callerActivity
#elif DESKTOP
IntPtr callerHandle
#endif
        )
    {
        try
        {
            var authContext = new AuthenticationContext(Constants.ADAuthority);
#if !SILVERLIGHT
            if (authContext.TokenCache.ReadItems().Count() > 0)
                authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);
#endif
            var authResult =
                await
                    authContext.AcquireTokenAsync(Constants.MobileServiceAppIdUri,
                    Constants.ADNativeClientApplicationClientId,
                    new Uri(Constants.ADRedirectUri),
#if WINDOWS_PHONE_APP || SILVERLIGHT
                    new AuthorizationParameters()
#elif DROID
                    new AuthorizationParameters(callerActivity)
#elif DESKTOP
                        new AuthorizationParameters(PromptBehavior.Auto, callerHandle)
#else
                        new AuthorizationParameters(PromptBehavior.Auto, false)
#endif
                    );
            Debug.WriteLine(authResult != null);

            return authResult.AccessToken;

        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
            return null;
        }
    }
}

And that’s it, the WPF desktop application can be run up, the user can sign in and properties are synchronized before being displayed.

Adding Azure Active Directory Authentication to Android Xamarin.Forms Project

In my previous post I covered adding authentication to the Xamarin Forms Windows Phone 8.0 project. Next step, add it to the Android project. I figured this would be much simpler. However after adding a reference to ADAL from NuGet my Android project failed to build with some esoteric error about some missing layout xml in a referenced component. A quick internet search later I figured it might be due to the path lengths of my projects. I’d been relatively descriptive in my project names (eg RealEstateInspector.XForms.Droid) which had resulted in some very long paths, particularly during the build process where components are added based on the compilation path, the referenced library path and of course the file name. The upshot was that I needed to shorten not the project names, just the physical paths of the projects (easily done via VSO and Source Control Explorer within VS).

After doing the path restructure, I then amended the login the MainActivity:

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

    global::Xamarin.Forms.Forms.Init(this, bundle);
    RealEstateInspector.XForms.MainPage.AuthenticateRequested += Authenticate;
    LoadApplication(new App());
}

public async void Authenticate(object sender, EventArgs e)
{
    var page = sender as RealEstateInspector.XForms.MainPage;
    var token = await AuthenticationHelper.Authenticate(this);
    Debug.WriteLine(token);
    (page.BindingContext as MainViewModel).LoadPropertyData(token);
}

You’ll notice that the activity is passed into the Authenticate method, which means I’ve had to make some minor changes to the AuthenticationHelper code:

public static async Task<string> Authenticate(
#if DROID
    Activity callerActivity
#endif
    )
{
    try
    {
        var authContext = new AuthenticationContext(Constants.ADAuthority);
#if !SILVERLIGHT
        if (authContext.TokenCache.ReadItems().Count() > 0)
            authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);
#endif
        var authResult =
            await
                authContext.AcquireTokenAsync(Constants.MobileServiceAppIdUri,
                Constants.ADNativeClientApplicationClientId,
                new Uri(Constants.ADRedirectUri),
#if WINDOWS_PHONE_APP || SILVERLIGHT
                new AuthorizationParameters()
#elif DROID
new AuthorizationParameters(callerActivity)
#else
                    new AuthorizationParameters(PromptBehavior.Auto, false)
#endif
                );
        Debug.WriteLine(authResult != null);

        return authResult.AccessToken;

    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.Message);
        return null;
    }
}

At this point I also ran into an issue using my dummy redirect uri of http://tba.com, which is actually a real website and has an alternative mobile site which they redirect to. The issue was that after the user had authenticated the web view would redirect to http://tba.com but would then be redirected to the mobile site. I switched to using http://builttoroam.com which I know doesn’t have a redirect. Don’t forget when doing this you also have to update the redirect uri in the Native application in Azure Active Directory.

Adding Azure Active Directory Authentication to Windows Phone 8.0 Application with Xamarin.Forms

In the previous post I covered addition authentication to the Windows platform applications but I explicitly excluded the Windows Phone 8.0 project that’s part of the XForms set of projects. This was because the ADAL doesn’t currently support Windows Phone 8.0. In this post we’ll add a custom implementation which will authenticate the user using a WebBrowser control within the Windows Phone 8.0 application. We’ll start by adding a reference to the Windows Phone 8.0 project to the Shared.Client project – this will cause build errors as there is no reference to ADAL so the classes which are referenced in this shared code don’t exist. I’ll make some small amendments using the SILVERLIGHT compilation attribute (note that this is only defined for the WP8.0 project):

using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
#if !SILVERLIGHT
using Microsoft.IdentityModel.Clients.ActiveDirectory;
#else
using RealEstateInspector.XForms.WinPhone;
#endif
using RealEstateInspector.Core;

namespace RealEstateInspector.Shared.Client
{
    public static class AuthenticationHelper
    {

        public static async Task<string> Authenticate()
        {
            try
            {
                var authContext = new AuthenticationContext(Constants.ADAuthority);
#if !SILVERLIGHT
                if (authContext.TokenCache.ReadItems().Count() > 0)
                    authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);
#endif

                var authResult =
                    await
                        authContext.AcquireTokenAsync(Constants.MobileServiceAppIdUri,
                        Constants.ADNativeClientApplicationClientId,
                        new Uri(Constants.ADRedirectUri),
#if WINDOWS_PHONE_APP || SILVERLIGHT
                        new AuthorizationParameters()
#else
                            new AuthorizationParameters(PromptBehavior.Auto, false)
#endif
                        );
                Debug.WriteLine(authResult != null);

                return authResult.AccessToken;

            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                return null;
            }
        }
    }
}

The next thing to do is to provide an implementation of the AuthenticationContext class and it’s associated classes. These are added to the Windows Phone 8.0 project:

public class AuthenticationResult
{
    [JsonProperty("access_token")]
    public string AccessToken { get; set; }
}

public class AuthorizationParameters
{
}

public class AuthenticationContext
{
    public string Authority { get; set; }
    public string Resource { get; set; }
    public string ClientId { get; set; }
    public Uri RedirectUri { get; set; }

    public AuthenticationContext(string authority)
    {
        Authority = authority;
    }

    public async Task<AuthenticationResult> AcquireTokenAsync(
        string resource,
        string clientId,
        Uri redirectUri,
        AuthorizationParameters parameters)
    {
        Resource = resource;
        ClientId = clientId;
        RedirectUri = redirectUri;
        var code = await Authenticate();

        var http = new HttpClient();

        var tokenUrl = string.Format("{0}/oauth2/token",Authority);
        var formData = new Dictionary<string, string>
        {
            {"grant_type","authorization_code"},
            {"client_id",ClientId},
            {"code",code},
            {"resource",Resource},
            {"redirect_uri",RedirectUri.OriginalString}
        };

        var content = new FormUrlEncodedContent(formData);
        var data = await http.PostAsync(new Uri(tokenUrl), content);
        var result = JsonConvert.DeserializeObject<AuthenticationResult>(await data.Content.ReadAsStringAsync());
        return result;
    }

    private ManualResetEvent authenticateWaiter = new ManualResetEvent(false);
    private string AccessToken { get; set; }
    public async Task<string> Authenticate()
    {
        authenticateWaiter.Reset();
        var authUrlTemplate =
            "{0}/oauth2/authorize?response_type=code&client_id={1}&redirect_uri={2}";
        var authUrl = string.Format(authUrlTemplate,
            Authority,
            ClientId,
            Uri.EscapeDataString(RedirectUri.OriginalString)
            );

        var page = (Application.Current.RootVisual as Frame).Content as Page;
        var firstChild = page.Content;
        if (!(firstChild is Grid))
        {
            page.Content = null;
            var gd = new Grid();
            gd.Children.Add(firstChild);
            page.Content = gd;
            firstChild = gd;
        }

        var mainGrid = firstChild as Grid;
        var browser = new WebBrowser
        {
            IsScriptEnabled = true
        };
        browser.Navigating += BrowserNavigating;
        Grid.SetRowSpan(browser, (mainGrid.RowDefinitions != null && mainGrid.RowDefinitions.Count > 0) ? mainGrid.RowDefinitions.Count : 1);
        Grid.SetColumnSpan(browser, (mainGrid.ColumnDefinitions != null && mainGrid.ColumnDefinitions.Count > 0) ? mainGrid.ColumnDefinitions.Count : 1);
        mainGrid.Children.Add(browser);
        browser.Navigate(new Uri(authUrl));

        await Task.Run(() => authenticateWaiter.WaitOne());
        return AccessToken;
    }

    private void BrowserNavigating(object sender, NavigatingEventArgs e)
    {
        if (e.Uri.OriginalString.ToLower().StartsWith(RedirectUri.OriginalString.ToLower()))
        {
            try
            {
                var query = e.Uri.OriginalString.Substring(e.Uri.OriginalString.IndexOf('?') + 1);
                var code = (from pair in query.Split('&')
                            let bits = pair.Split('=')
                            where bits.Length == 2
                                    && bits[0] == "code"
                            select bits[1]).FirstOrDefault();
                AccessToken = code;
            }
            catch (Exception ex)
            {
                AccessToken = null;
            }
            finally
            {
                authenticateWaiter.Set();
                var browser = sender as WebBrowser;
                browser.Navigating -= BrowserNavigating;
                (browser.Parent as Grid).Children.Remove(browser);
            }
        }
    }
}

Reading this code you’ll see that I’m manually inserting and removing a WebBrowser control into the current page of the WP8.0 application. This is then used to authenticate the user and return the

authorization code which is then used to make the POST to request the access token (basically following what I did in my previous post when I walked this through manually in the browser/Fiddler).

I’ve also updated the XAML in my XForms MainPage:

<Page
    x:Class="RealEstateInspector.MainPage"
    xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.Resources>
            <DataTemplate
                x:Key="PropertyItemTemplate">
                <TextBlock
                    Text="{Binding Address}"
                    FontSize="30"
                    Foreground="WhiteSmoke"/>
            </DataTemplate>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition />
        </Grid.RowDefinitions>
        <Button Content="Authenticate" Click="AuthenticateClick"/>
        <ListView
            ItemTemplate="{StaticResource PropertyItemTemplate}"
            Grid.Row="1"
            ItemsSource="{Binding Properties}"/>
    </Grid>
</Page>

As well as the code behind to handle the button click:

public static event EventHandler AuthenticateRequested;

public void AuthenticateClick(object sender, EventArgs e)
{
    if (AuthenticateRequested != null)
    {
        AuthenticateRequested(this, EventArgs.Empty);
    }
}

Lastly in the MainPage of my Windows Phone 8.0 application I’ve wired up a listener for the AuthenticateRequested event to make sure I can trigger the authentication process:

public MainPage()
{
    InitializeComponent();
    SupportedOrientations = SupportedPageOrientation.PortraitOrLandscape;

    global::Xamarin.Forms.Forms.Init();
    RealEstateInspector.XForms.MainPage.AuthenticateRequested += Authenticate;
    LoadApplication(new RealEstateInspector.XForms.App());
}

public async void Authenticate(object sender, EventArgs e)
{
    var page = sender as RealEstateInspector.XForms.MainPage;
    var token = await AuthenticationHelper.Authenticate();
    Debug.WriteLine(token);
    (page.BindingContext as MainViewModel).LoadPropertyData(token);
}

Authenticating With Azure Active Directory In Universal Windows Platform Applications

The AAD team are continuing to evolve the samples and NuGet packages that can be referenced when authenticating with Azure Active Directory. In this post I’m going to add authentication to the Windows platform applications using the Active Directory Authentication Library (package id: Microsoft.Indentity.Clients.ActiveDirectory) and the corresponding sample found on github (https://github.com/AzureADSamples/NativeClient-MultiTarget-DotNet). One limitation of the current ADAL is that it doesn’t support Windows Phone 8.0 – adding support for this platform is slightly harder than for universal applications as there is no WebAuthenticationBroker so doing authentication will have to be done via a hosted web browser control within the application.

The first step in adding authentication support across the applications is to a reference to the ADAL package. I’ve added it to the Windows and Windows Phone 8.1 projects, as well as the iOS and Android XForms applications. As the package doesn’t support WP8.0 it can’t be added to either the XForms portable class library, the Core portable class library, nor the Windows Phone 8.0 projects. At this stage we’ll exclude the Mobile Service project as we currently don’t need ADAL there.

Into the RealEstateInspector.Core portable class library I’m going to add a Constants class which contains the various values required when requesting the authorization code and access token using the ADAL.

public static class Constants
{
    public const string ADTenant = "realestateinspector.onmicrosoft.com";
    public const string ADAuthority="https://login.windows.net/" + ADTenant;

    public const string ADNativeClientApplicationClientId = "a5a10ee9-f871-4bde-997f-3f1c323fefa5";

    public const string ADRedirectUri = "http://tba.com";

    public const string MobileServiceAppIdUri= "https://realestateinspector.azure-mobile.net/login/aad";
}

Rather than having to duplicate the authentication code between each of the client projects I’m going to create another Shared project called RealEstateInspector.Shared.Client and add a class called AuthenticationHelper. I’ll add a reference to this project to all of the client projects, except the Windows Phone 8.0 project, since this is currently unsupported.

public static class AuthenticationHelper
{

    public static async Task<string> Authenticate()
    {
        try
        {
            var authContext = new AuthenticationContext(Constants.ADAuthority);
            if (authContext.TokenCache.ReadItems().Count() > 0)
                authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);
            var authResult =
                await
                    authContext.AcquireTokenAsync(Constants.MobileServiceAppIdUri,
                    Constants.ADNativeClientApplicationClientId,
                    new Uri(Constants.ADRedirectUri),
#if WINDOWS_PHONE_APP
                    new AuthorizationParameters()
#else
                        new AuthorizationParameters(PromptBehavior.Auto, false)
#endif
                    );
            Debug.WriteLine(authResult != null);

            return authResult.AccessToken;

        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
            return null;
        }
    }
}

In our Windows platform projects I need to update the AuthenticationClick methods as follows:

private async void AuthenticateClick(object sender, RoutedEventArgs e)
{
    var token = await AuthenticationHelper.Authenticate();
    await CurrentViewModel.LoadPropertyData(token);

}

And I’ve made a simple tweak to the LoadPropertyData method to accept the access token as a parameter.

The last thing to do is in the App.xaml.cs file to add an override to the OnActivated method. Note that this is required due to the differences in the WebAuthenticationBroker implementations between Windows and Windows Phone 8.1.

protected override void OnActivated(IActivatedEventArgs args)
{
    base.OnActivated(args);

#if WINDOWS_PHONE_APP
    if (args is IWebAuthenticationBrokerContinuationEventArgs)
    {
        WebAuthenticationBrokerContinuationHelper.SetWebAuthenticationBrokerContinuationEventArgs(args as IWebAuthenticationBrokerContinuationEventArgs);
    }
#endif

}

At this point whilst we’ve added references to ADAL to the client projects, the only applications that can be run and signed into are the Windows platform applications (Windows and Windows Phone 8.1).

Accessing Authentication Required Mobile Service

Previously I added security to my mobile service by Requiring Authentication on the Azure Mobile Service and in my previous post I showed how you can manually request an authorization and access token. In addition to exploring the id_token (which is the unassigned JWT) if you explore the access_token you can see that it has a claim pertaining to the Mobile Service

image

We’re going to use this value to authenticate against our Mobile Service, which will allow us to query the data. In my MainViewModel I’m going to adjust the code slightly to use this access token value – this is just to demonstrate how the access token is going to be used, of course in a real world application you’ll need to authenticate the user using a web browser in the application in order to retrieve the access_token, but more on that later. My LoadPropertyData method now looks like this (the access_token value has been shortened to make the code more readable but was copied directly from the response in fiddler:

public async Task LoadPropertyData()
{
    var access_token="eyJ0eXAiOiJKV1Qi---------TOF9eYN97Jey-r_oDq5anQ";
    var jobj = new JObject();
    jobj["access_token"] = access_token;
    var access = await MobileService.LoginAsync(MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory, jobj);
    Debug.WriteLine(access!=null);
    var data = new MobileServiceSQLiteStore("inspections.db");
    data.DefineTable<RealEstateProperty>();
    data.DefineTable<Inspection>();

    await MobileService.SyncContext.InitializeAsync(data, new MobileServiceSyncHandler());

    await MobileService.PullLatestAsync<RealEstateProperty>();
    await MobileService.PullLatestAsync<Inspection>();

    var props = await MobileService.GetSyncTable<RealEstateProperty>().ToListAsync();
    foreach (var prop in props)
    {
        Properties.Add(prop);
    }
}

This code can be run and will retrieve the properties in the Mobile Service, at least whilst the access_token remains valid

Manually Using Fiddler to Authenticate (Part II – Actual Walkthrough)

In this second part of Manually Using Fiddler to Authenticate I’ll use a combination of web browser and fiddler to request both an authorization code and then an access token for the Azure Active Directory I setup in an earlier post. This is going to follow the workflow covered in this MSDN document.

There are a couple of things I’ll need before I start:

- The tenant id of the AAD that I’m going to be signing into. This can be the actual id (eg e688d594-8643-4bdf-9e4c-0be8bcbc645f which you can see in the address bar when editing information via the Azure portal eg https://manage.windowsazure.com/@hutchinsonbuilders.com.au#Workspaces/ActiveDirectoryExtension/Directory/e688d594-8643-4bdf-9e4c-0be8bcbc645f) or the domain:

realestateinspector.onmicrosoft.com

- The Client Id of the application I setup for the native client (remember that I’m effectively simulating the workflow that my native clients will go through, so it makes sense to use that AAD application)

client_id=a5a10ee9-f871-4bde-997f-3f1c323fefa5

- The redirect uri that was defined in the AAD application for the native client. When we actually come to use this process in the native client we will of course have to determine the native clients redirect uri and add that to the AAD application but for the timebeing I’ll use the value I specified when setting up the AAD application:

redirect_uri=http//tba.com

NOTE: I need to make sure that I appropriately url encode any query string parameters (there are plenty of web based converters – I use this URL decoder/encoder), so in this case the redirect uri will need to be specified as follows:

redirect_uri=http%3A%2F%2Ftba.com

Putting this all together we can generate the url for requesting an authorization code https://login.windows.net/realestateinspector.onmicrosoft.com/oauth2/authorize?response_type=code&client_id=a5a10ee9-f871-4bde-997f-3f1c323fefa5&redirect_uri=http%3A%2F%2Ftba.com. Navigating to this url via a web browser will prompt the user to sign in using the standard aad sign in prompt

image

After signing in the user will be redirected to the redirect uri, in this case http://tba.com with the authorization code specified in the address eg http://www.tba.com/?code=AAABAAAAvPM1KaPlrEqdFSBzjqfTGKrfFcsSklul1Lrd_bv-lbWetE6ZyTlruH0Yy7bB6Zue1lg0hpJ_2h5dLxd8gweAItUT6Hgvh7dXcyKsTuYfW_gpo9kkiGHYzxo53ayrrBJqsVyPLkJ6SagQp7_8vyfvieYrGF2tTXy_bMPpA3HG63qe_D_Iqpie9AtSnXWT7ax2UlufFSHNiu4pqIPxz_yc_TXBAHNKjSCevVTbLc4Kg71pyf3galmjXwi72KxDRn4QSwmY9Gdmhllo3A1ywOVrfct0DtZhe3oxzIdVpi5TUhKmDxbsnk2kHo60H1_SnmMFoIY-H2GTWdEScF0kPEa7NztBTJ9RIvx3YBMSPL4tZCgWo6Ta-xfCfeo47LZmWr_k07f1N85S1dhfumeVsSORGJI3CtTnnQxDxbLCKhaQweIW08pl1198STbwpFokuOMjH20KXX2KdbXxoaw67wWMsoyQypVDhBFgDPcZqHPOVT1J8pj-G6ic_WR3JtQ_Ig1xIAA&session_state=d2b5f011-74db-4b0e-84eb-979250fdee97

The next step is to request an access token. Now remember that this access token should be one that has permissions to access the Mobile Service I setup. As such, when requesting the access token I need to specify the Mobile Service as the resource I want to have access to. Here are the attributes I need for the access token request.

grant_type=authorization_code
client_id=a5a10ee9-f871-4bde-997f-3f1c323fefa5                <—
same as previous request
code=AAABAAAAvPM1KaP-----------_WR3JtQ_Ig1xIAA      <—truncated for brevity 
resource=https://realestateinspector.azure-mobile.net/login/aad    <—
the Mobile Service APP ID URI specified in the AAD application setup for the Mobile Service
redirect_uri=http://tba.com     <—the same redirect uri used in the authorization code request

Putting this all together into a POST request that I can issue in Fiddler:

POST: https://login.windows.net/realestateinspector.onmicrosoft.com/oauth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&client_id=a5a10ee9-f871-4bde-997f-3f1c323fefa5&code=AAABAAAAvPM1KaPlrEqdFSBzjqfTGKrfFcsSklul1Lrd_bv-lbWetE6ZyTlruH0Yy7bB6Zue1lg0hpJ_2h5dLxd8gweAItUT6Hgvh7dXcyKsTuYfW_gpo9kkiGHYzxo53ayrrBJqsVyPLkJ6SagQp7_8vyfvieYrGF2tTXy_bMPpA3HG63qe_D_Iqpie9AtSnXWT7ax2UlufFSHNiu4pqIPxz_yc_TXBAHNKjSCevVTbLc4Kg71pyf3galmjXwi72KxDRn4QSwmY9Gdmhllo3A1ywOVrfct0DtZhe3oxzIdVpi5TUhKmDxbsnk2kHo60H1_SnmMFoIY-H2GTWdEScF0kPEa7NztBTJ9RIvx3YBMSPL4tZCgWo6Ta-xfCfeo47LZmWr_k07f1N85S1dhfumeVsSORGJI3CtTnnQxDxbLCKhaQweIW08pl1198STbwpFokuOMjH20KXX2KdbXxoaw67wWMsoyQypVDhBFgDPcZqHPOVT1J8pj-G6ic_WR3JtQ_Ig1xIAA&resource=https%3A%2F%2Frealestateinspector.azure-mobile.net%2Flogin%2Faad&redirect_uri=http%3A%2F%2Ftba.com

What I get back from this request is a JSON response

image

The response gives a number of return values which can be used for a variety of things, one of which is the unassigned JSON Web Token which you can explore using tools such as http://jwt.io/.

image

Manually Using Fiddler to Authenticate

One thing I would encourage anyone planning to use Azure Active Directory to authenticate users is to understand a bit more about the oauth 2.0 workflow. To this end I’m going to follow the instructions on the blog post, Using Fiddler to acquire a JWT ( JSON Web Token ) for use with the Graph API, to access content from the Azure Mobile Service. I’d also suggest reading this page which covers the Authorization Code Grant Flow

Requiring Authentication on the Azure Mobile Service

In the previous post I configured a Azure Active Directory and the Mobile Service with the appropriate application definitions. This in itself isn’t enough – you can prove this by making a request using Fiddler to the existing controllers eg  GET https://realestateinspector.azure-mobile.net/tables/realestateproperty (don’t forget you’ll need to specify the X-ZUMO-APPLICATION header). Mobile Services already require the use of the X-ZUMO-APPLICATION key to be specified on requests, but what we want to do is enforce a user-level authentication.Luckily it’s as simple as adding the AuthorizationLevel attribute to the controllers with the level set to AuthorizationLevel.User. In the following code I’ve applied the attribute to the base controller I created earlier.

public class RealEstatePropertyController : RealEstateBaseTableController<RealEstateProperty> { }

public class InspectionController : RealEstateBaseTableController<Inspection> { }

[AuthorizeLevel(AuthorizationLevel.User)]
public class RealEstateBaseTableController<TEntity> : TableController<TEntity>
    where TEntity : class, ITableData
{

When I publish this update and attempt to run the same Fiddler request I get a 401 unauthorized exception:

HTTP/1.1 401 Unauthorized
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 61
Content-Type: application/json; charset=utf-8
Expires: 0
Server: Microsoft-IIS/8.0
WWW-Authenticate: Basic realm="Service"
X-Powered-By: ASP.NET
Set-Cookie: ARRAffinity=0289d9a2e779a2431db31b4a154e84828a77f89dbbe1fe391d5fe9794f54f970;Path=/;Domain=realestateinspector.azure-mobile.net
Date: Wed, 14 Jan 2015 11:14:21 GMT

{"message":"Authorization has been denied for this request."}

Adding Azure Active Directory Authentication to Azure Mobile Service

In my post “Add Azure Active Directory Support to Azure Mobile Services-Enabled Windows Phone Apps” I go through how to setup Azure Mobile Service to work with Azure Active Directory. Firstly I’m going to create a separate directory for this application. From the toolbar at the bottom of the Azure management portal I select App Service –> Active Directory –> Directory –> Custom Create

image 

The Name of the Azure Active Directory (AAD) is a friendly name which you can use to identify the directory in the portal. The Domain Name has to be unique and will be the identifier, and default tenant, of the directory.

image

The next thing I’ll need is to create two Application entries within the AAD. You can think of applications as the glue that connects AAD to both the Mobile Service (the resource being protected) and the native client applications.

I’ll first create an application that will link AAD to the Mobile Service. From the Applications pane in the AAD, click Create, followed by the link to “Add an application my organisation is developing”.

image

Next I need to give the application a name (again this is for identification in the portal – as you’ll see the name I chose is quite long and gets truncated in some of the later views, so I’d suggest a shorter name), and select “Web Application and/or Web API” under the Type heading.

image 

On the next pane I’m prompted to enter a App Id and Reply Url. On a separate pane I’ll open up the Mobile Service and go to the Identity pane. At the bottom under the Windows Azure Active Directory section I’ll copy out the App Url (ie https://realestateinspector.azure-mobile.net/login/aad). This value should be set for both App Id and Reply Url. After completing the creation process for the application, copy the Client Id value from the Configure pane and switch back to the Identity pane of the Mobile Service. Enter the Client Id into the Client Id field under the Windows Azure Active Directory section. I also need to specify the allowed tenant, which in this case is the default tenant from the AAD I created earlier.

image

Next I’ll create an application that will connect our native client applications to AAD. This time I’ll select Native Client Application under the Type heading.

image

On the next pane I’m prompted for a redirect url. For the timebeing I’m going to enter a placeholder value (eg http://tba.com)– we’ll come back to this when I start writing the code in the native applications to authenticate with AAD.

Now that I have applications that represent both the Mobile Service and the native client applications, I need to establish a trust relationship between them. From the Configure pane of the application for the native clients, select Add Application from the “permissions to other applications” section. Select Other in the Show dropbox and click the tick button to invoke the search. Select the application for the Mobile Service (ie in this case the Real Estate Inspector Mobile Service) and click the tick button at the bottom of the dialog.

image

From the Delegated Permissions dropdown, check the box next to “Access Real Estate Inspector Mobile Service” and click Save from the lower toolbar of the pane.

image

This completes the configuration of AAD to work with Mobile Service and Native Client applications. In the coming posts we’ll leverage this configuration to authenticate the mobile applications.