I am working on an Asp.Net 4.0 web application that uses Asp.Net membership and role functions.
The application will have three roles that have access to the login page, and the other to it.
The way it should work is as follows.
The back user (in one of the three privileged roles) creates the user. In the code, this is done programmatically, and not on the Register Register page. When a user is created, they are added to the unprivileged role, which for clarity is called the visitor role.
Back the end user then creates a link for the new user, which is in the form https://www.example.com?link=cc82ae24-df47-4dbf-9440-1a6923945cf2
When the link is visited, the application will find the user associated with the query string, get the username and password (which are hashed and salted accordingly) and register the user.
That's where I go. Until now, creating a user’s work just fine, querying the database based on the value of the query string does its job and returns the corresponding bits of information, all this seems to be flowing pretty well, for actual logging with an exception. Apparently, there is no clear method for user registration programmatically without going through rigmarole to force the user to log in, which I explicitly said to avoid.
Here is my code, the “pers” object is a class that populates from the database when they land on the default link page:
protected void LogUserIn(string p) { SqlConnection conn = UtilityMethods.GetConnection(); Guid par = Guid.Parse(p); BioProspect pers= new BioProspect(conn); pers.FillDetailsFromDb(par); testlable.Text = pers.ToString(); Response.Cookies.Remove(FormsAuthentication.FormsCookieName); try { if (Membership.ValidateUser(pers.Email, pers.Pword)) { FormsAuthentication.SetAuthCookie(pers.Email, true); Response.Redirect(Request.Url.Scheme + "://" + Request.Url.Host + "/About.aspx"); testlable.Text = "Logged in!"; } else { throw new Exception("Something went wrong"); } } catch (Exception ex) { StringBuilder sb = new StringBuilder(); foreach (DictionaryEntry d in ex.Data) { sb.Append(d.Key.ToString()); sb.Append(": "); sb.Append(d.Value.ToString()); sb.Append("\r\n"); } AMessage(sb.ToString()); } }
Now I checked the username and password values for the database table itself, and all of this is correct. I understand that the password stored in aspnet tables was salty and hashed, so I check the values in the temporary table I created to keep clear text. It is right. In addition, in the code above, the FormsAuthentication.SetAuthCookie method asks for a username and password — in this case, the username is an email address. This information is also valid when checking during debugging.
I must point out that the links we send are pretty much one-time links. Each time a change is made relevant to that particular user, the value of the link parameter will change and the old link will be completely useless. The page to which they will be redirected will contain documents that are directly related to this particular user and no one else.
However, we still need Asp.Net membership benefits, profiles and role frames, since the “visitor” may also have several links sent to them with various documents and document versions added and changed over time.
Can anyone think of a better way? I still looked at most of the relevant entries here and here , but they all seem somewhat incomplete.
EDIT
It seems that I have at least partially solved this using the information obtained from the accepted answer here
Essentially, the problem was that my web.config membership section had to say which hash algorithm to use. At the moment, I have no idea what the default is, if there is one, but it adds
<membership hashAlgorithmType="SHA1">
in web.config at least allowed me to register users created after adding the specified line. The next step for me is to understand why I cannot get other users to log in.
However, I am still getting a ThreadAbortException thrown by Joe, which I am currently actively working on a resolution.