com.microsoft.azure.storage.util.KeyVaultUtility.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.azure.storage.util.KeyVaultUtility.java

Source

/**
 * Copyright Microsoft Corporation
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.microsoft.azure.storage.util;

import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

import org.apache.commons.codec.binary.Base64;
import org.apache.http.impl.client.HttpClientBuilder;

import com.microsoft.azure.keyvault.KeyVaultClient;
import com.microsoft.azure.keyvault.KeyVaultClientImpl;
import com.microsoft.azure.keyvault.models.Secret;
import com.microsoft.windowsazure.exception.ServiceException;

/**
 * A utility class for interacting with KeyVault
 */
public class KeyVaultUtility {
    /**
     * Creates a secret in Azure Key Vault and returns its ID.
     * 
     * @param secretName
     *            The name of the secret to create
     * @return The ID of the created secret
     * @throws InterruptedException
     * @throws ExecutionException
     * @throws NoSuchAlgorithmException
     * @throws URISyntaxException
     * @throws MalformedURLException
     */
    public static String SetUpKeyVaultSecret(String secretName) throws InterruptedException, ExecutionException,
            NoSuchAlgorithmException, URISyntaxException, MalformedURLException {
        KeyVaultClient cloudVault = GetKeyVaultClient();

        if (Utility.vaultURL == null || Utility.vaultURL.isEmpty()) {
            throw new IllegalArgumentException("No Keyvault URL specified.");
        }

        try {
            // Delete the secret if it exists.
            cloudVault.deleteSecretAsync(Utility.vaultURL, secretName).get();
        } catch (ExecutionException ex) {
            boolean keyNotFound = false;
            if (ex.getCause().getClass() == ServiceException.class) {
                ServiceException serviceException = (ServiceException) ex.getCause();
                if (serviceException.getHttpStatusCode() == 404) {
                    keyNotFound = true;
                }
            }

            if (!keyNotFound) {
                System.out.println(
                        "Unable to access the specified vault. Please confirm the KVClientId, KVClientKey, and VaultUri are valid in the app.config file.");
                System.out.println(
                        "Also ensure that the client ID has previously been granted full permissions for Key Vault secrets using the Set-AzureKeyVaultAccessPolicy command with the -PermissionsToSecrets parameter.");
                System.out.println("Press any key to exit");
                Scanner input = new Scanner(System.in);
                input.nextLine();
                input.close();
                throw ex;
            }
        }

        // Create a 256bit symmetric key and convert it to Base64.
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(256); // Note that we cannot use SymmetricKey.KeySize256,
                          // because this resolves to '0x20'.
        SecretKey wrapKey = keyGen.generateKey();

        // Store the Base64 of the key in the key vault. Note that the
        // content-type of the secret must
        // be application/octet-stream or the KeyVaultKeyResolver will not load
        // it as a key.
        Map<String, String> headers = new HashMap<String, String>();
        headers.put("Content-Type", "application/octet-stream");
        Secret cloudSecret = cloudVault.setSecretAsync(Utility.vaultURL, secretName,
                Base64.encodeBase64String(wrapKey.getEncoded()), "application/octet-stream", null, null).get();

        // Return the base identifier of the secret. This will be resolved to
        // the current version of the secret.
        return cloudSecret.getSecretIdentifier().getBaseIdentifier();
    }

    /**
     * Creates the KeyVaultClient using the credentials specified in the Utility
     * class.
     * 
     * @return
     * @throws URISyntaxException
     * @throws MalformedURLException
     * @throws InterruptedException
     * @throws ExecutionException
     */
    public static KeyVaultClient GetKeyVaultClient()
            throws URISyntaxException, MalformedURLException, InterruptedException, ExecutionException {
        if (Utility.AuthClientId == null || Utility.AuthClientId.isEmpty() || Utility.AuthClientSecret == null
                || Utility.AuthClientSecret.isEmpty()) {
            throw new IllegalArgumentException("Invalid AuthClientID or AuthClientSecret specified.");
        }

        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        ExecutorService executorService = Executors.newCachedThreadPool();
        KVCredentials creds = new KVCredentials(Utility.AuthClientId, Utility.AuthClientSecret);
        KeyVaultClient cloudVault = new KeyVaultClientImpl(httpClientBuilder, executorService, creds);
        return cloudVault;
    }

    /**
     * Helper method to create a new secret on the KeyVault service.
     * 
     * @param defaultKeyName
     *            The default key name to use if the user does not provide one
     * @return The keyID for the newly-created secret (or the existing secret,
     *         if one was passed in.)
     * @throws InterruptedException
     * @throws ExecutionException
     * @throws NoSuchAlgorithmException
     * @throws URISyntaxException
     * @throws MalformedURLException
     */
    public static String createSecret(String defaultKeyName) throws InterruptedException, ExecutionException,
            NoSuchAlgorithmException, URISyntaxException, MalformedURLException {
        System.out.println("No secret specified in Utility class.");
        System.out.println("Please enter the name of a new secret to create in Key Vault.");
        System.out.println("WARNING: This will delete any existing secret with the same name.");
        System.out.println("If nothing is entered, the value \"" + defaultKeyName + "\" will be used.");

        @SuppressWarnings("resource")
        Scanner input = new Scanner(System.in);
        String newSecretName = input.nextLine();

        if (newSecretName == null || newSecretName.isEmpty()) {
            newSecretName = defaultKeyName;
        }

        // Although it is possible to use keys (rather than secrets) stored in
        // Key Vault, this prevents caching.
        // Therefore it is recommended to use secrets along with a caching
        // resolver (see below).
        String keyID = KeyVaultUtility.SetUpKeyVaultSecret(newSecretName);

        System.out.println();
        System.out.println("Created a secret with ID: " + keyID);
        System.out.println("Copy the secret ID to App.config to reuse.");
        System.out.println();
        return keyID;
    }
}