ActiveDirectoryMembershipProvider.ValidateUser problem

R

Renaud Langis

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
 
G

gmurchison

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.
 
R

Renaud Langis

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();
}
}

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 said:
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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,905
Latest member
Kristy_Poole

Latest Threads

Top