Quantcast
Channel: ASP.NET Core
Viewing all articles
Browse latest Browse all 9386

Identity: Creating password change token from a netstandard 1.6 console app doesn't work for the user in the netcore asp.net webapi app

$
0
0

I have a large netcore WebAPI application with multiple databases, each serving a different client. Data is shared via a queue that is handled by a netstandard 1.6 console app. Here's the relevant identity setup code in startup.cs (for the WebAPI app)

Services.AddEntityFramework()
                .AddEntityFrameworkNpgsql()
                .AddDbContext<Repository.IdentityDbContext>();

            services.AddIdentity<ApplicationUser, IdentityRole>(options =>
            {
                options.Cookies.ApplicationCookie.AutomaticChallenge = false;
                options.Cookies.ApplicationCookie.AutomaticAuthenticate = false;

                // Password settings
                options.Password.RequireDigit = Convert.ToBoolean(Configuration.GetSection("PasswordStrengthSettings")["RequireDigit"]);
                options.Password.RequiredLength = Convert.ToInt32(Configuration.GetSection("PasswordStrengthSettings")["MinimumPasswordLength"]);
                options.Password.RequireNonAlphanumeric = Convert.ToBoolean(Configuration.GetSection("PasswordStrengthSettings")["RequireNonAlphanumeric"]);
                options.Password.RequireUppercase = Convert.ToBoolean(Configuration.GetSection("PasswordStrengthSettings")["RequireUppercase"]);
                options.Password.RequireLowercase = Convert.ToBoolean(Configuration.GetSection("PasswordStrengthSettings")["RequireLowercase"]);
                options.Tokens.ProviderMap.Add("Default", new TokenProviderDescriptor(typeof(IUserTwoFactorTokenProvider<ApplicationUser>)));

                // Lockout settings
                options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(Convert.ToDouble(Configuration.GetSection("SecuritySettings")["LockoutDurationInMinutes"]));
                options.Lockout.MaxFailedAccessAttempts = Convert.ToInt32(Configuration.GetSection("SecuritySettings")["NumberOfAttemptsUntilLockout"]);

                // User settings
                options.User.RequireUniqueEmail = true;
            }).AddDefaultTokenProviders().AddEntityFrameworkStores<Repository.IdentityDbContext>();

            services.Configure<DataProtectionTokenProviderOptions>(o =>
            {
                o.Name = "Default";
                o.TokenLifespan = TimeSpan.FromMinutes(Convert.ToDouble(Configuration.GetSection("SecuritySettings")["PasswordChangeTokenExpirationInMinutes"]));
            });

Here's the (identical) code in my DI setup in my console app:

services.AddIdentity<ApplicationUser, IdentityRole>(options =>
            {
                options.Cookies.ApplicationCookie.AutomaticChallenge = false;
                options.Cookies.ApplicationCookie.AutomaticAuthenticate = false;

                // Password settings
                options.Password.RequireDigit = Convert.ToBoolean(configuration.GetSection("PasswordStrengthSettings")["RequireDigit"]);
                options.Password.RequiredLength = Convert.ToInt32(configuration.GetSection("PasswordStrengthSettings")["MinimumPasswordLength"]);
                options.Password.RequireNonAlphanumeric = Convert.ToBoolean(configuration.GetSection("PasswordStrengthSettings")["RequireNonAlphanumeric"]);
                options.Password.RequireUppercase = Convert.ToBoolean(configuration.GetSection("PasswordStrengthSettings")["RequireUppercase"]);
                options.Password.RequireLowercase = Convert.ToBoolean(configuration.GetSection("PasswordStrengthSettings")["RequireLowercase"]);
                options.Tokens.ProviderMap.Add("Default", new TokenProviderDescriptor(typeof(IUserTwoFactorTokenProvider<ApplicationUser>)));

                // Lockout settings
                options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(Convert.ToDouble(configuration.GetSection("SecuritySettings")["LockoutDurationInMinutes"]));
                options.Lockout.MaxFailedAccessAttempts = Convert.ToInt32(configuration.GetSection("SecuritySettings")["NumberOfAttemptsUntilLockout"]);

                // User settings
                options.User.RequireUniqueEmail = true;
            }).AddDefaultTokenProviders().AddEntityFrameworkStores<Repository.IdentityDbContext>();

            services.Configure<DataProtectionTokenProviderOptions>(o =>
            {
                o.Name = "Default";
                o.TokenLifespan = TimeSpan.FromMinutes(Convert.ToDouble(configuration.GetSection("SecuritySettings")["PasswordChangeTokenExpirationInMinutes"]));
            });

When the console app generates a password change token, it is rejected as "invalid" by Identity in the API endpoint to change password. If I create a password change token for the same user via the WebAPI, it works fine for the same endpoint. Thoughts? Any help would be most appreciated, as I'm sure I'm missing something!

Edit: I have ensured that the PasswordChangeTokenExpiration setting is identical in both json config files and is being picked up by both apps. Also, here's the code that generates a token and sends an email: both apps call the same function (it's in its own DLL):

private async Task SendNewUserEmail()
        {
            if (!_serviceResult.HasAnyError)
            {
                var token = await _userManager.GeneratePasswordResetTokenAsync(_userModel);
                if (token != null)
                {
                    var template = _emailTemplates.GetEmailTemplate("new-user");
                    var emailBody = template.Body
                        .Replace("~~~BaseUrl~~~", _emailSettings.FrontEndBaseUrl.Replace("~~~Subdomain~~~", _currentUserTools.GetCurrentDestination()))
                        .Replace("~~~Token~~~", HtmlEncoder.Default.Encode(token))
                        .Replace("~~~FirstName~~~", HtmlEncoder.Default.Encode(_userModel.FirstName ?? ""))
                        .Replace("~~~LastName~~~", HtmlEncoder.Default.Encode(_userModel.LastName ?? ""))
                        .Replace("~~~Type~~~", HtmlEncoder.Default.Encode("NEW_USER"))
                        .Replace("~~~Email~~~", HtmlEncoder.Default.Encode(_userModel.Email));

                    await _emailSender.SendEmail(
                        new EmailTools.Models.MailParticipant(_emailSettings.DefaultFromEmailName, _emailSettings.DefaultFromEmailAddress),
                        new EmailTools.Models.MailParticipant("", _userModel.Email),
                        template.Subject,
                        emailBody);
                }

                _serviceResult.Data = UserDto.GetDto(_userModel);
            }
        }



Viewing all articles
Browse latest Browse all 9386

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>