Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restructuring package layout, removing behaviors #76

Merged
merged 23 commits into from
Mar 24, 2021
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
902a1f9
- Removed Behaviors
shweaver-MSFT Mar 9, 2021
486fd32
Update Graph SDK and change default sample auth method
shweaver-MSFT Mar 9, 2021
8557e9b
Major restructuring wip
shweaver-MSFT Mar 11, 2021
7d19b88
Restructuring completed
shweaver-MSFT Mar 11, 2021
751c7fa
Fixed GraphPresenter sample after latest changes
shweaver-MSFT Mar 11, 2021
6283857
Removed unecessary IProviderConfig interface, replaced with object
shweaver-MSFT Mar 15, 2021
aa8662a
Updated syntax in provider implementations
shweaver-MSFT Mar 15, 2021
306b9b9
Lint fix
shweaver-MSFT Mar 15, 2021
92ad9b1
Renamed packages to new-er format
shweaver-MSFT Mar 16, 2021
976ee86
Renamed UI to Controls
shweaver-MSFT Mar 16, 2021
17a4673
csproj fixes
shweaver-MSFT Mar 17, 2021
cb9c2a6
Removed Graph Auth reference and moved Msal to own package
shweaver-MSFT Mar 18, 2021
e1b24d1
Added helper method for authenticating http requests manually
shweaver-MSFT Mar 18, 2021
ee9e658
csproj adjustments and added helper method for authenticating requests
shweaver-MSFT Mar 18, 2021
0833f15
Update CommunityToolkit.Uwp.Graph.Controls/CommunityToolkit.Uwp.Graph…
shweaver-MSFT Mar 24, 2021
8d0da59
Update CommunityToolkit.Net.Graph/CommunityToolkit.Net.Graph.csproj
shweaver-MSFT Mar 24, 2021
9000daa
Update CommunityToolkit.Net.Graph/CommunityToolkit.Net.Graph.csproj
shweaver-MSFT Mar 24, 2021
07f6036
Update CommunityToolkit.Net.Authentication/CommunityToolkit.Net.Authe…
shweaver-MSFT Mar 24, 2021
50947c9
Update CommunityToolkit.Net.Authentication/CommunityToolkit.Net.Authe…
shweaver-MSFT Mar 24, 2021
32c10b8
Update SampleTest/App.xaml.cs
shweaver-MSFT Mar 24, 2021
4f215c7
Update CommunityToolkit.Net.Authentication.Msal/CommunityToolkit.Net.…
shweaver-MSFT Mar 24, 2021
25bd63c
Adjusted msalProvider constructor argument order
shweaver-MSFT Mar 24, 2021
0ce9faf
Merge branch 'shweaver/bad-behaviors' of https://github.com/windows-t…
shweaver-MSFT Mar 24, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions CommunityToolkit.Net.Authentication/BaseProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// 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 CommunityToolkit.Net.Authentication.Extensions;

namespace CommunityToolkit.Net.Authentication
{
/// <summary>
/// A base construct for building Graph Providers on top of.
/// </summary>
public abstract class BaseProvider : IProvider
{
private ProviderState _state;

/// <summary>
/// Gets or sets the current state of the provider.
/// </summary>
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));
}
}
}

/// <inheritdoc/>
public event EventHandler<ProviderStateChangedEventArgs> StateChanged;

/// <summary>
/// Initializes a new instance of the <see cref="BaseProvider"/> class.
/// </summary>
public BaseProvider()
{
_state = ProviderState.Loading;
}

/// <inheritdoc />
public abstract Task LoginAsync();

/// <inheritdoc />
public abstract Task LogoutAsync();

/// <inheritdoc />
public abstract Task AuthenticateRequestAsync(HttpRequestMessage request);

/// <summary>
/// Append the Sdk version to the request headers.
/// </summary>
/// <param name="request">
/// The request to append the header to.
/// </param>
protected void AddSdkVersion(HttpRequestMessage request)
{
request.AddSdkVersion();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<Project Sdk="MSBuild.Sdk.Extras">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Title>Community Toolkit .NET Standard Auth Services</Title>
<Description>
This package includes .NET Standard authentication helpers such as:
- BaseProvider:
- IProvider:
- MockPRovider:
- MsalProvider:
- ProviderManager:
- ProviderManagerChangedState:
- ProviderState:
- ProviderStateChangedEventArgs:
- ProviderUpdatedEventArgs:
</Description>
<PackageTags>Community Toolkit Provider Authentication Auth</PackageTags>

<!-- This is a temporary workaround for https://github.com/dotnet/sdk/issues/955 -->
<DebugType>Full</DebugType>
<Configurations>Debug;Release;CI</Configurations>
<Platforms>AnyCPU;ARM;ARM64;x64;x86</Platforms>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Graph.Auth" Version="1.0.0-preview.6" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, so we're still relying on this package... hmmm. This is what's pulling in MSAL/ (So if you only want the Windows provider, you're still pulling in MSAL?)

Also, this is the part that's getting rolled into the new Graph SDK which includes everything together... @nmetulev thoughts on if we should try and isolate that for the future vs. knowing eventually we'll pull in the whole Graph SDK... This seems like it's going to be a big problem for consumption of their v2 as we had mentioned.

What pieces are we still referencing from here (besides MSAL)? Like should we have an explicit CommunityToolkit.Net.Authentication.Msal or something?

I wonder if we investigate the source only style package, so rather than having another DLL for just the single MSAL Provider, it effectively just includes the CS file and it builds as part of the consuming app... 🤔 @Sergio0694 thoughts here? Is this the article you've been looking at for this 'feature'?

Copy link
Member Author

@shweaver-MSFT shweaver-MSFT Mar 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved MsalProvider to it's own package, CommunityToolkit.Net.Authentication.Msal, and it's now based on the official Microsoft.Identity.Client.Extensions.Msal library.

I looked into the source code only package, but it has an unfortunate side effect of not being able to use project references anymore. Which means I can't reference the msal package from the sample app, because it emits a nuget from build, not a DLL. I think it's probably fine to leave it as a typical, dll-emitting package imo.

</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -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 CommunityToolkit.Net.Authentication.Extensions
{
/// <summary>
/// Helpers for Graph related HTTP Headers.
/// </summary>
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)
{
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@
// 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;

namespace Microsoft.Toolkit.Graph.Providers
namespace CommunityToolkit.Net.Authentication
{
/// <summary>
/// <see cref="IAuthenticationProvider"/> helper wrapper to expose more states around the authentication process for graph controls.
Expand All @@ -21,15 +18,10 @@ public interface IProvider : IAuthenticationProvider
/// </summary>
ProviderState State { get; }

/// <summary>
/// Gets the <see cref="GraphServiceClient"/> object to access the Microsoft Graph APIs.
/// </summary>
GraphServiceClient Graph { get; }

/// <summary>
/// Event called when the login <see cref="State"/> changes.
/// </summary>
event EventHandler<StateChangedEventArgs> StateChanged;
event EventHandler<ProviderStateChangedEventArgs> StateChanged;

/// <summary>
/// Login the user.
Expand Down
60 changes: 60 additions & 0 deletions CommunityToolkit.Net.Authentication/MockProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// 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 CommunityToolkit.Net.Authentication.Extensions;

namespace CommunityToolkit.Net.Authentication
{
/// <summary>
/// Provider to connect to the example data set for Microsoft Graph. Useful for prototyping and samples.
/// </summary>
public class MockProvider : BaseProvider
{
private const string GRAPH_PROXY_URL = "https://proxy.apisandbox.msdn.microsoft.com/svc?url=";

/// <summary>
/// Initializes a new instance of the <see cref="MockProvider"/> class.
/// </summary>
/// <param name="signedIn">Configuration for the MockProvider.</param>
public MockProvider(bool signedIn = true)
{
State = signedIn ? ProviderState.SignedIn : ProviderState.SignedOut;
}

/// <inheritdoc/>
public override Task AuthenticateRequestAsync(HttpRequestMessage request)
{
// Append the SDK version header
AddSdkVersion(request);

// Append the token auth header
request.AddMockProviderToken();

// Prepend Proxy Service URI
var requestUri = request.RequestUri.ToString();
request.RequestUri = new Uri(GRAPH_PROXY_URL + Uri.EscapeDataString(requestUri));

return Task.FromResult(0);
}

/// <inheritdoc/>
public override async Task LoginAsync()
{
State = ProviderState.Loading;
await Task.Delay(3000);
State = ProviderState.SignedIn;
}

/// <inheritdoc/>
public override async Task LogoutAsync()
{
State = ProviderState.Loading;
await Task.Delay(3000);
State = ProviderState.SignedOut;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,93 +3,61 @@
// 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 CommunityToolkit.Net.Authentication
{
//// TODO: Move some of this to a simple base-class for non-MSAL parts related to Provider only and properties?

/// <summary>
/// <a href="https://github.com/AzureAD/microsoft-authentication-library-for-dotnet">MSAL.NET</a> provider helper for tracking authentication state using an <see cref="IAuthenticationProvider"/> class.
/// </summary>
public class MsalProvider : IProvider
public class MsalProvider : BaseProvider
{
/// <summary>
/// Gets or sets the MSAL.NET Client used to authenticate the user.
/// </summary>
protected IPublicClientApplication Client { get; set; }

/// <summary>
/// Gets or sets the provider used by the graph to manage requests.
/// Gets the MSAL.NET Client used to authenticate the user.
/// </summary>
protected IAuthenticationProvider Provider { get; set; }

private ProviderState _state = ProviderState.Loading;

/// <inheritdoc/>
public ProviderState State
{
get
{
return _state;
}

private set
{
var current = _state;
_state = value;

StateChanged?.Invoke(this, new StateChangedEventArgs(current, _state));
}
}

/// <inheritdoc/>
public GraphServiceClient Graph { get; private set; }

/// <inheritdoc/>
public event EventHandler<StateChangedEventArgs> StateChanged;
protected IPublicClientApplication Client { get; private set; }

/// <summary>
/// Initializes a new instance of the <see cref="MsalProvider"/> class. <see cref="CreateAsync"/>.
/// Gets the provider used by the graph to manage requests.
/// </summary>
private MsalProvider()
{
}
protected IAuthenticationProvider Provider { get; private set; }

/// <summary>
/// Initializes a new instance of the <see cref="MsalProvider"/> class.
/// </summary>
/// <param name="client">Existing <see cref="IPublicClientApplication"/> instance.</param>
/// <param name="provider">Existing <see cref="IAuthenticationProvider"/> instance.</param>
/// <returns>A <see cref="Task"/> returning a <see cref="MsalProvider"/> instance.</returns>
public static async Task<MsalProvider> CreateAsync(IPublicClientApplication client, IAuthenticationProvider provider)
/// <param name="clientid">Registered ClientId.</param>
/// <param name="redirectUri">RedirectUri for auth response.</param>
/// <param name="scopes">List of Scopes to initially request.</param>
public MsalProvider(string clientid, string redirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient", string[] scopes = null)
{
//// TODO: Check all config provided

var msal = new MsalProvider
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)
{
Client = client,
Provider = provider,
};

msal.Graph = new GraphServiceClient(msal);
scopes = new string[] { string.Empty };
}

await msal.TrySilentSignInAsync();
Client = client;
Provider = new InteractiveAuthenticationProvider(client, scopes);

return msal;
_ = TrySilentSignInAsync();
}

/// <inheritdoc/>
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
public override async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
request.AddSdkVersion();
AddSdkVersion(request);

try
{
Expand Down Expand Up @@ -159,14 +127,14 @@ public async Task TrySilentSignInAsync()
}

/// <inheritdoc/>
public async Task LoginAsync()
public override async Task LoginAsync()
{
// Force fake request to start auth process
await AuthenticateRequestAsync(new System.Net.Http.HttpRequestMessage());
}

/// <inheritdoc/>
public async Task LogoutAsync()
public override async Task LogoutAsync()
{
// Forcibly remove each user.
foreach (var user in await Client.GetAccountsAsync())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using System;
using System.ComponentModel;

namespace Microsoft.Toolkit.Graph.Providers
namespace CommunityToolkit.Net.Authentication
{
/// <summary>
/// Shared provider manager used by controls in Microsoft.Toolkit.Graph.Controls to authenticate and call the Microsoft Graph.
Expand All @@ -15,7 +15,7 @@ namespace Microsoft.Toolkit.Graph.Providers
/// ProviderManager.Instance.GlobalProvider = await MsalProvider.CreateAsync(...);
/// </code>
/// </example>
public class ProviderManager : INotifyPropertyChanged
public partial class ProviderManager : INotifyPropertyChanged
{
/// <summary>
/// Gets the name of the toolkit client to identify self in Graph calls.
Expand Down Expand Up @@ -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));
}
Expand Down
Loading