Ends in:
7 DAYS
14 HRS
11 MIN
46 SEC
Ends in:
7 D
14 H
11 M
46 S

Activities of "pvala"

Sure, here it is.


namespace G1.health.AuthServer.PasswordlessAuthentication;

public class EmpowermTokenExtensionGrant : ITokenExtensionGrant
{
    public const string ExtensionGrantName = "PasswordlessLoginProvider";

    public string Name => ExtensionGrantName;
    public async Task<IActionResult> HandleAsync(ExtensionGrantContext context)
    {
        var userToken = context.Request.GetParameter("token").ToString();

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

        var transaction = await context.HttpContext.RequestServices.GetRequiredService<IOpenIddictServerFactory>().CreateTransactionAsync();
        transaction.EndpointType = OpenIddictServerEndpointType.Introspection;
        transaction.Request = new OpenIddictRequest
        {
            ClientId = context.Request.ClientId,
            ClientSecret = context.Request.ClientSecret,
            Token = userToken
        };

        var notification = new OpenIddictServerEvents.ProcessAuthenticationContext(transaction);
        var dispatcher = context.HttpContext.RequestServices.GetRequiredService<IOpenIddictServerDispatcher>();
        await dispatcher.DispatchAsync(notification);

        if (notification.IsRejected)
        {
            return new ForbidResult(
                new[] { OpenIddictServerAspNetCoreDefaults.AuthenticationScheme },
                properties: new AuthenticationProperties(new Dictionary<string, string>
                {
                    [OpenIddictServerAspNetCoreConstants.Properties.Error] = notification.Error ?? OpenIddictConstants.Errors.InvalidRequest,
                    [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = notification.ErrorDescription,
                    [OpenIddictServerAspNetCoreConstants.Properties.ErrorUri] = notification.ErrorUri
                }));
        }

        var principal = notification.GenericTokenPrincipal;
        if (principal == null)
        {
            return new ForbidResult(
                new[] { OpenIddictServerAspNetCoreDefaults.AuthenticationScheme },
                properties: new AuthenticationProperties(new Dictionary<string, string>
                {
                    [OpenIddictServerAspNetCoreConstants.Properties.Error] = notification.Error ?? OpenIddictConstants.Errors.InvalidRequest,
                    [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = notification.ErrorDescription,
                    [OpenIddictServerAspNetCoreConstants.Properties.ErrorUri] = notification.ErrorUri
                }));
        }

        var userId = principal.FindUserId();
        var userManager = context.HttpContext.RequestServices.GetRequiredService<EmpowermIdentityUserManager>();
        var user = await userManager.GetByIdAsync(userId.Value);
        var userClaimsPrincipalFactory = context.HttpContext.RequestServices.GetRequiredService<IUserClaimsPrincipalFactory<Volo.Abp.Identity.IdentityUser>>();
        var claimsPrincipal = await userClaimsPrincipalFactory.CreateAsync(user);
        claimsPrincipal.SetScopes(principal.GetScopes());
        claimsPrincipal.SetResources(await GetResourcesAsync(context, principal.GetScopes()));

        await context.HttpContext.RequestServices.GetRequiredService<AbpOpenIddictClaimsPrincipalManager>().HandleAsync(context.Request, claimsPrincipal);

        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 context.HttpContext.RequestServices.GetRequiredService<IOpenIddictScopeManager>().ListResourcesAsync(scopes))
        {
            resources.Add(resource);
        }
        return resources;
    }
}

I have updated the ExtensionGrantName value to "PasswordlessLoginProvider", since I am generating and validating the token with the same token provider name (I am not sure if it's necessary), but to avoid any confusion I have done that.

Also, the Token that I am getting is not like a JWT Token, it's like a 6 digit number, so I am not sure how it's working in the background.

Hi, I went through the implementation you have provided. Here is what I have done.

I have two APIs, the first one is a send OTP API, which sends the OTP to the mobile number and the other API validates that OTP and on successful validation of the API it let's the user signs in. We are creating a new user using the Mobile Number as the username of the user and mobile_number@example.com as the Email of the user. If the user is already registered, then we just fetch the user details, otherwise we create the user and let it log in into the application.

Here's the controller :

[HttpPost]
[AllowAnonymous]
[Route("passwordless-authentication")]
public async Task&lt;VerifyOTPAndSignInResponseDto&gt; VerifyOTPAndSignIn(VerifyOTPAndSignInInput input)
{
    using (CurrentTenant.Change(input.TenantId))
    {
        using (var unitOfWork = UnitOfWorkManager.Begin())
        {
            try
            {
                VerifyOTPResponseDto otpVerification = await VerifyOTP(
                    new VerifyOTPInput()
                    {
                        CountryCode = input.CountryCode,
                        MobileNumber = input.MobileNumber,
                        OTP = input.OTP,
                    });

                if (otpVerification.type == "success")
                {
                    var existingUser = await UserManager.FindByNameAsync(input.CountryCode + input.MobileNumber);
                    var user = new Volo.Abp.Identity.IdentityUser(GuidGenerator.Create(), input.CountryCode + input.MobileNumber, input.CountryCode + input.MobileNumber + "@example.com", null);
                    user.SetPhoneNumber(input.CountryCode + "-" + input.MobileNumber, true);

                    if (existingUser == null)
                    {
                        (await UserManager.CreateAsync(user)).CheckErrors();
                        using (CurrentTenant.Change(null))
                        {
                            (await UserManager.AddToRoleAsync(user, "Patient")).CheckErrors();
                        }
                        await UsersAppService.PasswordlessUserRegistration(new PasswordlessUserRegistration(input.CountryCode, input.MobileNumber, user.Id));
                    }
                    else
                    {
                        user = existingUser;
                    }

                    var token = await UserManager.GenerateUserTokenAsync(user, "PasswordlessLoginProvider", "passwordless-auth");

                    var isValid = await UserManager.VerifyUserTokenAsync(user, "PasswordlessLoginProvider", "passwordless-auth", token);
                    if (!isValid)
                    {
                        throw new UnauthorizedAccessException("The token " + token + " is not valid for the user " + user.Id);
                    }

                    await UserManager.UpdateSecurityStampAsync(user);
                    await unitOfWork.CompleteAsync();
                    await SignInManager.SignInAsync(user, isPersistent: true);
                    return
                        new VerifyOTPAndSignInResponseDto()
                        {
                            message = otpVerification.message,
                            type = otpVerification.type,
                            token = token
                        };
                }
                else
                {
                    return new VerifyOTPAndSignInResponseDto()
                    {
                        message = otpVerification.message,
                        type = otpVerification.type
                    };
                }
            }
            catch (Exception e)
            {
                await unitOfWork.RollbackAsync();
                unitOfWork.Dispose();
                throw;
            }
        }
    }
}

Here the UserManager is our UserManager, that we have overridden.

Also, this i the file I have added as well,

using Microsoft.AspNetCore.Identity; using System.Threading.Tasks;

namespace G1.health.AuthServer.PasswordlessAuthentication;

public class PasswordlessLoginProvider<TUser> : TotpSecurityStampBasedTokenProvider<TUser> where TUser : class { public override Task<bool> CanGenerateTwoFactorTokenAsync(UserManager<TUser> manager, TUser user) { return Task.FromResult(false); }

public async override Task&lt;string&gt; GetUserModifierAsync(string purpose, UserManager&lt;TUser&gt; manager, TUser user)
{
    var userId = await manager.GetUserIdAsync(user);

    return "PasswordlessLogin:" + purpose + ":" + userId;
}

}

And this one as well,

using Microsoft.AspNetCore.Identity;

namespace G1.health.AuthServer.PasswordlessAuthentication;

public static class IdentityBuilderExtensions { public static IdentityBuilder AddPasswordlessLoginProvider(this IdentityBuilder builder) { var userType = builder.UserType; var totpProvider = typeof(PasswordlessLoginProvider<>).MakeGenericType(userType); return builder.AddTokenProvider("PasswordlessLoginProvider", totpProvider); } }

As mentioned in this article.

https://abp.io/community/articles/implementing-passwordless-authentication-with-asp.net-core-identity-c25l8koj

Now, after configuring all these things, I added whatever you asked in this implementation : https://abp.io/community/articles/how-to-add-a-custom-grant-type-in-openiddict.-6v0df94z

public const string ExtensionGrantName = "PasswordlessAuthentication";

This is the ExtensionGrantName name that I have given and the same Grant Name I have added in the OpenIddictApplications table as well for the Angular client.

After that, using postman, I am trying to validate the user and let it log in, but it says, invalid token.

The token that I am passing that I am deriving from here in my Validating OTP controller :

                    var token = await UserManager.GenerateUserTokenAsync(user, "PasswordlessLoginProvider", "passwordless-auth");

                    var isValid = await UserManager.VerifyUserTokenAsync(user, "PasswordlessLoginProvider", "passwordless-auth", token);

Can you tell me if anything I need to configure or if I am missing something.

https://abp.io/support/questions/7882/Override-the-existing-Users-Roles--Permissions-Methodology

Here is the earlier ticket we raised to order to override and configure the role assignment fo users. Now we such a system where the roles can be only created from the host and the tenants can't create any new role, but they can use the roles which are created from the host. Now what we want is that when we update the permissions of a role, and if that role is assigned to a user in a tenant, it should immediately reflect the updated permissions for that tenant user.

We are changing the permissions from UI only, but there as well we need to clear redia cache and then only it reflets.

public class PermissionGrantCacheItemInvalidator : Volo.Abp.PermissionManagement.PermissionGrantCacheItemInvalidator { protected ITenantStore TenantStore { get; set; }

public PermissionGrantCacheItemInvalidator(IDistributedCache&lt;PermissionGrantCacheItem&gt; cache, ICurrentTenant currentTenant, ITenantStore tenantStore)
    : base(cache, currentTenant)
{
    TenantStore = tenantStore;
}

public override async Task HandleEventAsync(EntityChangedEventData&lt;PermissionGrant&gt; eventData)
{
    var cacheKey = CalculateCacheKey(
        eventData.Entity.Name,
        eventData.Entity.ProviderName,
        eventData.Entity.ProviderKey
    );

    var tenants = await TenantStore.GetListAsync();

    foreach (var tenant in tenants)
    {
        using (CurrentTenant.Change(tenant.Id))
        {
            await Cache.RemoveAsync(cacheKey, considerUow: true);
        }
    }
}

protected override string CalculateCacheKey(string name, string providerName, string providerKey)
{
    return PermissionGrantCacheItem.CalculateCacheKey(name, providerName, providerKey);
}

}

I added this file in the domain project of the AdministrationService. Here, because all the tenants will use the roles from the host tenant only, that's why if we update the permission of a role from host, it should reflect in all the tenants which are using that role. After adding this file, I ran the solution, and logged in as a user of a tenant and gave it a role from the host, now if I update the permissions of that role from the host and clear the redis cache, and refresh the page where I am logged in as a tenant user, it immediately reflects al the permissions as updated. But only after we clear redis cache. Any solution for thsi?

Hi, can we get any update on this?

I have done some more analysis on this. I took the JWT tokens from the API calls 2 scenarios, one where we haven't overridden anything and kept everything as per the Framework, and one where we have our implementation.

I took those 2 JWT tokens and decoded them and came to know that the one which is using the default Framework implementation is these properties extra then the one where we have our implementation

session_id unique_name given_name email_verified phone_number_verified

Is there any significance of this? What I am thinking is somehow, it's because of the session id being null here.

I checked the current claims, there I am getting the preferred_username as "admin", which is correct. So, I am not sure if it's related to claims.

I am not sure, how this is specifically happening with the Payment packages. But for now I have commented all the line of code which is referencing the Payment packages. Can you pull the latest changes and try to build?

Showing 11 to 20 of 129 entries
Made with ❤️ on ABP v9.1.0-preview. Updated on November 20, 2024, 13:06