0

Triyng to integrate Vuforia Web API in Java...

These are the requirements to submit a recognition query from the official website https://library.vuforia.com/web-api/vuforia-query-web-api

enter image description here

And this is the explanation of building the signature key for Authorization header https://library.vuforia.com/web-api/vuforia-web-api-authentication

enter image description here

enter image description here

They also provide a sample in Java where you can find whole process of setting request with Authorization Header

Following the instructions of sample i wrote the following code

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.security.SignatureException;
import java.util.Date;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.cookie.DateUtils;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;


@Service
@Repository
public class VuforiaServices {

private static final String BASE_URL = "https://cloudreco.vuforia.com";

private static final String ACCESS_KEY = "AGDPKY9CBAEVCKQENRZPX"; // Replace with your Vuforia access key
private static final String SECRET_KEY = "eLIsEsiqloSazCWpn9csRHnqso784wZSi"; // Replace with your Vuforia secret key
private static final String DATABASE_ID = "condivino"; // Replace with your Vuforia database ID

public String tmsSignature(HttpUriRequest request, String secretKey) {
    String method = request.getMethod();
    String contentType = "";
    String hexDigest = "d41d8cd98f00b204e9800998ecf8427e"; // Hex digest of an empty string

    if (method.equalsIgnoreCase("GET") || method.equalsIgnoreCase("DELETE")) {
        // Do nothing because the strings are already set correctly
    } else if (method.equalsIgnoreCase("POST") || method.equalsIgnoreCase("PUT")) {
        contentType = "application/json";
        // If this is a POST or PUT the request should have a request body
        hexDigest = contentMD5((HttpEntityEnclosingRequestBase) request);
    } else {
        System.out.println("ERROR: Invalid content type passed to Sig Builder");
    }

    // Date in the header and date used to calculate the hash must be the same
    String dateValue = request.getFirstHeader("Date").getValue();
    String requestPath = request.getURI().getPath();
    String toDigest = new String(method + "\n" + hexDigest + "\n" + contentType + "\n" + dateValue + "\n" + requestPath);
    String shaHashed = "";
    try {
        System.out.println(toDigest);
        shaHashed = calculateRFC2104HMAC(secretKey, toDigest);
    } catch (SignatureException e) {
        e.printStackTrace();
    }
    return new String(shaHashed);
}

private String contentMD5(HttpEntityEnclosingRequestBase httpMethod) {
    ByteArrayOutputStream requestOutputStream = new ByteArrayOutputStream();
    try {
        httpMethod.getEntity().writeTo(requestOutputStream);
    } catch (IOException e) {
        System.out.println("ERROR: IOException caught when writing Content MD5 hash");
        e.printStackTrace();
    }
    return DigestUtils.md5Hex(requestOutputStream.toByteArray()).toLowerCase();
}

public static String calculateRFC2104HMAC(String key, String data) throws java.security.SignatureException {
    String result = "";
    try {
        // get an hmac_sha1 key from the raw key bytes
        SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA1");

        // get an hmac_sha1 Mac instance and initialize with the signing key
        Mac mac = Mac.getInstance("HmacSHA1");
        mac.init(signingKey);

        // compute the hmac on input data bytes
        byte[] rawHmac = mac.doFinal(data.getBytes());

        // base64-encode the hmac
        result = new String(org.apache.commons.codec.binary.Base64.encodeBase64(rawHmac, false));

    } catch (Exception e) {
        e.printStackTrace();
    }
    return result;
}

public void queryTargetRecognitionV2(String targetFilePath) throws URISyntaxException, ClientProtocolException, IOException {
     String endpoint = "/v1/query";
     String url = BASE_URL + endpoint;
     
     HttpClient client = new DefaultHttpClient();
     HttpPost postRequest = new HttpPost(url);

    setBody(postRequest, targetFilePath);
    setHeaders(postRequest);
    
    HttpResponse response = client.execute(postRequest);
    System.out.println(EntityUtils.toString(response.getEntity()));
}

private void setHeaders(HttpUriRequest request) {
    request.setHeader(new BasicHeader("Date", DateUtils.formatDate(new Date()).replaceFirst("[+]00:00$", "")));
    request.setHeader("Authorization", "VWS " + ACCESS_KEY + ":" + tmsSignature(request, SECRET_KEY));
}

private void setBody(HttpPost postRequest, String imagePath) {
    File imageFile = new File(imagePath);
    
    // Create the multipart request entity
    MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
    entityBuilder.addTextBody("database_id", DATABASE_ID);
    entityBuilder.addBinaryBody("image", imageFile, ContentType.IMAGE_PNG, imageFile.getName());
    postRequest.setEntity(entityBuilder.build());
}
}

As result this is output from header

Method: POST
Content-MD5: 8b8fcc7b800a277a832ce87833038725
Content-Type: multipart/form-data
Date: Tue, 30 May 2023 09:19:41 GMT
Request-Path: /v1/query

But somehow the API respond to me with an 401 ( AuthenticationFailure ) error that should be generated when the signature key is malformatted.

{"transaction_id":"34e9ab80bd9f47989141c5844322255d","result_code":"AuthenticationFailure"}

Maybe someone already integrated Vuforia Recognition Web API in Java and know to give me an answer to resolve this problem, the point is that the documentation on their website is not quite clear, or the sample that they provided is outdated? Of course I tried different approaches and tried to get some answers from their forum that now is readonly, but only thing i got is that I'm not the only getting troubles with signature key.

oskar2771
  • 63
  • 9

0 Answers0