Hello,
I am following this document to generate JKS store file, using KeyTool.
The commands I am using
keytool -import -alias DigiCertGlobalCA -keystore visa-integration_keyAndCertBundle.jks -file DigiCertGlobalRootCA.crt
keytool -genkeypair -alias client -keyalg RSA -keysize 2048 -keystore visa-integration_keyAndCertBundle.jks --storepass {password} -keypass {password} -dname "CN=**, OU=**, O=**, L=**, ST=California, C=US, UID=**-PROD"
keytool -certreq -alias client -keystore visa-integration_keyAndCertBundle.jks -storepass {password} -keypass {password} -file certreq.csr
### Then I upload certreq.csr to VISA and get cert.perm and username and password.
keytool -import -alias ejbca -keystore visa-integration_keyAndCertBundle.jks -file VDPCA-SBX.pem -storepass {password}
keytool -import -alias client -keystore visa-integration_keyAndCertBundle.jks -file cert.pem -storepass {password}
Note: all the {password} above are same, I am not sure whether they are correct? Below is my code to connect the VISA. I got a 401 error Do you know what's wrong?
public HttpURLConnection initURLConnection(String apiUrl) {
HttpURLConnection con;
try {
URL url = new URL(apiUrl);
con = (HttpURLConnection) url.openConnection();
} catch (MalformedURLException e) {
log.error("Fail to initialize url {}.", apiUrl);
throw new DnaJobsException(e);
} catch (IOException e) {
log.error("Fail to open connection for url {}.", apiUrl);
throw new DnaJobsException(e);
}
String keystoreFileName = getKeystoreFileName();// which is visa-integration_keyAndCertBundle.jks
String keystorePassword = getKeystorePassword();// which is password in above commands
KeyStore ks;
try {
ks = KeyStore.getInstance("PKCS12");
} catch (KeyStoreException e) {
log.error("Failed to get key store PKCS12");
throw new DnaJobsException(e);
}
ClassPathResource classPathResource = new ClassPathResource(keystoreFileName);
try (InputStream fis = classPathResource.getInputStream()) {
ks.load(fis, keystorePassword.toCharArray());
} catch (FileNotFoundException e) {
log.error("Failed to open file in {}.", keystoreFileName);
throw new DnaJobsException(e);
} catch (Exception e) {
log.error("Failed to load keystore password");
throw new DnaJobsException(e);
}
KeyManagerFactory kmf;
try {
kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, keystorePassword.toCharArray());
} catch (NoSuchAlgorithmException e) {
log.error("Failed to get key manager SunX509.");
throw new DnaJobsException(e);
} catch (Exception e) {
log.error("Failed to initialize password");
throw new DnaJobsException(e);
}
SSLContext sslContext;
try {
sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), null, null);
} catch (NoSuchAlgorithmException e) {
log.error("Failed to get algorithm TLS.");
throw new DnaJobsException(e);
} catch (Exception e) {
log.error("Failed to initialize password for SSLContext.");
throw new DnaJobsException(e);
}
if (con instanceof HttpsURLConnection) {
((HttpsURLConnection) con).setSSLSocketFactory(sslContext.getSocketFactory());
}
try {
con.setRequestMethod("POST");
} catch (ProtocolException e) {
log.error("Failed to set request method");
throw new DnaJobsException(e);
}
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
String auth = getVisaUserId() + ":" + getVisaPassword();//UserId and password are from VISA Dashboard
byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes(StandardCharsets.UTF_8));
String authHeaderValue = "Basic " + new String(encodedAuth);
con.setRequestProperty("Authorization", authHeaderValue);
return con;
}
Hi @Yong, Thank you for reaching out. An agent will get back to you as soon as possible. In the meantime, if any community member knows a solution, please reply to this thread.
Hello, do you have any feedback?
Hey @Yong,
Please refer to the Visa Developer Error Codes page for cause and resolution.
Your code and commands seem mostly correct, but there are a few areas where issues might arise. Here are some suggestions:
1. Keystore Type: Your commands are for creating a JKS keystore, but in the code, you're trying to load a PKCS12 keystore. Ensure consistency between the keystore type used in your commands and your code.
2. Certificate Chain: Ensure that the certificate chain is correctly imported into the keystore.
3. HTTP Response: Check the response from the server to get more specific details about the error.
4. Password Consistency: Ensure that the password used for the keystore and keys is consistent.
5. Debugging: Enable SSL debugging for more detailed logs.
Here's an updated version of your code considering the above points:
```java
// START
public HttpURLConnection initURLConnection(String apiUrl) {
HttpURLConnection con;
try {
URL url = new URL(apiUrl);
con = (HttpURLConnection) url.openConnection();
} catch (MalformedURLException e) {
log.error("Fail to initialize url {}.", apiUrl);
throw new DnaJobsException(e);
} catch (IOException e) {
log.error("Fail to open connection for url {}.", apiUrl);
throw new DnaJobsException(e);
}
String keystoreFileName = getKeystoreFileName(); // which is visa-integration_keyAndCertBundle.jks
String keystorePassword = getKeystorePassword(); // which is password in above commands
KeyStore ks;
try {
ks = KeyStore.getInstance("JKS"); // Changed to JKS to match your keytool commands
} catch (KeyStoreException e) {
log.error("Failed to get key store JKS");
throw new DnaJobsException(e);
}
ClassPathResource classPathResource = new ClassPathResource(keystoreFileName);
try (InputStream fis = classPathResource.getInputStream()) {
ks.load(fis, keystorePassword.toCharArray());
} catch (FileNotFoundException e) {
log.error("Failed to open file in {}.", keystoreFileName);
throw new DnaJobsException(e);
} catch (Exception e) {
log.error("Failed to load keystore password");
throw new DnaJobsException(e);
}
KeyManagerFactory kmf;
try {
kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, keystorePassword.toCharArray());
} catch (NoSuchAlgorithmException e) {
log.error("Failed to get key manager SunX509.");
throw new DnaJobsException(e);
} catch (Exception e) {
log.error("Failed to initialize password");
throw new DnaJobsException(e);
}
SSLContext sslContext;
try {
sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), null, null);
} catch (NoSuchAlgorithmException e) {
log.error("Failed to get algorithm TLS.");
throw new DnaJobsException(e);
} catch (Exception e) {
log.error("Failed to initialize password for SSLContext.");
throw new DnaJobsException(e);
}
if (con instanceof HttpsURLConnection) {
((HttpsURLConnection) con).setSSLSocketFactory(sslContext.getSocketFactory());
}
try {
con.setRequestMethod("POST");
} catch (ProtocolException e) {
log.error("Failed to set request method");
throw new DnaJobsException(e);
}
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
String auth = getVisaUserId() + ":" + getVisaPassword(); // UserId and password are from VISA Dashboard
byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes(StandardCharsets.UTF_8));
String authHeaderValue = "Basic " + new String(encodedAuth);
con.setRequestProperty("Authorization", authHeaderValue);
return con;
}
// END
```
Additional Tips:
1. SSL Debugging: Add `-Djavax.net.debug=all` to your JVM options to enable detailed SSL debugging.
2. Check Server Logs: If possible, check the server logs for more information on the 401 error.
3. Certificate Chain: Ensure that the full certificate chain is correctly imported into the keystore.
Thank you for your reply.
Now I found the issue in my side, while I am renewing the Prod certificate, I submitted the CSR to sandbox. Now I am resubmitting the CSR and waiting for VISA to approve it.