From 94515106d1ec802c081b1217c3239176138748a9 Mon Sep 17 00:00:00 2001 From: Arthur Thomas Date: Sat, 27 Jul 2024 12:57:52 -0400 Subject: [PATCH] fix: user from seeing that they are signed in when they are signed out --- KeyVaultExplorer/Services/AuthService.cs | 29 +++- .../CreateNewSecretVersionViewModel.cs | 8 -- .../ViewModels/KeyVaultTreeListViewModel.cs | 4 +- KeyVaultExplorer/ViewModels/MainViewModel.cs | 29 ++-- .../ViewModels/SettingsPageViewModel.cs | 28 +--- .../CustomControls/KeyVaultTreeList.axaml.cs | 9 +- KeyVaultExplorer/Views/MainPage.axaml | 7 +- KeyVaultExplorer/Views/MainView.axaml.cs | 128 +++++++++--------- KeyVaultExplorer/Views/MainWindow.axaml | 2 +- .../Views/Pages/SettingsPage.axaml | 4 +- .../Views/Pages/SettingsPage.axaml.cs | 35 +++-- 11 files changed, 142 insertions(+), 141 deletions(-) diff --git a/KeyVaultExplorer/Services/AuthService.cs b/KeyVaultExplorer/Services/AuthService.cs index 4b528044..84411e7c 100644 --- a/KeyVaultExplorer/Services/AuthService.cs +++ b/KeyVaultExplorer/Services/AuthService.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; using System.Linq; +using System.Security.Principal; using System.Threading; using System.Threading.Tasks; @@ -17,6 +18,8 @@ public class AuthService // Providing the RedirectionUri to receive the token based on success or failure. public bool IsAuthenticated { get; private set; } = false; + public AuthenticatedUserClaims AuthenticatedUserClaims { get; private set; } + public string TenantName { get; private set; } public IAccount Account { get; private set; } @@ -34,7 +37,7 @@ public AuthService() public async Task LoginAsync(CancellationToken cancellationToken) { await AttachTokenCache(); - AuthenticationResult result; + AuthenticationResult authenticationResult; try { var options = new SystemWebViewOptions() @@ -47,7 +50,7 @@ public async Task LoginAsync(CancellationToken cancellatio //.WithUseEmbeddedWebView(false) //.WithSystemWebViewOptions(options) //#endif - result = await authenticationClient.AcquireTokenInteractive(Constants.Scopes) + authenticationResult = await authenticationClient.AcquireTokenInteractive(Constants.Scopes) //.WithExtraScopesToConsent(Constants.AzureRMScope) /* * Not including extra scopes allows personal accounts to sign in, however, this will be thrown. @@ -60,11 +63,19 @@ public async Task LoginAsync(CancellationToken cancellatio .ExecuteAsync(cancellationToken); IsAuthenticated = true; - TenantName = result.Account.Username.Split("@").TakeLast(1).Single(); + TenantName = authenticationResult.Account.Username.Split("@").TakeLast(1).Single(); + AuthenticatedUserClaims = new AuthenticatedUserClaims() + { + Username = authenticationResult.Account.Username, + TenantId = authenticationResult.TenantId, + Name = authenticationResult.ClaimsPrincipal.Identities.First().FindFirst("name").Value, + Email = authenticationResult.ClaimsPrincipal.Identities.First().FindFirst("preferred_username").Value + }; + // set the preferences/settings of the signed in account //IAccount cachedUserAccount = Task.Run(async () => await PublicClientSingleton.Instance.MSALClientHelper.FetchSignedInUserFromCache()).Result; //Preferences.Default.Set("auth_account_id", JsonSerializer.Serialize(result.UniqueId)); - return result; + return authenticationResult; } catch (MsalClientException ex) { @@ -90,6 +101,14 @@ public async Task RefreshTokenAsync(CancellationToken canc authenticationResult = await authenticationClient.AcquireTokenSilent(Constants.Scopes, accounts.FirstOrDefault()).WithForceRefresh(true).ExecuteAsync(); IsAuthenticated = true; TenantName = Account.Username.Split("@").TakeLast(1).Single(); + AuthenticatedUserClaims = new AuthenticatedUserClaims() + { + Username = authenticationResult.Account.Username, + TenantId = authenticationResult.TenantId, + Name = authenticationResult.ClaimsPrincipal.Identities.First().FindFirst("name").Value, + Email = authenticationResult.ClaimsPrincipal.Identities.First().FindFirst("preferred_username").Value + }; + return authenticationResult; } @@ -122,6 +141,8 @@ public async Task RemoveAccount() await AttachTokenCache(); var accounts = await authenticationClient.GetAccountsAsync(); Account = null; + IsAuthenticated = false; + AuthenticatedUserClaims = null; await authenticationClient.RemoveAsync(accounts.FirstOrDefault()); } diff --git a/KeyVaultExplorer/ViewModels/CreateNewSecretVersionViewModel.cs b/KeyVaultExplorer/ViewModels/CreateNewSecretVersionViewModel.cs index 1ac03407..a91c9a19 100644 --- a/KeyVaultExplorer/ViewModels/CreateNewSecretVersionViewModel.cs +++ b/KeyVaultExplorer/ViewModels/CreateNewSecretVersionViewModel.cs @@ -83,14 +83,6 @@ public CreateNewSecretVersionViewModel() _authService = Defaults.Locator.GetRequiredService(); _vaultService = Defaults.Locator.GetRequiredService(); _notificationViewModel = Defaults.Locator.GetRequiredService(); - if (Subscriptions is null || Subscriptions.Count == 0) - { - Dispatcher.UIThread.InvokeAsync(async () => - { - Subscriptions = await GetAvailableSubscriptions(); - }, DispatcherPriority.Input); - } - } public bool HasActivationDate => KeyVaultSecretModel is not null && KeyVaultSecretModel.NotBefore.HasValue; diff --git a/KeyVaultExplorer/ViewModels/KeyVaultTreeListViewModel.cs b/KeyVaultExplorer/ViewModels/KeyVaultTreeListViewModel.cs index 22253526..f30b7913 100644 --- a/KeyVaultExplorer/ViewModels/KeyVaultTreeListViewModel.cs +++ b/KeyVaultExplorer/ViewModels/KeyVaultTreeListViewModel.cs @@ -1,4 +1,6 @@ -using Avalonia.Threading; +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Threading; using Azure.Core; using Azure.ResourceManager; using Azure.ResourceManager.KeyVault; diff --git a/KeyVaultExplorer/ViewModels/MainViewModel.cs b/KeyVaultExplorer/ViewModels/MainViewModel.cs index 9752ac04..35b20639 100644 --- a/KeyVaultExplorer/ViewModels/MainViewModel.cs +++ b/KeyVaultExplorer/ViewModels/MainViewModel.cs @@ -15,9 +15,6 @@ namespace KeyVaultExplorer.ViewModels; public partial class MainViewModel : ViewModelBase { - [ObservableProperty] - private string email; - [ObservableProperty] private AuthenticatedUserClaims authenticatedUserClaims; @@ -28,13 +25,18 @@ public partial class MainViewModel : ViewModelBase public NavigationFactory NavigationFactory { get; } + + partial void OnIsAuthenticatedChanged(bool value) + { + AuthenticatedUserClaims = _authService.AuthenticatedUserClaims; + } + public MainViewModel() { _authService = Defaults.Locator.GetRequiredService(); NavigationFactory = new NavigationFactory(); } - public async Task RefreshTokenAndGetAccountInformation() { var cancellation = new CancellationToken(); @@ -46,35 +48,26 @@ public async Task RefreshTokenAndGetAccountInformation() var identity = account.ClaimsPrincipal.Identities.First(); var email = identity.FindAll("preferred_username").First().Value ?? account.Account.Username; - Email = email.ToLowerInvariant(); - - AuthenticatedUserClaims = new AuthenticatedUserClaims() - { - Username = account.Account.Username, - TenantId = account.TenantId, - Name = account.ClaimsPrincipal.Identities.First().FindFirst("name").Value, - Email = account.ClaimsPrincipal.Identities.First().FindFirst("preferred_username").Value, - }; + AuthenticatedUserClaims = _authService.AuthenticatedUserClaims; IsAuthenticated = _authService.IsAuthenticated; } - - - [RelayCommand] + [RelayCommand] private async Task ForceSignIn() { var cancellation = new CancellationToken(); var account = await _authService.LoginAsync(cancellation); - Email = account.ClaimsPrincipal.Identities.First().FindFirst("preferred_username").Value; + AuthenticatedUserClaims = _authService.AuthenticatedUserClaims; + IsAuthenticated = _authService.IsAuthenticated; } [RelayCommand] private async Task SignOut() { await _authService.RemoveAccount(); + AuthenticatedUserClaims = null; } - } public class NavigationFactory : INavigationPageFactory diff --git a/KeyVaultExplorer/ViewModels/SettingsPageViewModel.cs b/KeyVaultExplorer/ViewModels/SettingsPageViewModel.cs index d81b5f9f..a469e7c5 100644 --- a/KeyVaultExplorer/ViewModels/SettingsPageViewModel.cs +++ b/KeyVaultExplorer/ViewModels/SettingsPageViewModel.cs @@ -133,21 +133,14 @@ private async Task SignInOrRefreshTokenAsync() if (account is null) account = await _authService.LoginAsync(cancellation); - - AuthenticatedUserClaims = new AuthenticatedUserClaims() - { - Username = account.Account.Username, - TenantId = account.TenantId, - Name = account.ClaimsPrincipal.Identities.First().FindFirst("name").Value, - Email = account.ClaimsPrincipal.Identities.First().FindFirst("{preferred_username")?.Value, - }; + AuthenticatedUserClaims = _authService.AuthenticatedUserClaims; } [RelayCommand] private async Task SignOut() { await _authService.RemoveAccount(); - AuthenticatedUserClaims = null; + AuthenticatedUserClaims = _authService.AuthenticatedUserClaims; } [RelayCommand] @@ -156,20 +149,5 @@ private void OpenIssueGithub() Process.Start(new ProcessStartInfo("https://github.com/cricketthomas/KeyVaultExplorer/issues/new") { UseShellExecute = true, Verb = "open" }); } - // TODO: Create method of changing the background color from transparent to non stranparent - //[RelayCommand] - //private async Task SetNavigationLayout() - //{ - // await AddOrUpdateAppSettings(nameof(NavigationLayoutMode), NavigationLayoutMode); - //} - //private async Task LoadApplicationVersion() - //{ - // //string buildDirProps = Environment.GetEnvironmentVariable("EnvironmentName"); - // //string _version = await File.ReadAllTextAsync(".\\VERSION.txt"); - // //if (!System.Version.TryParse(_version, out Version fullVersion)) - // //{ - // // Version = "Missing version file" + buildDirProps; - // // return; - // //} - // //Version = $"{fullVersion.Major}.{fullVersion.Minor}.{fullVersion.Build}.{fullVersion.Revision}-{buildDirProps}"; + } \ No newline at end of file diff --git a/KeyVaultExplorer/Views/CustomControls/KeyVaultTreeList.axaml.cs b/KeyVaultExplorer/Views/CustomControls/KeyVaultTreeList.axaml.cs index ba9b88c7..979cd367 100644 --- a/KeyVaultExplorer/Views/CustomControls/KeyVaultTreeList.axaml.cs +++ b/KeyVaultExplorer/Views/CustomControls/KeyVaultTreeList.axaml.cs @@ -84,8 +84,15 @@ private void RefreshKeyVaultList(object sender, RoutedEventArgs e) { Dispatcher.UIThread.Post(async () => { - await (DataContext as KeyVaultTreeListViewModel)!.GetAvailableKeyVaultsCommand.ExecuteAsync(true); + await (DataContext as KeyVaultTreeListViewModel)!.GetAvailableKeyVaultsCommand.ExecuteAsync(true).ContinueWith((t) => + { + ((Control)sender)!.RaiseEvent(new RoutedEventArgs(MainView.SignInRoutedEvent)); + + }); }, DispatcherPriority.Input); + + + } private void OnDoubleClicked(object sender, TappedEventArgs args) diff --git a/KeyVaultExplorer/Views/MainPage.axaml b/KeyVaultExplorer/Views/MainPage.axaml index 5e9fce79..98942271 100644 --- a/KeyVaultExplorer/Views/MainPage.axaml +++ b/KeyVaultExplorer/Views/MainPage.axaml @@ -4,6 +4,7 @@ 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" + xmlns:models="clr-namespace:KeyVaultExplorer.Models;assembly=KeyVaultExplorer" xmlns:pages="clr-namespace:KeyVaultExplorer.Views.Pages" xmlns:ui="using:FluentAvalonia.UI.Controls" xmlns:vm="clr-namespace:KeyVaultExplorer.ViewModels" @@ -43,12 +44,12 @@ Background="{x:Null}" FontSize="{StaticResource FontSizeSmall}" Text="You are currently signed out." /> - + TextDecorations="Underline" />--> @@ -68,7 +69,7 @@ Margin="5,0" Background="{x:Null}" FontSize="{StaticResource FontSizeSmall}" - Text="{Binding Email}" /> + Text="{Binding AuthenticatedUserClaims.Email}" /> diff --git a/KeyVaultExplorer/Views/MainView.axaml.cs b/KeyVaultExplorer/Views/MainView.axaml.cs index d79d7e0f..e5260e51 100644 --- a/KeyVaultExplorer/Views/MainView.axaml.cs +++ b/KeyVaultExplorer/Views/MainView.axaml.cs @@ -9,10 +9,13 @@ using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Media.Animation; using FluentAvalonia.UI.Navigation; +using KeyVaultExplorer.Models; +using KeyVaultExplorer.Services; using KeyVaultExplorer.ViewModels; using KeyVaultExplorer.Views.Pages; using System; using System.Diagnostics; +using System.Linq; #nullable disable @@ -20,15 +23,15 @@ namespace KeyVaultExplorer.Views; public partial class MainView : UserControl { - public static MainView? Instance { get; private set; } public static readonly RoutedEvent NavigateHomeEvent = RoutedEvent.Register(nameof(NavigateHomeEvent), RoutingStrategies.Tunnel); public static readonly RoutedEvent NavigateSettingsEvent = RoutedEvent.Register(nameof(NavigateSettingsEvent), RoutingStrategies.Tunnel); public static readonly RoutedEvent NavigateSubscriptionsEvent = RoutedEvent.Register(nameof(NavigateSubscriptionsEvent), RoutingStrategies.Tunnel); + public static readonly RoutedEvent SignInRoutedEvent = RoutedEvent.Register(nameof(SignInRoutedEvent), RoutingStrategies.Tunnel); public static readonly RoutedEvent SignOutRoutedEvent = RoutedEvent.Register(nameof(SignOutRoutedEvent), RoutingStrategies.Tunnel); - private readonly KeyVaultTreeListViewModel keyVaultTreeListViewModel; - private readonly TabViewPageViewModel tabViewPageViewModel; private readonly MainViewModel mainViewModel; + private readonly TabViewPageViewModel tabViewPageViewModel; + private readonly AuthService authService; public MainView() { @@ -39,6 +42,8 @@ public MainView() keyVaultTreeListViewModel = Defaults.Locator.GetRequiredService(); tabViewPageViewModel = Defaults.Locator.GetRequiredService(); mainViewModel = Defaults.Locator.GetRequiredService(); + authService = Defaults.Locator.GetRequiredService(); + Dispatcher.UIThread.Post(async () => { @@ -51,41 +56,16 @@ await mainViewModel.RefreshTokenAndGetAccountInformation().ContinueWith(async (t AddHandler(NavigateHomeEvent, OnNavigateHomeEvent, RoutingStrategies.Tunnel, handledEventsToo: false); AddHandler(NavigateSettingsEvent, OnNavigateSettingsEvent, RoutingStrategies.Tunnel, handledEventsToo: false); AddHandler(NavigateSubscriptionsEvent, OnNavigateSubscriptionsEvent, RoutingStrategies.Tunnel, handledEventsToo: false); - AddHandler(SignOutRoutedEvent, OnSignOutRoutedEvent, RoutingStrategies.Tunnel, handledEventsToo: true); - - } - - private void OnNavigationViewBackRequested(object sender, NavigationViewBackRequestedEventArgs e) - { - FrameView.GoBack(); - } - private void OnSignOutRoutedEvent(object sender, RoutedEventArgs e) - { - Debug.WriteLine("Signed out button pressed"); - keyVaultTreeListViewModel.TreeViewList.Clear(); - tabViewPageViewModel.Documents.Clear(); - mainViewModel.IsAuthenticated = false; - } - private void OnNavigateHomeEvent(object sender, RoutedEventArgs e) - { - if (FrameView.Content.GetType().Name != nameof(MainPage)) - FrameView.NavigateFromObject(new MainPage(), NavOptions); - } - - private void OnNavigateSettingsEvent(object sender, RoutedEventArgs e) - { - if (FrameView.Content.GetType().Name != nameof(SettingsPage)) - FrameView.NavigateFromObject(new SettingsPage(), NavOptions); + AddHandler(SignInRoutedEvent, OnSignInRoutedEvent, RoutingStrategies.Tunnel, handledEventsToo: false); + AddHandler(SignOutRoutedEvent, OnSignOutRoutedEvent, RoutingStrategies.Tunnel, handledEventsToo: false); } - private void OnNavigateSubscriptionsEvent(object sender, RoutedEventArgs e) + public static MainView? Instance { get; private set; } + private FrameNavigationOptions NavOptions => new FrameNavigationOptions { - if (FrameView.Content.GetType().Name != nameof(SubscriptionsPage)) - FrameView.NavigateFromObject(new SubscriptionsPage(), NavOptions); - } - - //var menuItems = new List(4); - //var footerItems = new List(2); + TransitionInfoOverride = new SlideNavigationTransitionInfo(), + IsNavigationStackEnabled = true + }; protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { @@ -101,20 +81,6 @@ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) FrameView.NavigateFromObject(new MainPage()); } - private void OnFrameViewNavigated(object sender, NavigationEventArgs e) - { - var page = e.Content as Control; - - if (FrameView.BackStackDepth > 0) //&& !NavView.IsBackButtonVisible - { - AnimateContentForBackButton(true); - } - else if (FrameView.BackStackDepth == 0) // && NavView.IsBackButtonVisible - { - AnimateContentForBackButton(false); - } - } - private async void AnimateContentForBackButton(bool show) { if (!WindowIcon.IsVisible) @@ -186,11 +152,44 @@ private async void AnimateContentForBackButton(bool show) } } - private FrameNavigationOptions NavOptions => new FrameNavigationOptions + //var menuItems = new List(4); + //var footerItems = new List(2); + private void OnFrameViewNavigated(object sender, NavigationEventArgs e) { - TransitionInfoOverride = new SlideNavigationTransitionInfo(), - IsNavigationStackEnabled = true - }; + var page = e.Content as Control; + + if (FrameView.BackStackDepth > 0) //&& !NavView.IsBackButtonVisible + { + AnimateContentForBackButton(true); + } + else if (FrameView.BackStackDepth == 0) // && NavView.IsBackButtonVisible + { + AnimateContentForBackButton(false); + } + } + + private void OnNavigateHomeEvent(object sender, RoutedEventArgs e) + { + if (FrameView.Content.GetType().Name != nameof(MainPage)) + FrameView.NavigateFromObject(new MainPage(), NavOptions); + } + + private void OnNavigateSettingsEvent(object sender, RoutedEventArgs e) + { + if (FrameView.Content.GetType().Name != nameof(SettingsPage)) + FrameView.NavigateFromObject(new SettingsPage(), NavOptions); + } + + private void OnNavigateSubscriptionsEvent(object sender, RoutedEventArgs e) + { + if (FrameView.Content.GetType().Name != nameof(SubscriptionsPage)) + FrameView.NavigateFromObject(new SubscriptionsPage(), NavOptions); + } + + private void OnNavigationViewBackRequested(object sender, NavigationViewBackRequestedEventArgs e) + { + FrameView.GoBack(); + } private void OnNavigationViewItemInvoked(object? sender, NavigationViewItemInvokedEventArgs e) { @@ -200,18 +199,19 @@ private void OnNavigationViewItemInvoked(object? sender, NavigationViewItemInvok } } - //private void ShowAccountTeachingTip(object sender, TappedEventArgs e) - //{ - // AccountTeachingTip.IsOpen = true; - //} - - //private void TeachingTip_ActionButtonClick(TeachingTip sender, System.EventArgs args) - //{ - // if (FrameView.Content.GetType().Name == nameof(SettingsPage)) - // return; - // FrameView.NavigateFromObject(new SettingsPage(), NavOptions); - //} + private void OnSignInRoutedEvent(object sender, RoutedEventArgs e) + { + mainViewModel.AuthenticatedUserClaims = authService.AuthenticatedUserClaims; + mainViewModel.IsAuthenticated = authService.IsAuthenticated; + } + private void OnSignOutRoutedEvent(object sender, RoutedEventArgs e) + { + keyVaultTreeListViewModel.TreeViewList.Clear(); + tabViewPageViewModel.Documents.Clear(); + mainViewModel.IsAuthenticated = false; + mainViewModel.AuthenticatedUserClaims = null; + } private void TabViewPage_KeyUpFocusSearchBox(object sender, KeyEventArgs e) { if (e.Key == Avalonia.Input.Key.F && (e.KeyModifiers == KeyModifiers.Control || e.Key == Avalonia.Input.Key.LWin || e.Key == Avalonia.Input.Key.RWin)) diff --git a/KeyVaultExplorer/Views/MainWindow.axaml b/KeyVaultExplorer/Views/MainWindow.axaml index dbbdcd01..beb51494 100644 --- a/KeyVaultExplorer/Views/MainWindow.axaml +++ b/KeyVaultExplorer/Views/MainWindow.axaml @@ -56,7 +56,7 @@ - + diff --git a/KeyVaultExplorer/Views/Pages/SettingsPage.axaml b/KeyVaultExplorer/Views/Pages/SettingsPage.axaml index 3911c5e0..616de916 100644 --- a/KeyVaultExplorer/Views/Pages/SettingsPage.axaml +++ b/KeyVaultExplorer/Views/Pages/SettingsPage.axaml @@ -48,14 +48,14 @@ - +