ActiveDirectoryMembershipProvider.ValidateUser problem

Discussion in 'ASP .Net Security' started by Renaud Langis, Oct 20, 2006.

  1. Hello,

    I am using the ActiveDirectoryMembershipProvider class to access active
    directory in an asp.net application. It is working well appart from one
    thing. When a user's password has expired, i can't validate if the password
    entered is correct before allowing the user to change it.

    According to the following sample
    code(http://msdn2.microsoft.com/en-us/li...y.membershipuser.lastpasswordchangeddate.aspx), it should work. But it doesn't.

    Question #1 : I am using active directory on a windows 2003 server with an
    asp.net 2.0 application. Should ValidateUser work if the user's password has
    expired? If so, is there a particular setup necessary to make it work?

    Question #2 : To overcome that problem, i added some code to unexpire the
    password prior to validation using the pwdLastSet flag. This works fine on
    all platforms except for 1 server on which there is a delay problem. Setting
    pwdLastSet seems to be immediate but the ValidateUser method returns false
    for around 10 seconds after setting the pwdLastSet flag. Is there a way to
    force a refresh before using ValidateUser?

    Thanks for any help
     
    Renaud Langis, Oct 20, 2006
    #1
    1. Advertising

  2. Renaud Langis

    gmurchison Guest

    Renaud,

    Was having exactly the same problems as yourself... and found the
    following solution this morning!

    Using the ActiveDirectoryMembershipProvider you can check
    MembershipUser.LastPasswordChangeDate prior to Validating the user, so
    pretty much it's a code/logic reorg exercise [from the link provided by
    you] :

    as an example :

    protected void Login_OnClick(object sender, EventArgs e)
    {
    MembershipUser user = Membership.GetUser(UsernameTextbox.Text);
    if (user == null)
    {
    Msg.Text = "Invalid user name. Please check your user name
    and try again.";
    return;
    }

    if (LoginHelper.PasswordRequiresChange(user))
    {
    Msg.Text = "Your password has expired. Please change your
    password to a new value.";
    UsernameLabel.Text = UsernameTextbox.Text;
    ChangePasswordPanel.Visible = true;
    LoginPanel.Visible = false;
    return;
    }

    if (Membership.ValidateUser(UsernameTextbox.Text,
    PasswordTextbox.Text))
    {

    FormsAuthentication.RedirectFromLoginPage(UsernameTextbox.Text, false);
    }
    else
    {
    Msg.Text = "Invalid password. Please check your password
    and try again.";
    }
    }
    protected void ChangePassword_OnClick(object sender, EventArgs e)
    {
    MembershipUser user = Membership.GetUser(UsernameLabel.Text);
    if (user == null)
    {
    Msg.Text = "Invalid user name. Please check your user name
    and try again.";
    return;
    }

    if (user.ChangePassword(OldPasswordTextbox.Text,
    NewPasswordTextbox.Text))
    {
    Msg.Text = "Password changed.";
    ChangePasswordPanel.Visible = false;
    LoginPanel.Visible = true;
    }
    else
    {
    Msg.Text = "Failed to change password.";
    }
    }

    public class LoginHelper
    {

    public static readonly int MAX_PASSWORD_AGE =
    GetMaxPasswordAge().Days;

    private static TimeSpan GetMaxPasswordAge()
    {
    using (Domain d = Domain.GetCurrentDomain())
    using (DirectoryEntry domain = d.GetDirectoryEntry())
    {
    DirectorySearcher ds = new DirectorySearcher(
    domain,
    "(objectClass=*)",
    null,
    SearchScope.Base
    );
    SearchResult sr = ds.FindOne();
    TimeSpan maxPwdAge = TimeSpan.MinValue;
    if (sr.Properties.Contains("maxPwdAge"))
    maxPwdAge =
    TimeSpan.FromTicks((long)sr.Properties["maxPwdAge"][0]);
    return maxPwdAge.Duration();
    }
    }

    public static bool PasswordRequiresChange(MembershipUser user)
    {
    DateTime passwordLastChanged = user.LastPasswordChangedDate;

    return DateTime.Now >
    user.LastPasswordChangedDate.AddDays(MAX_PASSWORD_AGE);
    }
    }

    HTH,
    Gary.

    Renaud Langis wrote:
    > Hello,
    >
    > I am using the ActiveDirectoryMembershipProvider class to access active
    > directory in an asp.net application. It is working well appart from one
    > thing. When a user's password has expired, i can't validate if the password
    > entered is correct before allowing the user to change it.
    >
    > According to the following sample
    > code(http://msdn2.microsoft.com/en-us/li...y.membershipuser.lastpasswordchangeddate.aspx), it should work. But it doesn't.
    >
    > Question #1 : I am using active directory on a windows 2003 server with an
    > asp.net 2.0 application. Should ValidateUser work if the user's password has
    > expired? If so, is there a particular setup necessary to make it work?
    >
    > Question #2 : To overcome that problem, i added some code to unexpire the
    > password prior to validation using the pwdLastSet flag. This works fine on
    > all platforms except for 1 server on which there is a delay problem. Setting
    > pwdLastSet seems to be immediate but the ValidateUser method returns false
    > for around 10 seconds after setting the pwdLastSet flag. Is there a way to
    > force a refresh before using ValidateUser?
    >
    > Thanks for any help
     
    gmurchison, Oct 25, 2006
    #2
    1. Advertising

  3. Thanks for your reply.

    The problem i have with this solution is that i don't want to redirect the
    user to a ChangePassword page if he did not provide the correct password.

    Of course that doesn't cause any security problem since user.ChangePassword
    will return false if the old password provided is incorrect. It's only a
    functionnal problem.

    Presently, i'm doing the following:

    bool isExpired = PasswordRequiresChange(userId);
    bool isValid;
    if(isExpired)
    {
    activatePassword(userId);
    }

    isValid = Membership.ValidateUser(userId, password);

    if(isExpired)
    {
    expirePassword(userId);
    }

    return isValid;

    public void activatePassword(string userId)
    {
    DirectoryEntry de = getAdUser(userId);
    SetProperty(de, "pwdLastSet", -1);
    de.CommitChanges();
    }


    public void expirePassword(string userId)
    {
    DirectoryEntry de = getAdUser(userId);
    SetProperty(de, "pwdLastSet", 0);
    de.CommitChanges();
    }

    public DirectoryEntry getAdUser(string userId)
    {
    {
    DirectorySearcher ds = new DirectorySearcher()
    ds.SearchRoot = getRoot()
    ds.Filter = "(&(objectClass=user)(saMAccountName=" + userId + "))"
    ds.SearchScope = SearchScope.Subtree
    SearchResult sr = ds.FindOne();
    return sr.GetDirectoryEntry();
    }
    }

    On some servers, there is a delay problem between activatePassword and
    ValidateUser.


    "gmurchison" wrote:

    > Renaud,
    >
    > Was having exactly the same problems as yourself... and found the
    > following solution this morning!
    >
    > Using the ActiveDirectoryMembershipProvider you can check
    > MembershipUser.LastPasswordChangeDate prior to Validating the user, so
    > pretty much it's a code/logic reorg exercise [from the link provided by
    > you] :
    >
    > as an example :
    >
    > protected void Login_OnClick(object sender, EventArgs e)
    > {
    > MembershipUser user = Membership.GetUser(UsernameTextbox.Text);
    > if (user == null)
    > {
    > Msg.Text = "Invalid user name. Please check your user name
    > and try again.";
    > return;
    > }
    >
    > if (LoginHelper.PasswordRequiresChange(user))
    > {
    > Msg.Text = "Your password has expired. Please change your
    > password to a new value.";
    > UsernameLabel.Text = UsernameTextbox.Text;
    > ChangePasswordPanel.Visible = true;
    > LoginPanel.Visible = false;
    > return;
    > }
    >
    > if (Membership.ValidateUser(UsernameTextbox.Text,
    > PasswordTextbox.Text))
    > {
    >
    > FormsAuthentication.RedirectFromLoginPage(UsernameTextbox.Text, false);
    > }
    > else
    > {
    > Msg.Text = "Invalid password. Please check your password
    > and try again.";
    > }
    > }
    > protected void ChangePassword_OnClick(object sender, EventArgs e)
    > {
    > MembershipUser user = Membership.GetUser(UsernameLabel.Text);
    > if (user == null)
    > {
    > Msg.Text = "Invalid user name. Please check your user name
    > and try again.";
    > return;
    > }
    >
    > if (user.ChangePassword(OldPasswordTextbox.Text,
    > NewPasswordTextbox.Text))
    > {
    > Msg.Text = "Password changed.";
    > ChangePasswordPanel.Visible = false;
    > LoginPanel.Visible = true;
    > }
    > else
    > {
    > Msg.Text = "Failed to change password.";
    > }
    > }
    >
    > public class LoginHelper
    > {
    >
    > public static readonly int MAX_PASSWORD_AGE =
    > GetMaxPasswordAge().Days;
    >
    > private static TimeSpan GetMaxPasswordAge()
    > {
    > using (Domain d = Domain.GetCurrentDomain())
    > using (DirectoryEntry domain = d.GetDirectoryEntry())
    > {
    > DirectorySearcher ds = new DirectorySearcher(
    > domain,
    > "(objectClass=*)",
    > null,
    > SearchScope.Base
    > );
    > SearchResult sr = ds.FindOne();
    > TimeSpan maxPwdAge = TimeSpan.MinValue;
    > if (sr.Properties.Contains("maxPwdAge"))
    > maxPwdAge =
    > TimeSpan.FromTicks((long)sr.Properties["maxPwdAge"][0]);
    > return maxPwdAge.Duration();
    > }
    > }
    >
    > public static bool PasswordRequiresChange(MembershipUser user)
    > {
    > DateTime passwordLastChanged = user.LastPasswordChangedDate;
    >
    > return DateTime.Now >
    > user.LastPasswordChangedDate.AddDays(MAX_PASSWORD_AGE);
    > }
    > }
    >
    > HTH,
    > Gary.
    >
    > Renaud Langis wrote:
    > > Hello,
    > >
    > > I am using the ActiveDirectoryMembershipProvider class to access active
    > > directory in an asp.net application. It is working well appart from one
    > > thing. When a user's password has expired, i can't validate if the password
    > > entered is correct before allowing the user to change it.
    > >
    > > According to the following sample
    > > code(http://msdn2.microsoft.com/en-us/li...y.membershipuser.lastpasswordchangeddate.aspx), it should work. But it doesn't.
    > >
    > > Question #1 : I am using active directory on a windows 2003 server with an
    > > asp.net 2.0 application. Should ValidateUser work if the user's password has
    > > expired? If so, is there a particular setup necessary to make it work?
    > >
    > > Question #2 : To overcome that problem, i added some code to unexpire the
    > > password prior to validation using the pwdLastSet flag. This works fine on
    > > all platforms except for 1 server on which there is a delay problem. Setting
    > > pwdLastSet seems to be immediate but the ValidateUser method returns false
    > > for around 10 seconds after setting the pwdLastSet flag. Is there a way to
    > > force a refresh before using ValidateUser?
    > >
    > > Thanks for any help

    >
    >
     
    Renaud Langis, Oct 25, 2006
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    0
    Views:
    493
  2. Replies:
    0
    Views:
    526
  3. John Devlon

    Membership.ValidateUser always false

    John Devlon, Apr 17, 2008, in forum: ASP .Net
    Replies:
    0
    Views:
    2,588
    John Devlon
    Apr 17, 2008
  4. Craig Wagner

    ActiveDirectoryMembershipProvider & ValidateUser

    Craig Wagner, Feb 27, 2007, in forum: ASP .Net Security
    Replies:
    12
    Views:
    682
    Joe Kaplan
    May 5, 2007
  5. Replies:
    2
    Views:
    790
Loading...

Share This Page