ASP.NET Core Identity - Extending Password Hasher - asp.net-core

I'm working towards moving an application from Web Forms to MVC and opted to go with MVC 6 using ASP.NET Core.
In my current application I have a custom password hasher used with Identity. The implementation is very simple in my custom UserManager class:
public ApplicationUserManager()
: base(new UserStore<IdentityUser>(new AuthContext()))
{
this.PasswordHasher = new SqlPasswordHasher();
}
I'm trying to do the same with .NET Core but the PasswordHasher property doesn't exist in UserManager. I see that the constructor will take an IPasswordHasher parameter so I tried this:
public ApplicationUserManager(IUserStore<ApplicationUser> store, IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<ApplicationUser> passwordHasher, IEnumerable<IUserValidator<ApplicationUser>> userValidators,
IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors, IServiceProvider serviceProvider, ILogger<UserManager<ApplicationUser>> logger)
: base(store, optionsAccessor, new SqlPasswordHasher(), userValidators, passwordValidators, keyNormalizer, errors,
serviceProvider, logger)
{
}
In SqlPasswordHasher I'm simply overriding the VerifyHashedPassword method which looks like this:
public override PasswordVerificationResult VerifyHashedPassword(ApplicationUser user, string hashedPassword, string providedPassword)
{
// My custom logic is here
...
}
However, the above doesn't work. I have a breakpoint set in the VerifyHashedPassword method of SqlPasswordHasher and it doesn't get triggered.
I thought I was going about this the wrong way and I should be utilizing DI to accomplish this. I updated the constructor of my user manager so that it doesn't instantiate a new SqlPasswordHasher, but uses the default interface parameter instead:
public ApplicationUserManager(IUserStore<ApplicationUser> store, IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<ApplicationUser> passwordHasher, IEnumerable<IUserValidator<ApplicationUser>> userValidators,
IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors, IServiceProvider serviceProvider, ILogger<UserManager<ApplicationUser>> logger)
: base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors,
serviceProvider, logger)
{
}
Then in Startup.cs I added a scoped service:
services.AddScoped<IPasswordHasher<ApplicationUser>, SqlPasswordHasher>();
But again, this doesn't work and the breakpoint in SqlPasswordHasher is never triggered.
I have a similar line for my custom Sign In Manager:
services.AddScoped<SignInManager<ApplicationUser>, ApplicationSignInManager>();
That works great. The ApplicationSignInManager takes a UserManager parameter and I can see that the UserManager takes an IPasswordHasher parameter.
I'm assuming SignInManager uses the UserManager which uses the PasswordHasher. So my question is, how do I get the UserManager to use my custom Password Hasher? Or if thats not the case, how do I get the SignInManager to use my Password hasher?
EDIT: I've been able to confirm that when my ApplicationUserManager is instantiated, my SqlPasswordHasher is being used in the constructor so the DI is working properly. I just can't figure out why my override of VerifyHashedPassword is not being triggered.

It turns out the problem was not related to code at all. Adding my SqlPasswordHasher to the services via
services.AddScoped<IPasswordHasher<ApplicationUser>, SqlPasswordHasher>();
worked perfectly.
The problem was with how I migrated the data. Since I was using an existing database that was being used with an older version of Identity, I had to add the following fields to my existing AspNetUsers table:
NormalizedUserName
ConcurrencyStamp
LockoutEnd
NormalizedEmail
However I didn't populate the NormalizedUserName or NormalizedEmail fields. So that's why it was never triggering my override of VerifyHashedPassword; because it never found my user since it was looking up based on NormalizedUserName.
Once I populated those fields it started triggering my VerifyHashedPassword method.

Related

Replace the injected HttpContext for class in application

I'm setting up some integration tests for mediatr handlers using xunit, respawn, and webapplicationfactory....
One of classes ultimately called by the mediatr handler that is being tested.. has a dependency on IHttpContextAccessor as you can see below
I feel like I've set up the "replacement" singleton that I want injected correctly as per below:
But when the integration test runs.. the httpContextAccessor is not null but the HttpContext is ALWAYS null.
I've tried about 6 million things :( Much sadness.
How can get the IHttpContextAccessor to resolve correctly to what I'm setting in ConfigureServices?
When the integration test runs.. the httpContextAccessor is not null but the HttpContext is ALWAYS null.How can get the IHttpContextAccessor to resolve correctly to what I'm
setting in ConfigureServices?
No we cannot, The HttpContext will only be available within the scope of the request because ConfigureServices invocked before constructing Startup so if we try to inject, it will through exception, even if we declare at global variable in that scenario it will always be null. Application startup happens only once, and long before any request has been received.
Let's try to access it within IConfiguration as following:
public Startup(IConfiguration configuration,IHttpContextAccessor httpContextAccessor)
{
Configuration = configuration;
HttpContextAccessor = httpContextAccessor;
}
public IConfiguration Configuration { get; }
public IHttpContextAccessor HttpContextAccessor { get; }
Output:
As you can see, it doesn't allow us to do so.
Even if we try to inject it within configuration itself it will ended up with following exception:
Therefore, ConfigureServices runs once before any httprequest coming to application. If we forcefully try to call it outside of request life-cycle it will always ended up with NullReferenceException. You can get more details in the official document.
In addition to this, we can inject service reference within configuration as following:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
I needed to implement IHttpContextAccessor myself
Then utilise in the ConfigureTestServices of the WebApplicationFactory ConfigureWebHost

How to get the object in constructor in MEF Framework same as AspNet Core Identity UserManager implementation

I am using ASPNET.Core.Identity UserManager as constructor parameter in my class
public class UserService
{
[ImportingConstructor]
public UserService(UserManager<ApplicationUser> userManager)
{
}
}
When I resolve the MEF container using
UserService= container.GetExportedValue<UserService>();
I am getting a error as "'No exports were found that match the constraint'"
My question is how to get the usermanager object without initializing usermanager object.
As I saw in many examples regarding ASPNET.Core.Identity UserManager, The UserManger object is configured in Startup class and using dependency injection we can get the object in constructor how to do the same in MEF?

No service for type 'Microsoft.AspNetCore.Identity.SignInManager When

I am getting
InvalidOperationException: No service for type
'Microsoft.AspNetCore.Identity.SignInManager
1[Authorization.IdentityModels.ApplicationUser]' has been registered.
when I run my ApsCore MVC website.
this are segments from my code:
ConfigureServices:
services.AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(configuration["Data:DefaultConnection:ConnectionString"]));
services.AddIdentity<ApplicationUser, IdentityRole<Guid>>()
.AddEntityFrameworkStores<ApplicationDbContext, Guid>()
.AddDefaultTokenProviders();
Configure:
app.UseIdentity();
ApplicationDbContext.cs
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>
ApplicationUser.cs
public class ApplicationUser : IdentityUser<Guid>
I will be very happy if you can help me.
Faced with the same issue after moving my Identity classes to Guid and found solution here:
You probably need to change your login partial view to use the new
user type IdentityUser
Within Views/Shared/_LoginPartial.cshtml, I just changed
#using Microsoft.AspNetCore.Identity
#inject SignInManager<IdentityUser> SignInManager
#inject UserManager<IdentityUser> UserManager
To
#using Microsoft.AspNetCore.Identity
#inject SignInManager<MyUser> SignInManager
#inject UserManager<MyUser> UserManager
and that worked for me.
Not sure if you are still seeing this issue, but here's some help for anyone else that stumbles upon this. (Note that the specifics are for version 1, but the need for an injected dependency not being available is the same.)
The issue is coming from some class in your application requiring a SignInManager in its constructor, but there isn't an implementation associated with it in the dependency injection setup.
To fix, in your Startup class, in the ConfigureServices method, register the SignInManager class in the services. For example:
services.AddScoped<SignInManager<ApplicationUser>, SignInManager<ApplicationUser>>();
The AddIdentity extension method may have been updated since the original question was asked to add this in, but the same error type will show up for anything the IoC container can't resolve.
This is what worked for me. I had added identity when i was creating the project which made it possible for the framework to inject UserManager<IdentityUser> and SignInManager<IdentityUser> into my _loginPartial View. What i did was to change the Type<TUser> from <IdentityUser> to <ApplicationUser>(ApplicationUser is the identity class i want to use in the project which inherits from IdentityUser class) and everything works fine.

Windsor Dependencies injection in mvc 4 rc into parametereized apicontroller

So, i used Mark Seemann's example to do dependency injection with Windsor in MVC 4 RC Web Api, but i get an exception saying that it can't resolve the dependencies to my ApiController
public class StatisticsController : ApiController
{
private readonly ILogger _logger;
private readonly IClickMessageProducer _producer;
public StatisticsController(ILogger logger,
IClickMessageProducer clickMsgProducer)
{
_logger = logger;
_producer = clickMsgProducer;
}
public string Get(string msg, string con) {...}
}
My Global.asax looks like this:
protected void Application_Start()
{
// different configs removed for brevity
BootstrapContainer();
}
private static IWindsorContainer _container;
private static void BootstrapContainer()
{
_container = new WindsorContainer()
.Install(FromAssembly.This(), new ProducerInstaller())
.Install(FromAssembly.This(), new WebWindsorInstaller());
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpControllerActivator),
new WindsorHttpControllerActivator(_container));
}
The Installers gives Windsor the references needed to IClickMessageProducer. I have it working with IController in a genuine MVC 4 project so i'm confident that part is working.
To specify, this is the error message i get, when trying to access a method in StatisticsController with a GET call to the API:
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Can't create component 'APIMVC.Controllers.StatisticsController'
as it has dependencies to be satisfied.
'APIMVC.Controllers.StatisticsController' is waiting for the following
dependencies: - Service 'Castle.Core.Logging.ILogger' which was not registered.
</ExceptionMessage>
<ExceptionType>Castle.MicroKernel.Handlers.HandlerException</ExceptionType>
<StackTrace>...</StackTrace>
</Error>
The call being something like this:
"http://localhost:60000/api/statistics?msg=apitest&con=apimvc"
If anyone has a working example or just a comment to the problem about my Windsor implementation i'll be happy to see it.
Your ILogger implementation isn't registered with Windsor. Remove the ILogger parameter from StatisticsController and try again. If it works, you're going to need to register an ILogger implementation.
_container = new WindsorContainer().Install(FromAssembly.This(), new ProducerInstaller()).Install(FromAssembly.This(), new WebWindsorInstaller());
this was the part at fault. As you can see I call Install(FromAssembly.This()) twice witch caused the LoggerInstaller to try to add a LoggingFacilitytwice causing an error.
The new implementation would look like this:
_container = new WindsorContainer().Install(FromAssembly.This(), new ProducerInstaller(), new WebWindsorInstaller());

ServiceStack Authenticate attribute results in null ref exception - pull request 267

I am making an MVC3 site using ServiceStacks authentication mechanism. When I add the AuthenticateAttribute to a controller, I get a null reference exception:
System.NullReferenceException was unhandled by user code
HResult=-2147467261
Message=Object reference not set to an instance of an object.
Source=ServiceStack.FluentValidation.Mvc3
StackTrace:
at ServiceStack.Mvc.ExecuteServiceStackFiltersAttribute.OnActionExecuting(ActionExecutingContext filterContext) in C:\src\ServiceStack\src\ServiceStack.FluentValidation.Mvc3\Mvc\ExecuteServiceStackFiltersAttribute.cs:line 21
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
I can see in github that pull request #267 seems to make some null ref check exactly where my code currently throws. I have another project where authentication works, but the new failing code is running on a newer version of ServiceStack and I can't see what the difference is, so any ideas about what could cause this exception for new versions of service stack (v. 3.9.18)
Here is my configuration code:
Plugins.Add(new AuthFeature(
() => new AuthUserSession(), // Here a custom IAuthSession implementation could be used instead of UserSession.
// Allow authentication by using cookies set when authenticating with username/password credentials posted to the /auth/credentials service.
new IAuthProvider[]{ new CredentialsAuthProvider() }
)
);
//Enable Funq IOC in MVC controllers.
ControllerBuilder.Current.SetControllerFactory(new FunqControllerFactory(container));
IUserAuthRepository userRepository = new OrmLiteAuthRepository(dbFactory);
container.Register(userRepository);
container.Register<ICacheClient>(new MemoryCacheClient());
// Initialise Registration feature, providing the /register route.
Plugins.Add(new RegistrationFeature());
And my Controller base class:
public abstract class ControllerBase : ServiceStackController<AuthUserSession> {
public IDbConnectionFactory Db { get; set; }
public ILog Log { get; set; }
//Common extension point for all controllers. Inherits from ServiceStack to take advantage of SS powerpack + auth.
public override string LoginRedirectUrl {
get {
return "/Auth/Login?redirect={0}";
}
}
}
I've updated the ServiceStack.Mvc NuGet package that resolved a null reference exception in (v3.9.18+). Try updating and see if that resolves it.