diff --git a/sandbox/OpenIddict.Sandbox.Console.Client/InteractiveService.cs b/sandbox/OpenIddict.Sandbox.Console.Client/InteractiveService.cs index 0a844a3a..e19c9ccf 100644 --- a/sandbox/OpenIddict.Sandbox.Console.Client/InteractiveService.cs +++ b/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; } diff --git a/sandbox/OpenIddict.Sandbox.WinForms.Client/MainForm.Designer.cs b/sandbox/OpenIddict.Sandbox.WinForms.Client/MainForm.Designer.cs index 4f50811a..39176684 100644 --- a/sandbox/OpenIddict.Sandbox.WinForms.Client/MainForm.Designer.cs +++ b/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; } \ No newline at end of file diff --git a/sandbox/OpenIddict.Sandbox.WinForms.Client/MainForm.cs b/sandbox/OpenIddict.Sandbox.WinForms.Client/MainForm.cs index 37d76a9f..bedf6d0b 100644 --- a/sandbox/OpenIddict.Sandbox.WinForms.Client/MainForm.cs +++ b/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? 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; } } } \ No newline at end of file diff --git a/sandbox/OpenIddict.Sandbox.WinForms.Client/Worker.cs b/sandbox/OpenIddict.Sandbox.WinForms.Client/Worker.cs index d71c4aca..958395bf 100644 --- a/sandbox/OpenIddict.Sandbox.WinForms.Client/Worker.cs +++ b/sandbox/OpenIddict.Sandbox.WinForms.Client/Worker.cs @@ -20,40 +20,26 @@ public class Worker : IHostedService var context = scope.ServiceProvider.GetRequiredService(); 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; diff --git a/sandbox/OpenIddict.Sandbox.Wpf.Client/MainWindow.xaml b/sandbox/OpenIddict.Sandbox.Wpf.Client/MainWindow.xaml index b38b3b18..105046f3 100644 --- a/sandbox/OpenIddict.Sandbox.Wpf.Client/MainWindow.xaml +++ b/sandbox/OpenIddict.Sandbox.Wpf.Client/MainWindow.xaml @@ -6,7 +6,8 @@ mc:Ignorable="d" Title="OpenIddict WPF client" Height="450" Width="800"> -