From e8c6a32e6fbd90c90faa2133c788eb1e8132c536 Mon Sep 17 00:00:00 2001 From: Matthew Inger Date: Wed, 11 Jan 2017 12:54:58 -0500 Subject: [PATCH] Check Response Code before using conn.getInputStream If the response code is a non 200, use conn.getErrorStream instead. This will allow things like token refresh errors to be handled correctly. Currently, you get an AuthorizationException with a FileNotFoundException as it's cause due to the call to conn.getInputStream. --- .../openid/appauth/AuthorizationService.java | 9 +++- .../appauth/AuthorizationServiceTest.java | 42 +++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/library/java/net/openid/appauth/AuthorizationService.java b/library/java/net/openid/appauth/AuthorizationService.java index ab0d541d..b0731b23 100644 --- a/library/java/net/openid/appauth/AuthorizationService.java +++ b/library/java/net/openid/appauth/AuthorizationService.java @@ -345,7 +345,12 @@ protected JSONObject doInBackground(Void... voids) { wr.write(queryData); wr.flush(); - is = conn.getInputStream(); + if (conn.getResponseCode() >= HttpURLConnection.HTTP_OK + && conn.getResponseCode() < HttpURLConnection.HTTP_MULT_CHOICE) { + is = conn.getInputStream(); + } else { + is = conn.getErrorStream(); + } String response = Utils.readInputStream(is); return new JSONObject(response); } catch (IOException ex) { @@ -378,7 +383,7 @@ protected void onPostExecute(JSONObject json) { error, json.getString(AuthorizationException.PARAM_ERROR_DESCRIPTION), UriUtil.parseUriIfAvailable( - json.getString(AuthorizationException.PARAM_ERROR_URI))); + json.optString(AuthorizationException.PARAM_ERROR_URI))); } catch (JSONException jsonEx) { ex = AuthorizationException.fromTemplate( GeneralErrors.JSON_DESERIALIZATION_ERROR, diff --git a/library/javatests/net/openid/appauth/AuthorizationServiceTest.java b/library/javatests/net/openid/appauth/AuthorizationServiceTest.java index 7f239a66..88335699 100644 --- a/library/javatests/net/openid/appauth/AuthorizationServiceTest.java +++ b/library/javatests/net/openid/appauth/AuthorizationServiceTest.java @@ -94,6 +94,12 @@ public class AuthorizationServiceTest { + " \"application_type\": " + RegistrationRequest.APPLICATION_TYPE_NATIVE + "\n" + "}"; + private static final String INVALID_GRANT_RESPONSE_JSON = "{\n" + + " \"error\": \"invalid_grant\",\n" + + " \"error_description\": \"invalid_grant description\"\n" + + "}"; + private static final int TEST_INVALID_GRANT_CODE = 2002; + private AuthorizationCallback mAuthCallback; private RegistrationCallback mRegistrationCallback; private AuthorizationService mService; @@ -170,6 +176,7 @@ public void testAuthorizationRequest_afterDispose() throws Exception { public void testTokenRequest() throws Exception { InputStream is = new ByteArrayInputStream(AUTH_CODE_EXCHANGE_RESPONSE_JSON.getBytes()); when(mHttpConnection.getInputStream()).thenReturn(is); + when(mHttpConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); TokenRequest request = getTestAuthCodeExchangeRequest(); mService.performTokenRequest(request, mAuthCallback); mAuthCallback.waitForCallback(); @@ -182,6 +189,7 @@ public void testTokenRequest() throws Exception { public void testTokenRequest_withBasicAuth() throws Exception { ClientSecretBasic csb = new ClientSecretBasic(TEST_CLIENT_SECRET); InputStream is = new ByteArrayInputStream(AUTH_CODE_EXCHANGE_RESPONSE_JSON.getBytes()); + when(mHttpConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); when(mHttpConnection.getInputStream()).thenReturn(is); TokenRequest request = getTestAuthCodeExchangeRequest(); mService.performTokenRequest(request, csb, mAuthCallback); @@ -198,6 +206,7 @@ public void testTokenRequest_withPostAuth() throws Exception { ClientSecretPost csp = new ClientSecretPost(TEST_CLIENT_SECRET); InputStream is = new ByteArrayInputStream(AUTH_CODE_EXCHANGE_RESPONSE_JSON.getBytes()); when(mHttpConnection.getInputStream()).thenReturn(is); + when(mHttpConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); TokenRequest request = getTestAuthCodeExchangeRequest(); mService.performTokenRequest(request, csp, mAuthCallback); mAuthCallback.waitForCallback(); @@ -209,10 +218,35 @@ public void testTokenRequest_withPostAuth() throws Exception { assertTokenRequestBody(postBody, expectedRequestBody); } + @Test + public void testTokenRequest_withInvalidGrant() throws Exception { + ClientSecretPost csp = new ClientSecretPost(TEST_CLIENT_SECRET); + InputStream is = new ByteArrayInputStream(INVALID_GRANT_RESPONSE_JSON.getBytes()); + when(mHttpConnection.getErrorStream()).thenReturn(is); + when(mHttpConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_BAD_REQUEST); + TokenRequest request = getTestAuthCodeExchangeRequest(); + mService.performTokenRequest(request, csp, mAuthCallback); + mAuthCallback.waitForCallback(); + assertInvalidGrant(mAuthCallback.error); + } + + @Test + public void testTokenRequest_withInvalidGrant2() throws Exception { + ClientSecretPost csp = new ClientSecretPost(TEST_CLIENT_SECRET); + InputStream is = new ByteArrayInputStream(INVALID_GRANT_RESPONSE_JSON.getBytes()); + when(mHttpConnection.getErrorStream()).thenReturn(is); + when(mHttpConnection.getResponseCode()).thenReturn(199); + TokenRequest request = getTestAuthCodeExchangeRequest(); + mService.performTokenRequest(request, csp, mAuthCallback); + mAuthCallback.waitForCallback(); + assertInvalidGrant(mAuthCallback.error); + } + @Test public void testTokenRequest_IoException() throws Exception { Exception ex = new IOException(); when(mHttpConnection.getInputStream()).thenThrow(ex); + when(mHttpConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); mService.performTokenRequest(getTestAuthCodeExchangeRequest(), mAuthCallback); mAuthCallback.waitForCallback(); assertNotNull(mAuthCallback.error); @@ -272,6 +306,14 @@ private void assertTokenResponse(TokenResponse response, TokenRequest expectedRe assertEquals(TEST_ID_TOKEN, response.idToken); } + private void assertInvalidGrant(AuthorizationException error) { + assertNotNull(error); + assertEquals(AuthorizationException.TYPE_OAUTH_TOKEN_ERROR, error.type); + assertEquals(TEST_INVALID_GRANT_CODE, error.code); + assertEquals("invalid_grant", error.error); + assertEquals("invalid_grant description", error.errorDescription); + } + private void assertRegistrationResponse(RegistrationResponse response, RegistrationRequest expectedRequest) { assertThat(response).isNotNull();