Repository: knox Updated Branches: refs/heads/master 660b5bca0 -> 3760da52f
KNOX-1646 - Improve export-cert command - JKS, PEM, JCEKS, PKCS12 (Lars Francke via lmccay) Project: http://git-wip-us.apache.org/repos/asf/knox/repo Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/3760da52 Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/3760da52 Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/3760da52 Branch: refs/heads/master Commit: 3760da52f4164efcf0db9dc4794c46cc80fdf65c Parents: 660b5bc Author: Larry McCay <lmc...@apache.org> Authored: Fri Nov 30 11:26:31 2018 -0500 Committer: Larry McCay <lmc...@apache.org> Committed: Fri Nov 30 11:27:58 2018 -0500 ---------------------------------------------------------------------- .../resources/build-tools/spotbugs-filter.xml | 2 +- .../org/apache/knox/gateway/util/KnoxCLI.java | 77 +++++++------------- .../apache/knox/gateway/util/KnoxCLITest.java | 27 +++++++ .../security/impl/X509CertificateUtil.java | 22 +++++- 4 files changed, 75 insertions(+), 53 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/knox/blob/3760da52/build-tools/src/main/resources/build-tools/spotbugs-filter.xml ---------------------------------------------------------------------- diff --git a/build-tools/src/main/resources/build-tools/spotbugs-filter.xml b/build-tools/src/main/resources/build-tools/spotbugs-filter.xml index c779bac..3a32686 100644 --- a/build-tools/src/main/resources/build-tools/spotbugs-filter.xml +++ b/build-tools/src/main/resources/build-tools/spotbugs-filter.xml @@ -37,7 +37,7 @@ limitations under the License. <Match> <Class name="org.apache.knox.gateway.services.security.impl.X509CertificateUtil" /> - <Method name="writeCertificateToJKS" /> + <Method name="writeCertificateToKeyStore" /> <Bug pattern="HARD_CODE_PASSWORD" /> </Match> http://git-wip-us.apache.org/repos/asf/knox/blob/3760da52/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java b/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java index 652e90c..108961a 100644 --- a/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java +++ b/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java @@ -181,29 +181,10 @@ public class KnoxCLI extends Configured implements Tool { } /** - * Parse the command line arguments and initialize the data - * <pre> - * % knoxcli version - * % knoxcli list-topologies - * % knoxcli master-create keyName [--size size] [--master mastersecret] [--generate] - * % knoxcli create-alias alias [--cluster clustername] [--generate] [--value v] - * % knoxcli list-alias [--cluster clustername] - * % knoxcli delete=alias alias [--cluster clustername] - * % knoxcli create-cert alias [--hostname h] - * % knoxcli redeploy [--cluster clustername] - * % knoxcli validate-topology [--cluster clustername] | [--path <path/to/file>] - * % knoxcli user-auth-test [--cluster clustername] [--u username] [--p password] - * % knoxcli system-user-auth-test [--cluster clustername] [--d] - * % knoxcli service-test [--u user] [--p password] [--cluster clustername] [--hostname name] [--port port] - * % knoxcli list-registry-clients - * % knoxcli get-registry-acl entryName --registry-client name - * % knoxcli list-provider-configs --registry-client - * % knoxcli upload-provider-config filePath --registry-client name [--entry-name entryName] - * % knoxcli list-descriptors --registry-client - * % knoxcli upload-descriptor filePath --registry-client name [--entry-name entryName] - * % knoxcli delete-provider-config providerConfig --registry-client name - * % knoxcli delete-descriptor descriptor --registry-client name - * </pre> + * Parse the command line arguments and initialize the data. + * + * See the usage information for the commands itself for information on which parameters they take. + * * @param args command line arguments * @return return exit code * @throws IOException exception on starting KnoxCLI @@ -581,22 +562,21 @@ public class KnoxCLI extends Configured implements Tool { } } - public class CertExportCommand extends Command { + public class CertExportCommand extends Command { - public static final String USAGE = "export-cert"; - public static final String DESC = "The export-cert command exports the public certificate\n" + - "from the a gateway.jks keystore with the alias of gateway-identity."; - private static final String GATEWAY_CREDENTIAL_STORE_NAME = "__gateway"; - private static final String GATEWAY_IDENTITY_PASSPHRASE = "gateway-identity-passphrase"; - - public CertExportCommand() { - } + public static final String USAGE = "export-cert [--type PEM|JKS|JCEKS|PKCS12]"; + public static final String DESC = "The export-cert command exports the public certificate\n" + + "from the a gateway.jks keystore with the alias of gateway-identity.\n" + + "It will be exported to `{GATEWAY_HOME}/data/security/keystores/` with a name of `gateway-client-trust.<type>`" + + "Using the --type option you can specify which keystore type you need (default: PEM)\n" + + "NOTE: The password for the JKS, JCEKS and PKCS12 types is `changeit`.\n" + + "It can be changed using: `keytool -storepasswd -storetype <type> -keystore gateway-client-trust.<type>`"; private GatewayConfig getGatewayConfig() { GatewayConfig result; Configuration conf = getConf(); - if( conf != null && conf instanceof GatewayConfig ) { - result = (GatewayConfig)conf; + if (conf instanceof GatewayConfig) { + result = (GatewayConfig) conf; } else { result = new GatewayConfigImpl(); } @@ -607,37 +587,36 @@ public class KnoxCLI extends Configured implements Tool { public void execute() throws Exception { KeystoreService ks = getKeystoreService(); - AliasService as = getAliasService(); - if (ks != null) { try { if (!ks.isKeystoreForGatewayAvailable()) { out.println("No keystore has been created for the gateway. Please use the create-cert command or populate with a CA signed cert of your own."); } - char[] passphrase = as.getPasswordFromAliasForCluster(GATEWAY_CREDENTIAL_STORE_NAME, GATEWAY_IDENTITY_PASSPHRASE); - if (passphrase == null) { - MasterService ms = services.getService("MasterService"); - passphrase = ms.getMasterSecret(); - } + Certificate cert = ks.getKeystoreForGateway().getCertificate("gateway-identity"); String keyStoreDir = getGatewayConfig().getGatewaySecurityDir() + File.separator + "keystores" + File.separator; File ksd = new File(keyStoreDir); if (!ksd.exists()) { - if( !ksd.mkdirs() ) { + if (!ksd.mkdirs()) { // certainly should not happen if the keystore is known to be available throw new ServiceLifecycleException("Unable to create keystores directory" + ksd.getAbsolutePath()); } } - if ("PEM".equals(type) || type == null) { + + if ("PEM".equalsIgnoreCase(type) || type == null) { X509CertificateUtil.writeCertificateToFile(cert, new File(keyStoreDir + "gateway-identity.pem")); out.println("Certificate gateway-identity has been successfully exported to: " + keyStoreDir + "gateway-identity.pem"); - } - else if ("JKS".equals(type)) { - X509CertificateUtil.writeCertificateToJKS(cert, new File(keyStoreDir + "gateway-client-trust.jks")); + } else if ("JKS".equalsIgnoreCase(type)) { + X509CertificateUtil.writeCertificateToJks(cert, new File(keyStoreDir + "gateway-client-trust.jks")); out.println("Certificate gateway-identity has been successfully exported to: " + keyStoreDir + "gateway-client-trust.jks"); - } - else { - out.println("Invalid type for export file provided. Export has not been done. Please use: [PEM|JKS] default value is PEM."); + } else if ("JCEKS".equalsIgnoreCase(type)) { + X509CertificateUtil.writeCertificateToJceks(cert, new File(keyStoreDir + "gateway-client-trust.jceks")); + out.println("Certificate gateway-identity has been successfully exported to: " + keyStoreDir + "gateway-client-trust.jceks"); + } else if ("PKCS12".equalsIgnoreCase(type)) { + X509CertificateUtil.writeCertificateToPkcs12(cert, new File(keyStoreDir + "gateway-client-trust.pkcs12")); + out.println("Certificate gateway-identity has been successfully exported to: " + keyStoreDir + "gateway-client-trust.pkcs12"); + } else { + out.println("Invalid type for export file provided. Export has not been done. Please use: [PEM|JKS|JCEKS|PKCS12] default value is PEM."); } } catch (KeystoreServiceException e) { throw new ServiceLifecycleException("Keystore was not loaded properly - the provided (or persisted) master secret may not match the password for the keystore.", e); http://git-wip-us.apache.org/repos/asf/knox/blob/3760da52/gateway-server/src/test/java/org/apache/knox/gateway/util/KnoxCLITest.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/util/KnoxCLITest.java b/gateway-server/src/test/java/org/apache/knox/gateway/util/KnoxCLITest.java index e40125e..42dbc63 100644 --- a/gateway-server/src/test/java/org/apache/knox/gateway/util/KnoxCLITest.java +++ b/gateway-server/src/test/java/org/apache/knox/gateway/util/KnoxCLITest.java @@ -717,6 +717,33 @@ public class KnoxCLITest { assertTrue(outContent.toString(StandardCharsets.UTF_8.name()), outContent.toString(StandardCharsets.UTF_8.name()).contains("Certificate gateway-identity has been successfully exported to")); assertTrue(outContent.toString(StandardCharsets.UTF_8.name()), outContent.toString(StandardCharsets.UTF_8.name()).contains("gateway-identity.pem")); + // case insensitive + outContent.reset(); + String[] gwCreateArgs2_6 = {"export-cert", "--type", "pem"}; + rc = 0; + rc = cli.run(gwCreateArgs2_6); + assertEquals(0, rc); + assertTrue(outContent.toString(StandardCharsets.UTF_8.name()), outContent.toString(StandardCharsets.UTF_8.name()).contains("Certificate gateway-identity has been successfully exported to")); + assertTrue(outContent.toString(StandardCharsets.UTF_8.name()), outContent.toString(StandardCharsets.UTF_8.name()).contains("gateway-identity.pem")); + + // pkcs12 + outContent.reset(); + String[] gwCreateArgs2_7 = {"export-cert", "--type", "pkcs12"}; + rc = 0; + rc = cli.run(gwCreateArgs2_7); + assertEquals(0, rc); + assertTrue(outContent.toString(StandardCharsets.UTF_8.name()), outContent.toString(StandardCharsets.UTF_8.name()).contains("Certificate gateway-identity has been successfully exported to")); + assertTrue(outContent.toString(StandardCharsets.UTF_8.name()), outContent.toString(StandardCharsets.UTF_8.name()).contains("gateway-identity.pkcs12")); + + // jceks + outContent.reset(); + String[] gwCreateArgs2_8 = {"export-cert", "--type", "jceks"}; + rc = 0; + rc = cli.run(gwCreateArgs2_8); + assertEquals(0, rc); + assertTrue(outContent.toString(StandardCharsets.UTF_8.name()), outContent.toString(StandardCharsets.UTF_8.name()).contains("Certificate gateway-identity has been successfully exported to")); + assertTrue(outContent.toString(StandardCharsets.UTF_8.name()), outContent.toString(StandardCharsets.UTF_8.name()).contains("gateway-identity.jceks")); + outContent.reset(); String[] gwCreateArgs2_5 = {"export-cert"}; rc = 0; http://git-wip-us.apache.org/repos/asf/knox/blob/3760da52/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/X509CertificateUtil.java ---------------------------------------------------------------------- diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/X509CertificateUtil.java b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/X509CertificateUtil.java index 19d0dd0..1cce280 100644 --- a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/X509CertificateUtil.java +++ b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/X509CertificateUtil.java @@ -39,9 +39,9 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Date; -import org.apache.knox.gateway.i18n.messages.MessagesFactory; import org.apache.commons.codec.binary.Base64; import org.apache.knox.gateway.i18n.GatewaySpiMessages; +import org.apache.knox.gateway.i18n.messages.MessagesFactory; public class X509CertificateUtil { @@ -283,9 +283,9 @@ public class X509CertificateUtil { } } - public static void writeCertificateToJKS(Certificate cert, final File file) + private static void writeCertificateToKeyStore(Certificate cert, final File file, String type) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException { - KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); + KeyStore ks = KeyStore.getInstance(type); char[] password = "changeit".toCharArray(); ks.load(null, password); @@ -295,5 +295,21 @@ public class X509CertificateUtil { ks.store(fos, password); } } + + public static void writeCertificateToJks(Certificate cert, final File file) + throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException { + writeCertificateToKeyStore(cert, file, "jks"); + } + + public static void writeCertificateToJceks(Certificate cert, final File file) + throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException { + writeCertificateToKeyStore(cert, file, "jceks"); + } + + public static void writeCertificateToPkcs12(Certificate cert, final File file) + throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException { + writeCertificateToKeyStore(cert, file, "pkcs12"); + } + }