diff --git a/src/main/java/com/pusher/client/util/BaseHttpAuthClient.java b/src/main/java/com/pusher/client/util/BaseHttpAuthClient.java index c5774380..97af8aae 100644 --- a/src/main/java/com/pusher/client/util/BaseHttpAuthClient.java +++ b/src/main/java/com/pusher/client/util/BaseHttpAuthClient.java @@ -134,18 +134,26 @@ protected String performAuthRequest() { wr.flush(); wr.close(); - // Read response - final InputStream is = connection.getInputStream(); - final BufferedReader rd = new BufferedReader(new InputStreamReader(is)); - String line; + // Read response. For error statuses, getInputStream() throws, so the + // body the server sent is read from the error stream instead. + final int responseHttpStatus = connection.getResponseCode(); + final InputStream is = responseHttpStatus >= HttpURLConnection.HTTP_BAD_REQUEST + ? connection.getErrorStream() + : connection.getInputStream(); final StringBuilder response = new StringBuilder(); - while ((line = rd.readLine()) != null) { - response.append(line); + if (is != null) { + final BufferedReader rd = new BufferedReader(new InputStreamReader(is)); + String line; + while ((line = rd.readLine()) != null) { + response.append(line); + } + rd.close(); } - rd.close(); - final int responseHttpStatus = connection.getResponseCode(); if (responseHttpStatus != 200 && responseHttpStatus != 201) { + if (response.length() == 0) { + throw authFailureException("Server returned HTTP response code: " + responseHttpStatus); + } throw authFailureException(response.toString()); } diff --git a/src/test/java/com/pusher/client/util/HttpChannelAuthorizerTest.java b/src/test/java/com/pusher/client/util/HttpChannelAuthorizerTest.java index 106c9626..d014c4b4 100644 --- a/src/test/java/com/pusher/client/util/HttpChannelAuthorizerTest.java +++ b/src/test/java/com/pusher/client/util/HttpChannelAuthorizerTest.java @@ -1,12 +1,22 @@ package com.pusher.client.util; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import com.pusher.client.AuthorizationFailureException; +import com.sun.net.httpserver.HttpServer; + import org.junit.Test; +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; + public class HttpChannelAuthorizerTest { @Test(expected = IllegalArgumentException.class) @@ -31,4 +41,26 @@ public void testNon200ResponseThrowsAuthorizationFailureException() { final HttpChannelAuthorizer auth = new HttpChannelAuthorizer("https://127.0.0.1/no-way-this-is-a-valid-url"); auth.authorize("private-fish", "some socket id"); } + + @Test + public void testErrorResponseBodyIsUsedAsAuthorizationFailureMessage() throws IOException { + final byte[] errorBody = "{\"error\":\"forbidden\"}".getBytes(StandardCharsets.UTF_8); + final HttpServer server = HttpServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0); + server.createContext("/auth", exchange -> { + exchange.sendResponseHeaders(403, errorBody.length); + try (OutputStream os = exchange.getResponseBody()) { + os.write(errorBody); + } + }); + server.start(); + try { + final HttpChannelAuthorizer auth = new HttpChannelAuthorizer("http://127.0.0.1:" + server.getAddress().getPort() + "/auth"); + auth.authorize("private-fish", "some socket id"); + fail("Expected AuthorizationFailureException"); + } catch (final AuthorizationFailureException e) { + assertEquals("{\"error\":\"forbidden\"}", e.getMessage()); + } finally { + server.stop(0); + } + } } diff --git a/src/test/java/com/pusher/client/util/HttpUserAuthenticatorTest.java b/src/test/java/com/pusher/client/util/HttpUserAuthenticatorTest.java index 9edde256..c9e12198 100644 --- a/src/test/java/com/pusher/client/util/HttpUserAuthenticatorTest.java +++ b/src/test/java/com/pusher/client/util/HttpUserAuthenticatorTest.java @@ -1,12 +1,22 @@ package com.pusher.client.util; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import com.pusher.client.AuthenticationFailureException; +import com.sun.net.httpserver.HttpServer; + import org.junit.Test; +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; + public class HttpUserAuthenticatorTest { @Test(expected = IllegalArgumentException.class) @@ -31,4 +41,26 @@ public void testNon200ResponseThrowsAuthenticationFailtureException() { final HttpUserAuthenticator auth = new HttpUserAuthenticator("https://127.0.0.1/no-way-this-is-a-valid-url"); auth.authenticate("some socket id"); } + + @Test + public void testErrorResponseBodyIsUsedAsAuthenticationFailureMessage() throws IOException { + final byte[] errorBody = "{\"error\":\"forbidden\"}".getBytes(StandardCharsets.UTF_8); + final HttpServer server = HttpServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0); + server.createContext("/auth", exchange -> { + exchange.sendResponseHeaders(403, errorBody.length); + try (OutputStream os = exchange.getResponseBody()) { + os.write(errorBody); + } + }); + server.start(); + try { + final HttpUserAuthenticator auth = new HttpUserAuthenticator("http://127.0.0.1:" + server.getAddress().getPort() + "/auth"); + auth.authenticate("some socket id"); + fail("Expected AuthenticationFailureException"); + } catch (final AuthenticationFailureException e) { + assertEquals("{\"error\":\"forbidden\"}", e.getMessage()); + } finally { + server.stop(0); + } + } }