diff --git a/plugin/pom.xml b/plugin/pom.xml index 2e4585a6..c4f16925 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -97,14 +97,6 @@ org.wildfly.launcher wildfly-launcher - - org.wildfly.plugins - wildfly-plugin-core - - - org.wildfly.plugins - wildfly-maven-plugin - org.wildfly.plugins wildfly-plugin-tools diff --git a/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/AbstractBuildBootableJarMojo.java b/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/AbstractBuildBootableJarMojo.java index e16c6343..82d96dae 100644 --- a/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/AbstractBuildBootableJarMojo.java +++ b/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/AbstractBuildBootableJarMojo.java @@ -82,8 +82,6 @@ import org.jboss.galleon.util.IoUtils; import org.jboss.galleon.util.ZipUtils; import org.wildfly.channel.UnresolvedMavenArtifactException; -import org.wildfly.plugin.common.PropertyNames; -import org.wildfly.plugin.core.MavenJBossLogger; import org.wildfly.plugin.tools.PluginProgressTracker; import org.wildfly.plugins.bootablejar.maven.cli.CLIExecutor; @@ -386,7 +384,7 @@ public abstract class AbstractBuildBootableJarMojo extends AbstractMojo { * *

*/ - @Parameter(alias = "channels", property = PropertyNames.CHANNELS) + @Parameter(alias = "channels", property = "wildfly.channels") List channels; MavenProjectArtifactVersions artifactVersions; diff --git a/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/AbstractServerConnection.java b/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/AbstractServerConnection.java new file mode 100644 index 00000000..84ed0924 --- /dev/null +++ b/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/AbstractServerConnection.java @@ -0,0 +1,193 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.plugins.bootablejar.maven.goals; + +import java.net.URISyntaxException; +import java.net.URL; + +import javax.inject.Inject; + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.settings.Server; +import org.apache.maven.settings.Settings; +import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest; +import org.apache.maven.settings.crypto.SettingsDecrypter; +import org.apache.maven.settings.crypto.SettingsDecryptionResult; +import org.jboss.as.controller.client.ModelControllerClient; +import org.jboss.as.controller.client.ModelControllerClientConfiguration; +import org.wildfly.plugin.tools.client.ClientCallbackHandler; + +/** + * The default implementation for connecting to a running WildFly instance + * + * @author James R. Perkins + * @author Stuart Douglas + */ +public abstract class AbstractServerConnection extends AbstractMojo { + + public static final String DEBUG_MESSAGE_NO_CREDS = "No username and password in settings.xml file - falling back to CLI entry"; + public static final String DEBUG_MESSAGE_NO_ID = "No element was found in the POM - Getting credentials from CLI entry"; + public static final String DEBUG_MESSAGE_NO_SERVER_SECTION = "No section was found for the specified id"; + public static final String DEBUG_MESSAGE_NO_SETTINGS_FILE = "No settings.xml file was found in this Mojo's execution context"; + public static final String DEBUG_MESSAGE_POM_HAS_CREDS = "Getting credentials from the POM"; + public static final String DEBUG_MESSAGE_SETTINGS_HAS_CREDS = "Found username and password in the settings.xml file"; + public static final String DEBUG_MESSAGE_SETTINGS_HAS_ID = "Found the server's id in the settings.xml file"; + + static { + // This is odd, but if not set we should set the JBoss Logging provider to slf4j as that is what Maven uses + final String provider = System.getProperty("org.jboss.logging.provider"); + if (provider == null || provider.isBlank()) { + System.setProperty("org.jboss.logging.provider", "slf4j"); + } + } + + /** + * The protocol used to connect to the server for management. + */ + @Parameter(property = "wildfly.protocol") + private String protocol; + + /** + * Specifies the host name of the server where the deployment plan should be executed. + */ + @Parameter(defaultValue = "localhost", property = "wildfly.hostname") + private String hostname; + + /** + * Specifies the port number the server is listening on. + */ + @Parameter(defaultValue = "9990", property = "wildfly.port") + private int port; + + /** + * Specifies the id of the server if the username and password is to be + * retrieved from the settings.xml file + */ + @Parameter(property = "wildfly.id") + private String id; + + /** + * Provides a reference to the settings file. + */ + @Parameter(property = "settings", readonly = true, required = true, defaultValue = "${settings}") + private Settings settings; + + /** + * Specifies the username to use if prompted to authenticate by the server. + *

+ * If no username is specified and the server requests authentication the user + * will be prompted to supply the username, + */ + @Parameter(property = "wildfly.username") + private String username; + + /** + * Specifies the password to use if prompted to authenticate by the server. + *

+ * If no password is specified and the server requests authentication the user + * will be prompted to supply the password, + */ + @Parameter(property = "wildfly.password") + private String password; + + /** + * The timeout, in seconds, to wait for a management connection. + */ + @Parameter(property = "wildfly.timeout", defaultValue = "60") + protected int timeout; + + /** + * A URL which points to the authentication configuration ({@code wildfly-config.xml}) the client uses to + * authenticate with the server. + */ + @Parameter(alias = "authentication-config", property = "wildfly.authConfig") + private URL authenticationConfig; + + @Inject + private SettingsDecrypter settingsDecrypter; + + /** + * The goal of the deployment. + * + * @return the goal of the deployment. + */ + public abstract String goal(); + + /** + * Creates a new client. + * + * @return the client + */ + protected ModelControllerClient createClient() { + return ModelControllerClient.Factory.create(getClientConfiguration()); + } + + /** + * Gets a client configuration used to create a new {@link ModelControllerClient}. + * + * @return the configuration to use + */ + protected synchronized ModelControllerClientConfiguration getClientConfiguration() { + final Log log = getLog(); + String username = this.username; + String password = this.password; + if (username == null && password == null) { + if (id != null) { + if (settings != null) { + Server server = settings.getServer(id); + if (server != null) { + log.debug(DEBUG_MESSAGE_SETTINGS_HAS_ID); + password = decrypt(server); + username = server.getUsername(); + if (username != null && password != null) { + log.debug(DEBUG_MESSAGE_SETTINGS_HAS_CREDS); + } else { + log.debug(DEBUG_MESSAGE_NO_CREDS); + } + } else { + log.debug(DEBUG_MESSAGE_NO_SERVER_SECTION); + } + } else { + log.debug(DEBUG_MESSAGE_NO_SETTINGS_FILE); + } + } else { + log.debug(DEBUG_MESSAGE_NO_ID); + } + } else { + log.debug(DEBUG_MESSAGE_POM_HAS_CREDS); + } + final ModelControllerClientConfiguration.Builder builder = new ModelControllerClientConfiguration.Builder() + .setProtocol(protocol) + .setHostName(getManagementHostName()) + .setPort(getManagementPort()) + .setConnectionTimeout(timeout * 1000); + if (authenticationConfig != null) { + try { + builder.setAuthenticationConfigUri(authenticationConfig.toURI()); + } catch (URISyntaxException e) { + throw new RuntimeException("Failed to create URI from " + authenticationConfig, e); + } + } else { + builder.setHandler(new ClientCallbackHandler(username, password)); + } + return builder.build(); + } + + protected int getManagementPort() { + return port; + } + + protected String getManagementHostName() { + return hostname; + } + + private String decrypt(final Server server) { + SettingsDecryptionResult decrypt = settingsDecrypter.decrypt(new DefaultSettingsDecryptionRequest(server)); + return decrypt.getServer().getPassword(); + } +} diff --git a/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/ClientCallbackHandler.java b/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/ClientCallbackHandler.java new file mode 100644 index 00000000..8b665c50 --- /dev/null +++ b/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/ClientCallbackHandler.java @@ -0,0 +1,103 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.wildfly.plugins.bootablejar.maven.goals; + +import java.io.Console; +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.RealmCallback; +import javax.security.sasl.RealmChoiceCallback; + +/** + * A CallbackHandler implementation to supply the username and password if required when + * connecting to the server - if these are not available the user will be prompted to + * supply them. + * + * @author Darran Lofthouse + */ +public class ClientCallbackHandler implements CallbackHandler { + + private final Console console; + private boolean promptShown = false; + private String username; + private char[] password; + + public ClientCallbackHandler(final String username, final String password) { + console = System.console(); + this.username = username; + if (password != null) { + this.password = password.toCharArray(); + } + } + + @Override + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + // Special case for anonymous authentication to avoid prompting user for their name. + if (callbacks.length == 1 && callbacks[0] instanceof NameCallback) { + ((NameCallback) callbacks[0]).setName("anonymous demo user"); + return; + } + + for (Callback current : callbacks) { + if (current instanceof RealmCallback) { + final RealmCallback rcb = (RealmCallback) current; + final String defaultText = rcb.getDefaultText(); + rcb.setText(defaultText); // For now just use the realm suggested. + + prompt(defaultText); + } else if (current instanceof RealmChoiceCallback) { + throw new UnsupportedCallbackException(current, "Realm choice not currently supported."); + } else if (current instanceof NameCallback) { + final NameCallback ncb = (NameCallback) current; + final String userName = obtainUsername("Username:"); + + ncb.setName(userName); + } else if (current instanceof PasswordCallback) { + PasswordCallback pcb = (PasswordCallback) current; + char[] password = obtainPassword("Password:"); + + pcb.setPassword(password); + } else { + throw new UnsupportedCallbackException(current); + } + } + } + + private void prompt(final String realm) { + if (!promptShown) { + promptShown = true; + } + } + + private String obtainUsername(final String prompt) { + if (username == null) { + checkConsole(); + username = console.readLine(prompt); + } + return username; + } + + private char[] obtainPassword(final String prompt) { + if (password == null) { + checkConsole(); + password = console.readPassword(prompt); + } + + return password; + } + + private void checkConsole() { + if (console == null) { + throw new IllegalStateException( + "The environment does not have a usable console. Cannot prompt for user name and password"); + } + } + +} diff --git a/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/DevWatchBootableJarMojo.java b/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/DevWatchBootableJarMojo.java index 6148de57..2d779153 100644 --- a/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/DevWatchBootableJarMojo.java +++ b/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/DevWatchBootableJarMojo.java @@ -98,7 +98,6 @@ import org.jboss.as.controller.client.helpers.Operations; import org.jboss.dmr.ModelNode; import org.wildfly.core.launcher.BootableJarCommandBuilder; -import org.wildfly.plugin.common.PropertyNames; /** * Build and start a bootable JAR for dev-watch mode. This goal monitors the @@ -170,19 +169,19 @@ public final class DevWatchBootableJarMojo extends AbstractDevBootableJarMojo { * Specifies the host name of the server where the deployment plan should be * executed. */ - @Parameter(defaultValue = "localhost", property = PropertyNames.HOSTNAME) + @Parameter(defaultValue = "localhost", property = "wildfly.hostname") private String hostname; /** * Specifies the port number the server is listening on. */ - @Parameter(defaultValue = "9990", property = PropertyNames.PORT) + @Parameter(defaultValue = "9990", property = "wildfly.port") private int port; /** * The timeout, in seconds, to wait for a management connection. */ - @Parameter(property = PropertyNames.TIMEOUT, defaultValue = "60") + @Parameter(property = "wildfly.timeout", defaultValue = "60") protected int timeout; @Parameter(defaultValue = "${project.remotePluginRepositories}", readonly = true, required = true) diff --git a/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/MavenJBossLogger.java b/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/MavenJBossLogger.java new file mode 100644 index 00000000..8210eb3d --- /dev/null +++ b/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/MavenJBossLogger.java @@ -0,0 +1,100 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.plugins.bootablejar.maven.goals; + +import java.text.MessageFormat; + +import org.apache.maven.plugin.logging.Log; +import org.jboss.logging.Logger; + +/** + * A logger which delegates to a {@link Log}. + *

+ * For {@link #isEnabled(Level)} {@link org.jboss.logging.Logger.Level#TRACE} is ignored and + * {@link org.jboss.logging.Logger.Level#FATAL} + * is treated as an {@link Log#error(CharSequence, Throwable) error}. + *

+ *

+ * For the log methods, {@link org.jboss.logging.Logger.Level#TRACE} is treated as a {@link Log#debug(CharSequence, Throwable) + * debug} + * and {@link org.jboss.logging.Logger.Level#FATAL} is treated as {@link Log#error(CharSequence, Throwable) error}. + *

+ * + * @author James R. Perkins + */ +public class MavenJBossLogger extends Logger { + private final Log mavenLogger; + + public MavenJBossLogger(final Log mavenLogger) { + super(mavenLogger.toString()); + this.mavenLogger = mavenLogger; + } + + @Override + protected void doLog(final Level level, final String loggerClassName, final Object message, final Object[] parameters, + final Throwable thrown) { + final String msg = parameters == null ? String.valueOf(message) + : MessageFormat.format(String.valueOf(message), parameters); + doMavenLog(level, msg, thrown); + } + + @Override + protected void doLogf(final Level level, final String loggerClassName, final String format, final Object[] parameters, + final Throwable thrown) { + final String msg = String.format(format, parameters); + doMavenLog(level, msg, thrown); + } + + @Override + public boolean isEnabled(final Level level) { + switch (level) { + case DEBUG: + return mavenLogger.isDebugEnabled(); + case INFO: + return mavenLogger.isInfoEnabled(); + case WARN: + return mavenLogger.isWarnEnabled(); + case FATAL: + case ERROR: + return mavenLogger.isErrorEnabled(); + } + return false; + } + + private void doMavenLog(final Level level, final String msg, final Throwable thrown) { + switch (level) { + case TRACE: + case DEBUG: + if (thrown == null) { + mavenLogger.debug(msg); + } else { + mavenLogger.debug(msg, thrown); + } + break; + case WARN: + if (thrown == null) { + mavenLogger.warn(msg); + } else { + mavenLogger.warn(msg, thrown); + } + break; + case FATAL: + case ERROR: + if (thrown == null) { + mavenLogger.error(msg); + } else { + mavenLogger.error(msg, thrown); + } + break; + default: + if (thrown == null) { + mavenLogger.info(msg); + } else { + mavenLogger.info(msg, thrown); + } + } + } +} diff --git a/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/ShutdownBootableJarMojo.java b/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/ShutdownBootableJarMojo.java index ca30aa02..671668d4 100644 --- a/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/ShutdownBootableJarMojo.java +++ b/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/ShutdownBootableJarMojo.java @@ -24,7 +24,6 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import org.jboss.as.controller.client.ModelControllerClient; -import org.wildfly.plugin.common.AbstractServerConnection; import org.wildfly.plugin.tools.server.ServerManager; /** diff --git a/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/StartBootableJarMojo.java b/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/StartBootableJarMojo.java index 44908500..be197877 100644 --- a/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/StartBootableJarMojo.java +++ b/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/StartBootableJarMojo.java @@ -31,7 +31,6 @@ import org.jboss.as.controller.client.ModelControllerClient; import org.wildfly.core.launcher.BootableJarCommandBuilder; import org.wildfly.core.launcher.Launcher; -import org.wildfly.plugin.common.AbstractServerConnection; import org.wildfly.plugin.tools.server.ServerManager; import org.wildfly.plugins.bootablejar.maven.common.Utils; diff --git a/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/ToolsModelControllerClientConfiguration.java b/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/ToolsModelControllerClientConfiguration.java new file mode 100644 index 00000000..5780b56d --- /dev/null +++ b/plugin/src/main/java/org/wildfly/plugins/bootablejar/maven/goals/ToolsModelControllerClientConfiguration.java @@ -0,0 +1,146 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.plugins.bootablejar.maven.goals; + +import java.io.IOException; +import java.net.URI; +import java.util.Map; +import java.util.concurrent.ExecutorService; + +import javax.net.ssl.SSLContext; +import javax.security.auth.callback.CallbackHandler; + +import org.jboss.as.controller.client.ModelControllerClientConfiguration; +import org.wildfly.security.SecurityFactory; + +/** + * A configuration used to connect a {@link org.jboss.as.controller.client.ModelControllerClient} or used to connect a + * CLI {@code CommandContext} + * + * @author James R. Perkins + */ +public class ToolsModelControllerClientConfiguration implements ModelControllerClientConfiguration { + + private final ModelControllerClientConfiguration delegate; + private final String username; + private final String password; + private final CallbackHandler callbackHandler; + + public ToolsModelControllerClientConfiguration(final ModelControllerClientConfiguration delegate, final String username, + final String password) { + this.delegate = delegate; + this.username = username; + this.password = password; + if (delegate.getAuthenticationConfigUri() == null) { + callbackHandler = new ClientCallbackHandler(username, password); + } else { + callbackHandler = delegate.getCallbackHandler(); + } + } + + @Override + public String getHost() { + return delegate.getHost(); + } + + @Override + public int getPort() { + return delegate.getPort(); + } + + @Override + public String getProtocol() { + return delegate.getProtocol(); + } + + @Override + public int getConnectionTimeout() { + return delegate.getConnectionTimeout(); + } + + @Override + public CallbackHandler getCallbackHandler() { + return callbackHandler; + } + + @Override + public Map getSaslOptions() { + return delegate.getSaslOptions(); + } + + @Override + @SuppressWarnings("deprecation") + public SSLContext getSSLContext() { + return delegate.getSSLContext(); + } + + @Override + public SecurityFactory getSslContextFactory() { + return delegate.getSslContextFactory(); + } + + @Override + public ExecutorService getExecutor() { + return delegate.getExecutor(); + } + + @Override + public String getClientBindAddress() { + return delegate.getClientBindAddress(); + } + + @Override + public URI getAuthenticationConfigUri() { + return delegate.getAuthenticationConfigUri(); + } + + @Override + public void close() throws IOException { + delegate.close(); + } + + /** + * The username provided or {@code null} if one was not provided. + * + * @return the username or {@code null} + */ + public String getUsername() { + return username; + } + + /** + * The password providedor {@code null} if one was not provided. + * + * @return the password or {@code null} + */ + public char[] getPassword() { + if (password == null) { + return null; + } + return password.toCharArray(); + } + + /** + * Formats a connection string for CLI to use as it's controller connection. + * + * @return the controller string to connect CLI + */ + public String getController() { + final StringBuilder controller = new StringBuilder(); + if (getProtocol() != null) { + controller.append(getProtocol()).append("://"); + } + if (getHost() != null) { + controller.append(getHost()); + } else { + controller.append("localhost"); + } + if (getPort() > 0) { + controller.append(':').append(getPort()); + } + return controller.toString(); + } +} diff --git a/pom.xml b/pom.xml index f5da93f6..3b1d7670 100644 --- a/pom.xml +++ b/pom.xml @@ -66,13 +66,12 @@ 0.13.1 2.0.0 6.0.4.Final - 27.0.0.Beta5 - 1.0.0.Beta3 + 27.0.0.Beta6 + 1.0.0.Final 1.7.0.Final - 5.1.0.Alpha2 - 1.2.0.Beta2 + 1.2.0.Final 1.2.1.Final - 1.3.0.Beta2 + 1.3.0.Final 3.0.0-M6 4.5.13 @@ -292,18 +291,6 @@ wildfly-checkstyle-config ${version.org.wildfly.checkstyle-config}
- - - org.wildfly.plugins - wildfly-plugin-core - ${version.org.wildfly.plugins.wildfly-maven-plugin} - - - * - * - - - org.wildfly.plugins @@ -325,18 +312,6 @@ - - org.wildfly.plugins - wildfly-maven-plugin - ${version.org.wildfly.plugins.wildfly-maven-plugin} - - - * - * - - - - org.wildfly.channel channel-core diff --git a/tests/pom.xml b/tests/pom.xml index 66457f00..4c1db493 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -135,7 +135,7 @@ org.jboss.shrinkwrap shrinkwrap-impl-base test - +