Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SimpleMembership password reset hyperlink 401 redirects even with AllowAnonymous

I'm attempting to migrate my MVC4 application from ASP.NET Membership to the new SimpleMembership and have run into a snag with password resets. In my Login view, I have "Forgot Password" hyperlink that does an AJAX post to an action that sends an email with a reset password hyperlink (based loosely on MSDN guidelines):

[HttpPost]
[AllowAnonymous]
public ActionResult ForgotPassword(string userName)
{
    //get the user from database, validate it exists, etc.
    var token = WebSecurity.GeneratePasswordResetToken(userName);
    var resetLink = "<a href='" + Url.Action("ResetPassword", "Account", new {un = userName, rt = token}, "http") + "'>Reset Password</a>";
    //send the email
    return Json(new {result = "Email sent."});
}

This works fine, but for some reason when I attempt to use the Reset Password link, I get redirected to the Login screen and Fiddler shows a 401-Unauthorized. I've tried copy/pasting the link into the browser address bar as well as creating a junk HTML file with the anchor tag in it, but the result is still a 401. Here's the Reset Password action (also in the Account controller from the MVC4 template):

[HttpPost]
[AllowAnonymous]
public ActionResult ResetPassword(string un, string rt)
{
    var model = new ResetPasswordViewModel {UserName = un, ResetToken = rt};
    return View(model);
}

I've tried removing the HttpPost attribute as well, but that also yields a 401. What am I missing here?

UPDATE
Thanks to Steve's comment, I fully-qualified the HttpPost attribute and have now realized that it's attempting to post to an area instead of straight to the root Account controller. Using RouteDebugger, I see a resource not found error:

Matched Route: {controller}/{action}/{id}
Generated URL: /SiteRoot/Reports/Account/ResetPassword?un=whatever&rt=removedForSecurity using the route "Reports/{controller}/{action}/{id}"

Note that it is looking in the Reports area. So, I changed my anchor tag construction in the ForgotPassword action, adding the Area specification in the route values object, as follows:

var resetLink = "<a href='" + Url.Action("ResetPassword", "Account", new {un = userName, rt = token, Area = ""}, "http") + "'>Reset Password</a>";

But it's still attempting to use the Reports area. How can I assure that the anchor tag in the email will direct to the site root instead of an area?

UPDATE 2
I removed the HttpPost attribute, and am now getting the original 401 redirect.

UPDATE 3 ResetPassword view code:

@model Whatever.Web.Models.ResetPasswordViewModel
@{
    ViewBag.Title = "Reset Password";
}
@using (Html.BeginForm())
{
    <fieldset>
        <legend>Reset Password</legend>
        <table>
            <tr>
                <td>User name:</td>
                <td>@Html.TextBoxFor(m => m.UserName, new { @class="disabled-textbox", @readonly="readonly", autocomplete="off" })</td>
                <td></td>
            </tr>
            <tr>
                <td>New Password:</td>
                <td>@Html.PasswordFor(m => m.NewPassword, new { id = "resetPasswordNewPassword" })</td>
                <td></td>
            </tr>
            <tr>
                <td>Confirm New Password:</td>
                <td>@Html.Password("resetPasswordConfirmPassword", "", new { id = "resetPasswordConfirmPassword"})</td>
                <td>
                    <div id="passwordsMatch"></div>
                </td>
            </tr>
        </table>
        <input type="submit" id="submitButton" value="Submit" disabled="disabled"/>
        <div id="resetPasswordResultDiv"></div>
    </fieldset>
}
<script type="text/javascript">
    $(document).ready(function() {
        $("#resetPasswordNewPassword, #resetPasswordConfirmPassword").keyup(function() {
            if ($("#resetPasswordNewPassword").val().length > 0 && $("#resetPasswordConfirmPassword").val().length > 0 && $("#resetPasswordNewPassword").val() != $("#resetPasswordConfirmPassword").val()) {
                if ($("#resetPasswordNewPassword").val() != $("#resetPasswordConfirmPassword").val()) {
                    $("#passwordsMatch").html('<span style="color: red; font-weight: bold;>Passwords do not match</span>');
                    $("#submitButton").attr('disabled', true);
                } else {
                    $("#submitButton").removeAttr('disabled');
                }
            } else {
                $("#passwordsMatch").html('');
                $("#submitButton").attr('disabled', true);
            }
        });
    });
</script>

UPDATE 4
I tried adding another action method to the Account controller that results in a "hello world" style view. Added [AllowAnonymous] attribute, of course. This method also results in a 401 redirect to login.

like image 649
AJ. Avatar asked Nov 04 '22 06:11

AJ.


1 Answers

I don't see any problems with the way you've got this set up. There has to be something else going on here. Check your _Layout.cshmtl file and assure that you don't have ANY calls to other actions that could be causing the 401.

This person had a similar problem: https://stackoverflow.com/a/11046666/199913

like image 165
Dean Avatar answered Nov 15 '22 12:11

Dean