I have removed the "AspNetUserClaims" table from my DB because I am not saving any claims information.
After creating a user I am trying to fetch user info by its user name and it returns an error:
"Invalid object name 'dbo.AspNetUserClaims'.".
IdentityResult result = await manager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
var userInfo = manager.FindByName(user.UserName);
foreach (var myRole in myRoles)
{
manager.AddToRole(userInfo.Id, myRole.Name);
}
await AddToPreviousPasswordsAsync(user, user.PasswordHash);
}
In the UserManager class of Identity 2, the Entity Framework-backed UserStore will ensure the claims are loaded for the requested user.
This accesses the AspNetUserClaims table, which will throw an exception when your database doesn't contain that table.
Simply don't remove tables that are required by a library, or rebuild the library without the claims part. And you don't want to do the latter, because then you won't receive any updates from the official channel anymore, and have to manually patch it. This is no way to handle a security-related library, or generally any library for that matter.
Related
I'm learning asp.net core and I'm stuck. I'll try to explain somehow.
Problem is with user claim.
When I log in into website, user have, let's say Create and Delete Claim and all working.
But when THAT user changes that HE cannot Delete something, after updating database HE still can.
In database Delete is gone (which is good).
Authorization is checked by authorization attribute:
[Authorize(Policy="DeletePolicy")]
I found something what may help.
ClaimsPrincipal User
property still have both claims (Create and Delete), but when I check DB:
await userManager.GetClaimsAsync("user_id")
I get only Create Claim which is good.
My question is: what precisely is that ClaimsPrincipal User property and why is not updated automatically?
Do I need to update User's Claims manually?
Claims are embedded in authentication cookie. It's like a snapshot of user's claims at a moment when user was signed in. Instead of putting all claims into cookie you can create ExtraClaimsMiddleware and put it after authentication middleware:
public class ExtraClaimsMiddleware
{
private readonly RequestDelegate _next;
public ExtraClaimsMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context,
YourDb db)
{
//get additional claims for the current user from database, cache it if you want
var userId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
var extraClaims = await db.GetExtraClaimsAsync(userId);
foreach (var claim in extraClaims)
{
context.User.Identities.First().AddClaim(new Claim(claim.ClaimType, claim.ClaimValue));
}
await _next(context);
}
}
public static class ExtraClaimsMiddlewareExtensions
{
public static IApplicationBuilder UseExtraClaims(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ExtraClaimsMiddleware>();
}
}
Then in Startup.cs:
app.UseAuthentication();
app.UseExtraClaims();
I am not sure if I understand your problem correctly but I guess it can be solved with the SignInManager Class.
After you deleted the claim from the database you should be able to use the “RefreshSignInAsync”-Method to update the user´s cookie.
I'm making my own system to authenticate jwt tokens in certain scenarios.
When I have properly validated the token, I have
var userIdentity = await user.CreateIdentityAsync(DefaultAuthenticationTypes.ExternalBearer);
owinContext.Authentication.User = new System.Security.Claims.ClaimsPrincipal(userIdentity);
owinContext.Authentication.SignIn(userIdentity);
System.Web.HttpContext.Current.User = owinContext.Authentication.User;
await next()
but that doesn't seem to fix authentication which still fails at - I believe - the Asp.Net Mvc level. Because I know it uses HttpContext I try adding this before calling next()
HttpContext.Current.User = new GenericPrincipal(userIdentity, new string[0]);
This gets me further along but I still seem to be getting an an authorization error it would seem (by searching source for the message that I get and where its used) to be coming from the Web Api [Authorize] attribute.
I'm hitting a wall as far as tracing through the .net source code. The only way I should be getting this message is if IsAuthorized returns false. But there are no roles nor users specified (it's just plain [Authorize]) and before heading off to the next() I can stop the debugger and check that yes there is a user identity, and yes it IsAuthorized.
I've overridden the AuthorizeAttribute so as to place breakpoints and can see that by the time it is called however, my actionContext is associated with a completely different identity with IsAuthorized == false. Which in turn makes me wonder if I'm signing in the user identity wrong
So... am I doing this correctly? What should I be doing?
I have never undertstood why but in my case, i have need to valid the ticket after signing in:
var userIdentity = await user.CreateIdentityAsync(DefaultAuthenticationTypes.ExternalBearer);
ctx.Authentication.SignIn(userIdentity);
AuthenticationTicket ticket = new AuthenticationTicket(userIdentity, null);
ctx.Validated(ticket);
Edit
I'm not really in the same context. In my case, I have a custom authentication provider inheriting of Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationProvider :
public class CustomBearerAuthenticationProvider:OAuthBearerAuthenticationProvider
{
public CustomBearerAuthenticationProvider() : base()
{
this.OnValidateIdentity = (context) => Task.Run(() =>
{
var identity = this.CreateApplicationIdentity(user);
context.OwinContext.Authentication.SignIn(identity);
AuthenticationTicket ticket = new AuthenticationTicket(identity, null);
context.Validated(ticket);
});
}
}
context is of type : Microsoft.Owin.Security.OAuth.OAuthValidateIdentityContext
MVC 5 with Dapper and User < int >
I followed ASP.Net's MVC 5 Guidance for Google OAuth2
I set up UseGoogleAuthentication in Startup.ConfigureAuth
Clicking the Google login button all seems to work, until the user tries to finalize to connection to the web app in
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl)
In the basic template of code created, when I created the project, the function creates a user object and tries to create the User:
var user = new PortalUser { UserName = model.Email, Email = model.Email };
var result = await UserManager.CreateAsync(user);
Then I get the lovely error:
Source: .Net SqlClient Data Provider
Target: Void OnError(System.Data.SqlClient.SqlException, Boolean, System.Action`1[System.Action])
Type: SqlException
Message: Cannot insert the value NULL into column 'PasswordHash', table 'WebApplication1.dbo.AspNetusers'; column does not allow nulls. INSERT fails.
The statement has been terminated.
So, how am I supposed to pass a password hash, from an External Login?
Or - do I allow nulls in the table?
Or - is there some aspect of the UserManager / UserStore / PortalClaimsIdentityFactory that I'm not fulfilling (overriding) because I'm using User < int > User keys?
I have implemented the ForgotPassword (with token reset) into my MVC 5 application. We are in production. Although this works in majority of the cases, many of our end-users are of older age and get confused when they cannot login and need a reset. So in those situations, I am considering giving one of our admin staff the ability to reset a user's password and giving them the new password on the phone. The data is not that sensitive.
I tried this:
public ActionResult ResetPassword()
{ UserManager<IdentityUser> userManager =
new UserManager<IdentityUser>(new UserStore<IdentityUser>());
var user = userManager.FindByEmail("useremail.samplecom");
userManager.RemovePassword(user.Id);
userManager.AddPassword(user.Id, "newpassword");
}
I get a cryptic error stating Invalid Column EMail, Invalid Column Email Confirmed ......
I also tried the userManager.ResetPassword(), but abandoned that idea because it needs a token reset. I want to bypass it.
What am I not seeing?
Thanks in advance.
I also tried the userManager.ResetPassword(), but abandoned that idea because it needs a token reset. I want to bypass it.
How about you just generate the token and pass it to the Reset routine ?
var userManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
var code = await userManager.GeneratePasswordResetTokenAsync("username");
var result = await userManager.ResetPasswordAsync("username", code, "your new password");
if (!result.Succeeded)
{
//password does not meet standards
}
The idea here is you are just emulating/bypassing the usual routine of sending the token to the client (via email) and having the link that they click on call ResetPasswordAsync
I'm not completely sure if this will work in your implementation but I use the following code with success in a use case which has basically the same requirements as yours. The difference is that I'm not letting any user reset it's own password. This is always the task of an admin.
I'm bypassing the ApplicationUserManager and edit the information directly in the table, using just Entity Framework.
// I created an extension method to load the user from the context
// you will load it differently, but just for completeness
var user = db.LoadUser(id);
// some implementation of random password generator
var password = General.Hashing.GenerateRandomPassword();
var passwordHasher = new Microsoft.AspNet.Identity.PasswordHasher();
user.PasswordHash = passwordHasher.HashPassword(password);
db.SaveChanges();
You have to get the user from the database and generate the code not by username :
public async Task<Unit> ResetPassword(string userName, string password)
{
if (!string.IsNullOrWhiteSpace(userName))
{
var returnUser = await _userManager.Users.Where(x => x.UserName == userName).FirstOrDefaultAsync();
var code = await _userManager.GeneratePasswordResetTokenAsync(returnUser);
if (returnUser != null)
await _userManager.ResetPasswordAsync(returnUser, code, password);
}
return Unit.Value;
}
I would like to manually validate a password reset token in ASP.NET Identity 2.0. I'm trying to create my own version of UserManager.ResetPasswordAsync(string userId, string token, string newPassword) that takes and IdentityUser instead of userId like this:
UserManager.ResetPasswordAsync(IdentityUser user, string token, string newPassword)
Not sure if I am doing this right, but here I am attempting to validate the code that was emailed to the user in an earlier step. I have not modified the code/token that sends the email to the user and generates the code. I am assuming this is the correct method to call, but the purpose argument is incorrect. (I tried passing "ASP.NET Identity" but no dice.)
if (await userManager.UserTokenProvider.ValidateAsync(purpose: "?", token: code, manager: userManager, user: user))
{
return IdentityResult.Success;
}
else
{
return new IdentityResult("Invalid code.");
}
If someone could fill me in on the details of how it works out of the box, or point me at Microsoft's source code for UserManager.ResetPasswordAsync(IdentityUser user, string token, string newPassword) that would be most appreciated!
I overcame my problem by setting the purpose to "ResetPassword".
Below is a snippet of the final result in case someone wants to do something similar. It is a method in my ApplicationUserManager class. Realize, though, that some of the exception handling that Microsoft implements is missing or not localized because certain private variables, methods, and resources used in their code are inaccessible. It's unfortunate they did not make that stuff protected so that I could have gotten at it. The missing ThrowIfDisposed method call in particular is interesting (and bazaar) to me. Apparently they are anticipating method calls after an instance has been disposed in order to provide a friendlier error message and avoid the unexpected.
public async Task<IdentityResult> ResetPasswordAsync(IdentityUser user,
string token, string newPassword)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
// Make sure the token is valid and the stamp matches.
if (!await UserTokenProvider.ValidateAsync("ResetPassword", token,
this, user))
{
return IdentityResult.Failed("Invalid token.");
}
// Make sure the new password is valid.
var result = await PasswordValidator.ValidateAsync(newPassword)
.ConfigureAwait(false);
if (!result.Succeeded)
{
return result;
}
// Update the password hash and invalidate the current security stamp.
user.PasswordHash = PasswordHasher.HashPassword(newPassword);
user.SecurityStamp = Guid.NewGuid().ToString();
// Save the user and return the outcome.
return await UpdateAsync(user).ConfigureAwait(false);
}
It appears that the code for Microsoft.AspNet.Identity has not been Open Sourced according to the Codeplex repository located at:
https://aspnetidentity.codeplex.com/SourceControl/latest#Readme.markdown
At present, the ASP.NET Identity framework code is not public and
therefore will not be published on this site. However, we are planning
to change that, and as soon as we are able, the code will be published
in this repository.
However I did find this which might be the source for the UserManager based on the debug symbols:
UserManager Source Code
I also found these posts which might help:
Implementing custom password policy using ASP.NET Identity
UserManager Class Documentation
IUserTokenProvider Interface Documentation