484621 - Client hangs till timeout when Authentication.authenticate() throws exception.

Fixed by surrounding the call to Authentication.authenticate() with a
try/catch and acting appropriately in case of exceptions.
This commit is contained in:
Simone Bordet 2016-01-05 11:02:52 +01:00
parent b5db18378d
commit 0050ad5a99
2 changed files with 73 additions and 18 deletions

View File

@ -135,27 +135,36 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
return;
}
final Authentication.Result authnResult = authentication.authenticate(request, response, headerInfo, conversation);
if (LOG.isDebugEnabled())
LOG.debug("Authentication result {}", authnResult);
if (authnResult == null)
try
{
forwardSuccessComplete(request, response);
return;
}
conversation.setAttribute(AUTHENTICATION_ATTRIBUTE, true);
Request newRequest = client.copyRequest(request, request.getURI());
authnResult.apply(newRequest);
newRequest.onResponseSuccess(new Response.SuccessListener()
{
@Override
public void onSuccess(Response response)
final Authentication.Result authnResult = authentication.authenticate(request, response, headerInfo, conversation);
if (LOG.isDebugEnabled())
LOG.debug("Authentication result {}", authnResult);
if (authnResult == null)
{
client.getAuthenticationStore().addAuthenticationResult(authnResult);
forwardSuccessComplete(request, response);
return;
}
}).send(null);
conversation.setAttribute(AUTHENTICATION_ATTRIBUTE, true);
Request newRequest = client.copyRequest(request, request.getURI());
authnResult.apply(newRequest);
newRequest.onResponseSuccess(new Response.SuccessListener()
{
@Override
public void onSuccess(Response response)
{
client.getAuthenticationStore().addAuthenticationResult(authnResult);
}
}).send(null);
}
catch (Throwable x)
{
if (LOG.isDebugEnabled())
LOG.debug("Authentication failed", x);
forwardFailureComplete(request, null, response, x);
}
}
private void forwardSuccessComplete(HttpRequest request, Response response)

View File

@ -34,6 +34,8 @@ import org.eclipse.jetty.client.api.Authentication;
import org.eclipse.jetty.client.api.AuthenticationStore;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.client.util.BasicAuthentication;
import org.eclipse.jetty.client.util.DigestAuthentication;
import org.eclipse.jetty.security.Authenticator;
@ -47,6 +49,7 @@ import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.Attributes;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.util.ssl.SslContextFactory;
@ -320,4 +323,47 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest
Assert.assertNotNull(response);
Assert.assertEquals(401, response.getStatus());
}
@Test
public void test_Authentication_ThrowsException() throws Exception
{
startBasic(new EmptyServerHandler());
// Request without Authentication would cause a 401,
// but the client will throw an exception trying to
// send the credentials to the server.
final String cause = "thrown_explicitly_by_test";
client.getAuthenticationStore().addAuthentication(new Authentication()
{
@Override
public boolean matches(String type, URI uri, String realm)
{
return true;
}
@Override
public Result authenticate(Request request, ContentResponse response, HeaderInfo headerInfo, Attributes context)
{
throw new RuntimeException(cause);
}
});
final CountDownLatch latch = new CountDownLatch(1);
client.newRequest("localhost", connector.getLocalPort())
.scheme(scheme)
.path("/secure")
.timeout(5, TimeUnit.SECONDS)
.send(new Response.CompleteListener()
{
@Override
public void onComplete(Result result)
{
Assert.assertTrue(result.isFailed());
Assert.assertEquals(cause, result.getFailure().getMessage());
latch.countDown();
}
});
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
}
}