Skip to content
This repository has been archived by the owner on Jul 11, 2022. It is now read-only.

Commit

Permalink
[1119127] rhqctl to prompt for rhqadmin password, rather than using h…
Browse files Browse the repository at this point in the history
…ard-coded default

We no longer support the default rhqadmin/rhqadmin user/password superuser
combination.  The rhqadmin user still exists but the password must be
set by the user. The new rhq.autoinstall.server.admin.password property
must be set in rhq-server.properties.  If not set the 'rhqctl install'
command will prompt for a password and update rhq-server.properties with
the encrypted value.  Additionally, the rhq-encode-password.sh|bat machanism has been
enhanced to allow the user to generate the value.

Note that dev containers are unchanged and automatically provide rhqadmin/rhqadmin.
  • Loading branch information
jshaughn committed Jul 29, 2014
1 parent 58369f1 commit 8ae6185
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 63 deletions.
3 changes: 0 additions & 3 deletions modules/core/dbutils/src/main/scripts/dbsetup-build.xml
Expand Up @@ -156,11 +156,8 @@ To run the default target, you must set one of the following properties to true:
<replacefilter token="@@@LARGE_TABLESPACE_FOR_INDEX@@@" value="${server.tablespace.large-index}"/>
</replace>

<md5 value="${server.admin.password}" property="server.admin.password.encrypted"/>

<replace file="${dbsetup.combined.data}">
<replacefilter token="@@@ADMINUSERNAME@@@" value="${server.admin.username}"/>
<replacefilter token="@@@ADMINPASSWORD@@@" value="${server.admin.password.encrypted}"/>
<replacefilter token="@@@ADMINEMAIL@@@" value="${server.admin.email}"/>
<replacefilter token="@@@BASEURL@@@" value="${server.webapp.baseurl}"/>
<replacefilter token="@@@JAASPROVIDER@@@" value="${server.jaas.provider}"/>
Expand Down
1 change: 0 additions & 1 deletion modules/core/dbutils/src/main/scripts/dbsetup.properties
Expand Up @@ -9,7 +9,6 @@ server.webapp.baseurl=http://localhost:${server.webapp.port}/

# Default admin user properties
server.admin.username=rhqadmin
server.admin.password=rhqadmin
server.admin.email=nobody@localhost

# Default JAAS properties
Expand Down
9 changes: 0 additions & 9 deletions modules/core/dbutils/src/main/scripts/dbsetup/auth-data.xml

This file was deleted.

Expand Up @@ -3,39 +3,45 @@
<project name="rhq-appserver-container" basedir=".">

<!-- rhq-server.properties defaults -->

<!-- database -->
<property name="default.rhq.server.database.hibernate-dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="default.rhq.server.database.connection-url" value="jdbc:postgresql://127.0.0.1:5432/rhq" />
<property name="default.rhq.server.database.user-name" value="rhqadmin" />
<property name="default.rhq.server.database.password" value="rhqadmin" />
<property name="default.rhq.server.database.password.encrypted" value="1eeb2f255e832171df8592078de921bc" />
<property name="default.rhq.server.database.type-mapping" value="PostgreSQL" />

<!-- these are needed for the PostgreSQL XADataSource setup -->
<property name="default.rhq.server.database.server-name" value="127.0.0.1" />
<property name="default.rhq.server.database.port" value="5432" />
<property name="default.rhq.server.database.db-name" value="rhq" />

<!-- quartz scheduler -->
<property name="default.rhq.server.quartz.driverDelegateClass" value="org.quartz.impl.jdbcjobstore.PostgreSQLDelegate" />
<property name="default.rhq.server.quartz.selectWithLockSQL" value="SELECT * FROM {0}LOCKS ROWLOCK WHERE LOCK_NAME = ? FOR UPDATE" />
<property name="default.rhq.server.quartz.lockHandlerClass" value="org.quartz.impl.jdbcjobstore.StdRowLockSemaphore" />

<!-- other -->
<property name="default.rhq.autoinstall.server.admin.password" value=""/>
<property name="default.rhq.server.drift.binary.content" value="false"/>

<!-- storage -->
<property name="default.rhq.storage.username" value=""/>
<property name="default.rhq.storage.password" value=""/>

<property name="default.jboss.bind.address" value=""/>
<property name="default.jboss.bind.address" value=""/>

<property name="default.rhq.storage.commitlog" value=""/>
<property name="default.rhq.storage.data" value=""/>
<property name="default.rhq.storage.saved-caches" value=""/>
<property name="default.rhq.storage.heap-size" value=""/>
<property name="default.rhq.storage.heap-new-size" value=""/>
<property name="default.rhq.storage.hostname" value=""/>
<property name="default.rhq.storage.jmx-port" value=""/>
<property name="default.rhq.storage.seeds" value=""/>
<property name="default.rhq.storage.verify-data-dirs-empty" value=""/>
<property name="default.rhq.storage.cql-port" value="9142"/>
<property name="default.rhq.storage.gossip-port" value="7100"/>
<property name="default.rhq.storage.commitlog" value=""/>
<property name="default.rhq.storage.data" value=""/>
<property name="default.rhq.storage.saved-caches" value=""/>
<property name="default.rhq.storage.heap-size" value=""/>
<property name="default.rhq.storage.heap-new-size" value=""/>
<property name="default.rhq.storage.hostname" value=""/>
<property name="default.rhq.storage.jmx-port" value=""/>
<property name="default.rhq.storage.seeds" value=""/>
<property name="default.rhq.storage.verify-data-dirs-empty" value=""/>
<property name="default.rhq.storage.cql-port" value="9142"/>
<property name="default.rhq.storage.gossip-port" value="7100"/>

<target name="set-predeploy-prop">
<condition property="predeploy" value="true">
Expand All @@ -60,10 +66,13 @@
<property name="rhq.server.quartz.selectWithLockSQL" value="${rhq.dev.quartz.selectWithLockSQL}" />
<property name="rhq.server.quartz.lockHandlerClass" value="${rhq.dev.quartz.lockHandlerClass}" />
<property name="rhq.server.drift.store-binary-content" value="${default.rhq.server.drift.binary.content}"/>

<!-- these are only set explicitly in dev envs, prod envs generate these at install time -->
<property name="rhq.storage.username" value="rhqadmin"/>
<property name="rhq.storage.password" value="1eeb2f255e832171df8592078de921bc"/>
<!-- this is only set explicitly in dev envs, prod envs must set these manually for security -->

<!-- these are only set explicitly in dev envs, prod envs must set these manually for security -->
<property name="rhq.autoinstall.server.admin.password" value="x1XwrxKuPvYUILiOnOZTLg==" />
<property name="jboss.bind.address" value="0.0.0.0"/>

<echo>*** Using dev settings in rhq-storage.properties...</echo>
Expand Down Expand Up @@ -96,7 +105,8 @@
<!-- these are only set explicitly in dev envs, prod envs generate these at install time -->
<property name="rhq.storage.username" value="${default.rhq.storage.username}"/>
<property name="rhq.storage.password" value="${default.rhq.storage.password}"/>
<!-- this is only set by default in dev envs, prod envs must set these manually for security -->
<!-- these are only set by default in dev envs, prod envs must set these manually for security -->
<property name="rhq.autoinstall.server.admin.password" value="${default.rhq.autoinstall.server.admin.password}"/>
<property name="jboss.bind.address" value="${default.jboss.bind.address}"/>

<echo>*** Using default settings in rhq-storage.properties...</echo>
Expand Down Expand Up @@ -682,30 +692,36 @@ rhq.server.socket.binding.port.txn-status-manager=3713
# ------------------
# INSTALLATION ACTION REQUIRED! Review the default settings:
#
# These enable the installer when starting for the first time.
# To do so, first ensure all values in this properties file are appropriately
# set for your environment. Once you are sure all values are as you want them,
# These enable the installer when starting for the first time. To do so,
# first ensure all values in this properties file are appropriately set
# for your environment. Once you are sure all values are as you want them,
# set rhq.autoinstall.enabled=true and run the server then run the installer.
#
# rhq.autoinstall.enabled: must be true to trigger the automatic install.
# rhq.autoinstall.database: allowed values: auto, overwrite, skip
# "auto" will create a new schema if one does not
# yet exist or, if a schema does exist, will simply
# upgrade it as needed (which keeps existing data).
# "overwrite" if you want to create an empty schema,
# even if one already exists (loses existing data).
# "skip" if you don't want to do any database
# upgrade or creation. WARNING! You must ensure your
# database schema already exists and is up to date.
# rhq.autoinstall.public-endpoint-address: public IP/hostname that all agents
# will use to talk to this server.
# If not set, a value to use is
# determined at auto-install time.
# rhq.autoinstall.enabled
# This must be true to trigger the automatic install.
# rhq.autoinstall.database
# Allowed values: auto, overwrite, skip:
# auto : create a new schema if one does not exist, otherwise
# upgrade the existing schema as needed (keep existing data).
# overwrite: create a new schema even if one exists (lose existing data).
# skip : leave existing database as is. WARNING! You must ensure your
# database schema already exists and is up to date.
# rhq.autoinstall.public-endpoint-address
# The public IP/hostname that all agents will use to talk to this server.
# If not set, a value to use is determined at auto-install time.
# rhq.autoinstall.server.admin.password
# The password for the built-in "rhqadmin" superuser. If not set the
# password will be prompted for by the "rhqctl install" command.
#
# NOTE: rhq.autoinstall.server.admin.password is not to be set to the
# actual password but instead should be the encoded password value
# as generated by: rhq-encode-password.sh(.bat)
#############################################################################

rhq.autoinstall.enabled=true
rhq.autoinstall.database=auto
rhq.autoinstall.public-endpoint-address=
rhq.autoinstall.server.admin.password=${rhq.autoinstall.server.admin.password}

#############################################################################
# Advanced Settings
Expand Down
Expand Up @@ -28,6 +28,8 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.jboss.crypto.CryptoUtil;

import org.rhq.core.util.exception.ThrowableUtil;
import org.rhq.enterprise.server.installer.InstallerService.AlreadyInstalledException;
import org.rhq.enterprise.server.installer.InstallerService.AutoInstallDisabledException;
Expand Down Expand Up @@ -234,8 +236,13 @@ private WhatToDo[] processArguments(String[] args) throws Exception {
Console console = System.console();
if (null != console) {
passwordToEncode = String.valueOf(console.readLine("%s", "Password: "));
associatedProperty = String.valueOf(console.readLine("%s",
"Property [rhq.server.database.password]: "));
associatedProperty = "rhq.autoinstall.server.admin.password";
if (!confirm(console, "Property " + associatedProperty)) {
associatedProperty = "rhq.server.database.password";
if (!confirm(console, "Property " + associatedProperty)) {
associatedProperty = ask(console, "Property to encode: ");
}
}
} else {
LOG.error("NO CONSOLE!");
}
Expand Down Expand Up @@ -267,14 +274,17 @@ private WhatToDo[] processArguments(String[] args) throws Exception {

// if a password was asked to be encoded, that's all we do on the execution
if (passwordToEncode != null) {
if (associatedProperty == null || associatedProperty.trim().isEmpty()) {
associatedProperty = "rhq.server.database.password";
String encodedPassword;
if ("rhq.autoinstall.server.admin.password".equals(associatedProperty)) {
encodedPassword = CryptoUtil.createPasswordHash("MD5", CryptoUtil.BASE64_ENCODING, null, null,
passwordToEncode);
} else {
encodedPassword = new InstallerServiceImpl(installerConfig).obfuscatePassword(String
.valueOf(passwordToEncode));
}

String encodedPassword = new InstallerServiceImpl(installerConfig).obfuscatePassword(String
.valueOf(passwordToEncode));

if ("rhq.server.database.password".equals(associatedProperty.trim())) {
if ("rhq.server.database.password".equals(associatedProperty)
|| "rhq.autoinstall.server.admin.password".equals(associatedProperty)) {
LOG.info("*** Encoded password for rhq-server.properties:");
LOG.info("*** " + associatedProperty + "=" + encodedPassword);
LOG.info("*** ");
Expand Down Expand Up @@ -320,4 +330,22 @@ private WhatToDo[] processArguments(String[] args) throws Exception {

return new WhatToDo[] { WhatToDo.INSTALL };
}

private String ask(Console console, String prompt) {
String response = "";
do {
response = String.valueOf(console.readLine("%s", prompt).trim());
} while (response.isEmpty());

return response;
}

private boolean confirm(Console console, String option) {
String response = "";
do {
response = ask(console, option + " [y/n]: ").trim().toLowerCase();
} while (!(response.startsWith("y") || response.startsWith("n")));

return response.startsWith("y");
}
}
Expand Up @@ -603,6 +603,7 @@ public Connection newConnection() throws SQLException {

// ensure the server info is up to date and stored in the DB
ServerInstallUtil.storeServerDetails(serverProperties, clearTextDbPassword, serverDetails);
ServerInstallUtil.persistAdminPasswordIfNecessary(serverProperties, clearTextDbPassword);
ServerInstallUtil.persistStorageNodesIfNecessary(serverProperties, clearTextDbPassword,
parseNodeInformation(serverProperties, storageNodeAddresses));
ServerInstallUtil.persistStorageClusterSettingsIfNecessary(serverProperties, clearTextDbPassword);
Expand Down
Expand Up @@ -945,6 +945,65 @@ public static Connection getDatabaseConnection(String connectionUrl, String user
return DbUtil.getConnection(connectionUrl, userName, password);
}

/**
* @param serverProperties the server properties
* @param dbpassword clear text password to connect to the database
* @throws Exception
*/
public static void persistAdminPasswordIfNecessary(HashMap<String, String> serverProperties, String dbpassword)
throws Exception {
DatabaseType db = null;
Connection connection = null;
Statement queryStatement = null;
Statement insertStatement = null;
ResultSet resultSet = null;

try {
String dbUrl = serverProperties.get(ServerProperties.PROP_DATABASE_CONNECTION_URL);
String userName = serverProperties.get(ServerProperties.PROP_DATABASE_USERNAME);
connection = getDatabaseConnection(dbUrl, userName, dbpassword);
db = DatabaseTypeFactory.getDatabaseType(connection);

if (!(db instanceof PostgresqlDatabaseType || db instanceof OracleDatabaseType)) {
throw new IllegalArgumentException("Unknown database type, can't continue: " + db);
}

queryStatement = connection.createStatement();
resultSet = queryStatement.executeQuery("SELECT count(*) FROM rhq_principal WHERE id=2");
resultSet.next();

if (resultSet.getInt(1) == 0) {
connection.setAutoCommit(false);

try {
LOG.info("Persisting admin password to database for property [rhq.autoinstall.server.admin.password]");

insertStatement = connection.createStatement();
insertStatement.executeUpdate("INSERT INTO rhq_principal VALUES (2, 'rhqadmin', '"
+ serverProperties.get(ServerProperties.PROP_AUTOINSTALL_ADMIN_PASSWORD) + "')");

connection.commit();
} catch (SQLException e) {
LOG.error(
"Failed to persist admin password to database for property [rhq.autoinstall.server.admin.password]. Transaction will be rolled back.",
e);
connection.rollback();
throw e;
}
} else {
LOG.info("Admin user password is already set, property [rhq.autoinstall.server.admin.password] will be ignored.");
}

} finally {
if (db != null) {
db.closeResultSet(resultSet);
db.closeStatement(queryStatement);
db.closeStatement(insertStatement);
db.closeConnection(connection);
}
}
}

/**
* Persists the storage nodes to the database only if no storage node entities already exist. This method is used
* to persist storage nodes created from the rhq.storage.nodes server configuration property. The only time those
Expand Down Expand Up @@ -1081,7 +1140,7 @@ public static Map<String, String> fetchStorageClusterSettings(HashMap<String, St
while (resultSet.next()) {
String address = resultSet.getString(1);

if(address != null && !address.trim().isEmpty()){
if (address != null && !address.trim().isEmpty()) {
if (addressList.length() != 0) {
addressList.append(',');
}
Expand Down Expand Up @@ -1651,7 +1710,7 @@ private static String buildExpression(String propName, HashMap<String, String> d
}
} else {
String attributeType = "restricted";
if(!restricted){
if (!restricted) {
attributeType = "open";
}
if ((defaultProperties != null) && (defaultProperties.containsKey(propName))) {
Expand Down
Expand Up @@ -60,6 +60,7 @@ public class ServerProperties {
public static final String PROP_AUTOINSTALL_ENABLE = "rhq.autoinstall.enabled";
public static final String PROP_AUTOINSTALL_DATABASE = "rhq.autoinstall.database";
public static final String PROP_AUTOINSTALL_PUBLIC_ADDR = "rhq.autoinstall.public-endpoint-address";
public static final String PROP_AUTOINSTALL_ADMIN_PASSWORD = "rhq.autoinstall.server.admin.password";

public static final String PROP_TOMCAT_SECURITY_CLIENT_AUTH_MOD = "rhq.server.tomcat.security.client-auth-mode";
public static final String PROP_TOMCAT_SECURITY_SSL_PROTOCOL = "rhq.server.tomcat.security.secure-socket-protocol";
Expand Down Expand Up @@ -172,6 +173,7 @@ public class ServerProperties {
static {
STRING_PROPERTIES = new HashSet<String>();
STRING_PROPERTIES.add(PROP_AUTOINSTALL_DATABASE);
STRING_PROPERTIES.add(PROP_AUTOINSTALL_ADMIN_PASSWORD);
STRING_PROPERTIES.add(PROP_DATABASE_TYPE);
STRING_PROPERTIES.add(PROP_DATABASE_CONNECTION_URL);
STRING_PROPERTIES.add(PROP_DATABASE_PASSWORD);
Expand All @@ -187,7 +189,7 @@ public class ServerProperties {
STRING_PROPERTIES.add(PROP_QUARTZ_SELECT_WITH_LOCK_SQL);
}

// this list contains all the STRING properties that are to have obfuscated values
// this list contains all the STRING properties that are to have obfuscated/encoded values
private static final Set<String> OBFUSCATED_PROPERTIES;
static {
OBFUSCATED_PROPERTIES = new HashSet<String>();
Expand Down

0 comments on commit 8ae6185

Please sign in to comment.