/* * JBoss, Home of Professional Open Source. * Copyright 2011, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.domain.management.security.adduser; import static org.jboss.as.domain.management.security.adduser.AddUser.APPLICATION_ROLES_PROPERTIES; import static org.jboss.as.domain.management.security.adduser.AddUser.APPLICATION_USERS_PROPERTIES; import static org.jboss.as.domain.management.security.adduser.AddUser.DOMAIN_BASE_DIR; import static org.jboss.as.domain.management.security.adduser.AddUser.DOMAIN_CONFIG_DIR; import static org.jboss.as.domain.management.security.adduser.AddUser.DOMAIN_CONFIG_USER_DIR; import static org.jboss.as.domain.management.security.adduser.AddUser.MGMT_USERS_PROPERTIES; import static org.jboss.as.domain.management.security.adduser.AddUser.MGMT_GROUPS_PROPERTIES; import static org.jboss.as.domain.management.security.adduser.AddUser.SERVER_BASE_DIR; import static org.jboss.as.domain.management.security.adduser.AddUser.SERVER_CONFIG_DIR; import static org.jboss.as.domain.management.security.adduser.AddUser.SERVER_CONFIG_USER_DIR; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.jboss.as.domain.management.logging.DomainManagementLogger; import org.jboss.as.domain.management.security.PropertiesFileLoader; import org.jboss.as.domain.management.security.UserPropertiesFileLoader; import org.jboss.as.domain.management.security.adduser.AddUser.FileMode; import org.jboss.as.domain.management.security.adduser.AddUser.RealmMode; import org.jboss.msc.service.StartException; /** * The first state executed, responsible for searching for the relevant properties files. * * @author <a href="mailto:flemming.harms@gmail.com">Flemming Harms</a> * @author <a href="mailto:bgaisford@punagroup.com">Brandon Gaisford</a> */ public class PropertyFileFinder implements State { private ConsoleWrapper theConsole; private final StateValues stateValues; private boolean validFilePermissions = true; private String filePermissionsProblemPath; public PropertyFileFinder(ConsoleWrapper theConsole, final StateValues stateValues) { this.theConsole = theConsole; this.stateValues = stateValues; } @Override public State execute() { stateValues.setKnownGroups(new HashMap<String, String>()); if (stateValues.getOptions().getGroupProperties() != null && stateValues.getOptions().getUserProperties() == null) { return new ErrorState(theConsole, DomainManagementLogger.ROOT_LOGGER.groupPropertiesButNoUserProperties(stateValues.getOptions().getGroupProperties()), null, stateValues); } List<File> foundFiles = new ArrayList<File>(2); String fileName = stateValues.getOptions().getUserProperties(); fileName = fileName == null ? stateValues.getFileMode() == FileMode.MANAGEMENT ? MGMT_USERS_PROPERTIES : APPLICATION_USERS_PROPERTIES : fileName; if (!findFiles(foundFiles, fileName)) { return new ErrorState(theConsole, DomainManagementLogger.ROOT_LOGGER.propertiesFileNotFound(fileName), null, stateValues); } else if(!validFilePermissions) { return new ErrorState(theConsole, DomainManagementLogger.ROOT_LOGGER.filePermissionsProblemsFound( filePermissionsProblemPath + File.separator + fileName), null, stateValues); } fileName = stateValues.getOptions().getGroupProperties(); if (fileName != null || stateValues.getFileMode() != FileMode.UNDEFINED) { boolean groupFileMandatory = true; List<File> foundGroupFiles = new ArrayList<File>(2); if (fileName == null && stateValues.getFileMode() == FileMode.APPLICATION) { fileName = APPLICATION_ROLES_PROPERTIES; } else if (fileName == null) { fileName = MGMT_GROUPS_PROPERTIES; groupFileMandatory = false; } fileName = fileName == null ? APPLICATION_ROLES_PROPERTIES : fileName; if (!findFiles(foundGroupFiles, fileName) && groupFileMandatory) { return new ErrorState(theConsole, DomainManagementLogger.ROOT_LOGGER.propertiesFileNotFound(fileName), null, stateValues); } else if(!validFilePermissions) { return new ErrorState(theConsole, DomainManagementLogger.ROOT_LOGGER.filePermissionsProblemsFound( filePermissionsProblemPath + File.separator + fileName), null, stateValues); } stateValues.setGroupFiles(foundGroupFiles); try { stateValues.setKnownGroups(loadAllGroups(foundGroupFiles)); } catch (Exception e) { return new ErrorState(theConsole, DomainManagementLogger.ROOT_LOGGER.propertiesFileNotFound(fileName), null, stateValues); } } stateValues.setUserFiles(foundFiles); String realmName = null; Set<String> enabledFoundUsers = new HashSet<String>(); Set<String> disabledFoundUsers = new HashSet<String>(); for (File current : stateValues.getUserFiles()) { UserPropertiesFileLoader pfl = null; try { pfl = loadUsersFile(current); enabledFoundUsers.addAll(pfl.getEnabledUserNames()); disabledFoundUsers.addAll(pfl.getDisabledUserNames()); if (realmName == null) { realmName = pfl.getRealmName(); } else { String nextRealm = pfl.getRealmName(); if (realmName.equals(nextRealm) == false) { return new ErrorState(theConsole, DomainManagementLogger.ROOT_LOGGER.multipleRealmsDetected(realmName, nextRealm), null, stateValues); } } pfl.stop(null); pfl = null; } catch (IOException e) { return new ErrorState(theConsole, DomainManagementLogger.ROOT_LOGGER.unableToLoadUsers(current.getAbsolutePath(), e.getMessage()), null, stateValues); } finally { if (pfl != null) { pfl.stop(null); pfl = null; } } } if (realmName != null) { if (stateValues.getRealmMode() == RealmMode.USER_SUPPLIED && realmName.equals(stateValues.getRealm()) == false) { return new ErrorState(theConsole, DomainManagementLogger.ROOT_LOGGER.userRealmNotMatchDiscovered(stateValues.getRealm(), realmName), null, stateValues); } stateValues.setRealm(realmName); stateValues.setRealmMode(RealmMode.DISCOVERED); } stateValues.setEnabledKnownUsers(enabledFoundUsers); stateValues.setDisabledKnownUsers(disabledFoundUsers); // TODO - Should we go straight to user validation instead of prompting? return stateValues.isInteractive() ? new PromptRealmState(theConsole, stateValues) : new PromptNewUserState(theConsole, stateValues); } private UserPropertiesFileLoader loadUsersFile(File file) throws IOException { UserPropertiesFileLoader fileLoader = new UserPropertiesFileLoader(file.getAbsolutePath(), null); try { fileLoader.start(null); } catch (StartException e) { throw new IOException(e); } return fileLoader; } private Map<String, String> loadAllGroups(List<File> foundGroupsFiles) throws StartException, IOException { Map<String, String> loadedGroups = new HashMap<String, String>(); for (File file : foundGroupsFiles) { PropertiesFileLoader propertiesLoad = null; try { propertiesLoad = new PropertiesFileLoader(file.getCanonicalPath(), null); propertiesLoad.start(null); loadedGroups.putAll((Map) propertiesLoad.getProperties()); } finally { if (propertiesLoad != null) { propertiesLoad.stop(null); } } } return loadedGroups; } private boolean findFiles(final List<File> foundFiles, final String fileName) { File singleFile = new File(fileName); // Check for existence and writability (Windows file may have Read-Only bit set) if (singleFile.exists() && singleFile.canWrite()) { foundFiles.add(singleFile); return true; } String serverConfigOpt = stateValues.getOptions().getServerConfigDir(); String domainConfigOpt = stateValues.getOptions().getDomainConfigDir(); // if no option is set, add to both standalone and domain if (serverConfigOpt == null && domainConfigOpt == null) { File standaloneProps = buildFilePath(SERVER_CONFIG_USER_DIR, stateValues.getOptions().getServerConfigDir(), SERVER_CONFIG_DIR, SERVER_BASE_DIR, "standalone", fileName); if (standaloneProps.exists()) { foundFiles.add(standaloneProps); } File domainProps = buildFilePath(DOMAIN_CONFIG_USER_DIR, stateValues.getOptions().getDomainConfigDir(), DOMAIN_CONFIG_DIR, DOMAIN_BASE_DIR, "domain", fileName); if (domainProps.exists()) { foundFiles.add(domainProps); } } // if either the -sc or -dc options are set, use only the one specified. if (serverConfigOpt != null) { File standaloneProps = buildFilePath(SERVER_CONFIG_USER_DIR, stateValues.getOptions().getServerConfigDir(), SERVER_CONFIG_DIR, SERVER_BASE_DIR, "standalone", fileName); if (standaloneProps.exists()) { foundFiles.add(standaloneProps); } } 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); } } return !foundFiles.isEmpty(); } private File buildFilePath(final String serverConfigUserDirPropertyName, final String suppliedConfigDir, final String serverConfigDirPropertyName, final String serverBaseDirPropertyName, final String defaultBaseDir, final String fileName) { File dirPath = buildDirPath(serverConfigUserDirPropertyName, suppliedConfigDir, serverConfigDirPropertyName, serverBaseDirPropertyName, defaultBaseDir); File file = new File(dirPath, fileName); validatePermissions(dirPath, file); return file; } /** * This method attempts to locate a suitable directory by checking a number of different configuration sources. * * 1 - serverConfigUserDirPropertyName - This value is used to check it a matching system property has been set. 2 - * suppliedConfigDir - If a path was specified on the command line it is expected to be passed in as this parameter. 3 - * serverConfigDirPropertyName - This is a second system property to check. * * And finally if none of these match defaultBaseDir specifies the configuration being searched and is appended to the JBoss * Home value discovered when the utility started. */ private File buildDirPath(final String serverConfigUserDirPropertyName, final String suppliedConfigDir, final String serverConfigDirPropertyName, final String serverBaseDirPropertyName, final String defaultBaseDir) { String propertyDir = System.getProperty(serverConfigUserDirPropertyName); if (propertyDir != null) { return new File(propertyDir); } if (suppliedConfigDir != null) { return new File(suppliedConfigDir); } propertyDir = System.getProperty(serverConfigDirPropertyName); if (propertyDir != null) { return new File(propertyDir); } propertyDir = System.getProperty(serverBaseDirPropertyName); if (propertyDir != null) { return new File(propertyDir); } return new File(new File(stateValues.getOptions().getJBossHome(), defaultBaseDir), "configuration"); } /** * This method performs a series of permissions checks given a directory and properties file path. * * 1 - Check whether the parent directory dirPath has proper execute and read permissions * 2 - Check whether properties file path is readable and writable * * If either of the permissions checks fail, update validFilePermissions and filePermissionsProblemPath * appropriately. * */ private void validatePermissions(final File dirPath, final File file) { // Check execute and read permissions for parent dirPath if( !dirPath.canExecute() || !dirPath.canRead() ) { validFilePermissions = false; filePermissionsProblemPath = dirPath.getAbsolutePath(); return; } // Check read and write permissions for properties file if( !file.canRead() || !file.canWrite() ) { validFilePermissions = false; filePermissionsProblemPath = dirPath.getAbsolutePath(); } } }