participate


Naming and Directory (JNDI) - JNDI, Active Directory and User Account status (account expired, locked)
<<   Back to Forum  |   Give us Feedback Topics: « Previous | Next »
This topic has 16 replies on 2 pages.    1 | 2 | Next »
adler_steven
Posts:669
Registered: 12/9/04
JNDI, Active Directory and User Account status (account expired, locked)   
Mar 9, 2006 11:37 AM

 
I figure enough people are confused that this topic deserves a post of it's own.

Account Expires
An account can be set to expire automatically, by simply assigning a valid expiration date to the account. What this means is that a user, even though they may have valid credentials, will not be able to logon with that account.

The attribute is called accountExpires and it contains a Win32 time value (I used to think it was the number of milliseconds since 1/1/1601, but there seems to be a discrepency between the Java time epoch which is based on number of milliseconds since 1/1/1970 and the Win32 units. Perhaps Win32 is measured in tenth of nanoseconds, perhaps the Java docs are wrong, or perhaps I'm wrong ?).

To determine whether an account expires today, calculate the number of millisecond/nanosecond units since 1/1/1601 and check whether this value is greater than the value of the accountExpires attribute.
//Specifiy the LDAP search filter
GregorianCalendar Win32Epoch = new GregorianCalendar(1601,Calendar.JANUARY,1);
Date Win32EpochDate = Win32Epoch.getTime()
//Note that 1/1/1601 will be returned as a negative value by Java
GregorianCalendar Today = new GregorianCalendar();
Date TodaysDate = Today.getTime();
long TimeSinceWin32Epoch = 10000 * (TodaysDate.getTime() - Win32EpochDate.getTime());
String searchFilter = "(&(objectClass=User)(accountExpires<=" + TimeSinceWin32Epoch + ")(accountExpires>=1))";


To set an account to not expire, set the value of accountExpires to zero. Hence the reason to check that accountExpires is non zero.

Account Locked
An account may be automatically locked, if the domain's security policy has been configured to lock accounts after a number of unsuccessful logon attempts. If an account has been locked out, the lockoutTime attribute will contain a Win32 time value that indicates when the account was locked.

An easy way to search for locked out accounts is an LDAP query similar to (&objectClass=user)(lockoutTime=*)) Eg. Search for any accounts that have a value for lockoutTime. However this is not an accurate method to use because an account is determined to be locked out if the CurrentTime - LockoutTime exceeds the Lockout Duration. It is only upon a successful logon that the system would set the value of lockoutTime to zero, so it is possible for an account to still contain a value for lockoutTime, yet the account is not locked.

You obtain the value of lockoutDuration from the domainDNS object
....
Attributes attrs = ctx.getAttributes("dc=antipodes,dc=com");
System.out.println("Account Lockout Policy for " + attrs.get("distinguishedName").get());
System.out.println("Threshold " + attrs.get("lockoutThreshold").get());
System.out.println("Duration " + attrs.get("lockoutDuration").get());
//Save the duration for later calculations
long lockoutDuration = Long.parseLong(attrs.get("lockoutDuration").get().toString());
....
SearchControls searchCtls = new SearchControls();
//Specify the attributes to return
String returnedAtts[]={"sn","givenName"};
//Specify the search scope
searchCtls.setSearchScope(searchControls.SUBTREE.SCOPE);
//specify the filter
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());
String searchFilter = "(&(objectClass=user)(lockoutTime>=" + (TimeSinceWin32Epoch + lockoutDuration) + "))";


Note to unlock an account, just set the value of the attribute lockoutTime to zero

Password Expires
Similar to above but just need to retrieve the maxPwdAge from the domainDNS object and perform a similar comparison to the user's pwdLastSet atribute

To force a password to expire (eg. the user must change it at the next logon, set the value of pwdLastSet to zero. To "unexpire" the password set the value to -1 which implies the current time. Values other than 0 or -1 are not permitted.

Account Disabled
Accounts may be disabled by setting the second bit of the userAccountControl attribute. For code samples refer to http://forum.java.sun.com/thread.jspa?threadID=588430&messageID=3045217


Note:
For Active Directory Application Mode (ADAM, now referred to as Active Directory Lightweight Directiry Service) there are constructed boolean attributes that simplify some of these operations. These include:
msDS-UserAccountDisabled, ms-DS-UserAccountAutoLocked, msDS-UserPasswordExpired, msDS-User-Account-Control-Computed (an enumerated value for account & password expiration).
Active Directory schema definitions can be found at http://msdn.microsoft.com/library/en-us/adschema/adschema/active_directory_schema.asp
 
cliles
Posts:16
Registered: 8/30/05
Re: JNDI, Active Directory and User Account status (account expired, locked   
Apr 27, 2006 2:43 PM (reply 1 of 16)  (In reply to original post )

 
This is some excellent info!

I am having some issues with getting expired passwords to work.

I have followed the outline from checking if the account is locked (which works correctly), but I keep getting incorrect return values. Accounts are showing that the pasword is expired, but I physically watched the user change his/her password, and have also changed the password through the mmc, but it still shows up as expired.

Here is the code I used for checking if the account is lockedout and if the password is disabled


.
.
.
 
long lockoutDuration = Long.parseLong(attrsDomain.get("lockoutDuration").get().toString());
//query for password expiration period
long pwdexpireDuration = Long.parseLong(attrsDomain.get("maxPwdAge").get().toString());
//setup the calander for calculation
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());
 
.
.
.
//locked/unlocked
long userLockoutTime = 0;
							
try{
userLockoutTime = Long.parseLong((String)attrs.get("lockoutTime").get());
}
									
catch(Exception e){
System.out.println("Account has never been locked out, setting to 0 to cheat it");
userLockoutTime = 0;
}
																		
if ( userLockoutTime >= (TimeSinceWin32Epoch + lockoutDuration))
{
        tempuser.isLockedaccount(true);
}
else {
	tempuser.isLockedaccount(false);
}
									
									
//expired password
long userpwdChangeTime;
userpwdChangeTime = Long.parseLong((String)attrs.get("pwdLastSet").get());
if ( userpwdChangeTime >= (TimeSinceWin32Epoch + pwdexpireDuration))
		{
		tempuser.isExpiredpw(true);
         	}
		else {
		tempuser.isExpiredpw(false);
		}
 



I am truely confused to why when my code says the password is expired, the use can log in fine and not get the "change your password" window.

I am also confused as the maxPwdAge value from the domain is a rather large negative number...

Anyone see what I am doing wrong, or any thoughts on this??

Thanks!

--
cliles
 
adler_steven
Posts:669
Registered: 12/9/04
Re: JNDI, Active Directory and User Account status (account expired, locked   
May 1, 2006 3:40 AM (reply 2 of 16)  (In reply to #1 )

 
maxPwdAge IS a large negative number.

It is stored as the negative number of 100 nanosecond intervals.

These snippets may help you:
Determing domain policy settings
Attributes attrs = ctx.getAttributes("dc=antipodes,dc=com");
System.out.println("Password Policy for " + attrs.get("distinguishedName").get());
System.out.println("Password Age: " + attrs.get("maxPwdAge").get());
Long pwdAge = new Long(attrs.get("maxPwdAge").get().toString());
System.out.println("Password Age (Days): " + ((pwdAge/-86400)/10000000)); //stored as -ve number of hundred nanosecond intervals Eg. 10^7
System.out.println("Min Password Length: " + attrs.get("minPwdLength").get());

Determing the LDAP searchfilter
//calculate the password expiration date
GregorianCalendar Win32Epoch = new GregorianCalendar(1601,Calendar.JANUARY,1);
GregorianCalendar Today = new GregorianCalendar();
Long Win32EpochInMillis = Win32Epoch.getTimeInMillis();
Long TodayInMillis = Today.getTimeInMillis();
Long Expiration = (TodayInMillis - Win32EpochInMillis) * 10000; 
System.out.println("Today's Date: " + DisplayWin32Date(Expiration.toString());
Expiration = Expiration + pwdAge;
System.out.println("Expiration Date: " + DisplayWin32Date(Expiration.toString());
//Specify the search filter
String searchFilter = ((&(objectClass=user)(pwdLastSet<=" + Expiration + "))";

A useful function for displaying Win32 Date/Time
static String DisplayWin32Date(String Win32FileTime) {
GregorianCalendar Win32Epoch = new GregorianCalendar(1601,Calendar.JANUARY,1);
Long lWin32Epoch = Win32Epoch.getTimeInMillis();
Long lWin32FileTime = new Long(Win32FileTime);
return(DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.FULL).format((lWin32FileTime/10000) + lWin32Epoch));

Note that a password may have expired, but the user may not be prompted to change their password if the userAccountControl is set to not expire the password. Also note that the Active Directory stores date/time as UTC, so your application may need to take into consideration different timezones and/or daylight savings time.

Good luck.
 
cliles
Posts:16
Registered: 8/30/05
Re: JNDI, Active Directory and User Account status (account expired, locked   
May 8, 2006 1:42 PM (reply 3 of 16)  (In reply to #2 )

 
I see what you are saying about the whole time thinggy. I ended up hitting up our friend MSDN to get the whole 100 nanoseconds thing figured out.

After trial and error, I came up with the following:

I don't know if it does the same thing as what you posted, but it seems to work <shrug>

.
.
.
 
//query for password expiration period
long pwdexpireDuration =Math.abs(Long.parseLong(attrsDomain.get("maxPwdAge").get().toString()));
//setup the calander for calculation
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());
.
.
.
//expired password
long userpwdChangeTime;
userpwdChangeTime = Long.parseLong((String)attrs.get("pwdLastSet").get());
																    
if ( (TimeSinceWin32Epoch - userpwdChangeTime) >= (pwdexpireDuration) )
{
tempuser.setExpiredpw(true);
}
									
				
else {
tempuser.setExpiredpw(false);
}
.
.
.
 


Are we doing the same thing?
 
pandu345
Posts:119
Registered: 1/5/06
Re: JNDI, Active Directory and User Account status (account expired, locked   
Jun 15, 2006 12:26 PM (reply 4 of 16)  (In reply to #3 )

 
Hey

I want to calculate the password expiration date of a
user in AD, but when I query the domain for maxpwdAge
I am getting negative value
-332640000000000


How can I proceed

Thanks,
pandu
 
pandu345
Posts:119
Registered: 1/5/06
Re: JNDI, Active Directory and User Account status (account expired, locked   
Jun 15, 2006 1:28 PM (reply 5 of 16)  (In reply to #4 )

 
Hey Thanks guys,

This code helped sove my problem

My value from AD is lasppwdset =127948319499226601
long pwdLastSet = Long.parseLong("127948319499226601");
		System.out.println("long value : "+pwdLastSet);	
		
		long javaTime = pwdLastSet - 0x19db1ded53e8000L;
        javaTime /= 10000L;
        
        Date today = new Date(javaTime);
        
        System.out.println("java DATE value : "+today);
       
         SimpleDateFormat sdf2 = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
		
		String newDateString = sdf2.format(today);
		
		System.out.println("Date When Password Last Set :"+newDateString);
		
		GregorianCalendar cal0=new GregorianCalendar();
		cal0.setTime(today);
		cal0.add(5, 385);
		newDateString = sdf2.format(cal0.getTime());
        
        System.out.println("Date When Password Expires :"+newDateString);
        
		GregorianCalendar cal = (GregorianCalendar)Calendar.getInstance();
        cal.add(5, 385);
        cal.getTime();
		
		
		 /***
         * Fine till above line getting expected Value in java.util.date
         */
        
		long pwdAge = new Long("-332640000000000").longValue();		
		
		System.out.println("Password Age (Days): " + ((pwdAge/-86400)/10000000)); //stored as -ve number of hundred nanosecond intervals Eg. 10^7
		
		GregorianCalendar Win32Epoch = new GregorianCalendar(1601,Calendar.JANUARY,1);
		GregorianCalendar Today = new GregorianCalendar();
		long Win32EpochInMillis = Win32Epoch.getTimeInMillis();
		long TodayInMillis = Today.getTimeInMillis();
		long Expiration = (TodayInMillis - Win32EpochInMillis) * 10000; 
		System.out.println("Today's Date: " + Expiration);
		Expiration = Expiration + pwdAge;
		System.out.println("Expiration Date: " + Expiration);


Thanks,
pandu
 
ashutoshdash
Posts:43
Registered: 26/05/03
Re: JNDI, Active Directory and User Account status (account expired, locked)   
Jun 16, 2006 12:36 AM (reply 6 of 16)  (In reply to original post )

 
Hi
I am tring to find out a user is currently lockedout or password expired from MS Active Directory. I used the codes to write my methods for checking. but at the end one question comeing up to my mind on this code.
how correct is it to get current time in java from system that runs jvn rather than active directory's. because all the times entered in user attributes are in refference to active direcotries system date and we are compairing it with jvm's system date which might be two different m/c.
if someone agrees might concerned please provide solutions to may be reading datetime from active directory.

any comment is appriciated.

Thanks
 
adler_steven
Posts:669
Registered: 12/9/04
Re: JNDI, Active Directory and User Account status (account expired, locked)   
Jun 16, 2006 8:35 AM (reply 7 of 16)  (In reply to #6 )

 
Active Directory date/time fields such as lockoutTime, pwdlastSet, lastLogon are stored as UTC time.

Therefore your Java apps, need to take into consideration both the local timezone and daylight savings settings.
 
k_reji
Posts:20
Registered: 4/16/02
Re: JNDI, Active Directory and User Account status (account expired, locked)   
Jul 26, 2006 9:38 AM (reply 8 of 16)  (In reply to #7 )

 
Hi Steve,

Infact i'm trying to query AD for the status of an account like a/c locked and password expired. As you mentioned in the starting section of this thread, i tried to retrieve lockoutDuration and lockoutThreshold. But unfortunately i couldn't find those variables.

When i browse the AD through a LDAP browser, i couldn't see these attributes. In this situation what 'd i do to get the accounts which are really locked ? I tried to search by lockOutTime > 0, but many accounts satisfying this criteria doesn't seems to be locked, they are disabled.

Would you suggest me a better way to do this ?

regards
RK
 
k_reji
Posts:20
Registered: 4/16/02
Re: JNDI, Active Directory and User Account status (account expired, locked   
Jul 28, 2006 3:13 AM (reply 9 of 16)  (In reply to #5 )

 
Hi pandu,

In your message reply, you've used one value (0x19db1ded53e8000L) to find out the java time. May i know how do you get this value ? After caluculation are you getting the time in java, corresponding to the pwdLastSet time ?

I'm just now working with AD. Since new, i've got few doubts.

Thanks in advance.

RK.
 
adler_steven
Posts:669
Registered: 12/9/04
Re: JNDI, Active Directory and User Account status (account expired, locked)   
Jul 28, 2006 8:07 AM (reply 10 of 16)  (In reply to #8 )

 
Sorry, I'm only guessing here, but I think that the only reasons why you may not be able to retrieve the values for lockoutDuration and lockoputThreshold are:
a. No group policy settings have been configured for account lockout, or
b. The account you are using does not have permission to read the values

If the first reason applies, then accounts won't get locked out, so the question is moot (although I would suggest that this is a bad security policy, allowing your directory to be targetted by dictionary attacks).

If the latter reason is the cause, then you may have to hardcode the values in your app, rather than obtain them programmatically. However more importantly, it is also likely that you may not have permission to retrieve the value of lockoutTime from the user objects, so again the question becomes moot.

BTW, Are you using Active Directory, or Active Directory Application Mode (ADAM) ?

If you are using ADAM, it will derive it's password & account policy from the server's policy. If the server is a member of a domain, it will derive its policy from the domain. If it is a stand-alone server, it uses its own policy. And if ADAM is running on XP, then no account or password policies are applied.

Good luck.
 
k_reji
Posts:20
Registered: 4/16/02
Re: JNDI, Active Directory and User Account status (account expired, locked)   
Jul 31, 2006 7:17 AM (reply 11 of 16)  (In reply to #10 )

 
Hi Steve,

First of all, let me answer your last question. I'm using Active Directory, not ADAM, thats for sure.

Infact, one service account has been created for our use, we access AD through this account. Hope your guessing about enough permission is true, i think.

Moreover i'm not using JNDI, instead i use direct LDAPConnection to the server. Will that make any problem ? Below is my code, would you just try to point out the problem. Due to security problems, i've deleted few lines, but you can understand the logic.


import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.text.DateFormatSymbols;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
 
import com.novell.ldap.LDAPAttribute;
import com.novell.ldap.LDAPAttributeSet;
import com.novell.ldap.LDAPConnection;
import com.novell.ldap.LDAPControl;
import com.novell.ldap.LDAPException;
import com.novell.ldap.LDAPSearchConstraints;
import com.novell.ldap.LDAPSearchResults;
 
public class ADLookupUtil {
 
	private final int LDAP_AUTH_SUCCESS  = 0;
	private final int LDAP_AUTH_FAIL     = -1;
	private final int INVALID_CREDENTIAL = 49;
	private LDAPConnection connection = null;
	 
	private final int UF_ACCOUNTDISABLE     = 2;//0x0002
	private final int UF_LOCKOUT            = 16;//0x0010
	private final int UF_PASSWORD_EXPIRED   = 8388608;//0x800000
	private final int UF_DONT_EXPIRE_PASSWD = 65536;//0x00010000
	private final int UF_NORMAL_ACCOUNT     = 512;//0x0200
	
 
	String searchAttribs[] = {"userAccountControl","lockoutTime","pwdLastSet","logonCount"};
	
	/**
	 * Constructor
	 * Making a LDAP Connection
	 */
	public ADLookupUtil(){
		connection = new LDAPConnection();
	}
 
    /**
     * Function tries to connect to Active Directory
     * @param host Active Directory server name
     * @param port the port 
     */ 
	private boolean connect(String host, String port) {
		try {
			connection.connect(host, new Integer(port).intValue());
			return true;
		} catch (LDAPException ldapex) {
			
		}
 
		return false;	  	
	}
    
    /**
     * Function to disconnect from Active Directory
     *
     */
	private void disconnect() {
		try {
			if (connection.isConnected()) {
				connection.disconnect();
			}
		} catch (LDAPException ldapex) {
		}
	}
	
	/**
	 * Function to authenticate the user to Active directory with user credentials
	 * @param baseDN	the baseDN
	 * @param passwd    the password
	 * @return
	 */
	private int authenticate(String baseDN, String passwd) {
		try {
			try {
				connection.bind(LDAPConnection.LDAP_V3,	baseDN.toString(), passwd.getBytes("UTF8"));
			} catch (UnsupportedEncodingException e) {
				disconnect();
				return LDAP_AUTH_FAIL;
			}
			return LDAP_AUTH_SUCCESS;
		} catch (LDAPException ldapex) {
			disconnect();
		}
		return LDAP_AUTH_FAIL;				
	}
    
    /**
     * Function to look up the active directory when corpId is supplied
     * @param corpId	the unique corpId of the person calling
     * @return	the account status object
     */ 	
	public ActiveDirectoryResponse lookupEmployee(String corpId, Employee employee) {
		ActiveDirectoryResponse adr = new ActiveDirectoryResponse();
		ApplicationContext context = ApplicationContext.getInstance();
		HashMap searchResult = new HashMap();
		int adReturnValue = -1;
		String searchFilter = "sAMAccountName=".concat(corpId);
		try{
			
			adr = new ActiveDirectoryResponse();
			searchResult =lookupAD(context.getProperty(HOST),
										context.getProperty(PORT),
										context.getProperty(BASE_DN),
										context.getProperty(PASSWORD),
										context.getProperty(SEARCH_BASE),
										searchFilter, LDAPConnection.SCOPE_SUB);
			try{
				if(searchResult.size() == 0){
					searchResult =lookupAD(context.getProperty(ANOTHER_HOST),
											context.getProperty(ANOTHER_PORT),
											context.getProperty(ANOTHER_BASE_DN),
											context.getProperty(ANOTHER_PASSWORD),
											context.getProperty(ANOTHER_SEARCH_BASE),
											searchFilter,LDAPConnection.SCOPE_SUB);	
				}
			}catch(LDAPException lde){
			}
		}catch(LDAPException lde){
		}
		
		if(searchResult.size() >0){
			try{
				//Checks whether user account is disabled 
				long userAccountControl = new Long(searchResult.get(searchAttribs[0]).toString()).longValue();
				if((userAccountControl & UF_ACCOUNTDISABLE)== UF_ACCOUNTDISABLE){
					adr.setAcDisabled(true);
					try{
	searchResult =lookupAD(context.getProperty(ANOTHER__HOST),
												context.getProperty(ANOTHER_PORT),
												context.getProperty(ANOTHER_BASE_DN),
												context.getProperty(ANOTHER_PASSWORD),
												context.getProperty(ANOTHER_SEARCH_BASE),
												searchFilter,LDAPConnection.SCOPE_SUB);	
					}catch(LDAPSearchException lde){
					(searchResult.size() >0){
						userAccountControl = new Long(searchResult.get(searchAttribs[0]).toString()).longValue();
						if((userAccountControl & UF_ACCOUNTDISABLE)== UF_ACCOUNTDISABLE){
								adr.setAcDisabled(true);
								return adr;
						}else{
							adr.setAcDisabled(false);
						}
					}else{		
						return adr;
					}
				}
				
				//Checks whether the user's accout is locked out
				if(searchResult.containsKey(searchAttribs[1].toString())){
					long lockoutTime = new Long(searchResult.get(searchAttribs[1]).toString()).longValue();
					if(lockoutTime >0){
						adr.setAcLocked(true);
					}
				}
             
                //Checks whether the user is a new hire
				if(searchResult.containsKey(searchAttribs[2].toString())){
					long logonCount = -1;
					if(searchResult.containsKey(searchAttribs[3].toString()))
						 logonCount = new Long(searchResult.get(searchAttribs[3]).toString()).longValue();
					else
						 logonCount = 0;	 
					//long pwdLastSet = new Long(searchResult.get(searchAttribs[2]).toString()).longValue();
					long pwdLastSet = Long.parseLong(searchResult.get(searchAttribs[2]).toString());
					if(pwdLastSet != 0){
						pwdLastSet -= 0x19db1ded53e8000L;//the difference Win32 date(1/1/1601) and java date(1/1/1970)
						pwdLastSet /= 10000;
					} 
					pwdLastSet = new Date(pwdLastSet).getTime();
					DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S",new DateFormatSymbols(Locale.US));
					Date hireDate = (Date)formatter.parse(employee.getHireDate());
					
				    System.out.println(" Password Last set on :"+formatter.format(new Date(pwdLastSet)));
				
					userAccountControl = new Long(searchResult.get(searchAttribs[0]).toString()).longValue();
					if(((pwdLastSet == 0)
					  ||(pwdLastSet < hireDate.getTime())) 
					  &&(logonCount == 0)
					  &&(userAccountControl & UF_DONT_EXPIRE_PASSWD) != UF_DONT_EXPIRE_PASSWD){
						adr.setIsNewHire(true);
					}
				}
				// Checks whether the user's password is expired
				if((userAccountControl & UF_PASSWORD_EXPIRED) == UF_PASSWORD_EXPIRED){
					adr.setAcExpired(true);
				}
				
			}catch(Exception ee){						}
		}
		return adr;
	}
	
 
 
	private HashMap lookupAD(String adHost,String adPort, String adBaseDN, 
	                        String adPassword, String searchBase, String searchFilter,
	                        int searchScope) throws LDAPException {
		CSCWebAppTrace.entering(this, "lookupAD");
		Long attributeValue = null;
		Iterator allAttributes=null;
		Enumeration allValues=null;
		LDAPAttribute attribute=null;
		LDAPAttributeSet attributeSet=null;
		String sAttrName, sAttrValue = null;
		LDAPSearchResults searchResults = null;
		HashMap searchResult = new HashMap();
		
		try{
			connect(adHost,adPort); 
		}catch(ADConnectionException eadc){
		 	CSCWebAppTrace.debug(this,eadc.getMessage());
		 	return searchResult;
		}
		try{
			authenticate(adBaseDN, adPassword);
		}catch(ADBindException eadb){
			return searchResult;
		}
		//Search the directory
		try{
			LDAPSearchConstraints srchConst = connection.getSearchConstraints();
			connection.setConstraints(srchConst);
			
			try{						
			
					searchResults = connection.search(searchBase, //search base
									   searchScope,//search scope
									   searchFilter,//"cn=",//search filter
									   searchAttribs,// return all attributes
									   false,
									   srchConst); //search constraints
			}catch(LDAPException lde){
							disconnect();
				return searchResult;
			}
					  
			
			LDAPControl[] controls = connection.getResponseControls();
			while ( searchResults.hasMore()){
				//Print out all the attributes for each entry
				attributeSet = searchResults.next().getAttributeSet();
				allAttributes = attributeSet.iterator();
				while (allAttributes.hasNext()) {
					attribute = (LDAPAttribute)allAttributes.next();
					sAttrName = attribute.getName();
					
					allValues = attribute.getStringValues();
					attributeValue = null;
					while (allValues.hasMoreElements()) {
						Object obj = allValues.nextElement();
						if(obj != null){ 
							attributeValue = new Long((String)obj);
							searchResult.put(sAttrName,attributeValue);
							System.out.println("sAttrName :"+sAttrName+" value :"+attributeValue);
						}
					}
				}
			} // end while
		} // end try
		
		
		
		catch (Exception e) {
			
		}
		disconnect();		
		return searchResult;
	}
	
}
 


Would you able to help me ?

Thanks,
RK
 
adler_steven
Posts:669
Registered: 12/9/04
Re: JNDI, Active Directory and User Account status (account expired, locked)   
Aug 4, 2006 8:19 AM (reply 12 of 16)  (In reply to #11 )

 
HI RK,

The password & account lockout policies are stored as attributes on the domainDNS object, not on each user object. It doesn't look like you are retrieving these values in your code.

For example in my domain "Antipodes.com", I retrieve the policy values from the attributes: lockoutThreshold, lockoutDuration, minPwdAge, maxPwdAge, minPwdLength which are stored on the domainDNS object which has a distinguished name "dc=antipodes,dc=com".
String returnedAtts[] = {"lockoutThreshold", "lockoutDuration", "minPwdAge","maxPwdAge", "minPwdLength"};
String searchBase = "dc=antipodes,dc=com";
String searchFilter = "(objectClass=domainDNS)";
searchCtls.setSearchScope(SearchControls.OBJECT_SCOPE);


Note that the userAccountControl flags do not automagically get updated to correctly indicate the account lockout or password expired status. You should check the user's lockoutTime and pwdLastSet respectively.

You also mention that you are using a service account. I'm assuming that you are using Network Service. Assuming the default permissions are in place, I think it should work OK.
Good luck.
 
letuka
Posts:1
Registered: 12/5/06
Re: JNDI, Active Directory and User Account status (account expired, locked)   
Dec 5, 2006 1:18 AM (reply 13 of 16)  (In reply to #12 )

 
Hi,
I have read all the posts on this thread but I am still having a problem in checking whether an account is locked out or not. Please check the snippet and let me know if there is something I'm doing wrong...
public boolean isAccountLocked(){
        //if lockoutTime flag is zero, immediately return false
        if(lockoutTime == 0){
            return false;
        }
        
         //otherwise, determine if account is still locked out
        try {
            //Call to set get the lockoutDuration attribute from the domainDNS
            setLockoutDuration();
        } catch (LDAPException ex) {
            ex.printStackTrace();
            return true; 
        }
        
 
        GregorianCalendar win32epoch = new GregorianCalendar(1601,Calendar.JANUARY,01);
        Date Win32EpochDate = win32epoch.getTime();
        GregorianCalendar Today = new GregorianCalendar();
        Date TodaysDate = Today.getTime();
        long TimeSinceWin32Epoch = 10000 * (TodaysDate.getTime() - Win32EpochDate.getTime());
 
        if(lockoutTime >= (TimeSinceWin32Epoch + lockoutDuration)){ 
            return true;
        }
        return false;
    }

I am using the netscape.ldap package to connect to the AD, the value I get for lockoutDuration is -18000000000. As you can see the code is similar to the code posted earlier by you. When I test this code is always returns false even for accounts I have intentionally locked out.
 
adler_steven
Posts:669
Registered: 12/9/04
Re: JNDI, Active Directory and User Account status (account expired, locked)   
Dec 17, 2006 5:10 PM (reply 14 of 16)  (In reply to #13 )

 
I can't comment on the Netscape LDP SDK as I haven;t used it.

This is my complete sample for searching for locked accounts, hopefully it will be of some use to you.
/**
 * searchlocked.java
 * 5 July 2001 (some subtle mods over time)
 * Sample JNDI application to search for locked out accounts
 * 
 */
 
import java.util.Hashtable;
import javax.naming.ldap.*;
import javax.naming.directory.*;
import javax.naming.*;
import java.util.*;
import java.util.Calendar.*;
import java.text.*;
 
 
public class searchlocked	{
	public static void main (String[] args)	{
	
		Hashtable env = new Hashtable();
		String adminName = "ANTIPODES\\Administrator";
		String adminPassword = "XXXXXX";
		String ldapURL = "ldap://mydc.antipodes.com:389";
		
		env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
 
		//set security credentials, note using simple cleartext authentication
		env.put(Context.SECURITY_AUTHENTICATION,"simple");
		env.put(Context.SECURITY_PRINCIPAL,adminName);
		env.put(Context.SECURITY_CREDENTIALS,adminPassword);
				
		//connect to my domain controller
		env.put(Context.PROVIDER_URL,ldapURL);
		try {
 
			//Create the initial directory context
			LdapContext ctx = new InitialLdapContext(env,null);
 
			//lets get the domain lockout duration policy
			Attributes attrs = ctx.getAttributes("dc=antipodes,dc=com");
			System.out.println("Lockout policy for " + attrs.get("distinguishedName").get());
			System.out.println("Duration: " + attrs.get("lockoutDuration").get());
			System.out.println("Threshold: " + attrs.get("lockoutThreshold").get());
			Long lockoutDuration = Long.parseLong(attrs.get("lockoutDuration").get().toString());
 
			//Create the search controls 		
			SearchControls searchCtls = new SearchControls();
		
			//Specify the attributes to return
			String returnedAtts[]={"sn","givenName","mail","lockoutTime"};
			searchCtls.setReturningAttributes(returnedAtts);
		
			//Specify the search scope
			searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
 
			//Create  the correct LDAP search filter
			//Win32 file time is based from 1/1/1601
			//Java date/time is based from 1/1/1970
			GregorianCalendar Win32Epoch = new GregorianCalendar(1601,Calendar.JANUARY,1);
			GregorianCalendar Today = new GregorianCalendar();
			Long Win32Date = Win32Epoch.getTimeInMillis();
			Long TodaysDate = Today.getTimeInMillis();
			Long TimeSinceWin32Epoch = TodaysDate - Win32Date;
			
			Long lockoutDate = (TimeSinceWin32Epoch * 10000) + lockoutDuration;
			System.out.println("Lockout (Long): " + lockoutDate.toString());
			System.out.println("Lockout (Date): " + DisplayWin32Date(lockoutDate.toString()));
			String searchFilter = "(&(objectClass=user)(lockoutTime>=" + lockoutDate + "))";
 
			//Specify the Base for the search
			String searchBase = "DC=Antipodes,DC=Com"; 
 
			//initialize counter to total the results
			int totalResults = 0;
 
 
			//Search for objects using the filter
			NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls);
 
			//Loop through the search results
			while (answer.hasMoreElements()) {
				SearchResult sr = (SearchResult)answer.next();
 
				totalResults++;
 
				System.out.println(">>>" + sr.getName());
 
				// Print out some of the attributes, catch the exception if the attributes have no values
				attrs = sr.getAttributes();
				if (attrs != null) {
					try {
						System.out.println("   name: " + attrs.get("givenName").get() + " " + attrs.get("sn").get());
						System.out.println("   mail: " + attrs.get("mail").get());
						System.out.println("   locked: " + DisplayWin32Date(attrs.get("lockoutTime").get().toString()));
 
						}
					catch (NullPointerException e)	{
						System.err.println("Problem listing attributes: " + e);
					}
				
				}
 
			}
 
	 		System.out.println("Total results: " + totalResults);
			ctx.close();
 
		} 
		catch (NamingException e) {
			System.err.println("Problem searching directory: " + e);
 
		}
 
	}
 
	static String DisplayWin32Date(String Win32FileTime) {
		GregorianCalendar Win32Epoch = new GregorianCalendar(1601,Calendar.JANUARY,1);
		Long lWin32Epoch = Win32Epoch.getTimeInMillis();
		Long lWin32FileTime = new Long(Win32FileTime);
		return(DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.FULL).format((lWin32FileTime/10000)+lWin32Epoch));
 
	}
 
 
}
 
This topic has 16 replies on 2 pages.    1 | 2 | Next »
Back to Forum
 
Read the Developer Forums Code of Conduct

Click to email this message Email this Topic

Edit this Topic
  
 
 
Forums Statistics

About Sun forums
  • Oracle Forums is a large collection of user generated discussions. It is here to help you ask questions, find answers, and participate in discussions.

    Check out our guide on Getting started with Oracle Forums for a full walkthrough of how to best leverage the benefits of this community.

Powered by Jive Forums