Maciej Miklas created DIRKRB-620:
------------------------------------
Summary: KerberosChannel does not read whole response
Key: DIRKRB-620
URL: https://issues.apache.org/jira/browse/DIRKRB-620
Project: Directory Kerberos
Issue Type: Bug
Components: changepw
Reporter: Maciej Miklas
We have in production some customers who cannot change their password. In log
we observe following exception:
{noformat}
20.02.2017 10:59:11,987 DEBUG [http-bio-127.22.1.62-80-exec-383]
org.apache.directory.api.asn1.ber.Asn1Decoder -
<<<==========================================
20.02.2017 10:59:11,987 ERROR [http-bio-127.22.1.62-80-exec-383]
org.apache.directory.kerberos.client.KdcConnection - Authentication failed :
timeout occured
20.02.2017 10:59:11,987 WARN [http-bio-127.22.1.62-80-exec-383]
org.apache.directory.kerberos.client.KdcConnection - failed to change the
password
org.apache.directory.shared.kerberos.exceptions.KerberosException: TimeOut
occured
at
org.apache.directory.kerberos.client.KdcConnection._getTgt(KdcConnection.java:294)
at
org.apache.directory.kerberos.client.KdcConnection.getTgt(KdcConnection.java:181)
at
org.apache.directory.kerberos.client.KdcConnection.changePassword(KdcConnection.java:535)
{noformat}
Real reason for this error is incorrect socket implementation:
{code:title=org.apache.directory.kerberos.client.KerberosChannel|borderStyle=solid}
byte[] tmp = new byte[ 1024 * 8 ];
while ( in.available() > 0 )
{
int read = in.read( tmp );
repData.put( tmp, 0, read );
}
{code}
You should not relay on _available()_ - it returns only assumption. In our case
for some users it returns 0 before whole message has been consumed.
In order to fix it, you should first read header of the message in order to
figure out its size. Now use _in.read(...)_ until you consume expected amount
of bytes. Eventually you will run into timeout, which is fine and happens if
server does not keep its promise from header and cuts the message.
I've changed code into this:
{code:title=org.apache.directory.kerberos.client.KerberosChannel|borderStyle=solid}
byte[] tmp = new byte[1024 * 8];
int read;
try {
while ((read = in.read(tmp)) > 0) {
repData.put(tmp, 0, read);
}
}
catch (SocketTimeoutException e) {
// OK
}
{code}
and customers now can change their password. Obviously this implementation is
*incorrect*, because it runs into timeout with every call. Bu it proves that
using _available()_ does not work.
--
This message was sent by Atlassian JIRA
(v6.3.15#6346)