Open Closed

External user being prompted to generate local password after upgrading to ABP 9 #8866


User avatar
0
maria_ruiz created
  • ABP Framework version: v9.0.4

  • UI Type: Blazor WASM

  • Database System: EF Core (SQL Server)

  • Tiered (for MVC) or Auth Server Separated (for Angular): no

Good afternoon,

I need you to indicate me the changes to make that you indicated in this thread, we have the same problem, it forces to change the password,

the resource indicates that it is no longer available and I can not see the solution.

https://abp.io/support/questions/8722/External-user-being-prompted-to-generate-local-password-after-upgrading-to-ABP-9


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

    hi

    Please use these code to override the login and register class.

    https://we.tl/t-YQ7tQxfSjw

  • User Avatar
    0
    maria_ruiz created

    Good morning,

    we have reviewed the class,

    in this class, what we are doing is commenting on the part where we ask for the password change.

    image.png

    In our case we have not added that, it suddenly appeared in the login to change the password.

    using System;
    using System.Linq;
    using System.Security.Claims;
    using System.Threading.Tasks;
    using Fundanet.Core.Extensions;
    using Fundanet.Core.Infrastructure.Abstractions.AzureAd;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.AspNetCore.Identity;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Caching.Distributed;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    using OpenIddict.Abstractions;
    using Owl.reCAPTCHA;
    using Volo.Abp.Account.ExternalProviders;
    using Volo.Abp.Account.Public.Web;
    using Volo.Abp.Account.Public.Web.Pages.Account;
    using Volo.Abp.Account.Security.Recaptcha;
    using Volo.Abp.AspNetCore.MultiTenancy;
    using Volo.Abp.Caching;
    using Volo.Abp.DependencyInjection;
    using Volo.Abp.MultiTenancy;
    using Volo.Abp.Security.Claims;
    using IdentityUser = Volo.Abp.Identity.IdentityUser;

    namespace Semicrol.Arco.Core.HttpApi.Host.Auth;

    [ExposeServices(typeof(ArcoLoginModel), typeof(LoginModel))]
    public class ArcoLoginModel : LoginModel
    {
    private const string IsHostSessionKey = "isHostSession";

    private readonly ITenantStore _tenantStore;
    
    private readonly IDistributedCache<IsHostCacheItem> _cache;
    
    private readonly IAzureAdManager _azureAdManager;
    
    public bool HasB2CConfiguration { get; set; }
    
    [BindProperty(SupportsGet = true)] public string TenancyName { get; set; }
    
    [BindProperty(SupportsGet = true)]
    [HiddenInput]
    public bool ShowTenantSelector { get; set; }
    
    protected AbpAspNetCoreMultiTenancyOptions Options { get; }
    
    public ArcoLoginModel(
        IAuthenticationSchemeProvider schemeProvider,
        IOptions<AbpAccountOptions> accountOptions,
        IAbpRecaptchaValidatorFactory recaptchaValidatorFactory,
        IAccountExternalProviderAppService accountExternalProviderAppService,
        ICurrentPrincipalAccessor currentPrincipalAccessor,
        IOptions<Microsoft.AspNetCore.Identity.IdentityOptions> identityOptions,
        IOptionsSnapshot<reCAPTCHAOptions> reCaptchaOptions,
        ITenantStore tenantStore,
        ICurrentTenantAccessor currentTenantAccessor,
        IDistributedCache<IsHostCacheItem> cache,
        IOptions<AbpAspNetCoreMultiTenancyOptions> options,
        IAzureAdManager azureAdManager) : base(
        schemeProvider,
        accountOptions,
        recaptchaValidatorFactory,
        accountExternalProviderAppService,
        currentPrincipalAccessor,
        identityOptions,
        reCaptchaOptions)
    {
        _tenantStore = tenantStore;
        _cache = cache;
        _azureAdManager = azureAdManager;
        HasB2CConfiguration = _azureAdManager.HasB2CConfiguration();
        Options = options.Value;
    }
    
    public override async Task<IActionResult> OnGetAsync()
    {
        await GetShowTenantSelector();
        TenancyName = await HostSessionIsActive() ? "host" : CurrentTenant?.Name;
        var result = await base.OnGetAsync();
    
        if (LoginInput != null)
        {
            LoginInput.RememberMe = true;
        }
    
        return result;
    }
    
    public override async Task<IActionResult> OnPostAsync(string action)
    {
        if (LoginInput != null)
        {
            LoginInput.RememberMe = true;
        }
        
    
        if (action is "ChangeTenant")
        {
            if (TenancyName == null)
            {
                return await OnGetAsync();
            }
    
            var changeTenantResult = await ChangeTenantAsync();
            var externalProviders = await GetExternalProviders();
            var visibleExternalProviders =
                externalProviders.Where(x => !string.IsNullOrWhiteSpace(x.DisplayName)).ToList();
            if (changeTenantResult && visibleExternalProviders.Count == 1)
            {
                return await OnPostExternalLogin(visibleExternalProviders.First().AuthenticationScheme);
            }
            else
            {
                return await base.OnGetAsync();
            }
        }
    
        if (action is "ResetTenant")
        {
            await _cache.RemoveAsync(IsHostSessionKey);
            CurrentTenant.Change(null);
            AbpMultiTenancyCookieHelper.SetTenantCookie(HttpContext, null, Options.TenantKey);
            TenancyName = null;
            return await OnGetAsync();
        }
    
        TenancyName = await HostSessionIsActive() ? "host" : CurrentTenant?.Name;
        if (!ModelState.IsValid)
        {
            return await base.OnGetAsync();
        }
        return await base.OnPostAsync(action);
    }
    
    public override async Task<IActionResult> OnGetExternalLoginCallbackAsync(string remoteError = null)
    {
        var tenancyName = await HostSessionIsActive() ? "host" : CurrentTenant?.Name;
    
        if (remoteError != null)
        {
            Logger.LogWarning($"External login callback error: {remoteError}");
            return RedirectToPage("./Login");
        }
    
        await IdentityOptions.SetAsync();
    
        var loginInfo = await SignInManager.GetExternalLoginInfoAsync();
        if (loginInfo == null)
        {
            Logger.LogWarning("External login info is not available");
            return RedirectToPage("./Login");
        }
    
        var emailAddress = loginInfo.Principal.FindFirstValue(ClaimTypes.Email) ??
                           loginInfo.Principal.FindFirstValue(AbpClaimTypes.Email);
    
        if (string.IsNullOrEmpty(emailAddress))
        {
            emailAddress = loginInfo.Principal.FindFirstValue("preferred_username");
        }
    
        var emailFromClaimTypes = loginInfo.Principal.FindFirstValue(AbpClaimTypes.Email);
    
        if (string.IsNullOrEmpty(emailFromClaimTypes) && string.IsNullOrEmpty(emailAddress) == false)
        {
            loginInfo.Principal.AddClaim(AbpClaimTypes.Email, emailAddress);
        }
    
        var tenant = tenancyName ?? "host";
    
        var b2CUser = await _azureAdManager.User(tenant, emailAddress);
    
        if ((b2CUser?.CompanyName?.Split("|").TrimAll().ToLower().Contains(tenant.Trim().ToLower()) ?? false) == false)
        {
            await SignInManager.SignOutAsync();
            return RedirectToPage("./AccessDenied");
        }
    
        var user = await UserManager.FindByEmailAsync(emailAddress);
        if (user == null)
        {
            var externalLoginInfo = await SignInManager.GetExternalLoginInfoAsync();
            if (externalLoginInfo == null)
            {
                Logger.LogWarning("External login info is not available");
                return RedirectToPage("./Login");
            }
    
            await RegisterExternalUserAsync(externalLoginInfo, b2CUser, emailAddress, loginInfo.LoginProvider);
        }
    
        return await base.OnGetExternalLoginCallbackAsync(remoteError);
    }
    
    protected virtual async Task RegisterExternalUserAsync(ExternalLoginInfo externalLoginInfo, UserModel userModel,
        string emailAddress, string externalLoginAuthSchema)
    {
        await IdentityOptions.SetAsync();
    
        var userName = emailAddress;
        var user = new IdentityUser(GuidGenerator.Create(), userName, emailAddress, CurrentTenant.Id)
        {
            Name = userModel?.Name,
            Surname = userModel?.Surname
        };
    
        (await UserManager.CreateAsync(user)).CheckErrors();
        (await UserManager.AddDefaultRolesAsync(user)).CheckErrors();
    
        var userLoginAlreadyExists = user.Logins.Any(x =>
            x.TenantId == user.TenantId &&
            x.LoginProvider == externalLoginInfo.LoginProvider &&
            x.ProviderKey == externalLoginInfo.ProviderKey);
    
        if (!userLoginAlreadyExists)
        {
            (await UserManager.AddLoginAsync(user, new UserLoginInfo(
                externalLoginInfo.LoginProvider,
                externalLoginInfo.ProviderKey,
                externalLoginInfo.ProviderDisplayName
            ))).CheckErrors();
        }
    
        await SignInManager.SignInAsync(user, isPersistent: true, externalLoginAuthSchema);
    
        // Clear the dynamic claims cache.
        await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId);
    }
    
    private async Task<bool> ChangeTenantAsync()
    {
        var isHostSession = TenancyName?.ToLower().Equals("host") ?? false;
        await SetCacheValue(isHostSession);
    
        if (isHostSession)
        {
            CurrentTenant.Change(null);
            return true;
        }
    
        TenantConfiguration tenant = null;
        if (string.IsNullOrEmpty(TenancyName) == false)
        {
            tenant = await _tenantStore.FindAsync(TenancyName);
            if (tenant == null)
            {
                Alerts.Danger(L["Arco:GivenTenantDoesNotExist"].Value);
                return false;
            }
    
            if (!tenant.IsActive)
            {
                Alerts.Danger(L["Arco:GivenTenantIsNotAvailable"].Value);
                return false;
            }
        }
    
        CurrentTenant.Change(tenant?.Id, tenant?.Name);
    
        await CurrentUnitOfWork.SaveChangesAsync();
        AbpMultiTenancyCookieHelper.SetTenantCookie(HttpContext, tenant?.Id, Options.TenantKey);
    
        return true;
    }
    
    private async Task SetCacheValue(bool isHostSession)
    {
        await _cache.RemoveAsync(IsHostSessionKey);
        await _cache.SetAsync(IsHostSessionKey,
            new IsHostCacheItem()
            {
                IsHostSession = isHostSession
            },
            new DistributedCacheEntryOptions
            {
                AbsoluteExpiration = DateTimeOffset.Now.AddYears(10)
            });
    }
    
    private async Task<bool> HostSessionIsActive()
    {
        var cacheResult = await _cache.GetAsync(IsHostSessionKey);
        return cacheResult?.IsHostSession ?? false;
    }
    
    private async Task GetShowTenantSelector()
    {
        if (await HostSessionIsActive())
        {
            ShowTenantSelector = false;
        }
        else
        {
            ShowTenantSelector = CurrentTenant?.Id.HasValue == false;
        }
    }
    

    }

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    ok, Sorry for that.

    Does the code work now?

    Thanks.

  • User Avatar
    0
    maria_ruiz created

    Sorry,

    We don't have this code, I've explained myself wrong,
    and without that piece of code it still fails us.

  • User Avatar
    0
    maria_ruiz created
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Is the same problem that this https://abp.io/support/questions/8887/SSO-Users-forced-to-add-password-VoloAccountPro-900

    Yes. We will change this behavior in next 9.0.x patch version.

    We don't have this code, I've explained myself wrong,

    Can you send an email to liming.ma@volosoft.com

    I will share the code with you.

  • User Avatar
    0
    maria_ruiz created

    Okay, Can you tell me if you know approximately how much the new release will generate?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    It will be released in one or two weeks.

    You can override the page now.
    I have sent the code to you.

    Thanks.

Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
Do you need assistance from an ABP expert?
Schedule a Meeting
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v9.2.0-preview. Updated on March 13, 2025, 04:08