Enigma about property Request.IsAuthenticted

Damir Dobric Posts

Next talks:

 

    

Follow me on Twitter: #ddobric



 

 

Archives

There are many scenarios which require you to read or set the property HttpRequest.IsAuthenticated, while implementing some security staffs.

 

For example, imagine you write a web application, which utilizes the forms authentication.

 

The forms authentication's simplified pattern is shown in the code bellow:

 

protected void cmdLogin_Click(object sender, EventArgs e)

{     

      ValidateUser(username, password);

 

      DoSomething() ;

 

      FormsAuthentication.RedirectFromLoginPage(username, true);

}

 

The method cmdLogin_Click is called when the user clicks in the browser corresponding LogIn-button. The method ValidateUser implements some custom authentication, which simply throws an exception, when the user’s credentials are invalid.

 

After successful validation your code could do something, before the login-process leaves the method cmdLogin_Click and redirects the browser to the page, which was originally requested.

 

Intersting and confusing things can happen, in implementation of DoSomething(). Because this method is called after the user "is authenticated", it is to expect that some of execution paths in and after of this method demand (require) the authenticated user.

 

In such cases most people expect that the property Request.IsAuthenticated could be used. Unfortunately, this is in general not true. Because this property is read-only, it can not be set while authenticating somewhere in method ValidateUser. The method ValidateUser does not authenticate the user. It just checks user's credentials.

 

So, I decided to dig into the implementation of the property IsAuthenticated.

The original implementation of this property looks as shown in following code snippet:

 public bool IsAuthenticated
{
      get{
      if ((this._context.User != null) && (this._context.User.Identity != null))
      {
            return this._context.User.Identity.IsAuthenticated;
      }
       return false;
     }
}

 

Now, it is obvious that the value of this property can be manipulated by using of security principal: System.Threading.Thread.CurrentPrincipal.Identity.

Followong code snippet shows how to set the current principal:

 

GenericIdentity myIdentity = new GenericIdentity(userName);

GenericPrincipal myPrincipal = new GenericPrincipal(MyIdentity, new string[]{“role1”, “role2”}); 

Thread.CurrentPrincipal = myPrincipal;

 

Onother interesting point is try to change the value of property IsAuthenticated by using of the method FormsAuthentication.SetAuthCookie.

This method will not change the request in authenticated state. However, this method will send the cookie to the client, which will represent the authenticated user in the next request:

 

HttpContext.Current.Response.Cookies.Add(cookie1);

 

That means, after the call to SetAuthCookie the current request remains unauthenticated, but the next request will automatically become authenticated.

 

In the first example, we redirected the user to the next page by calling of RedirectFromLoginPage. It is important to now, that this method internally calls the method SetAuthCookie and after all, it redirects the browser by using real redirect and not transfer (Server.Transfer). This means, that after successful authentication, the browser is forced to send the new request, which is authenticated.

 

Following code-snippet shows the full implementation of RedirectFromLoginPage:

 

 

public static void RedirectFromLoginPage(string userName, bool createPersistentCookie, string strCookiePath)
{
      FormsAuthentication.Initialize();
      if (userName != null)
      {
            HttpContext context1 = HttpContext.Current;
            string text1 = FormsAuthentication.GetReturnUrl(true);
            if (FormsAuthentication.CookiesSupported || FormsAuthentication.IsPathWithinAppRoot(context1, text1))
            {
                  FormsAuthentication.SetAuthCookie(userName, createPersistentCookie, strCookiePath);
                  text1 = FormsAuthentication.RemoveQueryStringVariableFromUrl(text1, FormsAuthentication.FormsCookieName);
                  if (!FormsAuthentication.CookiesSupported)
                  {
                        int num1 = text1.IndexOf("://", StringComparison.Ordinal);
                        if (num1 > 0)
                        {
                              num1 = text1.IndexOf('/', num1 + 3);
                              if (num1 > 0)
                              {
                                    text1 = text1.Substring(num1);
                              }
                        }
                  }
            }
            else
            {
                  if (!FormsAuthentication.EnableCrossAppRedirects)
                  {
                        throw new HttpException(SR.GetString("Can_not_issue_cookie_or_redirect"));
                  }
                  HttpCookie cookie1 = FormsAuthentication.GetAuthCookie(userName, createPersistentCookie, strCookiePath);
                  text1 = FormsAuthentication.RemoveQueryStringVariableFromUrl(text1, cookie1.Name);
                  if (text1.IndexOf('?') > 0)
                  {
                        string text2 = text1;
                        text1 = text2 + "&" + cookie1.Name + "=" + cookie1.Value;
                  }
                  else
                  {
                        string text3 = text1;
                        text1 = text3 + "?" + cookie1.Name + "=" + cookie1.Value;
                  }
            }
            context1.Response.Redirect(text1, false);
      }
}

 

 


Posted Oct 09 2006, 01:27 AM by Damir Dobric
Filed under:
developers.de is a .Net Community Blog powered by daenet GmbH.