From 902a1f98f6e97f2270d463bc50791c9a270d02df Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Tue, 9 Mar 2021 14:37:43 -0800 Subject: [PATCH 01/22] - Removed Behaviors - Renamed StateChangedEventArgs to ProviderStateChangedEventArgs - Moved provider implementations to new providers package --- .../CommonProviderBehaviorBase.Properties.cs | 74 -------- .../Providers/CommonProviderBehaviorBase.cs | 25 --- .../Providers/InteractiveProviderBehavior.cs | 63 ------- .../Providers/MockProviderBehavior.cs | 69 ------- .../Providers/QuickCreate.cs | 56 ------ .../BaseProvider.cs | 74 ++++++++ .../HttpRequestMessageExtensions.cs | 12 +- Microsoft.Toolkit.Graph.Providers/Graph.cs | 102 +++++++++++ .../IGraphConfig.cs | 13 ++ .../Microsoft.Toolkit.Graph.Providers.csproj | 49 +++++ .../MockConfig.cs | 17 ++ .../MockProvider.cs | 46 +---- .../Msal/MsalConfig.cs | 40 +++++ .../Msal}/MsalProvider.cs | 87 ++++----- .../Properties/AssemblyInfo.cs | 11 ++ .../Microsoft.Toolkit.Graph.Providers.rd.xml | 5 + .../ScopeSet.cs | 25 +-- .../Extensions/GraphExtensions.cs | 1 - .../Providers/IProvider.cs | 5 +- .../Providers/ProviderManager.cs | 2 +- ...gs.cs => ProviderStateChangedEventArgs.cs} | 6 +- .../AssemblyInfo.cs | 14 -- .../Behaviors/BehaviorBase.cs | 169 ------------------ ...crosoft.Toolkit.Wpf.Graph.Providers.csproj | 30 ---- .../Providers/ScopeSetTypeConverter.cs | 45 ----- SampleTest/App.xaml | 21 ++- SampleTest/MainPage.xaml | 16 +- SampleTest/SampleTest.csproj | 4 + .../WPF-Core-GraphApp.csproj | 1 - Windows-Toolkit-Graph-Controls.sln | 82 ++++----- 30 files changed, 444 insertions(+), 720 deletions(-) delete mode 100644 Microsoft.Toolkit.Graph.Controls/Providers/CommonProviderBehaviorBase.Properties.cs delete mode 100644 Microsoft.Toolkit.Graph.Controls/Providers/CommonProviderBehaviorBase.cs delete mode 100644 Microsoft.Toolkit.Graph.Controls/Providers/InteractiveProviderBehavior.cs delete mode 100644 Microsoft.Toolkit.Graph.Controls/Providers/MockProviderBehavior.cs delete mode 100644 Microsoft.Toolkit.Graph.Controls/Providers/QuickCreate.cs create mode 100644 Microsoft.Toolkit.Graph.Providers/BaseProvider.cs rename {Microsoft.Toolkit.Graph => Microsoft.Toolkit.Graph.Providers}/Extensions/HttpRequestMessageExtensions.cs (79%) create mode 100644 Microsoft.Toolkit.Graph.Providers/Graph.cs create mode 100644 Microsoft.Toolkit.Graph.Providers/IGraphConfig.cs create mode 100644 Microsoft.Toolkit.Graph.Providers/Microsoft.Toolkit.Graph.Providers.csproj create mode 100644 Microsoft.Toolkit.Graph.Providers/MockConfig.cs rename {Microsoft.Toolkit.Graph/Providers => Microsoft.Toolkit.Graph.Providers}/MockProvider.cs (62%) create mode 100644 Microsoft.Toolkit.Graph.Providers/Msal/MsalConfig.cs rename {Microsoft.Toolkit.Graph/Providers => Microsoft.Toolkit.Graph.Providers/Msal}/MsalProvider.cs (65%) create mode 100644 Microsoft.Toolkit.Graph.Providers/Properties/AssemblyInfo.cs create mode 100644 Microsoft.Toolkit.Graph.Providers/Properties/Microsoft.Toolkit.Graph.Providers.rd.xml rename {Microsoft.Toolkit.Graph.Controls/Providers => Microsoft.Toolkit.Graph.Providers}/ScopeSet.cs (81%) rename Microsoft.Toolkit.Graph/Providers/{StateChangedEventArgs.cs => ProviderStateChangedEventArgs.cs} (80%) delete mode 100644 Microsoft.Toolkit.Wpf.Graph.Providers/AssemblyInfo.cs delete mode 100644 Microsoft.Toolkit.Wpf.Graph.Providers/Behaviors/BehaviorBase.cs delete mode 100644 Microsoft.Toolkit.Wpf.Graph.Providers/Microsoft.Toolkit.Wpf.Graph.Providers.csproj delete mode 100644 Microsoft.Toolkit.Wpf.Graph.Providers/Providers/ScopeSetTypeConverter.cs diff --git a/Microsoft.Toolkit.Graph.Controls/Providers/CommonProviderBehaviorBase.Properties.cs b/Microsoft.Toolkit.Graph.Controls/Providers/CommonProviderBehaviorBase.Properties.cs deleted file mode 100644 index e957366..0000000 --- a/Microsoft.Toolkit.Graph.Controls/Providers/CommonProviderBehaviorBase.Properties.cs +++ /dev/null @@ -1,74 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#if DOTNET -using System.Windows; -#else -using Windows.UI.Xaml; -#endif - -#if DOTNET -namespace Microsoft.Toolkit.Wpf.Graph.Providers -#else -namespace Microsoft.Toolkit.Graph.Providers -#endif -{ - /// - /// Properties for . - /// - public partial class CommonProviderBehaviorBase - { - /// - /// Gets or sets the Client ID (the unique application (client) ID assigned to your app by Azure AD when the app was registered). - /// - /// - /// For details about how to register an app and get a client ID, - /// see the Register an app quick start. - /// - public string ClientId - { - get { return (string)GetValue(ClientIdProperty); } - set { SetValue(ClientIdProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - /// - /// The identifier for the dependency property. - /// - public static readonly DependencyProperty ClientIdProperty = - DependencyProperty.Register(nameof(ClientId), typeof(string), typeof(CommonProviderBehaviorBase), new PropertyMetadata(string.Empty)); - - /// - /// Gets or sets the redirect URI (the URI the identity provider will send the security tokens back to). - /// - public string RedirectUri - { - get { return (string)GetValue(RedirectUriProperty); } - set { SetValue(RedirectUriProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - /// - /// The identifier for the dependency property. - /// - public static readonly DependencyProperty RedirectUriProperty = -#if DOTNET - DependencyProperty.Register(nameof(RedirectUri), typeof(string), typeof(CommonProviderBehaviorBase), new PropertyMetadata("http://localhost")); //// https://aka.ms/msal-net-os-browser -#else - DependencyProperty.Register(nameof(RedirectUri), typeof(string), typeof(CommonProviderBehaviorBase), new PropertyMetadata("https://login.microsoftonline.com/common/oauth2/nativeclient")); -#endif - - /// - /// Gets or sets the list of Scopes (permissions) to request on initial login. - /// - /// - /// This list can be modified by controls which require specific scopes to function. This will aid in requesting all scopes required by controls used before login is initiated, if using the LoginButton. - /// - public ScopeSet Scopes { get; set; } = new ScopeSet { "User.Read", "User.ReadBasic.All" }; - } -} diff --git a/Microsoft.Toolkit.Graph.Controls/Providers/CommonProviderBehaviorBase.cs b/Microsoft.Toolkit.Graph.Controls/Providers/CommonProviderBehaviorBase.cs deleted file mode 100644 index bf8bd86..0000000 --- a/Microsoft.Toolkit.Graph.Controls/Providers/CommonProviderBehaviorBase.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#if DOTNET -using System.Windows; -using Microsoft.Toolkit.Wpf.UI.Behaviors; -#else -using Microsoft.Toolkit.Uwp.UI.Behaviors; -using Windows.UI.Xaml; -#endif - -#if DOTNET -namespace Microsoft.Toolkit.Wpf.Graph.Providers -#else -namespace Microsoft.Toolkit.Graph.Providers -#endif -{ - /// - /// Provides a common base class for UWP XAML based provider wrappers to the Microsoft.Graph.Auth SDK. - /// - public abstract partial class CommonProviderBehaviorBase : BehaviorBase - { - } -} diff --git a/Microsoft.Toolkit.Graph.Controls/Providers/InteractiveProviderBehavior.cs b/Microsoft.Toolkit.Graph.Controls/Providers/InteractiveProviderBehavior.cs deleted file mode 100644 index 99de148..0000000 --- a/Microsoft.Toolkit.Graph.Controls/Providers/InteractiveProviderBehavior.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#if DOTNET -using System; -using System.Linq; -using System.Windows; -using Microsoft.Toolkit.Graph.Providers; -#else -using System.Linq; -using Windows.System; -#endif - -#if DOTNET -namespace Microsoft.Toolkit.Wpf.Graph.Providers -#else -namespace Microsoft.Toolkit.Graph.Providers -#endif -{ - /// - /// Put in a xaml page with ClientId - /// https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Acquiring-tokens-interactively. - /// - /// - /// - /// <Interactivity:Interaction.Behaviors> - /// <providers:InteractiveProviderBehavior ClientId = "MyClientIdGuid"/> - /// </Interactivity:Interaction.Behaviors> - /// - /// - public class InteractiveProviderBehavior : CommonProviderBehaviorBase - { - private object lock_sync = new object(); - private bool initialized = false; - - /// - protected override bool Initialize() - { - lock (lock_sync) - { - if (!initialized) - { -#if DOTNET - _ = Dispatcher.BeginInvoke(new Action(async () => - { - ProviderManager.Instance.GlobalProvider = - await QuickCreate.CreateMsalProviderAsync(ClientId, RedirectUri, Scopes.ToArray()); - }), System.Windows.Threading.DispatcherPriority.Normal); -#else - _ = DispatcherQueue.GetForCurrentThread().TryEnqueue(DispatcherQueuePriority.Normal, async () => - { - ProviderManager.Instance.GlobalProvider = - await QuickCreate.CreateMsalProviderAsync(ClientId, RedirectUri, Scopes.ToArray()); - }); -#endif - } - } - - return base.Initialize(); - } - } -} diff --git a/Microsoft.Toolkit.Graph.Controls/Providers/MockProviderBehavior.cs b/Microsoft.Toolkit.Graph.Controls/Providers/MockProviderBehavior.cs deleted file mode 100644 index 03a7ba7..0000000 --- a/Microsoft.Toolkit.Graph.Controls/Providers/MockProviderBehavior.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#if DOTNET -using System; -using System.Linq; -using System.Windows; -using Microsoft.Toolkit.Graph.Providers; -#else -using System.Linq; -using Windows.UI.Xaml; -#endif - -#if DOTNET -namespace Microsoft.Toolkit.Wpf.Graph.Providers -#else -namespace Microsoft.Toolkit.Graph.Providers -#endif -{ - /// - /// Put in a xaml page with ClientId - /// https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Acquiring-tokens-interactively. - /// - /// - /// - /// <Interactivity:Interaction.Behaviors> - /// <providers:InteractiveProviderBehavior ClientId = "MyClientIdGuid"/> - /// </Interactivity:Interaction.Behaviors> - /// - /// - public class MockProviderBehavior : CommonProviderBehaviorBase - { - private object lock_sync = new object(); - private bool initialized = false; - - /// - /// Gets or sets a value indicating whether the mock provider is signed-in upon initialization. - /// - public bool SignedIn - { - get { return (bool)GetValue(SignedInProperty); } - set { SetValue(SignedInProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - /// - /// The identifier for the dependency property. - /// - public static readonly DependencyProperty SignedInProperty = - DependencyProperty.Register(nameof(SignedIn), typeof(bool), typeof(MockProviderBehavior), new PropertyMetadata(true)); - - /// - protected override bool Initialize() - { - lock (lock_sync) - { - if (!initialized) - { - ProviderManager.Instance.GlobalProvider = new MockProvider(SignedIn); - } - } - - return base.Initialize(); - } - } -} diff --git a/Microsoft.Toolkit.Graph.Controls/Providers/QuickCreate.cs b/Microsoft.Toolkit.Graph.Controls/Providers/QuickCreate.cs deleted file mode 100644 index b9fdfe7..0000000 --- a/Microsoft.Toolkit.Graph.Controls/Providers/QuickCreate.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Reflection; -using System.Threading.Tasks; -using Microsoft.Graph.Auth; -using Microsoft.Identity.Client; -using Microsoft.Toolkit.Graph.Providers; - -#if DOTNET -namespace Microsoft.Toolkit.Wpf.Graph.Providers -#else -namespace Microsoft.Toolkit.Graph.Providers -#endif -{ - //// TODO: This should probably live in .NET Standard lib; however, Uno one needs to be at UI layer for Parent Window? - //// TODO: Need to set up XAML Islands sample to test in the new repo and make sure this works from this context. - - /// - /// Helper class to easily initialize provider from just ClientId. - /// - public static class QuickCreate - { - /// - /// Easily creates a from a ClientId. - /// - /// - /// - /// ProviderManager.Instance.GlobalProvider = await QuickCreate.CreateMsalProviderAsync("MyClientId"); - /// - /// - /// Registered ClientId. - /// RedirectUri for auth response. - /// List of Scopes to initially request. - /// New reference. - public static async Task CreateMsalProviderAsync(string clientid, string redirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient", string[] scopes = null) - { - var client = PublicClientApplicationBuilder.Create(clientid) - .WithAuthority(AzureCloudInstance.AzurePublic, AadAuthorityAudience.AzureAdAndPersonalMicrosoftAccount) - .WithRedirectUri(redirectUri) - .WithClientName(ProviderManager.ClientName) - .WithClientVersion(Assembly.GetExecutingAssembly().GetName().Version.ToString()) - .Build(); - - if (scopes == null) - { - scopes = new string[] { string.Empty }; - } - - var provider = new InteractiveAuthenticationProvider(client, scopes); - - return await MsalProvider.CreateAsync(client, provider); - } - } -} diff --git a/Microsoft.Toolkit.Graph.Providers/BaseProvider.cs b/Microsoft.Toolkit.Graph.Providers/BaseProvider.cs new file mode 100644 index 0000000..4c5d7f7 --- /dev/null +++ b/Microsoft.Toolkit.Graph.Providers/BaseProvider.cs @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.Graph; +using Microsoft.Toolkit.Graph.Providers.Extensions; + +namespace Microsoft.Toolkit.Graph.Providers +{ + /// + /// A base construct for building Graph Providers on top of. + /// + public abstract class BaseProvider : IProvider + { + private ProviderState _state; + + /// + /// Gets or sets the current state of the provider. + /// + public ProviderState State + { + get => _state; + protected set + { + var oldState = _state; + var newState = value; + if (oldState != newState) + { + _state = newState; + StateChanged?.Invoke(this, new ProviderStateChangedEventArgs(oldState, newState)); + } + } + } + + /// + public event EventHandler StateChanged; + + /// + /// Gets or sets the service client instance for making Graph calls. + /// + public virtual GraphServiceClient Graph { get; protected set; } + + /// + /// Initializes a new instance of the class. + /// + public BaseProvider() + { + _state = ProviderState.Loading; + } + + /// + public abstract Task LoginAsync(); + + /// + public abstract Task LogoutAsync(); + + /// + public abstract Task AuthenticateRequestAsync(HttpRequestMessage request); + + /// + /// Append the Sdk version to the request headers. + /// + /// + /// The request to append the header to. + /// + protected void AddSdkVersion(HttpRequestMessage request) + { + request.AddSdkVersion(); + } + } +} diff --git a/Microsoft.Toolkit.Graph/Extensions/HttpRequestMessageExtensions.cs b/Microsoft.Toolkit.Graph.Providers/Extensions/HttpRequestMessageExtensions.cs similarity index 79% rename from Microsoft.Toolkit.Graph/Extensions/HttpRequestMessageExtensions.cs rename to Microsoft.Toolkit.Graph.Providers/Extensions/HttpRequestMessageExtensions.cs index 9d75abf..0059590 100644 --- a/Microsoft.Toolkit.Graph/Extensions/HttpRequestMessageExtensions.cs +++ b/Microsoft.Toolkit.Graph.Providers/Extensions/HttpRequestMessageExtensions.cs @@ -2,28 +2,24 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; -using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using System.Reflection; -using System.Text; -using System.Threading.Tasks; -namespace Microsoft.Toolkit.Graph.Extensions +namespace Microsoft.Toolkit.Graph.Providers.Extensions { /// /// Helpers for Graph related HTTP Headers. /// - internal static class HttpRequestMessageExtensions + public static class HttpRequestMessageExtensions { private const string SdkVersion = "SdkVersion"; private const string LibraryName = "wct"; private const string Bearer = "Bearer"; private const string MockGraphToken = "{token:https://graph.microsoft.com/}"; - public static void AddSdkVersion(this HttpRequestMessage request) + internal static void AddSdkVersion(this HttpRequestMessage request) { if (request == null || request.Headers == null) { @@ -39,7 +35,7 @@ public static void AddSdkVersion(this HttpRequestMessage request) } } - public static void AddMockProviderToken(this HttpRequestMessage request) + internal static void AddMockProviderToken(this HttpRequestMessage request) { request .Headers diff --git a/Microsoft.Toolkit.Graph.Providers/Graph.cs b/Microsoft.Toolkit.Graph.Providers/Graph.cs new file mode 100644 index 0000000..28ca326 --- /dev/null +++ b/Microsoft.Toolkit.Graph.Providers/Graph.cs @@ -0,0 +1,102 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using Windows.UI.Xaml; + +namespace Microsoft.Toolkit.Graph.Providers +{ + /// + /// Creates a new provider instance for the provided configuration and sets the GlobalProvider. + /// + public static class Graph + { + /// + /// Gets the Graph Config property value. + /// + /// + /// The target object to retrieve the property value from. + /// + /// + /// The value of the property on the target. + /// + public static IGraphConfig GetConfig(ResourceDictionary target) + { + return (IGraphConfig)target.GetValue(ConfigProperty); + } + + /// + /// Sets the GraphConfig property value. + /// + /// + /// The target object to set the value on. + /// + /// + /// The value to apply to the target property. + /// + public static void SetConfig(ResourceDictionary target, IGraphConfig value) + { + target.SetValue(ConfigProperty, value); + } + + /// + /// Identifies the Config dependency property. + /// + /// + /// The identifier for the Config dependency property. + /// + public static readonly DependencyProperty ConfigProperty = + DependencyProperty.RegisterAttached("Config", typeof(IGraphConfig), typeof(Graph), new PropertyMetadata(null, OnConfigChanged)); + + private static void OnConfigChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) + { + if (sender is ResourceDictionary rd) + { + IGraphConfig config = GetConfig(rd); + + Type configType = config.GetType(); + if (_providers.ContainsKey(configType)) + { + var providerFactory = _providers[configType]; + ProviderManager.Instance.GlobalProvider = providerFactory.Invoke(config); + } + else if (config is MockConfig mockConfig) + { + ProviderManager.Instance.GlobalProvider = new MockProvider(mockConfig); + } + } + else + { + ProviderManager.Instance.GlobalProvider = null; + } + } + + private static readonly Dictionary> _providers = new Dictionary>(); + + /// + /// Register a provider to be available for declaration in XAML using the ConfigProperty. + /// Use in the static constructor of an IGraphConfig implementation. + /// + /// + /// static MsalConfig() + /// { + /// Graph.RegisterConfig(typeof(MsalConfig), (c) => MsalProvider.Create(c as MsalConfig)); + /// }. + /// + /// + /// The Type of the IGraphConfig implementation associated with provider. + /// + /// + /// A factory function for creating a new instance of the IProvider implementation. + /// + public static void RegisterConfig(Type configType, Func providerFactory) + { + if (!_providers.ContainsKey(configType)) + { + _providers.Add(configType, providerFactory); + } + } + } +} diff --git a/Microsoft.Toolkit.Graph.Providers/IGraphConfig.cs b/Microsoft.Toolkit.Graph.Providers/IGraphConfig.cs new file mode 100644 index 0000000..37886da --- /dev/null +++ b/Microsoft.Toolkit.Graph.Providers/IGraphConfig.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Toolkit.Graph.Providers +{ + /// + /// An interface to base Graph configuration implementations on. + /// + public interface IGraphConfig + { + } +} diff --git a/Microsoft.Toolkit.Graph.Providers/Microsoft.Toolkit.Graph.Providers.csproj b/Microsoft.Toolkit.Graph.Providers/Microsoft.Toolkit.Graph.Providers.csproj new file mode 100644 index 0000000..4910cf8 --- /dev/null +++ b/Microsoft.Toolkit.Graph.Providers/Microsoft.Toolkit.Graph.Providers.csproj @@ -0,0 +1,49 @@ + + + + uap10.0.17763 + Windows Community Toolkit Graph Providers + Microsoft.Toolkit.Graph.Providers + + This library provides base constructs for building Microsoft Graph XAML providers. It is part of the Windows Community Toolkit. + + Classes: + - BaseProvider: + - Graph: + - IGraphConfig: + - ScopeSet: + - MockConfig: + - MockProvider: + - MsalConfig: + - MsalProvider: + - WindowsConfig: + - WindowsProvider: + + UWP Toolkit Windows Providers MSAL Microsoft Graph Auth Authentication + false + true + 8.0 + Debug;Release;CI + AnyCPU;ARM;ARM64;x64;x86 + + + + + + + + + + + + + + + + + + + + + + diff --git a/Microsoft.Toolkit.Graph.Providers/MockConfig.cs b/Microsoft.Toolkit.Graph.Providers/MockConfig.cs new file mode 100644 index 0000000..c857a47 --- /dev/null +++ b/Microsoft.Toolkit.Graph.Providers/MockConfig.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Toolkit.Graph.Providers +{ + /// + /// The configuration for the MockProvider. + /// + public class MockConfig : IGraphConfig + { + /// + /// Gets or sets a value indicating whether the provider should automatically sign in or not. + /// + public bool SignedIn { get; set; } = true; + } +} diff --git a/Microsoft.Toolkit.Graph/Providers/MockProvider.cs b/Microsoft.Toolkit.Graph.Providers/MockProvider.cs similarity index 62% rename from Microsoft.Toolkit.Graph/Providers/MockProvider.cs rename to Microsoft.Toolkit.Graph.Providers/MockProvider.cs index a0d54ec..beec22e 100644 --- a/Microsoft.Toolkit.Graph/Providers/MockProvider.cs +++ b/Microsoft.Toolkit.Graph.Providers/MockProvider.cs @@ -3,47 +3,22 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; -using System.Linq; using System.Net.Http; -using System.Net.Http.Headers; -using System.Reflection; -using System.Text; using System.Threading.Tasks; -using System.Web; using Microsoft.Graph; -using Microsoft.Toolkit.Graph.Extensions; +using Microsoft.Toolkit.Graph.Providers.Extensions; namespace Microsoft.Toolkit.Graph.Providers { /// /// Provider to connect to the example data set for Microsoft Graph. Useful for prototyping and samples. /// - public class MockProvider : IProvider + public class MockProvider : BaseProvider { private const string GRAPH_PROXY_URL = "https://proxy.apisandbox.msdn.microsoft.com/svc?url="; - private ProviderState _state = ProviderState.Loading; - /// - public ProviderState State - { - get - { - return _state; - } - - private set - { - var current = _state; - _state = value; - - StateChanged?.Invoke(this, new StateChangedEventArgs(current, _state)); - } - } - - /// - public GraphServiceClient Graph => new GraphServiceClient( + public override GraphServiceClient Graph => new GraphServiceClient( new DelegateAuthenticationProvider((requestMessage) => { var requestUri = requestMessage.RequestUri.ToString(); @@ -54,16 +29,13 @@ private set return this.AuthenticateRequestAsync(requestMessage); })); - /// - public event EventHandler StateChanged; - /// /// Initializes a new instance of the class. /// - /// Whether the default state should be signedIn, defaults to true. - public MockProvider(bool signedIn = true) + /// Configuration for the MockProvider. + public MockProvider(MockConfig config = null) { - if (signedIn) + if (config == null || config.SignedIn) { State = ProviderState.SignedIn; } @@ -74,7 +46,7 @@ public MockProvider(bool signedIn = true) } /// - public Task AuthenticateRequestAsync(HttpRequestMessage request) + public override Task AuthenticateRequestAsync(HttpRequestMessage request) { request.AddSdkVersion(); @@ -84,7 +56,7 @@ public Task AuthenticateRequestAsync(HttpRequestMessage request) } /// - public async Task LoginAsync() + public override async Task LoginAsync() { State = ProviderState.Loading; await Task.Delay(3000); @@ -92,7 +64,7 @@ public async Task LoginAsync() } /// - public async Task LogoutAsync() + public override async Task LogoutAsync() { State = ProviderState.Loading; await Task.Delay(3000); diff --git a/Microsoft.Toolkit.Graph.Providers/Msal/MsalConfig.cs b/Microsoft.Toolkit.Graph.Providers/Msal/MsalConfig.cs new file mode 100644 index 0000000..cd763a9 --- /dev/null +++ b/Microsoft.Toolkit.Graph.Providers/Msal/MsalConfig.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Toolkit.Graph.Providers.Msal +{ + /// + /// Configuration values for initializing the MsalProvider. + /// + public class MsalConfig : IGraphConfig + { + static MsalConfig() + { + Graph.RegisterConfig(typeof(MsalConfig), (c) => MsalProvider.Create(c as MsalConfig)); + } + + /// + /// Gets or sets the Client ID (the unique application (client) ID assigned to your app by Azure AD when the app was registered). + /// + /// + /// For details about how to register an app and get a client ID, + /// see the Register an app quick start. + /// + public string ClientId { get; set; } + + /// + /// Gets or sets the redirect URI (the URI the identity provider will send the security tokens back to). + /// + public string RedirectUri { get; set; } + + /// + /// Gets or sets the list of Scopes (permissions) to request on initial login. + /// + /// + /// This list can be modified by controls which require specific scopes to function. + /// This will aid in requesting all scopes required by controls used before login is initiated, if using the LoginButton. + /// + public ScopeSet Scopes { get; set; } + } +} diff --git a/Microsoft.Toolkit.Graph/Providers/MsalProvider.cs b/Microsoft.Toolkit.Graph.Providers/Msal/MsalProvider.cs similarity index 65% rename from Microsoft.Toolkit.Graph/Providers/MsalProvider.cs rename to Microsoft.Toolkit.Graph.Providers/Msal/MsalProvider.cs index 42c00bc..2987e98 100644 --- a/Microsoft.Toolkit.Graph/Providers/MsalProvider.cs +++ b/Microsoft.Toolkit.Graph.Providers/Msal/MsalProvider.cs @@ -3,23 +3,20 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Reflection; using System.Threading.Tasks; using Microsoft.Graph; +using Microsoft.Graph.Auth; using Microsoft.Identity.Client; -using Microsoft.Toolkit.Graph.Extensions; -namespace Microsoft.Toolkit.Graph.Providers +namespace Microsoft.Toolkit.Graph.Providers.Msal { - //// TODO: Move some of this to a simple base-class for non-MSAL parts related to Provider only and properties? - /// /// MSAL.NET provider helper for tracking authentication state using an class. /// - public class MsalProvider : IProvider + public class MsalProvider : BaseProvider { /// /// Gets or sets the MSAL.NET Client used to authenticate the user. @@ -31,65 +28,71 @@ public class MsalProvider : IProvider /// protected IAuthenticationProvider Provider { get; set; } - private ProviderState _state = ProviderState.Loading; - - /// - public ProviderState State + /// + /// Initializes a new instance of the class. . + /// + private MsalProvider() { - get - { - return _state; - } - - private set - { - var current = _state; - _state = value; - - StateChanged?.Invoke(this, new StateChangedEventArgs(current, _state)); - } } - /// - public GraphServiceClient Graph { get; private set; } - - /// - public event EventHandler StateChanged; - /// - /// Initializes a new instance of the class. . + /// Easily creates a from a config object. /// - private MsalProvider() + /// + /// The configuration object used to initialize the provider. + /// + /// + /// A new instance of the MsalProvider. + /// + public static MsalProvider Create(MsalConfig config) { + return Create(config.ClientId, config.RedirectUri, config.Scopes.ToArray()); } /// - /// Initializes a new instance of the class. + /// Easily creates a from a ClientId. /// - /// Existing instance. - /// Existing instance. - /// A returning a instance. - public static async Task CreateAsync(IPublicClientApplication client, IAuthenticationProvider provider) + /// + /// + /// ProviderManager.Instance.GlobalProvider = await QuickCreate.CreateMsalProviderAsync("MyClientId"); + /// + /// + /// Registered ClientId. + /// RedirectUri for auth response. + /// List of Scopes to initially request. + /// New reference. + public static MsalProvider Create(string clientid, string redirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient", string[] scopes = null) { //// TODO: Check all config provided + var client = PublicClientApplicationBuilder.Create(clientid) + .WithAuthority(AzureCloudInstance.AzurePublic, AadAuthorityAudience.AzureAdAndPersonalMicrosoftAccount) + .WithRedirectUri(redirectUri) + .WithClientName(ProviderManager.ClientName) + .WithClientVersion(Assembly.GetExecutingAssembly().GetName().Version.ToString()) + .Build(); + + if (scopes == null) + { + scopes = new string[] { string.Empty }; + } + var msal = new MsalProvider { Client = client, - Provider = provider, + Provider = new InteractiveAuthenticationProvider(client, scopes), }; - msal.Graph = new GraphServiceClient(msal); - await msal.TrySilentSignInAsync(); + _ = msal.TrySilentSignInAsync(); return msal; } /// - public async Task AuthenticateRequestAsync(HttpRequestMessage request) + public override async Task AuthenticateRequestAsync(HttpRequestMessage request) { - request.AddSdkVersion(); + AddSdkVersion(request); try { @@ -159,14 +162,14 @@ public async Task TrySilentSignInAsync() } /// - public async Task LoginAsync() + public override async Task LoginAsync() { // Force fake request to start auth process await AuthenticateRequestAsync(new System.Net.Http.HttpRequestMessage()); } /// - public async Task LogoutAsync() + public override async Task LogoutAsync() { // Forcibly remove each user. foreach (var user in await Client.GetAccountsAsync()) diff --git a/Microsoft.Toolkit.Graph.Providers/Properties/AssemblyInfo.cs b/Microsoft.Toolkit.Graph.Providers/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c244792 --- /dev/null +++ b/Microsoft.Toolkit.Graph.Providers/Properties/AssemblyInfo.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Resources; +using System.Runtime.CompilerServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: NeutralResourcesLanguage("en-US")] \ No newline at end of file diff --git a/Microsoft.Toolkit.Graph.Providers/Properties/Microsoft.Toolkit.Graph.Providers.rd.xml b/Microsoft.Toolkit.Graph.Providers/Properties/Microsoft.Toolkit.Graph.Providers.rd.xml new file mode 100644 index 0000000..b4f2d7f --- /dev/null +++ b/Microsoft.Toolkit.Graph.Providers/Properties/Microsoft.Toolkit.Graph.Providers.rd.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/Microsoft.Toolkit.Graph.Controls/Providers/ScopeSet.cs b/Microsoft.Toolkit.Graph.Providers/ScopeSet.cs similarity index 81% rename from Microsoft.Toolkit.Graph.Controls/Providers/ScopeSet.cs rename to Microsoft.Toolkit.Graph.Providers/ScopeSet.cs index 28ba91d..21eb552 100644 --- a/Microsoft.Toolkit.Graph.Controls/Providers/ScopeSet.cs +++ b/Microsoft.Toolkit.Graph.Providers/ScopeSet.cs @@ -2,32 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if DOTNET -using Microsoft.Xaml.Behaviors; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Linq; -#else -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -#endif -#if DOTNET -namespace Microsoft.Toolkit.Wpf.Graph.Providers -#else namespace Microsoft.Toolkit.Graph.Providers -#endif { /// /// Helper Class for XAML string Scope conversion. /// -#if DOTNET - [TypeConverter(typeof(ScopeSetTypeConverter))] -#else [Windows.Foundation.Metadata.CreateFromString(MethodName = "Microsoft.Toolkit.Graph.Providers.ScopeSet.ConvertToScopeArray")] -#endif public class ScopeSet : Collection { /// @@ -47,7 +30,7 @@ public static ScopeSet ConvertToScopeArray(string rawString) return new ScopeSet(rawString.Split(",")); } - return ScopeSet.Empty; + return Empty; } /// @@ -56,7 +39,7 @@ public static ScopeSet ConvertToScopeArray(string rawString) /// Array to copy as ScopeSet. public ScopeSet(string[] arr) { - this.AddRange(arr); + AddRange(arr); } /// @@ -65,7 +48,7 @@ public ScopeSet(string[] arr) /// List to copy as ScopeSet. public ScopeSet(List list) { - this.AddRange(list.ToArray()); + AddRange(list.ToArray()); } /// @@ -83,7 +66,7 @@ public void AddRange(string[] items) { foreach (var item in items) { - this.Add(item); + Add(item); } } } diff --git a/Microsoft.Toolkit.Graph/Extensions/GraphExtensions.cs b/Microsoft.Toolkit.Graph/Extensions/GraphExtensions.cs index 9d7668a..8e8a433 100644 --- a/Microsoft.Toolkit.Graph/Extensions/GraphExtensions.cs +++ b/Microsoft.Toolkit.Graph/Extensions/GraphExtensions.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.IO; using System.Threading.Tasks; using Microsoft.Graph; diff --git a/Microsoft.Toolkit.Graph/Providers/IProvider.cs b/Microsoft.Toolkit.Graph/Providers/IProvider.cs index ea59b80..0afcde6 100644 --- a/Microsoft.Toolkit.Graph/Providers/IProvider.cs +++ b/Microsoft.Toolkit.Graph/Providers/IProvider.cs @@ -3,9 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.ComponentModel; -using System.Net.Http; -using System.Runtime.CompilerServices; using System.Threading.Tasks; using Microsoft.Graph; @@ -29,7 +26,7 @@ public interface IProvider : IAuthenticationProvider /// /// Event called when the login changes. /// - event EventHandler StateChanged; + event EventHandler StateChanged; /// /// Login the user. diff --git a/Microsoft.Toolkit.Graph/Providers/ProviderManager.cs b/Microsoft.Toolkit.Graph/Providers/ProviderManager.cs index e417de0..301c912 100644 --- a/Microsoft.Toolkit.Graph/Providers/ProviderManager.cs +++ b/Microsoft.Toolkit.Graph/Providers/ProviderManager.cs @@ -72,7 +72,7 @@ private ProviderManager() // Use Instance } - private void ProviderStateChanged(object sender, StateChangedEventArgs e) + private void ProviderStateChanged(object sender, ProviderStateChangedEventArgs e) { ProviderUpdated?.Invoke(this, new ProviderUpdatedEventArgs(ProviderManagerChangedState.ProviderStateChanged)); } diff --git a/Microsoft.Toolkit.Graph/Providers/StateChangedEventArgs.cs b/Microsoft.Toolkit.Graph/Providers/ProviderStateChangedEventArgs.cs similarity index 80% rename from Microsoft.Toolkit.Graph/Providers/StateChangedEventArgs.cs rename to Microsoft.Toolkit.Graph/Providers/ProviderStateChangedEventArgs.cs index f2f65d0..37b1c95 100644 --- a/Microsoft.Toolkit.Graph/Providers/StateChangedEventArgs.cs +++ b/Microsoft.Toolkit.Graph/Providers/ProviderStateChangedEventArgs.cs @@ -9,14 +9,14 @@ namespace Microsoft.Toolkit.Graph.Providers /// /// event arguments. /// - public class StateChangedEventArgs : EventArgs + public class ProviderStateChangedEventArgs : EventArgs { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Previous . /// Current . - public StateChangedEventArgs(ProviderState oldState, ProviderState newState) + public ProviderStateChangedEventArgs(ProviderState oldState, ProviderState newState) { OldState = oldState; NewState = newState; diff --git a/Microsoft.Toolkit.Wpf.Graph.Providers/AssemblyInfo.cs b/Microsoft.Toolkit.Wpf.Graph.Providers/AssemblyInfo.cs deleted file mode 100644 index a06202d..0000000 --- a/Microsoft.Toolkit.Wpf.Graph.Providers/AssemblyInfo.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Windows; - -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located - //(used if a resource is not found in the page, - // or application resource dictionaries) - ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located - //(used if a resource is not found in the page, - // app, or any theme specific resource dictionaries) -)] diff --git a/Microsoft.Toolkit.Wpf.Graph.Providers/Behaviors/BehaviorBase.cs b/Microsoft.Toolkit.Wpf.Graph.Providers/Behaviors/BehaviorBase.cs deleted file mode 100644 index 800df3c..0000000 --- a/Microsoft.Toolkit.Wpf.Graph.Providers/Behaviors/BehaviorBase.cs +++ /dev/null @@ -1,169 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Windows; -using Microsoft.Xaml.Behaviors; - -namespace Microsoft.Toolkit.Wpf.UI.Behaviors -{ - /// - /// INTERNAL DO NOT USE, please thumb-up this comment https://github.com/windows-toolkit/Microsoft.Toolkit.Win32/issues/93#issuecomment-545091683 if you think this would be useful to you. - /// Base class for behaviors that solves 2 problems: - /// 1. Prevent duplicate initialization that can happen (prevent multiple OnAttached calls); - /// 2. Whenever initially fails, this method will subscribe to to allow lazy initialization. - /// - /// The type of the associated object. - /// - /// - /// For more info, see https://github.com/windows-toolkit/WindowsCommunityToolkit/issues/1008. - /// - public abstract class BehaviorBase : Behavior - where T : UIElement - { - private bool _isAttaching; - private bool _isAttached; - - /// - /// Gets a value indicating whether this behavior is attached. - /// - /// - /// true if this behavior is attached; otherwise, false. - /// - protected bool IsAttached - { - get { return _isAttached; } - } - - /// - /// Called after the behavior is attached to the . - /// - /// - /// Override this to hook up functionality to the - /// - protected override void OnAttached() - { - base.OnAttached(); - - HandleAttach(); - - var frameworkElement = AssociatedObject as FrameworkElement; - if (frameworkElement != null) - { - frameworkElement.Loaded += OnAssociatedObjectLoaded; - frameworkElement.Unloaded += OnAssociatedObjectUnloaded; - frameworkElement.SizeChanged += OnAssociatedObjectSizeChanged; - } - } - - /// - /// Called when the behavior is being detached from its . - /// - /// - /// Override this to unhook functionality from the - /// - protected override void OnDetaching() - { - base.OnDetaching(); - - var frameworkElement = AssociatedObject as FrameworkElement; - if (frameworkElement != null) - { - frameworkElement.Loaded -= OnAssociatedObjectLoaded; - frameworkElement.Unloaded -= OnAssociatedObjectUnloaded; - frameworkElement.SizeChanged -= OnAssociatedObjectSizeChanged; - } - - HandleDetach(); - } - - /// - /// Called when the associated object has been loaded. - /// - protected virtual void OnAssociatedObjectLoaded() - { - } - - /// - /// Called when the associated object has been unloaded. - /// - protected virtual void OnAssociatedObjectUnloaded() - { - } - - /// - /// Initializes the behavior to the associated object. - /// - /// true if the initialization succeeded; otherwise false. - protected virtual bool Initialize() - { - return true; - } - - /// - /// Uninitializes the behavior from the associated object. - /// - /// true if uninitialization succeeded; otherwise false. - protected virtual bool Uninitialize() - { - return true; - } - - private void OnAssociatedObjectLoaded(object sender, RoutedEventArgs e) - { - if (!_isAttached) - { - HandleAttach(); - } - - OnAssociatedObjectLoaded(); - } - - private void OnAssociatedObjectUnloaded(object sender, RoutedEventArgs e) - { - OnAssociatedObjectUnloaded(); - - // Note: don't detach here, we'll let the behavior implementation take care of that - } - - private void OnAssociatedObjectSizeChanged(object sender, SizeChangedEventArgs e) - { - if (!_isAttached) - { - HandleAttach(); - } - } - - private void HandleAttach() - { - if (_isAttaching || _isAttached) - { - return; - } - - _isAttaching = true; - - var attached = Initialize(); - if (attached) - { - _isAttached = true; - } - - _isAttaching = false; - } - - private void HandleDetach() - { - if (!_isAttached) - { - return; - } - - var detached = Uninitialize(); - if (detached) - { - _isAttached = false; - } - } - } -} \ No newline at end of file diff --git a/Microsoft.Toolkit.Wpf.Graph.Providers/Microsoft.Toolkit.Wpf.Graph.Providers.csproj b/Microsoft.Toolkit.Wpf.Graph.Providers/Microsoft.Toolkit.Wpf.Graph.Providers.csproj deleted file mode 100644 index ae43cf0..0000000 --- a/Microsoft.Toolkit.Wpf.Graph.Providers/Microsoft.Toolkit.Wpf.Graph.Providers.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - - netcoreapp3.1 - true - AnyCPU;x86;x64 - Debug;Release;CI - - - - DOTNET - - - - - - - - - - - - - - - - - - - diff --git a/Microsoft.Toolkit.Wpf.Graph.Providers/Providers/ScopeSetTypeConverter.cs b/Microsoft.Toolkit.Wpf.Graph.Providers/Providers/ScopeSetTypeConverter.cs deleted file mode 100644 index 2ce2951..0000000 --- a/Microsoft.Toolkit.Wpf.Graph.Providers/Providers/ScopeSetTypeConverter.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.ComponentModel; -using System.Globalization; - -namespace Microsoft.Toolkit.Wpf.Graph.Providers -{ - /// - /// - /// - public class ScopeSetTypeConverter : TypeConverter - { - /// - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - /// - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - return ScopeSet.ConvertToScopeArray(value as string); - } - - /// - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) - { - return destinationType == typeof(string[]); - } - - /// - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - if (value is ScopeSet set) - { - return string.Join(",", set); - } - - return null; - } - } -} \ No newline at end of file diff --git a/SampleTest/App.xaml b/SampleTest/App.xaml index ea9689d..9856b3a 100644 --- a/SampleTest/App.xaml +++ b/SampleTest/App.xaml @@ -1,4 +1,23 @@  + xmlns:providers="using:Microsoft.Toolkit.Graph.Providers" + xmlns:msal="using:Microsoft.Toolkit.Graph.Providers.Msal"> + + + + + + + + + + + diff --git a/SampleTest/MainPage.xaml b/SampleTest/MainPage.xaml index 272dfa1..a52c522 100644 --- a/SampleTest/MainPage.xaml +++ b/SampleTest/MainPage.xaml @@ -1,8 +1,6 @@  - - - - - - +