diff --git a/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrCertificateImportHandler.java b/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrCertificateImportHandler.java new file mode 100644 index 00000000000..cdaadbba509 --- /dev/null +++ b/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrCertificateImportHandler.java @@ -0,0 +1,75 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.core.instmgr; + +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ATTACHED_STREAMS; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.FILESYSTEM_PATH; + +import java.io.InputStream; +import java.nio.file.Path; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationDefinition; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.OperationStepHandler; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.SimpleOperationDefinitionBuilder; +import org.jboss.as.controller.registry.OperationEntry; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.installationmanager.MavenOptions; +import org.wildfly.installationmanager.spi.InstallationManager; +import org.wildfly.installationmanager.spi.InstallationManagerFactory; + +/** + * Operation handler to get the history of the installation manager changes, either artifacts or configuration metadata as + * channel changes. + */ +public class InstMgrCertificateImportHandler extends InstMgrOperationStepHandler { + public static final String OPERATION_NAME = "certificate-import"; + + protected static final AttributeDefinition CERT_FILE = SimpleAttributeDefinitionBuilder.create(InstMgrConstants.CERT_FILE, ModelType.INT) + .setStorageRuntime() + .setRequired(true) + .addArbitraryDescriptor(FILESYSTEM_PATH, ModelNode.TRUE) + .addArbitraryDescriptor(ATTACHED_STREAMS, ModelNode.TRUE) + .build(); + + public static final OperationDefinition DEFINITION = new SimpleOperationDefinitionBuilder(OPERATION_NAME, InstMgrResolver.RESOLVER) + .withFlags(OperationEntry.Flag.HOST_CONTROLLER_ONLY) + .setReplyType(ModelType.OBJECT) + .setRuntimeOnly() + .setReplyValueType(ModelType.OBJECT) + .addParameter(CERT_FILE) + .build(); + + InstMgrCertificateImportHandler(InstMgrService imService, InstallationManagerFactory imf) { + super(imService, imf); + } + + @Override + public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { + context.addStep(new OperationStepHandler() { + @Override + public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { + try { + Path serverHome = imService.getHomeDir(); + MavenOptions mavenOptions = new MavenOptions(null, false); + InstallationManager installationManager = imf.create(serverHome, mavenOptions); + + try (InputStream is = context.getAttachmentStream(CERT_FILE.resolveModelAttribute(context, operation).asInt())) { + installationManager.acceptTrustedCertificates(is); + } + } catch (OperationFailedException | RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }, OperationContext.Stage.RUNTIME); + } +} diff --git a/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrCertificateParseHandler.java b/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrCertificateParseHandler.java new file mode 100644 index 00000000000..5a16df4ddec --- /dev/null +++ b/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrCertificateParseHandler.java @@ -0,0 +1,87 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.core.instmgr; + +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ATTACHED_STREAMS; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.FILESYSTEM_PATH; +import static org.wildfly.core.instmgr.InstMgrConstants.CERT_DESCRIPTION; +import static org.wildfly.core.instmgr.InstMgrConstants.CERT_FINGERPRINT; +import static org.wildfly.core.instmgr.InstMgrConstants.CERT_KEY_ID; +import static org.wildfly.core.instmgr.InstMgrConstants.CERT_STATUS; + +import java.io.InputStream; +import java.nio.file.Path; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationDefinition; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.OperationStepHandler; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.SimpleOperationDefinitionBuilder; +import org.jboss.as.controller.registry.OperationEntry; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.installationmanager.MavenOptions; +import org.wildfly.installationmanager.TrustCertificate; +import org.wildfly.installationmanager.spi.InstallationManager; +import org.wildfly.installationmanager.spi.InstallationManagerFactory; + +/** + * Operation handler to get the history of the installation manager changes, either artifacts or configuration metadata as + * channel changes. + */ +public class InstMgrCertificateParseHandler extends InstMgrOperationStepHandler { + public static final String OPERATION_NAME = "certificate-parse"; + + protected static final AttributeDefinition CERT_FILE = SimpleAttributeDefinitionBuilder.create(InstMgrConstants.CERT_FILE, ModelType.INT) + .setStorageRuntime() + .setRequired(true) + .addArbitraryDescriptor(FILESYSTEM_PATH, ModelNode.TRUE) + .addArbitraryDescriptor(ATTACHED_STREAMS, ModelNode.TRUE) + .build(); + + public static final OperationDefinition DEFINITION = new SimpleOperationDefinitionBuilder(OPERATION_NAME, InstMgrResolver.RESOLVER) + .withFlags(OperationEntry.Flag.HOST_CONTROLLER_ONLY) + .setReplyType(ModelType.OBJECT) + .setRuntimeOnly() + .setReplyValueType(ModelType.OBJECT) + .addParameter(CERT_FILE) + .build(); + + InstMgrCertificateParseHandler(InstMgrService imService, InstallationManagerFactory imf) { + super(imService, imf); + } + + @Override + public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { + context.addStep(new OperationStepHandler() { + @Override + public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { + try { + Path serverHome = imService.getHomeDir(); + MavenOptions mavenOptions = new MavenOptions(null, false); + InstallationManager installationManager = imf.create(serverHome, mavenOptions); + + try (InputStream is = context.getAttachmentStream(CERT_FILE.resolveModelAttribute(context, operation).asInt())) { + TrustCertificate tc = installationManager.parseCA(is); + + ModelNode entry = new ModelNode(); + entry.get(CERT_KEY_ID).set(tc.getKeyID()); + entry.get(CERT_FINGERPRINT).set(tc.getFingerprint()); + entry.get(CERT_DESCRIPTION).set(tc.getDescription()); + entry.get(CERT_STATUS).set(tc.getStatus()); + context.getResult().set(entry); + } + } catch (OperationFailedException | RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }, OperationContext.Stage.RUNTIME); + } +} diff --git a/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrCertificateRemoveHandler.java b/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrCertificateRemoveHandler.java new file mode 100644 index 00000000000..be6b0e1ac22 --- /dev/null +++ b/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrCertificateRemoveHandler.java @@ -0,0 +1,70 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.core.instmgr; + +import static org.wildfly.core.instmgr.InstMgrConstants.CERT_KEY_ID; + +import java.nio.file.Path; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationDefinition; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.OperationStepHandler; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.SimpleOperationDefinitionBuilder; +import org.jboss.as.controller.registry.OperationEntry; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.installationmanager.MavenOptions; +import org.wildfly.installationmanager.spi.InstallationManager; +import org.wildfly.installationmanager.spi.InstallationManagerFactory; + +/** + * Operation handler to get the history of the installation manager changes, either artifacts or configuration metadata as + * channel changes. + */ +public class InstMgrCertificateRemoveHandler extends InstMgrOperationStepHandler { + public static final String OPERATION_NAME = "certificate-remove"; + + protected static final AttributeDefinition KEY_ID = SimpleAttributeDefinitionBuilder.create(CERT_KEY_ID, ModelType.STRING) + .setStorageRuntime() + .setRequired(true) + .build(); + + public static final OperationDefinition DEFINITION = new SimpleOperationDefinitionBuilder(OPERATION_NAME, InstMgrResolver.RESOLVER) + .withFlags(OperationEntry.Flag.HOST_CONTROLLER_ONLY) + .setReplyType(ModelType.OBJECT) + .setRuntimeOnly() + .setReplyValueType(ModelType.OBJECT) + .addParameter(KEY_ID) + .build(); + + InstMgrCertificateRemoveHandler(InstMgrService imService, InstallationManagerFactory imf) { + super(imService, imf); + } + + @Override + public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { + final String keyId = KEY_ID.resolveModelAttribute(context, operation).asString(); + context.addStep(new OperationStepHandler() { + @Override + public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { + try { + Path serverHome = imService.getHomeDir(); + MavenOptions mavenOptions = new MavenOptions(null, false); + InstallationManager installationManager = imf.create(serverHome, mavenOptions); + + installationManager.revokeTrustedCertificate(keyId); + } catch (OperationFailedException | RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }, OperationContext.Stage.RUNTIME); + } +} diff --git a/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrConstants.java b/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrConstants.java index 2abebd93f1f..a68b5a7c788 100644 --- a/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrConstants.java +++ b/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrConstants.java @@ -15,6 +15,12 @@ public interface InstMgrConstants { Path PREPARED_SERVER_SUBPATH = Paths.get("installation-manager") .resolve("prepared-server"); + String CERT_DESCRIPTION = "description"; + String CERT_FINGERPRINT = "fingerprint"; + String CERT_KEY_ID = "key-id"; + String CERT_STATUS = "status"; + String CERT_FILE = "cert-file"; + String CERTIFICATES = "certificates"; String CHANNEL = "channel"; String CHANNELS = "channels"; String CHANNEL_NAME = "name"; diff --git a/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrResourceDefinition.java b/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrResourceDefinition.java index 890cb8c088a..364ce63bd1f 100644 --- a/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrResourceDefinition.java +++ b/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrResourceDefinition.java @@ -39,6 +39,7 @@ import org.wildfly.installationmanager.Channel; import org.wildfly.installationmanager.MavenOptions; import org.wildfly.installationmanager.Repository; +import org.wildfly.installationmanager.TrustCertificate; import org.wildfly.installationmanager.spi.InstallationManager; import org.wildfly.installationmanager.spi.InstallationManagerFactory; @@ -86,6 +87,12 @@ class InstMgrResourceDefinition extends SimpleResourceDefinition { .setRequired(true) .build(); + private static final AttributeDefinition KEY_ID = new SimpleAttributeDefinitionBuilder(InstMgrConstants.CERT_KEY_ID, ModelType.STRING) + .setStorageRuntime() + .setRuntimeServiceNotRequired() + .setRequired(true) + .build(); + private static final AttributeDefinition MANIFEST_GAV = new SimpleAttributeDefinitionBuilder(InstMgrConstants.MANIFEST_GAV, ModelType.STRING) .setAlternatives(InstMgrConstants.MANIFEST_URL) .setStorageRuntime() @@ -115,11 +122,23 @@ class InstMgrResourceDefinition extends SimpleResourceDefinition { .setSuffix("channel") .build(); + private static final ObjectTypeAttributeDefinition CERTIFICATE = ObjectTypeAttributeDefinition.create("certificate", KEY_ID) +// .setValidator(new ChannelValidator()) + .setStorageRuntime() + .setRuntimeServiceNotRequired() + .setRequired(true) + .setSuffix("certificate") + .build(); + private static final AttributeDefinition CHANNELS = ObjectListAttributeDefinition.Builder.of(InstMgrConstants.CHANNELS, CHANNEL) .setStorageRuntime() .setRuntimeServiceNotRequired() .build(); + private static final AttributeDefinition CERTIFICATES = ObjectListAttributeDefinition.Builder.of("certificates", CERTIFICATE) + .setStorageRuntime() + .setRuntimeServiceNotRequired() + .build(); public static PathElement getPath(String name) { return PathElement.pathElement(CORE_SERVICE, name); } @@ -167,11 +186,21 @@ public void registerOperations(ManagementResourceRegistration resourceRegistrati InstMgrCustomPatchRemoveHandler customPatchRemoveHandler = new InstMgrCustomPatchRemoveHandler(imService, imf); resourceRegistration.registerOperationHandler(customPatchRemoveHandler.DEFINITION, customPatchRemoveHandler); + + InstMgrCertificateParseHandler certificateParseHandler = new InstMgrCertificateParseHandler(imService, imf); + resourceRegistration.registerOperationHandler(InstMgrCertificateParseHandler.DEFINITION, certificateParseHandler); + + InstMgrCertificateImportHandler certificateImportHandler = new InstMgrCertificateImportHandler(imService, imf); + resourceRegistration.registerOperationHandler(InstMgrCertificateImportHandler.DEFINITION, certificateImportHandler); + + InstMgrCertificateRemoveHandler certificateRemoveHandler = new InstMgrCertificateRemoveHandler(imService, imf); + resourceRegistration.registerOperationHandler(InstMgrCertificateRemoveHandler.DEFINITION, certificateRemoveHandler); } @Override public void registerAttributes(ManagementResourceRegistration resourceRegistration) { resourceRegistration.registerReadWriteAttribute(CHANNELS, new ReadHandler(), new WriteHandler()); + resourceRegistration.registerReadOnlyAttribute(CERTIFICATES, new CertReadHandler()); } private class WriteHandler implements OperationStepHandler { @@ -364,4 +393,38 @@ public void validateParameter(String parameterName, ModelNode value) throws Oper } } } + + private class CertReadHandler implements OperationStepHandler { + @Override + public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { + context.addStep(new OperationStepHandler() { + @Override + public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { + try { + final ModelNode result = context.getResult(); + Path serverHome = imService.getHomeDir(); + + MavenOptions mavenOptions = new MavenOptions(null, false); + InstallationManager installationManager = imf.create(serverHome, mavenOptions); + + ModelNode mCertificates = new ModelNode().addEmptyList(); + Collection trustedCertificates = installationManager.listCA(); + for (TrustCertificate tc : trustedCertificates) { + ModelNode entry = new ModelNode(); + entry.get(InstMgrConstants.CERT_KEY_ID).set(tc.getKeyID()); + entry.get(InstMgrConstants.CERT_FINGERPRINT).set(tc.getFingerprint()); + entry.get(InstMgrConstants.CERT_DESCRIPTION).set(tc.getDescription()); + entry.get(InstMgrConstants.CERT_STATUS).set(tc.getStatus()); + mCertificates.add(entry); + } + result.set(mCertificates); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }, OperationContext.Stage.RUNTIME); + } + } } diff --git a/installation-manager/src/main/java/org/wildfly/core/instmgr/cli/AbstractInstMgrCommand.java b/installation-manager/src/main/java/org/wildfly/core/instmgr/cli/AbstractInstMgrCommand.java index 578f77b9aeb..85c6d3cdad2 100644 --- a/installation-manager/src/main/java/org/wildfly/core/instmgr/cli/AbstractInstMgrCommand.java +++ b/installation-manager/src/main/java/org/wildfly/core/instmgr/cli/AbstractInstMgrCommand.java @@ -61,6 +61,10 @@ public abstract class AbstractInstMgrCommand implements Command { public static final String COMMAND_NAME = "installer"; diff --git a/installation-manager/src/main/java/org/wildfly/core/instmgr/cli/ListCertificatesCommand.java b/installation-manager/src/main/java/org/wildfly/core/instmgr/cli/ListCertificatesCommand.java new file mode 100644 index 00000000000..c2873e67ffe --- /dev/null +++ b/installation-manager/src/main/java/org/wildfly/core/instmgr/cli/ListCertificatesCommand.java @@ -0,0 +1,93 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.core.instmgr.cli; + +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.NAME; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RESULT; +import static org.wildfly.core.instmgr.InstMgrConstants.CERT_DESCRIPTION; +import static org.wildfly.core.instmgr.InstMgrConstants.CERT_FINGERPRINT; +import static org.wildfly.core.instmgr.InstMgrConstants.CERT_KEY_ID; +import static org.wildfly.core.instmgr.InstMgrConstants.CERT_STATUS; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.aesh.command.CommandDefinition; +import org.aesh.command.CommandException; +import org.aesh.command.CommandResult; +import org.jboss.as.cli.CommandContext; +import org.jboss.as.cli.Util; +import org.jboss.as.controller.client.ModelControllerClient; +import org.jboss.as.controller.client.Operation; +import org.jboss.as.controller.client.OperationBuilder; +import org.jboss.dmr.ModelNode; +import org.wildfly.core.cli.command.aesh.CLICommandInvocation; +import org.wildfly.core.instmgr.InstMgrConstants; + +@CommandDefinition(name = "certificates-list", description = "List trusted component certificates.", activator = InstMgrActivator.class) +public class ListCertificatesCommand extends AbstractInstMgrCommand { + + @Override + protected Operation buildOperation() { + final ModelNode op = new ModelNode(); + op.get(Util.OPERATION).set(Util.READ_RESOURCE); + op.get(Util.INCLUDE_RUNTIME).set(true); + + return OperationBuilder.create(op, true).build(); + } + + @Override + public CommandResult execute(CLICommandInvocation commandInvocation) throws CommandException, InterruptedException { + final CommandContext ctx = commandInvocation.getCommandContext(); + final ModelControllerClient client = ctx.getModelControllerClient(); + if (client == null) { + ctx.printLine("You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands."); + return CommandResult.FAILURE; + } + + ModelNode response = this.executeOp(commandInvocation.getCommandContext(), this.host); + ModelNode result = response.get(Util.RESULT); + List certificatesMn = result.get(InstMgrConstants.CERTIFICATES).asListOrEmpty(); + + if (certificatesMn.isEmpty()) { + ctx.printLine("No component certificates have been trusted for this installation."); + + return CommandResult.SUCCESS; + } + + ctx.printLine("-------"); + for (ModelNode certificate : certificatesMn) { + ctx.printLine("key ID " + certificate.get(CERT_KEY_ID).asString()); + ctx.printLine("fingerprint " + certificate.get(CERT_FINGERPRINT).asString()); + ctx.printLine("description " + certificate.get(CERT_DESCRIPTION).asString()); + ctx.printLine("status " + certificate.get(CERT_STATUS).asString()); + ctx.printLine("-------"); + } + return CommandResult.SUCCESS; + } + + /** + * Returns a Set with the current channel names available on the server installation + * + * @param ctx + * @param host + * @return + * @throws CommandException + */ + Set getAllChannelNames(CommandContext ctx, String host) throws CommandException { + final Set existingChannelNames = new HashSet<>(); + ModelNode listCmdResponse = this.executeOp(ctx, host); + if (listCmdResponse.hasDefined(RESULT)) { + ModelNode result = listCmdResponse.get(RESULT); + List channels = result.get(InstMgrConstants.CHANNELS).asListOrEmpty(); + for (ModelNode channel : channels) { + existingChannelNames.add(channel.get(NAME).asString()); + } + } + return existingChannelNames; + } +} diff --git a/installation-manager/src/main/java/org/wildfly/core/instmgr/cli/RemoveCertificatesCommand.java b/installation-manager/src/main/java/org/wildfly/core/instmgr/cli/RemoveCertificatesCommand.java new file mode 100644 index 00000000000..e33ccaa8460 --- /dev/null +++ b/installation-manager/src/main/java/org/wildfly/core/instmgr/cli/RemoveCertificatesCommand.java @@ -0,0 +1,45 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.core.instmgr.cli; + +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP; +import static org.wildfly.core.instmgr.InstMgrConstants.CERT_KEY_ID; + +import org.aesh.command.CommandDefinition; +import org.aesh.command.CommandException; +import org.aesh.command.CommandResult; +import org.aesh.command.option.Option; +import org.jboss.as.cli.CommandContext; +import org.jboss.as.controller.client.Operation; +import org.jboss.as.controller.client.OperationBuilder; +import org.jboss.dmr.ModelNode; +import org.wildfly.core.cli.command.aesh.CLICommandInvocation; +import org.wildfly.core.instmgr.InstMgrCertificateRemoveHandler; + +@CommandDefinition(name = "certificates-remove", description = "Removes a trusted component certificate.", activator = InstMgrActivator.class) +public class RemoveCertificatesCommand extends AbstractInstMgrCommand { + + @Option(name = CERT_KEY_ID, required = true) + private String keyId; + @Override + protected Operation buildOperation() { + final ModelNode op = new ModelNode(); + + op.get(OP).set(InstMgrCertificateRemoveHandler.DEFINITION.getName()); + op.get(CERT_KEY_ID).set(keyId); + + return OperationBuilder.create(op).build(); + } + + @Override + public CommandResult execute(CLICommandInvocation commandInvocation) throws CommandException, InterruptedException { + final CommandContext ctx = commandInvocation.getCommandContext(); + + this.executeOp(ctx, this.host); + + return CommandResult.SUCCESS; + } +} diff --git a/installation-manager/src/main/resources/org/wildfly/core/instmgr/LocalDescriptions.properties b/installation-manager/src/main/resources/org/wildfly/core/instmgr/LocalDescriptions.properties index 4b6c3af1692..549341f2d05 100644 --- a/installation-manager/src/main/resources/org/wildfly/core/instmgr/LocalDescriptions.properties +++ b/installation-manager/src/main/resources/org/wildfly/core/instmgr/LocalDescriptions.properties @@ -82,3 +82,8 @@ installation-manager.custom-patch.upload-custom-patch.custom-patch-file=A custom installation-manager.custom-patch.remove-custom-patch=Removes a custom patch from the base server. It also removes the channel that provides this custom patch and unsubscribes the installation from this channel. installation-manager.custom-patch.remove-custom-patch.manifest=Channel Manifest maven coordinates associated with the custom patch. Expected format is Maven GA (GroupId:ArtifactId). +installation-manager.certificate-list=Lists certificates used to verify components. +installation-manager.certificate-parse=Parses a certificate +installation-manager.certificate-parse.cert-file=A certificate file +installation-manager.certificate-import=Add a certificate to verify installation components. +installation-manager.certificate-remove=Remove a certificate to verify installation components.