Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically log a user in to asp.net membership and roles?

I'm working on an Asp.Net 4.0 web application which is using the Membership and Roles features of Asp.Net.

In the application, there will be three roles which have access to the login page and one role which doesn't.

The way it is supposed to work is as follows.

Back end user (in one of the three privileged roles) creates a user. In the code, this is done programmatically rather than using the Register User page. When the user is created, they are added to the unprivileged role, which, for the sake of clarity is called the Visitor role.

Back end user then creates a link for the new user which is in the form of https://www.example.com?link=cc82ae24-df47-4dbf-9440-1a6923945cf2

When the link is visited, the application will locate the user associated with the query string, get the username and password (which are suitably hashed and salted) and logs the user in.

This is where I'm coming undone. So far, the user creation is working just fine, the database query based on the value of the query string is doing its job and returning the relevant bits of information, it all seems to be flowing pretty well, except for the actual logging in. There doesn't seem to be a clear method of logging a user in programmatically, without going through the rigmarole of getting the user to log themselves in, which I have been explicitly told to avoid.

Here is my code, the "pers" object is a class which is populated from the database when they land on the default page of the link:

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've checked the values of the username and password against the database table itself and it is all correct. I understand the password stored in the aspnet tables has been salted and hashed, so I'm checking the values in a temporary table I created to hold the clear text. It's right. In addition, in the code above, the FormsAuthentication.SetAuthCookie method is asking for a username and password - in this instance, the username is the email address. This information is also correct when inspected during debugging.

I should point out, the links we are sending are pretty much one time links. Every time a change is made relevant to that particular user, the value of the link parameter will change and the old link will be come completely useless. The page they will be redirected to will hold documents which are directly relevant to that particular user and to no others.

However, we still need the benefits of the Asp.Net Membership, Profiles and Roles framework, since the "Visitor" may well have several links sent to them, with different documents and versions of documents being added and changed over time.

Can anyone think of a better way? I have so far looked at most of the relevant entries here and here but they all seem somewhat incomplete.

EDIT

I seem to have at least partially resolved this, using information gleaned from the accepted answer here

Essentially, the problem was my web.config membership section needed to be told which hashing algorithm to use. At the moment, I have no idea what the default one is, if there is one, but adding

<membership hashAlgorithmType="SHA1">

to the web.config has at least allowed me to log in users created after the above line was added. The next step is for me to understand why I can't get the other users logged in.

I am however still getting a ThreadAbortException as suggested by Joe, which I am now busily working to resolve.

like image 223
inksmithy Avatar asked May 18 '12 15:05

inksmithy


2 Answers

I'm not sure I completely understand your problem, but a call to FormsAuthentication.SetAuthCookie will essentially log the user in programatically.

In addition, in the code above, the FormsAuthentication.SetAuthCookie method is asking for a username and password

No, SetAuthCookie needs a username, but not a password.

In your sample code, the call to Response.Redirect will throw a ThreadAbortException, so that your catch block will execute. Maybe that's confusing you.

In response to comment:

Essentially, the problem I am having is that the user appears not to be getting logged on. The FormsAuthenticate method is returning false

There is no FormsAuthenticate method in the above code.

Having said that, I don't see why you're trying to authenticate the user (Membership.ValidateUser) in this scenario. I'd have thought you'd want to locate the username associated with the querystring, then simply call FormsAuthentication.SetAuthCookie to log him in.

like image 124
Joe Avatar answered Oct 06 '22 01:10

Joe


I understand the password stored in the aspnet tables has been salted and hashed, so I'm checking the values in a temporary table I created to hold the clear text. It's right. In addition, in the code above, the FormsAuthentication.SetAuthCookie method is asking for a username and password - in this instance, the username is the email address. This information is also correct when inspected during debugging.

Please do not store the password or any password in plain text.

Essentially, the problem I am having is that the user appears not to be getting logged on. The FormsAuthenticate method is returning false.

Are you 100% sure this simply isn't a cookie issue?

It seems to be you should be able to provide the stored password hash and the username and log into said user account. Just override the method that hashes the "password" and instead forward the protected password onwards to the authentication system instead.

like image 26
Security Hound Avatar answered Oct 05 '22 23:10

Security Hound