Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

I recently had a requirment come accross my desk that required user passwords to expire after a certain period of time.  Upon expiration, the user is required to change their password and cannot perform any function until they have changed their password.  The existing system was already using the Membership and Role Providers with great success.  I wanted to implement this new requirement with minimal impact to the system.  I did a few quick Google searchs and did not find existing solutions (if I can't find something on Google within 60 seconds of searching then its not out there :)  I want to share my solution with the masses and get feedback on other implementaions currently out there.

To implement expiring passwords we need an additional data element associated with each user, the date/time at which their password will expire.  I didn't want to add a new table just to store this information.  I briefly considered using the Profile API (you may choose to modify my solution to do just that) but we weren't currently using it and I saw no reason to introduce that.  Looking at the Membership Provider I saw a lovely little field called "Comment" that was currenly unused...this would be perfect for our uses.

So, we have half the problem solved.  Anytime a user changes their password, we will set their password expiration date 30 days into the future and store this value in the Comment field of the Membership Provider.  Now, when a user has an expired password, how do we prevent them from doing anything until they change their password?

You have all been good developers and added a layer of abstraction to your pages by implementing a custom base page that all of your pages inherit from right?  If you haven't, shame on you and go do that before you finish the article.  If you have, then our implementation is pretty straight forward.  Simply override your OnInit method in your base page, check if the users password is expired, if so, redirect them to the change password page.  Since you are modifying your base page, if the user tries to navigate to any page other than change password, they will be immidiately redirected to the Change Password page.  Viola.

I actually took my implementation a tiny step further.  Whenever a user's password expires, I add them to a Role called "Must Change Password".  Our system provides an interface that allows administrator's to manage a users' roles.  So now an administrator can force a password change simply by adding the user(s) to this role.  Because roles can be cached via cookie on the user's machine, you do not need to access the database on every page to determine if a user's password has expired, simple check for the precense of the proper role.

You can download the goods here.

ExpiringMembershipUser.cs

using System;
using System.Configuration;
using System.Globalization;
using System.Web.Security;
 
namespace ExpiringPasswords
{
  public class ExpiringMembershipUser
  {
    private readonly MembershipUser _membershipUser;
    public static readonly string ExpiredPasswordRole;
    public static readonly int PasswordExpiresAfterDays;
 
    /// <summary>
    /// Initializes the <see cref="ExpiringMembershipUser"/> class.  Reads and 
    /// validates configuration values from the web.config file.
    /// </summary>
    static ExpiringMembershipUser()
    {
      // Expired Password Role
      ExpiredPasswordRole = ConfigurationManager.AppSettings["ExpiredPasswordRole"] ?? string.Empty;
      if (!Roles.RoleExists(ExpiredPasswordRole))
      {
        throw new ConfigurationErrorsException(
          "Please add '<add key=\"ExpiredPasswordRole\" value=\"{Your Role Here}\" />' " +
          "to the appSettings section of your web.config file and ensure you have created " +
          "the role with the ASP.Net Role Manager");
      }
 
      // Password Expires After Days
      string sPasswordExpiresAfterDays = ConfigurationManager.AppSettings["PasswordExpiresAfterDays"];
      if (string.IsNullOrEmpty(sPasswordExpiresAfterDays))
      {
        PasswordExpiresAfterDays = 30;
      }
      else
      {
        bool validValue = Int32.TryParse(sPasswordExpiresAfterDays, out PasswordExpiresAfterDays);
        if (!validValue || PasswordExpiresAfterDays <= 0)
        {
          throw new ConfigurationErrorsException(string.Format(
            "Invalid value '{0}' for appSetting 'PasswordExpiresAfterDays'",
            sPasswordExpiresAfterDays));
        }
      }
    }
 
    /// <summary>
    /// Initializes a new instance of the <see cref="ExpiringMembershipUser"/> class.
    /// </summary>
    /// <param name="membershipUser">The membership user.</param>
    public ExpiringMembershipUser(MembershipUser membershipUser)
    {
      if (membershipUser == null) throw new ArgumentNullException("membershipUser");
 
      _membershipUser = membershipUser;
    }
 
    /// <summary>
    /// Initializes a new instance of the <see cref="ExpiringMembershipUser"/> class.
    /// </summary>
    /// <param name="username">The username.</param>
    public ExpiringMembershipUser(string username)
    {
      _membershipUser = EnsureMembershipUser(username);
    }
 
    /// <summary>
    /// Gets or sets the password expiration date in UTC time.  
    /// When setting this value, it will be converted to UTC time.
    /// </summary>
    /// <value>The password expiration date.</value>
    public virtual DateTime PasswordExpiresOnUTC
    {
      get
      {
        string sPasswordExpiresOn = _membershipUser.Comment;
        DateTime dtPasswordExpiresOn = DateTime.Now.AddDays(PasswordExpiresAfterDays).ToUniversalTime();
 
        if (!DateTime.TryParse(sPasswordExpiresOn, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out dtPasswordExpiresOn))
        {
          _membershipUser.Comment = dtPasswordExpiresOn.ToString();
          Membership.UpdateUser(_membershipUser);
        }
 
        return dtPasswordExpiresOn;
      }
      set
      {
        _membershipUser.Comment = value.ToUniversalTime().ToString();
      }
    }
 
    /// <summary>
    /// Gets a value indicating whether [password expired].
    /// </summary>
    /// <value><c>true</c> if [password expired]; otherwise, <c>false</c>.</value>
    public virtual bool PasswordExpired
    {
      get
      {
        return PasswordExpiresOnUTC < DateTime.Now.ToUniversalTime();
      }
    }
 
    /// <summary>
    /// Expires the password.
    /// </summary>
    public virtual void ExpirePassword()
    {
      PasswordExpiresOnUTC = DateTime.Now;
      if (!Roles.IsUserInRole(_membershipUser.UserName, ExpiredPasswordRole))
      {
        Roles.AddUserToRole(_membershipUser.UserName, ExpiredPasswordRole);
      }
      Membership.UpdateUser(_membershipUser);
    }
 
    /// <summary>
    /// Unexpires the password.
    /// </summary>
    public virtual void UnexpirePassword()
    {
      PasswordExpiresOnUTC = DateTime.Now.AddDays(PasswordExpiresAfterDays);
      if (Roles.IsUserInRole(_membershipUser.UserName, ExpiredPasswordRole))
      {
        Roles.RemoveUserFromRole(_membershipUser.UserName, ExpiredPasswordRole);
      }
      Membership.UpdateUser(_membershipUser);
    }
 
    /// <summary>
    /// Expires the password if expired.
    /// </summary>
    /// <param name="username">The username.</param>
    public static void ExpirePasswordIfExpired(string username)
    {
      if (!IsPasswordExpired(username))
      {
        ExpiringMembershipUser expiringMembershipUser = new ExpiringMembershipUser(username);
        if (expiringMembershipUser.PasswordExpired)
        {
          expiringMembershipUser.ExpirePassword();
        }
      }
    }
 
    /// <summary>
    /// Determines whether the specified user's password is expired.
    /// </summary>
    /// <param name="username">The username.</param>
    /// <returns>
    ///   <c>true</c> if [is password expired] [the specified username]; otherwise, <c>false</c>.
    /// </returns>
    public static bool IsPasswordExpired(string username)
    {
      return Roles.IsUserInRole(username, ExpiredPasswordRole);
    }
 
    /// <summary>
    /// Unexpires the password.
    /// </summary>
    /// <param name="username">The username.</param>
    public static void UnexpirePassword(string username)
    {
      ExpiringMembershipUser expiringMembershipUser = new ExpiringMembershipUser(username);
      expiringMembershipUser.UnexpirePassword();
    }
 
    /// <summary>
    /// Ensures the membership user.
    /// </summary>
    /// <param name="username">The username.</param>
    /// <returns></returns>
    protected static MembershipUser EnsureMembershipUser(string username)
    {
      if (username == null) throw new ArgumentNullException("username");
 
      MembershipUser membershipUser = Membership.GetUser(username);
      if (membershipUser == null)
      {
        throw new InvalidOperationException(string.Format("No user exists for username '{0}'", username));
      }
 
      return membershipUser;
    }
  }
}

Example BasePage.cs

using System;
using System.Web;
using System.Web.UI;
 
namespace ExpiringPasswords
{
  public class BasePage : Page
  {
    protected virtual bool CheckForExpiredPassword
    {
      get { return true; }
    }
 
    protected override void OnInit(EventArgs e)
    {
      base.OnInit(e);
 
      if (CheckForExpiredPassword)
      {
        if (ExpiringMembershipUser.IsPasswordExpired(HttpContext.Current.User.Identity.Name))
        {
          Response.Redirect("ChangePassword.aspx?Message=Your password has expired and must be changed");
          Response.End();
        }
      }
    }
  }
}

Example Login.aspx.cs

using System;
 
namespace ExpiringPasswords
{
  public partial class Login : BasePage
  {
    protected override bool CheckForExpiredPassword
    {
      get { return false; }
    }
 
    protected override void OnInit(EventArgs e)
    {
      base.OnInit(e);
 
      if (!IsPostBack)
      {
        login.Focus();
      }
    }
 
    protected virtual void login_LoggedIn(object s, EventArgs e)
    {
      ExpiringMembershipUser.ExpirePasswordIfExpired(login.UserName);
    }
  }
}

Example ChangePassword.aspx.cs

using System;
 
namespace ExpiringPasswords
{
  public partial class ChangePassword : BasePage
  {
    protected override bool CheckForExpiredPassword
    {
      get { return false; }
    }
 
    protected override void OnInit(EventArgs e)
    {
      base.OnInit(e);
 
      string message = Request.QueryString["Message"];
      if (!string.IsNullOrEmpty(message))
      {
        changePassword.ChangePasswordTitleText = message;
      }
 
      if (!IsPostBack)
      {
        changePassword.Focus();
      }
    }
 
    protected virtual void changePassword_OnChangedPassword(object s, EventArgs e)
    {
      ExpiringMembershipUser.UnexpirePassword(changePassword.UserName);
    }
  }
}

posted @ Friday, January 05, 2007 6:00 PM


Print

Comments on this entry:

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by Willie at 1/6/2007 3:48 AM

Like always I'm thinking lazy. Couldn't you at login check to see if the password has expired? If so, then take to a screen to change it up? This would essentially combine the login with another call to the database to check the date. Right?

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by Bill Pierce at 1/6/2007 2:43 PM

You could definitely do that however what would prevent the user from navigating away from the change password screen?

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by Willie at 1/8/2007 6:05 PM

Essentially you have the one page that isn't secure (Default.aspx). Upon login, before authentication, you check the date the password had changed before. If so, bring up a panel or whatnot on the same page, and don't authenticate the user. This way, they won't be able to login until the change is made. You could do something similar when the password is about to change ... bring up a alert that says, "Your password will change in x amount of days. Wanna change it?"

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by Dave at 3/3/2008 7:43 AM

There's a LastPasswordChangedDate property of the MembershipUser, that could be used to evaluate the date which the password must expire

# re: Implement Expiring Previous Appointment in ASP.Net 2.0 using C#

Left by jassper at 3/24/2008 10:40 PM
Gravatar

Sir having a problem about my last project dis graduation,,,I'm getting tired to do this task....visual studio.net/aspnet 2.0 that I used to make a project but my problem is this.....I used formview to set an appointment having time of coarse with start and end so I display it in a gridview what I want Sir is to delete the previous appointments but I can't....Pls....Sir thank you I hope you to see your codes soon..

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by Tachyomatic at 6/20/2008 2:09 PM

Ever thought of doing it yourself?

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by Drickus at 11/19/2008 4:43 AM
Gravatar

I cannot use the comment field to save the date. So I tried using LastPasswordChangedDate but that field is readonly unlike the Comment field.
So when trying to change the code to set the date to the LastPasswordChangedDate it gives an error. Any suggestions?

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by Drickus at 11/20/2008 6:42 AM
Gravatar

Thanks. The code worked perfectly.

I had to use to profile api to store the Expiry Date (Comment field was already used).

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by rüya tabiri at 11/25/2008 12:30 AM
Gravatar

Thank you...

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by flas game at 12/2/2008 7:28 AM
Gravatar

thank you

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by Rae at 12/14/2008 8:31 PM
Gravatar

I need something similiar and am wondering if this would work. I create users and passwords for paid subscribers to news reports. When their subscription time is up, I need their password to expire so they can no longer log in with it unless they renew. Is this the ticket for me?

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by chat at 1/3/2009 12:30 PM
Gravatar

thank you

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by rüya tabirleri at 1/8/2009 4:26 PM
Gravatar

Thank You...

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by Corey at 1/27/2009 8:13 AM
Gravatar

Nice article. Your implementation works great. I was also able to add to your code to integrate storing and checking a history of passwords to prevent usage of the previous x number of passwords.

Thanks!

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by Rob at 1/28/2009 1:20 PM

The following MSDN code example shows a login page that indicates a password has expired after a specified number of days. If the LastPasswordChangedDate is earlier than the current date and time minus the number of days specified for the expiration of a password, then the user is directed to change his or her password.

http://msdn.microsoft.com/en-us/library/system.web.security.membershipuser.lastpasswordchangeddate.aspx

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by sohbet odalari at 3/7/2009 1:44 AM
Gravatar

thank you!

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by Sohbet at 3/7/2009 2:10 PM
Gravatar

thankss

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by Sohbet Odalari at 3/7/2009 2:35 PM
Gravatar

thanks you

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by Mirc at 3/7/2009 2:35 PM
Gravatar

thnks

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by chat at 3/13/2009 3:11 AM
Gravatar

thank you mujuka kokulu

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by ligtv izle at 3/18/2009 11:45 AM
Gravatar

thank you cano

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by Chat Odalari at 3/21/2009 10:03 AM
Gravatar

thanksss youuuuuuuu

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by Mynet at 3/23/2009 5:57 AM
Gravatar

thank you kankamm

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by maç izle at 3/28/2009 4:48 PM
Gravatar

thanki..

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by mirc yükle at 4/3/2009 4:25 AM
Gravatar

bedava indir

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by cet at 4/5/2009 3:29 AM
Gravatar

thank you admin good post

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by ligtv izle at 4/6/2009 3:27 AM
Gravatar

you are my desire..

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by chat at 4/11/2009 11:51 PM
Gravatar

thank you turkish chat34 !

# re:sohbet

Left by Sohbet at 4/27/2009 12:57 PM
Gravatar

Thank you good post

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by chat odalari at 4/28/2009 2:48 AM
Gravatar

thanki

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by TRsohbet at 5/3/2009 4:08 AM
Gravatar

Thank You

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by justin tv at 5/4/2009 5:50 AM
Gravatar

turkish justin tv..

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by Sohbet at 5/10/2009 10:59 AM
Gravatar

hallo i wish you succes on your job thanks a lot

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by Sohbet at 5/12/2009 5:13 PM
Gravatar

hallo i wish you verry succes operator

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by lig tv izle at 5/22/2009 7:31 AM
Gravatar

thanx you

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by chat yap at 5/24/2009 8:25 PM
Gravatar

thankss alll very nice a post...

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by çet at 6/15/2009 3:11 PM
Gravatar

thanks admin.

çet çetavatar yapma
oyular

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by sXe at 7/1/2009 5:21 PM
Gravatar

thank you admin saol

# re: Implement Expiring Passwords with Membership and Role Providers in ASP.Net 2.0

Left by tolga at 7/1/2009 5:33 PM
Gravatar

Thank you darsaım

Your comment:



 (will not be displayed)


 
 
 
Please add 4 and 8 and type the answer here:
 

Live Comment Preview:

 
«July»
SunMonTueWedThuFriSat
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678