You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2023/02/21 01:15:30 UTC
[james-project] 02/08: fixup! JAMES-3881 Set a JMX password
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 919e518672f7dc3ed61ac434c88c8bf69c7a75c9
Author: Tung Tran <vt...@linagora.com>
AuthorDate: Tue Feb 14 06:58:02 2023 +0700
fixup! JAMES-3881 Set a JMX password
---
.../cli/JmxSecurityServerIntegrationTest.java | 115 +++++++++++++++++++++
.../main/java/org/apache/james/cli/ServerCmd.java | 24 ++++-
.../apache/james/cli/probe/impl/JmxConnection.java | 16 +++
.../java/org/apache/james/cli/ServerCmdTest.java | 59 +++++++++++
.../docs/modules/ROOT/pages/configure/jmx.adoc | 34 ++++++
.../org/apache/james/TemporaryJamesServer.java | 2 +-
.../org/apache/james/modules/server/JMXServer.java | 39 ++++---
.../james/modules/server/JmxConfiguration.java | 8 +-
8 files changed, 277 insertions(+), 20 deletions(-)
diff --git a/server/apps/cli-integration-tests/src/test/java/org/apache/james/cli/JmxSecurityServerIntegrationTest.java b/server/apps/cli-integration-tests/src/test/java/org/apache/james/cli/JmxSecurityServerIntegrationTest.java
new file mode 100644
index 0000000000..089016684e
--- /dev/null
+++ b/server/apps/cli-integration-tests/src/test/java/org/apache/james/cli/JmxSecurityServerIntegrationTest.java
@@ -0,0 +1,115 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.cli;
+
+import static org.apache.james.MemoryJamesServerMain.IN_MEMORY_SERVER_AGGREGATE_MODULE;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.util.List;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.james.GuiceJamesServer;
+import org.apache.james.TemporaryJamesServer;
+import org.apache.james.cli.util.OutputCapture;
+import org.apache.james.data.UsersRepositoryModuleChooser;
+import org.apache.james.mailbox.store.search.ListeningMessageSearchIndex;
+import org.apache.james.modules.data.MemoryUsersRepositoryModule;
+import org.apache.james.modules.server.JMXServerModule;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import com.google.common.collect.ImmutableList;
+
+class JmxSecurityServerIntegrationTest {
+
+ private static final List<String> BASE_CONFIGURATION_FILE_NAMES = ImmutableList.of("dnsservice.xml",
+ "dnsservice.xml",
+ "imapserver.xml",
+ "jwt_publickey",
+ "lmtpserver.xml",
+ "mailetcontainer.xml",
+ "mailrepositorystore.xml",
+ "managesieveserver.xml",
+ "pop3server.xml",
+ "smtpserver.xml");
+
+ private GuiceJamesServer jamesServer;
+
+ @BeforeEach
+ void beforeEach(@TempDir Path workingPath) throws Exception {
+ TemporaryJamesServer temporaryJamesServer = new TemporaryJamesServer(workingPath.toFile(), BASE_CONFIGURATION_FILE_NAMES);
+ writeFile(workingPath + "/conf/jmx.properties", "jmx.address=127.0.0.1\n" +
+ "jmx.port=9999\n");
+ writeFile(workingPath + "/conf/jmxremote.password", "james-admin pass1\n");
+ writeFile(workingPath + "/conf/jmxremote.access", "james-admin readwrite\n");
+
+ jamesServer = temporaryJamesServer.getJamesServer()
+ .combineWith(IN_MEMORY_SERVER_AGGREGATE_MODULE)
+ .combineWith(new UsersRepositoryModuleChooser(new MemoryUsersRepositoryModule())
+ .chooseModules(UsersRepositoryModuleChooser.Implementation.DEFAULT))
+ .overrideWith(new JMXServerModule(),
+ binder -> binder.bind(ListeningMessageSearchIndex.class).toInstance(mock(ListeningMessageSearchIndex.class)));
+ jamesServer.start();
+
+ }
+
+ @AfterEach
+ void afterEach() {
+ if (jamesServer != null && jamesServer.isStarted()) {
+ jamesServer.stop();
+ }
+ }
+
+ @Test
+ void jamesCliShouldFailWhenNotGiveAuthCredential() throws Exception {
+ OutputCapture outputCapture = new OutputCapture();
+
+ assertThatThrownBy(() -> ServerCmd.executeAndOutputToStream(new String[]{"-h", "127.0.0.1", "-p", "9999", "listdomains"}, outputCapture.getPrintStream()))
+ .isInstanceOf(SecurityException.class)
+ .hasMessageContaining("Authentication failed! Credentials required");
+ }
+
+ @Test
+ void jamesCliShouldWorkWhenGiveAuthCredential() throws Exception {
+ OutputCapture outputCapture = new OutputCapture();
+ ServerCmd.executeAndOutputToStream(new String[]{"-h", "127.0.0.1", "-p", "9999", "-username", "james-admin", "-password", "pass1",
+ "listdomains"}, outputCapture.getPrintStream());
+
+ assertThat(outputCapture.getContent()).contains("localhost");
+ }
+
+ private void writeFile(String fileNamePath, String data) {
+ File passwordFile = new File(fileNamePath);
+ try (OutputStream outputStream = new FileOutputStream(passwordFile)) {
+ IOUtils.write(data, outputStream, StandardCharsets.UTF_8);
+ } catch (IOException ignored) {
+ }
+ }
+}
diff --git a/server/apps/cli/src/main/java/org/apache/james/cli/ServerCmd.java b/server/apps/cli/src/main/java/org/apache/james/cli/ServerCmd.java
index bb42cb5650..77b3aa1496 100644
--- a/server/apps/cli/src/main/java/org/apache/james/cli/ServerCmd.java
+++ b/server/apps/cli/src/main/java/org/apache/james/cli/ServerCmd.java
@@ -18,13 +18,16 @@
****************************************************************/
package org.apache.james.cli;
+import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
+import java.util.StringTokenizer;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
@@ -34,6 +37,7 @@ import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
+import org.apache.commons.io.FileUtils;
import org.apache.james.cli.exceptions.InvalidArgumentNumberException;
import org.apache.james.cli.exceptions.JamesCliException;
import org.apache.james.cli.exceptions.MissingCommandException;
@@ -74,6 +78,7 @@ public class ServerCmd {
public static final String JMX_USERNAME_OPT = "username";
public static final String JMX_PASSWORD_OPT = "password";
+ public static final String JMX_PASSWORD_FILE_PATH_DEFAULT = System.getProperty("user.home") + "/conf/jmxremote.password";
private static final String DEFAULT_HOST = "127.0.0.1";
private static final int DEFAULT_PORT = 9999;
@@ -116,7 +121,7 @@ public class ServerCmd {
public static void executeAndOutputToStream(String[] args, PrintStream printStream) throws Exception {
Stopwatch stopWatch = Stopwatch.createStarted();
CommandLine cmd = parseCommandLine(args);
- JmxConnection jmxConnection = new JmxConnection(getHost(cmd), getPort(cmd), getAuthCredential(cmd));
+ JmxConnection jmxConnection = new JmxConnection(getHost(cmd), getPort(cmd), getAuthCredential(cmd, JMX_PASSWORD_FILE_PATH_DEFAULT));
CmdType cmdType = new ServerCmd(
new JmxDataProbe().connect(jmxConnection),
@@ -161,7 +166,13 @@ public class ServerCmd {
return host;
}
- static Optional<JmxConnection.AuthCredential> getAuthCredential(CommandLine cmd) {
+ @VisibleForTesting
+ static Optional<JmxConnection.AuthCredential> getAuthCredential(CommandLine cmd, String jmxPasswordFilePath) {
+ return getAuthCredentialFromCommandLine(cmd)
+ .or(() -> getAuthCredentialFromJmxPasswordFile(jmxPasswordFilePath));
+ }
+
+ static Optional<JmxConnection.AuthCredential> getAuthCredentialFromCommandLine(CommandLine cmd) {
String username = cmd.getOptionValue(JMX_USERNAME_OPT);
String password = cmd.getOptionValue(JMX_PASSWORD_OPT);
if (Strings.isNullOrEmpty(username) || Strings.isNullOrEmpty(password)) {
@@ -170,6 +181,15 @@ public class ServerCmd {
return Optional.of(new JmxConnection.AuthCredential(username, password));
}
+ static Optional<JmxConnection.AuthCredential> getAuthCredentialFromJmxPasswordFile(String jmxPasswordFilePath) {
+ try {
+ StringTokenizer stringTokenizer = new StringTokenizer(FileUtils.readLines(new File(jmxPasswordFilePath), StandardCharsets.US_ASCII).get(0), " ");
+ return Optional.of(new JmxConnection.AuthCredential(stringTokenizer.nextToken(), stringTokenizer.nextToken()));
+ } catch (Exception e) {
+ return Optional.empty();
+ }
+ }
+
@VisibleForTesting
static int getPort(CommandLine cmd) throws ParseException {
String portNum = cmd.getOptionValue(PORT_OPT_LONG);
diff --git a/server/apps/cli/src/main/java/org/apache/james/cli/probe/impl/JmxConnection.java b/server/apps/cli/src/main/java/org/apache/james/cli/probe/impl/JmxConnection.java
index 3c410fb988..a6762b1054 100644
--- a/server/apps/cli/src/main/java/org/apache/james/cli/probe/impl/JmxConnection.java
+++ b/server/apps/cli/src/main/java/org/apache/james/cli/probe/impl/JmxConnection.java
@@ -21,6 +21,7 @@ package org.apache.james.cli.probe.impl;
import java.io.Closeable;
import java.io.IOException;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import javax.management.MBeanServerConnection;
@@ -43,6 +44,21 @@ public class JmxConnection implements Closeable {
this.username = username;
this.password = password;
}
+
+ @Override
+ public final boolean equals(Object o) {
+ if (o instanceof AuthCredential) {
+ AuthCredential that = (AuthCredential) o;
+ return Objects.equals(this.username, that.username)
+ && Objects.equals(this.password, that.password);
+ }
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(username, password);
+ }
}
private static final String fmtUrl = "service:jmx:rmi:///jndi/rmi://%s:%d/jmxrmi";
diff --git a/server/apps/cli/src/test/java/org/apache/james/cli/ServerCmdTest.java b/server/apps/cli/src/test/java/org/apache/james/cli/ServerCmdTest.java
index 0b8d025dda..5f169ad3d3 100644
--- a/server/apps/cli/src/test/java/org/apache/james/cli/ServerCmdTest.java
+++ b/server/apps/cli/src/test/java/org/apache/james/cli/ServerCmdTest.java
@@ -25,14 +25,24 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Optional;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.ParseException;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.RandomStringUtils;
import org.apache.james.cli.exceptions.InvalidArgumentNumberException;
import org.apache.james.cli.exceptions.MissingCommandException;
import org.apache.james.cli.exceptions.UnrecognizedCommandException;
+import org.apache.james.cli.probe.impl.JmxConnection;
import org.apache.james.cli.probe.impl.JmxDataProbe;
import org.apache.james.cli.probe.impl.JmxMailboxProbe;
import org.apache.james.cli.probe.impl.JmxQuotaProbe;
@@ -48,6 +58,7 @@ import org.apache.james.mailbox.model.SerializableQuotaLimitValue;
import org.apache.james.rrt.lib.MappingsImpl;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
import com.google.common.collect.ImmutableList;
@@ -1200,4 +1211,52 @@ class ServerCmdTest {
.isInstanceOf(IllegalArgumentException.class);
}
+ @Test
+ void getAuthCredentialShouldReturnEmptyWhenNotGiven(@TempDir Path tempDir) throws Exception {
+ String[] arguments = {"-h", "127.0.0.1", "-p", "99999", "command", "arg1", "arg2", "arg3"};
+ CommandLine commandLine = ServerCmd.parseCommandLine(arguments);
+
+ assertThat(ServerCmd.getAuthCredential(commandLine, tempDir.toString()))
+ .isEmpty();
+ }
+
+ @Test
+ void getAuthCredentialShouldReturnValueWhenGivenViaCommandLine(@TempDir Path tempDir) throws Exception {
+ String[] arguments = {"-h", "127.0.0.1", "-p", "99999", "-username", "james-admin", "-password", "123456", "command", "arg1", "arg2", "arg3"};
+ CommandLine commandLine = ServerCmd.parseCommandLine(arguments);
+
+ assertThat(ServerCmd.getAuthCredential(commandLine, tempDir.toString()))
+ .isEqualTo(Optional.of(new JmxConnection.AuthCredential("james-admin", "123456")));
+ }
+
+ @Test
+ void getAuthCredentialShouldReturnValueWhenGivenViaJmxPasswordFile(@TempDir Path tempDir) throws Exception {
+ String[] arguments = {"-h", "127.0.0.1", "-p", "99999", "command", "arg1", "arg2", "arg3"};
+ CommandLine commandLine = ServerCmd.parseCommandLine(arguments);
+
+ File passwordFile = new File(tempDir.toString() + "/jmxremote.password");
+ try (OutputStream outputStream = new FileOutputStream(passwordFile)) {
+ IOUtils.write("james-admin1 pass2\n", outputStream, StandardCharsets.UTF_8);
+ } catch (IOException ignored) {
+ }
+
+ assertThat(ServerCmd.getAuthCredential(commandLine, passwordFile.getPath()))
+ .isEqualTo(Optional.of(new JmxConnection.AuthCredential("james-admin1", "pass2")));
+ }
+
+ @Test
+ void getAuthCredentialShouldPreferCommandlineValue(@TempDir Path tempDir) throws Exception {
+ String[] arguments = {"-h", "127.0.0.1", "-p", "99999", "-username", "james-admin", "-password", "123456", "command", "arg1", "arg2", "arg3"};
+ CommandLine commandLine = ServerCmd.parseCommandLine(arguments);
+
+ File passwordFile = new File(tempDir.toString() + "/jmxremote.password");
+ try (OutputStream outputStream = new FileOutputStream(passwordFile)) {
+ IOUtils.write("james-admin1 pass2\n", outputStream, StandardCharsets.UTF_8);
+ } catch (IOException ignored) {
+ }
+
+ assertThat(ServerCmd.getAuthCredential(commandLine, tempDir.toString()))
+ .isEqualTo(Optional.of(new JmxConnection.AuthCredential("james-admin", "123456")));
+ }
+
}
diff --git a/server/apps/distributed-app/docs/modules/ROOT/pages/configure/jmx.adoc b/server/apps/distributed-app/docs/modules/ROOT/pages/configure/jmx.adoc
index 695128588b..996b8a6ebd 100644
--- a/server/apps/distributed-app/docs/modules/ROOT/pages/configure/jmx.adoc
+++ b/server/apps/distributed-app/docs/modules/ROOT/pages/configure/jmx.adoc
@@ -22,3 +22,37 @@ in GIT to get some examples and hints.
To access from a remote location, it has been reported that `-Dcom.sun.management.jmxremote.ssl=false` is needed as
a JVM argument.
+
+
+== JMX Security
+
+In order to set up JMX authentication, we need to put `jmxremote.password` and `jmxremote.access` file
+to `/conf` directory.
+
+- `jmxremote.password`: define the username and password, that will be used by the client (here is james-cli)
+
+File's content example:
+```
+james-admin pass1
+```
+
+- `jmxremote.access`: define the pair of username and access permission
+
+File's content example:
+```
+james-admin readWrite
+```
+
+When James runs with option `-Djames.jmx.credential.generation=true`, James will automatically generate `jmxremote.password` if the file does not exist.
+Then the default username is `james-admin` and a random password.
+
+=== James-cli
+
+When the JMX server starts with authentication configuration, it will require the client need provide username/password for bypass.
+To do that, we need set arguments `-username` and `-password` for the command request.
+
+Command example:
+```
+james-cli -h 127.0.0.1 -p 9999 -username james-admin -password pass1 listdomains
+```
+
diff --git a/server/container/guice/common/src/main/java/org/apache/james/TemporaryJamesServer.java b/server/container/guice/common/src/main/java/org/apache/james/TemporaryJamesServer.java
index 811189f360..231d3586c2 100644
--- a/server/container/guice/common/src/main/java/org/apache/james/TemporaryJamesServer.java
+++ b/server/container/guice/common/src/main/java/org/apache/james/TemporaryJamesServer.java
@@ -88,7 +88,7 @@ public class TemporaryJamesServer {
.forEach(resourceName -> copyResource(resourcesFolder, resourceName));
}
- private void copyResource(Path resourcesFolder, String resourceName) {
+ public static void copyResource(Path resourcesFolder, String resourceName) {
var resolvedResource = resourcesFolder.resolve(resourceName);
try (OutputStream outputStream = new FileOutputStream(resolvedResource.toFile())) {
URL resource = ClassLoader.getSystemClassLoader().getResource(resourceName);
diff --git a/server/container/guice/jmx/src/main/java/org/apache/james/modules/server/JMXServer.java b/server/container/guice/jmx/src/main/java/org/apache/james/modules/server/JMXServer.java
index 2e16907674..badd87f9b3 100644
--- a/server/container/guice/jmx/src/main/java/org/apache/james/modules/server/JMXServer.java
+++ b/server/container/guice/jmx/src/main/java/org/apache/james/modules/server/JMXServer.java
@@ -19,8 +19,10 @@
package org.apache.james.modules.server;
-import static org.apache.james.modules.server.JmxConfiguration.JMX_CREDENTIAL_GENERATION_ENABLE_DEFAULT;
-import static org.apache.james.modules.server.JmxConfiguration.JMX_CREDENTIAL_GENERATION_ENABLE_PROPERTY;
+import static org.apache.james.modules.server.JmxConfiguration.ACCESS_FILE_NAME;
+import static org.apache.james.modules.server.JmxConfiguration.JMX_CREDENTIAL_GENERATION_ENABLE_DEFAULT_VALUE;
+import static org.apache.james.modules.server.JmxConfiguration.JMX_CREDENTIAL_GENERATION_ENABLE_PROPERTY_KEY;
+import static org.apache.james.modules.server.JmxConfiguration.PASSWORD_FILE_NAME;
import java.io.File;
import java.io.FileOutputStream;
@@ -31,6 +33,7 @@ import java.net.ServerSocket;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.attribute.PosixFilePermission;
import java.rmi.registry.LocateRegistry;
import java.util.HashSet;
import java.util.Map;
@@ -47,6 +50,7 @@ import javax.management.remote.JMXServiceURL;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.james.filesystem.api.JamesDirectoriesProvider;
import org.apache.james.lifecycle.api.Startable;
import org.apache.james.util.FunctionalUtils;
import org.apache.james.util.RestrictingRMISocketFactory;
@@ -62,13 +66,17 @@ public class JMXServer implements Startable {
private final JmxConfiguration jmxConfiguration;
private final Set<String> registeredKeys;
private final Object lock;
+ private final String jmxPasswordFilePath;
+ private final String jmxAccessFilePath;
private JMXConnectorServer jmxConnectorServer;
private boolean isStarted;
private RestrictingRMISocketFactory restrictingRMISocketFactory;
@Inject
- public JMXServer(JmxConfiguration jmxConfiguration) {
+ public JMXServer(JmxConfiguration jmxConfiguration, JamesDirectoriesProvider directoriesProvider) {
this.jmxConfiguration = jmxConfiguration;
+ this.jmxPasswordFilePath = directoriesProvider.getConfDirectory() + PASSWORD_FILE_NAME;
+ this.jmxAccessFilePath = directoriesProvider.getConfDirectory() + ACCESS_FILE_NAME;
isStarted = false;
registeredKeys = new HashSet<>();
lock = new Object();
@@ -116,8 +124,8 @@ public class JMXServer implements Startable {
Map<String, String> environment = Optional.of(existJmxPasswordFile())
.filter(FunctionalUtils.identityPredicate())
- .map(hasJmxPasswordFile -> ImmutableMap.of("jmx.remote.x.password.file", JmxConfiguration.PASSWORD_FILE_PATH,
- "jmx.remote.x.access.file", JmxConfiguration.ACCESS_FILE_PATH))
+ .map(hasJmxPasswordFile -> ImmutableMap.of("jmx.remote.x.password.file", jmxPasswordFilePath,
+ "jmx.remote.x.access.file", jmxAccessFilePath))
.orElse(ImmutableMap.of());
jmxConnectorServer = JMXConnectorServerFactory.newJMXConnectorServer(new JMXServiceURL(serviceURL),
@@ -147,37 +155,42 @@ public class JMXServer implements Startable {
}
private void generateJMXPasswordFileIfNeed() {
- if (Boolean.parseBoolean(System.getProperty(JMX_CREDENTIAL_GENERATION_ENABLE_PROPERTY, JMX_CREDENTIAL_GENERATION_ENABLE_DEFAULT))
+ if (Boolean.parseBoolean(System.getProperty(JMX_CREDENTIAL_GENERATION_ENABLE_PROPERTY_KEY, JMX_CREDENTIAL_GENERATION_ENABLE_DEFAULT_VALUE))
&& !existJmxPasswordFile()) {
generateJMXPasswordFile();
}
}
private boolean existJmxPasswordFile() {
- return Files.exists(Path.of(JmxConfiguration.PASSWORD_FILE_PATH)) && Files.exists(Path.of(JmxConfiguration.ACCESS_FILE_PATH));
+ return Files.exists(Path.of(jmxPasswordFilePath)) && Files.exists(Path.of(jmxAccessFilePath));
}
private void generateJMXPasswordFile() {
- File passwordFile = new File(JmxConfiguration.PASSWORD_FILE_PATH);
+ File passwordFile = new File(jmxPasswordFilePath);
if (!passwordFile.exists()) {
try (OutputStream outputStream = new FileOutputStream(passwordFile)) {
String randomPassword = RandomStringUtils.random(10, true, true);
IOUtils.write(JmxConfiguration.JAMES_ADMIN_USER_DEFAULT + " " + randomPassword + "\n", outputStream, StandardCharsets.UTF_8);
- LOGGER.info("Generated JMX password file: " + JmxConfiguration.PASSWORD_FILE_PATH);
+ setPermissionOwnerOnly(passwordFile);
+ LOGGER.info("Generated JMX password file: " + passwordFile.getPath());
} catch (IOException e) {
- throw new RuntimeException("Error when creating JMX password file: " + JmxConfiguration.PASSWORD_FILE_PATH, e);
+ throw new RuntimeException("Error when creating JMX password file: " + passwordFile.getPath(), e);
}
}
- File accessFile = new File(JmxConfiguration.ACCESS_FILE_PATH);
+ File accessFile = new File(jmxAccessFilePath);
if (!accessFile.exists()) {
try (OutputStream outputStream = new FileOutputStream(accessFile)) {
IOUtils.write(JmxConfiguration.JAMES_ADMIN_USER_DEFAULT + " readwrite\n", outputStream, StandardCharsets.UTF_8);
- LOGGER.info("Generated JMX access file: " + JmxConfiguration.ACCESS_FILE_PATH);
+ setPermissionOwnerOnly(accessFile);
+ LOGGER.info("Generated JMX access file: " + accessFile.getPath());
} catch (IOException e) {
- throw new RuntimeException("Error when creating JMX access file: " + JmxConfiguration.ACCESS_FILE_PATH, e);
+ throw new RuntimeException("Error when creating JMX access file: " + accessFile.getPath(), e);
}
}
}
+ private void setPermissionOwnerOnly(File file) throws IOException {
+ Files.setPosixFilePermissions(file.toPath(), Set.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE));
+ }
}
diff --git a/server/container/guice/jmx/src/main/java/org/apache/james/modules/server/JmxConfiguration.java b/server/container/guice/jmx/src/main/java/org/apache/james/modules/server/JmxConfiguration.java
index eeef6e2e09..c833990e20 100644
--- a/server/container/guice/jmx/src/main/java/org/apache/james/modules/server/JmxConfiguration.java
+++ b/server/container/guice/jmx/src/main/java/org/apache/james/modules/server/JmxConfiguration.java
@@ -34,10 +34,10 @@ public class JmxConfiguration {
public static final String LOCALHOST = "localhost";
public static final int DEFAULT_PORT = 9999;
public static final boolean ENABLED = true;
- public static final String JMX_CREDENTIAL_GENERATION_ENABLE_PROPERTY = "james.jmx.credential.generation";
- public static final String JMX_CREDENTIAL_GENERATION_ENABLE_DEFAULT = "false";
- public static final String PASSWORD_FILE_PATH = "/root/conf/jmxremote.password";
- public static final String ACCESS_FILE_PATH = "/root/conf/jmxremote.access";
+ public static final String JMX_CREDENTIAL_GENERATION_ENABLE_PROPERTY_KEY = "james.jmx.credential.generation";
+ public static final String JMX_CREDENTIAL_GENERATION_ENABLE_DEFAULT_VALUE = "false";
+ public static final String PASSWORD_FILE_NAME = "jmxremote.password";
+ public static final String ACCESS_FILE_NAME = "jmxremote.access";
public static final String JAMES_ADMIN_USER_DEFAULT = "james-admin";
public static final JmxConfiguration DEFAULT_CONFIGURATION = new JmxConfiguration(ENABLED, Optional.of(Host.from(LOCALHOST, DEFAULT_PORT)));
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org