How can I send a Confirmation Email in asp.net mvc - c#

Today i'm trying to follow this article of Shai Raiten's Blog and when I finish it the createStatus return invalidAnswer
here is my Register action
[HttpPost]
[AllowAnonymous]
[CaptchaValidation("CaptchaCode", "registerCaptcha", "Wrong captcha!")]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
MembershipCreateStatus createStatus;
Membership.CreateUser(model.UserName, model.Password, model.Email, null, null, false, null, out createStatus);
if (createStatus == MembershipCreateStatus.Success)
{
MailHelper.SendConfirmationEmail(model.UserName);
return RedirectToAction("Confirmation", "User");
}
else
{
ModelState.AddModelError("", "Failed!");
}
}
return View(model);
}
and here is my RegisterModel.cs
public class RegisterModel
{
[Key]
public long ID { set; get; }
[Required(ErrorMessage = "Do not Skip this")]
public string UserName { set; get; }
[StringLength(500, MinimumLength = 6, ErrorMessage = "Atleast 6 characters in passwords")]
[Required(ErrorMessage = "Do not Skip this")]
public string Password { set; get; }
[Compare("Password", ErrorMessage = "Wrong confirm passwords")]
[Required(ErrorMessage = "Do not skip this")]
public string ConfirmPassword { set; get; }
public string Name { set; get; }
public string Address { set; get; }
[RegularExpression(#"\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z", ErrorMessage = "This is not an email")]
public string Email { set; get; }
public string Phone { set; get; }
public bool EmailConfirm { set; get; }
}
any suggestion for me , really appreciated all the help you guys make.

The simplest thing you can do is:
First, you should define a property in your user model which will hold email confirmation token. Also, you should define property bool IsEmailConfirmed which defaults to false.
The token should be something like auto-generated random string. E.g. Guid.NewGuid().ToString()
Then, you should define another action, say [HttpGet, AllowAnonymous] ConfirmEmail(string email, string token), which will validate that token against saved in the database and update IsEmailConfirmed accordingly.
And the link you are asking about, should then point to an url which will look like something like that: http://YOUR.SERVER/YourController/ConfirmEmail?email={0}&token={1}, where {0} is user email and {1} is your user email confirmation token. It should return a view that tells whether confirmation was successfull.
However, i do recommend not to reinvent the wheel and to simply use Asp.Net Identity 2.0 framework, which will do all that authn & authz stuff for you.

Please follow the below example from ASP.Net site where its beautifully explained how to send email during registration prcoess.
http://www.asp.net/mvc/overview/security/create-an-aspnet-mvc-5-web-app-with-email-confirmation-and-password-reset
Additionally I would not recommend MD5 password hashinh since its pretty old, try using SHA 256 hashing for password encryption.
http://forums.asp.net/t/1211478.aspx?How+do+I+use+Sha256+to+Encrypt+a+String+

Related

How do I update a password that's in a different format from the defined model? I'm getting DbEntityValidationException

The Problem
I have a pre-defined [StringLength()] and [RegularExpression()] constraint on my Code-First Model.
The [StringLength()] requirement is 8-16 characters
The [RegularExpression()] constraint for the password is in a different format from the encrypted password.
The password is encrypted before being shoved into the database.
The encrypted password is 70 characters in length, which is higher than the 8-16 character limit defined in the Model.
I am required to use e.Encrypt(), meaning I cannot use the default ASP.NET hashing algorithm.
I've searched high and low, but have yet to find the correct answer.
My Code
I have a function that allows a user to register an account. It looks like this:
[HttpPost]
public ActionResult Register([Bind(Include="Username,Password,EmailAddress")] UserModel user)
{
if (TryUpdateModel(user))
{
// Set password to a different format than Model's designated Regex
user.Password = e.Encrypt(user.Password);
context.Entry(user).State = EntityState.Added;
context.SaveChanges();
return RedirectToAction("Login", "Account");
}
return View();
}
In my UserModel.cs file, I have the following constraints:
[Required]
[DataType(DataType.Password)]
[StringLength(16, MinimumLength = 8, ErrorMessage = "Must be between 8 and 16 characters.")]
[RegularExpression("^(?=.*[0-9])(?=.*[!##$%^&*])[a-zA-Z0-9!##$%^&*]", ErrorMessage = ErrorMessage_PasswordRegex)]
public string Password { get; set; }
Again, the hashed password is in a completely different format. Therefore, I cannot update it because it throws a DbEntityValidationException. This [RegularExpression()] is for the format of the user's password. I need to be able to bypass or suspend the password's Regex constraint.
What I have done to remedy this
I've removed the [RegularExpression()] requirements, and upped the [StringLength()] to 70, which is the length of my password hash.
However, I don't want to allow users to input 70 characters of text. This seems like a cheap hack, and I feel that there should be a better way to do this. Any ideas?
Here's an example:
We've got different requirements for user input than what our database requires. We might need more user input which we will programmatically act upon.
The EF model
public class UserModel()
{
[Key]
public string Id { get; set; }
public string Name { get; set; }
[Required, StringLength(70)]
public string Password { get; set; }
}
Now here's the class we use to capture user input
public class UserViewModel()
{
[Required]
public string Name { get; set; }
[Required]
[RegularExpression("^(?=.*[0-9])(?=.*[!##$%^&*])[a-zA-Z0-9!##$%^&*]", ErrorMessage = ErrorMessage_PasswordRegex)]
public string Password { get; set; }
[Required]
public string ConfirmPassword { get; set; }
}
Now we transform and map values.
The user won't know what to use for Id and the database doesn't have need for ConfirmPassword. We can also transform what the user originally entered as a password.
[HttpPost]
public ActionResult Register(UserViewModel model)
{
if ((ModelState.IsValid) &&
(model.Password == model.ConfirmPassword))
{
// map to EF model
var user = new UserModel
{
Name = model.Name,
Password = e.encrypt(model.Password) // transform, encrypt, whatever
};
db.Users.Add(user); // use EF model to persist
...
return RedirectToAction("Login", "Account");
}
return(model);
}

MVC Querying a list of rights for logged on user

The following ActionResult logs in a user and puts it in a cookie. I create a JSON string for the user data; which includes loggingOnUser.MergedRights (a list of type RightModel).
How can I access the merged rights list from a view to see if the user has a specific right?
UserController
[HttpPost]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
{
string username = model.Email;
string password = model.Password;
var loggingOnUser = _userService.Login(username, password);
if (loggingOnUser != null)
{
string userData = OptionBox.Common.JSON.ToJSON(loggingOnUser);
var ticket = new FormsAuthenticationTicket(1, loggingOnUser.Email.ToString(), DateTime.Now, DateTime.Now.AddDays(1), true, userData, FormsAuthentication.FormsCookiePath);
//Encrypt ticket
string encTicket = FormsAuthentication.Encrypt(ticket);
//Create the cookie
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Dashboard");
}
}
}
ModelState.AddModelError("", "The username or password provided is incorrect");
return View(model);
}
RightModel.cs
public class RightModel
{
public string RightName { get; set; }
public string Description { get; set; }
public bool Assigned { get; set; }
}
LoginModel.cs
public class LoginModel
{
public int ID { get; set; }
[Required]
[Display(Name = "Email Address")]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
public string RedirectUrl { get; set; }
public DateTime LastLoggedIn { get; set; }
public virtual List<RightModel> MergedRights { get; set; }
}
Screenshot of userData as JSON
Setting aside the obvious concerns that you shouldn't be creating cookies with sensitive data in plain text such as the username and password, the only way you can access data and perform operations on it in a view is if the data is already stored in a container accessible by the view, such as the ViewBag/ViewData, the Model or the TempData object.
In order to include the desired information within the view, you should read the data from the cookie in the controller, and then include it in either the ViewBag/TempData or the Model if that is applicable to your design, then you would simply access it as ViewBag.MergedRigts / Model.MergedRights, etc.
IMO these types of operations (checking for user permissions and authentication) should be done in a controller action instead of within a view, so that you can route the request to the respective view depending on the model and session data, but as far as simply accessing the data stored in a cookie, that's one way you can do it.
Your problem here is that you're essentially bypassing all the built-in security that .NET provides for you, and that security is well written and extensive. By bypassing, you're are fighting against the current.
What you need to do is implement a custom IPrincipal interface that can provide an IsMemberOf() implementation. This way, you can use all the built-in security seamlessly.
I suggest you begin by reading up on IPrincipal, IIdentity, and custom implementations in MVC.

Passing a variable to validator

I am trying to set-up a remote validation similar to the one in this example:
Example
My application has a twist however, my form elements are dynamically generated, therefore this tag:
[Remote("doesUserNameExist", "Account", HttpMethod = "POST", ErrorMessage = "User name already exists. Please enter a different user name.")]
is not set in stone, I need to vary the ErrorMessage for example and preferably vary the action. Is it possible, or would you suggest taking the long-way, meaning to implement the whole ajax validation on my own.
Any suggestions are appreciated.
If you need to have a dynamic error message then you could return this as string from your validation action:
public ActionResult DoesUserNameExist(string username)
{
if (Exists(uasername))
{
string errorMessage = "Some dynamic error message";
return Json(errorMessage, JsonRequestBehavior.AllowGet);
}
return Json(true, JsonRequestBehavior.AllowGet);
}
And if you need even more flexibility such as invoking dynamic dynamic actions, then you're better of rolling your custom validation solution instead of relying on the built-in Remote attribute.
You can inherit from RemoteAttribute and make it fetch the required values from a service or factory according to your own logic. Here is an example:
[AttributeUsage(AttributeTargets.Property)]
public class MyRemoteAttribute : RemoteAttribute
{
public MyRemoteAttribute(Type type, string propertyName)
: base(MyRemoteAttributeDataProvider.GetAttributeData(type,propertyName).Action, MyRemoteAttributeDataProvider.GetAttributeData(type,propertyName).Controller)
{
var data = MyRemoteAttributeDataProvider.GetAttributeData(type,propertyName);
base.ErrorMessage = data.ErrorMessage;
base.HttpMethod = data.HttpMethod;
}
}
public static class MyRemoteAttributeDataProvider
{
public static RemoteAttributeData GetAttributeData(Type type
, string propertyName)
{
//this is where you are going to implement your logic im just implementing as an example
//you can pass in a different type to get your values. For example you can pass in a service to get required values.
//property specific logic here, again im going to implement to make this
//specification by example
var attrData = new RemoteAttributeData();
if(propertyName == "MyOtherProperty")
{
attrData.Action = "MyOtherPropertyRelatedAction";
attrData.Controller = "MyOtherPropertyRelatedController";
attrData.ErrorMessage = "MyOtherPropertyRelated Error Message";
attrData.HttpMethod = "POST";
}
else
{
attrData.Action = "UserNameExists";
attrData.Controller = "AccountController";
attrData.ErrorMessage = "Some Error Message";
attrData.HttpMethod = "POST";
}
return attrData;
}
}
public class RemoteAttributeData
{
public string Controller { get; set; }
public string Action { get; set; }
public string HttpMethod { get; set; }
public string ErrorMessage { get; set; }
}
And this is how you are supposed to use is:
public class RegisterViewModel
{
[Required]
[Display(Name = "User name")]
[MyRemote(typeof(RegisterViewModel),"UserName")]
public string UserName { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[System.ComponentModel.DataAnnotations.Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
[Required]
[MyRemote(typeof(RegisterViewModel),"MyOtherProperty")]
public string MyOtherProperty { get; set; }
}
As I also mentioned above at the commentary. You should specialize that provider according to your needs.
I hope this helps.
UPDATE:
I update the implementation based on your comment, so that it takes a property name and does some property name specific wiring.

bypassing model validation in controller?

I have created an ADO.NET model of my database.
Created a new controller with CRUD (entity framework and using the ADO.NET entity model I created).
In my database I have a simple Users table. The Password row in the table will hold the users passwords encrypted with SimpleCrypto (PBKDF2).
In my ADO.NET Users.cs model I have added following validation:
[Required]
[DataType(DataType.Password)]
[StringLength(20, MinimumLength = 6)]
[Display(Name = "Password")]
public string Password { get; set; }
That works with jQuery in the browser with validation.
But in my controller I am encrypting the Password, and then the Password string will be way more than 20 chars in lenght.
var crypto = new SimpleCrypto.PBKDF2();
var encryptedPass = crypto.Compute(user.Password);
user.Password = encryptedPass;
user.PasswordSalt = crypto.Salt;
_db.Users.Add(user);
_db.SaveChanges();
And this gives me and "Validation failed for one or more entities."-error.
I can copy the user over to a "var newUser" and then set all the properties there, but isn't there a easier way to bypass the model validation in this case?
EDIT: If I remove the validation of the Password prop in the model then everything works. So it is the validation that gives me the error because I alter the Password from 6-20 length chars to +100 lengt chars because of the encryption in the controller.
EDIT: Complete controller section inserted to this question.
[HttpPost]
public ActionResult Create(Users user)
{
if (!ModelState.IsValid)
{
return View();
}
if (_db.Users.FirstOrDefault(u => u.Email == user.Email) != null)
{
ModelState.AddModelError("", "User already exists in database!");
return View();
}
var crypto = new SimpleCrypto.PBKDF2();
var encryptedPass = crypto.Compute(user.Password);
user.Password = encryptedPass;
user.PasswordSalt = crypto.Salt;
_db.Users.Add(user);
_db.SaveChanges();
return RedirectToAction("Index", "User");
}
This is where ViewModels enter the game. You should create a model which you pass to the view and map that back to the domain model later.
The ViewModel:
public class RegisterModel
{
[Required]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[StringLength(20, MinimumLength = 6)]
[Display(Name = "Password")]
public string Password { get; set; }
}
The domain model (your current User model):
public class User
{
// other properties..
[Required]
public string Password { get; set; }
}
You can use these models in your controller like this:
The GET action:
public ActionResult Register()
{
var registerModel = new RegisterModel();
return View(registerModel)
}
With a view like this:
#model RegisterModel
#Html.LabelFor(model => model.UserName)
#Html.TextBoxFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
#Html.LabelFor(model => model.Password)
#Html.PasswordFor(model => model.Password)
#Html.ValidationMessageFor(model => model.Password)
And the POST action:
[HttpPost]
public ActionResult Register(RegisterModel registerModel)
{
// Map RegisterModel to a User model.
var user = new User
{
UserName = registerModel.UserName,
Password = registerModel.Password // Do the hasing here for example.
};
db.Users.Add(user);
db.SaveChanges();
}
You say your password encryption is occurring in the controller. In this case shouldn't you be encrypting after validation? For example:
public ActionResult SomeControllerAction(UserViewModel user)
{
if (!ModelState.IsValid)
{
// at this point the human readable (and assuming < 20 length) password
// would be getting validated
return View(user);
}
// now when you're writing the record to the DB, encrypt the password
var crypto = new SimpleCrypto.PBKDF2();
var encryptedPass = crypto.Compute(user.Password);
user.Password = encryptedPass;
user.PasswordSalt = crypto.Salt;
_db.Users.Add(user);
_db.SaveChanges();
// return or redirect to whatever route you need
}
If you wanted to specifically control your validation, then try implementing IValidatableObject on your view model class and perform validation here, instead of via attributes. For example:
public class UserViewModel : IValidatableObject
{
public string Username { get; set; }
public string Password { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// validate the unencrypted password's length to be < 20
if (this.Password.Length > 20)
{
yield return new ValidationResult("Password too long!");
}
}
}
If i understand correctly you have a database table with a password field.
According to your model this password field is 20 characters long
[StringLength(20, MinimumLength = 6)]
And you want to insert a value greater then 20 characters.
If entity framework did not stop you then you would get a database error.(Entity framework doesn't know there is a mismatch between your data model and the database and it doesn't wanna take the risk of pushing the insert through)
I assume however that you ment to specify a clientSide validation rule on your viewmodel and not a length constraint on the database.
I hope you see why this is a confusing setup.
My advice would be to either split your viewModel and model up so you can post a viewModel with unencrypted password of maxlength 20 that you can convert to a model password with length 100.
If you find that too much hassle you could create an unmapped password property which you set from html when you post it and you convert it to the password property in your controller.
Your class could look like this :
public class RegisterModel
{
[Required]
public string UserName { get; set; }
[Required]
[NotMapped]
[StringLength(20, MinimumLength = 6)]
[Display(Name = "Password")]
public string PlainTextPassword { get; set; }
[Required]
[StringLength(300)]//This is optional
[DataType(DataType.Password)]
public string Password { get; set; }
}

mvc model and viewmodel?

so,
i have a "User" model that has a lot of fields but following are the impt ones:
public int Id {get;set;}
public string Username { get; set; }
public string Pwd { get; set; }
and i have a view model that validates the password that i use on a different controller:
public class ConfirmPassword : IValidatableObject
{
[Required]
public string Password { get; set; }
[Required(ErrorMessage="Confirm Password field is required.")]
public string ConfirmPwd { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
string regex1 = #"^.{8,10}$"; // 8 - 10 characters
Match requirement1 = Regex.Match(Password, regex1);
if (Password != ConfirmPwd)
yield return new ValidationResult("Password and Confirm Password is not identical.");
if (!requirement1.Success)
yield return new ValidationResult("Password must be between 8 and 10 characters.");
}
}
is there a way where i can connect the view model to my model entity? or just copy paste the codes my only option? I can't do copy paste since the code needs to have a IValidateObject which will mess up the whole User entity as there's a ton of background auditing happeneing.. I just need to validate the passwords whenever a profile is edited / created.
EDIT:
so sorry if everybody got confused. basically, i have multiple validations that i need on the confirm passwords that can't be handled by dataannotations, ergo the confirmpassword viewmodel. this validation i want to be applied onto the User model but without adding the "ConfirmPassword" field into it. as i dont need another field on the database. My question is how do i force the validations i have from the confirmapassword to trigger whenever the view POSTs and the password field does not meet its requirements?
namespace
{
public class User
{
public int Id {get;set;}
public string Username { get; set; }
public string Pwd { get; set; }
}
}
namespace
{
public class ConfirmPassword : IValidatableObject
{
[Required]
public string Password { get; set; }
[Required(ErrorMessage="Confirm Password field is required.")]
public string ConfirmPwd { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
string regex1 = #"^.{8,10}$"; // 8 - 10 characters
string regex2 = #"(?:.*?[A-Z]){1}"; // 1 uppercase
string regex3 = ""; // 1 lowercase
string regex4 = ""; // 1 numeric
Match requirement1 = Regex.Match(Password, regex1);
Match requirement2 = Regex.Match(Password, regex2);
Match requirement3 = Regex.Match(Password, regex3);
Match requirement4 = Regex.Match(Password, regex4);
if (Password != ConfirmPwd)
yield return new ValidationResult("Password and Confirm Password is not identical.");
if (!requirement1.Success)
yield return new ValidationResult("Password must be between 8 and 10 characters.");
if (!requirement2.Success)
yield return new ValidationResult("Password must contain at least 1 uppercase letter.");
if (!requirement3.Success)
yield return new ValidationResult("Password must contain at least 1 lowercase letter.");
if (!requirement4.Success)
yield return new ValidationResult("Password must contain at least 1 numeric character.");
}
}
}
You can use the decorator patter in your view model to do what you like. You can also use the System.ComponentModel.DataAnnotations namespace attributes to do all your validation for you.
public class ConfirmPassword
{
User model;
[Required]
public string Username
{
get { return this.model.Username; }
set { this.model.Username = value; }
}
[Required]
[DataType(DataType.Password)]
public string Password
{
get { return this.model.Pwd; }
set { this.model.Pwd = value; }
}
[Required(ErrorMessage = "Confirm Password field is required.")]
[Compare("NewPassword",
ErrorMessage = "The new password and confirmation password do not match.")]
[RegularExpression(#"^.{8,10}$")]
[DataType(DataType.Password)]
public string ConfirmPwd { get; set; }
public ConfirmPassword()
{
this.model = new User();
}
public ConfirmPassword(User model)
{
this.model = model;
}
}
Ok, I am still a little iffy on what you mean by connect view model to model entity... I think what you want is to now check if the password from the actual user matches the password passed in to the view model.
I personally would not do this in the view model itself, but rather in the controller and would add a ModelState.AddError if the password was incorrect.
The normal input validation can happen on the server or client side if you are using client side validation, but you can't check the password client side, so it will have to go to the server.
public LoginViewModel()
{
[Required]
public string LoginId {get; set;}
[DataType(DataType.Password)]
public string Password {get; set;}
[DataType(DataType.Password)]
public string ConfirmPassword {get; set;}
// this validation is not db related and can be done client side...
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
string regex1 = #"^.{8,10}$"; // 8 - 10 characters
Match requirement1 = Regex.Match(Password, regex1);
if (Password != ConfirmPwd)
yield return new ValidationResult("Password and Confirm Password is not identical.");
if (!requirement1.Success)
yield return new ValidationResult("Password must be between 8 and 10 characters.");
}
}
[HttpGet]
public ActionResult Login()
{
var model = new LoginViewModel();
return View("Login",model);
}
[HttpPost]
public ActionResult Login(LoginViewModel model)
{
var user = GetUserFromRepositoryByUsername(model.username);
if(user != null)
{
if(user.password == model.Password)
{
RedirectToAction("YouLoggedInYay!");
}
}
// if we made it this far, the user didn't exist or the password was wrong.
// Highlight the username field red and add a validation error message.
ModelState.AddError("Username","Your credentials were invalid punk!");
return View("Login",model);
}
I would include a userId in your ViewModel or add it on the URL so the controller can pick it up.
After validating the password combo you use the Id to retrieve the relevant User and update it with the new password. You can just do this within your new password post action.
You may want to match with the old password btw.
From what I believe, your UI validations and Logic validations should not be mixed up. It is worth doing in over again in the Logic even if it is the same thing. Basically, it is not the responsibility of the Entity object to carry the validations. It might be some service layer class that does it for the Entity. And you can probably throw an exception at that point.So it is handled in completely different ways in the UI and the Logic.
"I just need to validate the passwords whenever a profile is edited / created"
Use data annotations combined with IsValid on the ViewModel to check for failures. As far as mapping a Model to a View Model just use a decorator pattern.
Use System.ComponentModel.DataAnnotations (they even have a regular expression validator you can use)
Once passwords are verified against a policy, convert them to an MD5 hash and store that, not the password value
If all else fails there is nothing wrong with creating a separate UserValidation Class and share logic between the View Model and Model e.g. they both call the same methods to determine validity (reducing code).

Categories