diff --git a/sdk/resourcemanager/azure-resourcemanager-appplatform/src/test/java/com/azure/resourcemanager/appplatform/SpringCloudLiveOnlyTest.java b/sdk/resourcemanager/azure-resourcemanager-appplatform/src/test/java/com/azure/resourcemanager/appplatform/SpringCloudLiveOnlyTest.java index e600066f9633..1d6af96dad10 100644 --- a/sdk/resourcemanager/azure-resourcemanager-appplatform/src/test/java/com/azure/resourcemanager/appplatform/SpringCloudLiveOnlyTest.java +++ b/sdk/resourcemanager/azure-resourcemanager-appplatform/src/test/java/com/azure/resourcemanager/appplatform/SpringCloudLiveOnlyTest.java @@ -3,21 +3,19 @@ package com.azure.resourcemanager.appplatform; +import com.azure.core.management.Region; import com.azure.core.test.annotation.DoNotRecord; import com.azure.resourcemanager.appplatform.models.RuntimeVersion; import com.azure.resourcemanager.appplatform.models.SpringApp; import com.azure.resourcemanager.appplatform.models.SpringAppDeployment; import com.azure.resourcemanager.appplatform.models.SpringService; -import com.azure.resourcemanager.appservice.models.AppServiceCertificateOrder; import com.azure.resourcemanager.appservice.models.AppServiceDomain; import com.azure.resourcemanager.dns.models.DnsZone; import com.azure.resourcemanager.keyvault.models.CertificatePermissions; -import com.azure.resourcemanager.keyvault.models.Secret; import com.azure.resourcemanager.keyvault.models.SecretPermissions; import com.azure.resourcemanager.keyvault.models.Vault; import com.azure.resourcemanager.resources.fluentcore.arm.CountryIsoCode; import com.azure.resourcemanager.resources.fluentcore.arm.CountryPhoneCode; -import com.azure.core.management.Region; import com.azure.security.keyvault.certificates.CertificateClient; import com.azure.security.keyvault.certificates.CertificateClientBuilder; import com.azure.security.keyvault.certificates.models.ImportCertificateOptions; @@ -28,19 +26,33 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; import javax.xml.bind.DatatypeConverter; +import java.io.BufferedReader; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.security.KeyManagementException; import java.security.KeyStore; import java.security.MessageDigest; -import java.util.Base64; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.List; public class SpringCloudLiveOnlyTest extends AppPlatformTest { private static final String PIGGYMETRICS_CONFIG_URL = "https://github.com/Azure-Samples/piggymetrics-config"; @@ -150,6 +162,14 @@ public void canCreateCustomDomainWithSsl() throws Exception { String appName = "gateway"; Region region = Region.US_EAST; + allowAllSSL(); + String cerPassword = password(); + String cerPath = this.getClass().getResource("/").getPath() + domainName + ".cer"; + String pfxPath = this.getClass().getResource("/").getPath() + domainName + ".pfx"; + createCertificate(cerPath, pfxPath, domainName, cerPassword, "ssl." + domainName, "ssl." + domainName); + + byte[] certificate = readAllBytes(new FileInputStream(pfxPath)); + appPlatformManager.resourceManager().resourceGroups().define(rgName) .withRegion(region) .create(); @@ -178,17 +198,9 @@ public void canCreateCustomDomainWithSsl() throws Exception { .withExistingDnsZone(dnsZone) .create(); - AppServiceCertificateOrder certificateOrder = appServiceManager.certificateOrders().define(certOrderName) + Vault vault = keyVaultManager.vaults().define(vaultName) + .withRegion(region) .withExistingResourceGroup(rgName) - .withHostName(String.format("*.%s", domainName)) - .withWildcardSku() - .withDomainVerification(domain) - .withNewKeyVault(vaultName, region) - .withAutoRenew(true) - .create(); - - Vault vault = keyVaultManager.vaults().getByResourceGroup(rgName, vaultName); - vault.update() .defineAccessPolicy() .forServicePrincipal(clientIdFromFile()) .allowSecretAllPermissions() @@ -199,11 +211,7 @@ public void canCreateCustomDomainWithSsl() throws Exception { .allowCertificatePermissions(CertificatePermissions.GET, CertificatePermissions.LIST) .allowSecretPermissions(SecretPermissions.GET, SecretPermissions.LIST) .attach() - .apply(); - - Secret secret = vault.secrets().getByName(certOrderName); - - byte[] certificate = Base64.getDecoder().decode(secret.getValue()); + .create(); // upload certificate CertificateClient certificateClient = new CertificateClientBuilder() @@ -213,12 +221,13 @@ public void canCreateCustomDomainWithSsl() throws Exception { certificateClient.importCertificate( new ImportCertificateOptions(certName, certificate) + .setPassword(cerPassword) .setEnabled(true) ); // get thumbprint KeyStore store = KeyStore.getInstance("PKCS12"); - store.load(new ByteArrayInputStream(certificate), null); + store.load(new ByteArrayInputStream(certificate), cerPassword.toCharArray()); String alias = Collections.list(store.aliases()).get(0); String thumbprint = DatatypeConverter.printHexBinary(MessageDigest.getInstance("SHA-1").digest(store.getCertificate(alias).getEncoded())); @@ -275,4 +284,123 @@ private void extraTarGzSource(File folder, URL url) throws IOException { connection.disconnect(); } } + + private byte[] readAllBytes(InputStream inputStream) throws IOException { + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + byte[] data = new byte[4096]; + while (true) { + int size = inputStream.read(data); + if (size > 0) { + outputStream.write(data, 0, size); + } else { + return outputStream.toByteArray(); + } + } + } + } + + public static void createCertificate(String certPath, String pfxPath, + String alias, String password, String cnName, String dnsName) throws IOException { + if (new File(pfxPath).exists()) { + return; + } + String validityInDays = "3650"; + String keyAlg = "RSA"; + String sigAlg = "SHA1withRSA"; + String keySize = "2048"; + String storeType = "pkcs12"; + String command = "keytool"; + String jdkPath = System.getProperty("java.home"); + if (jdkPath != null && !jdkPath.isEmpty()) { + jdkPath = jdkPath.concat("\\bin"); + if (new File(jdkPath).isDirectory()) { + command = String.format("%s%s%s", jdkPath, File.separator, command); + } + } else { + return; + } + + // Create Pfx file + String[] commandArgs = {command, "-genkey", "-alias", alias, + "-keystore", pfxPath, "-storepass", password, "-validity", + validityInDays, "-keyalg", keyAlg, "-sigalg", sigAlg, "-keysize", keySize, + "-storetype", storeType, "-dname", "CN=" + cnName, "-ext", "EKU=1.3.6.1.5.5.7.3.1"}; + if (dnsName != null) { + List args = new ArrayList<>(Arrays.asList(commandArgs)); + args.add("-ext"); + args.add("san=dns:" + dnsName); + commandArgs = args.toArray(new String[0]); + } + cmdInvocation(commandArgs, true); + + // Create cer file i.e. extract public key from pfx + File pfxFile = new File(pfxPath); + if (pfxFile.exists()) { + String[] certCommandArgs = {command, "-export", "-alias", alias, + "-storetype", storeType, "-keystore", pfxPath, + "-storepass", password, "-rfc", "-file", certPath}; + // output of keytool export command is going to error stream + // although command is + // executed successfully, hence ignoring error stream in this case + cmdInvocation(certCommandArgs, true); + + // Check if file got created or not + File cerFile = new File(pfxPath); + if (!cerFile.exists()) { + throw new IOException( + "Error occurred while creating certificate" + + String.join(" ", certCommandArgs)); + } + } else { + throw new IOException("Error occurred while creating certificates" + + String.join(" ", commandArgs)); + } + } + + public static String cmdInvocation(String[] command, + boolean ignoreErrorStream) throws IOException { + String result = ""; + String error = ""; + + Process process = new ProcessBuilder(command).start(); + try ( + InputStream inputStream = process.getInputStream(); + InputStream errorStream = process.getErrorStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + BufferedReader ebr = new BufferedReader(new InputStreamReader(errorStream, StandardCharsets.UTF_8)); + ) { + result = br.readLine(); + process.waitFor(); + error = ebr.readLine(); + if (error != null && (!error.equals(""))) { + // To do - Log error message + + if (!ignoreErrorStream) { + throw new IOException(error, null); + } + } + } catch (Exception e) { + throw new RuntimeException("Exception occurred while invoking command", e); + } + return result; + } + + private static void allowAllSSL() throws NoSuchAlgorithmException, KeyManagementException { + TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + public void checkClientTrusted( + java.security.cert.X509Certificate[] certs, String authType) { + } + public void checkServerTrusted( + java.security.cert.X509Certificate[] certs, String authType) { + } + } + }; + SSLContext sslContext = SSLContext.getInstance("SSL"); + sslContext.init(null, trustAllCerts, new SecureRandom()); + HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); + } } diff --git a/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/appplatform/samples/ManageSpringCloud.java b/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/appplatform/samples/ManageSpringCloud.java index 4cce0601d20c..5d477cfde58e 100644 --- a/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/appplatform/samples/ManageSpringCloud.java +++ b/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/appplatform/samples/ManageSpringCloud.java @@ -187,19 +187,17 @@ // .withCNameRecordSet("ssl", gateway.fqdn()) // .apply(); // -// System.out.printf("Purchasing a certificate for *.%s and save to %s in key vault named %s ...%n", domainName, certOrderName, vaultName); -// AppServiceCertificateOrder certificateOrder = azureResourceManager.appServiceCertificateOrders().define(certOrderName) -// .withExistingResourceGroup(rgName) -// .withHostName(String.format("*.%s", domainName)) -// .withWildcardSku() -// .withDomainVerification(domain) -// .withNewKeyVault(vaultName, region) -// .withAutoRenew(true) -// .create(); -// System.out.printf("Purchased certificate: *.%s ...%n", domain.name()); -// Utils.print(certificateOrder); +// // Please use a trusted certificate for actual use +// System.out.printf("Generate a self-signed certificate for ssl.%s %n", domainName); +// allowAllSSL(); +// String cerPassword = password(); +// String cerPath = ManageSpringCloud.class.getResource("/").getPath() + domainName + ".cer"; +// String pfxPath = ManageSpringCloud.class.getClass().getResource("/").getPath() + domainName + ".pfx"; +// createCertificate(cerPath, pfxPath, domainName, cerPassword, "ssl." + domainName, "ssl." + domainName); +// +// byte[] certificate = readAllBytes(new FileInputStream(pfxPath)); // -// System.out.printf("Updating key vault %s with access from %s, %s%n", vaultName, clientId, SPRING_CLOUD_SERVICE_PRINCIPAL); +// System.out.printf("Creating key vault %s with access from %s, %s%n", vaultName, clientId, SPRING_CLOUD_SERVICE_PRINCIPAL); // Vault vault = azureResourceManager.vaults().getByResourceGroup(rgName, vaultName); // vault.update() // .defineAccessPolicy() @@ -213,20 +211,13 @@ // .allowSecretPermissions(SecretPermissions.GET, SecretPermissions.LIST) // .attach() // .apply(); -// System.out.printf("Updated key vault %s%n", vault.name()); +// System.out.printf("Created key vault %s%n", vault.name()); // Utils.print(vault); // -// Secret secret = vault.secrets().getByName(certOrderName); -// -// byte[] certificate = Base64.getDecoder().decode(secret.getValue()); -// -// String thumbprint = secret.tags().get("Thumbprint"); -// if (thumbprint == null || thumbprint.isEmpty()) { -// KeyStore store = KeyStore.getInstance("PKCS12"); -// store.load(new ByteArrayInputStream(certificate), null); -// String alias = Collections.list(store.aliases()).get(0); -// thumbprint = DatatypeConverter.printHexBinary(MessageDigest.getInstance("SHA-1").digest(store.getCertificate(alias).getEncoded())); -// } +// KeyStore store = KeyStore.getInstance("PKCS12"); +// store.load(new ByteArrayInputStream(certificate), cerPassword.toCharArray()); +// String alias = Collections.list(store.aliases()).get(0); +// thumbprint = DatatypeConverter.printHexBinary(MessageDigest.getInstance("SHA-1").digest(store.getCertificate(alias).getEncoded())); // // System.out.printf("Get certificate: %s%n", secret.getValue()); // System.out.printf("Certificate Thumbprint: %s%n", thumbprint); @@ -240,6 +231,7 @@ // System.out.printf("Uploading certificate to %s in key vault ...%n", certName); // certificateClient.importCertificate( // new ImportCertificateOptions(certName, certificate) +// .setPassword(cerPassword) // .setEnabled(true) // ); // @@ -323,4 +315,23 @@ // connection.disconnect(); // } // } +// +// private static void allowAllSSL() throws NoSuchAlgorithmException, KeyManagementException { +// TrustManager[] trustAllCerts = new TrustManager[]{ +// new X509TrustManager() { +// public java.security.cert.X509Certificate[] getAcceptedIssuers() { +// return null; +// } +// public void checkClientTrusted( +// java.security.cert.X509Certificate[] certs, String authType) { +// } +// public void checkServerTrusted( +// java.security.cert.X509Certificate[] certs, String authType) { +// } +// } +// }; +// SSLContext sslContext = SSLContext.getInstance("SSL"); +// sslContext.init(null, trustAllCerts, new SecureRandom()); +// HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); +// } //} diff --git a/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/appservice/samples/ManageFunctionAppWithDomainSsl.java b/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/appservice/samples/ManageFunctionAppWithDomainSsl.java index 6dff00bf7722..95b966ac3ea8 100644 --- a/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/appservice/samples/ManageFunctionAppWithDomainSsl.java +++ b/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/appservice/samples/ManageFunctionAppWithDomainSsl.java @@ -120,7 +120,7 @@ public static boolean runSample(AzureResourceManager azureResourceManager) throw System.out.println("Creating a self-signed certificate " + pfxPath + "..."); - Utils.createCertificate(cerPath, pfxPath, domainName, certPassword, "*." + domainName); + Utils.createCertificate(cerPath, pfxPath, domainName, certPassword, "*." + domainName, null); System.out.println("Created self-signed certificate " + pfxPath); diff --git a/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/appservice/samples/ManageLinuxWebAppWithDomainSsl.java b/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/appservice/samples/ManageLinuxWebAppWithDomainSsl.java index 5f76377120ac..1b6278ba7d3c 100644 --- a/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/appservice/samples/ManageLinuxWebAppWithDomainSsl.java +++ b/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/appservice/samples/ManageLinuxWebAppWithDomainSsl.java @@ -127,7 +127,7 @@ public static boolean runSample(AzureResourceManager azureResourceManager) throw System.out.println("Creating a self-signed certificate " + pfxPath + "..."); - Utils.createCertificate(cerPath, pfxPath, domainName, certPassword, "*." + domainName); + Utils.createCertificate(cerPath, pfxPath, domainName, certPassword, "*." + domainName, null); System.out.println("Created self-signed certificate " + pfxPath); diff --git a/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/appservice/samples/ManageWebAppWithDomainSsl.java b/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/appservice/samples/ManageWebAppWithDomainSsl.java index 6f778547430c..d60972ed3e07 100644 --- a/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/appservice/samples/ManageWebAppWithDomainSsl.java +++ b/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/appservice/samples/ManageWebAppWithDomainSsl.java @@ -124,7 +124,7 @@ public static boolean runSample(AzureResourceManager azureResourceManager) throw System.out.println("Creating a self-signed certificate " + pfxPath + "..."); - Utils.createCertificate(cerPath, pfxPath, domainName, certPassword, "*." + domainName); + Utils.createCertificate(cerPath, pfxPath, domainName, certPassword, "*." + domainName, null); System.out.println("Created self-signed certificate " + pfxPath); diff --git a/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/samples/Utils.java b/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/samples/Utils.java index f4e3e407c3e7..93a3eb756d96 100644 --- a/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/samples/Utils.java +++ b/sdk/resourcemanager/azure-resourcemanager-samples/src/main/java/com/azure/resourcemanager/samples/Utils.java @@ -166,6 +166,7 @@ import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; @@ -1589,11 +1590,12 @@ public static String getSecondaryServicePrincipalSecret(String envSecondaryServi * @param alias User alias * @param password alias password * @param cnName domain name + * @param dnsName dns name in subject alternate name * @throws Exception exceptions from the creation * @throws IOException IO Exception */ - public static void createCertificate(String certPath, String pfxPath, - String alias, String password, String cnName) throws IOException { + public static void createCertificate(String certPath, String pfxPath, String alias, + String password, String cnName, String dnsName) throws IOException { if (new File(pfxPath).exists()) { return; } @@ -1618,6 +1620,12 @@ public static void createCertificate(String certPath, String pfxPath, "-keystore", pfxPath, "-storepass", password, "-validity", validityInDays, "-keyalg", keyAlg, "-sigalg", sigAlg, "-keysize", keySize, "-storetype", storeType, "-dname", "CN=" + cnName, "-ext", "EKU=1.3.6.1.5.5.7.3.1"}; + if (dnsName != null) { + List args = new ArrayList<>(Arrays.asList(commandArgs)); + args.add("-ext"); + args.add("san=dns:" + dnsName); + commandArgs = args.toArray(new String[0]); + } Utils.cmdInvocation(commandArgs, true); // Create cer file i.e. extract public key from pfx