-
Notifications
You must be signed in to change notification settings - Fork 7
Large file upload fix without rest template #123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
ab775e0
5536083
3410442
caadd74
5083e6e
57f7980
bed4364
d18f87b
868cd9d
5529816
1802cb9
172cce5
801dce0
60858cb
698be97
b1be974
99439da
c9cc062
671f4d6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
import com.google.gson.JsonObject; | ||
import com.google.gson.JsonParser; | ||
import com.sap.cds.sdm.caching.CacheConfig; | ||
import com.sap.cds.sdm.caching.CacheKey; | ||
import com.sap.cds.sdm.caching.TokenCacheKey; | ||
import com.sap.cds.sdm.constants.SDMConstants; | ||
import com.sap.cds.sdm.model.SDMCredentials; | ||
|
@@ -19,19 +20,37 @@ | |
import com.sap.cloud.sdk.cloudplatform.connectivity.OAuth2DestinationBuilder; | ||
import com.sap.cloud.sdk.cloudplatform.connectivity.OnBehalfOf; | ||
import com.sap.cloud.security.config.ClientCredentials; | ||
import com.sap.cloud.security.xsuaa.client.OAuth2ServiceException; | ||
import com.sap.cloud.security.xsuaa.http.HttpHeaders; | ||
import com.sap.cloud.security.xsuaa.http.MediaType; | ||
import java.io.*; | ||
import java.net.HttpURLConnection; | ||
import java.net.URL; | ||
import java.net.URLEncoder; | ||
import java.nio.charset.StandardCharsets; | ||
import java.time.Duration; | ||
import java.util.Arrays; | ||
import java.util.Arrays; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.stream.Collectors; | ||
import org.apache.commons.codec.binary.Base64; | ||
import org.apache.http.HttpResponse; | ||
import org.apache.http.HttpStatus; | ||
import org.apache.http.client.ClientProtocolException; | ||
import org.apache.http.client.HttpClient; | ||
import org.apache.http.client.entity.UrlEncodedFormEntity; | ||
import org.apache.http.client.methods.HttpPost; | ||
import org.apache.http.impl.client.CloseableHttpClient; | ||
import org.apache.http.impl.client.HttpClients; | ||
import org.apache.http.message.BasicNameValuePair; | ||
import org.json.JSONObject; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
public class TokenHandler { | ||
private static final Logger logger = LoggerFactory.getLogger(TokenHandler.class); | ||
|
||
private static final ObjectMapper mapper = new ObjectMapper(); | ||
|
||
|
@@ -140,6 +159,109 @@ public static String getDITokenUsingAuthorities( | |
return cachedToken; | ||
} | ||
|
||
public static String getDIToken(String token, SDMCredentials sdmCredentials) throws IOException { | ||
JsonObject payloadObj = getTokenFields(token); | ||
String email = payloadObj.get("email").getAsString(); | ||
JsonObject tenantDetails = payloadObj.get("ext_attr").getAsJsonObject(); | ||
String subdomain = tenantDetails.get("zdn").getAsString(); | ||
String tokenexpiry = payloadObj.get("exp").getAsString(); | ||
CacheKey cacheKey = new CacheKey(); | ||
cacheKey.setKey(email + "_" + subdomain); | ||
cacheKey.setExpiration(tokenexpiry); | ||
String cachedToken = CacheConfig.getUserTokenCache().get(cacheKey); | ||
if (cachedToken == null) { | ||
cachedToken = generateDITokenFromTokenExchange(token, sdmCredentials, payloadObj); | ||
} | ||
return cachedToken; | ||
} | ||
|
||
public static Map<String, String> fillTokenExchangeBody(String token, SDMCredentials sdmEnv) { | ||
Map<String, String> parameters = new HashMap<>(); | ||
parameters.put("assertion", token); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can add a null check for token and throw an exception if ever token is null. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the application access token and if null the app framework would have thrown the exception even before all these flows! |
||
return parameters; | ||
} | ||
|
||
public static String generateDITokenFromTokenExchange( | ||
String token, SDMCredentials sdmCredentials, JsonObject payloadObj) | ||
throws OAuth2ServiceException { | ||
String cachedToken = null; | ||
CloseableHttpClient httpClient = null; | ||
try { | ||
httpClient = HttpClients.createDefault(); | ||
if (sdmCredentials.getClientId() == null) { | ||
throw new IOException(SDMConstants.NO_SDM_BINDING); | ||
} | ||
Map<String, String> parameters = fillTokenExchangeBody(token, sdmCredentials); | ||
HttpPost httpPost = | ||
new HttpPost(sdmCredentials.getBaseTokenUrl() + SDMConstants.DI_TOKEN_EXCHANGE_PARAMS); | ||
httpPost.setHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON.value()); | ||
httpPost.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED.value()); | ||
httpPost.setHeader("X-zid", getTokenFields(token).get("zid").getAsString()); | ||
|
||
String encoded = | ||
java.util.Base64.getEncoder() | ||
.encodeToString( | ||
(sdmCredentials.getClientId() + ":" + sdmCredentials.getClientSecret()) | ||
.getBytes()); | ||
httpPost.setHeader("Authorization", "Basic " + encoded); | ||
|
||
List<BasicNameValuePair> basicNameValuePairs = | ||
parameters.entrySet().stream() | ||
.map(entry -> new BasicNameValuePair(entry.getKey(), entry.getValue())) | ||
.collect(Collectors.toList()); | ||
httpPost.setEntity(new UrlEncodedFormEntity(basicNameValuePairs)); | ||
|
||
HttpResponse response = httpClient.execute(httpPost); | ||
String responseBody = extractResponseBodyAsString(response); | ||
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { | ||
logger.error("Error fetching token with JWT bearer : " + responseBody); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In case status is not 200 do we still need to continue the processing? Or can we throw an exception from here and exit? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
throw new OAuth2ServiceException( | ||
String.format(SDMConstants.DI_TOKEN_EXCHANGE_ERROR, responseBody)); | ||
} | ||
Map<String, Object> accessTokenMap = new JSONObject(responseBody).toMap(); | ||
cachedToken = String.valueOf(accessTokenMap.get("access_token")); | ||
String expiryTime = payloadObj.get("exp").getAsString(); | ||
CacheKey cacheKey = new CacheKey(); | ||
JsonObject tenantDetails = payloadObj.get("ext_attr").getAsJsonObject(); | ||
String subdomain = tenantDetails.get("zdn").getAsString(); | ||
cacheKey.setKey(payloadObj.get("email").getAsString() + "_" + subdomain); | ||
cacheKey.setExpiration(expiryTime); | ||
CacheConfig.getUserTokenCache().put(cacheKey, cachedToken); | ||
} catch (UnsupportedEncodingException e) { | ||
throw new OAuth2ServiceException("Unexpected error parsing URI: " + e.getMessage()); | ||
} catch (ClientProtocolException e) { | ||
throw new OAuth2ServiceException( | ||
"Unexpected error while fetching client protocol: " + e.getMessage()); | ||
} catch (IOException e) { | ||
logger.error( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In case of IO exception do we not need to throw any exception? We are only logging it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done! |
||
"Error in POST request while fetching token with JWT bearer \n" | ||
+ Arrays.toString(e.getStackTrace())); | ||
throw new OAuth2ServiceException( | ||
"Error in POST request while fetching token with JWT bearer: " + e.getMessage()); | ||
} finally { | ||
safeClose(httpClient); | ||
} | ||
return cachedToken; | ||
} | ||
|
||
private static void safeClose(CloseableHttpClient httpClient) { | ||
if (httpClient != null) { | ||
try { | ||
httpClient.close(); | ||
} catch (IOException ex) { | ||
logger.error("Failed to close httpclient \n" + Arrays.toString(ex.getStackTrace())); | ||
} | ||
} | ||
} | ||
|
||
public static String extractResponseBodyAsString(HttpResponse response) throws IOException { | ||
// Ensure that InputStream and BufferedReader are automatically closed | ||
try (InputStream inputStream = response.getEntity().getContent(); | ||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { | ||
return bufferedReader.lines().collect(Collectors.joining(System.lineSeparator())); | ||
} | ||
} | ||
|
||
public static JsonObject getTokenFields(String token) { | ||
String[] chunks = token.split("\\."); | ||
java.util.Base64.Decoder decoder = java.util.Base64.getUrlDecoder(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SDMCredentials sdmEnv
is passed but not used, can we remove it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done