Redirection based on user role upon login - asp.net-mvc

I am trying to redirect user to page based on their role. Below is the login code in a controller:
[HttpPost]
public ActionResult Login(User model)
{
// Lets first check if the Model is valid or not
if (ModelState.IsValid)
{
using (AuthenticationAppEntities1 entities = new AuthenticationAppEntities1())
{
string username = model.Username;
string password = model.Password;
// Now if our password was enctypted or hashed we would have done the
// same operation on the user entered password here, But for now
// since the password is in plain text lets just authenticate directly
bool userValid = entities.Users.Any(user => user.Username == username && user.Password == password);
// User found in the databases
if (userValid)
{
FormsAuthentication.SetAuthCookie(username, false);
if (Roles.IsUserInRole(model.Roles, "admin"))
{
return RedirectToAction("Home", "Authentication");
}
else
{
return RedirectToAction("HomeAdmin", "Authentication");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
As you can see in the code, I redirect users based on their roles, using a if. However, model.Roles contain a null value as the controller is getting only the username and password from the login page. Any simple idea how I get the role of the authenticated user? I thought of searching it through the username, but am not sure if this is the best solution.

You can get the User's roles and then compare it with 'admin' and then redirect accordingly.

Honestly, I'm not even sure how you're getting that to run in the first place. The method signature for Roles.IsUserInRole is:
Roles.IsUserInRole(string username, string role);
Passing model.Roles is neither a string, nor a username, if it was a string.

Related

I'm validating the credentials of a user but this function is always evaluated as true

I'm validating the credentials of a user but this function is always evaluated as true
public ActionResult Authorize(string emai, string pass)
{
using (WorkFlowContext db = new WorkFlowContext())
{
var email = db.User.Where(x => x.Email_Address == emai).FirstOrDefault();
var password = db.User.Where(x => x.Password == pass).FirstOrDefault();
//if one of these if true it will send a menssage asking for the email or the password again
if ((email == null) || (password == null))
{
ViewBag.Message = "The email or password is incorrect.";
return View("Index");
}
else {
return RedirectToAction("About", "Home");
}
}
// return RedirectToAction("Index", "Login");
}
this part is the form from where I'm getting the values
As #the_lotus has mentioned, the logic there is (dangerously) wrong. You're saying get me ANY user with this password AND ANY user with this email address...which could be > 1 users.
You should try something like this:
using (WorkFlowContext db = new WorkFlowContext())
{
var user = db.User.Where(x => x.Email_Address == email).FirstOrDefault();
if(user!=null) {
if(user.Password == pass) {
//all ok - send to home (see my notes below though)
return RedirectToAction("About", "Home");
}
}
}
//if we get here - something went wrong
ViewBag.Message = "The email or password is incorrect.";
return View("Index");
...other notes
Look up ASP.NET Identity - it's a really good system with lots of security features available out of the box covering lots of things you may not think of.
Don't store your password as plain text
Be ambigous in your error message - no need to give too much away like "we found the email in our database but the password isn't right"

ASP.NET MVC 5 - let admin change other users password. Password changed in database but can't login

I'm told to make admin have a functionality to change other users password without knowing their original password. I wrote a code that changes and saves password successfully in database, but when I try to login as that user I can't.
UsersController:
public ActionResult ChangePassword()
{
return View();
}
[HttpPost]
public ActionResult ChangePassword(int id, ViewModels.ChangePasswordViewModel model)
{
if (!SessionControlService.CheckIsLoginStillTrue(_loginsService, HttpContext))
return RedirectToAction("Login", "Account");
if (!User.IsInAnyRoles("Admin", "PropertyManager"))
return RedirectToAction("Error", "Errors",
new { error = Facility.Web.Resources.Resources.ErrorNotHavePermission });
var user = _userService.GetUser(id);
if (user == null)
return RedirectToAction("Error", "Errors",
new { error = Facility.Web.Resources.Resources.ErrorURLNotExist });
user.Password = model.NewPassword;
_userService.UpdateUser(user);
return RedirectToAction("Details", new { id = id });
}
Why can't I use the changed password which is saved in the database to login?
How can I make this work?
In ASP.NET MVC5, password is hashed... you cannot save a plaintext password like that.
You need to use these two methods:
var manager = new ApplicationUserManager(...);
var token = manager.GeneratePasswordResetToken(userId)
manager.ResetPassword(userId, token, newPassword)
You could also try ApplicationUserManager.UpdatePassword(...), or RemovePassword(...) and AddPassword(...)
ApplicationUserManager is normally in IdentityConfig.cs

How to return an error if UserName Password does not match in MVC 4?

i am new to MVC, i want to create a simple Login Control. I have write the below code in controller:
public ActionResult LoginControl(String UserName, String Password)
{
string result = "";
if (UserName == "ram" && Password == "ram123")
{
result = "1";
}
if (result == "1")
{
return View("LoginControl");
}
else
{
return View("Index", "Login");
}
}
Now what i want to do is: if the UserName and password does not match, it will show me error that "UserName or password does not matched or user does not exists.", please help me how can i do it.
You could add an error to the ModelState:
else
{
ModelState.AddModelError("", "Invalid username or password");
return View("Index", "Login");
}
and then inside the corresponding view use the ValidationSummary helper to display the error:
#Html.ValidationSummary()
You could pass your result to the view and than display there.
To do this create a TempData key and pass your result there and in the view you can get the value of the tempdata key and than show there.
Here is an example on how to use it: ViewBag, ViewData and TempData

Authenticating User via Ajax: User.Identity.IsAuthenticated in ajax method, but False elsewhere

I'm using Facebook to preautheticate users, so when they visit a page, an ajax function is called to login the user, and the server will also check to see if the user is already authenticated to the site. These users have entries in the user database on the server.
The server side code is below, which is called by ajax. After that, is a second method I use to get more information on the user that is stored in the database.
When I call User.Identity.IsAuthticaed in the second method, in the same Controller, the User object is still null. The User object contains all the information in FBReg below.
Edit:
After further troubleshooting I found that the ActionResult that calls getUserInfo() has the User object populated. So I'm not sure why getUserInfo() has a null User. I guess I can just pass the object then, but I'm still just curious why this happens.
[HttpPost]
public String FBReg(FBInfo userinfo)
{
..
..
..
if (!User.Identity.IsAuthenticated)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(userinfo.id, "FBPassword"))
{
FormsAuthentication.SetAuthCookie(userinfo.id, true);
var result = (from u in db.users where (u.username == userinfo.id) select u).FirstOrDefault();
result.LastLoginDate = DateTime.Now;
db.SaveChanges();
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
..
..
..
return "";
}
public UserRepository getUserInfo()
{
bool isauth = false;
try
{
if (User.Identity.IsAuthenticated) // User is always null even after FBReg has User as Authnticated with all the correct information
{
isauth = User.Identity.IsAuthenticated;
}
}
catch { }
// get user info from database to display on page
..
..
..
return userInfo;
}

ASP.NET MVC Custom Membership Provider "CreateUser"

I've implemented some basic, custom membership provider for my ASP.NET MVC application so I thought that all validation will be done in my custom code.
Unfortunately when I'm trying to create new user by calling function:
Membership.CreateUser(user.UserName, user.Password, user.Email, null, null, true, Guid.NewGuid(), out status);
which should eventually throw an exception with all validation errors I'm getting a status like "InvalidUserName" or "InvalidPassword" instead... That means that my custom CreateUser function isn't call directly, it's used after some basic validation which I would wish to skip.
My CreateUser function (in my custom provider):
public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
{
try
{
User user = new User();
user.UserKey = Guid.NewGuid();
user.UserName = username;
user.passwordSalt = string.Empty;
user.Password = this.TransformPassword(password, ref user.passwordSalt);
user.Email = email;
user.PasswordQuestion = passwordQuestion;
user.PasswordAnswer = passwordAnswer;
user.CreationDate = DateTime.Now;
user.LastActivityDate = DateTime.Now;
user.LastLoginDate = DateTime.MinValue;
user.LastPasswordChangeDate = DateTime.Now;
this._UsersRepository.SaveUser(user);
status = MembershipCreateStatus.Success;
return CreateMembershipFromInternalUser(user);
}
catch(RuleException ex)
{
throw ex;
}
}
Do you know how to enforce direct usage of custom CreateUser function !?
But I'm not using a default ASP.NET MVC project's AccountController...
Just take a look:
[AcceptVerbs(HttpVerbs.Post)]
public ViewResult Register(User user, string password_confirm, bool acceptsTerms)
{
if (!acceptsTerms)
ModelState.AddModelError("acceptsTerms", "Musisz zaakceptować regulamin");
if (ModelState.IsValid)
{
try
{
MembershipCreateStatus status = new MembershipCreateStatus();
Membership.CreateUser(user.UserName, user.Password, user.Email, null, null, true, Guid.NewGuid(), out status);
}
catch (RuleException ex){
ex.CopyToModelState(ModelState,"user");
}
}
return View();
}
The point is that I'm getting a status instead of RuleException ex when user.UserName or user.Password is empty. My custom RuleException ex would give me back such informations as well. Where a status value is assigned right now !? Bacouse it's not done in my implementation of CreateUser...
I am using this (MVC3) and I have no issues:
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
MembershipCreateStatus status;
Membership.Provider.CreateUser(model.UserName, model.Password, model.Email, "", "", true, Guid.NewGuid(), out status);
if (status == MembershipCreateStatus.Success)
{
FormsService.SignIn(model.UserName, false);
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", AccountValidation.ErrorCodeToString(status));
}
}
// If we got this far, something failed, redisplay form
ViewBag.PasswordLength = MembershipService.MinPasswordLength;
return View(model);
}
Using ILSpy to view the static method Membership.CreateUser, you will find it performs validation on
Username (trim whitespace + not null, not empty)
Password (trim whitespace + not null, not empty, length checks)
Email (trim whitespace)
Password Question (trim whitespace + not empty)
Password Answer (trim whitespace + not empty)
It then calls the custom provider.
The key here is to not call the static method CreateUser
Membership.CreateUser(...)
Rather, call the custom provider directly by using:
Membership.Provider.CreateUser(...)
Tested and verified working, as of .NET 4
While my site recommends having a password, we support openid. So forcing a user to have a password just seemed counter to what openid is good for.
Complete rewrite
The ASP.NET Membership system always does some initial validation of the inputs when APIs such as CreateUser are called.
I don't know of any way around this aside from not going directly to the ASP.NET membership APIs.

Resources