Browse Source

Update the client console sandbox to support refreshing the user authentication

pull/1969/head
Kévin Chalet 2 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
{
ClaimsPrincipal principal;
// Resolve the server configuration and determine the type of flow
// to use depending on the supported grants and the user selection.
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.[/]");
// 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,
DeviceCode = result.DeviceCode,
Interval = result.Interval,
ProviderName = provider,
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
@ -99,29 +113,28 @@ public class InteractiveService : BackgroundService
AnsiConsole.MarkupLine("[cyan]Waiting for the user to approve the authorization demand.[/]");
// Wait for the user to complete the authorization process.
principal = (await _service.AuthenticateInteractivelyAsync(new()
var response = await _service.AuthenticateInteractivelyAsync(new()
{
CancellationToken = stoppingToken,
Nonce = result.Nonce
})).Principal;
}
AnsiConsole.MarkupLine("[green]Authentication successful:[/]");
});
var table = new Table()
.AddColumn(new TableColumn("Claim type").Centered())
.AddColumn(new TableColumn("Claim value type").Centered())
.AddColumn(new TableColumn("Claim value").Centered());
AnsiConsole.MarkupLine("[green]Interactive authentication successful:[/]");
AnsiConsole.Write(CreateClaimTable(response.Principal));
foreach (var claim in principal.Claims)
{
table.AddRow(
claim.Type.EscapeMarkup(),
claim.ValueType.EscapeMarkup(),
claim.Value.EscapeMarkup());
// 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));
}
}
AnsiConsole.Write(table);
}
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 bool Prompt() => AnsiConsole.Prompt(new ConfirmationPrompt(
@ -152,6 +184,18 @@ public class InteractiveService : BackgroundService
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)
{
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 () =>
{
// 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.
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));
// 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
OpenIddictServerEndpointType.Logout 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.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
OpenIddictServerEndpointType.Logout or
OpenIddictServerEndpointType.Userinfo or

Loading…
Cancel
Save