views:

1124

answers:

3

HEllo,

In an ASP.net application I'm using Login control with custom membership provider that I wrote, and what I also want to do is to set Thread.CurrentPrincipal to my custom Principal object, just after the user is authenticated.

I'm using the setter: Thread.CurrentPrincipal and it sets the Principal object for me but, on all the consequent threads this CurrentPrincipal is overridden with the default one.

Here is my code for the Authenticate event of the Login control:

protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)
    {
        string username = Login1.UserName;
        string password = Login1.Password;

        if (Membership.ValidateUser(username, password))
        {
            var login = sender as Login;
            var phoenixIdentity = new PhoenixIdentity("B", "Forms" , true);
            var principal = new PhoenixPrincipal(phoenixIdentity);

            Thread.CurrentPrincipal = principal;
            AppDomain.CurrentDomain.SetThreadPrincipal(principal);

            HttpContext.Current.User = principal;

            e.Authenticated = true;
        }
    }

For example, imagine that I login with the username A, everything goes well... Validation passes, but I hardcode the user with the username B in the Identity object which is set to the Principal object I set as the CurrentPrincipal object.

When I check which user is set to the CurrentPrincipal Identity at the end of this method it says it's user B. But when I load another page and then check what the Identity of the CurrentPrincipal is, it says it's user A.

So, how can I make my CurrentPrincipal object to be persistent accross all other threads, and where/when does this Login control sets the CurrentPrincipal object of the Thread?

thx in adv

+1  A: 

You can handle FormsAuthentication_OnAuthenticate(object sender, FormsAuthenticationEventArgs e) (in Global.asax) and set CurrentPrincipal here.


void FormsAuthentication_OnAuthenticate(object sender, FormsAuthenticationEventArgs e)
{
var phoenixIdentity = new PhoenixIdentity("B", "Forms" , true);
var principal = new PhoenixPrincipal(phoenixIdentity);
e.User = principal;
}
Tadas
Let me clarify this more... I AM using Forms authentication already, if you haven't noticed... It's just that I want to hold the User Id (along with some other user info) in the Identity object of the Thread.CurrentPrincipal, so I implemented my own Principal and Identity objects and overriden the Authenticate method of the Login control of THE Forms authentication.
Goran
I'll try this right now...
Goran
+1  A: 

Tadas is not wrong, FormsAuthentication correctly implemented will not cause this problem.

Your page is accessible even without login, only in the login page, your thread's principle is set manually by you, but when you hit the other URL, it sure doesnt call your login page and remember each page runs on its own different thread. If you request first page and set thread principle and you request second page in same browser instance, it may or may not be the exact same thread.

This is how FormsAuthentication works,

  1. It checks if Auth Cookie is set or not, it then directs user to login page
  2. Login page must validate and set auth cookie, like FormsAuthentication.SetAuthCookie
  3. Before every page access, Step 1 is executed.
  4. After successful validation of Auth Cookie, ASP.NET internally sets the current user and all differnet parameters according to your membership component.
  5. ASP.NET Global.asax file can give you some events where in you can plugin your code to check just after authentication is successful you can change your current user, remember setting your current principle on login page will not help

We had similar issue when we were using session to store certain important information, after auth sessions were not rebuilt, so we wrote a HTTP Module, and in it's init method, we attached AfterRequestAcquired event and in this event you can write your code to instantiate all your important user related variables.

Akash Kava
A: 

This is what I did in FormsAuthentication_OnAuthenticate method:

if (FormsAuthentication.CookiesSupported)
        {
            if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
            {
                try
                {
                    FormsAuthenticationTicket ticket = 
                        FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value);

                    var myIdentity = new GenericIdentity("B");
                    var principal = new GenericPrincipal(myIdentity, new string[]{"rola1"});
                    e.User = principal;
                }
                catch (Exception ex)
                {
                    // Decrypt method failed.
                }
            }
        }
        else
        {
            throw new HttpException("Cookieless Forms Authentication is not " +
                                    "supported for this application.");
        }

it seems that it's working what it should do... It's just that if I put my custom principal/identity pair as e.User, then I have serialization problem which I need to fix next... Thank you guys...

Goran
Serialization problem just went away when I switched to IIS instead of using Visual Studio Development server.
Goran