Bug 33774 - JNDIRealm fails when server disconnects after time
Summary: JNDIRealm fails when server disconnects after time
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 5
Classification: Unclassified
Component: Catalina (show other bugs)
Version: 5.5.20
Hardware: PC Solaris
: P2 normal with 2 votes (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks: 50775
  Show dependency tree
 
Reported: 2005-02-28 17:25 UTC by Will Stranathan
Modified: 2011-02-14 16:19 UTC (History)
0 users



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Will Stranathan 2005-02-28 17:25:59 UTC
Using the JNDIRealm for authentication, if the LDAP server is set to 
automatically disconnect the client (in this case, tomcat's JNDIRealm), tomcat 
does not discover this until it attempts another login.  If the connection has 
been reset, it results in a failed login attempt for the user.  So the first 
time somebody logs into the application after some period of time (I think the 
timeout is pretty short on our LDAP server), the user will get one failed 
login attempt before a real one.

I've not seen in the documentation any properties on the JNDIRealm an amount 
of time to hold the connection open before electively disconnecting it.

2005-02-28 07:47:39 JNDIRealm[/iso]:   Searching for myuserid
2005-02-28 07:47:39 JNDIRealm[/iso]:   base: ou=users,dc=company,dc=com  
filter: (&(objectClass=user)(uid=myuserid))
2005-02-28 07:47:39 JNDIRealm[/iso]: Exception performing authentication
javax.naming.CommunicationException: Connection reset [Root exception is 
java.net.SocketException: Connection reset]; remaining 
name 'ou=ou=users,dc=company,dc=com'
        at com.sun.jndi.ldap.LdapCtx.doSearch(LdapCtx.java:1961)
        at com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1806)
        at com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1731)
        at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search
(ComponentDirContext.java:368)
        at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search
(PartialCompositeDirContext.java:338)
        at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search
(PartialCompositeDirContext.java:321)
        at javax.naming.directory.InitialDirContext.search
(InitialDirContext.java:248)
        at org.apache.catalina.realm.JNDIRealm.getUserBySearch
(JNDIRealm.java:1074)
        at org.apache.catalina.realm.JNDIRealm.getUser(JNDIRealm.java:967)
        at org.apache.catalina.realm.JNDIRealm.authenticate(JNDIRealm.java:916)
        at org.apache.catalina.realm.JNDIRealm.authenticate(JNDIRealm.java:809)
        at org.apache.catalina.authenticator.FormAuthenticator.authenticate
(FormAuthenticator.java:235)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke
(AuthenticatorBase.java:446)
        at org.apache.catalina.core.StandardValveContext.invokeNext
(StandardValveContext.java:102)
        at org.apache.catalina.core.StandardPipeline.invoke
(StandardPipeline.java:520)
        at org.apache.catalina.core.StandardHostValve.invoke
(StandardHostValve.java:137)
        at org.apache.catalina.core.StandardValveContext.invokeNext
(StandardValveContext.java:104)
        at org.apache.catalina.valves.ErrorReportValve.invoke
(ErrorReportValve.java:118)
        at org.apache.catalina.core.StandardValveContext.invokeNext
(StandardValveContext.java:102)
        at org.apache.catalina.core.StandardPipeline.invoke
(StandardPipeline.java:520)
        at org.apache.catalina.core.StandardEngineValve.invoke
(StandardEngineValve.java:109)
        at org.apache.catalina.core.StandardValveContext.invokeNext
(StandardValveContext.java:104)
        at org.apache.catalina.core.StandardPipeline.invoke
(StandardPipeline.java:520)
        at org.apache.catalina.core.ContainerBase.invoke
(ContainerBase.java:929)
        at org.apache.coyote.tomcat5.CoyoteAdapter.service
(CoyoteAdapter.java:160)
        at org.apache.jk.server.JkCoyoteHandler.invoke
(JkCoyoteHandler.java:300)
        at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:374)
        at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:743)
        at org.apache.jk.common.ChannelSocket.processConnection
(ChannelSocket.java:675)
        at org.apache.jk.common.SocketConnection.runIt(ChannelSocket.java:866)
        at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run
(ThreadPool.java:684)
        at java.lang.Thread.run(Thread.java:595)
Caused by: java.net.SocketException: Connection reset
        at java.net.SocketInputStream.read(SocketInputStream.java:168)
        at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
        at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
        at java.io.BufferedInputStream.read(BufferedInputStream.java:313)
        at com.sun.jndi.ldap.Connection.run(Connection.java:780)
        ... 1 more

2005-02-28 07:47:39 JNDIRealm[/iso]: Closing directory context
Comment 1 Yoav Shapira 2005-03-24 15:22:47 UTC
The amount of time to hold a connection open on the Tomcat JNDIRealm side
wouldn't matter, though, would it?  It's the LDAP server that's disconnecting
the connection, not Tomcat.

Looking at the current JNDIRealm code, in the authenticate method, it already
tries twice automatically to account for the first-time failure.  It tries once,
and if a CommunicationException occurs (as is the case you report), it tries
again.  However, if the exception message is not null and does not contain
"close", it won't try again.  Maybe it's this check that's the problem.
Comment 2 Remy Maucherat 2005-03-24 18:10:29 UTC
Right, but when handling the said communication exception:
                // If contains the work closed. Then assume socket is closed.
                // If message is null, assume the worst and allow the
                // connection to be closed.
                if (e.getMessage()!=null &&
                    e.getMessage().indexOf("closed") < 0)
                    throw(e);

Here, the text is: exception performing authentication
javax.naming.CommunicationException: Connection reset [Root exception is 
java.net.SocketException: Connection reset]; remaining 
name 'ou=ou=users,dc=company,dc=com'

So no "closed", which means there won't be any retry. This type of hack is bad:
we should just retry once anyway. I'm changing that in 5.5.x.
Comment 3 Will Stranathan 2005-03-25 01:56:43 UTC
I hope when you say you're going to retry once anyway, you ONLY mean if there's
a CommunicationException - if under normal circumstances, a user puts in a bad
password, an exception is thrown - if you try again with any type of exception,
it could trigger an account lockout.  (I'll have to try a bad password to see
what the precise exception is.)
Comment 4 Remy Maucherat 2005-03-25 18:00:51 UTC
We have a CVS browser, so how about verifying in the code that I did the right
thing ?

I did not test it, I simply removed the portions of code which looked highly
suspicious.
Comment 5 Yoav Shapira 2005-03-26 04:20:31 UTC
The code looks decent to me.  Will, please test 5.5.9 which will be out in a
couple of days, and if it still fails reopen this issue.  Thanks.
Comment 6 Tim Funk 2005-03-27 17:04:15 UTC
The patch looks ok to me too. For historical reference see ...
http://cvs.apache.org/viewcvs.cgi/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/JNDIRealm.java
revision 1.12.

At one time, there was even more specific logic looking for "Socket closed".
Comment 7 John Zornig 2007-04-17 17:10:22 UTC
The first login attempt each morning fails because the LDAP server has closed the idle connection. We 
are running Tomcat 5.5.15 It looks to me as though this results in a ServiceUnavailableException rather 
than a CommunicationException which the previous fix addressed.

Apr 17, 2007 8:18:38 AM org.apache.catalina.realm.JNDIRealm authenticate
SEVERE: Exception performing authentication
javax.naming.ServiceUnavailableException: public.ldap.uq.edu.au:389; socket closed; remaining name 
'ou=People,o=The University of Queensland,c=AU'
        at com.sun.jndi.ldap.Connection.readReply(Connection.java:410)
        at com.sun.jndi.ldap.LdapClient.ldapBind(LdapClient.java:340)
        at com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:170)
        at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2637)
        at com.sun.jndi.ldap.LdapCtx.ensureOpen(LdapCtx.java:2546)
        at com.sun.jndi.ldap.LdapCtx.ensureOpen(LdapCtx.java:2520)
        at com.sun.jndi.ldap.LdapCtx.doSearch(LdapCtx.java:1901)
        at com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1806)
        at com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1731)
        at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search(ComponentDirContext.java:368)
        at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:
338)
        at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:
321)
        at javax.naming.directory.InitialDirContext.search(InitialDirContext.java:248)
        at org.apache.catalina.realm.JNDIRealm.getUserBySearch(JNDIRealm.java:1055)
        at org.apache.catalina.realm.JNDIRealm.getUser(JNDIRealm.java:958)
        at org.apache.catalina.realm.JNDIRealm.authenticate(JNDIRealm.java:907)
        at org.apache.catalina.realm.JNDIRealm.authenticate(JNDIRealm.java:808)
        at org.apache.catalina.authenticator.FormAuthenticator.authenticate(FormAuthenticator.java:257)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:416)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
        at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:199)
        at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:282)
        at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:754)
        at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:684)
        at org.apache.jk.common.ChannelSocket$SocketConnection.runIt(ChannelSocket.java:876)
        at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
        at java.lang.Thread.run(Thread.java:595)
Comment 8 Mark Thomas 2007-06-01 18:42:41 UTC
This has been fixed in svn and will be included in 5.5.24 and 6.0.14 onwards.
Comment 9 Keith Ellis 2007-08-28 07:11:17 UTC
(In reply to comment #8)
> This has been fixed in svn and will be included in 5.5.24 and 6.0.14 onwards.

I have recently tried using the JNDIRealm in 6.0.14 and it appears this problem
has not been fixed. I cannot post the message because it is on an internal
system, but the error message is the same "connection reset" problem as before.
Maybe the fix did not reach this release?!
Comment 10 Mark Thomas 2007-09-04 19:11:24 UTC
The "connection reset" message refers to a problem that never existed in the
6.0.x series - it was fixed before that series was started.

Please check your configuration via the users list. If you still see the
problem, you will need to post the stack trace (you can XXX out server names,
ports etc from the stack trace) so we can figure out where the problem lies.
Comment 11 Wynne Carter 2008-02-05 04:46:35 UTC
This is NOT fixed on a Solaris platform in 5.5.25 although 5.5.17 works ok on 
Windows XP. See below....

29-Jan-2008 14:35:30 org.apache.catalina.realm.JNDIRealm authenticate
SEVERE: Exception performing authentication
javax.naming.ServiceUnavailableException: ldap2.dundee.ac.uk:389; socket
closed; remaining name 'o=
dundee'
at com.sun.jndi.ldap.Connection.readReply(Connection.java:416)
at
com.sun.jndi.ldap.LdapClient.getSearchReply(LdapClient.java:611)
at com.sun.jndi.ldap.LdapClient.search(LdapClient.java:534)
at com.sun.jndi.ldap.LdapCtx.doSearch(LdapCtx.java:1948)
at com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1810)
at com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1735)
at
com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search
(ComponentDirContext.java:368)
at
com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search
(PartialCompositeDirContext.ja
va:338)
at
com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search
(PartialCompositeDirContext.ja
va:321)
at
javax.naming.directory.InitialDirContext.search(InitialDirContext.java:248)
at
org.apache.catalina.realm.JNDIRealm.getUserBySearch(JNDIRealm.java:1051)
at
org.apache.catalina.realm.JNDIRealm.getUser(JNDIRealm.java:959)
at
org.apache.catalina.realm.JNDIRealm.authenticate(JNDIRealm.java:908)
at
org.apache.catalina.realm.JNDIRealm.authenticate(JNDIRealm.java:809)
at
org.apache.catalina.authenticator.FormAuthenticator.authenticate
(FormAuthenticator.java:
258)
at
org.apache.catalina.authenticator.AuthenticatorBase.invoke
(AuthenticatorBase.java:417)
at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
at
org.apache.catalina.core.StandardEngineValve.invoke
(StandardEngineValve.java:108)
at
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:151)
at
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:870)
at org.apache.coyote.http11.Http11BaseProtocol
$Http11ConnectionHandler.processConnection(Ht
tp11BaseProtocol.java:665)
at
org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket
(PoolTcpEndpoint.java:528)
at
org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt
(LeaderFollowerWorkerThread.j
ava:81)
at org.apache.tomcat.util.threads.ThreadPool
$ControlRunnable.run(ThreadPool.java:685)
at java.lang.Thread.run(Thread.java:619)
Comment 12 Mark Thomas 2008-02-05 10:53:22 UTC
(In reply to comment #11)
> This is NOT fixed on a Solaris platform in 5.5.25 although 5.5.17 works ok on 
> Windows XP. See below....

That it works on an earlier release on XP and fails on a later release on
Solaris is a strong indication of a configuration problem on Solaris. That said,
there was a minor improvement to the fix in 5.5.26. I don't think it will help
but it is worth trying.

If you still have problems, please use the users list in the first instance as
this looks like a configuration issue.

Comment 13 Wynne Carter 2008-02-12 02:14:18 UTC
(In reply to comment #12)
> (In reply to comment #11)
> > This is NOT fixed on a Solaris platform in 5.5.25 although 5.5.17 works ok 
on 
> > Windows XP. See below....
> That it works on an earlier release on XP and fails on a later release on
> Solaris is a strong indication of a configuration problem on Solaris. That 
said,
> there was a minor improvement to the fix in 5.5.26. I don't think it will help
> but it is worth trying.
> If you still have problems, please use the users list in the first instance as
> this looks like a configuration issue.

No response from users list. Its just this first time delay after the remote 
server has closed the connection thats the pain.  (it eventually authenticates 
ok once the timeout has expired). Which is this timeout? Can't find what 
configuration to look at ( server.xml 's match on both platforms ). 

Some pointers much appreciated.