Browse Source

Add default scopes fallback for client_credentials/password/token_exchange grants

pull/25356/head
maliming 3 weeks ago
parent
commit
ec38960f0a
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 4
      modules/openiddict/app/OpenIddict.Demo.Server/OpenIddict.Demo.Server.csproj
  2. 7
      modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs
  3. 24
      modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictOptions.cs
  4. 100
      modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Claims/AbpDefaultScopesHandler.cs

4
modules/openiddict/app/OpenIddict.Demo.Server/OpenIddict.Demo.Server.csproj

@ -68,6 +68,10 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
<PrivateAssets>compile; contentFiles; build; buildMultitargeting; buildTransitive; analyzers; native</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
<PrivateAssets>compile; contentFiles; build; buildMultitargeting; buildTransitive; analyzers; native</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>

7
modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs

@ -25,9 +25,16 @@ public class AbpOpenIddictAspNetCoreModule : AbpModule
Configure<AbpOpenIddictClaimsPrincipalOptions>(options =>
{
options.ClaimsPrincipalHandlers.Add<AbpDefaultScopesHandler>();
options.ClaimsPrincipalHandlers.Add<AbpDefaultOpenIddictClaimsPrincipalHandler>();
});
var preActions = context.Services.GetPreConfigureActions<AbpOpenIddictAspNetCoreOptions>();
Configure<AbpOpenIddictAspNetCoreOptions>(options =>
{
preActions.Configure(options);
});
Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationFormats.Add("/Volo/Abp/OpenIddict/Views/{1}/{0}.cshtml");

24
modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictOptions.cs

@ -25,4 +25,28 @@ public class AbpOpenIddictAspNetCoreOptions
/// Set the url of the select account page.
/// </summary>
public string SelectAccountPage { get; set; } = "~/Account/SelectAccount";
/// <summary>
/// When set to <c>true</c>, the access token issued for the <c>client_credentials</c> grant
/// automatically includes the scopes configured on the client application (permissions
/// prefixed with <c>oi_scp:</c>) when the client does not explicitly request any scope.
/// Default: false.
/// </summary>
public bool UseDefaultScopesForClientCredentials { get; set; }
/// <summary>
/// When set to <c>true</c>, the access token issued for the <c>password</c> grant
/// automatically includes the scopes configured on the client application (permissions
/// prefixed with <c>oi_scp:</c>) when the client does not explicitly request any scope.
/// Default: false.
/// </summary>
public bool UseDefaultScopesForPassword { get; set; }
/// <summary>
/// When set to <c>true</c>, the access token issued for the <c>urn:ietf:params:oauth:grant-type:token-exchange</c>
/// grant automatically includes the scopes configured on the client application (permissions
/// prefixed with <c>oi_scp:</c>) when the client does not explicitly request any scope.
/// Default: false.
/// </summary>
public bool UseDefaultScopesForTokenExchange { get; set; }
}

100
modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Claims/AbpDefaultScopesHandler.cs

@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.OpenIddict;
public class AbpDefaultScopesHandler : IAbpOpenIddictClaimsPrincipalHandler, ITransientDependency
{
public ILogger<AbpDefaultScopesHandler> Logger { get; set; }
= NullLogger<AbpDefaultScopesHandler>.Instance;
public async Task HandleAsync(AbpOpenIddictClaimsPrincipalHandlerContext context)
{
var options = context.ScopeServiceProvider
.GetRequiredService<IOptions<AbpOpenIddictAspNetCoreOptions>>().Value;
var request = context.OpenIddictRequest;
if (!IsDefaultScopesEnabled(request, options))
{
return;
}
if (!context.Principal.GetScopes().IsDefaultOrEmpty)
{
return;
}
var clientId = request.ClientId;
if (string.IsNullOrEmpty(clientId))
{
return;
}
var applicationManager = context.ScopeServiceProvider.GetRequiredService<IOpenIddictApplicationManager>();
var scopeManager = context.ScopeServiceProvider.GetRequiredService<IOpenIddictScopeManager>();
var application = await applicationManager.FindByClientIdAsync(clientId);
if (application == null)
{
return;
}
var permissions = await applicationManager.GetPermissionsAsync(application);
var prefix = OpenIddictConstants.Permissions.Prefixes.Scope;
var scopes = permissions
.Where(p => p.StartsWith(prefix, StringComparison.Ordinal))
.Select(p => p[prefix.Length..])
.ToImmutableArray();
if (scopes.IsDefaultOrEmpty)
{
return;
}
Logger.LogDebug(
"Injecting default scopes for client {ClientId} (grant_type {GrantType}): {Scopes}",
clientId,
request.GrantType,
string.Join(", ", scopes));
context.Principal.SetScopes(scopes);
var resources = new List<string>();
await foreach (var resource in scopeManager.ListResourcesAsync(scopes))
{
resources.Add(resource);
}
context.Principal.SetResources(resources);
}
protected virtual bool IsDefaultScopesEnabled(OpenIddictRequest request, AbpOpenIddictAspNetCoreOptions options)
{
if (request.IsClientCredentialsGrantType())
{
return options.UseDefaultScopesForClientCredentials;
}
if (request.IsPasswordGrantType())
{
return options.UseDefaultScopesForPassword;
}
if (request.IsTokenExchangeGrantType())
{
return options.UseDefaultScopesForTokenExchange;
}
return false;
}
}
Loading…
Cancel
Save