This is an automated email from the ASF dual-hosted git repository.
hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git
The following commit(s) were added to refs/heads/main by this push:
new ece32dbc76 [Feature] --auth option in hop-server.sh to correctly
enable/disable authentication (#6040)
ece32dbc76 is described below
commit ece32dbc76b176d027d8e442628dda8e357cbc5f
Author: lance <[email protected]>
AuthorDate: Thu Nov 27 19:43:28 2025 +0800
[Feature] --auth option in hop-server.sh to correctly enable/disable
authentication (#6040)
* whether authentication is enabled for the Hop Server via --auth
Signed-off-by: lance <[email protected]>
* Minor improvements
- Align the XML tag content to the command, so true/false and not Y/N
- The XML value was overwritten by the CLI because of the default value
- Update docker scripts and add ENV variable to enable/disable
- Update default provided hop-server.xml
- Add the new option to the docs
---------
Signed-off-by: lance <[email protected]>
Co-authored-by: Hans Van Akelyen <[email protected]>
---
.../static/src/main/resources/hop-server.xml | 1 +
docker/Dockerfile | 2 +
docker/resources/load-and-execute.sh | 1 +
.../modules/ROOT/pages/docker-container.adoc | 4 +
.../modules/ROOT/pages/hop-server/index.adoc | 11 +-
.../java/org/apache/hop/server/HopServerMeta.java | 15 ++
.../main/java/org/apache/hop/www/HopServer.java | 10 +
.../main/java/org/apache/hop/www/WebServer.java | 232 ++++++++-------------
8 files changed, 129 insertions(+), 147 deletions(-)
diff --git a/assemblies/static/src/main/resources/hop-server.xml
b/assemblies/static/src/main/resources/hop-server.xml
index 7e9379e16c..967c29778b 100644
--- a/assemblies/static/src/main/resources/hop-server.xml
+++ b/assemblies/static/src/main/resources/hop-server.xml
@@ -23,6 +23,7 @@
<hostname>localhost</hostname>
<port>8181</port>
<shutdownPort>8182</shutdownPort>
+ <enable_auth>true</enable_auth>
</hop-server>
<!-- Join the web server thread and wait until it's finished.
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 9bf4a645eb..3441250525 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -65,6 +65,8 @@ ENV HOP_OPTIONS=-XX:+AggressiveHeap
# Path to custom entrypoint extension script file - optional
# e.g. to fetch Hop project files from S3 or gitlab
ENV HOP_CUSTOM_ENTRYPOINT_EXTENSION_SHELL_FILE_PATH=
+# Enable or disable the auth
+ENV HOP_SERVER_AUTH=true
# The server user
ENV HOP_SERVER_USER=cluster
# The server password
diff --git a/docker/resources/load-and-execute.sh
b/docker/resources/load-and-execute.sh
index c1c1f02f13..8def03b7fb 100755
--- a/docker/resources/load-and-execute.sh
+++ b/docker/resources/load-and-execute.sh
@@ -53,6 +53,7 @@ write_server_config() {
echo " <shutdownPort>${HOP_SERVER_SHUTDOWNPORT}</shutdownPort>"
>>${HOP_SERVER_XML}
echo " <username>${HOP_SERVER_USER}</username>" >>${HOP_SERVER_XML}
echo " <password>${HOP_SERVER_PASS}</password>" >>${HOP_SERVER_XML}
+ echo " <enable_auth>${HOP_SERVER_AUTH}</enable_auth>" >>${HOP_SERVER_XML}
# If an SSL configuration is needed we need to include it here
#
diff --git a/docs/hop-tech-manual/modules/ROOT/pages/docker-container.adoc
b/docs/hop-tech-manual/modules/ROOT/pages/docker-container.adoc
index 3ae2f2fb06..84ca471f71 100644
--- a/docs/hop-tech-manual/modules/ROOT/pages/docker-container.adoc
+++ b/docs/hop-tech-manual/modules/ROOT/pages/docker-container.adoc
@@ -166,6 +166,10 @@ Below are the variables you can use for a **long-lived**
container, running Hop
| `8079`
| The port the server shutdown listener will listen to.
+|```HOP_SERVER_AUTH```
+| `true`
+| Disable/Enable the authentication used for hop server
+
|```HOP_SERVER_USER```
|`cluster`
| The username to log into the Hop server.
diff --git a/docs/hop-user-manual/modules/ROOT/pages/hop-server/index.adoc
b/docs/hop-user-manual/modules/ROOT/pages/hop-server/index.adoc
index e35dcc4e03..f53e851737 100644
--- a/docs/hop-user-manual/modules/ROOT/pages/hop-server/index.adoc
+++ b/docs/hop-user-manual/modules/ROOT/pages/hop-server/index.adoc
@@ -39,16 +39,19 @@ On Windows, this is `hop-server.bat`, on Mac and Linux, run
`./hop-server.sh`.
[source,bash]
----
-Usage: <main class> [-k] [-gs] [-e=<environmentOption>] [-id=<id>]
+Usage: <main class> [-ahV] [-gs] [-e=<environmentOption>] [-id=<id>]
[-j=<projectOption>] [-l=<level>] [-n=<serverName>]
[-p=<password>] [-ps=<pipelineName>] [-u=<username>]
[-ws=<workflowName>] [-s=<systemProperties>[,
<systemProperties>...]]... [<parameters>...]
+Run a Hop server
[<parameters>...] One XML configuration file or a hostname and port
+ -a, --auth Does the Hop web server have authentication enabled
-e, --environment=<environmentOption>
The name of the lifecycle environment to use
-gs, --general-status
List the general status of the server
+ -h, --help Show this help message and exit.
-id=<id> Specify the ID of the pipeline or workflow to query
-j, --project=<projectOption>
The name of the project to use
@@ -68,6 +71,7 @@ Usage: <main class> [-k] [-gs] [-e=<environmentOption>]
[-id=<id>]
-u, --userName=<username>
The server user name. Required for administrative
operations only, not for starting the server.
+ -V, --version Print version information and exit.
-ws, --workflow-status=<workflowName>
List the status of the workflow with this name (also
specify the -id option)
@@ -84,6 +88,11 @@ The available Hop Server options are:
|--help
|This help text
+|-a
+|--auth
+|Default: true +
+Allows you to disable the authentication needed to access the server
+
|-p
|--password
|The server password.
diff --git a/engine/src/main/java/org/apache/hop/server/HopServerMeta.java
b/engine/src/main/java/org/apache/hop/server/HopServerMeta.java
index cbf157e229..1c191ee085 100644
--- a/engine/src/main/java/org/apache/hop/server/HopServerMeta.java
+++ b/engine/src/main/java/org/apache/hop/server/HopServerMeta.java
@@ -157,6 +157,9 @@ public class HopServerMeta extends HopMetadataBase
implements Cloneable, IXml, I
@HopMetadataProperty(password = true)
private String password;
+ /** enable authentication */
+ @HopMetadataProperty private boolean enableAuth;
+
@HopMetadataProperty private String proxyHostname;
@HopMetadataProperty private String proxyPort;
@@ -225,6 +228,8 @@ public class HopServerMeta extends HopMetadataBase
implements Cloneable, IXml, I
this.shutdownPort = shutdownPort;
this.username = username;
this.password = password;
+ // default true
+ this.enableAuth = true;
this.proxyHostname = proxyHostname;
this.proxyPort = proxyPort;
@@ -243,6 +248,11 @@ public class HopServerMeta extends HopMetadataBase
implements Cloneable, IXml, I
this.username = XmlHandler.getTagValue(node, "username");
this.password =
Encr.decryptPasswordOptionallyEncrypted(XmlHandler.getTagValue(node,
"password"));
+
+ // if the enable_auth tag is empty or enable_auth=true, then it's true;
otherwise false.
+ String authValue = XmlHandler.getTagValue(node, "enable_auth");
+ this.enableAuth = Utils.isEmpty(authValue) ||
"true".equalsIgnoreCase(authValue);
+
this.proxyHostname = XmlHandler.getTagValue(node, "proxy_hostname");
this.proxyPort = XmlHandler.getTagValue(node, "proxy_port");
this.nonProxyHosts = XmlHandler.getTagValue(node, "non_proxy_hosts");
@@ -275,6 +285,10 @@ public class HopServerMeta extends HopMetadataBase
implements Cloneable, IXml, I
xml.append(
XmlHandler.addTagValue(
"password", Encr.encryptPasswordIfNotUsingVariables(password),
false));
+
+ // if the enable_auth tag is empty or enable_auth=Y, then it's true;
otherwise false.
+ xml.append(CONST_SPACE).append(XmlHandler.addTagValue("enable_auth",
enableAuth));
+
xml.append(CONST_SPACE).append(XmlHandler.addTagValue("proxy_hostname",
proxyHostname));
xml.append(CONST_SPACE).append(XmlHandler.addTagValue("proxy_port",
proxyPort));
xml.append(CONST_SPACE).append(XmlHandler.addTagValue("non_proxy_hosts",
nonProxyHosts));
@@ -309,6 +323,7 @@ public class HopServerMeta extends HopMetadataBase
implements Cloneable, IXml, I
this.proxyPort = hopServer.proxyPort;
this.nonProxyHosts = hopServer.nonProxyHosts;
this.sslMode = hopServer.sslMode;
+ this.enableAuth = hopServer.enableAuth;
}
public String toString() {
diff --git a/engine/src/main/java/org/apache/hop/www/HopServer.java
b/engine/src/main/java/org/apache/hop/www/HopServer.java
index e9c7bac30c..ff2ab19888 100644
--- a/engine/src/main/java/org/apache/hop/www/HopServer.java
+++ b/engine/src/main/java/org/apache/hop/www/HopServer.java
@@ -139,6 +139,11 @@ public class HopServer implements Runnable,
IHasHopMetadataProvider, IHopCommand
description = "The name of the server to start as defined in the
metadata.")
private String serverName;
+ @CommandLine.Option(
+ names = {"-a", "--auth"},
+ description = "Does the Hop web server have authentication enabled")
+ private Boolean enableAuth;
+
private WebServer webServer;
private HopServerConfig config;
private boolean allOK;
@@ -303,6 +308,11 @@ public class HopServer implements Runnable,
IHasHopMetadataProvider, IHopCommand
config.setVariables(variables);
config.setMetadataProvider(metadataProvider);
+ // enable auth
+ if (this.enableAuth != null) {
+ config.getHopServer().setEnableAuth(this.enableAuth);
+ }
+
// See if we need to add the metadata folder (legacy)
//
addMetadataFolderProvider();
diff --git a/engine/src/main/java/org/apache/hop/www/WebServer.java
b/engine/src/main/java/org/apache/hop/www/WebServer.java
index 485faa80a5..a3c90552b3 100644
--- a/engine/src/main/java/org/apache/hop/www/WebServer.java
+++ b/engine/src/main/java/org/apache/hop/www/WebServer.java
@@ -25,10 +25,13 @@ import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
import org.apache.hop.core.Const;
import org.apache.hop.core.HopEnvironment;
import org.apache.hop.core.encryption.Encr;
import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.exception.HopPluginException;
import org.apache.hop.core.extension.ExtensionPointHandler;
import org.apache.hop.core.extension.HopExtensionPoint;
import org.apache.hop.core.logging.ILogChannel;
@@ -77,19 +80,26 @@ public class WebServer {
private static final int DEFAULT_DETECTION_TIMER = 20000;
private static final Class<?> PKG = WebServer.class;
public static final String CONST_WEB_SERVER_LOG_CONFIG_OPTIONS =
"WebServer.Log.ConfigOptions";
- private ILogChannel log;
- private IVariables variables;
- private Server server;
+ @Getter @Setter private ILogChannel log;
- private PipelineMap pipelineMap;
- private WorkflowMap workflowMap;
+ /** value of variables */
+ @Setter @Getter private IVariables variables;
- private String hostname;
- private int port;
+ @Getter @Setter private Server server;
+ @Getter @Setter private PipelineMap pipelineMap;
+ @Setter @Getter private WorkflowMap workflowMap;
+
+ /** the hostname */
+ @Setter @Getter private String hostname;
+
+ @Setter @Getter private int port;
private final int shutdownPort;
private String passwordFile;
private final WebServerShutdownHook webServerShutdownHook;
+
+ /** Can be used to override the default shutdown behavior of performing a
System.exit */
+ @Setter
private IWebServerShutdownHandler webServerShutdownHandler =
new DefaultWebServerShutdownHandler();
@@ -177,71 +187,85 @@ public class WebServer {
this(log, pipelineMap, workflowMap, hostname, port, shutdownPort, join,
null, null);
}
- public Server getServer() {
- return server;
- }
-
- public void setServer(Server server) {
- this.server = server;
- }
-
public void startServer() throws Exception {
server = new Server();
-
- Constraint.Builder constraintBuilder =
- new Constraint.Builder()
- .name(Authenticator.BASIC_AUTH)
- .authorization(Constraint.Authorization.SPECIFIC_ROLE)
- .transport(Constraint.Transport.ANY);
-
- // Set up the security handler, optionally with JAAS
- //
- ConstraintSecurityHandler securityHandler = new
ConstraintSecurityHandler();
- securityHandler.setAuthenticationType(Authenticator.BASIC_AUTH);
-
- if (System.getProperty("loginmodulename") != null
- && System.getProperty("java.security.auth.login.config") != null) {
- constraintBuilder.roles("*");
- JAASLoginService jaasLoginService = new JAASLoginService("Hop");
-
jaasLoginService.setLoginModuleName(System.getProperty("loginmodulename"));
- securityHandler.setLoginService(jaasLoginService);
- } else {
- constraintBuilder.roles("default");
- HashLoginService hashLoginService;
- HopServerMeta hopServer =
pipelineMap.getHopServerConfig().getHopServer();
- if (!Utils.isEmpty(hopServer.getPassword())) {
- hashLoginService = new HashLoginService("Hop");
- UserStore userStore = new UserStore();
- userStore.addUser(
- hopServer.getUsername(),
- new Password(hopServer.getPassword()),
- new String[] {"default"});
- hashLoginService.setUserStore(userStore);
+ HopServerMeta hopServer = pipelineMap.getHopServerConfig().getHopServer();
+
+ Handler innerHandler;
+
+ if (hopServer.isEnableAuth()) {
+ Constraint.Builder constraintBuilder =
+ new Constraint.Builder()
+ .name(Authenticator.BASIC_AUTH)
+ .authorization(Constraint.Authorization.SPECIFIC_ROLE)
+ .transport(Constraint.Transport.ANY);
+
+ ConstraintSecurityHandler securityHandler = new
ConstraintSecurityHandler();
+ securityHandler.setAuthenticationType(Authenticator.BASIC_AUTH);
+
+ // basic authentication
+ if (System.getProperty("loginmodulename") != null
+ && System.getProperty("java.security.auth.login.config") != null) {
+ constraintBuilder.roles("*");
+ JAASLoginService jaasLoginService = new JAASLoginService("Hop");
+
jaasLoginService.setLoginModuleName(System.getProperty("loginmodulename"));
+ securityHandler.setLoginService(jaasLoginService);
} else {
- // See if there is a hop.pwd file in the HOP_HOME directory:
- if (Utils.isEmpty(passwordFile)) {
- passwordFile = Const.getHopLocalServerPasswordFile();
+ constraintBuilder.roles("default");
+ HashLoginService hashLoginService;
+ if (!Utils.isEmpty(hopServer.getPassword())) {
+ hashLoginService = new HashLoginService("Hop");
+ UserStore userStore = new UserStore();
+ userStore.addUser(
+ hopServer.getUsername(),
+ new Password(hopServer.getPassword()),
+ new String[] {"default"});
+ hashLoginService.setUserStore(userStore);
+ } else {
+ if (Utils.isEmpty(passwordFile)) {
+ passwordFile = Const.getHopLocalServerPasswordFile();
+ }
+ hashLoginService = new HashLoginService("Hop");
+ PropertyUserStore userStore = new PropertyUserStore();
+
userStore.setConfig(ResourceFactory.of(server).newResource(passwordFile));
+ hashLoginService.setUserStore(userStore);
}
- hashLoginService = new HashLoginService("Hop");
- PropertyUserStore userStore = new PropertyUserStore();
-
userStore.setConfig(ResourceFactory.of(server).newResource(passwordFile));
- hashLoginService.setUserStore(userStore);
+ securityHandler.setLoginService(hashLoginService);
}
- securityHandler.setLoginService(hashLoginService);
+
+ ConstraintMapping constraintMapping = new ConstraintMapping();
+ constraintMapping.setPathSpec("/*");
+ constraintMapping.setConstraint(constraintBuilder.build());
+ securityHandler.setConstraintMappings(new ConstraintMapping[]
{constraintMapping});
+
+ // create context handler collection
+ ContextHandlerCollection contexts = createContexts();
+ ResourceHandler resourceHandler = new ResourceHandler();
+ resourceHandler.setBaseResourceAsString("temp");
+
+ securityHandler.setHandler(new Handler.Sequence(resourceHandler,
contexts));
+ innerHandler = securityHandler;
+ log.logBasic("Hop Server: Basic authentication is ENABLED");
+ } else {
+ ContextHandlerCollection contexts = createContexts();
+ ResourceHandler resourceHandler = new ResourceHandler();
+ resourceHandler.setBaseResourceAsString("temp");
+
+ innerHandler = new Handler.Sequence(resourceHandler, contexts);
+ log.logBasic("Hop Server: Basic authentication is DISABLED
(enableAuth=false)");
}
- ConstraintMapping constraintMapping = new ConstraintMapping();
- constraintMapping.setPathSpec("/*");
- constraintMapping.setConstraint(constraintBuilder.build());
+ server.setHandler(innerHandler);
- securityHandler.setConstraintMappings(new ConstraintMapping[]
{constraintMapping});
+ // Start execution
+ createListeners();
+ server.start();
+ }
- // Add all the servlets defined in hop-servlets.xml ...
- //
+ private ContextHandlerCollection createContexts() throws HopPluginException {
ContextHandlerCollection contexts = new ContextHandlerCollection();
// Root
- //
ServletContextHandler root =
new ServletContextHandler(GetRootServlet.CONTEXT_PATH,
ServletContextHandler.SESSIONS);
contexts.addHandler(root);
@@ -252,7 +276,6 @@ public class WebServer {
PluginRegistry pluginRegistry = PluginRegistry.getInstance();
List<IPlugin> plugins =
pluginRegistry.getPlugins(HopServerPluginType.class);
for (IPlugin plugin : plugins) {
-
IHopServerPlugin servlet = pluginRegistry.loadClass(plugin,
IHopServerPlugin.class);
servlet.setup(pipelineMap, workflowMap);
servlet.setJettyMode(true);
@@ -274,13 +297,7 @@ public class WebServer {
"com.sun.jersey.config.property.packages", "org.apache.hop.www.jaxrs");
root.addServlet(jerseyServletHolder, "/api/*");
- // Allow png files to be shown for pipelines and workflows...
- //
- ResourceHandler resourceHandler = new ResourceHandler();
- resourceHandler.setBaseResourceAsString("temp");
- // add all handlers/contexts to server
-
- // set up static servlet
+ // Static resources
ServletHolder staticHolder = new ServletHolder("static",
DefaultServlet.class);
// baseResource maps to the path relative to where hop-server is started
Resource staticResource =
ResourceFactory.of(server).newResource("static/");
@@ -290,13 +307,7 @@ public class WebServer {
root.addServlet(staticHolder, "/static/*");
root.addServlet(new ServletHolder(rootServlet), "/*");
-
- securityHandler.setHandler(new Handler.Sequence(resourceHandler,
contexts));
- server.setHandler(securityHandler);
-
- // Start execution
- createListeners();
- server.start();
+ return contexts;
}
public String getContextPath(IHopServerPlugin servlet) {
@@ -449,20 +460,6 @@ public class WebServer {
return isValid;
}
- /**
- * @return the hostname
- */
- public String getHostname() {
- return hostname;
- }
-
- /**
- * @param hostname the hostname to set
- */
- public void setHostname(String hostname) {
- this.hostname = hostname;
- }
-
public String getPasswordFile() {
return passwordFile;
}
@@ -471,63 +468,6 @@ public class WebServer {
this.passwordFile = passwordFile;
}
- public ILogChannel getLog() {
- return log;
- }
-
- public void setLog(ILogChannel log) {
- this.log = log;
- }
-
- public PipelineMap getPipelineMap() {
- return pipelineMap;
- }
-
- public void setPipelineMap(PipelineMap pipelineMap) {
- this.pipelineMap = pipelineMap;
- }
-
- public WorkflowMap getWorkflowMap() {
- return workflowMap;
- }
-
- public void setWorkflowMap(WorkflowMap workflowMap) {
- this.workflowMap = workflowMap;
- }
-
- public int getPort() {
- return port;
- }
-
- public void setPort(int port) {
- this.port = port;
- }
-
- /**
- * Gets variables
- *
- * @return value of variables
- */
- public IVariables getVariables() {
- return variables;
- }
-
- /**
- * @param variables The variables to set
- */
- public void setVariables(IVariables variables) {
- this.variables = variables;
- }
-
- /**
- * Can be used to override the default shutdown behavior of performing a
System.exit
- *
- * @param webServerShutdownHandler
- */
- public void setWebServerShutdownHandler(IWebServerShutdownHandler
webServerShutdownHandler) {
- this.webServerShutdownHandler = webServerShutdownHandler;
- }
-
public int defaultDetectionTimer() {
String sDetectionTimer =
System.getProperty(Const.HOP_SERVER_DETECTION_TIMER);