2

I am trying to authenticate users who are logging into my web application from a log-in page. I was using this tutorial as a guide, which pretty much explained exactly what I'm hoping to do, but when I enter in the username and password, the validation is not working. Allow me to explain.

Here are relevant parts of my HTML. Nothing out of the ordinary:

<form id="form1" runat="server">
<div class=row>
<div class=col-xs-4>
    <div class="form-group">
<input id="txtUserName" type="text" runat="server">
<ASP:RequiredFieldValidator ControlToValidate="txtUserName"
       Display="Static" ErrorMessage="*" runat="server" 
       ID="vUserName" />
</div>
</div>

</div>
<div class=row>
<div class=col-xs-4>
<div class="form-group">
        <input id="txtUserPass" type="password" runat="server">
<ASP:RequiredFieldValidator ControlToValidate="txtUserPass"
      Display="Static" ErrorMessage="*" runat="server" 
      ID="vUserPass" />
</div>
</div>
</div>
<p><asp:Label ID="lblMsg" ForeColor="Red" runat="server" /></p>
<input type="submit" Value="Logon" runat="server" ID="cmdLogin"><p></p>
<ASP:CheckBox id="chkPersistCookie" runat="server" autopostback="false" />
</form>

The page contains a username and a button to login (and a checkbox for remembering cookies but I don't think that's relevant to my problem).

Here is the code behind:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.SqlClient;
using System.Web.Security;

namespace MRAApplication
{
    public partial class _1__0__0__0_LoginScreen : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            this.cmdLogin.ServerClick += new System.EventHandler(this.cmdLogin_ServerClick);
        }

        private bool ValidateUser(string userName, string passWord)
        {
            SqlConnection conn;
            SqlCommand cmd;
            string lookupPassword = null;

            // Check for invalid userName.
            // userName must not be null and must be between 1 and 15 characters.
            if ((null == userName) || (0 == userName.Length) || (userName.Length > 15))
            {
                System.Diagnostics.Trace.WriteLine("[ValidateUser] Input validation of userName failed.");
                return false;
            }

            // Check for invalid passWord.
            // passWord must not be null and must be between 1 and 25 characters.
            if ((null == passWord) || (0 == passWord.Length) || (passWord.Length > 25))
            {
                System.Diagnostics.Trace.WriteLine("[ValidateUser] Input validation of passWord failed.");
                return false;
            }

            try
            {
                // Consult with your SQL Server administrator for an appropriate connection
                // string to use to connect to your local SQL Server.
                conn = new SqlConnection("databaseConnect");
                conn.Open();

                // Create SqlCommand to select pwd field from users table given supplied userName.
                cmd = new SqlCommand("Select Password from Users where User=@userName", conn);
                cmd.Parameters.Add("@userName", System.Data.SqlDbType.VarChar, 25);
                cmd.Parameters["@userName"].Value = userName;

                // Execute command and fetch pwd field into lookupPassword string.
                lookupPassword = (string)cmd.ExecuteScalar();

                // Cleanup command and connection objects.
                cmd.Dispose();
                conn.Dispose();
            }
            catch (Exception ex)
            {
                // Add error handling here for debugging.
                // This error message should not be sent back to the caller.
                System.Diagnostics.Trace.WriteLine("[ValidateUser] Exception " + ex.Message);
            }

            // If no password found, return false.
            if (null == lookupPassword)
            {
                // You could write failed login attempts here to event log for additional security.
                return false;
            }

            // Compare lookupPassword and input passWord, using a case-sensitive comparison.
            return (0 == string.Compare(lookupPassword, passWord, false));

        }

        private void cmdLogin_ServerClick(object sender, System.EventArgs e)
        {
            if (ValidateUser(txtUserName.Value, txtUserPass.Value))
            {
                FormsAuthenticationTicket tkt;
                string cookiestr;
                HttpCookie ck;
                tkt = new FormsAuthenticationTicket(1, txtUserName.Value, DateTime.Now,
          DateTime.Now.AddMinutes(30), chkPersistCookie.Checked, "your custom data");
                cookiestr = FormsAuthentication.Encrypt(tkt);
                ck = new HttpCookie(FormsAuthentication.FormsCookieName, cookiestr);
                if (chkPersistCookie.Checked)
                    ck.Expires = tkt.Expiration;
                ck.Path = FormsAuthentication.FormsCookiePath;
                Response.Cookies.Add(ck);

                string strRedirect;
                strRedirect = Request["ReturnUrl"];
                if (strRedirect == null)
                    strRedirect = "default.aspx";
                Response.Redirect(strRedirect, true);
            }
            else
                Response.Redirect("1.0.0.0_LoginScreen.aspx", true);
        }
     }
    }

Now, I've tested my connection string and it works. It's connecting to a table in a SQL Server database which contains 3 columns of User, Password, and UserRole. Right now I just have a single test entry in the table, as shown here.

However, when I run the application and enter "test" into "txtUserName" and "password" into "txtUserPass" and click "submit" it is redirecting back to the login page, which means it is returning false for "if (ValidateUser(txtUserName.Value, txtUserPass.Value))".

If anybody could help me with this error I would appreciate it. Thank you for your help. :)

16
  • Are you using the ASP.NET <form>? Commented Sep 3, 2014 at 15:39
  • @Alexander Yes, I am, somehow it got cut out of the code I pasted here though. Edited for clarity. Commented Sep 3, 2014 at 15:41
  • 1
    @JaGo If you set a break point at if (ValidateUser(txtUse.., what is the return value - true or false? How do you create IPrincipal in AuthenticateRequest? Commented Sep 3, 2014 at 15:59
  • sounds like you need to learn how to use the debugger as well as how to setup Event handlers. I would look at some IsPostBack code and learn how to use that as well.. looks very sloppy Commented Sep 3, 2014 at 16:00
  • Try by adding FormsAuthentication.SetAuthCookie(userName,true) before redirecting Commented Sep 3, 2014 at 16:12

1 Answer 1

2

this is my first time trying to do authentication so I'm not totally sure how to get the return value by using the breakpoint.

You want to test with hard-coded username and password before connecting to SQL server.

protected void cmdLogin_ServerClick(object sender, System.EventArgs e)
{
    if (String.Equals(txtUserName.Value, "johndoe", 
        StringComparison.InvariantCultureIgnoreCase) &&
        String.Equals(txtUserPass.Value, "123456", 
        StringComparison.InvariantCultureIgnoreCase))
    {
        var roles = new[] {"Administrators"};

        var ticket = new FormsAuthenticationTicket(1, 
            txtUserName.Value,
            DateTime.Now,
            DateTime.Now.AddMinutes(30), 
            chkPersistCookie.Checked,
            string.Join(",", roles),
            FormsAuthentication.FormsCookiePath);

        var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, 
            FormsAuthentication.Encrypt(ticket));

        if (chkPersistCookie.Checked)
            cookie.Expires = ticket.Expiration;

        Response.Cookies.Add(cookie);

        string returnUrl = Request["ReturnUrl"];
        if (returnUrl == null)
            returnUrl = "default.aspx";
        Response.Redirect(returnUrl, true);
    }
    else
        Response.Redirect("1.0.0.0_LoginScreen.aspx", true);
}

How to create Principal Object

When an authenticated user is requested a page, you need to retrieve auth ticket from cookie, and create a Principal object.

// Global.asax.cs
public class Global : HttpApplication
{
    void Application_AuthenticateRequest(object sender, EventArgs e)
    {
        HttpCookie decryptedCookie =
            Context.Request.Cookies[FormsAuthentication.FormsCookieName];

        if (decryptedCookie != null)
        {
            FormsAuthenticationTicket ticket =
                FormsAuthentication.Decrypt(decryptedCookie.Value);

            string[] roles = ticket.UserData.Split(new[] {","}, 
                 StringSplitOptions.RemoveEmptyEntries);

            var identity = new GenericIdentity(ticket.Name);
            var principal = new GenericPrincipal(identity, roles);

            HttpContext.Current.User = principal;
            Thread.CurrentPrincipal = HttpContext.Current.User;
        }
    }
}

Usage

public partial class _Default : Page
{
    protected void Page_Load(object sender, EventArgs e)
    {    
        if (User.Identity.IsAuthenticated)
        {
            string username = User.Identity.Name;

            bool isAdministrator = User.IsInRole("Administrators");
        }
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for the detailed response. The authentication works when I'm using "johndoe", so that means the problem must be with getting the info from SQL Server, right?
I gotta say yes. Connecting to SQL Server is different animal; a lot of things can go wrong easily. So take your time and study how to debug web application first. Otherwise, you'll get frustrated easily. Good luck!
Okay, cool. I was able to populate a table with data from the same database and same connectionstring elsewhere in my application, so I'm guessing it must be something I'm doing wrong within "cmdLogin_ServerClick". I'll look into what the issue is. You've been very helpful, I owe you one, Win.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.