.NET Active Directory Password Expiration on Windows 2008
Searched SO and Everywhere else, including the .net developers guide to directory services programming book - no luck.
I am trying to create a simple password reset web page that allows the user to change their password. The change password portion of the code is working fine. For the users I would also like to display when their current passwor开发者_运维知识库d will expire next.
Using the sample code from the book mentioned above I was able to get all of the code setup however, the attribute that is returned is always equal to Long.MinValue and hence cannot be inverted to a positive number, plus this means it did not find the proper domain setting.
Does anyone have sample code or references for getting the password expiration in a Windows 2008 or R2 domain environment where password policies can be different for each user?
Updated to include code
Constructor that gets the policy object:
public PasswordExpires()
{
//Get Password Expiration
Domain domain = Domain.GetCurrentDomain();
DirectoryEntry root = domain.GetDirectoryEntry();
using (domain)
using (root)
{
this.policy = new DomainPolicy(root);
}
}
Domain Policy Constructor:
public DomainPolicy(DirectoryEntry domainRoot)
{
string[] policyAttributes = new string[] {
"maxPwdAge", "minPwdAge", "minPwdLength",
"lockoutDuration", "lockOutObservationWindow",
"lockoutThreshold", "pwdProperties",
"pwdHistoryLength", "objectClass",
"distinguishedName"
};
//we take advantage of the marshaling with
//DirectorySearcher for LargeInteger values...
DirectorySearcher ds = new DirectorySearcher(
domainRoot,
"(objectClass=domainDNS)",
policyAttributes,
SearchScope.Base
);
SearchResult result = ds.FindOne();
//do some quick validation...
if (result == null)
{
throw new ArgumentException(
"domainRoot is not a domainDNS object."
);
}
this.attribs = result.Properties;
}
Call this method to get the password expiration:
public TimeSpan MaxPasswordAge
{
get
{
string val = "maxPwdAge";
if (this.attribs.Contains(val))
{
long ticks = GetAbsValue(
this.attribs[val][0]
);
if (ticks > 0)
return TimeSpan.FromTicks(ticks);
}
return TimeSpan.MaxValue;
}
}
Code fails here because it cannot convert Long.MinValue, which it should not be in the first place
private long GetAbsValue(object longInt)
{
return Math.Abs((long)longInt);
}
Here is the debugger output and values. According to the MSDN Site the overflow exception is caused from the minvalue. My numbers match the examples for minvalue.
Screenshot http://www.brentpabst.com/capture.png
Password expiration times are stored such that if lastPwdSet - maxPwdAge < DateTime.UtcNow
is true, then your password is expired. So if you set your password a week ago, but the password will expire in 10 days, the left side will be (DateTime.UtcNow - 7) - (-10)
, or DateTime.UtcNow - 7 + 10
, or DateTime.UtcNow + 3
, which is not less than DateTime.UtcNow
, so your password won't be expired.
This means that setting maxPwdAge to long.MinValue will effectively give you thousands of years before your password expires. So if you are getting long.MinValue
, your policy says that passwords won't expire. You should just look for that value and treat it properly, possibly like this:
private long GetAbsValue(object longInt) // poorly named
{
long val = (long)longInt;
if (val == long.MinValue)
return long.MaxValue;
return Math.Abs((long)longInt);
}
Also, I should point out that the values are stored in 100-nanosecond increments, so you should expect values in the billions.
精彩评论