Only allow registrations from specific email domains - asp.net-mvc

I am developing a site that uses the built in account model / controller that comes with the new MVC site template. I want to be able to only allow people to register if they use one of two specific domains in their email address.
So for example they can register if they use #domain1.co.uk or #domain2.co.uk, but no other domains (for example Gmail, Yahoo etc) can be used.
If anyone could point me in the right direction that would be great.

If using the MVC3 default site, you'll have a /Models/AccountModels.cs file. You can add a regular expression there to cause client-side* and server-side validation.
public class RegisterModel
{
...
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email address")]
[RegularExpression(#"^[a-zA-Z0-9._%+-]+(#domain1\.co\.uk|#domain2\.co\.uk)$", ErrorMessage = "Registration limited to domain1 and domain2.")]
public string Email { get; set; }
...
}
You will need to work out the expression that works out best for your requirements.
*client-side validation assumes your view references the jquery.validate script and has Html.ValidationMessageFor(m => m.Email) and/or Html.ValidationSummary(), which it should by default.

What more do you need than:
if( email.Contains("#domain1.co.uk") || email.Contains("#domain2.co.uk") )
Register(email);
else
throw, return false, whatever()

When it comes time to do your validation, i.e. is the email field populated, use a regex to make sure it is in the domain. As for what the actual regex should be, there is a lot of discussion online about validating email addresses with them. It even comes down to what a valid email address should contain. I found this example online, but it likely by no means the best solution, as I am not a regex expert. I have tried it with a few examples but I'm sure you can come up with some that will pass when they shouldn't:
^\w+([-+.']\w+)*#mail.com$
Where mail.com is the domain you want to check against. If you have multiple domains, you can either extend the regex or do multiple checks replacing mail.com in the regex with whatever else you want to use.
BTW I found that regex on this forums.asp.net post which touches on an issue like yours.

Validate that on both the frontend (the reg form) and the backend.
Here I recommend jquery validation plugin for client side validation.

Related

How to secure asp.net mvc5 applications?

<authentication mode="Forms"/>
<forms loginUrl="~/Login/Login" defaultUrl="~/Login/Something" protection="All"></forms>
</authentication>
One way is to add Authorization tag to every Controller to secure application from unauthorized user.Other way is to use session variables to store user information .So,my question is from hacking perspective,how we can secure our application form hackers?Is there any other way to secure application?
Note: This answer should not be viewed as complete in any way, security is always hard and if it's important to you - always consult with a third party security and penetration testing company. This is just a few things you should consider to make your MVC application safer (not necessarily safe).
Protect controllers
First step is to apply [Authorize] to your controllers, to make sure there is some sort of valid authentication before accessing a method. Preferably add Authorize to all controllers and make exceptions with [AllowAnonymous] to make it secure-by-default.
Authorize the user
Even though you've added [Authorize] to the controller, that only means that the user is logged in, not that the user should have access to whatever method is being accessed. The first step is to extend the attribute by specifying a set of roles for the method: [Authorize(Roles = "Administrator"]
Depending on the application, you might also have to check that the current user belongs to the company/group or whatever that is being edited, to prevent someone from modifying data that doesn't belong to them.
Don't leak data into models
If you're using your actual data models as view models, you are at risk of allowing the user to enter more data than they're supposed to. Consider this example:
class Employee {
public int Id { get; set; }
public string Name { get; set; }
public int Salary { get; set; }
}
Assume that we for some reason allow our employees to change their name, and we use the Employee model for that. But of course we only make an edit field for the Name, and not the Salary as that would be stupid :D. However, due to how the model-binding works, a smart Employee could just add <input type="text" name="Salary" value="2147483647"> to the form when changing their name, and our gullible db.Entry(employee).State = EntityState.Added; followed by db.SaveChanges() would update their salary as well.
Solution? Either make a view model with only the Id and Name property, to make it impossible to change the salary, or use the Bind attribute to only include the properties we allow: public IActionResult Update([Bind(Include="Id,Name")]Employee model).
XSS
A very important part is to protect your users from bad dynamic content. If I can enter HTML and Javascript that's displayed to some other user, I can abuse that to steal their authentication token for example. Making to never render user-entered data as HTML is a first step to prevent this. You should also make sure to always use the anti-forgery token in your forms as well. Adding CSP headers is a good practice to prevent someone from injecting scripts that shouldn't be there.

How can I validate an email address using the same method used by the DataAnnotations attribute DataType.EmailAddress?

I am using MVC3 and in certain locations in the code I am using the System.ComponentModel.DataAnnotations.DataType.EmailAddress attribute and letting MVCs Model validation do the validation for me.
However, I would now like to validate an email address in a different section of code where I am not using a model. I would like to use the same method that is already being used by MVC, however I was unable to find any information on how to do so.
EDIT - Sorry if my question was unclear. I will attempt to clarify.
Here is a snippet from the RegisterModel that is included with the default MVC template:
public class RegisterModel
{
...
[Required]
[DataType(DataType.EmailAddress)]
[DisplayName("Email address")]
public string Email { get; set; }
...
}
These attributes instruct mvcs model validation on how to validate this model.
However, I have a string that should contain an email address. I would like to validate the email address the same way that mvc is doing it.
string email = "noone#nowhere.com";
bool isValid = SomeMethodForValidatingTheEmailAddressTheSameWayMVCDoes(email);
As others have said, the DataType attribute doesn't actually do any validation. I would recommend you to look at Data Annotations Extensions which includes already written validation extensions for a variety of things, including Email.
It is also possible to do model validation on your full model explicitly: Manual Validation with Data Annotations.
If you want to do per attribute validation for a specific field/property, you can also look at the tests for DataAnnotationExtensions which should give you what you want:
[TestMethod]
public void IsValidTests()
{
var attribute = new EmailAttribute();
Assert.IsTrue(attribute.IsValid(null)); // Don't check for required
Assert.IsTrue(attribute.IsValid("foo#bar.com"));
..
}
Have a look at this blog post by Scott Guthrie, which shows how to implement validation of an email address using a custom attribute (based on the RegularExpressionAttribute).
You can reuse that logic if you need to validate the email address somewhere else.
You may want to look at this question: Is the DataTypeAttribute validation working in MVC2?
To summarize, [DataType(DataType.EmailAddress)] doesn't actually validate anything, it just says "hey, this property is supposed to be an e-mail address". Methods like Html.DisplayFor() will check for this and render it as foo, but the IsValid() method is pretty much a simple return true;.
You'll have to roll your own code to actually perform validation. The question linked above has some sample code you can use as a starting point.

Exclude a property from unobstrusive client Validation with MVC 3

I have a class User, that have an Email property, like that :
public class User : Entity
{
...
[Display(Name = "Email"), Required(ErrorMessage = "Required."), Remote("EmailExists", "User", ErrorMessage = "Email already in Use.")]
public virtual string Email { get; set; }
...
}
My View Create works fine with all the validation ...
But in my view Edit, my Email texbox is Readonly, so The user cant change the email...
The problem is my Remote validation EmailExists keeps firing...
Is there a way to exclude the Email client validation just in that case? Or maybe another solution?
Thanks
Best solution would be to render Email as text content(span, p, etc) in that particular case - validations would not fire. This would be best accomplished with editor templates. But if you don't wish to, you could use some javascript to remove rules on client side. Take a look at Plugins/Validation/rules - you would remove rule when textbox is readonly. But for me the first way is preferred option
I think that the easier way is to disable the field in the client instead of using readonly. The validate plugin doesn't take in account disabled fields.
You could use different ViewModels for the edit and create views and only apply the Remote attribute to view model associated with the create view or call some other remote validation logic for the view model associated with the edit view.

Is there any way to stop DataAnnotation validation after the first failure?

In my ViewModels I use several DataAnnotations to validate the form data, there are usually 2-3 annotations per field.
For example a field for an email address might look like this:
[Required(ErrorMessage = "Please enter an email address.")]
[Email(ErrorMessage = "That is not a valid email address.")] // Custom
public string Email { get; set; }
Now if someone were to submit the form, both errors would show up in the validation summary. Is there any easy way to specify an order to run the validation annotations so that if the Required validation fails, the Email validation doesn't run?
If this isn't possible, how is this usually handled? Should I create custom validators for any field that has more than a single annotation? Would that be a proper way to use annotations, where a single one handles multiple types of validation?
(I'm also aware I could probably combine the Required annotation into the custom Email one, but this is just an example).
In this specific case I would probably take the same approach that the ASP.NET WebForms validators take - simply have the EmailAttribute validator return true if the value is null or empty.
Think about it:
If the e-mail address is required, then there will also be a [Required] validator and a null/empty e-mail address will generate a validation error anyway;
If the e-mail address is optional, a null/empty value should be considered valid.
No need to solve the complex problem of intercepting validators when you can just design the individual validators to play nice together!
Ordering validation: No.
In this case you could simply remove the Required attribute because "" or " " will fail the email address validation.
And yes, AFAIK creating a custom validation attribute that combines both of them is probably your best bet.
The problem here is that the ordering on the attributes is completely arbitrary and decided at compile time. You actually can enforce simple ordering depending on the kind of validation runner you're using. If you are using something like xVal and a validation runner like the one mentioned here, you can add an orderby clause like this to force a specific kind of attribute to sort to the top:
orderby attribute.GetType() == typeof(T) ? 0 : 1
Just make a strongly-typed validation runner method, where T is derived from the ValidationAttribute class.

Partial Validation ASP.NET MVC

I've read a number of articles now in regard to validation and asp.net mvc and the majority tend to point to validation in the model. The problem I see with all of them is that they don't handle different scenarios, or at least, they don't show how they would be achieved e.g.
When creating or updating a user account the email address must match the email confirmation input. This email confirmation input isn't part of the model it's purely to assist correct user input, this might be called a virtual property. When a user logs in using their email address the validation shouldn't try and match the email against a confirmation input, however, in all the examples I've seen there is no way to differentiate between scenarios where the same data is validated in a different way.
Can anybody point me to any mvc validation articles that handle the above types of problem? Or does anybody have any advice on best practices to handle validation like this?
I had thought about introducing a "validation action" such as create, read, update, delete, and then I could validate the same bit of data depending on the context in which it is being used. Anybody have any thoughts on doing things in this manner?
Thanks in advance for any help
This is why I'm using Validators separated from Models. So, I have IValidator and different validators. For instantiate validator I use DI Container (StructureMap for example).
It was described (not by me) here:
Issues with my MVC repository pattern and StructureMap
According to my experience
1. Validator should be decoupled from controller into separate Service layer like, for instance, showed in this tutorial:
http://www.asp.net/learn/mvc/tutorial-38-cs.aspx
2. Service methods may encapsulate all the kind of validation. For example:
public bool PlaceBooking(Booking booking)
{
//Model validation
IEnumerable<ErrorInfo> errors = DataAnnotationsValidationRunner.GetErrors(booking);
if (errors.Any())
_validationDictionary.AddErrors("error", errors);
// Business rule: Can't place bookings on Sundays
if(booking.ArrivalDate.DayOfWeek == DayOfWeek.Sunday)
_validationDictionary.AddError("ArrivalDate", "Bookings are not permitted on Sundays");
if (!_validationDictionary.IsValid) return false;
//Errors comming from Data Access Layer
try
{
return _dao.Save(booking);
}
catch (DBExecutionException ex)
{
if (ex.ResultCode == ResultCodes.RES_UNIQUEINDEX)
_validationDictionary.AddError("error", "Booking already exists.");
else
_validationDictionary.AddError("error", "Some other DB issue happens.");
}
return false;
}

Resources