Forget password form in asp.net mvc 4 - c#

I try to implement forget password form in my asp.net mvc 4 project, everything works fine, but when I try to login to system with new password it told me that I have wrong password.
[HttpPost]
public ActionResult ForgetPassword(UserViewModel userModel) {
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var random = new Random();
var result = new string(
Enumerable.Repeat(chars, 8)
.Select(s => s[random.Next(s.Length)])
.ToArray());
User user = _userRepo.GetUserByEmail(userModel.Email);
if (user == null) {
ViewBag.Error = Resources.Account.userEmailNotExist;
return View(userModel);
}
String newHashedPassword = Crypto.HashPassword(result);
user.Password = newHashedPassword;
user.LastPasswordChangedDate = DateTime.UtcNow;
_userRepo.SaveChanges();
string enMessage = "Your new password: " + result;
var httpCookie = Request.Cookies["lang"];
if (httpCookie != null && httpCookie.Value == "en") {
_mailHelper.SendEmail(userModel.Email, "New password", enMessage);
}
return RedirectToAction("ConfirmPasswordChange", "Account");
}
Login form:
[HttpPost]
public ActionResult Login(UserViewModel user) {
var users = _userRepo.GetAllEntitiesWithParam("JobsDb_Users_GetByEmail", user.Email).FirstOrDefault();
...
try {
var tryLogin = WebSecurity.Login(users.Username, user.Password, true);
if (tryLogin == WebSecurity.MembershipLoginStatus.Failure)
{
var httpCookie = Request.Cookies["lang"];
if (httpCookie != null && httpCookie.Value == "en") {
ViewBag.Error = "Your password is incorrect.";
new SeoHelper().ReturnSeoTags(this, "Login");
}
return View(user);
}
...
} catch {
...
}
}
inside WebSecurity
public static MembershipLoginStatus Login(string username, string password, bool rememberMe) {
if (Membership.ValidateUser(username, password)) {
FormsAuthentication.SetAuthCookie(username, rememberMe);
return MembershipLoginStatus.Success;
} else {
return MembershipLoginStatus.Failure;
}
}
inside Membership
public override bool ValidateUser(string username, string password) {
if (string.IsNullOrEmpty(username)) {
return false;
}
if (string.IsNullOrEmpty(password)) {
return false;
}
User user = _userRepository.GetAll().FirstOrDefault(usr => usr.Username == username);
if (user == null) {
return false;
}
if (!user.IsApproved.Value) {
return false;
}
if (user.IsLockedOut.Value) {
return false;
}
String hashedPassword = user.Password;
Boolean verificationSucceeded = (hashedPassword != null && Crypto.VerifyHashedPassword(hashedPassword, password));
if (verificationSucceeded) { //here is I have false if try to login using password from forget form
user.PasswordFailuresSinceLastSuccess = 0;
user.LastLoginDate = DateTime.UtcNow;
user.LastActivityDate = DateTime.UtcNow;
} else {
int failures = user.PasswordFailuresSinceLastSuccess.Value;
if (failures < MaxInvalidPasswordAttempts) {
user.PasswordFailuresSinceLastSuccess += 1;
user.LastPasswordFailureDate = DateTime.UtcNow;
} else if (failures >= MaxInvalidPasswordAttempts) {
user.LastPasswordFailureDate = DateTime.UtcNow;
user.LastLockoutDate = DateTime.UtcNow;
user.IsLockedOut = true;
}
}
_userRepository.SaveChanges();
if (verificationSucceeded) {
return true;
}
return false;
}

First step is to open up your database and verify that the new password was actually persisted. If it has, the most likely cause is that your repository is working with stale (cached) data.
If you're using Entity Framework, this happens because the framework will, by default, cache the state of the database at the time the DbContext is created, so it is retaining your original password. You can verify this by logging in with the original password.

I am not sure but following code does not look right to me:
User user = _userRepo.GetUserByEmail(userModel.Email);
if (user == null) {
ViewBag.Error = Resources.Account.userEmailNotExist;
return View(userModel);
}
String newHashedPassword = Crypto.HashPassword(result);
user.Password = newHashedPassword;
user.LastPasswordChangedDate = DateTime.UtcNow;
_userRepo.SaveChanges();
You fetched the user from repository, make changes to user object in memory and then called SaveChanges() on the repository. Does that work in your world? How does _userRepo.SaveChanges(); knows which object has changed. Do you see correct hashed value in DB after the call? What value you see in ValidateUser() method for password? Is the hashing algorithm consistent both while generating hashed password and while verifying?
I could be wrong, if that's the case it will be good if you share little bit more of analysis around the question I asked above.

Related

ModelState.AddModelError is setup to display Canned message instead of real Error

In my website i had a group of people working on my site and i have this code that they put a canned message in for an error. When i debug the code it is actually a different error but displays this canned message. For instance when i put the information in the form i used an email address that already exists in the database but it is showing a message to check the password requirements. How can this be fixed to show the actual error. To me it also seems like there is a lot code going on in this that may not need to be or can be achieved cleaner Your thoughts?
Code of Post Action:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateCompanyUser(ExpandedUserDTO ExpandedUserDTO)
{
try
{
if (ExpandedUserDTO == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var Email = ExpandedUserDTO.Email.Trim();
var UserName = ExpandedUserDTO.UserName.Trim();
var Password = ExpandedUserDTO.Password.Trim();
if (UserName == "")
{
throw new Exception("No Username");
}
if (Password == "")
{
throw new Exception("No Password");
}
// UserName is LowerCase of the Email
// UserName = Email.ToLower();
// Create user
var objNewAdminUser = new Models.ApplicationUser { UserName = UserName, Email = Email };
var AdminUserCreateResult = UserManager.Create(objNewAdminUser, Password);
if (AdminUserCreateResult.Succeeded == true)
{
string strNewRole = Convert.ToString(Request.Form["Roles"]);
if (strNewRole != "0")
{
// Put user in role
UserManager.AddToRole(objNewAdminUser.Id, strNewRole);
}
var viewModel = new Users();
{
viewModel.UsersId = Convert.ToString(Guid.NewGuid());
viewModel.Email = Email;
viewModel.FirstName = UserName;
viewModel.AspNetUsersId = objNewAdminUser.Id;
viewModel.CreatedDate = System.DateTime.Now;
viewModel.UpdatedDate = System.DateTime.Now;
};
UsersBusinessModels Login = new UsersBusinessModels();
var results = Login.insertUserWithougAsny(viewModel);
string[] roleRemove = new string[2] { "Administrator", "CompanyAdmin" };
ViewBag.Roles = GetAllRolesAsSelectList().Where(k => !roleRemove.Contains(k.Text)).ToList();
// return RedirectToAction();
Response.Redirect("/Customer/ManageUsers/" + User.Identity.GetUserId());
return PartialView();
}
else
{
ViewBag.Roles = GetAllRolesAsSelectList();
ModelState.AddModelError(string.Empty,
"Error: Failed to create the user. Check password requirements.");
return PartialView(ExpandedUserDTO);
}
}
catch (Exception ex)
{
ViewBag.Roles = GetAllRolesAsSelectList();
ModelState.AddModelError(string.Empty, "Error: " + ex);
string[] roleRemove = new string[2] { "Administrator", "CompanyAdmin" };
ViewBag.Roles = GetAllRolesAsSelectList().Where(k => !roleRemove.Contains(k.Text)).ToList();
return PartialView(ExpandedUserDTO);
}
}

Use session state to redirect user to homepage if already logged in

I have a login page and and a accounts controller with Login action. When I log in I get redirected to home page(which is good) but after logging in if I re visit the login page it shows the login form again (although I am logged in).
I tried check for session state values but every time I try to use it I get null reference error.
public ActionResult Login(string name, string password, string hash)
{
if (!string.IsNullOrWhiteSpace(name))
{
var user = _model.tblUsers.FirstOrDefault(x => x.username == name);
if (user != null)
{
if (user.powerLevel == 0)
{
Session["IsAdmin"] = (user.password == password);
Session["IsAuthor"] = null;
Session["IsUser"] = null;
}
else if (user.powerLevel == 1)
{
Session["IsAdmin"] = null;
Session["IsAuthor"] = (user.password == password);
Session["IsUser"] = null;
}
else if (user.powerLevel == 2)
{
Session["IsAdmin"] = null;
Session["IsAuthor"] = null;
Session["IsUser"] = (user.password == password);
}
else
{
return View("Login");
}
return RedirectToAction("Index","Posts");
}
}
return View("Login");
}
so if either of IsAdmin, IsAuthor, IsUser Session is set to true I want to get redirected to homepage. I tried check it with string.IsNullOrWhiteSpace but it doesnt work I always get false even if the Session is set to true

FormAuthentication .ASPXAUTH cookie showing null after few moments in ASP.NET MVC

I have implemented FormAuthentication in asp.net mvc 5 and create FormsAuthenticationticket on LogIn and it creates successfully but after few moments that cookie is showing in browser but in application it's getting null.
Please help to solve this issue.
Any help will be appreciated Thanks
LOGIN FORM
public ActionResult Login([Bind(Include = "Username, Password")] LoginModel loginModel, string ReturnUrl)
{
if (ModelState.IsValid)
{
Egov_Users eGov_Users = db.Egov_Users
.Where(p => p.UserType.Type != "O" && p.UserName == loginModel.Username)
.FirstOrDefault();
if (eGov_Users == null)
{
ModelState.AddModelError("", "Invalid username");
return View();
}
else
{
if (eGov_Users.Password != loginModel.Password)
{
ModelState.AddModelError("", "Invalid Password");
return View();
}
var loginDetail = new LoginDetails();
var serializer = new JavaScriptSerializer();
loginDetail.userID = eGov_Users.UserId;
loginDetail.username = eGov_Users.UserName;
loginDetail.firstName = eGov_Users.FirstName;
loginDetail.lastName = eGov_Users.LastName;
var userData = SerializeUserInfoInternal(loginDetail);
FormsAuthentication.SetAuthCookie(loginDetail.username, false);
var cookie = FormsAuthentication.GetAuthCookie(
FormsAuthentication.FormsCookieName, false);
var ticket = FormsAuthentication.Decrypt(cookie.Value);
var durationInHours = 8;
FormsAuthenticationTicket newTicket = new FormsAuthenticationTicket(
ticket.Version,
loginDetail.username,
DateTime.Now,
DateTime.Now.AddHours(durationInHours),
true,
userData);
// Encrypt the ticket.
string encTicket = FormsAuthentication.Encrypt(newTicket);
cookie.Value = encTicket;
Response.Cookies.Add(cookie);
int cookieSize = System.Text.UTF8Encoding.UTF8.GetByteCount(cookie.Values.ToString());
Session["CookieSize"] = cookieSize;
if (string.IsNullOrEmpty(ReturnUrl))
{
return RedirectToAction("Index", "Users");
}
}
}
return RedirectToAction("Login", "Login");
}
GLOBAL ASAX
protected void Application_PostAuthenticateRequest()
{
var ticket = GetTicketFromCurrentCookie();
if (ticket == null)
{
Global.WriteLog("Application_PostAuthenticateRequest", "ticket becomes null");
return;
}
var user = DeserializeUserInfoInternal(ticket.Name, ticket.UserData);
if (user == null)
{
return;
}
var principal = new AppUserPrincipal(user);
HttpContext.Current.User = principal;
}
private static FormsAuthenticationTicket GetTicketFromCurrentCookie()
{
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie == null)
{
Global.WriteLog("GetTicketFromCurrentCookie", "Cookie becomes null");
return null;
}
var ticket = FormsAuthentication.Decrypt(cookie.Value);
return ticket;
}
static LoginDetails DeserializeUserInfoInternal(string name, string userData)
{
var deserialize = new JavaScriptSerializer();
var loginDetails = deserialize.Deserialize<LoginDetails>(userData);
return loginDetails;
}
use below code to get the cookie value
HttpContext.Current.Request.Cookies.Get(".ASPXAUTH");

How to get user's password expiration date from Active Directory?

I have implemented implemented Active Directory authentication in ASP.NET MVC 5 using LDAP. I want to know how to get a user's
Account Locked (boolean)
Password Expired (boolean)
Password Expiry Date (DateTime)
This is my current code:
using System.Web.Mvc;
using System.Web.Security;
using MvcApplication.Models;
[HttpPost]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (!this.ModelState.IsValid)
{
return this.View(model);
}
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (this.Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return this.Redirect(returnUrl);
}
return this.RedirectToAction("Index", "Home");
}
this.ModelState.AddModelError(string.Empty, "The user name or password provided is incorrect.");
return this.View(model);
}
public ActionResult LogOff()
{
FormsAuthentication.SignOut();
return this.RedirectToAction("Index", "Home");
}
The easiest way is to PInvoke LogonUser Win32 API.e.g
http://www.pinvoke.net/default.aspx/advapi32/LogonUser.html
Read also MSDN reference: https://msdn.microsoft.com/en-us/library/aa378184.aspx
The examples for your questions: https://www.codeproject.com/articles/18102/howto-almost-everything-in-active-directory-via-c
I manage to do it using a combination of System.Web.Security and System.DirectoryServices.
public bool IsExpired(MembershipUser user, LoginModel model)
{
bool result = false;
string ldap = ConfigurationManager.ConnectionStrings["ADConnectionString"].ConnectionString;
DirectoryEntry rootEntry = new DirectoryEntry(ldap, model.UserName, model.Password, AuthenticationTypes.Secure);
DirectorySearcher mySearcher = new DirectorySearcher(rootEntry);
SearchResultCollection results;
string filter = "maxPwdAge=*";
mySearcher.Filter = filter;
results = mySearcher.FindAll();
long maxDays = 0;
if (results.Count >= 1)
{
Int64 maxPwdAge = (Int64)results[0].Properties["maxPwdAge"][0];
maxDays = maxPwdAge / -864000000000;
}
long daysLeft = 0;
daysLeft = maxDays - DateTime.Today.Subtract(user.LastPasswordChangedDate).Days;
if (daysLeft <0)
{
result = true;
} else
{
if (daysLeft<=14)
{
this.Expiring = true;
this.ExpiringString = String.Format("You must change your password within" + " {0} days", daysLeft);
}
else
{
this.Expiring = false;
}
}
return result;
}
Here's another approach to getting the user's account password expiration date, and from the result you can easily calculate IsExpired:
public static DateTime GetPasswordExpirationDate(UserPrincipal user)
{
DirectoryEntry deUser = (DirectoryEntry)user.GetUnderlyingObject();
ActiveDs.IADsUser nativeDeUser = (ActiveDs.IADsUser)deUser.NativeObject;
return nativeDeUser.PasswordExpirationDate;
}
You'll need to add a reference to the ActiveDS COM library typically found at C:\Windows\System32\activeds.tlb.
I got here from Google search and I found the current answers to be outdated and/or cumbersome (I don't want to import COM dlls, and I would like to avoid complex arithmetics if possible). In addition, it seems that the accepted answer doesn't take into account more granular settings for maxPwdAge that could be in effect.
I found out that AD exposes the calculated property msDS-UserPasswordExpiryTimeComputed which can be used directly, instead of performing complex calculations:
public DateTime? GetPasswordExpirationTime()
{
var path = #"LDAP://yourserver";
// null uses the current user's credentials.
var user = "yourUserNameOrNull";
var password = "yourPasswordOrNull";
var idToSearch = "userNameToCheck";
using(var entry = new DirectoryEntry(path, user, password, AuthenticationTypes.Secure))
using(var ds = GetSearcher(entry, $"(sAMAccountName={idToSearch})"))
{
ds.PropertiesToLoad.Add("msDS-UserPasswordExpiryTimeComputed");
var user = ds.FindOne();
return DateTimePropertyFromLong(user, "msDS-UserPasswordExpiryTimeComputed")
}
}
public static DateTime? DateTimePropertyFromLong(SearchResult sr, string propName)
{
if (!sr.Properties.Contains(propName)) return null;
var value = (long) sr.Properties[propName][0];
return value == long.MaxValue ? (DateTime?)null : DateTime.FromFileTimeUtc(value);
}
The relevant bits are just PropertiesToLoad.Add("msDS-UserPasswordExpiryTimeComputed") and the conversion from the strange long format returned by AD via the DateTime.FromFileTimeUtc method.
Edit
As per #t3chb0t, GetSearcher is a simple helper method, responsible for opening a DirectorySearcher over the DirectoryEntry:
private static DirectorySearcher GetSearcher(DirectoryEntry entry, string filter = null)
{
if (filter == null)
return new DirectorySearcher(entry) {ClientTimeout = TimeSpan.FromSeconds(30)};
return new DirectorySearcher(entry, filter) {ClientTimeout = TimeSpan.FromSeconds(30)};
}

Bcrypt password verifying

I'm trying to decrypt the password on the login method, but it allows to login with any password I type in, not sure why, maybe someone could help me out?
My login method in the db layer:
public string loginUser(string userName, string pass)
{
string result = "";
try
{
var mongoClient = new MongoClient("mongodb://localhost");
var database = mongoClient.GetDatabase("SearchForKnowledge");
var coll = database.GetCollection<BsonDocument>("Users");
var filter = Builders<BsonDocument>.Filter.Eq("userName", userName);
var results = coll.Find(filter).ToList().First();
if (BCrypt.Net.BCrypt.Verify(pass, results["password"].ToString()))
{
result = results["userName"].ToString();
}
}
catch (Exception ex)
{
result = "";
}
return result;
}
My user controller:
public ActionResult Login(UsersLogin form)
{
User user = new User();
UserDB udb = new UserDB();
if (!form.Username.IsEmpty())
{
udb.loginUser(form.Username, form.Password);
Session["userName"] = form.Username;
return RedirectToRoute("Home");
}
return RedirectToRoute("Login");
}
The problem is in your controller
udb.loginUser(form.Username, form.Password);
Session["userName"] = form.Username;
return RedirectToRoute("Home");
You call udb.loginUser(form.Username, form.Password);, but you never check the return value of udb.loginUser method, so your code will always redirect to the home page no matter what the user name and password are.
Based on the code of loginUser method, it will return an empty string if the login fails, so change the above three lines of code to below
var loginResult = udb.loginUser(form.Username, form.Password);
if (!string.IsNullOrEmpty(loginResult))
{
Session["userName"] = form.Username;
return RedirectToRoute("Home");
}

Categories

Resources