-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Change Windows implementation with our own solution
- Loading branch information
1 parent
47ef0f9
commit 3a4b412
Showing
22 changed files
with
1,630 additions
and
233 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<?xml version="1.0"?> | ||
<package> | ||
<metadata> | ||
<id>Auth0.OidcClient.MAUI</id> | ||
<version>1.0.0-beta.0</version> | ||
<authors>Auth0</authors> | ||
<owners>Auth0</owners> | ||
<license type="expression">Apache-2.0</license> | ||
<projectUrl>https://github.com/auth0/auth0-oidc-client-net</projectUrl> | ||
<icon>Auth0Icon.png</icon> | ||
<requireLicenseAcceptance>false</requireLicenseAcceptance> | ||
<description>Auth0 OIDC Client for MAUI apps</description> | ||
<releaseNotes></releaseNotes> | ||
<copyright>Copyright 2017-2023 Auth0, Inc.</copyright> | ||
<tags>Auth0 OIDC MAUI</tags> | ||
<dependencies> | ||
<group targetFramework="net6.0-android29.0"> | ||
<dependency id="Auth0.OidcClient.Core" version="3.4.1" /> | ||
<dependency id="IdentityModel.OidcClient" version="5.2.1" /> | ||
</group> | ||
<group targetFramework="net6.0-ios13.0"> | ||
<dependency id="Auth0.OidcClient.Core" version="3.4.1" /> | ||
<dependency id="IdentityModel.OidcClient" version="5.2.1" /> | ||
<dependency id="System.Runtime.InteropServices.NFloat.Internal" version="6.0.1" /> | ||
</group> | ||
<group targetFramework="net6.0-maccatalyst14.0"> | ||
<dependency id="Auth0.OidcClient.Core" version="3.4.1" /> | ||
<dependency id="IdentityModel.OidcClient" version="5.2.1" /> | ||
<dependency id="System.Runtime.InteropServices.NFloat.Internal" version="6.0.1" /> | ||
</group> | ||
<group targetFramework="net6.0-windows10.0.19041"> | ||
<dependency id="Auth0.OidcClient.Core" version="3.4.1" /> | ||
<dependency id="IdentityModel.OidcClient" version="5.2.1" /> | ||
<dependency id="Microsoft.WindowsAppSDK" version="1.2.221209.1" /> | ||
</group> | ||
</dependencies> | ||
</metadata> | ||
<files> | ||
<file src="..\src\Auth0.OidcClient.MAUI\bin\Release\net6.0-android\Auth0.OidcClient.dll" target="lib\net6.0-android29.0" /> | ||
<file src="..\src\Auth0.OidcClient.MAUI\bin\Release\net6.0-android\Auth0.OidcClient.xml" target="lib\net6.0-android29.0" /> | ||
<file src="..\src\Auth0.OidcClient.MAUI\bin\Release\net6.0-ios\Auth0.OidcClient.dll" target="lib\net6.0-ios13.0" /> | ||
<file src="..\src\Auth0.OidcClient.MAUI\bin\Release\net6.0-ios\Auth0.OidcClient.xml" target="lib\net6.0-ios13.0" /> | ||
<file src="..\src\Auth0.OidcClient.MAUI\bin\Release\net6.0-maccatalyst\Auth0.OidcClient.dll" target="lib\net6.0-maccatalyst14.0" /> | ||
<file src="..\src\Auth0.OidcClient.MAUI\bin\Release\net6.0-maccatalyst\Auth0.OidcClient.xml" target="lib\net6.0-maccatalyst14.0" /> | ||
<file src="..\src\Auth0.OidcClient.MAUI\bin\Release\net6.0-windows10.0.19041.0\Auth0.OidcClient.dll" target="lib\net6.0-windows10.0.19041" /> | ||
<file src="..\src\Auth0.OidcClient.MAUI\bin\Release\net6.0-windows10.0.19041.0\Auth0.OidcClient.xml" target="lib\net6.0-windows10.0.19041" /> | ||
<file src="..\src\Auth0.OidcClient.MAUI\bin\Release\net6.0-windows10.0.19041.0\Auth0.OidcClient.MAUI.Platforms.Windows.dll" target="lib\net6.0-windows10.0.19041" /> | ||
<file src="..\build\Auth0Icon.png" /> | ||
</files> | ||
</package> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
using Microsoft.Windows.AppLifecycle; | ||
using Windows.ApplicationModel.Activation; | ||
|
||
namespace Auth0.OidcClient.Platforms.Windows | ||
{ | ||
public interface IActivator | ||
{ | ||
bool RedirectActivationChecked { get; } | ||
bool CheckRedirectionActivation(); | ||
} | ||
|
||
/// <summary> | ||
/// Activator class used to enable protocol activation check and redirects activation to the correct application instance | ||
/// </summary> | ||
public sealed class Activator : IActivator | ||
{ | ||
private readonly IAppInstanceProxy _appInstanceProxy; | ||
|
||
public static readonly Activator Default = new Activator(new AppInstanceProxy()); | ||
|
||
internal Activator(IAppInstanceProxy appInstanceProxy) | ||
{ | ||
_appInstanceProxy = appInstanceProxy; | ||
} | ||
|
||
/// <summary> | ||
/// Boolean indication the redirect activation was checked | ||
/// </summary> | ||
public bool RedirectActivationChecked { get; internal set; } | ||
|
||
/// <summary> | ||
/// Performs a protocol activation check and redirects activation to the correct application instance. | ||
/// </summary> | ||
public bool CheckRedirectionActivation() | ||
{ | ||
var activatedEventArgs = _appInstanceProxy.GetCurrentActivatedEventArgs(); | ||
|
||
RedirectActivationChecked = true; | ||
|
||
if (activatedEventArgs is null || activatedEventArgs.Kind != ExtendedActivationKind.Protocol || activatedEventArgs.Data is not IProtocolActivatedEventArgs protocolArgs) | ||
{ | ||
return false; | ||
} | ||
|
||
var ctx = RedirectionContextManager.GetRedirectionContext(protocolArgs); | ||
|
||
if (ctx is not null && ctx.AppInstanceKey is not null && ctx.TaskId is not null) | ||
{ | ||
return _appInstanceProxy.RedirectActivationToAsync(ctx.AppInstanceKey, activatedEventArgs); | ||
} | ||
else | ||
{ | ||
_appInstanceProxy.FindOrRegisterForKey(); | ||
} | ||
return false; | ||
} | ||
|
||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
src/Auth0.OidcClient.MAUI.Platforms.Windows/AppActivationArguments.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using Microsoft.Windows.AppLifecycle; | ||
|
||
namespace Auth0.OidcClient.Platforms.Windows; | ||
|
||
internal interface IAppActivationArguments | ||
{ | ||
ExtendedActivationKind Kind { get; set; } | ||
object Data { get; set; } | ||
} | ||
|
||
internal class AppActivationArguments : IAppActivationArguments | ||
{ | ||
public ExtendedActivationKind Kind { get; set; } | ||
public object Data { get; set; } | ||
} |
100 changes: 100 additions & 0 deletions
100
src/Auth0.OidcClient.MAUI.Platforms.Windows/AppInstanceProxy.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
using System.Diagnostics.CodeAnalysis; | ||
using Microsoft.Windows.AppLifecycle; | ||
|
||
namespace Auth0.OidcClient.Platforms.Windows; | ||
|
||
internal interface IAppInstanceProxy | ||
{ | ||
event EventHandler<IAppActivationArguments> Activated; | ||
string GetCurrentAppKey(); | ||
Microsoft.Windows.AppLifecycle.AppActivationArguments GetCurrentActivatedEventArgs(); | ||
|
||
bool RedirectActivationToAsync(string key, | ||
Microsoft.Windows.AppLifecycle.AppActivationArguments activatedEventArgs); | ||
|
||
void FindOrRegisterForKey(); | ||
} | ||
|
||
/// <summary> | ||
/// Excludes from Code Coverage because of the integration with AppInstance.GetCurrent() | ||
/// </summary> | ||
[ExcludeFromCodeCoverage] | ||
internal class AppInstanceProxy : IAppInstanceProxy | ||
{ | ||
public AppInstanceProxy() | ||
{ | ||
AppInstance.GetCurrent().Activated += OnActivated; | ||
} | ||
|
||
public event EventHandler<IAppActivationArguments> Activated; | ||
|
||
protected virtual void OnActivated(object? sender, Microsoft.Windows.AppLifecycle.AppActivationArguments e) | ||
{ | ||
Activated?.Invoke(this, new AppActivationArguments | ||
{ | ||
Kind = e.Kind, | ||
Data = e.Data | ||
}); | ||
} | ||
|
||
/// <summary> | ||
/// Get the current application key. | ||
/// </summary> | ||
/// <remarks> | ||
/// Proxy call to AppInstance.GetCurrent().Key. | ||
/// Used because AppInstance is complicated to use in tests. | ||
/// </remarks> | ||
/// <returns>The key for the current application.</returns> | ||
public virtual string GetCurrentAppKey() | ||
{ | ||
return AppInstance.GetCurrent().Key; | ||
} | ||
|
||
/// <summary> | ||
/// Get the current application <see cref="AppActivationArguments"/> | ||
/// </summary> | ||
/// <remarks> | ||
/// Proxy call to AppInstance.GetCurrent().GetActivatedEventArgs(). | ||
/// Used because AppInstance is complicated to use in tests. | ||
/// </remarks> | ||
/// <returns>Null if no current application instance is found, or the corresponding <see cref="AppActivationArguments"/>.</returns> | ||
public virtual Microsoft.Windows.AppLifecycle.AppActivationArguments GetCurrentActivatedEventArgs() | ||
{ | ||
return AppInstance.GetCurrent()?.GetActivatedEventArgs(); | ||
} | ||
|
||
/// <summary> | ||
/// Redirect the activation to the correct application instance and kill the current process. | ||
/// </summary> | ||
/// <param name="key">Key of the application to activated</param> | ||
/// <param name="activatedEventArgs"><see cref="AppActivationArguments"/> to pass to the application.</param> | ||
/// <returns>Boolean indicating an application instance was activated.</returns> | ||
public virtual bool RedirectActivationToAsync(string key, Microsoft.Windows.AppLifecycle.AppActivationArguments activatedEventArgs) | ||
{ | ||
var instance = AppInstance.GetInstances().FirstOrDefault(i => i.Key == key); | ||
|
||
if (instance is not null && !instance.IsCurrent) | ||
{ | ||
instance.RedirectActivationToAsync(activatedEventArgs).AsTask().Wait(); | ||
|
||
System.Diagnostics.Process.GetCurrentProcess().Kill(); | ||
|
||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/// <summary> | ||
/// Registers the current application using a new key. | ||
/// </summary> | ||
public virtual void FindOrRegisterForKey() | ||
{ | ||
var instance = AppInstance.GetCurrent(); | ||
|
||
if (string.IsNullOrEmpty(instance.Key)) | ||
{ | ||
AppInstance.FindOrRegisterForKey(Guid.NewGuid().ToString()); | ||
} | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
src/Auth0.OidcClient.MAUI.Platforms.Windows/Auth0.OidcClient.MAUI.Platforms.Windows.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFrameworks>net6.0-windows10.0.19041.0</TargetFrameworks> | ||
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET --> | ||
<!-- <TargetFrameworks>$(TargetFrameworks);net7.0-tizen</TargetFrameworks> --> | ||
<UseMaui>true</UseMaui> | ||
<SingleProject>true</SingleProject> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
|
||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion> | ||
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion> | ||
<AssemblyOriginatorKeyFile>..\..\build\Auth0OidcClientStrongName.snk</AssemblyOriginatorKeyFile> | ||
</PropertyGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
using System.Runtime.InteropServices; | ||
using System.Text; | ||
using System.Xml; | ||
using System.Xml.Linq; | ||
using System.Xml.XPath; | ||
|
||
namespace Auth0.OidcClient.Platforms.Windows | ||
{ | ||
internal interface IHelpers | ||
{ | ||
bool IsAppPackaged { get; } | ||
bool IsUriProtocolDeclared(string scheme); | ||
void OpenBrowser(Uri uri); | ||
} | ||
|
||
internal class Helpers : IHelpers | ||
{ | ||
#pragma warning disable SA1203 // Constants should appear before fields | ||
private const long AppModelErrorNoPackage = 15700L; | ||
#pragma warning restore SA1203 // Constants should appear before fields | ||
|
||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] | ||
private static extern int GetCurrentPackageFullName(ref int packageFullNameLength, System.Text.StringBuilder packageFullName); | ||
|
||
/// <summary> | ||
/// Helper property to verify the application is packaged. | ||
/// </summary> | ||
/// <remarks> | ||
/// Original source: https://github.com/dotMorten/WinUIEx | ||
/// </remarks> | ||
/// <returns>A boolean indicate whether or not the app is packaged.</returns> | ||
public bool IsAppPackaged | ||
{ | ||
get | ||
{ | ||
try | ||
{ | ||
// Application is MSIX packaged if it has an identity: https://learn.microsoft.com/en-us/windows/msix/detect-package-identity | ||
int length = 0; | ||
var sb = new StringBuilder(0); | ||
int result = GetCurrentPackageFullName(ref length, sb); | ||
return result != AppModelErrorNoPackage; | ||
} | ||
catch | ||
{ | ||
return false; | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Helper method to verify the scheme is defined as a protocol in the AppxManifest.xml files | ||
/// </summary> | ||
/// <remarks> | ||
/// Original source: https://github.com/dotMorten/WinUIEx | ||
/// </remarks> | ||
/// <param name="scheme">The scheme expected to be declared.</param> | ||
/// <returns>A boolean indicate whether or not the scheme is declared as an Uri protocol.</returns> | ||
public bool IsUriProtocolDeclared(string scheme) | ||
{ | ||
if (global::Windows.ApplicationModel.Package.Current is null) | ||
return false; | ||
var docPath = Path.Combine(global::Windows.ApplicationModel.Package.Current.InstalledLocation.Path, "AppxManifest.xml"); | ||
var doc = XDocument.Load(docPath, LoadOptions.None); | ||
var reader = doc.CreateReader(); | ||
var namespaceManager = new XmlNamespaceManager(reader.NameTable); | ||
namespaceManager.AddNamespace("x", "http://schemas.microsoft.com/appx/manifest/foundation/windows10"); | ||
namespaceManager.AddNamespace("uap", "http://schemas.microsoft.com/appx/manifest/uap/windows10"); | ||
|
||
// Check if the protocol was declared | ||
var decl = doc.Root?.XPathSelectElements($"//uap:Extension[@Category='windows.protocol']/uap:Protocol[@Name='{scheme}']", namespaceManager); | ||
|
||
return decl != null && decl.Any(); | ||
} | ||
|
||
/// <summary> | ||
/// Helper method to open the browser through the url.dll. | ||
/// </summary> | ||
/// <param name="uri">The Uri to open</param> | ||
public void OpenBrowser(Uri uri) | ||
{ | ||
var process = new System.Diagnostics.Process(); | ||
process.StartInfo.FileName = "rundll32.exe"; | ||
process.StartInfo.Arguments = $"url.dll,FileProtocolHandler \"{uri.ToString().Replace("\"", "%22")}\""; | ||
process.StartInfo.UseShellExecute = true; | ||
process.Start(); | ||
} | ||
|
||
public static string Encode(string value) | ||
{ | ||
var bytes = Encoding.UTF8.GetBytes(value); | ||
return Convert.ToBase64String(bytes); | ||
} | ||
|
||
public static string Decode(string value) | ||
{ | ||
var bytes = Convert.FromBase64String(value); | ||
return Encoding.UTF8.GetString(bytes); | ||
} | ||
} | ||
} |
Oops, something went wrong.