query string param is not url-encoded inside asp.net mvc action - asp.net-mvc-5

I'm calling ResetPassword action from an Email (ASP.NET MVC 5).
http://localhost:34162/Account/ResetPassword?code=BwEA181bAECFMcn1vwPdrctS/wcyncKPxGT9Zx1tDuPwKGpe9H1W7LI3Zm9fM+3aA5Fok5GhLPBHqbtiGfpL8Cmdx7RNC6RJ7d6t9ZgFBwgwYk3zssU1Nh64PWHJAabVG9Wv9VWDNdj+Fz0UA712XA==
This is the address in my Browser.
However, in debug I receive this string in the ResetPassword Action:
// GET: /Account/ResetPassword
[AllowAnonymous]
public ActionResult ResetPassword(string code)
{
return code == null ? View("Error") : View();
}
The 'code' is:
BwEA181bAECFMcn1vwPdrctS/wcyncKPxGT9Zx1tDuPwKGpe9H1W7LI3Zm9fM 3aA5Fok5GhLPBHqbtiGfpL8Cmdx7RNC6RJ7d6t9ZgFBwgwYk3zssU1Nh64PWHJAabVG9Wv9VWDNdj Fz0UA712XA==
i.e., it is not url-encoded and of course password is not reset with invalid token message.
What can I do for getting the right string in the Action?

You can encode the string in the following way:
[AllowAnonymous]
public ActionResult ResetPassword(string code)
{
code = Server.HtmlEncode(code);
}
Fore more information on how to encode you can look at
https://msdn.microsoft.com/en-us/library/w3te6wfz(v=vs.110).aspx

I still don't know what was the problem. Looks like it shouldn't have worked in the first place. I wish I knew why Microsoft feel the need to use tokens with slashes and pluses.
Anyway, I just Base64 encoded and decoded the token as follows:
before sending the Email to the user:
...
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
code = CommonFuncs.Base64Encode(code);
EmailsBL.PasswordResetEmail(model.Email, code); <-- emailing the link for password rest to the user
And then when receiving:
// POST: /Account/ResetPassword
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model)
{
/////////////////////////////////////////////////////////////////////
// NOTE: if email is not CONFIRMED then reset password silently fails
////////////////////////////////////////////////////////////////////
if (!ModelState.IsValid)
{
return View(model);
}
model.Code = CommonFuncs.Base64Decode(model.Code);
i.e., decoding the token.
This following is just for completeness:
public static string Base64Encode(string plainText)
{
string base64string = null;
if (plainText != null)
{
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
base64string = System.Convert.ToBase64String(plainTextBytes);
}
return base64string;
}
public static string Base64Decode(string base64EncodedData)
{
string decodedBase64String = null;
if (base64EncodedData != null)
{
var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
decodedBase64String = System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}
return decodedBase64String;
}

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")

Getting captcha plugin to work with register action

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.

After redirect from one controller to another controller Not able to receive User.Identity.name value in mvc. how to solve this Issue?

I am able to get the User.Identity.Name value from Login Controller after redirect to Dashboard(another Controller) i am not able to receive the User.Identity.Name value (i am getting Null value)
below is my code:-
[HttpPost]
public async Task<ActionResult> SignInCallback()
{
var token = Request.Form["id_token"];
var state = Request.Form["state"];
var claims = await ValidateIdentityTokenAsync(token, state);
var id = new ClaimsIdentity(claims, "Cookies");
Request.GetOwinContext().Authentication.SignIn(id);
string Id = System.Web.HttpContext.Current.User.Identity.Name;
return Redirect("/Dashboard");
}
After return Redirect("/Dashboard"); Getting null value in Dashbord Controller.
Below is my Dashborad controller code :-
public ActionResult Index()
{
string Id = System.Web.HttpContext.Current.User.Identity.Name;
return View();
}

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.

Resources