It’s again preview time for ADAL .NET! I can’t believe we are already working on version 3 – this pace would have been unthinkable just few years back, and yet today it is barely enough to keep up with the new possibilities that the tech landscape offers.

Version 1 and 2 have been enjoying great adoption level. While I am happy to report that overall it would appear you guys are very happy with it, of course we still have significant margin for improvement. This first preview does not address all the fundamental areas we want to work on (hint, hint: expect breaking changes before we’ll get to GA) but does tackle one of the greatest hits in the feature requests: the ability to use ADAL with PCL technology, and in particular with Xamarin.
If you are not familiar with those, here there’s how to wrap your head around what we are aiming at here.

Say that you are working on a native application that makes use of some Microsoft API (Office 365 Exchange and/or SharePoint, Directory Graph, Azure management, etc) and/or any API protected by AD. Say that you want versions of your application for .NET desktop, iOS, Android, Windows Store and Windows Phone 8.1.
With ADAL .NET v3 you will be able to write (in C#) a single class library containing all the authentication code and API calls. Done that, you will simply reference that class library and the ADAL .NET v3 NuGet from all your platform specific projects. Bam. Now you’ll just need to code the UX for every project, as the authentication code will simply be reused across all platforms.

Is your mind blown yet? Mine still is! Every time I see the debugger hit the exact same breakpoint regardless of the platform I am working with, I find myself in a marveling stupor Smile

This post will give you a quick introduction to the new approach this preview pursues. I won’t go too deep into details, mostly because those are super early bits: you should expect rougher edges than you’ve experienced in our past previews, as we really want to have an opportunity to hear from you before we start chiseling. And now, without further ado…

The New Architecture

ADAL v3 maintains the usual primitives that (at least, that’s what you tell us Smile) you already know and love: AuthenticationContext, AcquireToken, AuthenticationResult. From the code perspective, ADAL v3 preview 1 will hold very few surprises.
What changed is how the library itself is factored. At this point the library contains the following:

  • ADAL.PCL – a portable class library containing all the domain specific logic pertaining to token acquisition. Here you’ll find the code that is capable of assembling and sending token requests to AD according to different parameters combinations, that can tell whether a refresh token is multi-resource or otherwise, that knows how to validate an authority, and so on.
  • ADAL.PCL.<Platform> – For each targeted platform (.NET 4.5+, windows store, windows store for phone, iOS, Android) ADAL v3 provides an assembly containing platform specific logic. What constitutes platforms specific logic? Mostly 3 things:
    • Activation logic. Think callbacks in Android, continuation in WinPhone, basic return logic in .NET and WinRT.
    • Authentication experience. Think the browser control that pops out when you get a token in a .NET console/WPF/winform app vs. the WebAuthenticationBroker in WIndows Store vs. the WebAuthenticationBroker for Windows Phone vs. the web views in iOS and Android.
    • Storage. Every platform has its way of saving stuff, which is relevant for ADAL given its need to stash tokens somewhere.

On each platform, the full ADAL set of features is an emerging property of the combination of ADAL.PCL and ADAL.PCL.<Platform>. Oversimplifying a bit, the experience goes as follows:

  1. Say that your project is a Xamarin classic API iOS one. You add a reference to the ADAL v3 NuGet from your project.  That adds in your references both ADAL.PCL (Microsoft.IdentityModel.Clients.ActiveDirectory) and ADAL.PCL.iOS (Microsoft.IdentityModel.Clients.ActiveDirectory.Platform). The only exception is if your project is itself a PCL, in which case you’ll only get ADAL.PCL.
  2. Code normally against the usual OM, which comes from ADAL.PCL.
  3. When you run your project, at runtime ADAL executes the token request logic and, once it gets to the point in which it needs to leverage a platform specific component, it injects the logic from the platform specific assembly to perform the task requested: pop out a browser surface, dispatch a message to the app with the results, and so on.

How this is even possible is, in my opinion, a thing of beauty. We have Afshin Sepehri to thank for this neat trick, and in fact for the entire architecture!
Here there’s how it works. You will notice that AcquireTokenAsync accepts a new parameter, of type IAuthorizationParameter. This parameter passes to ADAL a reference to the parent component that hosts the logic requesting a token. Every platform will pass a different type – on the base of that, ADAL can load the correct assembly and inject it as a dynamic dependency. Neat-o!

As I mentioned in the intro to the post, if you are targeting more than one platform at once you can carry this approach further: instead of calling ADAL APIs directly from the platform specific project, you can gather all of that in your own shared PCL that exposes only business logic that makes sense for your app and none of the token acquisition logic. Remember, you’ll still need to reference the ADAL NuGet from every platform specific project for the aforementioned trick to work – but this will be able to have a 100% shared component across all projects.

To make this more practical, let me refer to our new sample here.

The sample represents a super simply Directory Graph API client, which you can use for looking up a user by its email alias.

The solution follows the structure we discussed, one PCL and many platform-specific projects:

image

The PCL holds a reference to ADAL.PCL:

image

As it is a very simple scenario, the PCL exposes a single method:

// …
public static async Task<List<User>> SearchByAlias(string alias, IAuthorizationParameters parent) {
    AuthenticationResult authResult = null;
    JObject jResult = null;
    List<User> results = new List<User>();

    try
    {
        AuthenticationContext authContext = new AuthenticationContext(commonAuthority);
        if (authContext.TokenCache.ReadItems().Count() > 0)
            authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);
        authResult = await authContext.AcquireTokenAsync(graphResourceUri, clientId, returnUri, parent);
    }
// …

The code looks up the cache to see if there is already an entry, in which case we’ll use its tenant as authority, otherwise falls back to common. Apart from the parent parameter, it’s business as usual.

To see how this is used, let’s pick a random project: say the iOS one.

image

Here the references include our own PCL, references to both ADAL.PCL and ADAL.PCL.iOS, and the usual Xamarin stuff.

All the interesting logic is in DirSearchClient_iOSViewController:

public override void ViewDidLoad()
{
    base.ViewDidLoad();

    // Perform any additional setup after loading the view, typically from a nib.
    SearchButton.TouchUpInside += async (object sender, EventArgs e) =>
    {
        if (string.IsNullOrEmpty(SearchTermText.Text))
        {
            // UX stuff cut for clarity
        }

        List<User> results = await DirectorySearcher.SearchByAlias(SearchTermText.Text, new AuthorizationParameters(this));
        if (results.Count == 0) 
        {
            // ...more stuff

The interesting bit is the highlighted. That’s the only code you need to have in the iOS project to take advantage of the dir searcher features, you don’t even need to know that ADAL is in there! Smile

Running the projects in the solution is a pretty amazing experience: an incredible reach with so little code… and in my favorite language, c#!!!

image

In fact, there is something I find even more mind blowing. You can actually take the solution, copy it to a Mac, open it with Xamarni Studio, and you’ll be able to edit and debug the iOS and Android solutions directly from there! See screenshot on my Mac below. I am sure that if you worked a lot with Xamarin you might be blasé about this, but being still new to it… this is awesome Open-mouthed smile

Screen Shot 2014-10-25 at 1.01.57 AM

Caveats

Did I mention this is rougher than our usual previews? This is meant to unblock a very specific scenario, use of interactive authentication in multi-platform solutions, so that we can gather early feedback and course-correct as appropriate. Everything outside of that scenario might fail, expect NotImplemented to pop up often if you delve from that path. Important features like persistent cache or silent token auth are missing. The OM *WILL* change, hence if you write code against it now please know that the next preview will very likely break it.

We also have limitations on the target platforms : ADA can’t target Xamarin Forms or the new project types yet, it does not work yet with ASP.NET vNext, and so on. We’ll iterate and make things better, but you need to expect an interesting ride Smile

Also, very important: this does not change our existing strategy for native libraries. ADAL .NET v3 will extend the scope of what a .NET developer can do, but this does not change at all our commitment to support developers who work natively on iOS and Android with Objective-C and Java. In fact, parity is not even a goal here. All the libraries share our general approach (Open source, rapid iterations, etc) but that’s about it. If you are an Objective-C or a Java developer don’t worry, we still got you covered! Smile

Next

I hope you’re as excited as I am about this new development in ADAL-land. A good starting point is this sample. I am planning to show this at my TechEd EU session today, hence shortly we should also have a video. The more feedback you give us, the faster we’ll make progress… I can’t wait to read your comments Smile

Happy coding!

 

Leave a Reply

Your email address will not be published. Required fields are marked *