From 125f7d91df8f5e5f5d05c45e72a57929fadcaab4 Mon Sep 17 00:00:00 2001 From: Mauro Mugnaini Date: Mon, 21 Dec 2020 18:00:08 +0100 Subject: [PATCH] Added parsing of the response if is JSON and added specific exception to handle also this response --- .../oidc/rest/OpenIdConnectRESTHelper.java | 119 +++++++++++++----- .../OpenIdConnectRESTHelperException.java | 59 +++++++++ .../org/gcube/oidc/rest/RestHelperTest.java | 40 +++--- 3 files changed, 172 insertions(+), 46 deletions(-) create mode 100644 src/main/java/org/gcube/oidc/rest/OpenIdConnectRESTHelperException.java diff --git a/src/main/java/org/gcube/oidc/rest/OpenIdConnectRESTHelper.java b/src/main/java/org/gcube/oidc/rest/OpenIdConnectRESTHelper.java index 700a137..591d1f6 100644 --- a/src/main/java/org/gcube/oidc/rest/OpenIdConnectRESTHelper.java +++ b/src/main/java/org/gcube/oidc/rest/OpenIdConnectRESTHelper.java @@ -18,6 +18,9 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,6 +28,11 @@ public class OpenIdConnectRESTHelper { protected static final Logger logger = LoggerFactory.getLogger(OpenIdConnectRESTHelper.class); + private static final String RESPONSE_ERROR_KEY = "error"; + private static final String RESPONSE_ERROR_INVALID_GRANT = "invalid_grant"; + private static final String RESPONSE_ERROR_DESCRIPTION_KEY = "error_description"; + private static final String RESPONSE_ERROR_MESSAGE_TINA = "Token is not active"; + public static String buildLoginRequestURL(URL loginURL, String clientId, String state, String redirectURI) throws UnsupportedEncodingException { @@ -47,11 +55,21 @@ public class OpenIdConnectRESTHelper { return q; } - public static JWTToken queryClientToken(String clientId, String clientSecret, URL tokenURL) throws Exception { + public static JWTToken queryClientToken(String clientId, String clientSecret, URL tokenURL) + throws OpenIdConnectRESTHelperException { + Map> params = new HashMap<>(); params.put("grant_type", Arrays.asList("client_credentials")); - params.put("client_id", Arrays.asList(URLEncoder.encode(clientId, "UTF-8"))); - params.put("client_secret", Arrays.asList(URLEncoder.encode(clientSecret, "UTF-8"))); + try { + params.put("client_id", Arrays.asList(URLEncoder.encode(clientId, "UTF-8"))); + } catch (UnsupportedEncodingException e) { + logger.error("Cannot URL encode 'client_id'", e); + } + try { + params.put("client_secret", Arrays.asList(URLEncoder.encode(clientSecret, "UTF-8"))); + } catch (UnsupportedEncodingException e) { + logger.error("Cannot URL encode 'client_secret'", e); + } return performQueryTokenWithPOST(tokenURL, null, params); } @@ -68,30 +86,45 @@ public class OpenIdConnectRESTHelper { } public static JWTToken performQueryTokenWithPOST(URL tokenURL, String authorization, - Map> params) - throws Exception { + Map> params) throws OpenIdConnectRESTHelperException { logger.debug("Querying access token from OIDC server with URL: {}", tokenURL); - HttpURLConnection httpURLConnection = performURLEncodedPOSTSendData(tokenURL, params, authorization); + StringBuilder sb; + try { + HttpURLConnection httpURLConnection = performURLEncodedPOSTSendData(tokenURL, params, authorization); - StringBuilder sb = new StringBuilder(); - int httpResultCode = httpURLConnection.getResponseCode(); - logger.trace("HTTP Response code: {}", httpResultCode); - if (httpResultCode != HttpURLConnection.HTTP_OK) { - BufferedReader br = new BufferedReader(new InputStreamReader(httpURLConnection.getErrorStream(), "UTF-8")); - String line = null; - while ((line = br.readLine()) != null) { - sb.append(line + "\n"); + sb = new StringBuilder(); + int httpResultCode = httpURLConnection.getResponseCode(); + logger.trace("HTTP Response code: {}", httpResultCode); + String responseContentType = httpURLConnection.getContentType(); + if (responseContentType != null) { + logger.debug("Response content type is: {}", responseContentType); + } else { + responseContentType = ""; } - br.close(); - throw new Exception("Unable to get token " + sb); - } else { - BufferedReader br = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(), "UTF-8")); - String line = null; - while ((line = br.readLine()) != null) { - sb.append(line + "\n"); + if (httpResultCode != HttpURLConnection.HTTP_OK) { + BufferedReader br = new BufferedReader( + new InputStreamReader(httpURLConnection.getErrorStream(), "UTF-8")); + + String line = null; + while ((line = br.readLine()) != null) { + sb.append(line + "\n"); + } + br.close(); + throw OpenIdConnectRESTHelperException.create("Unable to get token", httpResultCode, + responseContentType, sb.toString()); + } else { + BufferedReader br = new BufferedReader( + new InputStreamReader(httpURLConnection.getInputStream(), "UTF-8")); + + String line = null; + while ((line = br.readLine()) != null) { + sb.append(line + "\n"); + } + br.close(); } - br.close(); + } catch (IOException e) { + throw new OpenIdConnectRESTHelperException("Unable to get the token", e); } return JWTToken.fromString(sb.toString()); } @@ -119,11 +152,15 @@ public class OpenIdConnectRESTHelper { } public static JWTToken queryUMAToken(URL tokenUrl, String authorizationToken, String audience, - List permissions) throws Exception { + List permissions) throws OpenIdConnectRESTHelperException { Map> params = new HashMap<>(); params.put("grant_type", Arrays.asList("urn:ietf:params:oauth:grant-type:uma-ticket")); - params.put("audience", Arrays.asList(URLEncoder.encode(audience, "UTF-8"))); + try { + params.put("audience", Arrays.asList(URLEncoder.encode(audience, "UTF-8"))); + } catch (UnsupportedEncodingException e) { + logger.error("Cannot URL encode 'audience'", e); + } if (permissions != null && !permissions.isEmpty()) { params.put( "permission", permissions.stream().map(s -> { @@ -137,25 +174,34 @@ public class OpenIdConnectRESTHelper { return performQueryTokenWithPOST(tokenUrl, authorizationToken, params); } - public static JWTToken refreshToken(URL tokenURL, JWTToken token) throws Exception { + public static JWTToken refreshToken(URL tokenURL, JWTToken token) throws OpenIdConnectRESTHelperException { return refreshToken(tokenURL, null, null, token); } - public static JWTToken refreshToken(URL tokenURL, String clientId, JWTToken token) throws Exception { + public static JWTToken refreshToken(URL tokenURL, String clientId, JWTToken token) + throws OpenIdConnectRESTHelperException { return refreshToken(tokenURL, clientId, null, token); } public static JWTToken refreshToken(URL tokenURL, String clientId, String clientSecret, JWTToken token) - throws Exception { + throws OpenIdConnectRESTHelperException { Map> params = new HashMap<>(); params.put("grant_type", Arrays.asList("refresh_token")); if (clientId == null) { clientId = getClientIdFromToken(token); } - params.put("client_id", Arrays.asList(URLEncoder.encode(clientId, "UTF-8"))); + try { + params.put("client_id", Arrays.asList(URLEncoder.encode(clientId, "UTF-8"))); + } catch (UnsupportedEncodingException e) { + logger.error("Cannot URL encode 'client_id'", e); + } if (clientSecret != null) { - params.put("client_secret", Arrays.asList(URLEncoder.encode(clientSecret, "UTF-8"))); + try { + params.put("client_secret", Arrays.asList(URLEncoder.encode(clientSecret, "UTF-8"))); + } catch (UnsupportedEncodingException e) { + logger.error("Cannot URL encode 'client_secret'", e); + } } params.put("refresh_token", Arrays.asList(token.getRefreshTokenString())); return performQueryTokenWithPOST(tokenURL, null, params); @@ -226,9 +272,9 @@ public class OpenIdConnectRESTHelper { conn.setRequestProperty("Authorization", authorization); } String contentType = conn.getContentType(); - int contentLenght = conn.getContentLength(); + int contentLength = conn.getContentLength(); - logger.debug("Getting the stream to a %d bytes lenght resource with MIME: %s", contentLenght, contentType); + logger.debug("Getting the stream to a {} bytes lenght resource with MIME: {}", contentLength, contentType); InputStream is = conn.getInputStream(); buffer = new ByteArrayOutputStream(); @@ -247,4 +293,15 @@ public class OpenIdConnectRESTHelper { } return null; } + + public static boolean isTokenNotActiveError(String jsonString) { + try { + JSONObject json = (JSONObject) new JSONParser().parse(jsonString); + return RESPONSE_ERROR_INVALID_GRANT.equals(json.get(RESPONSE_ERROR_KEY)) + && RESPONSE_ERROR_MESSAGE_TINA.equals(json.get(RESPONSE_ERROR_DESCRIPTION_KEY)); + } catch (ParseException e) { + // Is an unparseable JSON + } + return false; + } } \ No newline at end of file diff --git a/src/main/java/org/gcube/oidc/rest/OpenIdConnectRESTHelperException.java b/src/main/java/org/gcube/oidc/rest/OpenIdConnectRESTHelperException.java new file mode 100644 index 0000000..65fae46 --- /dev/null +++ b/src/main/java/org/gcube/oidc/rest/OpenIdConnectRESTHelperException.java @@ -0,0 +1,59 @@ +package org.gcube.oidc.rest; + +public class OpenIdConnectRESTHelperException extends Exception { + + private static final long serialVersionUID = -1615745541003534684L; + + private int status = -1; + private String contentType = null; + private String responseString = null; + + public static OpenIdConnectRESTHelperException create(String message, int status, String contentType, + String textResponse) { + + OpenIdConnectRESTHelperException e = new OpenIdConnectRESTHelperException( + "[" + status + "] " + message + " (" + contentType + ") :" + textResponse); + + e.setStatus(status); + e.setContentType(contentType); + e.setResponseString(textResponse); + return e; + } + + public OpenIdConnectRESTHelperException(String message) { + super(message); + } + + public OpenIdConnectRESTHelperException(String message, Exception cause) { + super(message, cause); + } + + public void setStatus(int status) { + this.status = status; + } + + public int getStatus() { + return status; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public String getContentType() { + return contentType; + } + + public boolean hasJSONPayload() { + return getContentType().endsWith("json"); + } + + public void setResponseString(String responseString) { + this.responseString = responseString; + } + + public String getResponseString() { + return responseString; + } + +} diff --git a/src/test/java/org/gcube/oidc/rest/RestHelperTest.java b/src/test/java/org/gcube/oidc/rest/RestHelperTest.java index 5206d00..656cdb9 100644 --- a/src/test/java/org/gcube/oidc/rest/RestHelperTest.java +++ b/src/test/java/org/gcube/oidc/rest/RestHelperTest.java @@ -1,11 +1,8 @@ package org.gcube.oidc.rest; -import static org.junit.Assert.assertNotNull; - +import java.net.MalformedURLException; import java.net.URL; -import org.junit.Test; - public class RestHelperTest { public RestHelperTest() { @@ -14,24 +11,37 @@ public class RestHelperTest { /** * To be re-enabled when the token is took programmatically */ - // @Test - public void getAvatar() throws Exception { + public void getAvatar() throws MalformedURLException { String accessTokenBearer = "Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJSSklZNEpoNF9qdDdvNmREY0NlUDFfS1l0akcxVExXVW9oMkQ2Tzk1bFNBIn0.eyJleHAiOjE1OTc0MTc4MzEsImlhdCI6MTU5NzQxNzUzMSwiYXV0aF90aW1lIjoxNTk3NDE3NTI5LCJqdGkiOiI5ZjAwMzM1Yy1jM2NlLTQ3ZTktYTRhZS05MmM4ZDc1NmUyOWMiLCJpc3MiOiJodHRwczovL2FjY291bnRzLmRldi5kNHNjaWVuY2Uub3JnL2F1dGgvcmVhbG1zL2Q0c2NpZW5jZSIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiIzZTcwMzBhNS00M2MzLTRiNjUtYWMwYS0xNTJkYmU3MDI0NTIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJwcmVwcm9kMi5kNHNjaWVuY2Uub3JnIiwic2Vzc2lvbl9zdGF0ZSI6IjAxOWEzMTVjLTY3MTQtNDQyZi1hNDE2LWM4MjAxNWFhYzFmNSIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoib3BlbmlkIGVtYWlsIHByb2ZpbGUiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6Ik1hdXJvIE11Z25haW5pIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidGhlbWF4eDc2IiwiZ2l2ZW5fbmFtZSI6Ik1hdXJvIiwiZmFtaWx5X25hbWUiOiJNdWduYWluaSIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS0vQU9oMTRHaUFxUzZRc00xaDNXV1BqMU15VUdlRFA2VnFaQlhtOTZ4cHhZLXNndyIsImVtYWlsIjoidGhlbWF4eDc2QGdtYWlsLmNvbSJ9.WMddlUQujlpmzW07Lrk50vOyWpiT1Tp_RsBWRbzyrQnu5EQQSCq1uGOuSf7Z3VZFv8fbnzWekMZRNzhngEddzOQHgAlsgRdqNI_-ucjmb_8SfR2I5PkYJLTG0jF-Urqi-GvfJtLr2B8dBDnMDO6FLFsg1e5qb-5HkV60eEtY2Wult1PGxlkD05w-K2w513IOMkVIl25ZxKbP61-Iu1qfV_q3QFvUHl_pdqL7uKC5bkl1lqTVeuCwrXrKubHnKc-UzpHtHp8XY0Iao7LdLtON7SODYhU8EkZ860ZlFTSCszmLUpSH4t_shSk9Fiqd8wBKAet5ngmyAPzKx9TT2FK65g"; URL avatarURL = new URL("https://accounts.dev.d4science.org/auth/realms/d4science/avatar-provider/"); byte[] avatarBytes = OpenIdConnectRESTHelper.getUserAvatar(avatarURL, accessTokenBearer); - assertNotNull(avatarBytes); +// assertNotNull(avatarBytes); } // @Test - public void getExp() throws Exception { - URL tokenURL = new URL("https://nubis2.int.d4science.net/auth/realms/d4science/protocol/openid-connect/token"); - JWTToken token = OpenIdConnectRESTHelper.queryClientToken("lr62_portal", "28726d01-9f24-4ef4-a057-3d208d96aaa0", - tokenURL); - System.out.println(token.getExpAsDate()); - System.out.println(token.getAzp()); - Thread.sleep((token.getExp() * 1000 - System.currentTimeMillis() + 5000)); - System.out.println(token.isExpired()); + public void getExp() throws MalformedURLException, OpenIdConnectRESTHelperException, InterruptedException { + URL tokenURL = new URL("https://accounts.dev.d4science.org/auth/realms/d4science/protocol/openid-connect/token"); + JWTToken token = OpenIdConnectRESTHelper.queryClientToken("lr62_portal", "28726d01-9f24-4ef4-a057-3d208d96aaa0", + tokenURL); + System.out.println(token.getExpAsDate()); + System.out.println(token.getAzp()); + Thread.sleep((token.getExp() * 1000 - System.currentTimeMillis() + 5000)); + System.out.println(token.isExpired()); + } + + public static void main(String[] args) throws Exception { + RestHelperTest rht = new RestHelperTest(); +// rht.getAvatar(); + try { + rht.getExp(); + } catch (OpenIdConnectRESTHelperException e) { + if (e.hasJSONPayload()) { + System.out.println("JSON response: " + e.getResponseString()); + } else { + System.out.println("Plain text response: " + e.getResponseString()); + } + } } }