From 99358c1f62c772bcd6ed8ed32475a33259ebf657 Mon Sep 17 00:00:00 2001 From: Alfredo Oliviero Date: Thu, 4 Apr 2024 17:03:00 +0200 Subject: [PATCH] exchange uses custom context header instead of audience parameter --- .../OpenIdConnectRESTHelperExtended.java | 125 +++++++++++++++--- .../gcube/portlets/admin/RPTTokenReader.java | 34 ++--- 2 files changed, 121 insertions(+), 38 deletions(-) diff --git a/src/main/java/org/gcube/portlets/admin/OpenIdConnectRESTHelperExtended.java b/src/main/java/org/gcube/portlets/admin/OpenIdConnectRESTHelperExtended.java index 418d698..f4e9f23 100644 --- a/src/main/java/org/gcube/portlets/admin/OpenIdConnectRESTHelperExtended.java +++ b/src/main/java/org/gcube/portlets/admin/OpenIdConnectRESTHelperExtended.java @@ -1,6 +1,12 @@ package org.gcube.portlets.admin; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.ProtocolException; import java.net.URL; import java.net.URLEncoder; import java.util.Arrays; @@ -18,24 +24,30 @@ import org.slf4j.LoggerFactory; public class OpenIdConnectRESTHelperExtended extends OpenIdConnectRESTHelper { protected static final Logger logger = LoggerFactory.getLogger(OpenIdConnectRESTHelperExtended.class); - /** - * Queries from the OIDC server an exchanged token by using provided access token, for the given audience (context), + * Queries from the OIDC server an exchanged token by using provided access + * token, for the given audience (context), * in URLEncoded form or not, and optionally a list of permissions. * - * @param tokenUrl the token endpoint {@link URL} of the OIDC server - * @param authorization the auth token (the access token URLEncoded by the "Bearer " string) - * @param audience the audience (context) where to request the issuing of the ticket (URLEncoded) - * @param permissions a list of permissions, can be null + * @param tokenUrl the token endpoint {@link URL} of the OIDC server + * @param authorization the auth token (the access token URLEncoded by the + * "Bearer " string) + * @param audience the audience (context) where to request the issuing of + * the ticket (URLEncoded) + * @param permissions a list of permissions, can be null * @return the issued token - * @throws OpenIdConnectRESTHelperException if an error occurs (also an unauthorized call), inspect the exception for details + * @throws OpenIdConnectRESTHelperException if an error occurs (also an + * unauthorized call), inspect the + * exception for details */ - public static JWTToken queryExchangeToken(URL tokenUrl, String authorization, String audience, String client_id, String client_secret, + public static JWTToken queryExchangeToken(URL tokenUrl, String authorization, String audience, String client_id, + String client_secret, List permissions) throws OpenIdConnectRESTHelperException { logger.info("Queried exchangeToken for context " + audience); Map> params = new HashMap<>(); + Map extraHeaders = new HashMap<>(); params.put("subject_token", Arrays.asList(authorization)); params.put("client_id", Arrays.asList(client_id)); @@ -46,17 +58,20 @@ public class OpenIdConnectRESTHelperExtended extends OpenIdConnectRESTHelper { if (audience.startsWith("/")) { try { - logger.trace("Audience was provided in non URL encoded form, encoding it"); + // logger.trace("Audience was provided in non URL encoded form, encoding it"); audience = URLEncoder.encode(audience, "UTF-8"); } catch (UnsupportedEncodingException e) { logger.error("Cannot URL encode 'audience'", e); } } - try { - params.put("audience", Arrays.asList(URLEncoder.encode(audience, "UTF-8"))); - } catch (UnsupportedEncodingException e) { - logger.error("Cannot URL encode 'audience'", e); - } + + extraHeaders.put("X-D4Science-Context", audience); + + // 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 -> { @@ -68,6 +83,86 @@ public class OpenIdConnectRESTHelperExtended extends OpenIdConnectRESTHelper { }).collect(Collectors.toList())); } - return performQueryTokenWithPOST(tokenUrl, null, params); + // logger.info("Query exchangeToken, url " + tokenUrl); + // logger.info("Query exchangeToken, params " + params); + // logger.info("Query exchangeToken, extraHeaders " + extraHeaders); + + return performQueryTokenWithPOST(tokenUrl, null, params, extraHeaders); } + + protected static JWTToken performQueryTokenWithPOST(URL tokenURL, String authorization, + Map> params, Map headers) throws OpenIdConnectRESTHelperException { + + // logger.debug("Querying access token from OIDC server with URL: {}", tokenURL); + StringBuilder sb; + try { + HttpURLConnection httpURLConnection = performURLEncodedPOSTSendData(tokenURL, params, authorization, + headers); + + 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 = ""; + } + 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(); + } + } catch (IOException e) { + throw new OpenIdConnectRESTHelperException("Unable to get the token", e); + } + return JWTToken.fromString(sb.toString()); + } + + protected static HttpURLConnection performURLEncodedPOSTSendData(URL url, Map> params, + String authorization, Map headers) + throws IOException, ProtocolException, UnsupportedEncodingException { + + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("POST"); + con.setDoOutput(true); + con.setDoInput(true); + con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + con.setRequestProperty("Accept", "application/json"); + if (authorization != null) { + // logger.debug("Adding authorization header as: {}", authorization); + con.setRequestProperty("Authorization", authorization); + } + + if (headers != null) { + for (String key : headers.keySet()) { + con.setRequestProperty(key, headers.get(key)); + // logger.info("setting header " + key + " : " + headers.get(key)); + } + } + OutputStream os = con.getOutputStream(); + + String queryString = mapToQueryString(params); + // logger.debug("Parameters query string is: {}", queryString); + os.write(queryString.getBytes("UTF-8")); + os.close(); + return con; + } + } diff --git a/src/main/java/org/gcube/portlets/admin/RPTTokenReader.java b/src/main/java/org/gcube/portlets/admin/RPTTokenReader.java index f5be1f8..d2d0c0c 100644 --- a/src/main/java/org/gcube/portlets/admin/RPTTokenReader.java +++ b/src/main/java/org/gcube/portlets/admin/RPTTokenReader.java @@ -2,7 +2,6 @@ package org.gcube.portlets.admin; import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; @@ -14,14 +13,11 @@ import javax.portlet.ResourceRequest; import javax.portlet.ResourceResponse; import javax.servlet.http.HttpServletRequest; -import java.util.Base64; - import org.gcube.common.portal.PortalContext; import org.gcube.common.scope.impl.ScopeBean; import org.gcube.common.scope.impl.ScopeBean.Type; import org.gcube.oidc.rest.JWTToken; import org.gcube.oidc.rest.OpenIdConnectConfiguration; -import org.gcube.oidc.rest.OpenIdConnectRESTHelper; //import org.gcube.oidc.rest.OpenIdConnectRESTHelper; import org.gcube.oidc.rest.OpenIdConnectRESTHelperException; import org.gcube.portal.oidc.lr62.JWTCacheProxy; @@ -30,9 +26,9 @@ import org.gcube.vomanagement.usermanagement.GroupManager; import org.gcube.vomanagement.usermanagement.impl.LiferayGroupManager; import org.gcube.vomanagement.usermanagement.model.GCubeGroup; +import com.liferay.portal.kernel.json.JSONArray; import com.liferay.portal.kernel.json.JSONFactoryUtil; import com.liferay.portal.kernel.json.JSONObject; -import com.liferay.portal.kernel.json.JSONArray; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.util.ParamUtil; import com.liferay.portal.model.User; @@ -95,7 +91,7 @@ public class RPTTokenReader extends MVCPortlet { System.out.println("Selected context=" + context); HttpServletRequest httpReq = PortalUtil .getOriginalServletRequest(PortalUtil.getHttpServletRequest(resourceRequest)); - JWTToken umaToken = null; + // JWTToken umaToken = null; JWTToken exchangedToken = null; GroupManager gm = new LiferayGroupManager(); @@ -120,12 +116,13 @@ public class RPTTokenReader extends MVCPortlet { } JWTToken authToken = jwtCacheProxy.getOIDCToken(theUser, sessionId); - umaToken = OpenIdConnectRESTHelper.queryUMAToken(configuration.getTokenURL(), - authToken.getAccessTokenAsBearer(), urlEncodedContext, null); + + // umaToken = OpenIdConnectRESTHelper.queryUMAToken(configuration.getTokenURL(), + // authToken.getAccessTokenAsBearer(), urlEncodedContext, null); // URL auth_url = configuration.getTokenURL(); // log.info("auth_url " + auth_url); - // log.info("authToken " + authToken.getAccessTokenString()); + log.info("authToken '" + authToken.getAccessTokenString() + "'"); // log.info("umaToken " + umaToken.getAccessTokenString()); // log.info("context " + context); // log.info("encoded_context " + urlEncodedContext); @@ -134,13 +131,13 @@ public class RPTTokenReader extends MVCPortlet { exchangedToken = OpenIdConnectRESTHelperExtended.queryExchangeToken( configuration.getTokenURL(), - umaToken.getAccessTokenString(), + authToken.getAccessTokenString(), urlEncodedContext, configuration.getPortalClientId(), configuration.getPortalClientSecret(), - null); - - + null + ); + // log.info("exchangedToken " + exchangedToken.getAccessTokenString()); // log.debug("Got a new UMA token " + exchangedToken.getTokenEssentials()); @@ -162,15 +159,6 @@ public class RPTTokenReader extends MVCPortlet { return; } - // } catch (Exception e) { - // e.printStackTrace(); - // JSONObject jsonObject = JSONFactoryUtil.createJSONObject(); - // jsonObject.put("success", false); - // jsonObject.put("comment", e.getMessage()); - // resourceResponse.getWriter().println(jsonObject); - // super.serveResource(resourceRequest, resourceResponse); - // } - jsonObject.put("success", true); jsonObject.put("access_token", exchangedToken.getAccessTokenString()); jsonObject.put("refresh_token", exchangedToken.getRefreshTokenString()); @@ -180,7 +168,7 @@ public class RPTTokenReader extends MVCPortlet { jsonObject.put("access_token_exp", exchangedToken.getExp()); jsonObject.put("essential", exchangedToken.getTokenEssentials()); - jsonObject.put("client_id", umaToken.getAzp()); + jsonObject.put("client_id", exchangedToken.getAzp()); JSONArray audiences = JSONFactoryUtil.createJSONArray(); List list_audiences = exchangedToken.getAud();