Reputation: 856
I am new to Azure related concepts and am facing issue in connecting the Azure Key vault.
Please find my code snippets as follows and let me know why am getting the below exception:
Get Key started.../n SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. Get Key failedjava.lang.RuntimeException: java.util.concurrent.ExecutionException: com.microsoft.aad.adal4j.AuthenticationException: {"error_description":"AADSTS70002: Error validating credentials. AADSTS50012: Invalid client secret is provided.\r\nTrace ID: 13f8e909-89d8-472f-a1c1-9f4bcf693700\r\nCorrelation ID: bf818c41-4092-4f7d-8292-b1275a5da62f\r\nTimestamp: 2017-10-17 07:22:12Z","error":"invalid_client"} Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.RuntimeException: java.util.concurrent.ExecutionException: com.microsoft.aad.adal4j.AuthenticationException: {"error_description":"AADSTS70002: Error validating credentials. AADSTS50012: Invalid client secret is provided.\r\nTrace ID: 1234\r\nCorrelation ID: 123456\r\nTimestamp: 2017-10-17 07:22:12Z","error":"invalid_client"} at com.google.common.util.concurrent.AbstractFuture$Sync.getValue(AbstractFuture.java:299) at com.google.common.util.concurrent.AbstractFuture$Sync.get(AbstractFuture.java:286) at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:116) at Program.main(Program.java:88)
Corresponding Code am trying to connect Azure Key Vault :
KeyVaultCredentials kvCred = new ClientSecretKeyVaultCredential("clientID", "client Secret");
KeyVaultClient vc = new KeyVaultClient(kvCred);
byte[] byteText = textToEncrypt.getBytes("UTF-16");
/*************************************/
// Get Key from Key Vault
System.out.println("Get Key started.../n");
start = System.currentTimeMillis();
ServiceCallback<KeyBundle> serviceCallbackgetkey = new ServiceCallback<KeyBundle>(){
@Override
public void failure(Throwable t) {
System.out.println("Get Key failed"+t.toString());
}
@Override
public void success(KeyBundle result ) {//ServiceResponse
System.out.println("Get Key Success");
JsonWebKey myKey = result.key();
keyIdentifier = myKey.kid();
System.out.println("Key ID:"+keyIdentifier);
end = System.currentTimeMillis();
formatter = new DecimalFormat("#0.00000");
System.out.print("Get Key Execution time is " + formatter.format((end - start) / 1000d) + " seconds\n");
start = 0;
end =0;
}
};
ServiceCall<KeyBundle> call = vc.getKeyAsync(keyVaultURI, "MyKey1", serviceCallbackgetkey);
System.out.println(call.get());
Note: Am using the same Client-ID and Client Secret in postman for connecting a different REST api and is working fine.
Also, I tried executing the following code from here. But facing same issue.
Please help me identifying why am unable to connect the vault.
Upvotes: 0
Views: 3739
Reputation: 856
Figured out the issue, the problem is with the client_secret which has some special characters like % when generated. It seems, the azure key vault is accepting client secret which are encrypted with base64 encoding and it's special characters.
Upvotes: 1
Reputation: 23792
I tried to reproduce your issue but failed.
I thought your issue probably results from the permission
to authorize keyvault API for your application.
You could refer to the code below which works for me.
Program Class:
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutionException;
import com.microsoft.azure.keyvault.KeyVaultClient;
import com.microsoft.azure.keyvault.authentication.KeyVaultCredentials;
public class Program {
public static void main(String[] args)
throws InterruptedException, ExecutionException, URISyntaxException, UnsupportedEncodingException {
KeyVaultCredentials kvCred = new ClientSecretKeyVaultCredential("APP_ID", "APP_SECRET");
KeyVaultClient vc = new KeyVaultClient(kvCred);
String keyIdentifier = "https://jaygong.vault.azure.net/keys/jaytest/b21bae081025418c806d73affc2937e0";
System.out.println(vc.getKey(keyIdentifier));
}
}
ClientSecretKeyVaultCredential Class:
import java.net.MalformedURLException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientCredential;
import com.microsoft.azure.keyvault.authentication.KeyVaultCredentials;
public class ClientSecretKeyVaultCredential extends KeyVaultCredentials {
private String applicationId;
private String applicationSecret;
public ClientSecretKeyVaultCredential(String applicationId, String applicationSecret) {
this.setApplicationId(applicationId);
this.setApplicationSecret(applicationSecret);
}
public String getApplicationId() {
return applicationId;
}
private void setApplicationId(String applicationId) {
this.applicationId = applicationId;
}
public String getApplicationSecret() {
return applicationSecret;
}
private void setApplicationSecret(String applicationSecret) {
this.applicationSecret = applicationSecret;
}
@Override
public String doAuthenticate(String authorization, String resource, String scope) {
AuthenticationResult res = null;
try {
res = GetAccessToken(authorization, resource, applicationId, applicationSecret);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return res.getAccessToken();
}
private AuthenticationResult GetAccessToken(String authorization, String resource, String clientID, String clientKey)
throws InterruptedException, ExecutionException {
AuthenticationContext ctx = null;
ExecutorService service = Executors.newFixedThreadPool(1);
try {
ctx = new AuthenticationContext(authorization, false, service);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Future<AuthenticationResult> resp = ctx.acquireToken(resource, new ClientCredential(
clientID, clientKey), null);
AuthenticationResult res = resp.get();
return res;
}
}
Results:
Please notice that you should authorize your application to use the key or secret.
Here is the powershell
way which is mentioned in the official doc.
Set-AzureRmKeyVaultAccessPolicy -VaultName 'XXXXXXX' -ServicePrincipalName XXXXX -PermissionsToKeys decrypt,sign,get,unwrapKey
Update Answer:
I'm not sure if your application has permission to call KeyVault API
. You could add this permission on portal.
Hope it helps you.
Upvotes: 2