Is it ok to expose messages from the `IdentityError` class? - c#

I'm quite new to the asp.net core identity framework. Many tutorials, articles and guides seem to handle an IdentityError in the same way. They expose the description of the error to the user, i.e. they add the description of the error to the ModelState.
It's been drummed into my head that exposing errors to the user is a terrible idea as it empowers attackers.
So I thought, It must depend on what kind of information is available in the description. For example, if the error is "Your password is too weak" or "You need to enter in a valid e-mail address". That type of information is valuable to the user and should be ok to display. However a "The data source took too long to respond" is already too much information and offers little value. I'd rather catch that type of error and replace it with some generic 500 error.
So my question: Is it safe to show the raw Identity Error to the user? If not how can I filter what I should and Should not show to the user?
I tried looking at the MSDN docs to understand all the possible codes that I could receive. But those docs offer very little information.
I am specifically working with
var userCreationResult = await userManager.CreateAsync(newUser, password);
But it applies to any instance when an IdentityError might appear.

Many software quality and security regulations have audit requirements for this (no error message presented to end users may contain information that is secret or would enable users with malicious intent to compromise the system or access sensitive data), so this is an important question. If there is a documentation or article specifically addressing this, then it is well hidden.
The possible values that the two members of the IdentityError class can assume, are baked into the framework. So it looks like you can be sure that it will always be one of those, unless you obtain an instance of IdentityError from anything else than a UserManager.
The Code field is assigned from nameof of the error method, and the associated Description text is read from core framework resources, so those will be localized.
Source Code
en-us Descriptions
List of errors in current implementation (version 3.0.0):
DefaultError
ConcurrencyFailure
PasswordMismatch
InvalidToken
RecoveryCodeRedemptionFailed
LoginAlreadyAssociated
InvalidUserName
InvalidEmail
DuplicateUserName
DuplicateEmail
InvalidRoleName
DuplicateRoleName
UserAlreadyHasPassword
UserLockoutNotEnabled
UserAlreadyInRole
UserNotInRole
PasswordTooShort
PasswordRequiresUniqueChars
PasswordRequiresNonAlphanumeric
PasswordRequiresNonAlphanumeric
PasswordRequiresLower
PasswordRequiresUpper
Most of these are static strings and do not disclose any variable information.
The following do disclose variable information. This is data previously supplied by the user anyway in the first eight cases, and the value of a server configuration property in the last two cases, minimum required password length and minimum number of unique characters required in a valid password:
InvalidUserName: the user name
InvalidEmail: the email address
DuplicateUserName: the user name
DuplicateEmail: the email address
InvalidRoleName: the name of the role
DuplicateRoleName: the name of the role
UserAlreadyInRole: the name of the role
UserNotInRole: the name of the role
PasswordTooShort: the minimum password length
PasswordRequiresUniqueChars: the number of unique chars required
If that qualifies as "safe" within the constraints and specifications of your project, then the answer is yes.

Regarding your second question on how to do, you could do the following to filter out
a duplicate username as you loop through errors
if (error.Code == _userManager.ErrorDescriber.DuplicateUserName(user.UserName).Code)
{
//Hide info to user by, e.g. redirecting to a page for a registration flow, or display an invalid login attempt for a login flow
}

Related

Does IIS Metabase return sites in Id ascending order?

I'm not sure if my question on the face of it makes full sense, so let me try and elaborate. At the moment I try and check if a website already exists in IIS by creating a new DirectoryEntry:
DirectoryEntry IISWebsites = new DirectoryEntry(MetaBasePath);
MetaBasePath is defined earlier as:
private const string MetaBasePath = "IIS://Localhost/W3SVC";
I check IISWebsites children in a foreach loop and just wondered if this will run through the children in Id order? From what I've read this is actually stored in the DirectoryEntry 'Name' property.
The reason I ask is that if the website name entered by the user in my web setup project isn't found then I want to return the highest id so I can add 1 to it and create a new website with the name supplied by the user.
Having tested this with my IIS it does seem to return it in this order but I need to be sure.
EDIT
I've found the following on Microsoft support (http://support.microsoft.com/kb/240941):
Note that when the metabase is searched for configuration information,
it is enumerated from the bottom, or subkey, to top, or node.
This seems to imply that it does do what I think, but it's not 100% clear if it works on site Id as I'm not sure how this relates to the subkey.
The documentation does not specifically define the order as by site ID so it would not be safe to assume it will always be sorted that way (particularly as your current application eventually gets used with new versions of .NET/Windows/IIS in the future).
Most likely the number of websites is not going to be big enough that enumerating them to find the max would not be a bottleneck.
Even so, you can run a search for websites and specify the order using DirectorySearcher.Sort.
Note that in regards to your edit and how configuration information is enumerated, that does not related to sort order. The one sentence taken out of context is not as clear. Read it in context of the whole paragraph and it is clear that the enumeration behavior is related to metabase property inheritance.

Help with MVC 3 Routes

I have a simple route structure in my MVC 3 app that is breaking in an unexpected way.
My URL structure is fairly simple, but contains a handful of variables.
http://site.com/{location}/{stage}/{controller}/{action}/{id}
examples:
http://site.com/ny/prod/server/list - list all prod servers in ny
http://site.com/ny/test/server/123456 - list the details for the server in ny, in the test stage, with id 123456
http://site.com/ny/prod/server/reboot/565656 - reboot the server in ny, in the prod stage, with id 565656
I created the following route in my Global.asax file.
routes.MapRoute("Default", "{location}/{stage}/{controller}/{action}/{id}", new {controller="server", action="list", id = UrlParameter.Optional});
This works fine for displaying a list of servers and the details of a server at /server/details/id, but when I try to execute a reboot, I get an error.
URL: http://site.com/ny/prod/server/reboot/565656
The view 'ny' or its master was not found or no view engine supports
the searched locations. The following locations were searched: ...
Why would it try to look for a view name ny.cshtml?
i think your problem is that you are either not using a constraint to define what location and stage should look like and it is giving you false positives and reading things in where they are not supposed to or you have your route definitions in the wrong order
make sure you have the default mvc defined last and if you have multiple custom routes constrain the either using a regex or custom constraint class to define what locations are valid and they should look like
eg http://site.com/ny/test/server/123456
is ny a valid location - make a custom constraint that defines what a
valid location is validate it against a database or a list of valid
locations
is test a valid stage - regex could be sufficient but i always try to avoid regex whenever possible as it is evil and hard to maintain. again i would write a custom constraint to define what stages are valid likely validating against a list is sufficient is the case as you shouldnt have very many stages
also to be noted with using stages the way you are in your url you can also add authentication rules in a constraint so that for exaple only people that are ..say.. admin or stakeholder roles be mached to the route and regular or non authenticated users would simply fall through to the next route or can simply give a 404
writing routes can be tricky so it is advised to contrain your input data as much as you can especially if you are accepting string data
stephen walther has a good post on writing route constraint at his blog

I don't understand how email activation works

I want to verify that the user email is valid and turn this email into his id in my system.
Yet I don't know how to make a link in the mail, that activates the account like(facebook and others
) and I don't really understand what happens when the link is selected.
I thought of generating a key like "sdklbsdgk4493" to enter once- so that guessing is hard, yet for many people copy and paste is not trivial and I may annoy them with this solution.
Any thoughts or ideas?
p.s: I'm working in c# so if it can be done with c#... it will be great :)
Thanks Asaf
When you insert a new user in the Database, their status should be "Deactivated" and you insert a "GUID" you generate alongside. You send them a link to your activation Page which would contain this GUID in the Query String. It will look like this:
www.YourSite.com/Activation.aspx?GUID=jdfhg43h98234
In the Activation.aspx page, you take this GUID from the Query String and compare it to the one you have in the Database. You then activate the Account having that GUID.
Create the user
Generate a unique string for the user
Have a Table that stores the unique string, the user Id ,a boolean that holds whether it got activated or not, the generation date, the expiration date and if you have different uses for these activation strings, the type(link to another table)
Now within the email you should get the string and write it within the email along with a link to the page you're going to use for validation such as whatever.com/verify.aspx?activationString=hd3fd33fen342n43
Within this page you do a query search within the table that holds the keys and if its not already validated
You have your users table in the DB (or where ever it is that you store your list of users), just add a column stating if the user's mail is validated.
To the validation mail add a link that fires some PHP with a user-specific code (like it's index in the DB). The PHP will set the user's "validated" column to true, and it'll be done.
It's not as complicated as it may seem at first.
The idea is to create a random key, save it to the database connected to the useraccount, supplying a link to the users e-mail which could point to a webservice(or regular website) which takes the key as a querystring which will then activate the account connected to that specific key.

IPrincipal.IsInRole() only works when I truncate the role names - why?

I have an application that relies heavily on authorization of users. Within it, I am using IPrincipal.IsInRole() to check whether users are in the correct groups:
IPrincipal principal = Thread.CurrentPrincipal;
bool inRole = principal.IsInRole("mydomainname\some role with a long name");
This works fine for the most part, but fails (returns an incorrect result) if the principal is an instance of a WindowsPrincipal. I have found that to make it work correctly, I have to truncate the name of the role that I pass in to be 32 characters long (including the domain name and the \):
IPrincipal principal = Thread.CurrentPrincipal; // <- returns a WindowsPrincipal
bool inRole = principal.IsInRole("mydomainname\some role with a lo");
Truncating the role name then works correctly. Why? Is this a bug/feature/documented issue? I have an inkling that it may be related to Win2000 domains, but cannot find any info on it.
Some extra info:
This is a problem because the application can be configured to use either active directory or "custom" for its authorization ("custom" being any authorization provider that supports an interface - could be SQL-based, file-based, etc..). When custom is configured, the roles most likely do not need truncating and so I don't want to have to deal with this special case in my code. Additionally, I have another part of the application that uses classes in the System.DirectoryServices.AccountManagement namespace to look up groups memberships. This requires the full role name and does not work if they are truncated.
After much trial and error, I have figured out what is going on.
When a group is created in Active Directory, it is given two names:
It seems to be that WindowsPrincipal uses the pre-Windows 2000 group name when IsInRole is called.
After searching extensively, this does not seem to be documented anywhere. The closest I got was this speculative answer to a similar question here on SO.
In my case, the groups I was querying against on the domain had a long name, but a truncated pre-Windows 2000 name (truncated to 32 characters for some reason). Passing in the long name does not work as it was checking against the wrong group name.

How to Extend Membership in Asp.net?

I am wondering how do I extend the membership stuff in asp.net?
When a user logs in I want to check the UserName and Password. Of course the standard asp.net membership does this(this it is ValidateUser()).
I also want to check another field called "institution". If a user types something in this box I want to verify if the "institution", "userName" and "password" match what is in the database.
If a user leaves the "institution" blank then I just want to use it default ValidateUser() method that is provided in asp.net and check only "userName" and "password".
So can I overload the ValdiateUser() method? Or will I have to write my own one to handle this new case?
Where would I store this "institution" field in the database? I heard something about people recommending the "Profile" table but I am not sure.
Also how can I change the membership to treat these as 3 different users
Institution: ABC
UserName: A09410515
Password: 1234567
Institution: GHA
UserName: A09410515
Password: 1234567
UserName: A09410515
Password: 1234567
So as my database should be concerned these should be 3 unique users. Of course in the case that my database already would have the same information stored in it.
For example.
Institution: ABC
UserName: A09410515
Password: 1234567
and someone tries to sign up with the exact same information for "UserName" and "Institution" then it would spit back an error about being duplicate names.
Yes, you can create a custom membership provider. Your provider will implement MembershipProvider giving you full control over creating an interface between the membership system and extended database schema. Writing A Custom Membership Provider for your ASP.NET 2.0 Web Site is a detailed example.
The lazy way of doing this would be to combine institution and username together to create the actual username.
Thus you'd have 3 distinct usernames: ABC&A09410515, GHA&A09410515, and &A09410515. Just don't allow a user to use & in a username.
Then, before creating the user or logging in you just combine the two strings together.
I can't think of any significant problems that can't be fixed with a simple hack (e.g. displaying the username (use username.split('&')[1] ), but JP's post is definitely the "right" way to do it.
James
You might use Application Name as the institution, that way you would have the same user name in different applications
Rodrigo.

Categories

Resources