Hello Bastien,
Thanks for your help. I was able to build my BeforeRule for the WebService connector using your help and it’s seems to be working.
Here is the rule for people that may have the same need with HMAC or veracode :
import java.util.HashMap;
import java.util.Map;
import connector.common.JsonUtil;
import connector.common.Util;
import sailpoint.object.Application;
import sailpoint.connector.webservices.EndPoint;
import javax.crypto;
import sailpoint.tools.GeneralException;
String VERACODE_REQUEST_VERSION_STRING = \"vcode_request_version_1\";
String DATA_FORMAT = \"id=%s&host=%s&url=%s&method=%s\";
String HEADER_FORMAT = \"%s id=%s,ts=%s,nonce=%s,sig=%s\";
String VERACODE_HMAC_SHA_256 = \"VERACODE-HMAC-SHA-256\";
String HMAC_SHA_256 = \"HmacSHA256\";
String UTF_8 = \"UTF-8\";
java.security.SecureRandom secureRandom = new java.security.SecureRandom();
char[] hexCode = \"0123456789ABCDEF\".toCharArray();
Map body = requestEndPoint.getBody();
Map header = requestEndPoint.getHeader();
String fullUri = requestEndPoint.getFullUrl();
String operationType = requestEndPoint.getHttpMethodType();
String user_id = application.getAttributeValue(\"username\");
String user_secret = application.getAttributeValue(\"password\");
String getVeracodeAuthorizationHeader(String id, String key, String urlString, String httpMethod) throws Exception {
java.net.URL url = new java.net.URL(urlString);
String formatedId = removePrefixFromApiCredential(id);
String formatedKey = removePrefixFromApiCredential(key);
String urlPath = (url.getQuery() == null) ? url.getPath() : url.getPath().concat(\"?\").concat(url.getQuery());
String data = customFormat(DATA_FORMAT, new Object[]{formatedId, url.getHost(), urlPath, httpMethod});
String timestamp = String.valueOf(System.currentTimeMillis());
String nonce = printHexBinary(generateRandomBytes(16)).toLowerCase();
String signature = getSignature(formatedKey, data, timestamp, nonce);
return customFormat(HEADER_FORMAT, new Object[]{VERACODE_HMAC_SHA_256, id, timestamp, nonce, signature});
}
String customFormat(String format, Object[] args) {
return String.format(format, args);
}
String removePrefixFromApiCredential(String id) {
String[] parts = id.split(\"-\");
return parts.length == 2 ? parts[1] : id;
}
String getSignature(String key, String data, String timestamp, String nonce) throws Exception {
byte[] keyBytes = parseHexBinary(key);
byte[] nonceBytes = parseHexBinary(nonce);
byte[] encryptedNonce = hmacSha256(nonceBytes, keyBytes);
byte[] encryptedTimestamp = hmacSha256(timestamp.getBytes(UTF_8), encryptedNonce);
byte[] signingKey = hmacSha256(VERACODE_REQUEST_VERSION_STRING.getBytes(UTF_8), encryptedTimestamp);
byte[] signature = hmacSha256(data.getBytes(UTF_8), signingKey);
return printHexBinary(signature).toLowerCase();
}
byte[] hmacSha256(String data, byte[] key) throws Exception {
javax.crypto.Mac mac = javax.crypto.Mac.getInstance(HMAC_SHA_256);
mac.init(new javax.crypto.spec.SecretKeySpec(key, HMAC_SHA_256));
return mac.doFinal(data.getBytes(UTF_8));
}
byte[] hmacSha256(byte[] data, byte[] key) throws Exception {
javax.crypto.Mac mac = javax.crypto.Mac.getInstance(HMAC_SHA_256);
mac.init(new javax.crypto.spec.SecretKeySpec(key, HMAC_SHA_256));
return mac.doFinal(data);
}
byte[] generateRandomBytes(int size) {
byte[] key = new byte[size];
secureRandom.nextBytes(key);
return key;
}
String printHexBinary(byte[] data) {
StringBuilder r = new StringBuilder(data.length * 2);
for (byte b : data) {
r.append(hexCode[b >> 4 & 15]);
r.append(hexCode[b & 15]);
}
return r.toString();
}
byte[] parseHexBinary(String s) {
int len = s.length();
if (len % 2 != 0) {
throw new IllegalArgumentException(\"hexBinary needs to be even-length: \" + s);
} else {
byte[] out = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
int h = hexToBin(s.charAt(i));
int l = hexToBin(s.charAt(i + 1));
if (h == -1 || l == -1) {
throw new IllegalArgumentException(\"contains illegal character for hexBinary: \" + s);
}
out[i / 2] = (byte) (h * 16 + l);
}
return out;
}
}
int hexToBin(char ch) {
if ('0' <= ch && ch <= '9') {
return ch - 48;
} else if ('A' <= ch && ch <= 'F') {
return ch - 65 + 10;
} else {
return ('a' <= ch && ch <= 'f') ? ch - 97 + 10 : -1;
}
}
header.put(\"Authorization\", getVeracodeAuthorizationHeader(user_id, user_secret, fullUri, operationType));
header.put(\"Content-Type\", \"application/json\");
requestEndPoint.setHeader(header);
return requestEndPoint;
Also to avoid authentication steps, I had to select Custom Authentication without configuration of the HTTP Operation. I also need to add the BeforeRule on every HTTP Operation using the APIs.
Thnaks again for your help