ASP.NET membership password expiration

75

Solution 1

Further to csgero's answer, I found that you don't need to explicitly add an event handler for this event in ASP.Net 2.0 (3.5).

You can simply create the following method in global.asax and it gets wired up for you:

void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
    if (this.User.Identity.IsAuthenticated)
    {
        // get user
        MembershipUser user = Membership.GetUser();

        // has their password expired?
        if (user != null
            && user.LastPasswordChangedDate.Date.AddDays(90) < DateTime.Now.Date
            && !Request.Path.EndsWith("/Account/ChangePassword.aspx"))
        {
            Server.Transfer("~/ChangePassword.aspx");
        }
    }
}

Solution 2

You could add an event handler for the HttpApplication.PostAuthenticateRequest event in global.asax and handle the redirection there.

Solution 3

Further to Andrew's answer, I found you need to check that the user is not already on the change password page, or they will never be able to actually change their password, and hence never leave the change password site:

void Application_PostAuthenticateRequest(object sender, EventArgs e)
    {
        if (this.User.Identity.IsAuthenticated)
        {
            // get user 
            MembershipUser user = Membership.GetUser();

            // has their password expired? 
            if (user != null
                && user.LastPasswordChangedDate.AddMinutes(30) < DateTime.Now
                && !Request.Path.EndsWith("/Account/ChangePassword.aspx"))
            {
                Server.Transfer("~/Account/ChangePassword.aspx");
            }
        }
    } 

Solution 4

Just implemented this in about an hour, no need to modify your base page. Heres what you have to do:

  1. Respond to the LoggingIn event of the membership control

  2. Find the user in the membership database and get LastPasswordChangedDate

  3. Using a TimeSpan, compare this with the current date and decide if the password was last changed more than the requisite number of days ago. I get this value from web.config

  4. If expired, redirect to the ChangePassword screen

Solution 5

I got here looking for a solution to this but my current technology is ASP.NET MVC. So to help others: you can extend the AuthorizeAttribute, and override OnAuthorization method, like this:

public class ExpiredPasswordAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        IPrincipal user = filterContext.HttpContext.User;

        if(user != null && user.Identity.IsAuthenticated)
        {
            MembershipUser membershipUser = Membership.GetUser();

            if (PasswordExpired) // Your logic to check if password is expired...
            {
                filterContext.HttpContext.Response.Redirect(
                    string.Format("~/{0}/{1}?{2}", MVC.SGAccount.Name, MVC.SGAccount.ActionNames.ChangePassword,
                    "reason=expired"));

            }
        }

        base.OnAuthorization(filterContext);
    }
}

Note: I use T4MVC to retrieve the Controller and Action names in the code above.

Mark all controllers with this attribute except "AccountController". Doing so no user with an expired password will be able to surf the site.

Here's a post I did on the subject with some bonus points:

User Password Expired filter attribute in ASP.NET MVC

Share:
75

Related videos on Youtube

Mahdi Salah
Author by

Mahdi Salah

Updated on July 09, 2022

Comments

  • Mahdi Salah
    Mahdi Salah almost 2 years

    Is there a way to extend the supported entities in the GenericPathRoute.cs GetRouteData(...) from my custom plugin so that I can add generic url support for my custom entity?

    //process URL
                switch (urlRecord.EntityName.ToLowerInvariant())
                {
                    case "product":
                        {
                            data.Values["controller"] = "Catalog";
                            data.Values["action"] = "Product";
                            data.Values["productid"] = urlRecord.EntityId;
                            data.Values["SeName"] = urlRecord.Slug;
                        }
                        break;
                     ...
                    case "MyCustomEntity":
    
  • technophile
    technophile over 15 years
    That's what I'd do, combined with using the LastPasswordChangedDate property of the Membership Provider to determine when it expires.
  • Brett
    Brett almost 13 years
    This will not catch users who have an existing auth ticket ("remember me"). csgero's solution is correct.
  • Andrew
    Andrew over 12 years
    Yes, if they are currently authenticated I would say that is not a big issue, unless you make your cookies valid to infinity. Perhaps if you detect that they are already logged in, and expired, then just set the cookie to expire in 20 minutes or so, each time. Then, when they come back, they'll have to change it.
  • Adam Tuliper
    Adam Tuliper over 12 years
    The issue with checking in PostAuth also is a ton of added system activity for every single request. As long as your tickets expire fairly often there shouldn't be much of an issue, OR you simply run the PostAuth code for +1 day beyond your timeout time. This ensures anyone who hits the site with a valid forms auth ticket gets checked. Then if they don't login at all during that time, the forms auth tickets expire and LogginIn even can be used. After +1 day beyond the ticket expire time you can then remove the PostAuth event. Also you'll want to check upon login
  • Adam Tuliper
    Adam Tuliper over 12 years
    and force their ticket to expire at a MAX when their password expires. This prevents those cases of people expiring before their token is up.
  • joshschreuder
    joshschreuder about 11 years
    Please note Ben Rethmeier's fix below (stackoverflow.com/a/9879682/324817) so that it is possible to change password on the change password screen.
  • Andrew
    Andrew about 11 years
    Thanks @shrodes - I've updated my answer to include Ben Rethmeier's fix :o)
  • philw
    philw about 9 years
    This will not catch users who simply navigate away from the change password screen. They have just authenticated, they're good to go. That is why you have to check each request, inelegant though it is.
  • user2379087
    user2379087 over 8 years
    you handle this event : EngineContext.Current.Resolve<IEventPublisher>() .Publish(new CustomUrlRecordEntityNameRequested(data, urlRecord));