JudahGabriel / RavenDB.Identity

RavenDB Identity provider for ASP.NET Core. Let RavenDB manage your users and logins.
https://www.nuget.org/packages/RavenDB.Identity/1.0.0
MIT License
61 stars 29 forks source link

Two-factor authentication error: "Store does not implement IUserAuthenticatorKeyStore<User>" #3

Closed AlphaComposite closed 5 years ago

AlphaComposite commented 6 years ago

(there's a discussion about this error on another project's issues list https://github.com/mrahhal/MR.AspNet.Identity.EntityFramework6/issues/12)

When clicking on Two-factor authentication at /Manage/Index, I'm taken to /Manage/TwoFactorAuthentication and get the following error:

An unhandled exception occurred while processing the request. NotSupportedException: Store does not implement IUserAuthenticatorKeyStore. Microsoft.AspNetCore.Identity.UserManager.GetAuthenticatorKeyStore()

Here's the entire stack: NotSupportedException: Store does not implement IUserAuthenticatorKeyStore. Microsoft.AspNetCore.Identity.UserManager.GetAuthenticatorKeyStore() Microsoft.AspNetCore.Identity.UserManager.GetAuthenticatorKeyAsync(TUser user) Sample.Controllers.ManageController+d22.MoveNext() in ManageController.cs + var model = new TwoFactorAuthenticationViewModel System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) System.Runtime.CompilerServices.TaskAwaiter.GetResult() Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d12.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d10.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted) Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d14.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+d22.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context) Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted) Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+d17.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+d15.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Builder.RouterMiddleware+d4.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+d6.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware+d4.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware+d6.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware+d6.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

JudahGabriel commented 6 years ago

I've implemented IUserAuthenticatorKeyStore and pushed out a new version to NuGet. Can you try it and let me know?

AlphaComposite commented 6 years ago

Okay, I updated all the Nuget packages.

Now I get this:

An unhandled exception occurred while processing the request. NotSupportedException: Store does not implement IUserTwoFactorRecoveryCodeStore.

Stack:

NotSupportedException: Store does not implement IUserTwoFactorRecoveryCodeStore. Microsoft.AspNetCore.Identity.UserManager.GetRecoveryCodeStore() Microsoft.AspNetCore.Identity.UserManager.CountRecoveryCodesAsync(TUser user) Sample.Controllers.ManageController+d22.MoveNext() in ManageController.cs + var model = new TwoFactorAuthenticationViewModel System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) System.Runtime.CompilerServices.TaskAwaiter.GetResult() Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d12.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d10.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted) Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d14.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+d22.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context) Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted) Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+d17.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+d15.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Builder.RouterMiddleware+d4.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+d6.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware+d4.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware+d6.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware+d6.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware+d__7.MoveNext()

AlphaComposite commented 6 years ago

I think all these will have to be implemented. The latest changes to Core's Identity seem pretty substantial:

    IUserLoginStore<TUser>,
    IUserRoleStore<TUser>,
    IUserClaimStore<TUser>,
    IUserPasswordStore<TUser>,
    IUserSecurityStampStore<TUser>,
    IUserEmailStore<TUser>,
    IUserLockoutStore<TUser>,
    IUserPhoneNumberStore<TUser>,
    IQueryableUserStore<TUser>,
    IUserTwoFactorStore<TUser>,
    IUserAuthenticationTokenStore<TUser>,
    IUserAuthenticatorKeyStore<TUser>,
    IUserTwoFactorRecoveryCodeStore<TUser>
JudahGabriel commented 6 years ago

I've implemented all those interfaces except IQueryableUserStore. I uploaded a new package to NuGet. Let me know if that's working for you.

AlphaComposite commented 5 years ago

Sorry for the long overdue response, but I had to deal with my cancer treatment!

Now it's an error stating that IQueryableUserStore isn't implemented in Store. Looks like that one will have to be implemented, too.

image

JudahGabriel commented 5 years ago

So sorry to hear about your cancer. Get well.

I've committed a change to implement IQueryableUserStore, and I updated the NuGet package.

AlphaComposite commented 5 years ago

Thanks, Judah. It was a long process.

There's not a QueryAsync method. It's complaining about the Query method not being async.

The new exception is in the recent implementation: "System.NotSupportedException: You can't query sync from an async session at Raven.Client.Documents.Session.AsyncDocumentSession.Raven.Client.Documents.Linq.IDocumentQueryGenerator.Query[T](String indexName, String collectionName, Boolean isMapReduce) in C:\Builds\RavenDB-Stable-4.0\src\Raven.Client\Documents\Session\AsyncDocumentSession.Query.cs:line 83 at Raven.Client.Documents.Linq.RavenQueryProviderProcessor1.GetDocumentQueryFor(Expression expression) in C:\Builds\RavenDB-Stable-4.0\src\Raven.Client\Documents\Linq\RavenQueryProviderProcessor.cs:line 2581 at Raven.Client.Documents.Linq.RavenQueryProviderProcessor1.Execute(Expression expression) in C:\Builds\RavenDB-Stable-4.0\src\Raven.Client\Documents\Linq\RavenQueryProviderProcessor.cs:line 2653 at Raven.Client.Documents.Linq.RavenQueryProvider1.Execute(Expression expression) in C:\Builds\RavenDB-Stable-4.0\src\Raven.Client\Documents\Linq\RavenQueryProvider.cs:line 125 at Raven.Client.Documents.Linq.RavenQueryProvider1.System.Linq.IQueryProvider.Execute(Expression expression) in C:\Builds\RavenDB-Stable-4.0\src\Raven.Client\Documents\Linq\RavenQueryProvider.cs:line 197 at Raven.Client.Documents.Linq.RavenQueryInspector1.GetEnumerator() in C:\Builds\RavenDB-Stable-4.0\src\Raven.Client\Documents\Linq\RavenQueryInspector.cs:line 83 at Raven.Client.Documents.Linq.RavenQueryInspector1.System.Collections.IEnumerable.GetEnumerator() in C:\Builds\RavenDB-Stable-4.0\src\Raven.Client\Documents\Linq\RavenQueryInspector.cs:line 89"

image

JudahGabriel commented 5 years ago

You know, 2FA used to work just fine with this library; I'm disappointed Microsoft has so broken existing libs.

What part of your code triggers the exception? It's trying to synchronously enumerate results, which is a blocking call on an async doc session.

If you're not doing anything to trigger the exception, then there's no easy fix here. We'd have to wire up the store differently so as to fetch a sync IDocumentSession from the injector. Not fun.

AlphaComposite commented 5 years ago

It happens when clicking "two-factor authentication" on the page at /Manage/Index.

No custom code here. Just trying to run the sample app.

JudahGabriel commented 5 years ago

OK, looking at this now, seeing if we can have a clean way of making this work. I should have something today.

JudahGabriel commented 5 years ago

Are you sure this is as real exception (not one being thrown by the debugger's eager evaluation)? I applied a small fix to the library and now can access /manage/index just fine, as well as /manage/twofactorauthentication: image image

JudahGabriel commented 5 years ago

I just pushed a new update to source and NuGet, where the Sample project now has a fully-functional 2-factor auth. Please give it a try - it should work for you.

AlphaComposite commented 5 years ago

Getting past the other errors, but there's a new one that referenced a null value at line 720 in UserStore.cs:

    public Task<int> CountCodesAsync(TUser user, CancellationToken cancellationToken)
    {
        return Task.FromResult(user.TwoFactorRecoveryCodes.Count);
    }

It appears that when the user record is created that the roles, claims, and logins all have the values of "[]" in ravendb - indicating a list. But...the value listed for TwoFactorRecoveryCodes is "null" in ravendb. After changing the value to "[]", the error was eliminated.

The attached image is what was created in the AppUser document in Raven when registering a new user. image

AlphaComposite commented 5 years ago

Here's the change that I made to eliminate the error when clicking the two-factor authentication link. image

I couldn't tell what was causing the new user registration to have a null value added instead of a list added for the TwoFactorRecoveryCodes.

AlphaComposite commented 5 years ago

Ah...never mind...it was using an existing record from a previous version. All new records created with this newest version have the [] instead of the null for the value in TwoFactorRecoveryCodes.

I see you added this to IdentityUser.cs : this.TwoFactorRecoveryCodes = new List();

JudahGabriel commented 5 years ago

Yep, that was part of the fix. I'm closing this issue assuming you're not hitting any other problems. Let me know if you hit any other issues.