Logging into FormsAuthentication With Email Address Causes Redirect To Not Work

66 Views Asked by At

I have an asp.net/c# app that is using MembershipProvider and FormsAuthentication to verify a user is in Active Directory, creates a cookie and redirects back to the page they came from.

If the user logs in with their userID (active directory cn), I pass it through Membership.ValidateUser and if successful, use FormsAuthentication.GetRedirectURL to create the cookie and redirect them back to their original page. This works great and completely as expected.

If, however, the user logs in with their e-mail address, I swap out their e-mail address for their userID by doing a lookup in my database. At that point the same exact code is used as described above, but for some reason the redirect fails and my site stays on the Login page.

As you can see in the code below, I've even tried swapping out the FormsAuthentication.GetRedirectURL with SetAuthCookie and Response.Redirect, and it works exactly as described above still.

I thought perhaps the length of the email address was causing the size of the cookie to be too large, but the size is under 500, not close to the 4096 limit.

Has anybody seen anything like this before? Any suggestions?

protected void Login_Click(object sender, CommandEventArgs e)
{
    myUtils mu = new myUtils();

    string userID = (LoginUser.FindControl("UserName") as TextBox).Text;
    string userPW = (LoginUser.FindControl("Password") as TextBox).Text;
    bool remMe = (LoginUser.FindControl("RememberMe") as CheckBox).Checked;

    MembershipProvider dp;

    //Search for @ in the value typed into the User ID box to see if they are logging
    //in using their e-mail address or User ID, and if they are using their email 
    //address get their ID and continue processing with it
    if (userID.IndexOf("@") > 0)
        userID = mu.getUserIDByEmailAddress(userID);

    dp = Membership.Providers["MyADMembershipProvider_AccountName"];

    //Verify if the user is in Active Directory or that Jimmy is debugging...
    //if ((dp.ValidateUser(userID, userPW)) || (HttpContext.Current.Request.IsLocal))
    if (
        (dp.ValidateUser(userID, userPW))       //User is in active directory
        || (mu.isTestAccount(userID, userPW))   //User is logging in with a test account
        ) {
        mu.getUserData(userID);
        FormsAuthentication.SetAuthCookie(userID, remMe);
        string url = FormsAuthentication.GetRedirectUrl(userID, false);
        Response.Redirect(url, false);
        //FormsAuthentication.RedirectFromLoginPage(userID, remMe);
    }
    else
    {
        ((Label)LoginUser.FindControl("accessDenied")).Visible = true;
        Response.Write("Invalid UserID and Password");
    }
}
1

There are 1 best solutions below

0
Jimmy Genslinger On

What a journey. As I mentioned, this was developed in asp.net. The Login.aspx page is using most of the original template elements, including the original asp:Login control:

   <asp:Login ID="LoginUser" runat="server" ViewStateMode="Disabled" RenderOuterTable="false">
        <LayoutTemplate>
            <p class="validation-summary-errors" runat="server">
                <asp:Literal runat="server" ID="FailureText" />
                <asp:Label ID="accessDenied" Font-Size="Large" ForeColor="red" CssClass="accessDeniedLabel" Visible="false" runat="server" >
                    Only JCPS employees that are teachers, administrators, counselors, or support staff may enter the <strong>"Staff Only"</strong> 
                    sections of the DMC. 
                </asp:Label>
            </p>
            <fieldset>
                <legend>Log in Form</legend>
                <ol>
                    <li>
                        <asp:Label ID="Label1" runat="server" AssociatedControlID="UserName">User name:</asp:Label>
                        <asp:TextBox runat="server" ID="username" />
                        <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="UserName" CssClass="field-validation-error" ErrorMessage="The user name field is required." />
                    </li>
                    <li>
                        <asp:Label ID="Label2" runat="server" AssociatedControlID="Password">Password</asp:Label>
                        <asp:TextBox runat="server" ID="Password" TextMode="Password" />
                        <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" ControlToValidate="Password" CssClass="field-validation-error" ErrorMessage="The password field is required." />
                    </li>
                    <li>
                        <asp:CheckBox runat="server" ID="RememberMe" />
                        <asp:Label runat="server" ID="cbRememberMe" AssociatedControlID="RememberMe" CssClass="checkbox">Remember me on this device?</asp:Label>
                    </li>
                </ol>

                <asp:Button ID="Button1" runat="server" CommandName="Login" Text="Log in" OnCommand="Login_Click" />
            </fieldset>
            &nbsp;
        </LayoutTemplate>
    </asp:Login>

After the user types in their credentials and hits the Login button, it's sent to the Login method. If user signs in with their userID, I verify against active directory, set the cookie and redirect. This works perfectly. If the user signs in with their e-mail address, in the original function I posted above I do a lookup for their userID and then continue down the path to verify they are in active directory. This was causing redirect to not work.

I've modified the procedure to include an extra line of code -- after getting the userID I'm changing the value in the LoginUser.UserName field to also be the userID -- before I was just letting the e-mail address ride because if you look at the procedure, I'm not using it anywhere else and didn't think it mattered. Apparently it does, changing the LoginUser.UserName field to match the userID allowed the redirect to start working. So apparently there is some behind the scenes magic where asp.net is matching up the ID being passed into the formsAuthentication ticket with the text that's actually sitting in the asp.net:Login control, and if they don't match up I guess just redirecting it back to the Login page.

Hopefully this will help others who are trying to get logins to accept either a userID or e-mail address...

    protected void Login_Click(object sender, CommandEventArgs e)
    {
        myUtils mu = new myUtils();

        string userID = LoginUser.UserName;
        string userPW = LoginUser.Password;
        bool remMe = (LoginUser.FindControl("RememberMe") as CheckBox).Checked;

        MembershipProvider dp;

        //Search for @ in the value typed into the User ID box to see if they are logging
        //in using their e-mail address or User ID, and if they are using their email 
        //address get their ID and continue processing with it
        if (userID.IndexOf("@") > 0)
        {
            userID = mu.getUserIDByEmailAddress(userID);
            LoginUser.UserName = userID;
        }

        dp = Membership.Providers["MyADMembershipProvider_AccountName"];

        //Verify the user is in Active Directory, it's a test account, or that Jimmy is debugging...
        if (
            (dp.ValidateUser(userID, userPW))           //User is in active directory
            || (mu.isTestAccount(userID, userPW)        //User is logging in with a test account
            || (HttpContext.Current.Request.IsLocal))   //Debugging, doesn't really matter...
        ) {
        mu.getUserData(userID);
        FormsAuthentication.RedirectFromLoginPage(userID, remMe);
    }
    else
    {
        ((Label)LoginUser.FindControl("accessDenied")).Visible = true;
        Response.Write("Invalid UserID and Password");
    }
}