Authentication with Azure AD

StevenEversStevenEvers USMember
edited August 2015 in Xamarin.Forms

I've got an internal Xamarin.Forms (PCL) app that needs to auth the user via Azure AD.

The preferred scenario is that we take the user's name/pass (so we can control the login experience) and request the auth token from AD with that, but at this point I'll take anything. Here is what I've tried, and why it doesn't work:

1: The preferred method, write a platform-specific DependencyService, passing name/password:

I have a service interface declared as such:

public interface IAuthenticationService
{
    Task<Tuple<bool, string>> Authenticate(string username, string password);
}

I use it like this:

public async Task<bool> Login(string username, string password)
{
    var authService = DependencyService.Get<IAuthenticationService> ();
    var authResult = await authService.Authenticate (username, password);

    Settings.AuthToken = authResult.Item2;
    return authResult.Item1;
}

In the iOS project, I have an implementation where Authenticate is implemented like this:

// Note: AdalInitializer.Initialize(); is called in the static constructor
public async Task<Tuple<bool, string>> Authenticate (string username, string password)
{
    try
    {
        var authContext = new AuthenticationContext(authority);
        var userCredential = new UserCredential(username, password);
        var authResult = await authContext.AcquireTokenAsync(
                resourceId, 
                clientId,
                userCredential);

        return authResult != null && authResult.AccessToken != null
                ? Tuple.Create(true, authResult.AccessToken)
                : Tuple.Create(false, string.Empty);
    }
    catch (AdalException adalex)
    {
        return Tuple.Create(false, string.Empty);
    }
    catch (Exception ex)
    {
        return Tuple.Create(false, string.Empty);
    }
}
  • In a .NET console app, this works.
  • In iOS, this will throw a FormatException (at MediaTypeHeaderValue.set_MediaType ...).
  • In Android, this will throw an AdalException (accessing_ws_metadata_exchange_failed). Note that there is no AdalInitializer in the Android PCL, but the code is otherwise identical.

2: Use a redirect/webview (ie. this: http://www.cloudidentity.com/blog/2015/07/22/using-adal-3-x-with-xamarin-forms/ )

On iOS, this works mostly as advertised, and we don't get any control over the login experience within the app. It redirects to the MS branded Azure AD login page (which then redirects to our on-prem ADFS login page after the user enters their login name, which is ugly, but there's nothing I can do about that).

On Android, however, this doesn't work.

The PageRenderer looks like this:

[assembly:ExportRenderer(typeof(LaunchView), typeof(LaunchViewRenderer))]
namespace MyApp.Droid
{
    public class LaunchViewRenderer : PageRenderer
    {
        private LaunchView page;

        protected override void OnElementChanged (ElementChangedEventArgs<Page> e)
        {
            base.OnElementChanged (e);

            this.page = e.NewElement as LaunchView;
            this.page.PlatformParameters = new PlatformParameters (this.Context as Activity);
        }
    }
}

The login process operates just as it does with the iOS project, but after successful login (or failure), the awaited call to AcquireTokenAsync(resourceId, clientId, redirectUri, PlatformParameters)... never returns. It feels as if ADAL isn't overriding OnActivityResult properly, so I never get the authResult back.

So I'm stuck. The solution I want, doesn't work, and the alternative isn't ideal, and only half-works.

Best Answer

Answers

  • cmw9706cmw9706 Member

    Does authenticating like this still work? I am trying to get my xamarin app to load and the android screen shows a sign in header but will not load the contents of a login screen?

Sign In or Register to comment.