Andy Narain
Andy Narain

Reputation: 55

The provided anti-forgery token was meant for user “{user}”, but the current user is “”

I am having problems with my anti-forgery token after a form has been submitted. I keep on getting this error message:

The provided anti-forgery token was meant for user “{user}”, but the current user is “”

The difference between what other have asked here and with mine is that it's say the current user is blank and the anti-forgery token is looking for a user. This makes no sense because when I checked HttpContext.Current.User.Identity.Name and Membership.GetUser().UserName, they do have the user anti-forgery token is looking for. This is not really making any sense.

NewRecordEntry.cshtml

<h2>New Record</h2>
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    <div id="new-record-entry">
        @Html.DropDownListFor(model => model.recordTypeID, Model.GetRecordTypeList())
    </div>

    <input type="submit" name="NewRecordEntry" id="continue" size="11" />
}

Controller

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult NewRecordEntry(FormCollection frm, NewRecordEntryViewModel nrevm)
    {
        TempData["NewRecordEntry"] = nrevm;
        return RedirectToAction("NewRecord", "FakeController");
    }    

Authentication Filter

public class FakeAuthenticationFilter : ActionFilterAttribute, IAuthenticationFilter
{
    public void OnAuthentication(AuthenticationContext filterContext)
    {
        // Get userData stored in a session. Workplace environment does not allow cookies
        UserData userData = (UserData) filterContext.HttpContext.Session[UserInfo.SessionUser];
        if (userData != null)
        {
            // Get identity and principal
            var identity = new GenericIdentity(UserInfo.SessionUser, "Forms");
            var principal = new FakePrincipal(identity);

            principal.UserData = userData;

            // Set the context user.
            HttpContext.Current.User = principal;
        }
        else
        {
            filterContext.Result = new RedirectResult("~/Login");
        }
    }

    public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
    {
    }
  }

Membership

public class FakeMembershipProvider : MembershipProvider
{
    public override bool ValidateUser(string username, string password)
    {
        // Check if this is a valid user.
        // The application sends the username and password to an LDAP DLL which
        //   reurns "Success" if it was a match.
        string result = LoginService.AuthenticateUser(username, password);
        if (result == "Success")
        {
             return true;
        }
        return false;
    }

    public override MembershipUser GetUser(string username, bool userIsOnline)
    {

        if (LoginService.UserData != null)
        {
            return new MembershipUser("FakeMembershipProvider", 
                username, LoginService.UserData.UserID,
                null, null, null, true, false,
                DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, 
                DateTime.MinValue, DateTime.MinValue);
        }
        return null;
    }
}

Login Post Controller

#region Login Post Controllers
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Login(FormCollection frm, LoginViewModel lvm, string returnUrl)
    {
        List<string> errorList = null;
        try
        {

            if (ModelState.IsValid)
            {
                string result = Services.ValidateLogin(lvm);

                if (result == "Success")
                {
                    if (Url.IsLocalUrl(returnUrl)
                        && returnUrl.Length > 1
                        && returnUrl.StartsWith("/")
                        && !returnUrl.StartsWith("//")
                        && !returnUrl.StartsWith("/\\"))
                    {
                        return base.Redirect(returnUrl);
                    }
                    return base.RedirectToAction("Index");
                }
                else
                {
                    TempData["errors"] = result;
                    ModelState.AddModelError("", result);
                }
            }
            else
            {
                errorList = Services.AddErrorMesagesToView(ModelState);
                TempData["errors"] = errorList;
            }
            //return base.RedirectToAction("Admin", new { section = section });
            ModelState.Clear();
            return View(new LoginViewModel());
        }
        catch (NullReferenceException ne)
        {
            if (ne.Source != null)
                Console.WriteLine("NullReferenceException source: {0}", ne.Source);
        }
        catch (HttpException he)
        {
            if (he.Source != null)
                Console.WriteLine("HttpException source: {0}", he.Source);
        }
        catch (Exception e)
        {
            if (e.Source != null)
                Console.WriteLine("Exception source: {0}", e.Source);
        }
        finally
        {
            ModelState.Clear();
        }

        return base.RedirectToAction("Login");
    }
    #endregion

ValidateLogin

    public static string ValidateLogin(LoginViewModel lvm)
    {
        /* string ldapServer = WebConfigurationManager.AppSettings["LDAPServer"];
        string result = Fakeauthenticate.Fakeauth.LdapAuth(lvm.Login, lvm.Password, ldapServer);
         */
        string result = null;
        const int INACTIVE = 1;

        FakeEntities db = new FakeEntities();

        // This is the only feasible way to call an SQL user-defined scalar function
        string sqlQuery = "SELECT [dbo].[Util_GetUserActivationStatus] ({0})";
        Object[] parameters = { lvm.Login };
        int status = db.Database.SqlQuery<int>(sqlQuery, parameters).FirstOrDefault();

        if (status == INACTIVE)
        {
            return "The user is currently locked out.";
        }

        if (Membership.ValidateUser(lvm.Login, lvm.Password))
        {
            HttpContext.Current.Session[UserInfo.SessionUser] = LoginBusiness.GetUserData(lvm.Login);
            HttpContext.Current.Session.Timeout = UserInfo.Timeout;

            result = "Success";
        }
        else
        {
            result = LoginBusiness.AuthenticateUser(lvm.Login, lvm.Password);
            if (result == "Login_Failure")
            {
                if (HttpContext.Current.Session[lvm.Login] == null)
                {
                    HttpContext.Current.Session[lvm.Login] = 1;
                }
                else
                {
                    uint loginFailures = (uint)HttpContext.Current.Session[lvm.Login];
                    HttpContext.Current.Session[lvm.Login] = ++loginFailures;

                    // If the maximum number of login failures have been reached, then lock the user out.
                    if ((uint)HttpContext.Current.Session[lvm.Login] == UserInfo.MAX_LOGIN_FAILURES)
                    {
                        db.Util_LockUserOut(lvm.Login);
                        return "Your account has been temporarily locked.";
                    }
                }
            }
        }

        return result;
    }

Upvotes: 3

Views: 5938

Answers (2)

mikaelrs
mikaelrs

Reputation: 335

The problem lies in your FakeAuthenticationFilter. I'm guessing you are using this filter on the controller action which loads the page. FakeAuthenticationFilter sets HttpContext.Current.User = new FakePrincipal(identity). This principal probably has a Name property, which is the user you see in the error message. .NET uses this Principal to generate the tokens on the page, but when you submit the tokens, the HttpContext will not have the same Principal.

A solution could be to put FakeAuthenticationFilter on your NewRecordEntry Action.

Upvotes: 0

Mihai Dinculescu
Mihai Dinculescu

Reputation: 20033

You should check if there is more than one @Html.AntiForgeryToken() in your form. If yes, remove all but one.

Also make sure that you are not submitting the form twice. This will mess up the AntiForgeryToken.

If you want to disable this check, add the following to your Application_Start method:

AntiForgeryConfig.SuppressIdentityHeuristicChecks = true

Upvotes: 1

Related Questions