Open Closed

Tokens created via custom grant #8141


User avatar
0
naeem76 created
  • ABP Framework version: v8.3.1
  • UI Type: MVC
  • Database System: EF Core ( PostgreSQL)
  • Tiered (for MVC) or Auth Server Separated (for Angular): no
  • Exception message and full stack trace:
  • Steps to reproduce the issue:

I am currently using ABP 8.3.1 Pro version. There is a bug when trying to use tokens created via a custom grant. The main issue from the logs says:

[16:45:33 DBG] AuthenticationScheme: OpenIddict.Validation.AspNetCore was successfully authenticated. [16:45:33 DBG] Get dynamic claims cache for user: a9a8d44f-c8e3-482f-a870-66e93186d540 [16:45:33 DBG] Filling dynamic claims cache for user: a9a8d44f-c8e3-482f-a870-66e93186d540 [16:45:33 WRN] SessionId() claim not found for user: a9a8d44f-c8e3-482f-a870-66e93186d540, log out. [16:45:33 DBG] Remove dynamic claims cache for user: a9a8d44f-c8e3-482f-a870-66e93186d540 [16:45:33 WRN] The token is no longer valid because the user's session expired. [16:45:33 INF] Authorization failed. These requirements were not met: DenyAnonymousAuthorizationRequirement: Requires an authenticated user.

I am removing the dynamic claim right now with this as a temporary solution.

        context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
        {
            options.IsDynamicClaimsEnabled = false;
        });

But I would prefer to keep them for other flows of my application.

I would prefer that my custom grant is not part of dynamic claims (or it could if you provide some code to create sessions appropriately?) This page mentions that there is a Principal Contributor: https://abp.io/docs/latest/modules/identity/session-management#how-it-works So I tried to get rid of it with this command: options.RemoveEventHandler(OpenIddictValidateIdentitySessionValidationHandler.Descriptor); But I still get the error. Maybe there is a flag I can set on the context to avoid getting my principal attached with a sessionId, but I can’t really debug further because all these packages are in the Pro and not compiled with ILDASM.

Can you please provide the following:

  1. Have a way to turn off session in this token grant
  2. Have a way to create the session appropriately when creating the token

Supporting code

public class MagicTokenHandler
{
    public const string ExtensionGrantName = "magic_token";
    public const string MagicTokenKey = "magic_token";
}

// https://github.com/abpframework/abp/blob/b2878b4d3dca82811a5fc1739dee29cc88669eaa/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.cs#L49
// https://github.com/abpframework/abp/blob/b2878b4d3dca82811a5fc1739dee29cc88669eaa/docs/en/Community-Articles/2022-11-14-How-to-add-a-custom-grant-type-in-OpenIddict/POST.md
public class MagicTokenExtensionGrant(
    IdentityUserManager identityUserManager,
    SignInManager<Volo.Abp.Identity.IdentityUser> signInManager,
    IUserClaimsPrincipalFactory<Volo.Abp.Identity.IdentityUser> userClaimsPrincipalFactory,
    AbpOpenIddictClaimsPrincipalManager abpOpenIddictClaimsPrincipalManager,
    IOpenIddictScopeManager openIddictScopeManager
) : ITokenExtensionGrant, IScopedDependency
{
    public readonly string TOKEN_HANDLER = LinkUserTokenProviderConsts.LinkUserTokenProviderName;
    public readonly string TOKEN_PURPOSE = LinkUserTokenProviderConsts.LinkUserLoginTokenPurpose;

    public string Name => MagicTokenHandler.ExtensionGrantName;

    public async Task<IActionResult> HandleAsync(ExtensionGrantContext context)
    {
        var magicToken = context.Request.GetParameter(MagicTokenHandler.MagicTokenKey).ToString();

        if (string.IsNullOrEmpty(magicToken) || string.IsNullOrEmpty(context.Request.Username))
        {
            return GenericError;
        }

        var user = await identityUserManager.FindByNameAsync(context.Request.Username);
        if (user == null)
        {
            return GenericError;
        }

        var result = await identityUserManager.VerifyUserTokenAsync(user, TOKEN_HANDLER, TOKEN_PURPOSE, magicToken);
        if (!result)
        {
            return GenericError;
        }

        var principal = await signInManager.CreateUserPrincipalAsync(user);
        var claimsPrincipal = await userClaimsPrincipalFactory.CreateAsync(user);
        claimsPrincipal.SetScopes(principal.GetScopes());
        claimsPrincipal.SetAudiences("VarScanner");
        claimsPrincipal.SetResources(await GetResourcesAsync(context, principal.GetScopes()));

        //For abp version >= 7.3
        await abpOpenIddictClaimsPrincipalManager.HandleAsync(context.Request, principal);

        return new Microsoft.AspNetCore.Mvc.SignInResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, claimsPrincipal);
    }

    private async Task<IEnumerable<string>> GetResourcesAsync(ExtensionGrantContext context, ImmutableArray<string> scopes)
    {
        var resources = new List<string>();
        if (!scopes.Any())
        {
            return resources;
        }

        await foreach (var resource in openIddictScopeManager.ListResourcesAsync(scopes))
        {
            resources.Add(resource);
        }

        return resources;
    }

    private ForbidResult GenericError => new ForbidResult(
        new[] { OpenIddictServerAspNetCoreDefaults.AuthenticationScheme },
        properties: new AuthenticationProperties(new Dictionary<string, string>
        {
            [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidRequest
        }!));
}

6 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Can you try to get an access token and share the Logs.txt? also share an access token value.

    Thanks

    liming.ma@volosoft.com

  • User Avatar
    0
    jean@groovejones.com created

    Hello,

    Access Token:

    eyJhbGciOiJSUzI1NiIsImtpZCI6IkUzMEMxMUU1MDU2MUM5NDNFNzg5NkE2OTM2RTkyQTg2NTc3QTBEMTAiLCJ4NXQiOiI0d3dSNVFWaHlVUG5pV3BwTnVrcWhsZDZEUkEiLCJ0eXAiOiJhdCtqd3QifQ.eyJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo0NDM0My8iLCJleHAiOjE3Mjk2MDk4MzYsImlhdCI6MTcyOTYwNjIzNiwiYXVkIjoiVmFyU2Nhbm5lciIsInNjb3BlIjoib3BlbmlkIiwianRpIjoiZGU1NDIzNjgtN2Y0ZS00MWZjLThiZTEtZmY5YjYyZWE1N2JjIiwic3ViIjoiYTlhOGQ0NGYtYzhlMy00ODJmLWE4NzAtNjZlOTMxODZkNTQwIiwib2lfcHJzdCI6IlZhclNjYW5uZXJfQXBwIiwiY2xpZW50X2lkIjoiVmFyU2Nhbm5lcl9BcHAiLCJvaV90a25faWQiOiIzYTE1YzZiZC05MzU3LWVkNmMtMzQ5Ni1jY2IwOTBjNjA5NmIifQ.4eYHNo8OW1IYIAOMFe8PF3_ITM7bcuRmk6TrXx2Wb8M78_y0MLk5J6j0LE97yUhEtqkePD6MdLgL4cDBJMDONsqpkzQVXmG4-AZVrhp0oWUp4MK6ub3TvCDmFa1U0wN2FdpkUZ7JXRL1K_ix3N3xfOdbJmhgPOueWdFpCGEnHA26oxapd485x5iOPZMdebQ_-iLKAbYngOka53khB_SRH_48Hz47TQ3f44aLikSEAdZqZMpUAELMbc6vlzS56PPSWGsNmmY7tCoOCLXYKHpEVEiOELceRig6F475YWJDBcBOD9YOI_zUTcoADUkmHddeW57n6N39NF19Hr4neaZ4lA
    

    I'm not sure what are the "Logs.txt", but I will send you the output window by email.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    The claims in the access token are:

    {
      "iss": "https://localhost:44343/",
      "exp": 1729609836,
      "iat": 1729606236,
      "aud": "VarScanner",
      "scope": "openid",
      "jti": "de542368-7f4e-41fc-8be1-ff9b62ea57bc",
      "sub": "a9a8d44f-c8e3-482f-a870-66e93186d540",
      "oi_prst": "VarScanner_App",
      "client_id": "VarScanner_App",
      "oi_tkn_id": "3a15c6bd-9357-ed6c-3496-ccb090c6096b"
    }
    

    Can you try to call await abpOpenIddictClaimsPrincipalManager.HandleAsync(context.Request, claimsPrincipal);?

    Make sure the claimsPrincipal is handled by abpOpenIddictClaimsPrincipalManager.

    principal vs claimsPrincipal

    
    var principal = await signInManager.CreateUserPrincipalAsync(user);
    var claimsPrincipal = await userClaimsPrincipalFactory.CreateAsync(user);
    claimsPrincipal.SetScopes(principal.GetScopes());
    claimsPrincipal.SetAudiences("VarScanner");
    claimsPrincipal.SetResources(await GetResourcesAsync(context, principal.GetScopes()));
    
    //For abp version >= 7.3
    await abpOpenIddictClaimsPrincipalManager.HandleAsync(context.Request, claimsPrincipal);
    
    return new Microsoft.AspNetCore.Mvc.SignInResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, claimsPrincipal);```
    
  • User Avatar
    0
    jean@groovejones.com created

    It does indeed solve the issue. I was able to remove the RemoveEvent and re-activate the dynamic claims flag. I copied this code from your documentation here:

    https://github.com/abpframework/abp/blob/b2878b4d3dca82811a5fc1739dee29cc88669eaa/docs/en/Community-Articles/2022-11-14-How-to-add-a-custom-grant-type-in-OpenIddict/POST.md

    Maybe it could be updated.

    Thank you for your support.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Thanks, I will update it.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    https://github.com/abpframework/abp/pull/21167

Made with ❤️ on ABP v9.1.0-preview. Updated on December 05, 2024, 12:19