0
votes

I am trying to get secret from azure keyvault. When i run class independently from main method it returns secret but when i integrated this same code in servlet application at code line future.get(); here it gets blocks it do not proceed further like a deadlock it keeps waiting and sometime get java.util.concurrent.ExecutionException: java.lang.ClassCastException: java.lang.String cannot be cast to java.util.List and com.microsoft.azure.keyvault.models.KeyVaultErrorException: Status code 401, {"error":{"code":"Unauthorized","message":"AKV10001: Unable to parse JWT token: expected 3 compact JSON elements, found 1."}} at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) .Please help me on this.

public class KeyVaultTest {

private static AuthenticationResult getAccessToken(String authorization, String resource) throws InterruptedException, ExecutionException, MalformedURLException {

    String clientId = "XXX"; // Client ID
    String clientSecret = "XXX";  //Client Secret

    AuthenticationResult result = null;

    //Starts a service to fetch access token.
    ExecutorService service = null;
    try {
        service = Executors.newFixedThreadPool(1);
        AuthenticationContext context = new AuthenticationContext(authorization, false, service);

        Future<AuthenticationResult> future = null;

        //Acquires token based on client ID and client secret.
        if (clientSecret != null && clientSecret != null) {
            ClientCredential credentials = new ClientCredential(clientId, clientSecret);
            future = context.acquireToken(resource, credentials, null);
        }

        result = future.get();
    } finally {
        service.shutdown();
    }

    if (result == null) {
        throw new RuntimeException("Authentication results were null.");
    }
    return result;
}

public static void main(String[] args) {
    String vaultBase = "https://myapp-keyvault.vault.azure.net/";
    
    

    KeyVaultClient keyVaultClient = new KeyVaultClient(new KeyVaultCredentials(){
        @Override
        public String doAuthenticate(String authorization, String resource, String scope) {
            String token = null;
            try {
                AuthenticationResult authResult = getAccessToken(authorization, resource);
                token = authResult.getAccessToken();
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(token);
            return token;
        }
    });

    SecretBundle secretBundle = keyVaultClient.getSecret(vaultBase, "abc");
    System.out.println(secretBundle.value());
           
     
   
}

}enter image description here

2

2 Answers

0
votes

If you want to access Azure key vault in your servlet application, please refer to the following steps

  1. Configure Azure key vault
#create service pricipal
az ad sp create-for-rbac -n "MyApp" --password "hVFkk965BuUv" --skip-assignment --sdk-auth
#set access policy
az keyvault set-policy -n <your-unique-keyvault-name> --spn <clientId-of-your-service-principal> --secret-permissions list get set delete purge
  1. Application

    a. SDK

     <dependency>
      <groupId>com.microsoft.azure</groupId>
      <artifactId>adal4j</artifactId>
      <version>1.6.5</version>
    </dependency>
    
    
    <dependency>
      <groupId>com.microsoft.azure</groupId>
      <artifactId>azure-keyvault</artifactId>
      <version>1.2.4</version>
    </dependency>
    

    b. Servlet Class

        @WebServlet("/HelloServlet")
        public class HelloServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
    
        public HelloServlet() {
            super();
        }

        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String appId="42e0d080-b1f3-40cf-8db6-c4c522d988c4";
            String appSecret="Gbx2eK64iqq_g_3NCA.ClJDfQpIjoae:";
            KeyVaultClient keyVaultClient = new KeyVaultClient(new AzureKeyVaultCredential(appId,appSecret));
            String vaultBaseUrl="https://testsql08.vault.azure.net/";
            String secretName="sql";
            SecretBundle secret =keyVaultClient.getSecret(vaultBaseUrl, secretName);
            System.out.println(secret.value());
            PrintWriter writer = response.getWriter();
            writer.println("<h1>Hello " + secret.value() + "</h1>");
            writer.close();
        }
    }
    
    class AzureKeyVaultCredential extends KeyVaultCredentials {
        private String appId;
        private String appSecret;
    
        public AzureKeyVaultCredential(String appId, String appSecret) {
            this.appId = appId;
            this.appSecret = appSecret;
        }
    
        @Override
        public String doAuthenticate(String authorization, String resource, String scope) {
            AuthenticationContext context = null;
            AuthenticationResult result = null;
            String token = "";
    
            try {
                context = new AuthenticationContext(authorization, false, Executors.newSingleThreadExecutor());
    
                ClientCredential credential = new ClientCredential(this.appId, this.appSecret);
    
                Future<AuthenticationResult> future = context.acquireToken(resource, credential, null);
                result = future.get(3, TimeUnit.MINUTES);
                token = result.getAccessToken();
    
            } catch (Exception e) {
                e.printStackTrace();
            }
            return token;
        }
    }
  1. Test (I use Tomcat 9.0.22.0 to run the application ) enter image description here
0
votes

your keyvault most likely has IPv4/CIDR restrictions. check your IP and make sure it's on that list OR make sure you route your traffic through an approved IP (VPN)