World Check One API : JAVA Program for GET request to /v2/groups: 401 Unauthorized Error

Hi All,
We are trying to call the WorldCheckOne API from the SAP, where we need to convert the XML to JSON and post the data to WorldCheckOne API.
For which, I have written a program to make a GET request to /v2/groups , I am getting HTTP 401 error. Not exactly sure what is causing the error, could you please check and let me know what is wrong in the below code:
FYI. But from postman it is working fine with the same API key and Secret.
package HMACSignatureAuthentication;
import com.sap.aii.mapping.api.*;
import org.json.*;
import java.io.*;
import java.text.SimpleDateFormat;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import static java.lang.String.format;
import static java.time.ZoneOffset.UTC;
import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME;
import org.apache.commons.net.ntp.NTPUDPClient;
import java.net.InetAddress;
public class APICallWithHMACAuthentication extends AbstractTransformation {
private static final String HMAC_SHA_256 = "HmacSHA256";
private static final String CONTENT_TYPE_PREFIX = "application/json";
private static final String SIGNATURE_HEADERS_WITHOUT_CONTENT = "(request-target) host date";
private static final String SIGNATURE_HEADERS_WITH_CONTENT = "(request-target) host date content-type content-length";
private List<String> array_nodes = new ArrayList<>();
private boolean isSapEnvironment = false;
private static final String PROTOCOL = "https";
private static final String GATEWAY_HOST = "api-worldcheck.refinitiv.com";
private static final String GATEWAY_URL = "/v2/";
public static void main(String[] args) {
APICallWithHMACAuthentication authInstance = new APICallWithHMACAuthentication();
authInstance.isSapEnvironment = false;
try {
String keyId = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX";
String secretKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
String method = "groups"; // "cases/screeningRequest"; // groups
String requestMethod = "GET"; // GET
String sampleXml = "";
String result = authInstance.transformStandalone(secretKey, GATEWAY_HOST, method, requestMethod, sampleXml,
keyId);
System.out.println("Transformed Output: \n" + result);
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
e.printStackTrace();
}
}
public String transformStandalone(String secretKey, String host, String method, String requestMethod,
String inputXml, String keyId) throws Exception {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
InputStream inputStream = new ByteArrayInputStream(inputXml.getBytes());
performTransformation(secretKey, host, method, requestMethod, inputStream, outputStream, keyId);
return outputStream.toString("UTF-8");
}
public void transform(TransformationInput transformationInput, TransformationOutput transformationOutput)
throws StreamTransformationException {
this.isSapEnvironment = true;
try {
APICallWithHMACAuthentication authInstance = new APICallWithHMACAuthentication();
String secretKey = transformationInput.getInputParameters().getString("Secret_Key");
String host = transformationInput.getInputParameters().getString("Host");
String method = transformationInput.getInputParameters().getString("Method");
String requestMethod = transformationInput.getInputParameters().getString("Request_Method");
String sampleXml = "";
String keyId = "";
InputStream inputStream = transformationInput.getInputPayload().getInputStream();
OutputStream outputStream = transformationOutput.getOutputPayload().getOutputStream();
authInstance.transformStandalone(secretKey, GATEWAY_HOST, method, requestMethod, sampleXml, keyId);
} catch (Exception e) {
if (isSapEnvironment && getTrace() != null) {
getTrace().addDebugMessage(e.getMessage());
}
throw new StreamTransformationException(e.toString());
}
}
public void performTransformation(String secretKey, String host, String method, String requestMethod,
InputStream inputStream, OutputStream outputStream, String keyId) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder sourceXml = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sourceXml.append(line).append("\n");
}
br.close();
URI uri = new URI(PROTOCOL, null, GATEWAY_HOST, -1, GATEWAY_URL + method, null, null);
Map<String, String> authHeaders;
String jsonPayload = "";
System.out.println("URI: " + uri.toString());
System.out.println("sourceXML: " + sourceXml);
// Check if XML payload is empty
if (sourceXml.toString().trim().isEmpty()) {
// XML payload is empty, set empty JSON string
System.out.println("No XML payload provided. Skipping JSON transformation.");
// jsonPayload = "";
} else {
// XML payload exists, perform JSON transformation
JSONObject xmlJSONObj = XML.toJSONObject(sourceXml.toString());
array_nodes.add("arraynode");
xmlJSONObj = handleJSONData(xmlJSONObj);
// Attempt to remove root node if there is only one top-level key
Iterator<String> keys = xmlJSONObj.keys();
if (xmlJSONObj.length() == 1 && keys.hasNext()) {
String rootKey = keys.next(); // Get the root key
Object innerObject = xmlJSONObj.get(rootKey);
// Check if the inner object is a JSONObject (not an array or simple type)
if (innerObject instanceof JSONObject) {
xmlJSONObj = (JSONObject) innerObject; // Strip away the root by assigning inner JSON object
}
}
jsonPayload = xmlJSONObj.toString(4).replaceAll("\"xmlns:ns0\":\"your namespace\",", "")
.replaceAll("\"ns0:Message Type Name\":", "").trim();
}
String jsonBase64 = Base64.getEncoder().encodeToString(jsonPayload.getBytes());
System.out.println(jsonBase64);
authHeaders = generateAuthHeaders(keyId, secretKey, requestMethod, uri, "application/json", jsonPayload);
// Call API with either transformed JSON or empty payload
//postToAPI(uri, jsonBase64, authHeaders, requestMethod, outputStream);
postToAPI(uri, jsonPayload, authHeaders, requestMethod, outputStream);
}
/**
* Generates a {@link Map} with required authorization headers (Date, Authorization, Content-Type, Content-Length).
*
* @param apiKey the user's API key
* @param apiSecret the user's API secret
* @param httpMethod the HTTP method of a request (e.g. 'get', 'options', 'head', 'post', 'put', 'patch',
* or 'delete')
* @param uri the {@link URI} to send the request to (e.g. 'https://www.example.com/resources')
* @param payload payload/body of the request
* @return {@link Map} with all required headers for authorization (Date, Authorization, Content-Type,
* Content-Length)
*/
private Map<String, String> generateAuthHeaders(String apiKey, String apiSecret, String httpMethod, URI uri,
String contentType, String payload) {
Map<String, String> authHeaders = new HashMap<>();
Date now = new Date();
// Format the date to "EEE, dd MMM yyyy HH:mm:ss z"
SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z");
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); // Set time zone to GMT
// Print the formatted date
String date = dateFormat.format(now);
StringBuilder dataToSign = new StringBuilder(300).append("(request-target): ")
.append(httpMethod.toLowerCase()).append(' ')
.append(uri.getPath())
.append("\nhost: ").append(uri.getHost())
.append("\ndate: ").append(date);
validateContentType(contentType, payload);
if (payload != null) {
int contentLength = payload.length();
dataToSign.append("\ncontent-type: ").append(contentType)
.append("\ncontent-length: ").append(contentLength)
.append('\n').append(payload);
authHeaders.put("Content-Type", contentType);
authHeaders.put("Content-Length", String.valueOf(contentLength));
}
System.out.println(dataToSign);
System.out.println(payload);
String headers = payload == null ? SIGNATURE_HEADERS_WITHOUT_CONTENT : SIGNATURE_HEADERS_WITH_CONTENT;
String signature = signDataWithHmacSha256(apiSecret, dataToSign.toString());
String authorization = "Signature keyId=\"" + apiKey + "\",algorithm=\"hmac-sha256\",headers=\"" + headers
+ "\",signature=\"" + signature + '"';
authHeaders.put("Date", date);
authHeaders.put("Authorization", authorization);
return authHeaders;
}
private void validateContentType(String contentType, String payload) {
if (contentType != null && !contentType.startsWith(CONTENT_TYPE_PREFIX)) {
throw new IllegalArgumentException("Unsupported content type " + contentType);
}
if (contentType != null && payload == null) {
throw new IllegalArgumentException("The request payload(body) has not been provided");
}
if (contentType == null && payload != null) {
throw new IllegalArgumentException("The content type of request payload(body) has not been provided");
}
}
private String signDataWithHmacSha256(String apiSecret, String dataToSign) {
try {
Mac mac = Mac.getInstance(HMAC_SHA_256);
mac.init(new SecretKeySpec(apiSecret.getBytes(), HMAC_SHA_256));
byte[] hmac = mac.doFinal(dataToSign.getBytes());
return Base64.getEncoder().encodeToString(hmac);
} catch (NoSuchAlgorithmException | IllegalArgumentException | InvalidKeyException e) {
throw new RuntimeException(format("Unable to sign user: %s with data: %n%s", apiSecret, dataToSign), e);
}
}
private void postToAPI(URI uri, String payload, Map<String, String> authHeaders, String requestMethod,
OutputStream outputStream) throws Exception {
HttpURLConnection connection = null;
try {
// Open connection
connection = (HttpURLConnection) uri.toURL().openConnection();
connection.setRequestMethod(requestMethod.toUpperCase());
connection.setDoOutput(true);
System.out.println(requestMethod.toUpperCase() + " " + uri.toString());
// Set request headers
for (Map.Entry<String, String> entry : authHeaders.entrySet()) {
connection.setRequestProperty(entry.getKey(), entry.getValue());
System.out.println(entry.getKey() + ": " + entry.getValue());
}
System.out.println(payload);
// Write payload to output stream
try (OutputStream os = connection.getOutputStream()) {
os.write(payload.getBytes("UTF-8"));
os.flush();
}
// Get response code
int responseCode = connection.getResponseCode();
System.out.println("Response Code: " + responseCode);
// Check for successful response code (200-299)
if (responseCode >= 200 && responseCode < 300) {
try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
// Write response to output stream
outputStream.write(response.toString().getBytes("UTF-8"));
}
} else {
// Handle non-successful response
throw new IOException(
"HTTP error code: " + responseCode + ", Response message: " + connection.getResponseMessage());
}
} catch (IOException e) {
// Handle IOException (network issues, read/write errors)
System.err.println("IOException occurred: " + e.getMessage());
throw e; // Re-throwing the exception to be handled by the caller
} catch (Exception e) {
// Handle any other exceptions that might occur
System.err.println("Unexpected exception occurred: " + e.getMessage());
throw e; // Re-throwing the exception to be handled by the caller
} finally {
if (connection != null) {
connection.disconnect(); // Ensure the connection is closed
}
}
}
public JSONObject handleJSONData(JSONObject jsonObj) {
try {
String[] keys = (String[]) jsonObj.keySet().toArray(new String[0]);
for (String key : keys) {
if (array_nodes.contains(key)) {
jsonObj = forceToJSONArray(jsonObj, key);
}
if (jsonObj.get(key) instanceof JSONArray) {
JSONArray jsonArray = jsonObj.getJSONArray(key);
for (int i = 0; i < jsonArray.length(); i++) {
jsonArray.put(i, handleJSONData(jsonArray.getJSONObject(i)));
}
jsonObj.put(key, jsonArray);
} else if (jsonObj.get(key) instanceof JSONObject) {
jsonObj.put(key, handleJSONData(jsonObj.getJSONObject(key)));
} else if (jsonObj.get(key) instanceof Number) {
jsonObj.put(key, jsonObj.get(key).toString());
}
}
} catch (Exception e) {
if (isSapEnvironment && getTrace() != null) {
getTrace().addDebugMessage("Exception while updating payload: " + e.getMessage());
} else {
System.err.println("Exception while updating payload: " + e.getMessage());
}
}
return jsonObj;
}
public static JSONObject forceToJSONArray(JSONObject jsonObj, String key) throws JSONException {
Object obj = jsonObj.opt(key);
if (obj instanceof JSONObject) {
JSONArray jsonArray = new JSONArray();
jsonArray.put((JSONObject) obj);
jsonObj.put(key, jsonArray);
} else if (obj != null) {
JSONArray jsonArray = new JSONArray();
for (int i = 0; i < ((JSONArray) obj).length(); i++) {
jsonArray.put(((JSONArray) obj).getJSONObject(i));
}
jsonObj.put(key, jsonArray);
}
return jsonObj;
}
}
Thanks
Sai
Answers
-
Hi @sai.dhanekula,
Thank you for contacting us. We are currently reviewing your request and will get back to you shortly. Could you please provide your email ID so we can send you our authorization sample code?
Regards,
Ram.
0 -
Hi Ram,
Thanks for replying , here is my email Id: sai.dhanekula@equate.com
Looking forward to hear from you.
Thanks
Sai
0
Categories
- All Categories
- 3 Polls
- 6 AHS
- 36 Alpha
- 166 App Studio
- 6 Block Chain
- 4 Bot Platform
- 18 Connected Risk APIs
- 47 Data Fusion
- 34 Data Model Discovery
- 685 Datastream
- 1.4K DSS
- 615 Eikon COM
- 5.2K Eikon Data APIs
- 10 Electronic Trading
- Generic FIX
- 7 Local Bank Node API
- 3 Trading API
- 2.9K Elektron
- 1.4K EMA
- 252 ETA
- 556 WebSocket API
- 38 FX Venues
- 14 FX Market Data
- 1 FX Post Trade
- 1 FX Trading - Matching
- 12 FX Trading – RFQ Maker
- 5 Intelligent Tagging
- 2 Legal One
- 23 Messenger Bot
- 3 Messenger Side by Side
- 9 ONESOURCE
- 7 Indirect Tax
- 60 Open Calais
- 275 Open PermID
- 44 Entity Search
- 2 Org ID
- 1 PAM
- PAM - Logging
- 6 Product Insight
- Project Tracking
- ProView
- ProView Internal
- 22 RDMS
- 1.9K Refinitiv Data Platform
- 652 Refinitiv Data Platform Libraries
- 4 LSEG Due Diligence
- LSEG Due Diligence Portal API
- 4 Refinitiv Due Dilligence Centre
- Rose's Space
- 1.2K Screening
- 18 Qual-ID API
- 13 Screening Deployed
- 23 Screening Online
- 12 World-Check Customer Risk Screener
- 1K World-Check One
- 46 World-Check One Zero Footprint
- 45 Side by Side Integration API
- 2 Test Space
- 3 Thomson One Smart
- 10 TR Knowledge Graph
- 151 Transactions
- 143 REDI API
- 1.8K TREP APIs
- 4 CAT
- 27 DACS Station
- 121 Open DACS
- 1.1K RFA
- 104 UPA
- 193 TREP Infrastructure
- 228 TRKD
- 917 TRTH
- 5 Velocity Analytics
- 9 Wealth Management Web Services
- 90 Workspace SDK
- 11 Element Framework
- 5 Grid
- 18 World-Check Data File
- 1 Yield Book Analytics
- 46 中文论坛