Veracode Connector

Hello,

We would like to manage Veracode users from IdentityNow but for this we need a Webservice Connector to call Veracode API. For this, it’s okay on our side.

But Veracode is expecting HMAC authentication on each calls, and we do not need authentication configuration. From what I see, there is no documentation on this kind of things. So I was thinking about the web service before provisionning rule. But we need to get user ID and user secret for the HMAC generation. And I don’t know how to do it.

Do you have any idea on how to manage this ?

Regards

Hello @alexandre_mazars,

A solution could be to store the user ID and user secret into connector attributes (through API or Visual Studio Code for example) and add the name of those attributes into connector properties encrypted.

By adding the attributes name in encrypted properties, the value won’t be directly usable as there will be display as a hash.

Then you can build an before operation rule to make compute the HMAC and make your authentication call. The user ID or password can be used in the before operation rule using the following instruction: application.getAttributeValue("password").

Let me know if you have any questions.

Bastien

1 Like

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 :slightly_smiling_face:

1 Like

Hello,

I am re-opening this topic as we are now facing difficulties with the Veracode API.
We have managed to aggregate accounts, create accounts and add rights.

But to remove rights, the Veracode API is not including specific API Code. The only way to do it is to update the user with the full liste of rights in the json body (without the role to remove). But we have not found how to send this list with IDN. Is there an attribute somewhere in the plan for this ? Or should we developp a before provisionning rule for this use case ?

Regards

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.