From: Alistair Y. <ali...@sm...> - 2006-08-01 07:14:19
|
> I still feel a switch to JNDI is needed I don't see why. We've run the openLDAP api against AD, openLDAP and eDirectory for 2 years now without any problems. It doesn't work on your laptop. Is that a reason to change everything? I don't think so. What happens if you remove the custom socket? Why not go back to basics and add the extra stuff like sockets as you go along? Alistair On 31 Jul 2006, at 12:45, Jon Maber wrote: > Alistair Young wrote: >>> the main problem that >>> prompted the posting has been resolved and the Novell API is not to >>> blame >>> >> Can you tell us what the original problem was Jon? First of all it >> was all >> chaos and doom in the openldap api. Now it's not. It was only >> yesterday >> that you said a switch to jndi was essential. Now it's not? >> > The original problem prompted doubts but the test program prompted > alarm. The original problem has gone away but the results of the > test program have not! So, I still feel a switch to JNDI is needed. >> Sounds like you may have sorted a problem with ad interfacing - >> would be >> nice to know what it was. >> > The original problem initially seemed random - we put log results > into a database and ran a lot of queries but couldn't find a > pattern. Because it seemed random at first I created the test > program which attempts an LDAP search in a loop with a pause > between each iteration - it didn't recreate the same exceptions but > it produced the other random exceptions which caused so much > alarm. However, after we collected more data from the Bodington > installation and examined the code more carefully we found a > pattern to the *original* exceptions - it was always a student > whose DN was not cached in a Bodington alias and who typed in a > password other than the one in the active directory. The Leeds code > needs to search twice for user names from two different base DN > corresponding to staff and students because the common DN that > contains both also contains vast numbers of other records which are > best ignored. So, the code connects, loops on a list of configured > base DN doing a search on each and disconnects. However, the bug > was caused by not rebinding with the admin account to do the second > search. The part that confused us was that the exception didn't > occur on the search call or the hasMore call but with the next() > call to the API and that the error code from active directory > indicated an internal error. It looked like the connection was > bound when the search was performed but that this had been > forgotten or lost by the time the first record was loaded. We know > now that the error was generated in AD with the search operation > but the error condition is actually returned to the client end > inside the first search result record. So, hasMore returns true, > not because the search found a user record but because an error > record is available. It is the next call that throws the exception > because it loads the error record from the LDAP payload, interprets > it as an error and throws the appropriate exception. That problem > is now fixed - if the user can't authenticate using the first > configured base DN the admin credentials are used to rebind before > the next base DN is searched. >>> I can supply the test program to anyone who would >>> like to give a go. >>> >> go on then, mail it to the list. >> >> > Attached to this message. > I've now run this test against OpenLDAP and it also throws > exceptions for example; > > 13188 [main] DEBUG ADDebug - 1000000c Found by user name. > 13211 [main] DEBUG ADDebug - 1000000c Authentication OK > 14392 [main] DEBUG ADDebug - 1000000d Found by user name. > 14395 [main] DEBUG ADDebug - 1000000d Authentication OK > 15580 [main] DEBUG ADDebug - 1000000e Found by user name. > 15583 [main] DEBUG ADDebug - 1000000e Authentication OK > 16760 [main] DEBUG ADDebug - 1000000f Found by user name. > 16763 [main] DEBUG ADDebug - 1000000f Authentication OK > 17952 [main] DEBUG ADDebug - 10000010 Found by user name. > 17954 [main] DEBUG ADDebug - 10000010 Authentication OK > 19137 [main] DEBUG ADDebug - 10000011 Found by user name. > 19140 [main] DEBUG ADDebug - 10000011 Authentication OK > 20320 [main] DEBUG ADDebug - 10000012 Found by user name. > 20322 [main] DEBUG ADDebug - 10000012 Authentication OK > 21508 [main] DEBUG ADDebug - 10000013 Found by user name. > Exception in thread "Thread-72" java.lang.NullPointerException > at com.novell.ldap.Message.putReply(Message.java:340) > at com.novell.ldap.Connection$ReaderThread.run > (Connection.java:1295) > at java.lang.Thread.run(Thread.java:595) > > or like this; > > 0 [main] DEBUG ADDebug - 10000001 Found by user name. > 18 [main] DEBUG ADDebug - 10000001 Authentication OK > 1121 [main] DEBUG ADDebug - 10000002 Found by user name. > Exception in thread "Thread-4" java.lang.RuntimeException: > Connection.freeWriteSemaphore(7): thread does not own the > semaphore, owned by -3 > at com.novell.ldap.Connection.freeWriteSemaphore > (Connection.java:324) > 1141 [main] DEBUG ADDebug - 10000002 Authentication OK > at com.novell.ldap.Message.putReply(Message.java:348) > at com.novell.ldap.Connection$ReaderThread.run > (Connection.java:1295) > at java.lang.Thread.run(Thread.java:595) > 2251 [main] DEBUG ADDebug - 10000003 Found by user name. > Exception in thread "Thread-8" java.lang.RuntimeException: > Connection.freeWriteSemaphore(12): thread does not own the > semaphore, owned by -3 > at com.novell.ldap.Connection.freeWriteSemaphore > (Connection.java:324) > at com.novell.ldap.Message.putReply(Message.java:348) > at com.novell.ldap.Connection$ReaderThread.run > (Connection.java:1295) > at java.lang.Thread.run(Thread.java:595) > 2269 [main] DEBUG ADDebug - 10000003 Authentication OK > > > The Null pointer exception brings the code execution to a complete > halt but the runtime exception allows execution to continue. > > > > /* > * ADDebug.java > * > * Created on 25 July 2006, 14:08 > * > * To change this template, choose Tools | Template Manager > * and open the template in the editor. > */ > > import java.util.Properties; > import java.net.*; > import com.novell.ldap.*; > > import org.apache.log4j.Logger; > import org.apache.log4j.Level; > import org.apache.log4j.BasicConfigurator; > > /** > * > * @author jon > */ > public class ADDebug > { > private static Logger log = Logger.getLogger > ( ADDebug.class.getName() ); > > private static final String admin_dn = > "cn=Manager,dc=ds,dc=leeds,dc=ac,dc=uk"; > private static final String admin_password = "secret"; > private static final String search_base = > "OU=Staff,DC=ds,DC=leeds,DC=ac,DC=uk"; > private static final String search_user = "bio1ama"; > private static final String search_password = "secret"; > private static final String search_server = "localhost"; > > private static final int extradelaymillis = 5; > > static > { > BasicConfigurator.configure(); > //log.addAppender( new org.apache.log4j.ConsoleAppender() ); > } > > int serial = 0x10000000; > > /** Creates a new instance of ADDebug */ > public ADDebug() > { > } > > public void test() > throws Exception > { > boolean ok; > for ( int i=0; i<20; i++ ) > { > serial++; > ok = authenticateUserName( search_user, search_password ); > log.log( Level.DEBUG, logMessage( "Authentication " + > (ok?"OK":"Failed") ) ); > Thread.currentThread().sleep(1000); > } > } > > > > private boolean searchByUserName( > LDAPConnection lc, > String basedn, String user_name, String p ) > throws LDAPException, InterruptedException > { > LDAPSearchResults searchResults=null; > > String filter; > filter = "(&(objectClass=user)(cn=" + user_name + "))"; > > //log.log( Level.DEBUG, logMessage( "LDAP search basedn " + > basedn ) ); > //log.log( Level.DEBUG, logMessage( "LDAP search filter " + > filter ) ); > searchResults = > lc.search( > basedn, > LDAPConnection.SCOPE_SUB, > filter, > null, // null seems to fetch all attributes - not > documented in API docs! > false ); > > Thread.currentThread().sleep( extradelaymillis ); > if ( !searchResults.hasMore() ) > { > log.log( Level.DEBUG, logMessage( "LDAP Search\tUser > name not found." ) ); > return false; > } > Thread.currentThread().sleep( extradelaymillis ); > LDAPEntry entry = searchResults.next(); > //dumpResult( entry ); > Thread.currentThread().sleep( extradelaymillis ); > if ( searchResults.hasMore() ) > { > log.log( Level.WARN, logMessage( > "LDAP Search\tUser name appears in more than > one record." ) ); > //dumpResults( searchResults ); > return false; > } > String userDN = entry.getDN(); > > try {lc.bind( 3, userDN, p );} > catch ( LDAPException e ) {return false;} > return lc.isBound(); > } > > > > private boolean authenticateUserName( String user_name, String p ) > { > LDAPConnection lc=null; > try > { > lc = connect(); > if ( lc == null) > return false; > Thread.currentThread().sleep( extradelaymillis ); > try {lc.bind(3, admin_dn, admin_password );} > catch ( LDAPException e ) > { > log.log( Level.DEBUG, logMessage( "Bind > Failed." ) ); > return false; > } > Thread.currentThread().sleep( extradelaymillis ); > if ( !lc.isBound() ) > { > log.log( Level.DEBUG, logMessage( "Bind Failed. > (B)" ) ); > return false; > } > Thread.currentThread().sleep( extradelaymillis ); > //log.log( Level.DEBUG, logMessage( "Bound to LDAP > for searching." ) ); > > if ( !searchByUserName( lc, search_base, > user_name, p ) ) > return false; > log.log( Level.DEBUG, logMessage( "Found by > user name." ) ); > return true; > } > catch ( Exception e ) > { > log.log( Level.ERROR, logMessage( > "Exception\tSerious problem while searching > LDAP. " + > "See stdout for stack trace." ) ); > e.printStackTrace(); > return false; > } > finally > { > try > { > if ( lc!=null && lc.isConnected() ) > lc.disconnect(); > } > catch ( LDAPException ldape ) > { > } > } > } > > public LDAPConnection connect() > throws Exception > { > LDAPConstraints constraints = new LDAPSearchConstraints(); > constraints.setTimeLimit( 5*1000 ); > LDAPConnection lc = new LDAPConnection( new > CustomSocketFactory() ); > lc.setConstraints( constraints ); > lc.connect( search_server, 389 ); > > return lc; > } > > String logMessage( String message ) > { > StringBuffer buffer = new StringBuffer(); > buffer.append( Long.toHexString( serial ) ); > buffer.append( "\t" ); > buffer.append( message ); > return buffer.toString(); > } > > public static void main( String[] params ) > { > System.out.println( "Starting" ); > try > { > ADDebug debug = new ADDebug(); > debug.test(); > } > catch ( Exception e ) > { > e.printStackTrace(); > } > } > } > > > > class CustomSocketFactory implements LDAPSocketFactory > { > public Socket createSocket( String host, int port ) > throws java.io.IOException, java.net.UnknownHostException > { > Socket socket = new Socket(); > InetSocketAddress endpoint = new InetSocketAddress(host, > port); > socket.connect( endpoint, 2000 ); > return socket; > } > } > |