Browse Source

Update the client console sandbox to support refreshing the user authentication

pull/1969/head
Kévin Chalet 3 years ago
parent
commit
d2a35e844f
  1. 86
      sandbox/OpenIddict.Sandbox.Console.Client/InteractiveService.cs
  2. 2
      src/OpenIddict.Server/OpenIddictServerHandlers.Protection.cs
  3. 4
      src/OpenIddict.Server/OpenIddictServerHandlers.cs

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

@ -39,8 +39,6 @@ public class InteractiveService : BackgroundService
try try
{ {
ClaimsPrincipal principal;
// Resolve the server configuration and determine the type of flow // Resolve the server configuration and determine the type of flow
// to use depending on the supported grants and the user selection. // to use depending on the supported grants and the user selection.
var configuration = await _service.GetServerConfigurationByProviderNameAsync(provider, stoppingToken); var configuration = await _service.GetServerConfigurationByProviderNameAsync(provider, stoppingToken);
@ -75,14 +73,30 @@ public class InteractiveService : BackgroundService
AnsiConsole.MarkupLine("[cyan]Waiting for the user to approve the authorization demand.[/]"); AnsiConsole.MarkupLine("[cyan]Waiting for the user to approve the authorization demand.[/]");
// Wait for the user to complete the demand on the other device. // Wait for the user to complete the demand on the other device.
principal = (await _service.AuthenticateWithDeviceAsync(new() var response = await _service.AuthenticateWithDeviceAsync(new()
{ {
CancellationToken = stoppingToken, CancellationToken = stoppingToken,
DeviceCode = result.DeviceCode, DeviceCode = result.DeviceCode,
Interval = result.Interval, Interval = result.Interval,
ProviderName = provider, ProviderName = provider,
Timeout = result.ExpiresIn < TimeSpan.FromMinutes(5) ? result.ExpiresIn : TimeSpan.FromMinutes(5) Timeout = result.ExpiresIn < TimeSpan.FromMinutes(5) ? result.ExpiresIn : TimeSpan.FromMinutes(5)
})).Principal; });
AnsiConsole.MarkupLine("[green]Device authentication successful:[/]");
AnsiConsole.Write(CreateClaimTable(response.Principal));
// If a refresh token was returned by the authorization server, ask the user
// if the access token should be refreshed using the refresh_token grant.
if (!string.IsNullOrEmpty(response.RefreshToken) && await UseRefreshTokenGrantAsync(stoppingToken))
{
AnsiConsole.MarkupLine("[green]Token refreshing successful:[/]");
AnsiConsole.Write(CreateClaimTable((await _service.AuthenticateWithRefreshTokenAsync(new()
{
CancellationToken = stoppingToken,
ProviderName = provider,
RefreshToken = response.RefreshToken
})).Principal));
}
} }
else else
@ -99,29 +113,28 @@ public class InteractiveService : BackgroundService
AnsiConsole.MarkupLine("[cyan]Waiting for the user to approve the authorization demand.[/]"); AnsiConsole.MarkupLine("[cyan]Waiting for the user to approve the authorization demand.[/]");
// Wait for the user to complete the authorization process. // Wait for the user to complete the authorization process.
principal = (await _service.AuthenticateInteractivelyAsync(new() var response = await _service.AuthenticateInteractivelyAsync(new()
{ {
CancellationToken = stoppingToken, CancellationToken = stoppingToken,
Nonce = result.Nonce Nonce = result.Nonce
})).Principal; });
}
AnsiConsole.MarkupLine("[green]Authentication successful:[/]");
var table = new Table() AnsiConsole.MarkupLine("[green]Interactive authentication successful:[/]");
.AddColumn(new TableColumn("Claim type").Centered()) AnsiConsole.Write(CreateClaimTable(response.Principal));
.AddColumn(new TableColumn("Claim value type").Centered())
.AddColumn(new TableColumn("Claim value").Centered());
foreach (var claim in principal.Claims) // If a refresh token was returned by the authorization server, ask the user
{ // if the access token should be refreshed using the refresh_token grant.
table.AddRow( if (!string.IsNullOrEmpty(response.RefreshToken) && await UseRefreshTokenGrantAsync(stoppingToken))
claim.Type.EscapeMarkup(), {
claim.ValueType.EscapeMarkup(), AnsiConsole.MarkupLine("[green]Token refreshing successful:[/]");
claim.Value.EscapeMarkup()); AnsiConsole.Write(CreateClaimTable((await _service.AuthenticateWithRefreshTokenAsync(new()
{
CancellationToken = stoppingToken,
ProviderName = provider,
RefreshToken = response.RefreshToken
})).Principal));
}
} }
AnsiConsole.Write(table);
} }
catch (OperationCanceledException) catch (OperationCanceledException)
@ -140,6 +153,25 @@ public class InteractiveService : BackgroundService
} }
} }
static Table CreateClaimTable(ClaimsPrincipal principal)
{
var table = new Table()
.LeftAligned()
.AddColumn("Claim type")
.AddColumn("Claim value type")
.AddColumn("Claim value");
foreach (var claim in principal.Claims)
{
table.AddRow(
claim.Type.EscapeMarkup(),
claim.ValueType.EscapeMarkup(),
claim.Value.EscapeMarkup());
}
return table;
}
static Task<bool> UseDeviceAuthorizationGrantAsync(CancellationToken cancellationToken) static Task<bool> UseDeviceAuthorizationGrantAsync(CancellationToken cancellationToken)
{ {
static bool Prompt() => AnsiConsole.Prompt(new ConfirmationPrompt( static bool Prompt() => AnsiConsole.Prompt(new ConfirmationPrompt(
@ -152,6 +184,18 @@ public class InteractiveService : BackgroundService
return WaitAsync(Task.Run(Prompt, cancellationToken), cancellationToken); return WaitAsync(Task.Run(Prompt, cancellationToken), cancellationToken);
} }
static Task<bool> UseRefreshTokenGrantAsync(CancellationToken cancellationToken)
{
static bool Prompt() => AnsiConsole.Prompt(new ConfirmationPrompt(
"Would you like to refresh the user authentication using the refresh token grant?")
{
DefaultValue = false,
ShowDefaultValue = true
});
return WaitAsync(Task.Run(Prompt, cancellationToken), cancellationToken);
}
Task<string> GetSelectedProviderAsync(CancellationToken cancellationToken) Task<string> GetSelectedProviderAsync(CancellationToken cancellationToken)
{ {
async Task<string> PromptAsync() => AnsiConsole.Prompt(new SelectionPrompt<OpenIddictClientRegistration>() async Task<string> PromptAsync() => AnsiConsole.Prompt(new SelectionPrompt<OpenIddictClientRegistration>()

2
src/OpenIddict.Server/OpenIddictServerHandlers.Protection.cs

@ -132,7 +132,7 @@ public static partial class OpenIddictServerHandlers
parameters.IssuerSigningKeyResolver = (_, token, _, _) => Task.Run(async () => parameters.IssuerSigningKeyResolver = (_, token, _, _) => Task.Run(async () =>
{ {
// Resolve the client application corresponding to the token issuer and retrieve // Resolve the client application corresponding to the token issuer and retrieve
// the signing keys from to the JSON Web Key set attached to the client application. // the signing keys from the JSON Web Key set attached to the client application.
// //
// Important: at this stage, the issuer isn't guaranteed to be valid or legitimate. // Important: at this stage, the issuer isn't guaranteed to be valid or legitimate.
var application = await _applicationManager.FindByClientIdAsync(token.Issuer); var application = await _applicationManager.FindByClientIdAsync(token.Issuer);

4
src/OpenIddict.Server/OpenIddictServerHandlers.cs

@ -1078,7 +1078,7 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId)); Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
// Don't validate the client type on endpoint that don't support client authentication. // Don't validate the client type on endpoints that don't support client authentication.
if (context.EndpointType is OpenIddictServerEndpointType.Authorization or if (context.EndpointType is OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.Logout or OpenIddictServerEndpointType.Logout or
OpenIddictServerEndpointType.Userinfo or OpenIddictServerEndpointType.Userinfo or
@ -1187,7 +1187,7 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId)); Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
Debug.Assert(!string.IsNullOrEmpty(context.ClientSecret), SR.FormatID4000(Parameters.ClientSecret)); Debug.Assert(!string.IsNullOrEmpty(context.ClientSecret), SR.FormatID4000(Parameters.ClientSecret));
// Don't validate the client secret on endpoint that don't support client authentication. // Don't validate the client secret on endpoints that don't support client authentication.
if (context.EndpointType is OpenIddictServerEndpointType.Authorization or if (context.EndpointType is OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.Logout or OpenIddictServerEndpointType.Logout or
OpenIddictServerEndpointType.Userinfo or OpenIddictServerEndpointType.Userinfo or

Loading…
Cancel
Save