Getting captcha plugin to work with register action - asp.net-mvc-5

I have the login portion working and the register page displays the captcha clearly, the .dll for RecaptchaMVC5 says that AccountController does not contain a definition for verifyReCAPTCHA but it works with the login portion:
Examples:
Login thats working:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
// Verify the recaptcha response.
ReCaptchaResponse response = await this.verifyReCAPTCHA(model, "key", true);
if (response.Success)
{
var user = await UserManager.FindAsync(model.UserName, model.Password);
if (user != null)
{
await SignInAsync(user, model.RememberMe);
return RedirectToLocal(returnUrl);
}
else
{
ModelState.AddModelError("", "Invalid username or password.");
}
}
else
{
ModelState.AddModelError("", "Invalid Captcha Code!");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
My Register Mockup that throws errors on verifyReCAPTCHA:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
//Verify the recaptcha response.
ReCaptchaResponse response = await this.verifyReCAPTCHA(model, "key", true);
if (response.Success)
{
var user = new ApplicationUser() { UserName = model.UserName };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "Home");
}
else
{
AddErrors(result);
}
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
the error I get
Error 1 'ReCaptchaMVC5Test.Controllers.AccountController' does not contain a definition for 'verifyReCAPTCHA'

Inside Models folder > AccountViewModels.cs There is
public class LoginViewModel : ReCaptchaViewModel
and
public class RegisterViewModel : <Place 'RecaptchaViewModel' Here>
That's how you assign the Captcha's view model to other models

assuming both these methods are on the AccountController, what is the method signature for verifyReCAPTCHA as the methods both send different models (LoginViewModel and RegisterViewModel) do both inherit from the correct base?

From what I can tell by the source, there's an extension method you're unable to access. Looks like you need to add using ReCaptcha.Mvc5; to the top of your Controller's source file to gain access.
verifyReCAPTCHA(this Controller, ReCaptchaViewModel, String, Boolean)
Also, make sure your model inherits from ReCaptcha.Mvc5.Model.ReCaptchaViewModel (as demonstrated in their documentation), that way you satisfy the method signature.

Related

After Logout, login with the same user credentials is not working with Mongo Realm

I am using below code to log out the the current logged in user
public async Task Logout()
{
SecureStorage.RemoveAll();
await RealmMain.realmApp.CurrentUser.LogOutAsync();
}
Then, I use below code to sign in back again.
public async Task<bool> LoginWithCredential(Action<string> error)
{
try {
var credentials = Credentials.EmailPassword(userId, pass);
var user = await RealmMain.realmApp.LogInAsync(credentials);
return user != null;
}
catch (Exception ex){
SecureStorage.RemoveAll();
Console.WriteLine(ex);
error(exceptionText);
return false;
}
}
RealmMain Class is like this below.
public sealed class RealmMain
{
private const string AppId = "*************";
public static App realmApp = App.Create(AppId);
public SyncConfiguration ConfigForSync
{
get
{
var temp = new SyncConfiguration(realmApp.CurrentUser.Id, realmApp.CurrentUser)
{
// EncryptionKey = AppContext.GetBytes(AppContext.DbKey)
};
Console.WriteLine(temp.EncryptionKey);
return temp;
}
}
public static RealmMain Instance { get; } = new RealmMain();
private RealmMain()
{
}
}
Problem here is - When is log out and then try to sign in with the same user credential.
I get below error.
"Realms.Sync.Exceptions.AppException: Unknown: must authenticate first
at Realms.Sync.App.LogInAsync (Realms.Sync.Credentials credentials)"
If I use some different user to sign in after logging out.
I get this.
In nutshell Logout and then login is not working for me, I have to quit the app to make it work every time.
Any suggestion to solve this issue would be appreciated.

Getting UserId from MVC using WebMetrix

I'm using bellow login method to login in a MVC 5 application.
What I want to do is get the id of the user that is currently logged.
I tried to use these 2 methods:
// 1
// This one raise an exception:
Guid loggedUser = (Guid)Membership.GetUser().ProviderUserKey;
Additional information: Object reference not set to an instance of an
object.
// 2
// sets loggedUser variable to null
loggedUser = User.Identity.GetUserId();
// Login Method within Controller
public ActionResult Login(Login logindata, string ReturnUrl)
{
if (ModelState.IsValid)
{
if (WebSecurity.Login(logindata.Username, logindata.Password))
{
if (ReturnUrl != null)
{
return Redirect(ReturnUrl);
}
return RedirectToAction("Index", "Home");
}
}
ModelState.AddModelError("", "Sorry the username or password is invalid ");
return View(logindata);
}
My question is what I'm doing wrong and if it's possible to get the logged user id like this???
Thanks
I used this method and worked:
WebSecurity.GetUserId("loggedUser")

ASP.NET Identity: UserManager.PasswordHasher.VerifyHashedPassword keeps failing

I'm using ASP.NET Identity 2 with Entity Framework 5 (because our Oracle data provider does not support EF6). For some reason the password verification by means of UserManager.PasswordHasher.VerifyHashedPassword keeps failing.
My UserStore class contains:
public Task SetPasswordHashAsync(IccmUser user, string passwordHash)
{
IPasswordHasher hasher = new PasswordHasher();
var t = Task.Run(() => {
user.PasswordHash = hasher.HashPassword(passwordHash);
});
return t;
}
The (obviously hashed) password is stored in the database. Thus, this code seems to work just fine.
My AccountController does the password verification like this:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(SignInModel model, string returnUrl)
{
if (ModelState.IsValid) {
// This fails:
//var user = await UserManager.FindAsync(model.UserName, model.Password);
// Thus: do it step by step.
PasswordVerificationResult result = PasswordVerificationResult.Failed;
// Step 1: find user.
IccmUser user = await UserManager.FindByNameAsync(model.UserName);
if (user == null) {
ModelState.AddModelError("", "Couldn't find the user.");
} else {
// Step 2: validate password
result = UserManager.PasswordHasher.VerifyHashedPassword(user.PasswordHash, model.Password);
if (result != PasswordVerificationResult.Success) {
ModelState.AddModelError("", "The password is not valid.");
} else {
// Step 3: sign-in user.
await SignInAsync(user, model.RememberMe);
return Redirect(returnUrl);
}
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
The VerifyHashedPassword() in step 2 always returns Failed. Both parameters (PasswordHash and Password) are passed in correctly.
Any pointers to what I'm missing are greatly appreciated.
The error is in the UserStore implementation. SetPasswordHashAsync() is not supposed to hash the password. Instead, it receives the hashed password from UserManager.CreateAsync(). Thus, the following change in UserStore does the trick:
public Task SetPasswordHashAsync(IccmUser user, string passwordHash)
{
return Task.FromResult(user.PasswordHash = passwordHash);
}
Sorry for the noise.

MVC5 (VS2012) UserManager doesn't sign user in

This is a continuation of this question.
If I override the userManager:
public class NHibernateAspnetUserManager<TUser> : UserManager<TUser> where TUser : IdentityUser
{
public NHibernateAspnetUserManager(IUserStore<TUser> store) : base(store)
{
}
public override Task<ClaimsIdentity> CreateIdentityAsync(TUser user, string authenticationType)
{
var identity = new ClaimsIdentity();
identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName));
return Task.FromResult(identity);
}
}
This doesn't throw any errors but will not log the user in, (log process happens but #Request.IsAuthenticated will always return false). If I don't override it then I get a "System.Security.Claims.Claim..ctor" error as described in the other question. To try and solve that my own userstore implemented IUserClaimStore but simply return a new list of claims.
I am not sure what the default usermanager does under the hood that differs. I am guessing it sets up some form of claim identity object that allows MVC to recognise someone as logged in.
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = isPersistent}, identity);
EDIT
Found out why the ctor error was occuring. The user object was coming back without the ID so the default UserManager was getting upset. Fixed that and used the default UserManager which now no longer throws an error, but still doesn't log the user in. The identity object it returns looks good from what I can tell.
FURTHER NOTE
So I installed VS2013 and copied the store and NHibernate repo across, all worked first time. I can only assume there is some sutble difference between creating it and updating MVC5 in VS2012 and doing it in VS2013.
So the main issue is that you aren't respecting the authentication type in your method, you need to create a ClaimsIdentity for DefaultAuthenticationType.ApplicationCookie, here's what the default claims factory does:
public override Task<ClaimsIdentity> CreateIdentityAsync(TUser user, string authenticationType)
{
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));
I've faced the same problem implementing custom identity using ASP.NET 4.5. And the problem really was in adding null values into the Claims collection (see the comments):
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new AppUser { UserName = model.UserName };
// after the UserManager creates a user, all the properties of
// AppUser except "UserName" are automatically discarded
var result = await UserManager.CreateAsync(new AppUser
{
UserRealName = model.UserRealName,
UserName = model.UserName,
Password = model.Password
}, model.Password);
if (result.Succeeded)
{
// So we need to re-get the new user
user = AppUser.GetByName(model.UserName);
await SignInAsync(user, false); // otherwise here we will add null values ...
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
return View(model);
}
private async Task SignInAsync(AppUser user, Boolean isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
var identity = await UserManager.CreateIdentityAsync(user,
DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties // ... into the list of
// claims for all AppUser properties except UserName
{ IsPersistent = isPersistent }, identity);
}

ASP.net Identity Disable User

Using the new ASP.net Identity in MVC 5, How do we disable a user from logging in? I don't want to delete them, maybe just disable their account for a time period.
Does anyone have any ideas on this as I don't see a status column or anything on the ASPNetUsers table.
await userManager.SetLockoutEnabledAsync(applicationUser.Id, true);
await userManager.SetLockoutEndDateAsync(DateTime.Today.AddYears(10));
Update: As CountZero points out, if you're using v2.1+, then you should try and use the lockout functionality they added first, before trying the solution below. See their blog post for a full sample: http://blogs.msdn.com/b/webdev/archive/2014/08/05/announcing-rtm-of-asp-net-identity-2-1-0.aspx
Version 2.0 has the IUserLockoutStore interface that you can use to lockout users, but the downside is that there is no OOB functionality to actually leverage it beyond the pass-through methods exposed by the UserManager class. For instance, it would be nice if it would actually increment the lockout count as a part of the standard username/password verification process. However, it's fairly trivial to implement yourself.
Step #1: Create a custom user store that implements IUserLockoutStore.
// I'm specifying the TKey generic param here since we use int's for our DB keys
// you may need to customize this for your environment
public class MyUserStore : IUserLockoutStore<MyUser, int>
{
// IUserStore implementation here
public Task<DateTimeOffset> GetLockoutEndDateAsync(MyUser user)
{
//..
}
public Task SetLockoutEndDateAsync(MyUser user, DateTimeOffset lockoutEnd)
{
//..
}
public Task<int> IncrementAccessFailedCountAsync(MyUser user)
{
//..
}
public Task ResetAccessFailedCountAsync(MyUser user)
{
//..
}
public Task<int> GetAccessFailedCountAsync(MyUser user)
{
//..
}
public Task<bool> GetLockoutEnabledAsync(MyUser user)
{
//..
}
public Task SetLockoutEnabledAsync(MyUser user, bool enabled)
{
//..
}
}
Step #2: Instead of UserManager, use the following class in your login/logout actions, passing it an instance of your custom user store.
public class LockingUserManager<TUser, TKey> : UserManager<TUser, TKey>
where TUser : class, IUser<TKey>
where TKey : IEquatable<TKey>
{
private readonly IUserLockoutStore<TUser, TKey> _userLockoutStore;
public LockingUserManager(IUserLockoutStore<TUser, TKey> store)
: base(store)
{
if (store == null) throw new ArgumentNullException("store");
_userLockoutStore = store;
}
public override async Task<TUser> FindAsync(string userName, string password)
{
var user = await FindByNameAsync(userName);
if (user == null) return null;
var isUserLockedOut = await GetLockoutEnabled(user);
if (isUserLockedOut) return user;
var isPasswordValid = await CheckPasswordAsync(user, password);
if (isPasswordValid)
{
await _userLockoutStore.ResetAccessFailedCountAsync(user);
}
else
{
await IncrementAccessFailedCount(user);
user = null;
}
return user;
}
private async Task<bool> GetLockoutEnabled(TUser user)
{
var isLockoutEnabled = await _userLockoutStore.GetLockoutEnabledAsync(user);
if (isLockoutEnabled == false) return false;
var shouldRemoveLockout = DateTime.Now >= await _userLockoutStore.GetLockoutEndDateAsync(user);
if (shouldRemoveLockout)
{
await _userLockoutStore.ResetAccessFailedCountAsync(user);
await _userLockoutStore.SetLockoutEnabledAsync(user, false);
return false;
}
return true;
}
private async Task IncrementAccessFailedCount(TUser user)
{
var accessFailedCount = await _userLockoutStore.IncrementAccessFailedCountAsync(user);
var shouldLockoutUser = accessFailedCount > MaxFailedAccessAttemptsBeforeLockout;
if (shouldLockoutUser)
{
await _userLockoutStore.SetLockoutEnabledAsync(user, true);
var lockoutEndDate = new DateTimeOffset(DateTime.Now + DefaultAccountLockoutTimeSpan);
await _userLockoutStore.SetLockoutEndDateAsync(user, lockoutEndDate);
}
}
}
Example:
[AllowAnonymous]
[HttpPost]
public async Task<ActionResult> Login(string userName, string password)
{
var userManager = new LockingUserManager<MyUser, int>(new MyUserStore())
{
DefaultAccountLockoutTimeSpan = /* get from appSettings */,
MaxFailedAccessAttemptsBeforeLockout = /* get from appSettings */
};
var user = await userManager.FindAsync(userName, password);
if (user == null)
{
// bad username or password; take appropriate action
}
if (await _userManager.GetLockoutEnabledAsync(user.Id))
{
// user is locked out; take appropriate action
}
// username and password are good
// mark user as authenticated and redirect to post-login landing page
}
If you want to manually lock someone out, you can set whatever flag you're checking in MyUserStore.GetLockoutEnabledAsync().
You can have a new class, which should be derived from IdentityUser class. YOu can add a boolean property in the new class and can use this new property of take care per check for login process. I also done it pretty well. I might wanna take a look at : blog
UserManager.RemovePasswordAsync("userId") will effectively disable a user. If the user has no password he will not be able to log in. You will need to set a new password to enable the user again.

Resources