GithubHelp home page GithubHelp logo

aspnetidentity's People

Contributors

haok avatar joeloff avatar kahbazi avatar terrajobst avatar wtgodbe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aspnetidentity's Issues

where to register IUserTwoFactorTokenProvider type custom token provider?

I have created a custom google authenticator token provider implementing IUserTwoFactorTokenProvider. but I'm not sure where and how do I register this new provider in Startup?

public class GoogleAuthenticatorTokenProvider : IUserTwoFactorTokenProvider<User>
    {
        public GoogleAuthenticatorTokenProvider()
        {
        }

        public Task<bool> CanGenerateTwoFactorTokenAsync(UserManager<User> manager, User user)
        {
            return Task.FromResult(user.IsGoogleAuthenticatorEnabled);
        }

        public Task<string> GenerateAsync(string purpose, UserManager<User> manager, User user)
        {
            return Task.FromResult((string)null);
        }

        public Task<bool> ValidateAsync(string purpose, string token, UserManager<User> manager, User user)
        {
            long timeStepMatched = 0;

            var otp = new Totp(WebEncoders.Base64UrlDecode(user.GoogleAuthenticatorSecretKey));
            bool valid = otp.VerifyTotp(token, out timeStepMatched, new VerificationWindow(2, 2));

            return Task.FromResult(valid);
        }
    }

UseExternalSignInCookie needs a callback for configuring the cookie

aspnet/AspNetKatana#331 (comment)

public static void UseExternalSignInCookie(this IAppBuilder app, string externalAuthenticationType)
{
if (app == null)
{
throw new ArgumentNullException("app");
}
app.SetDefaultSignInAsAuthenticationType(externalAuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = externalAuthenticationType,
AuthenticationMode = AuthenticationMode.Passive,
CookieName = CookiePrefix + externalAuthenticationType,
ExpireTimeSpan = TimeSpan.FromMinutes(5),
});
}

UseExternalSignInCookie creates a temp cookie for remote auth signin (e.g. Facebook). However it only lets you configure the name. If you want to make changes then you need to copy the code into your project (very confusing for users).

This has become more relevant since there was a .NET patch that interferes with this cookie. Users need to set the SystemWebCookieManager to mitigate the issue.

Proposal:

public static void UseExternalSignInCookie(this IAppBuilder app, Action<CookieAuthenticationOptions> configure)
public static void UseExternalSignInCookie(this IAppBuilder app, string externalAuthenticationType, Action<CookieAuthenticationOptions> configure)

@blowdart

HttpContext.Current null in callbacks (caused by WithCurrentCulture)

I'm using Asp.Net Identity on .Net Framework 4.8 and MVC 5. I'm using HttpContext to track contextual information about a request. However Asp.Net Identity uses ConfigureAwait(false), which means that HttpContext.Current becomes null in callbacks. For example when subclassing PortalSignInManager, HttpContext.Current is null inside SignInAsync.

I suppose WithCurrentCulture was introduced when Asp.Net Core didn't flow HttpContext. However that's no longer the case for newer versions, and this workaround is breaking my application.

ChangeEmailAsync - not updating the username

ChangeEmailAsync is not updating the username though I have set the uniqueEmailAddress in the builder.

var builder = services.AddIdentity<ApplicationUser, ApplicationRole>(opt => { opt.User.RequireUniqueEmail = true; }

one of the issues have "IsUsernameEmailAddress" dynamic property added recently. I'm using 2.1 .net core. but could not see this.

Wondering do I need to use the above in this case? or Is it a bug?

Ex: Generate token GenerateChangeEmailTokenAsync then ChangeEmailAsync to see the behaviour.

Two factor code useable more than once

It is possible to use the second factor code more than once, e.g. when using the EmailTokenProvider. For security, I would expect that the second factor code becomes invalid after a successful login.

To reproduce:

  1. Log in with two factors.
  2. Log out
  3. Log in with two factors, using the second factor code from step 1.

A possible workaround is to call UserManager.UpdateSecurityStampAsync(userId) after a successful two factor authentication. This will invalidate all issued second factor codes for the user.

asp.net identity cross framework issue - .net core vs .net framework

I need to reuse Identity 3.0 (.Net Core) users to Identity 2.2.1 (.Net Framework) but login is failing because the password is not matching. help, please.

Is there a difference in the Hashing mechanism in .Net Core vs .Net Framework?

Identity 3.0 sample password looks like AQAAAAEAACcQAAAAExxxxxxxx.

Enabling and populating roles seems overly complicated and poorly documented

Setting up roles seems to be a lot harder than I think it should be. Using code first, it appears the tables related to roles were created. But understanding how to enable and populate them is frustrating.

I've found numerous articles explaining how to do it and everyone of them is different. None of the Microsoft articles seems specific to this.

Based on what I've read, I end up with something like this in startup.

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));

    services.AddDefaultIdentity<ApplicationUser>(options =>
        {
            options.SignIn.RequireConfirmedAccount = false;
        })
        .AddRoles<ApplicationUser>()
        .AddEntityFrameworkStores<ApplicationDbContext>();

    services.AddRazorPages();

    // Set the default authentication policy to require users to be authenticated
    services.AddControllers(config =>
    {
        var policy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .Build();
        config.Filters.Add(new AuthorizeFilter(policy));
    });
}

But the call to AddDefaultIdentity raises an exception.

System.InvalidOperationException: 'AddEntityFrameworkStores can only be called with a role that derives from IdentityRole.'

I just want to enable roles and prepopulate the roles with the ones I'm using. Is there no straight forward way documented to do this?

FileVersion of Microsoft.AspNet.Identity.* 2.2.2 is listed as 0.0.0.0

Reported by a user on nuget.org:

The file version of this library (Microsoft.AspNet.Identity.Core.dll, also Microsoft.AspNet.Identity.EntityFramework.dll and Microsoft.AspNet.Identity.Owin.dll) is set to 0.0.0.0 causing problems during update installations.

The problem might originate from the internal version number being 2.2.2.70424.0, with the fourth component being larger than 65535.

Can you rerelease this package with fixed version numbers?

Here is the info for 2.2.2 of Microsoft.AspNet.Identity.Core.dll

image

Password backward compatibility

From @rvandulek on November 12, 2017 22:41

I'm in the process of creating a new MVC application that has to plug in to our existing SQL Server based user store. The problem is old user accounts can't be used in the new website, trying to log in with one results in "failure". New accounts can be created, but can't be used by the existing MVC web sites, try to login in with one results in "failure". I'm guessing this is a compatibility issue for the hashed passwords. How can I configure the new site, to use the existing (circa 2014 MVC) password hash? I've compared the NuGet packages in both websites and they match (both are using 2.2.1)

Copied from original issue: aspnet/Identity#1501

Failed login attempts are not counted if email address is null or empty

If Email field is null or empty the UserManager will not update the database table and since AccessFailedCount is stored in the same table it will not be incremented.

await UserManager.AccessFailedAsync(user.Id).WithCurrentCulture(); returns an error, but this is not checked, in SignInManager.PasswordSignInAsync and SignInManager.TwoFactorSignInAsync.

This means that an attacker can guess passwords for such a user indefinitely.

Change EmailConfirmationToken expired time

Hi, i'm trying to change the expiration time of the EmailConfirmationToken that is generated with the GenerateEmailConfirmationTokenAsync method.

To do that, i added the next code in startup.cs class:

private const string EmailConfirmationTokenProviderName = "ConfirmEmail";

public void ConfigureServices(IServiceCollection services)
{
...

services.Configure<IdentityOptions>(options =>
{
    options.Tokens.EmailConfirmationTokenProvider = EmailConfirmationTokenProviderName;
});

services.Configure<ConfirmEmailDataProtectionTokenProviderOptions>(options =>
{
    options.TokenLifespan = TimeSpan.FromDays(1);
});

services.AddIdentity<ApplicationUser, IdentityRole>(
    item =>
    {
        ...
        item.Tokens.EmailConfirmationTokenProvider = EmailConfirmationTokenProviderName;
        item.Tokens.PasswordResetTokenProvider = EmailConfirmationTokenProviderName;
    })
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders()
    .AddTokenProvider<ConfirmEmailDataProtectorTokenProvider<ApplicationUser>>(EmailConfirmationTokenProviderName);
...

}
public class ConfirmEmailDataProtectionTokenProviderOptions : DataProtectionTokenProviderOptions { }

public class ConfirmEmailDataProtectorTokenProvider : DataProtectorTokenProvider where TUser : class
{
public ConfirmEmailDataProtectorTokenProvider(IDataProtectionProvider dataProtectionProvider, IOptions options, ILogger logger) : base(dataProtectionProvider, options, logger)
{
}
}
The project is in Core 3.1, when i set options.TokenLifespan = TimeSpan.FromMinutes(5) for example, it works perfectly but when i set 24 hours or one day in TokenLifespan, the token expire in one hour more or less. The same problem occurs with PasswordResetToken.

Can't exceed a max time? How could I solve the problem?

Sign in windows development machine is working, after publish to linux - error String '' was not recognized as a valid DateTime.

Result:

 fail: Microsoft.AspNetCore.Server.Kestrel[13]
 Connection id "0HMCIB3PQJ72M", Request id "0HMCIB3PQJ72M:00000002": An unhandled exception was thrown by the application.
 System.FormatException: String '' was not recognized as a valid DateTime.
    at System.DateTimeParse.Parse(ReadOnlySpan`1 s, DateTimeFormatInfo dtfi, DateTimeStyles styles, TimeSpan& offset)
    at System.DateTimeOffset.Parse(String input, IFormatProvider formatProvider, DateTimeStyles styles)
    at System.DateTimeOffset.Parse(String input, IFormatProvider formatProvider)
    at Microsoft.Data.Sqlite.SqliteValueReader.GetDateTimeOffset(Int32 ordinal)
    at Microsoft.Data.Sqlite.SqliteValueReader.GetFieldValue[T](Int32 ordinal)
    at Microsoft.Data.Sqlite.SqliteDataRecord.GetFieldValue[T](Int32 ordinal)
    at Microsoft.Data.Sqlite.SqliteDataReader.GetFieldValue[T](Int32 ordinal)
    at lambda_method104(Closure , QueryContext , DbDataReader , ResultContext , SingleQueryResultCoordinator )
    at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
    at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
    at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
    at Microsoft.AspNetCore.Identity.UserManager`1.FindByNameAsync(String userName)
    at Microsoft.AspNetCore.Identity.SignInManager`1.PasswordSignInAsync(String userName, String password, Boolean isPersistent, Boolean lockoutOnFailure)
    at BioMindsXRSrv.Web.Controllers.UserController.Login(String userName, String password) in D:\GitHub\BioMindsXR_Srv\BioMindsXRSrv.Web\Controllers\UserController.cs:line 78
    at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
    at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
    at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
    at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
    at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
    at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
 --- End of stack trace from previous location ---
    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
 --- End of stack trace from previous location ---
    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
    at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
    at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
    at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
    at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
    at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

Code for login:

var addInfo = string.Empty;
            if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password))
            {

[78line]                var result = await signInManager.PasswordSignInAsync(userName, password, false, false);
                addInfo = result.ToString();
                if (result.Succeeded)
                {
                    return Redirect("~/");
                }
            }

user:

    public class User : IdentityUser<Guid>
    {
        [DisallowNull]
        [Required]
        [PersonalData]
        public string FirstName { get; set; } = string.Empty;

        [DisallowNull]
        [Required]
        [PersonalData]
        public string LastName { get; set; } = string.Empty;

        [PersonalData]
        public UserSettings UserSettings { get; set; } = new UserSettings();

        [PersonalData]
        public ICollection<UserTherapy>? UserQuests { get; set; }
        [PersonalData]
        public bool IsAdmin { get; set; }
        [PersonalData]
        public bool IsDoctor { get; set; }
        [PersonalData]
        public Guid? DoctorId { get; set; }

        [NotMapped]
        public IEnumerable<string> RoleNames { get; set; }

        [IgnoreDataMember, NotMapped]
        public string Password { get; set; }

        [IgnoreDataMember, NotMapped]
        public string ConfirmPassword { get; set; }

        [IgnoreDataMember, NotMapped]
        public string Name
        {
            get => UserName;
            set => UserName = value;
        }
        [PersonalData]
        public string? HospitalName
        {
            get;
            set;
        }
        [PersonalData]
        public string? Phone
        {
            get;
            set;
        }

        [PersonalData]
        public DateTime? DateOfTheTest { get; set; }

        [PersonalData]
        public string? Diagnosis { get; set; }

        [PersonalData]
        public DateTime? DateOfDiagnosis { get; set; }

        [PersonalData]
        public DateTime? StartDateOfTherapy { get; set; }
        [PersonalData]
        public EHandiness? Handiness { get; set; }

        [PersonalData]
        public string? AdlScores { get; set; }

        [PersonalData]
        public string? BarthelResults { get; set; }

        [PersonalData]
        public string? NeuropsychologicalResults { get; set; }

        [PersonalData]
        public string? Other { get; set; }
    }

public virtual TKey ConvertIdFromString(string id) does not work for Guid

Could you please change the ConvertIdFromString method to return using this code in the Microsoft.AspNetIdentity.Owin.SignInManager class:

return (TKey)TypeDescriptor.GetConverter(typeof(TKey)).ConvertFromInvariantString(id);

I downloaded the source code, made this change on my local. However, when I try to run my project with this new update I get an error about StrongName verification.

UserManager.AddToRolesAsync() and RemoveFromRolesAsync() fail on any conflict

When adding multiple roles or generally updating a user's roles, I'd like to be able to just give UserManager.AddToRolesAsync() the full list of roles that the user should have and have it add any new roles. As it currently is, if the user already has even 1 of the roles being assigned, the operation reports as a failure, at best having added any new roles in the list prior to the role that the user already has.

Similarly, when removing roles, UserManager.RemoveFromRolesAsync() will fail if the user does not have any of the given roles when, in my opinion, it should ignore those and continue with removing any that the user does have.

Looking at the code, it appears that it could be as simple as changing return new IdentityResult(Resources.UserAlreadyInRole); to continue; in UserManager.AddToRolesAsync() and changing return new IdentityResult(Resources.UserNotInRole); to continue; in UserManager.RemoveFromRolesAsync().

Problem with change email confirmation after scaffolding

Hi,

After I scaffolded ASP.NET Core Identity into my Blazor (Server) project I noticed that I was unable to change email address using the function presented on Account\Manage\Email.cshtml

The email confirmation would send as expected however when I clicked on the link the value of result.Succeeded on line 42 of Account\ConfirmEmailChange.cshtml.cs was always false.

code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code));
var result = await _userManager.ChangeEmailAsync(user, email, code);
if (!result.Succeeded)
{
	StatusMessage = "Error changing email.";
	return Page();
}

In noticed on Account\Manage\Email.cshtml.cs that within OnPostSendVerificationEmailAsync() after the token code was generated on line 129 using await _userManager.GenerateEmailConfirmationTokenAsync(user) that it was then encoded using code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));

This encoding is missing within OnPostChangeEmailAsync() after var code = await _userManager.GenerateChangeEmailTokenAsync(user, Input.NewEmail); on line 93.

When I add code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); to line 94 the issue is resolved and result.Succeeded returns true.

Thanks

TKey should be reference type, or compared against `default`

Various places in the SignInManager compare the userId against null. This is a problem for value types, for example Guid. I cannot use Guid? in my TUser as it needs to implement IEquatable<TKey>.

public override Guid ConvertIdFromString(string id) => Guid.Parse(id);

This returns Guid.Empty if id == null. However Guid.Empty != null and various places now assume a valid user. I see two possible fixes for this:

  1. Require TKey to be a reference type: null checks can remain as-is.
  2. Replace null checks with default checks: Guid.Empty == default.

Some places where using a value type is a problem:



return await GetVerifiedUserIdAsync().WithCurrentCulture() != null;

SigninManager on Asp.Net 6 Identity returns failure when app is deployed

Hi,
I'm having a weird issue and this is the last place to search for an answer. I have created a site for deployment to my ISP. Whenever I try to sign in with users created locally it returns Result.Failed. I'm using the generic Identity scaffold with Personal Data added.

I have deployed another site to the same ISP with the same boiler plate code and it worked fine. I found the error by returning result.ToString() in the else statement in Login.cshtml.cs as the PasswordSighInAsync function only returns a status message and not an error.

else
{
     ModelState.AddModelError(string.Empty, result.ToString());
    return Page();
}

I checked the SigninManager code here and there are three situations when failure is assigned, but it's not clear why logging into the same remote DB with the same ApplicationDbContext succeeds when I run locally in either debug or release.

I also hit the error below when trying to register from the .com web site and it doesn't happen locally. But checking the DB the user is created. Testing also showed that setting RequireConfirmedAccount to false still returns NotAllowed.

Turning off the RequireConfirmed was necessary becuase the GenerateTokenAsync() call would fail

**Error.
An error occurred while processing your request.

Request ID: 00-825112947d1a57ef4eca465146ff6805-747b92bafdb872df-00
Development Mode

Swapping to Development environment will display more detailed information about the error that occurred.

The Development environment shouldn't be enabled for deployed applications. It can result in displaying sensitive information from exceptions to end users. For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development and restarting the app.**

Extend IdentityUserClaim

Hi,

I would like to know if it is possible to extend IdentityUserClaim.

So far I've created a CustomIdentityUser and CustomIdentityUserClaim. Next I've added a Claims property for CustomIdentityUserClaim using the new keyword (override not possible because of different type) to the CustomerIdentityUser.

The database is created without any troubles using EF. However when trying to use the database, e.g. using for CustomUserManager.FindAsync an exception is thrown stating "The navigation property 'Claims' on entity type 'CustomIdentityUser' cannot be used for entities of type 'IdentityUserClaim' because it refers to entities of type 'CustomIdentityUserClaim'."

I've already tried inheriting from IdentityUser<>, however this results in problems with using the UserStore as this expects IdentityUser.

Any thoughts or ideas?

Cheers,

Peter

Support For Chrome Cookie Extensions (CHIPS)

Similarly to the SameSite extension a few years ago, Google is planning to imminently change the default handling of third party cookies in Chrome (see https://developers.google.com/privacy-sandbox/3pcd/chips for more information). In many use cases and scenarios involving framing a widget or similar in an external site, this will be required for third party cookies to continue to work on Chrome (for non-tracking purposes). They plan to enable this for 1% of users imminently. We still have some applications on .NET 4.x using ASPNetIdentity and this support is fairly crucial for some of our embedding scenarios where our site is embedded in a third party site (not for advertising, but for functionality). We need support for adding the "Partitioned" attribute to auth cookies to allow them to continue to be set in these use cases.

It appears that this has been addressed in the Core Identity library, but not the 4.x version: dotnet/aspnetcore#39968

I'd propose that a new CookiePartitioned property be added to the CookieAuthenticationOptions class, and then used to send this attribute if true.

If there is some workaround to allow setting this additional attribute without adding an explicit property, I'd be open to hearing about it.

Resource file for Dutch (NL)

Hello,

on nuget we can find the language files for many languages, like Microsoft.AspNet.Identity.Core.es for Spanish, for example. But we need language file for Dutch now and we can't find the one. Do we search wrong way?

It is not problem for us to include these labels to be translated, as we translate rest of our app to Dutch, but we can't find repo or source code for other languages, so we do not know where to submit these translations eventually.

Can you help us with it?

Thanks, Tom

Entity Framework Core storage provider

I'm trying to migrate parts of my application to .net core instead of everything at once. I'd like to try moving from EF to EF Core now but can't because of ASP.NET Identity relying it. Are there any EF Core storage providers for ASP.NET Identity? I haven't had much luck searching for one because of the similar names.

Using navigation properties does not allow to use some methods from UserManager or RoleManager

I went through a guide describing how to configure navigation properties for the identity package and encounter a problem with relations between defined navigation properties, causing problem with eg. assinging role to user.

Steps to reproduce:

  1. Configure database context with the navigation properties eg. UserRoles link to source.
  2. Add application user using UserManager<ApplicationUser> with method CreateAsync.
  3. Add role using RoleManager<ApplicationRole> with method CreateAsync.
  4. Confirm that user and role are added to database.
  5. Assign role to the user using UserManager<ApplicationUser> with method AddToRoleAsync.
  6. Observe that there is new entry in UserRole table which is correct, but with incorrect UserId and RoleId, which does not exist and was generated with running previous step.

Users:
image

UserRoles:
image

Roles:
image

I checked assigning role to user directly using ApplicationDbContext, which was successful and no ghost entries were added to Users and Roles tables:

context.UserRoles.Add(new ApplicationUserRole
{
    RoleId = adminRole.Id,
    Role = adminRole,
    UserId = admin.Id,
    User = admin,
});

The same situation happens when using other navigation properties like IdentityClaims and etc.

Issue reproduced with:

  • PostgreSQL 16
  • .NET 6
  • Microsoft.AspNetCore.Identity.EntityFrameworkCore 6.0.24

FailedAccessAttempts doesn't reset when TwoFactorEnabled and Browser Remembered

Using 2.2.1 but can see the issue in master

PasswordSignInAsync will reset it for non-2FA accounts:

if (!await IsTwoFactorEnabled(user))

TwoFactorSignInAsync will reset it for 2FA accounts:

public virtual async Task<SignInStatus> TwoFactorSignInAsync(string provider, string code, bool isPersistent, bool rememberBrowser)

But if the user has previously remembered the browser, TwoFactorSignInAsync never happens, so it never resets.

Now that I understand what is going on, we can address it by resetting as appropriate, but this behavior was not expected and leaves 2FA accounts that have been locked out before in a state such that any single successive password failure after the lockout has expired, will increment the count (which is still over the limit) and locks the account again.

Some thoughts on possibilities:

  1. Check TwoFactorBrowserRememberedAsync during PasswordSignInAsync and reset if remembered.
  2. Don't increment failed access attempts during PasswordSignInAsync on 2FA accounts, but have lockout only apply on the TwoFactorSignInAsync. Basically 2FA would only lockout with 2FA failures, but not password failures.
  3. Force a 2FA verification after a lockout has occurred/expired

AuthenticationTicket claims vs UserClaimsPrincipalFactory claims

Hi,

I've been trying to persist a custom claim in the browser on sign-in and it feels like there's a bit of a conflict with how subsequent requests are handled, but maybe I'm missing something obvious.

The claims exist in the cookie, and are successfully restored to the ClaimsPrincipal via CookieAuthenticationHandler, but then somewhere further along the pipeline, the UserClaimsPrincipalFactory comes along and decides what the claims should be for the user - and obviously they don't include my custom one(s).

In the past I've dealt with this by subclassing UserClaimsPrincipalFactory and doing a database lookup for the extra claims I need, but in this case I don't want to, as the claim is specific to the browser that the user signed in with - not their account/identity. If they're signed out I'm perfectly happy to lose this claim as it'll be regenerated when they sign in again. It's also really useful to have that information as just another claim, as I can easily pick it up from filters, etc.

Am I doing something wrong? Is there a way to bring these two concepts together in some kind of harmony? At the moment it seems like cookie claims are pretty much irrelevant.

Thanks in advance for any pointers.

Nat

Conflict between Identity class and its extended one.

I am trying to add a shadow property to all my tables using the following code in my builder override,

foreach (var entityType in builder.Model.GetEntityTypes ()) {
        entityType.GetOrAddProperty ("IsDeleted", typeof (bool));
        var parameter = Expression.Parameter (entityType.ClrType);
        var propertyMethodInfo = typeof (EF).GetMethod ("Property").MakeGenericMethod (typeof (bool));
        var isDeletedProperty = Expression.Call (propertyMethodInfo, parameter, Expression.Constant ("IsDeleted"));
        BinaryExpression compareExpression = Expression.MakeBinary (ExpressionType.Equal, isDeletedProperty, Expression.Constant (false));
        var lambda = Expression.Lambda (compareExpression, parameter);
        builder.Entity (entityType.ClrType).HasQueryFilter (lambda);
 }

I have This "ApplicationRole" class which extends the IdentityRole,

    public class ApplicationRole : IdentityRole {
        public string Description { get; set; }

        [Required]
        public Guid DatabaseId { get; set; }

        [ForeignKey ("DatabaseId")]
        public virtual PracticeDatabase Database { get; set; }
    }

How can I resolve this conflict?

currently I resolve it by exlcuding the extended class as follows,

  if (entityType.Name == "ArtNgCore.Core.Models.IdentityModels.ApplicationRole") {
      return;
    }

is there another way ?

The conflict message is,

System.InvalidOperationException: The property or navigation 'IsDeleted' cannot be added to the entity type 'IdentityRole' because a property or navigation with the same name already exists on entity type 'ApplicationRole'.
at Microsoft.EntityFrameworkCore.Metadata.Internal.EntityType.AddProperty(String name, Type propertyType, MemberInfo memberInfo, ConfigurationSource configurationSource, Nullable1 typeConfigurationSource) at Microsoft.EntityFrameworkCore.Metadata.Internal.EntityType.AddProperty(String name, Type propertyType, ConfigurationSource configurationSource, Nullable1 typeConfigurationSource)
at ArtNgCore.Persistence.Core.ArtCoreDbContext.OnModelCreating(ModelBuilder builder) in /Users/json/OneDrive/MyProjects/ArtNgCore/Persistence/Core/ArtCoreDbContext.cs:line 68
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator)
at System.Lazy1.ViaFactory(LazyThreadSafetyMode mode) at System.Lazy1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
at System.Lazy1.CreateValue() at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel() at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model() at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies() at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider() at Microsoft.EntityFrameworkCore.Internal.InternalAccessorExtensions.GetService[TService](IInfrastructure1 accessor)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func1 factory) at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType) at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_01.b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
The property or navigation 'IsDeleted' cannot be added to the entity type 'IdentityRole' because a property or navigation with the same name already exists on entity type 'ApplicationRole'

wrong Newtonsoft.json when publish

It seems like there is something wrong with Microsoft.AspNetCore.Authentication.JwtBearer library. I made an API that uses this library. it works perfect in dev.
But when I publish in production (Release, Self-Contained, win-x64) , I am getting error indicating Newtonsoft.json version 10.0 not found (and further complaining about not able to get config from my IdentityServer).
My debug folder has version 10.0.1, but my publish folder has version 9.0.1 !
The error goes away when I manually replace the NewtonSoft.json with the one in my debug folder.
I am using
.NetCore 3.1.
Microsoft.AspNetCore.Authentication.JwtBearer 3.1.7

Assembly file versions not set for Microsoft.AspNet.Identity.* 2.2.2

I'm wondering if there's a reason why the file version field for 2.2.2 hasn't been set for the Owin, EntityFramework and Core assemblies? For 2.2.1 the file version field was set to 2.2.1.40403 but in the latest version it's just set to 0.0.0.0.

This is causing us issues when we try to update the assemblies with a Windows Installer because it thinks that 2.2.2 is older than 2.2.1 since the file version fields are set to zero. So we are seeing errors like this for the Identity components:

MSI (c) (84:54) [16:21:44:440]: Disallowing installation of component: {49CB1C30-1258-4AB8-951C-D580FCAFD9F8} since the same component with higher versioned keyfile exists

I found this StackOverflow answer from Rob Mensching explaining the problem in greater detail: https://stackoverflow.com/a/15139855/253193

Error while adding user to role if AutoSaveChanges is false

Description

I'd like to disable AutoSaveChanges (I also changed key type to int), then create user, add it to role and save it to database. CreateAsync is succcessful. However when I try to add user to role I'm getting following error:

{
    "error": "The property 'User.Id' has a temporary value while attempting to change the entity's state to 'Unchanged'. Either set a permanent value explicitly, or ensure that the database is configured to generate values for this property."
}

Steps to Reproduce

  1. Change key type to int
  2. Create CustomUserStore which inherits from UserStore
  3. Disable AutoSaveChanges
  4. Run UserManager::CreateAsync
  5. Run UserManager::AddToRoleAsync

Actual result:
Error occurs:

{
    "error": "The property 'User.Id' has a temporary value while attempting to change the entity's state to 'Unchanged'. Either set a permanent value explicitly, or ensure that the database is configured to generate values for this property."
}

Expected result:
User added to role

Did you find any workaround?

Yes. Looking at the identity code I noticed that internally UpdateAsync is called after AddToRoleAsync. UpdateAsync calls Context.Attach on the user object. However user object is already tracked and modified so that the exception is thrown. I changed UpdateAsync in my custom user store to:

public override async Task<IdentityResult> UpdateAsync(User user, CancellationToken cancellationToken = default)
{
    if (AutoSaveChanges)
    {
        return await base.UpdateAsync(user, cancellationToken);
    }

    return IdentityResult.Success;
}

but then different error occurred:

{
    "error": "The value of 'UserRole.UserId' is unknown when attempting to save changes. This is because the property is also part of a foreign key for which the principal entity in the relationship is not known."
}

Looking at DebugView.LongView I noticed that UserId in UserRole is different than Id in User so that relationship is wrong:

User {Id: -2147482647} Added
    Id: -2147482647 PK Temporary
    AccessFailedCount: 0
...


UserRole {UserId: -2147482646, RoleId: 1} Added
UserId: -2147482646 PK FK Temporary Unknown
RoleId: 1 PK FK    
...

Id which is set on User entity is 0 but Id tracked by EF is -2147482647. It seems that store does not recognize that Id has temporary value and treats it as new one. To "fix" relationship I assigned UserId in custom store:

protected override UserRole CreateUserRole(User user, Role role)
{
    var currentValueId = Context.Entry(user).Property(e => e.Id).CurrentValue;
    user.Id = currentValueId;

    return base.CreateUserRole(user, role);
}

Now it's working without exceptions. However it seems that it should be handled correctly by Identity. It seems that UpdateAsync is not needed to be called if AutoSaveChanges is false as the caller already decided to do it by himself. Entity should be also recognized as temporary.

Problem with Identity C# request with Entity Framework

Hello,
I have problem with Identity remote (in hosting),
the queries (list of products etc) to the database works, except the queries with Identity (Authentication)
Here is my connection chain:

And this is example for connection string from MS SQL Ionos:
Provider=sqloledb;Data Source=db******.hosting-data.io,1433;Initial Catalog=db*******;User Id=dbo******;Password=*****;

Stack Trace : https://pastebin.com/zjTyir6r

ASP.NET Identity CookieAuthentication middleware results in too many redirects for authorized users visiting login page with a ReturnUrl param

If you set an explicit LoginPath for CookieAuthenticationOptions, authenticated users who navigate a restricted area they are not authorized to access (e.g. because of not having the right role), will trap in a redirect loop.

Steps to produce the issue

  1. Create an ASP.NET MVC web application.
  2. Create an Area named 'Admin'.
  3. Add a controller named 'MainController'
  4. Decorate the controller with '[Authorize(Roles = "SomeRole")]'
  5. Customize CookieAuthentication in Start.Auth.cs by providing an explicit path for login page (CookieAuthenticationOptions.LoginPath property).
  6. Launch the application.
  7. Register.
  8. Login.
  9. Now, Navigate to "/admin/main".

[Authorize] filter in MainController sends the user to the login page (LoginPath) together with a ReturnUrl. There, CookieAuthentication middleware detects that current user is an authenticated user and there is also a ReturnUrl param in the Url, so, it redirects the user back to the ReturnUrl.

The surprising thing is that the Login() action in AccountController -AccountController.Login(string returnUrl) - is also executed each time the user is redirected to login page!

This issue does not happen if you do not set an explicit LoginPath for CookieAuthentication middleware. In this case, when an authenticated user is redirected from a restricted area to login page (with a ReturnUrl param), the View in login page is executed normally and returned. So, we can check Request.IsAuthenticated in the View and instead of the login form show a message such as "You are currently logged in as ...., click here to sign in as another user".

This is the same thing I wanted to do in my own project, but since I had set a LoginPath, I was facing the "too many redirects" error. It took me a half day until I found out the culprit is CookieAuthenticationOptions.LoginPath!

There may be problems with the usernames in uppercase in different cultures.

hi @HaoK

Queries for usernames and email addresses in UserStore and RoleStore are converted to uppercase.

public virtual Task<TUser> FindByNameAsync(string userName)
{
ThrowIfDisposed();
return GetUserAggregateAsync(u => u.UserName.ToUpper() == userName.ToUpper());
}

Consider this situation:

Thread.CurrentThread.CurrentCulture = new CultureInfo("tr");
var admin = await _userManager.FindByNameAsync("admin");

In the current culture, the uppercase of admin is no longer ADMIN but ADMİN

ADMİN ≠ ADMIN

This will cause problems.
I saw the latest IdentityCore added NormalizedUserName and converted using ToUpperInvariant.
How to deal with the problems caused by this cultural difference?

thanks.

AccessFailedAsync is not incrementing AccessFailedCount

Anytime I call userManager. AccessFailedAsync the database is never updated and the code never fails. When I attempt to debug the code using the downloaded symbols, I am not able to set breakpoints on every line and the code jumps out unexpectely

var result = await userManager.AccessFailedAsync(user);

A search of StackOverflow reveals others having the same problem
https://stackoverflow.com/questions/54460611/user-manager-accessfailed-async-not-incrementing

ClaimsIdentityFactory.CreateAsync Null Reference Exception

I am trying to use userManager.CreateIdentityAsync method, but I get a NRE everytime.
After debugging the code for AspNetIdentity, I have noticed that the NRE was thrown when calling CreateAsync in ClaimsIdentityFactory class method.
More precisely, the exception is thrown when iterating over the list of roles, but in my particular case it is null and so it throws. I have added a comment in the code to indicate exactly where the exception is thrown:

/// <summary>
///     Create a ClaimsIdentity from a user
/// </summary>
/// <param name="manager"></param>
/// <param name="user"></param>
/// <param name="authenticationType"></param>
/// <returns></returns>
public virtual async Task<ClaimsIdentity> CreateAsync(UserManager<TUser, TKey> manager, TUser user,
            string authenticationType)
        {
            if (manager == null)
            {
                throw new ArgumentNullException("manager");
            }
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }
            var id = new ClaimsIdentity(authenticationType, UserNameClaimType, RoleClaimType);
            id.AddClaim(new Claim(UserIdClaimType, ConvertIdToString(user.Id), ClaimValueTypes.String));
            id.AddClaim(new Claim(UserNameClaimType, user.UserName, ClaimValueTypes.String));
            id.AddClaim(new Claim(IdentityProviderClaimType, DefaultIdentityProviderClaimValue, ClaimValueTypes.String));
            if (manager.SupportsUserSecurityStamp)
            {
                id.AddClaim(new Claim(SecurityStampClaimType,
                    await manager.GetSecurityStampAsync(user.Id).WithCurrentCulture()));
            }
            if (manager.SupportsUserRole)
            {
                IList<string> roles = await manager.GetRolesAsync(user.Id).WithCurrentCulture(); // <-- roles is null
                foreach (string roleName in roles) // <-- NRE thrown here
                {
                    id.AddClaim(new Claim(RoleClaimType, roleName, ClaimValueTypes.String));
                }
            }
            if (manager.SupportsUserClaim)
            {
                id.AddClaims(await manager.GetClaimsAsync(user.Id).WithCurrentCulture());
            }
            return id;
        }

I am not sure why the list of roles is null though. Is this bug or is there something I am missing there? Thanks.

NuGet:

  • package: Microsoft.AspNet.Identity.Core
  • version: 2.2.1

TotpSecurityStampBasedTokenProvider defines a fixed timestep of 3 minutes

I'm implementing TOTP using the TotpSecurityStampBasedTokenProvider and couldn't figure out why it wasn't working with Google Authenticator.

While debugging I noticed that TotpSecurityStampBasedTokenProvider uses a fixed timestep of 3 minutes while google authenticator has a default set to 30 seconds. This difference causes the algorithm to generate different codes. It can not be modified in any way either.

The Google Authenticator documentation specifies it has the option but it is not taken into account.

How can I resolve this without creating my own provider?

If you like I can create a pull request that allows users to override the currently hardcoded timestep.

Extending UserRole-Class causes Exception

Hi There,

I am trying to extend the Identity framework. Extending IdenityUser works fine, but when I try to entend the IdenityUserRole class, I run into an System.Argument Exception "GenericArguments[5], 'SecondHandWeb.Areas.Identity.Data.SecondHandWebUserRole', on 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`9[TUser,TRole,TContext,TKey,TUserClaim,TUserRole,TUserLogin,TUserToken,TRoleClaim]' violates the constraint of type 'TUserRole'." in IdentityHostingStartup.cs

            services.AddIdentity<SecondHandWebUser, SecondHandWebRole>( )
                .AddEntityFrameworkStores<SecondHandWebContext>()
                .AddDefaultTokenProviders()
                .AddDefaultUI(); 

the constructor for my Context looks like this:

    public class SecondHandWebContext : IdentityDbContext<SecondHandWebUser, IdentityRole<string>, string, IdentityUserClaim<string>, SecondHandWebUserRole, IdentityUserLogin<string>, IdentityRoleClaim<string>, IdentityUserToken<string>>

I am using the latest Nugetpackage, Microsoft.AspNetCore.Identity.EntityFrameworkCore 5.0

who can I solve this??

Kind regards,

Martin

Issue with trying to use multiple identities .net core 5.0

Hi everyone,

I am new to asp.net core and i started working on asp.net from version 5.0 core. I have switched to asp.net from laravel php framework. This was my brief introduction. I have been working on asp.net and using database first approach i built dbcontext and implemented my whole system in asp.net but in start i wanted to use identity scaffolding and use all commands that added a new identitydbcontext. So i have now two dbcontext one is asp.net core default with only identity and other is my database from db first approach.

I have implemented the default identity system by using

services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = false)
                .AddRoles<IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>();

But after this i wanted to authenticate users against a custom model tblemployee with fields i.e phone and scale. But when i try to add this by using a method that I found here Asp.net core 2.0 multiple identity .

My code to do that is

services.AddIdentityCore<TblEmployee>().AddEntityFrameworkStores<DbBzuCCContext>().AddDefaultTokenProviders();

But the code is not working it says that extend from IdentityUser but i can't use identityuser fields in my model. I just want to use my 2 fields to work as additional identity provider. Is there any way in middle ware to change default route for different identity and all my previous controllers to be used from default identity but new one with other identity.

Any help will be highly appreciated.

Regards,

sign-oidc Redirect Loop

I consider this a bug in functionality as there should never get into an infinite loop. I've tried this question with IDS 4 team but they don't respond well. I've got a base asp.net core 3.1 application, trying to integrate it with Identity Server 4. Login page works, user gets authenticated. I've added code for the event handlers in
.AddOpenIdConnect("oidc", options =>

OnTicketReceived the Principal Identity is populated with claims, sub, name and a few others. User shows as authenticated. However, OnRedirectToIdentityProvider keeps firing in a loop. If you watch the browser, you see the code_challenge value constantly changing. Not sure that's an indicate or anything other than I'm stuck in an infinite loop. My first question, how can we enable some type of authentication logging to try and determine what is causing a problem with the asp.Net core Identity code? This has been a nuisance for a long time. At the very least we should be able to implement logging or debugging to try and determine why it's getting stuck in a loop and continually redirects. I just switched to trying IE 11 & Edge and sign in, get redirected back to the Signin-oidc link and I see a correlation failed message on the page. (I'm looking into that now.)

Checking to see if email confirmation token has expired

Is there a way to do this? Like an error code that will return when the email confirmation token has expired?
For example if the error code was "TokenExpired" I could use the following to return the user to a specific view which gives them advice on a process to follow if their token has expired:

        var result = await _userManager.ConfirmEmailAsync(user, code);
        if (result.Succeeded) return View("ConfirmEmail");

        return View(result.Errors.Any(c => c.Code == "TokenExpired") ? "TokenExpired" : "Error");

Tag and document releases

Nuget has new Microsoft.AspNet.Identity.* versions available (2.2.2), but it is impossible to get any information about what has changed compared to previous versions or which state of source code maps to given version for manual verification.

Please do add all releases to publicly visible release notes (or github Releases page), add link to it to nuget package metadata, and tag corresponding codebase in git.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.