Please help me! Need "isPasswordExpired" for AD (I'm *CLOSE*)...
Hi,
I'm trying to implement a method that, given the Active Directory attributes 'pwdLastSet' (from a user) and 'maxPwdAge' (from the domainDNS) will return 'true' or 'false'.
I have written code that (I think) successfully retrieves pwdLastSet and maxPwdAge values (both type long) from AD, but I'm going nuts trying to figure out how to determine if the password has expired from these values.
To be more specific, using information from various source, including here, I'm actually able to write such a method, but it only seems to determine the password expired status on the basis of the DAY, and I need to be able to essentially mimic AD's password expired status (e.g., down to the second or millisecond).
Here's what I have so far (which only triggers 'password expired' on the day:
GregorianCalendar Win32Epoch = new GregorianCalendar(1601,Calendar.JANUARY,1);
Date Win32EpochDate = Win32Epoch.getTime();
GregorianCalendar Today = new GregorianCalendar();
Date TodaysDate = Today.getTime();
long TimeSinceWin32Epoch = 10000 * (TodaysDate.getTime() - Win32EpochDate.getTime());
if ( lPwdLastSet <= (TimeSinceWin32Epoch + maxPwdAge))
{
System.out.println("isPwdExpired(): ********* EXPIRED ************** - returning 'true'");
return true;
}
else
{
System.out.println("isPwdExpired(): ********* NOT EXPIRED ************** - returning 'false'");
return false;
}
Maybe I've just been staring at this code too long :(, but I just can't get this to work correctly :(!!!
Can anyone help me get this working correctly?
Thanks in advance!!
Jim
[1713 byte] By [
jimcpl1a] at [2007-10-3 2:58:46]

hope this helps
import java.util.Calendar;
public class CompareDates
{
public static void main(String args[])
{
Calendar today = Calendar.getInstance();
Calendar lastPwdSetDate = Calendar.getInstance();
lastPwdSetDate.setTimeInMillis(89963);
if(today.after(lastPwdSetDate))
System.out.println("lastPwdSetDate is before today");
else
System.out.println("lastPwdSetDate is after today");
}
}
prassoon,
Actually, I think that the original code that I posted worked ok.
What happened, I think, was that I was testing by changing the system date back and forth, and while doing that, I had edited one of the .java files.
So, when I set the system date back, and ran javac to compile the "new" code, i think that it didn't actually compile the updated source, since the file date was "in the future" :)...
Jim
Hi,
I'm still having problems with this :(. At this point, I don't understand what's going on, because the calculation for 'now' always seems to come up less than the 'pwdLastSet'.
For example, I just reset my password in AD. I then ran my program, and here's what I got:
lPwdLastSet = 128014798644537904
TimeSinceWin32Epoch = 128014619454130000
maxPwdAge = -37108517437440
I have a feeling that my calculation for now/TimeSinceWin32Epoch incorrect. Here's the code:
GregorianCalendar Win32Epoch = new GregorianCalendar(1601,Calendar.JANUARY,1);
Date Win32EpochDate = Win32Epoch.getTime();
GregorianCalendar Today = new GregorianCalendar();
Date TodaysDate = Today.getTime();
long TimeSinceWin32Epoch = 10000 * (TodaysDate.getTime() - Win32EpochDate.getTime());
FYI, 'lPwdLastSet' is directly retrieved from AD, as is 'maxPwdAge'.
Can anyone tell me what I'm doing wrong here?
Thanks in advance!
Jim
If you shift your time base to Java epoch and use milliseconds, then you have:
long now = System.currentTimeMillis();
lPwdLastSet -= 11644473600000; // subtract the difference in milliseconds
// between Windows and Java epoch.
Now you should be able to perform your calculations.
Hope this helps
zigoal,
Are you saying that I don't any of that code using Calendar, etc.?
So, following your code, I can just:
long now = System.currentTimeMillis();
lPwdLastSet -= 11644473600000;
if ((now - lPwdLastSet) >= maxPwdAge)
{
.... password expired....
}
else
{
.... password not expired....
}
Will just that work?
Pls advise, and thanks!! I've really been struggling with trying all kinds of different ways to do this :(...
Jim
> long now = System.currentTimeMillis();
>
> PwdLastSet -= 11644473600000;
>
> if ((now - lPwdLastSet) >= maxPwdAge)
>{
> .... password expired....
>}
> else
>{
> .... password not expired....
>}
> Will just that work?
Yes, provided that:
- lPwdLastSet contains the time in milliseconds, relative to the Windows epoch (which then you translate to Java epoch), when the user changed his/her password last time.
- maxPwdAge contains the password expiration period in milliseconds (this is obviously independent from the epoch)
Are you sure about this values?
You can also take a look at this:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnclinic/html/scripting09102002.asp
It's VB code, but it should help.
Good luck!
zigoal,
I'm pulling 'pwdLastSet' and 'maxPwdAge' directly from AD.
I'm not sure what the units are for pwdLastSet, but I don't think that 'maxPwdAge' is in msecs. I think I may have to divide that by (10000 x 1000) to get it to msecs?
The reason that I say this is because if I take the 'maxPwdAge' and:
maxPwdAge / 86400 / 10000 / 1000
I get something like 42+, which I think is approximately the correct value (days) for 'maxPwdAge' in AD?
Jim
Hi,BTW, the code I'm working on is suppose to run on a Sun Solaris box. Is your suggestion only applicable under Windows?Jim
zigoal,BTW, I am getting a compile error:integer number too large: 11644473600000long lPwdLastSetMsecs = lPwdLastSet - 11644473600000; ^Jim
Here's the code I use to read lastPwdSet attribute:
SearchResult res = ... the User object retrieved via your LDAP query
Attribute attr = res.getAttributes().get("pwdLastSet");
// This value is expressed in hundreds of nanoseconds
long pwdLastSetAD = Long.parseLong(attr.get().toString());
// Here you convert from hundreds of nanoseconds to millis,
// then subtract the epoch offset (the trailing L gets rid of the compiler error)
long lPwdLastSet = (pwdLastSetAD / 10000) - 11644473600000;
I tried changing password and printing the date corresponding to lPwdLastSet, and everything works fine.
Attribute maxPwdAge is in hundreds of nanoseconds as well.
Solaris OS uses the same epoch as Java, so the code should work provided that your domain controller and Solaris box are synchronized. You can use NTP for this purpose.
Message was edited by:
zigoal
for some reason the code formatter trims the L at the end of 11644473600000L
zigoal,That seems to work!!Thanks for all of your help!Jim
Glad that you got that one worked out !
FYI, IIRC all of the AD date/time values that are stored as large integers represent 100 nanosecond intervals.
For those that represent a date such as pwdLastSet, accountExpires etc. the value is a Win32FileTime value which is stored as the number of 100 nanosconds since 1/1/1601 UTC.
For those that represent a period of time, such as maxPwdAge, it is just simply the number of 100 nanoseconds intervals.
In your last question, maxPwdAge and pwdLastSet, these are documented at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adschema/adschema/a_maxPwdAge.asp and http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adschema/adschema/a_pwdLastSet.asp respectively.