Ensure unique Username / Emails - asp.net-mvc

I am currently using Asp MVC / Identity 2.0 to build a membership site.
I have made some changes that now allow a user todo the following :
Create separate username / email values on account creation
Login using either username or email through a single text field
What I am concerned about is should user Alice register an account as follows :
Username - Alice
Email - alice#example.com
User Bob could create an account as follows :
Username - alice#example.com
Email - evilbob#l33th4x0rs.com
I'd like to ensure, that should a user create an account, their username is unique in both the UserName and EmailAddress columns.
I have currently achieved within my RegisterViewModel as follows
[RegularExpression(#"^([a-zA-Z0-9 \.\&\'\-]+)$", ErrorMessage = "{0} must be alpha numeric")]
[Display(Name = "Username")]
public string UserName { get; set; }
As such it is not possible to enter an email into the username field - is this the best way to do this though?
I'm concerned that later down the line, I may want to allow some special characters in the username field.
Forgive me if this is a n00b question, I'm still very much new to this.

You cannot ensure uniqueness of your records using the Data annotations you have in your view model properties. Those are for helping validations & display purposes primarily.
What you should be doing is checking the userName value againist both UserName and Email field of your User table and allow/deny user to continue his action.
To check the userName against both email and userName fields , you might try something like this.
var userNameToCheck="alice#ss.com";
var exists=db.Users.Any(x=>x.UserName==userNameToCheck||x.Email==userNameToCheck);
if(!exists)
{
// New record. Let's continue saving it.
}
But a better solution is to use email as your username for the app(Only one column in db table) and keep a unique constraint on that column(Email) to prevent accidental duplicate entry even if your code failed to stop the duplicate entry insertion.
You should always have validation in your code and db (constraints) to be on the safer side.

Related

Tenant based unique username in grails application

I am working on a application which has several companies as our clients and multiple users under each company which access our application.
So I have structured the table of users to save users of all companies in same table and have the company_id as a column-
class User {
String username
String password
static belongsTo = [company:Company]
static constraints = {
username blank: false
password blank: false
}
}
In this app I have customised the spring security to authenticate the user based on 3 fields- username, password and comapany. So if there are two users ABC in company Org1 and Org2 they will be identified properly.
Now if I apply the constraint of unique: true on username the constraint is applied on whole table and it does not allow me to save two users ABC, no matter if they are on two different companies.
(PS- I understand constraint is based on table, kindly read further).
Now the main problem is that I want to make the username unique based on the company not based on User table. How to do that? Is there a predefined constraint that can be used to check if the username is present in the company? Or will have to check it each time while registering, if the username already exits in a company?
You could try to use a multi-column constraint (see http://www.grails.org/doc/latest/ref/Constraints/unique.html)
Your username constraint would look something like this:
username blank: false, unique: 'company'

Using Claims Types properly in Owin Identity and Asp.Net MVC

I am using Owin and Identity and I am having a problem with Claims.
I have applications where users use an email to authenticate and others that use an username.
The sign in method in the business layer can accept an Email or an Username depending on the case.
To "obfuscate" the user identity I use a GUID, unique to each user, when displaying a page with user info.
I also use this because sometimes an email or an username can be a problem in the url ...
When I sign a user I have the following claims types:
new Claim(ClaimTypes.Email, user.Email),
new Claim(ClaimTypes.Name, user.FullName),
new Claim(ClaimTypes.GivenName, user.FirstName),
new Claim(ClaimTypes.Surname, user.LastName),
new Claim(ClaimTypes.NameIdentifier, user.UserUniqueIdentifier.ToString())
So my interpretation is:
Email is the user's email
Name is the user's full name
GivenName is the user's first name
Surname is the user's last name
NameIdentifier is the user's unique identifier ... It can be the email, the username or in this case I am using an Unique ID.
What is strange is there is no Claim Type for Username. Where would to place it?
Basically it seems there is a problem when a Username is not used as the Unique name identifier but it is still necessary.
Is something wrong with my logic claims types?
ClaimTypes.Name (http:// schemas.xmlsoap.org/ws/2005/05/identity/claims/name) should be used for the username.
ClaimTypes.NameIdentifier is typically used for the user's id. In some cases it could be a username.
ASP.NET Identity uses ClaimTypes.Name to store the username, and ClaimTypes.NameIdentifier to store the primary key GUID of the user.
If you examine what Facebook or Google return from oAuth you will see that ClaimTypes.Name is ClaimTypes.GivenName + ClaimTypes.Surname. LinkedIn returns then concatenated and I believe this is a bug because I have a completely different username there. Twitter returns username for ClaimTypes.Name, but Twitter is a special case and they do not even return email.
All of them are using some opaque numeric identifier for ClaimTypes.NameIdentifier. And they use their own string names, usually starting with urn:facebook:link, urn:google:profile, etc for custom data.
Asp.NET Identity model uses UserName for ClaimTypes.Name. The bottom line is that ClaimTypes.Name is used differently in practice. You could add any claim name as a string and could add the urn:... scheme to make it unambiguous.

AspNet Identity 2.0 Email and UserName duplication

My current Asp.Net MVC 5 project mandates Email address for UserName. Now I want to upgrade ASPNet Identity v1.0 to v2.0 to leverage all its new features (see here).
However, ASPNet Identity v2.0 adds Email as a separate column to the Users table and adds a corresponding property to the IdentityUser class.
I don't want to duplicate UserName into this new Email column. How can I map this Email Property of IdentityUser to use existing UserName column & property? Is it possible to ignore this Email property and skip adding the column in the Users table? Has anybody tried this?
Please share.
Update
This is the identity 2.0 limitation. We cannot ignore Email property or leave it Null. Some of the Identity functionality will not work. :(
You can try one of these:
Try to ignore it by either overriding Email property in your User class and unmapping it or using fluent API.
public class ApplicationUser : IdentityUser
{
// ....
[NotMapped]
public override string Email { get; set; }
}
or
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ApplicationUser>().Ignore(u => u.Email);
}
When you register your user just make sure that you populate Email with your UserName
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
// ...
}
}
Of course, you can always ignore Email column if you're not going to use it, since it allows NULLs, it'll just be sitting in your AspNetUsers table with bunch of NULLs, not the best approach but remember that by ignoring it you might lose new features that ASP.NET Identity 2 might offer that you might want to use.
NOTE However I'm not sure if option number 1 will work on Email property since it's probably used all over the place in new Identity code. Worth a try though. I know that's how you can get rid of other columns if you don't need them. I personally happen to use new Email property/column so I haven't tried it.
Not sure if it helps you, but thought I'd share it just in case.
I have the same problem, and the way that I resolved it was that the email address was the same as the username when creating a user:
var newUser = new ApplicationUser()
{
UserName = email,
Email = email,
};
However, if you try to create an account with a duplicate username, you will get 2 validation errors, one for the username field, and one for the email address.
To get around that, allow email addresses to not be unique (they will still be unique though as your usernames are unique) by editing the identityconfig.cs file:
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = false
};

Error while using Remote Property of DataAnnotation?

I am having a problem using the remote property of the data-anotation.
I am having a model for user which stores the data:
[DataType(DataType.EmailAddress,ErrorMessage="please enter valid email")]
[DisplayName("Email Address")]
[Required(ErrorMessage = "Email is Required")]
[Remote("CheckUniqueEmail","User",ErrorMessage="An account with this email address already exists.")]
public string Email { get; set; }
and I am checking the distinct user email while creating the new one...
When I try to login with the email and password in the different controller, it still calls the Remote and checks for the unique email...
I think I have to exclude the email and password property in the Login controller - but I don't know how.
you need to use 2 different view models, one for creating an account and one for logging in.
You should use another model for logging in at LoginController.
These validations will be used everywhere you use this model.
You can also use the MetadataType to reuse the same base model and apply different validations. Example Here.

Grails: String(username) as primary key, but save and get id string(username) with ignorecase?

I am using a string "username" as the primary-key of a table,
But when saving and getting the column with the username id I want the case to be ignored so that new users can't try to impersonate another user.
e.g. When registering a new user
username = Daxon
username = DaXoN //this should not be allowed
When getting the unique username it can be typed in any case and still be obtained.
Youtube do this with their usernames.
e.g.
youtube.com/user/Daxon
youtube.com/user/DaXoN //Should go to the same profile of 'Daxon' anyway
Domain Class
This uses username as the primary key
class User {
String username
String password
static constraints = {
}
static mapping = {
id generator: 'assigned', name: "username", type: 'string'
}
}
I then scaffold the controllers and views,
so can anyone help me on saving and getting unique usernames with case ignored?
One way you can prevent the second user from registering a name that differs only in case is to create a case insensitive unique index on username at the database layer. If you try to save a name that case-insensitively matches an existing one, you'll get a database exception. This is the default with mysql, but for other databases, something like the following should do it:
create unique index username_csunique_idx on user(lower(username));
I'm not aware of any way to specify that kind of index in the domain class DSL.
To find the objects, query by username case insensitively. For example, User.findByUsernameIlike(userName), or User.find("from User as u where lower(u.username) = ?", [userName.toLowerCase()]) if you prefer HQL.
You can modify your save and get methods of the generated controler to do string comparrisons. Before inserting a username you could do an HQL query that does a case insensitive comparrison on the user name you want to insert to make sure that no user name already exists. See the "HQL And Case Sensitivity" section of the following link. http://dev.wavemaker.com/wiki/bin/view/Dev/HqlTutorial#HCaseInsensitiveQuery

Resources