Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1241,6 +1241,15 @@ public interface DomainManagementLogger extends BasicLogger {
@Message(id = 146, value = "Outbound connections are no longer supported, please remove them from the configuration.")
XMLStreamException outboundConnectionsUnsupported();

/**
* Message stating that the required file or directory structure could not be created.
*
* @param path the path that could not be created.
* @return the message.
*/
@Message(id = 147, value = "Failed to create the required configuration path: %s")
String failedToCreateFilesConfigurationPath(String path);

/**
* Information message saying the username and password must be different.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ public static void main(String[] args) {
}
if (CommandLineArgument.DOMAIN_CONFIG_DIR_USERS.match(temp)) {
options.setDomainConfigDir(it.next());
} else if (CommandLineArgument.CREATE_FILES.match(temp)) {
options.setCreateFiles(true);
} else if (CommandLineArgument.SERVER_CONFIG_DIR_USERS.match(temp)) {
options.setServerConfigDir(it.next());
} else if (CommandLineArgument.APPLICATION_USERS.match(temp)) {
Expand Down Expand Up @@ -266,6 +268,12 @@ public String instructions() {
return DomainManagementLogger.ROOT_LOGGER.argDomainConfigDirUsers();
}
},
CREATE_FILES("-cf", "--create-files") {
@Override
public String instructions() {
return "Create files & directories if they do not exist";
}
},
SERVER_CONFIG_DIR_USERS("-sc") {
@Override
public String argumentExample() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
Expand All @@ -42,6 +43,8 @@ public class PropertyFileFinder implements State {
private final StateValues stateValues;
private boolean validFilePermissions = true;
private String filePermissionsProblemPath;
private boolean createFilesFailed = false;
private String createFilesFailedCause;

public PropertyFileFinder(ConsoleWrapper theConsole, final StateValues stateValues) {
this.theConsole = theConsole;
Expand All @@ -61,6 +64,9 @@ public State execute() {
fileName = fileName == null ? stateValues.getFileMode() == FileMode.MANAGEMENT ? MGMT_USERS_PROPERTIES
: APPLICATION_USERS_PROPERTIES : fileName;
if (!findFiles(foundFiles, fileName)) {
if (createFilesFailed) {
return new ErrorState(theConsole, DomainManagementLogger.ROOT_LOGGER.failedToCreateFilesConfigurationPath(createFilesFailedCause), null, null);
}
return new ErrorState(theConsole, DomainManagementLogger.ROOT_LOGGER.propertiesFileNotFound(fileName), null, stateValues);
} else if(!validFilePermissions) {
return new ErrorState(theConsole, DomainManagementLogger.ROOT_LOGGER.filePermissionsProblemsFound(
Expand Down Expand Up @@ -180,6 +186,7 @@ private boolean findFiles(final List<File> foundFiles, final String fileName) {

String serverConfigOpt = stateValues.getOptions().getServerConfigDir();
String domainConfigOpt = stateValues.getOptions().getDomainConfigDir();
Boolean createFilesOpt = stateValues.getOptions().isCreateFiles();

// if no option is set, add to both standalone and domain
if (serverConfigOpt == null && domainConfigOpt == null) {
Expand All @@ -201,15 +208,21 @@ private boolean findFiles(final List<File> foundFiles, final String fileName) {
SERVER_CONFIG_DIR, SERVER_BASE_DIR, "standalone", fileName);
if (standaloneProps.exists()) {
foundFiles.add(standaloneProps);
} // TODO should this invalid --sc be an error regardless of whether domainConfigOpt points to a valid dir?
} else if (createFilesOpt) {
createFiles(standaloneProps, foundFiles);
}
// TODO should this invalid --sc be an error regardless of whether domainConfigOpt points to a valid dir?
}

if (domainConfigOpt != null) {
File domainProps = buildFilePath(DOMAIN_CONFIG_USER_DIR, stateValues.getOptions().getDomainConfigDir(),
DOMAIN_CONFIG_DIR, DOMAIN_BASE_DIR, "domain", fileName);
if (domainProps.exists()) {
foundFiles.add(domainProps);
} // TODO should this invalid --dc be an error regardless of whether serverConfigOpt points to a valid dir?
} else if (createFilesOpt) {
createFiles(domainProps, foundFiles);
}
// TODO should this invalid --dc be an error regardless of whether serverConfigOpt points to a valid dir?
}

return !foundFiles.isEmpty();
Expand Down Expand Up @@ -290,4 +303,31 @@ private void validatePermissions(final File dirPath, final File file) {

}

/**
* Attempts to create the configuration file and its parent directories if they do not exist.
* This is used when the --create-files (-cf) flag is provided to ensure the environment
* is ready for user creation, especially in cloud or containerized deployments.
* If an error occurs, the {@code createFilesFailed} flag is set to true and the
* cause is captured in {@code createFilesFailedCause}.
*
* @param file the properties file to be created.
* @param foundFiles the list of files to be updated if creation is successful.
*/
private void createFiles(final File file, final List<File> foundFiles) {
File parentDir = file.getParentFile();

try {
if (parentDir != null && !parentDir.exists()) {
Files.createDirectories(parentDir.toPath());
}

if (!file.exists()) {
Files.createFile(file.toPath());
foundFiles.add(file);
}
} catch (IOException e) {
createFilesFailed = true;
createFilesFailedCause = file.getAbsolutePath() + " (" + e.toString() + ")";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ class RuntimeOptions {

private boolean displaySecret = false;

private boolean createFiles = false;

/**
* Enable/Disable mode is active by using --enable or --disable argument
*/
Expand Down Expand Up @@ -129,4 +131,12 @@ boolean isDisplaySecret() {
void setDisplaySecret(boolean displaySecret) {
this.displaySecret = displaySecret;
}

public boolean isCreateFiles() {
return createFiles;
}

public void setCreateFiles(boolean createFiles) {
this.createFiles = createFiles;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Properties;

import static java.lang.System.getProperty;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;

/**
* Test the property file finder.
Expand Down Expand Up @@ -157,5 +159,111 @@ public void noStandaloneDir() throws IOException {
assertTrue("Expected the values.getPropertiesFiles() contained the "+domainMgmtUserFile,values.getUserFiles().contains(domainMgmtUserFile));
}

/**
* Tests the creation of parent directories and property files when
* the -cf or --create-files flag is used in Standalone mode configuration.
*
* @throws IOException if an error occurs during directory or file creation.
*/
@Test
public void createFilesServerConfigDir() throws IOException {
RuntimeOptions options = new RuntimeOptions();
options.setCreateFiles(true);

File tempDir = new File(System.getProperty("java.io.tmpdir"));
// Using a unique suffix to avoid conflicts during parallel builds
File customDir = new File(tempDir, "user-secrets-test-" + java.util.UUID.randomUUID());
File customFileMgmtUsers = new File(customDir, "mgmt-users.properties");
File customFileMgmtGroups = new File(customDir, "mgmt-groups.properties");

StateValues stateValues = new StateValues(options);
stateValues.setFileMode(AddUser.FileMode.MANAGEMENT);
stateValues.getOptions().setServerConfigDir(customDir.getAbsolutePath());

PropertyFileFinder finder = new PropertyFileFinder(consoleMock, stateValues);
try {
State nextState = finder.execute();

assertTrue("Should transition to PromptRealmState", nextState instanceof PromptRealmState);
assertTrue("Directory should have been created", customDir.exists());
assertTrue("Path should be a directory", customDir.isDirectory());
assertTrue("User properties file should exist", customFileMgmtUsers.exists());
assertTrue("Group properties file should exist", customFileMgmtGroups.exists());
} finally {
if (customDir.exists()) {
cleanFiles(customDir);
}
}
}

/**
* Tests the creation of parent directories and property files when
* the -cf or --create-files flag is used in Domain mode configuration.
*
* @throws IOException if an error occurs during directory or file creation.
*/
@Test
public void createFilesDomainConfigDir() throws IOException {
RuntimeOptions options = new RuntimeOptions();
options.setCreateFiles(true);

File tempDir = new File(System.getProperty("java.io.tmpdir"));
// Using a unique suffix to avoid conflicts during parallel builds
File customDir = new File(tempDir, "user-secrets-test-" + java.util.UUID.randomUUID());
File customFileMgmtUsers = new File(customDir, "mgmt-users.properties");
File customFileMgmtGroups = new File(customDir, "mgmt-groups.properties");

StateValues stateValues = new StateValues(options);
stateValues.setFileMode(AddUser.FileMode.MANAGEMENT);
stateValues.getOptions().setDomainConfigDir(customDir.getAbsolutePath());

PropertyFileFinder finder = new PropertyFileFinder(consoleMock, stateValues);
try {
State nextState = finder.execute();

assertTrue("Should transition to PromptRealmState", nextState instanceof PromptRealmState);
assertTrue("Directory should have been created", customDir.exists());
assertTrue("Path should be a directory", customDir.isDirectory());
assertTrue("User properties file should exist", customFileMgmtUsers.exists());
assertTrue("Group properties file should exist", customFileMgmtGroups.exists());
} finally {
if (customDir.exists()) {
cleanFiles(customDir);
}
}
}

/**
* Tests the error handling when the -cf or --create-files flag is used
* and the application lacks the necessary permissions to create the path.
*
* @throws IOException if an unexpected error occurs.
*/
@Test
public void permissionError() throws IOException {
File readOnlyDir = Files.createTempDirectory("read_only_dir").toFile();

try {
readOnlyDir.setWritable(false);

if (System.getProperty("os.name").toLowerCase().contains("win")) {
assumeFalse("Skipping: Windows ignored setWritable(false) on directories", readOnlyDir.canWrite());
}

RuntimeOptions options = new RuntimeOptions();
options.setCreateFiles(true);

StateValues stateValues = new StateValues(options);
stateValues.setFileMode(AddUser.FileMode.MANAGEMENT);
stateValues.getOptions().setServerConfigDir(readOnlyDir.getAbsolutePath());

PropertyFileFinder finder = new PropertyFileFinder(consoleMock, stateValues);
State nextState = finder.execute();

assertTrue("Should return ErrorState due to lack of write permissions", nextState instanceof ErrorState);
} finally {
readOnlyDir.setWritable(true);
cleanFiles(readOnlyDir);
}
}
}
Loading