Skip to content

Commit

Permalink
Restructure application to show better use of .WithParentWindowOrActi… (
Browse files Browse the repository at this point in the history
#112)

* Restructure application to show better use of .WithParentWindowOrActivity(func)

* Fix iOS
  • Loading branch information
bgavrilMS authored Dec 17, 2019
1 parent 7709541 commit d1514e8
Show file tree
Hide file tree
Showing 11 changed files with 6,902 additions and 4,781 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,55 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace UserDetailsClient.Core.Features.LogOn
{
public class B2CAuthenticationService : IAuthenticationService
/// <summary>
/// For simplicity, we'll have this as a singleton.
/// </summary>
public class B2CAuthenticationService
{
public IPublicClientApplication PCA = null;
private readonly IPublicClientApplication _pca;

public object ParentActivityOrWindow { get; set; }

public B2CAuthenticationService()
private static readonly Lazy<B2CAuthenticationService> lazy = new Lazy<B2CAuthenticationService>
(() => new B2CAuthenticationService());

public static B2CAuthenticationService Instance { get { return lazy.Value; } }


private B2CAuthenticationService()
{

// default redirectURI; each platform specific project will have to override it with its own
PCA = PublicClientApplicationBuilder.Create(B2CConstants.ClientID)
var builder = PublicClientApplicationBuilder.Create(B2CConstants.ClientID)
.WithB2CAuthority(B2CConstants.AuthoritySignInSignUp)
.WithIosKeychainSecurityGroup(B2CConstants.IOSKeyChainGroup)
.WithRedirectUri($"msal{B2CConstants.ClientID}://auth")
.Build();
.WithRedirectUri($"msal{B2CConstants.ClientID}://auth");

// Android implementation is based on https://github.com/jamesmontemagno/CurrentActivityPlugin
// iOS implementation would require to expose the current ViewControler - not currently implemented as it is not required
// UWP does not require this
var windowLocatorService = DependencyService.Get<IParentWindowLocatorService>();

if (windowLocatorService != null)
{
builder = builder.WithParentActivityOrWindow(() => windowLocatorService?.GetCurrentParentWindow());
}

_pca = builder.Build();
}

public async Task<UserContext> SignInAsync()
{
UserContext newContext = null;
UserContext newContext;
try
{
// acquire token silent
newContext = await AcquireToken();
}
catch (MsalUiRequiredException ex)
catch (MsalUiRequiredException)
{
// acquire token interactive
newContext = await SignInInteractively();
Expand All @@ -42,8 +63,8 @@ public async Task<UserContext> SignInAsync()

private async Task<UserContext> AcquireToken()
{
IEnumerable<IAccount> accounts = await PCA.GetAccountsAsync();
AuthenticationResult authResult = await PCA.AcquireTokenSilent(B2CConstants.Scopes, GetAccountByPolicy(accounts, B2CConstants.PolicySignUpSignIn))
IEnumerable<IAccount> accounts = await _pca.GetAccountsAsync();
AuthenticationResult authResult = await _pca.AcquireTokenSilent(B2CConstants.Scopes, GetAccountByPolicy(accounts, B2CConstants.PolicySignUpSignIn))
.WithB2CAuthority(B2CConstants.AuthoritySignInSignUp)
.ExecuteAsync();

Expand All @@ -53,10 +74,9 @@ private async Task<UserContext> AcquireToken()

public async Task<UserContext> ResetPasswordAsync()
{
AuthenticationResult authResult = await PCA.AcquireTokenInteractive(B2CConstants.Scopes)
AuthenticationResult authResult = await _pca.AcquireTokenInteractive(B2CConstants.Scopes)
.WithPrompt(Prompt.NoPrompt)
.WithAuthority(B2CConstants.AuthorityPasswordReset)
.WithParentActivityOrWindow(ParentActivityOrWindow)
.ExecuteAsync();

var userContext = UpdateUserInfo(authResult);
Expand All @@ -66,13 +86,12 @@ public async Task<UserContext> ResetPasswordAsync()

public async Task<UserContext> EditProfileAsync()
{
IEnumerable<IAccount> accounts = await PCA.GetAccountsAsync();
IEnumerable<IAccount> accounts = await _pca.GetAccountsAsync();

AuthenticationResult authResult = await PCA.AcquireTokenInteractive(B2CConstants.Scopes)
AuthenticationResult authResult = await _pca.AcquireTokenInteractive(B2CConstants.Scopes)
.WithAccount(GetAccountByPolicy(accounts, B2CConstants.PolicyEditProfile))
.WithPrompt(Prompt.NoPrompt)
.WithAuthority(B2CConstants.AuthorityEditProfile)
.WithParentActivityOrWindow(ParentActivityOrWindow)
.ExecuteAsync();

var userContext = UpdateUserInfo(authResult);
Expand All @@ -82,11 +101,10 @@ public async Task<UserContext> EditProfileAsync()

private async Task<UserContext> SignInInteractively()
{
IEnumerable<IAccount> accounts = await PCA.GetAccountsAsync();
IEnumerable<IAccount> accounts = await _pca.GetAccountsAsync();

AuthenticationResult authResult = await PCA.AcquireTokenInteractive(B2CConstants.Scopes)
AuthenticationResult authResult = await _pca.AcquireTokenInteractive(B2CConstants.Scopes)
.WithAccount(GetAccountByPolicy(accounts, B2CConstants.PolicySignUpSignIn))
.WithParentActivityOrWindow(ParentActivityOrWindow)
.ExecuteAsync();

var newContext = UpdateUserInfo(authResult);
Expand All @@ -96,11 +114,11 @@ private async Task<UserContext> SignInInteractively()
public async Task<UserContext> SignOutAsync()
{

IEnumerable<IAccount> accounts = await PCA.GetAccountsAsync();
IEnumerable<IAccount> accounts = await _pca.GetAccountsAsync();
while (accounts.Any())
{
await PCA.RemoveAsync(accounts.FirstOrDefault());
accounts = await PCA.GetAccountsAsync();
await _pca.RemoveAsync(accounts.FirstOrDefault());
accounts = await _pca.GetAccountsAsync();
}
var signedOutContext = new UserContext();
signedOutContext.IsLoggedOn = false;
Expand Down Expand Up @@ -165,10 +183,5 @@ JObject ParseIdToken(string idToken)
idToken = Base64UrlDecode(idToken);
return JObject.Parse(idToken);
}

public void SetParent(object parent)
{
ParentActivityOrWindow = parent;
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace UserDetailsClient.Core.Features.LogOn
{
/// <summary>
/// Simple platform specific service that is responsible for locating a
/// </summary>
public interface IParentWindowLocatorService
{
object GetCurrentParentWindow();
}
}
30 changes: 10 additions & 20 deletions UserDetailsClient/UserDetailsClient.Core/MainPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,9 @@ namespace UserDetailsClient.Core
{
public partial class MainPage : ContentPage
{
protected readonly IAuthenticationService authenticationService;

public MainPage()
{
InitializeComponent();

/* Grab an instance of the IAuthenticationService using DependencyService.
*
* NOTE: this will give us an instance of B2CAuthenticationService
* because we registered that class in App.xaml.cs
*
* */
authenticationService = DependencyService.Get<IAuthenticationService>();
}

async void OnSignInSignOut(object sender, EventArgs e)
Expand All @@ -29,13 +19,13 @@ async void OnSignInSignOut(object sender, EventArgs e)
{
if (btnSignInSignOut.Text == "Sign in")
{
var userContext = await authenticationService.SignInAsync();
var userContext = await B2CAuthenticationService.Instance.SignInAsync();
UpdateSignInState(userContext);
UpdateUserInfo(userContext);
}
else
{
var userContext = await authenticationService.SignOutAsync();
var userContext = await B2CAuthenticationService.Instance.SignOutAsync();
UpdateSignInState(userContext);
UpdateUserInfo(userContext);
}
Expand All @@ -47,7 +37,7 @@ async void OnSignInSignOut(object sender, EventArgs e)
// reset and not any other error.
if (ex.Message.Contains("AADB2C90118"))
OnPasswordReset();
// Alert if any exception excluding user cancelling sign-in dialog
// Alert if any exception excluding user canceling sign-in dialog
else if (((ex as MsalException)?.ErrorCode != "authentication_canceled"))
await DisplayAlert($"Exception:", ex.ToString(), "Dismiss");
}
Expand All @@ -57,7 +47,7 @@ async void OnCallApi(object sender, EventArgs e)
try
{
lblApi.Text = $"Calling API {App.ApiEndpoint}";
var userContext = await authenticationService.SignInAsync();
var userContext = await B2CAuthenticationService.Instance.SignInAsync();
var token = userContext.AccessToken;

// Get data from API
Expand Down Expand Up @@ -89,13 +79,13 @@ async void OnEditProfile(object sender, EventArgs e)
{
try
{
var userContext = await authenticationService.EditProfileAsync();
var userContext = await B2CAuthenticationService.Instance.EditProfileAsync();
UpdateSignInState(userContext);
UpdateUserInfo(userContext);
}
catch (Exception ex)
{
// Alert if any exception excludig user cancelling sign-in dialog
// Alert if any exception excluding user canceling sign-in dialog
if (((ex as MsalException)?.ErrorCode != "authentication_canceled"))
await DisplayAlert($"Exception:", ex.ToString(), "Dismiss");
}
Expand All @@ -104,13 +94,13 @@ async void OnResetPassword(object sender, EventArgs e)
{
try
{
var userContext = await authenticationService.ResetPasswordAsync();
var userContext = await B2CAuthenticationService.Instance.ResetPasswordAsync();
UpdateSignInState(userContext);
UpdateUserInfo(userContext);
}
catch (Exception ex)
{
// Alert if any exception excludig user cancelling sign-in dialog
// Alert if any exception excluding user canceling sign-in dialog
if (((ex as MsalException)?.ErrorCode != "authentication_canceled"))
await DisplayAlert($"Exception:", ex.ToString(), "Dismiss");
}
Expand All @@ -119,13 +109,13 @@ async void OnPasswordReset()
{
try
{
var userContext = await authenticationService.ResetPasswordAsync();
var userContext = await B2CAuthenticationService.Instance.ResetPasswordAsync();
UpdateSignInState(userContext);
UpdateUserInfo(userContext);
}
catch (Exception ex)
{
// Alert if any exception excludig user cancelling sign-in dialog
// Alert if any exception excluding user canceling sign-in dialog
if (((ex as MsalException)?.ErrorCode != "authentication_canceled"))
await DisplayAlert($"Exception:", ex.ToString(), "Dismiss");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Compile Remove="Framework\**" />
<EmbeddedResource Remove="Framework\**" />
<None Remove="Framework\**" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="System.Net.Http" Version="4.3.3" />
<PackageReference Include="Xamarin.Forms" Version="3.0.0.530893" />
<PackageReference Include="Microsoft.Identity.Client" Version="4.6.0" />
</ItemGroup>

<ItemGroup>
<Folder Include="Framework\" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Microsoft.Identity.Client;
using Plugin.CurrentActivity;
using UserDetailsClient.Core.Features.LogOn;

namespace UserDetailsClient.Droid
{
class AndroidParentWindowLocatorService : IParentWindowLocatorService
{
public object GetCurrentParentWindow()
{
return CrossCurrentActivity.Current.Activity;
}
}
}
10 changes: 5 additions & 5 deletions UserDetailsClient/UserDetailsClient.Droid/MainActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using UserDetailsClient.Core;
using Xamarin.Forms;
using UserDetailsClient.Core.Features.LogOn;
using Plugin.CurrentActivity;

namespace UserDetailsClient.Droid
{
Expand All @@ -15,18 +16,17 @@ public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompa
{
protected override void OnCreate(Bundle bundle)
{
CrossCurrentActivity.Current.Init(this, bundle);
DependencyService.Register<IParentWindowLocatorService, AndroidParentWindowLocatorService>();

TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;

base.OnCreate(bundle);

global::Xamarin.Forms.Forms.Init(this, bundle);
Forms.Init(this, bundle);

LoadApplication(new App());

var authenticationService = DependencyService.Get<IAuthenticationService>();
// Default system browser
authenticationService.SetParent(this);
}

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
Expand Down
Loading

0 comments on commit d1514e8

Please sign in to comment.