使用 Java 连接 Azure Key Vault 时出错
Error Connecting Azure Key Vault using Java
我是 Azure 相关概念的新手,在连接 Azure Key Vault 时遇到问题。
请找到我的代码片段如下,让我知道为什么会出现以下异常:
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)
相应的代码正在尝试连接 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());
注意:我在邮递员中使用相同的客户端 ID 和客户端密码来连接不同的 REST api 并且工作正常。
此外,我尝试从 here 执行以下代码。但面临同样的问题。
请帮助我确定无法连接保险库的原因。
我试图重现你的问题但失败了。
我认为您的问题可能是由于 permission
为您的应用程序授权 keyvault API。
您可以参考下面适合我的代码。
计划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;
}
}
结果:
请注意,您应该授权您的应用程序使用密钥或秘密。
这是 official doc.
中提到的 powershell
方式
Set-AzureRmKeyVaultAccessPolicy -VaultName 'XXXXXXX' -ServicePrincipalName XXXXX -PermissionsToKeys decrypt,sign,get,unwrapKey
更新答案:
我不确定您的应用程序是否有权调用 KeyVault API
。您可以在门户网站上添加此权限。
希望对你有帮助。
找出问题所在,问题出在 client_secret 上,它在生成时有一些特殊字符,如 %。看来,Azure Key Vault 正在接受使用 base64 编码加密的客户端机密,它是特殊字符。
我是 Azure 相关概念的新手,在连接 Azure Key Vault 时遇到问题。
请找到我的代码片段如下,让我知道为什么会出现以下异常:
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)
相应的代码正在尝试连接 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());
注意:我在邮递员中使用相同的客户端 ID 和客户端密码来连接不同的 REST api 并且工作正常。
此外,我尝试从 here 执行以下代码。但面临同样的问题。
请帮助我确定无法连接保险库的原因。
我试图重现你的问题但失败了。
我认为您的问题可能是由于 permission
为您的应用程序授权 keyvault API。
您可以参考下面适合我的代码。
计划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;
}
}
结果:
请注意,您应该授权您的应用程序使用密钥或秘密。 这是 official doc.
中提到的powershell
方式
Set-AzureRmKeyVaultAccessPolicy -VaultName 'XXXXXXX' -ServicePrincipalName XXXXX -PermissionsToKeys decrypt,sign,get,unwrapKey
更新答案:
我不确定您的应用程序是否有权调用 KeyVault API
。您可以在门户网站上添加此权限。
希望对你有帮助。
找出问题所在,问题出在 client_secret 上,它在生成时有一些特殊字符,如 %。看来,Azure Key Vault 正在接受使用 base64 编码加密的客户端机密,它是特殊字符。