Browse Source

Update the WinForms/WPF samples to allow selecting a preferred service for local server authentication

pull/1940/head
Kévin Chalet 2 years ago
parent
commit
08eadde6ba
  1. 2
      sandbox/OpenIddict.Sandbox.Console.Client/InteractiveService.cs
  2. 21
      sandbox/OpenIddict.Sandbox.WinForms.Client/MainForm.Designer.cs
  3. 139
      sandbox/OpenIddict.Sandbox.WinForms.Client/MainForm.cs
  4. 40
      sandbox/OpenIddict.Sandbox.WinForms.Client/Worker.cs
  5. 5
      sandbox/OpenIddict.Sandbox.Wpf.Client/MainWindow.xaml
  6. 79
      sandbox/OpenIddict.Sandbox.Wpf.Client/MainWindow.xaml.cs
  7. 40
      sandbox/OpenIddict.Sandbox.Wpf.Client/Worker.cs

2
sandbox/OpenIddict.Sandbox.Console.Client/InteractiveService.cs

@ -71,6 +71,7 @@ public class InteractiveService : BackgroundService
// Wait for the user to complete the demand on the other device.
principal = (await _service.AuthenticateWithDeviceAsync(new()
{
CancellationToken = stoppingToken,
DeviceCode = result.DeviceCode,
Interval = result.Interval,
ProviderName = provider,
@ -92,6 +93,7 @@ public class InteractiveService : BackgroundService
// Wait for the user to complete the authorization process.
principal = (await _service.AuthenticateInteractivelyAsync(new()
{
CancellationToken = stoppingToken,
Nonce = result.Nonce
})).Principal;
}

21
sandbox/OpenIddict.Sandbox.WinForms.Client/MainForm.Designer.cs

@ -30,13 +30,14 @@ partial class MainForm
{
this.LocalLogin = new System.Windows.Forms.Button();
this.GitHubLogin = new System.Windows.Forms.Button();
this.LocalLoginWithGitHub = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// LocalLogin
//
this.LocalLogin.Location = new System.Drawing.Point(258, 93);
this.LocalLogin.Location = new System.Drawing.Point(214, 32);
this.LocalLogin.Name = "LocalLogin";
this.LocalLogin.Size = new System.Drawing.Size(283, 83);
this.LocalLogin.Size = new System.Drawing.Size(391, 83);
this.LocalLogin.TabIndex = 0;
this.LocalLogin.Text = "Log in using the local server";
this.LocalLogin.UseVisualStyleBackColor = true;
@ -44,20 +45,31 @@ partial class MainForm
//
// GitHubLogin
//
this.GitHubLogin.Location = new System.Drawing.Point(258, 258);
this.GitHubLogin.Location = new System.Drawing.Point(214, 321);
this.GitHubLogin.Name = "GitHubLogin";
this.GitHubLogin.Size = new System.Drawing.Size(283, 83);
this.GitHubLogin.Size = new System.Drawing.Size(391, 83);
this.GitHubLogin.TabIndex = 1;
this.GitHubLogin.Text = "Log in using GitHub";
this.GitHubLogin.UseVisualStyleBackColor = true;
this.GitHubLogin.Click += new System.EventHandler(this.GitHubLoginButton_Click);
//
// LocalLoginWithGitHub
//
this.LocalLoginWithGitHub.Location = new System.Drawing.Point(214, 177);
this.LocalLoginWithGitHub.Name = "LocalLoginWithGitHub";
this.LocalLoginWithGitHub.Size = new System.Drawing.Size(391, 83);
this.LocalLoginWithGitHub.TabIndex = 0;
this.LocalLoginWithGitHub.Text = "Log in using the local server (preferred service: GitHub)";
this.LocalLoginWithGitHub.UseVisualStyleBackColor = true;
this.LocalLoginWithGitHub.Click += new System.EventHandler(this.LocalLoginWithGitHubButton_Click);
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.GitHubLogin);
this.Controls.Add(this.LocalLoginWithGitHub);
this.Controls.Add(this.LocalLogin);
this.Name = "MainForm";
this.Text = "OpenIddict WinForms client";
@ -69,4 +81,5 @@ partial class MainForm
private Button LocalLogin;
private Button GitHubLogin;
private Button LocalLoginWithGitHub;
}

139
sandbox/OpenIddict.Sandbox.WinForms.Client/MainForm.cs

@ -1,4 +1,5 @@
using Dapplo.Microsoft.Extensions.Hosting.WinForms;
using OpenIddict.Abstractions;
using OpenIddict.Client;
using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Abstractions.OpenIddictExceptions;
@ -20,88 +21,112 @@ public partial class MainForm : Form, IWinFormsShell
private async void LocalLoginButton_Click(object sender, EventArgs e)
=> await AuthenticateAsync("Local");
private async void LocalLoginWithGitHubButton_Click(object sender, EventArgs e)
=> await AuthenticateAsync("Local", new()
{
[Parameters.IdentityProvider] = Providers.GitHub
});
private async void GitHubLoginButton_Click(object sender, EventArgs e)
=> await AuthenticateAsync(Providers.GitHub);
private async Task AuthenticateAsync(string provider)
private async Task AuthenticateAsync(string provider, Dictionary<string, OpenIddictParameter>? parameters = null)
{
using var source = new CancellationTokenSource(delay: TimeSpan.FromSeconds(90));
// Disable the login buttons to prevent concurrent authentication operations.
LocalLogin.Enabled = false;
LocalLoginWithGitHub.Enabled = false;
GitHubLogin.Enabled = false;
try
{
// Ask OpenIddict to initiate the authentication flow (typically, by starting the system browser).
var result = await _service.ChallengeInteractivelyAsync(new()
{
CancellationToken = source.Token,
ProviderName = provider
});
using var source = new CancellationTokenSource(delay: TimeSpan.FromSeconds(90));
// Wait for the user to complete the authorization process.
var principal = (await _service.AuthenticateInteractivelyAsync(new()
try
{
Nonce = result.Nonce
})).Principal;
// Ask OpenIddict to initiate the authentication flow (typically, by starting the system browser).
var result = await _service.ChallengeInteractivelyAsync(new()
{
AdditionalAuthorizationRequestParameters = parameters,
CancellationToken = source.Token,
ProviderName = provider
});
// Wait for the user to complete the authorization process.
var principal = (await _service.AuthenticateInteractivelyAsync(new()
{
CancellationToken = source.Token,
Nonce = result.Nonce
})).Principal;
#if SUPPORTS_WINFORMS_TASK_DIALOG
TaskDialog.ShowDialog(new TaskDialogPage
{
Caption = "Authentication successful",
Heading = "Authentication successful",
Icon = TaskDialogIcon.ShieldSuccessGreenBar,
Text = $"Welcome, {principal.FindFirst(Claims.Name)!.Value}."
});
TaskDialog.ShowDialog(new TaskDialogPage
{
Caption = "Authentication successful",
Heading = "Authentication successful",
Icon = TaskDialogIcon.ShieldSuccessGreenBar,
Text = $"Welcome, {principal.FindFirst(Claims.Name)!.Value}."
});
#else
MessageBox.Show($"Welcome, {principal.FindFirst(Claims.Name)!.Value}.",
"Authentication successful", MessageBoxButtons.OK, MessageBoxIcon.Information);
MessageBox.Show($"Welcome, {principal.FindFirst(Claims.Name)!.Value}.",
"Authentication successful", MessageBoxButtons.OK, MessageBoxIcon.Information);
#endif
}
}
catch (OperationCanceledException)
{
#if SUPPORTS_WINFORMS_TASK_DIALOG
TaskDialog.ShowDialog(new TaskDialogPage
catch (OperationCanceledException)
{
Caption = "Authentication timed out",
Heading = "Authentication timed out",
Icon = TaskDialogIcon.Warning,
Text = "The authentication process was aborted."
});
#if SUPPORTS_WINFORMS_TASK_DIALOG
TaskDialog.ShowDialog(new TaskDialogPage
{
Caption = "Authentication timed out",
Heading = "Authentication timed out",
Icon = TaskDialogIcon.Warning,
Text = "The authentication process was aborted."
});
#else
MessageBox.Show("The authentication process was aborted.",
"Authentication timed out", MessageBoxButtons.OK, MessageBoxIcon.Warning);
MessageBox.Show("The authentication process was aborted.",
"Authentication timed out", MessageBoxButtons.OK, MessageBoxIcon.Warning);
#endif
}
}
catch (ProtocolException exception) when (exception.Error is Errors.AccessDenied)
{
#if SUPPORTS_WINFORMS_TASK_DIALOG
TaskDialog.ShowDialog(new TaskDialogPage
catch (ProtocolException exception) when (exception.Error is Errors.AccessDenied)
{
Caption = "Authorization denied",
Heading = "Authorization denied",
Icon = TaskDialogIcon.Warning,
Text = "The authorization was denied by the end user."
});
#if SUPPORTS_WINFORMS_TASK_DIALOG
TaskDialog.ShowDialog(new TaskDialogPage
{
Caption = "Authorization denied",
Heading = "Authorization denied",
Icon = TaskDialogIcon.Warning,
Text = "The authorization was denied by the end user."
});
#else
MessageBox.Show("The authorization was denied by the end user.",
"Authorization denied", MessageBoxButtons.OK, MessageBoxIcon.Warning);
MessageBox.Show("The authorization was denied by the end user.",
"Authorization denied", MessageBoxButtons.OK, MessageBoxIcon.Warning);
#endif
}
}
catch
{
#if SUPPORTS_WINFORMS_TASK_DIALOG
TaskDialog.ShowDialog(new TaskDialogPage
catch
{
Caption = "Authentication failed",
Heading = "Authentication failed",
Icon = TaskDialogIcon.Error,
Text = "An error occurred while trying to authenticate the user."
});
#if SUPPORTS_WINFORMS_TASK_DIALOG
TaskDialog.ShowDialog(new TaskDialogPage
{
Caption = "Authentication failed",
Heading = "Authentication failed",
Icon = TaskDialogIcon.Error,
Text = "An error occurred while trying to authenticate the user."
});
#else
MessageBox.Show("An error occurred while trying to authenticate the user.",
"Authentication failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
MessageBox.Show("An error occurred while trying to authenticate the user.",
"Authentication failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
#endif
}
}
finally
{
// Re-enable the login buttons to allow starting a new authentication operation.
LocalLogin.Enabled = true;
LocalLoginWithGitHub.Enabled = true;
GitHubLogin.Enabled = true;
}
}
}

40
sandbox/OpenIddict.Sandbox.WinForms.Client/Worker.cs

@ -20,40 +20,26 @@ public class Worker : IHostedService
var context = scope.ServiceProvider.GetRequiredService<DbContext>();
await context.Database.EnsureCreatedAsync();
RegistryKey? root = null;
// Create the registry entries necessary to handle URI protocol activations.
//
// Note: this sample creates the entry under the current user account (as it doesn't
// require administrator rights), but the registration can also be added globally
// in HKEY_CLASSES_ROOT (in this case, it should be added by a dedicated installer).
//
// Alternatively, the application can be packaged and use windows.protocol to
// register the protocol handler/custom URI scheme with the operation system.
try
{
// Note: this sample creates the entry under the current user account (as it doesn't
// require administrator rights), but the registration can also be added globally
// in HKEY_CLASSES_ROOT (in this case, it should be added by a dedicated installer).
root = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Classes\\com.openiddict.sandbox.winforms.client");
if (root is null)
{
root = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Classes\\com.openiddict.sandbox.winforms.client");
root.SetValue(string.Empty, "URL:com.openiddict.sandbox.winforms.client");
root.SetValue("URL Protocol", string.Empty);
using var command = root.CreateSubKey("shell\\open\\command");
command.SetValue(string.Empty, string.Format("\"{0}\" \"%1\"",
using var root = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Classes\\com.openiddict.sandbox.winforms.client");
root.SetValue(string.Empty, "URL:com.openiddict.sandbox.winforms.client");
root.SetValue("URL Protocol", string.Empty);
using var command = root.CreateSubKey("shell\\open\\command");
command.SetValue(string.Empty, string.Format("\"{0}\" \"%1\"",
#if SUPPORTS_ENVIRONMENT_PROCESS_PATH
Environment.ProcessPath
Environment.ProcessPath
#else
Process.GetCurrentProcess().MainModule.FileName
Process.GetCurrentProcess().MainModule.FileName
#endif
));
}
}
finally
{
root?.Dispose();
}
));
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;

5
sandbox/OpenIddict.Sandbox.Wpf.Client/MainWindow.xaml

@ -6,7 +6,8 @@
mc:Ignorable="d"
Title="OpenIddict WPF client" Height="450" Width="800">
<Grid>
<Button Content="Log in using the local server" HorizontalAlignment="Center" VerticalAlignment="Top" Click="LocalLoginButton_Click" Height="64" Width="252" FontSize="20" Margin="0,130,0,0" />
<Button Content="Log in using GitHub" HorizontalAlignment="Center" VerticalAlignment="Top" Click="GitHubLoginButton_Click" Height="64" Width="252" FontSize="20" Margin="0,234,0,0" />
<Button Name="LocalLogin" Content="Log in using the local server" HorizontalAlignment="Center" VerticalAlignment="Top" Click="LocalLoginButton_Click" Height="64" Width="540" FontSize="20" Margin="0,50,0,0" />
<Button Name="LocalLoginWithGitHub" Content="Log in using the local server (preferred service: GitHub)" HorizontalAlignment="Center" VerticalAlignment="Center" Click="LocalLoginWithGitHubButton_Click" Height="64" Width="539" FontSize="20" />
<Button Name="GitHubLogin" Content="Log in using GitHub" HorizontalAlignment="Center" VerticalAlignment="Bottom" Click="GitHubLoginButton_Click" Height="64" Width="539" FontSize="20" Margin="0,0,0,50" />
</Grid>
</Window>

79
sandbox/OpenIddict.Sandbox.Wpf.Client/MainWindow.xaml.cs

@ -1,5 +1,6 @@
using System.Windows;
using Dapplo.Microsoft.Extensions.Hosting.Wpf;
using OpenIddict.Abstractions;
using OpenIddict.Client;
using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Abstractions.OpenIddictExceptions;
@ -21,48 +22,72 @@ public partial class MainWindow : Window, IWpfShell
private async void LocalLoginButton_Click(object sender, RoutedEventArgs e)
=> await AuthenticateAsync("Local");
private async void LocalLoginWithGitHubButton_Click(object sender, RoutedEventArgs e)
=> await AuthenticateAsync("Local", new()
{
[Parameters.IdentityProvider] = Providers.GitHub
});
private async void GitHubLoginButton_Click(object sender, RoutedEventArgs e)
=> await AuthenticateAsync(Providers.GitHub);
private async Task AuthenticateAsync(string provider)
private async Task AuthenticateAsync(string provider, Dictionary<string, OpenIddictParameter>? parameters = null)
{
using var source = new CancellationTokenSource(delay: TimeSpan.FromSeconds(90));
// Disable the login buttons to prevent concurrent authentication operations.
LocalLogin.IsEnabled = false;
LocalLoginWithGitHub.IsEnabled = false;
GitHubLogin.IsEnabled = false;
try
{
// Ask OpenIddict to initiate the authentication flow (typically, by starting the system browser).
var result = await _service.ChallengeInteractivelyAsync(new()
{
CancellationToken = source.Token,
ProviderName = provider
});
using var source = new CancellationTokenSource(delay: TimeSpan.FromSeconds(90));
// Wait for the user to complete the authorization process.
var principal = (await _service.AuthenticateInteractivelyAsync(new()
try
{
Nonce = result.Nonce
})).Principal;
// Ask OpenIddict to initiate the authentication flow (typically, by starting the system browser).
var result = await _service.ChallengeInteractivelyAsync(new()
{
AdditionalAuthorizationRequestParameters = parameters,
CancellationToken = source.Token,
ProviderName = provider
});
MessageBox.Show($"Welcome, {principal.FindFirst(Claims.Name)!.Value}.",
"Authentication successful", MessageBoxButton.OK, MessageBoxImage.Information);
}
// Wait for the user to complete the authorization process.
var principal = (await _service.AuthenticateInteractivelyAsync(new()
{
CancellationToken = source.Token,
Nonce = result.Nonce
})).Principal;
catch (OperationCanceledException)
{
MessageBox.Show("The authentication process was aborted.",
"Authentication timed out", MessageBoxButton.OK, MessageBoxImage.Warning);
}
MessageBox.Show($"Welcome, {principal.FindFirst(Claims.Name)!.Value}.",
"Authentication successful", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (ProtocolException exception) when (exception.Error is Errors.AccessDenied)
{
MessageBox.Show("The authorization was denied by the end user.",
"Authorization denied", MessageBoxButton.OK, MessageBoxImage.Warning);
catch (OperationCanceledException)
{
MessageBox.Show("The authentication process was aborted.",
"Authentication timed out", MessageBoxButton.OK, MessageBoxImage.Warning);
}
catch (ProtocolException exception) when (exception.Error is Errors.AccessDenied)
{
MessageBox.Show("The authorization was denied by the end user.",
"Authorization denied", MessageBoxButton.OK, MessageBoxImage.Warning);
}
catch
{
MessageBox.Show("An error occurred while trying to authenticate the user.",
"Authentication failed", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
catch
finally
{
MessageBox.Show("An error occurred while trying to authenticate the user.",
"Authentication failed", MessageBoxButton.OK, MessageBoxImage.Error);
// Re-enable the login buttons to allow starting a new authentication operation.
LocalLogin.IsEnabled = true;
LocalLoginWithGitHub.IsEnabled = true;
GitHubLogin.IsEnabled = true;
}
}
}

40
sandbox/OpenIddict.Sandbox.Wpf.Client/Worker.cs

@ -20,40 +20,26 @@ public class Worker : IHostedService
var context = scope.ServiceProvider.GetRequiredService<DbContext>();
await context.Database.EnsureCreatedAsync();
RegistryKey? root = null;
// Create the registry entries necessary to handle URI protocol activations.
//
// Note: this sample creates the entry under the current user account (as it doesn't
// require administrator rights), but the registration can also be added globally
// in HKEY_CLASSES_ROOT (in this case, it should be added by a dedicated installer).
//
// Alternatively, the application can be packaged and use windows.protocol to
// register the protocol handler/custom URI scheme with the operation system.
try
{
// Note: this sample creates the entry under the current user account (as it doesn't
// require administrator rights), but the registration can also be added globally
// in HKEY_CLASSES_ROOT (in this case, it should be added by a dedicated installer).
root = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Classes\\com.openiddict.sandbox.wpf.client");
if (root is null)
{
root = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Classes\\com.openiddict.sandbox.wpf.client");
root.SetValue(string.Empty, "URL:com.openiddict.sandbox.wpf.client");
root.SetValue("URL Protocol", string.Empty);
using var command = root.CreateSubKey("shell\\open\\command");
command.SetValue(string.Empty, string.Format("\"{0}\" \"%1\"",
using var root = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Classes\\com.openiddict.sandbox.wpf.client");
root.SetValue(string.Empty, "URL:com.openiddict.sandbox.wpf.client");
root.SetValue("URL Protocol", string.Empty);
using var command = root.CreateSubKey("shell\\open\\command");
command.SetValue(string.Empty, string.Format("\"{0}\" \"%1\"",
#if SUPPORTS_ENVIRONMENT_PROCESS_PATH
Environment.ProcessPath
Environment.ProcessPath
#else
Process.GetCurrentProcess().MainModule.FileName
Process.GetCurrentProcess().MainModule.FileName
#endif
));
}
}
finally
{
root?.Dispose();
}
));
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;

Loading…
Cancel
Save