Skip to content
Merged
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
4 changes: 4 additions & 0 deletions server/conf/mirth.properties
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ server.api.accesscontrolallowheaders = Content-Type
server.api.accesscontrolexposeheaders =
server.api.accesscontrolmaxage =

# Password for the admin user, only applied when the database is first created.
# If blank, a random password is generated and written to the log once on first startup.
server.initialadminpassword =

# Determines whether or not channels are deployed on server startup.
server.startupdeploy = true

Expand Down
2 changes: 0 additions & 2 deletions server/dbconf/derby/derby-database.sql
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,6 @@ CREATE TABLE DEBUGGER_USAGE

INSERT INTO PERSON (USERNAME, LOGGED_IN) VALUES('admin', 0);

INSERT INTO PERSON_PASSWORD (PERSON_ID, PASSWORD) VALUES(1, 'b8cA3mDkavInMc2JBYa6/C3EGxDp7ppqh7FsoXx0x8+3LWK3Ed3ELg==');

INSERT INTO SCHEMA_INFO (VERSION) VALUES ('4.6.0');

INSERT INTO CONFIGURATION (CATEGORY, NAME, VALUE) VALUES ('core', 'stats.enabled', '1');
Expand Down
2 changes: 0 additions & 2 deletions server/dbconf/mysql/mysql-database.sql
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,6 @@ CREATE TABLE DEBUGGER_USAGE

INSERT INTO PERSON (USERNAME, LOGGED_IN) VALUES('admin', FALSE);

INSERT INTO PERSON_PASSWORD (PERSON_ID, PASSWORD) VALUES(1, 'b8cA3mDkavInMc2JBYa6/C3EGxDp7ppqh7FsoXx0x8+3LWK3Ed3ELg==');

INSERT INTO SCHEMA_INFO (VERSION) VALUES ('4.6.0');

INSERT INTO CONFIGURATION (CATEGORY, NAME, VALUE) VALUES ('core', 'stats.enabled', '1');
Expand Down
2 changes: 0 additions & 2 deletions server/dbconf/oracle/oracle-database.sql
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,6 @@ CREATE TABLE DEBUGGER_USAGE

INSERT INTO PERSON (ID, USERNAME, LOGGED_IN, USERCONSENT) VALUES (PERSON_SEQUENCE.NEXTVAL, 'admin', '0', '0');

INSERT INTO PERSON_PASSWORD (PERSON_ID, PASSWORD) VALUES(PERSON_SEQUENCE.CURRVAL, 'b8cA3mDkavInMc2JBYa6/C3EGxDp7ppqh7FsoXx0x8+3LWK3Ed3ELg==');

INSERT INTO SCHEMA_INFO (VERSION) VALUES ('4.6.0');

INSERT INTO CONFIGURATION (CATEGORY, NAME, VALUE) VALUES ('core', 'stats.enabled', '1');
Expand Down
2 changes: 0 additions & 2 deletions server/dbconf/postgres/postgres-database.sql
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,6 @@ CREATE TABLE DEBUGGER_USAGE

INSERT INTO PERSON (USERNAME, LOGGED_IN) VALUES('admin', FALSE);

INSERT INTO PERSON_PASSWORD (PERSON_ID, PASSWORD) VALUES(1, 'b8cA3mDkavInMc2JBYa6/C3EGxDp7ppqh7FsoXx0x8+3LWK3Ed3ELg==');

INSERT INTO SCHEMA_INFO (VERSION) VALUES ('4.6.0');

INSERT INTO CONFIGURATION (CATEGORY, NAME, VALUE) VALUES ('core', 'stats.enabled', '1');
Expand Down
2 changes: 0 additions & 2 deletions server/dbconf/sqlserver/sqlserver-database.sql
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,6 @@ CREATE TABLE DEBUGGER_USAGE

INSERT INTO PERSON (USERNAME, LOGGED_IN, USERCONSENT) VALUES('admin', 0, 0);

INSERT INTO PERSON_PASSWORD (PERSON_ID, PASSWORD) VALUES(1, 'b8cA3mDkavInMc2JBYa6/C3EGxDp7ppqh7FsoXx0x8+3LWK3Ed3ELg==');

INSERT INTO SCHEMA_INFO (VERSION) VALUES ('4.6.0');

INSERT INTO CONFIGURATION (CATEGORY, NAME, VALUE) VALUES ('core', 'stats.enabled', '1');
Expand Down
7 changes: 6 additions & 1 deletion server/docs/README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,12 @@ After the installation, the Mirth Connect directory layout will look as follows:

Once Mirth Connect has been installed, there are several ways to connect to launch the Mirth Connect Administrator. On a Windows installation, there is a Mirth Connect Administrator item in the Start Menu which launches the application directly.

If the option is not available, you can connect to the Mirth Connect Administrator launch page which by default should be available at http://[server address]:8080 (i.e. http://localhost:8080). Clicking the Launch Mirth Connect Administrator button will connect you to the server which will be listening on https://[server address]:8443 (i.e. https://localhost:8443). If running a new installation, the default username and password for the login screen is admin and admin. This should be changed immediately for security purposes.
If the option is not available, you can connect to the Mirth Connect Administrator launch page which by default should be available at http://[server address]:8080 (i.e. http://localhost:8080). Clicking the Launch Mirth Connect Administrator button will connect you to the server which will be listening on https://[server address]:8443 (i.e. https://localhost:8443).

If running a new installation, the username for the login screen is admin, and its initial password is generated
randomly when the database is first created. You can find that password in logs/mirth.log, where it is written
once on first startup. You will be asked to change it when you log in. To choose the initial password yourself
instead, set server.initialadminpassword in conf/mirth.properties before starting the server for the first time.

If you are launching the administrator for the first time, you will notice that the libraries for the Mirth Connect Administrator will be loaded. This feature allows you run the Administrator from any remote Mirth Connect server without having to download and install a separate client.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public interface UserServletInterface extends BaseServletInterface {
@MirthOperation(name = "login", display = "Login")
public LoginStatus login(// @formatter:off
@Param("username") @Parameter(description = "The username to login with.", required = true, schema = @Schema(defaultValue = "admin")) @FormParam("username") String username,
@Param(value = "password", excludeFromAudit = true) @Parameter(description = "The password to login with.", required = true, schema = @Schema(defaultValue = "admin")) @FormParam("password") String password) throws ClientException;
@Param(value = "password", excludeFromAudit = true) @Parameter(description = "The password to login with.", required = true) @FormParam("password") String password) throws ClientException;
// @formatter:on

@POST
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.PropertiesConfigurationLayout;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.mirth.connect.client.core.PropertiesConfigurationUtil;
import com.mirth.connect.client.core.Version;
import com.mirth.connect.model.Channel;
import com.mirth.connect.model.ExportClearable;
Expand All @@ -38,9 +40,16 @@
import com.mirth.connect.model.codetemplates.CodeTemplateLibrary;
import com.mirth.connect.model.converters.ObjectXMLSerializer;
import com.mirth.connect.model.util.MigrationException;
import com.mirth.connect.server.Mirth;
import com.mirth.connect.server.controllers.ConfigurationController;
import com.mirth.connect.server.controllers.ControllerFactory;
import com.mirth.connect.server.util.DatabaseUtil;

public class ServerMigrator extends Migrator {
private static final String INITIAL_ADMIN_USERNAME = "admin";
private static final String INITIAL_ADMIN_PASSWORD_PROPERTY = "server.initialadminpassword";
private static final int GENERATED_PASSWORD_LENGTH = 20;

private Logger logger = LogManager.getLogger(getClass());

public ServerMigrator() {
Expand Down Expand Up @@ -250,27 +259,61 @@ private void initDatabase(Connection connection) throws MigrationException {
if (!DatabaseUtil.tableExists(connection, "CONFIGURATION")) {
executeScript("/" + getDatabaseType() + "/" + getDatabaseType() + "-database.sql");

/*
* We must update the password date for the initial user. Previously we let the database
* set this via CURRENT_TIMESTAMP, however this could create problems if the database is
* running on a separate machine in a different timezone. (MIRTH-2902)
*/
PreparedStatement statement = null;

try {
statement = getConnection().prepareStatement("UPDATE PERSON_PASSWORD SET PASSWORD_DATE = ?");
statement.setTimestamp(1, new Timestamp(System.currentTimeMillis()));
statement.executeUpdate();
} catch (SQLException e) {
throw new MigrationException(e);
} finally {
DbUtils.closeQuietly(statement);
}
initializeAdminPassword();

updateVersion(Version.getLatest());
}
}

/**
* Sets the password for the initial administrator account. The password is taken from the
* server.initialadminpassword property if it is set, otherwise a random password is generated
* and logged once so that it can be used to log in for the first time.
*
* The password date is set here rather than letting the database default it via
* CURRENT_TIMESTAMP, since that could create problems if the database is running on a separate
* machine in a different timezone. (MIRTH-2902)
*/
private void initializeAdminPassword() throws MigrationException {
ConfigurationController configurationController = ControllerFactory.getFactory().createConfigurationController();
PropertiesConfiguration mirthProperties = PropertiesConfigurationUtil.create();
configurationController.updatePropertiesConfiguration(mirthProperties);
// Log through the central Mirth.class logger to hit log4j filter configs
Logger startupLogger = LogManager.getLogger(Mirth.class);

String password = mirthProperties.getString(INITIAL_ADMIN_PASSWORD_PROPERTY);
if (StringUtils.isBlank(password)) {
// Prefix ensures the password meets complexity requirements
password = "Aa1!" + RandomStringUtils.secure().nextAlphanumeric(GENERATED_PASSWORD_LENGTH);

startupLogger.warn(System.lineSeparator() +
"********************************************************************************" + System.lineSeparator() +
"************ Initial {} password is {} ************" + System.lineSeparator() +
"********************************************************************************",
INITIAL_ADMIN_USERNAME, password);
}

PreparedStatement statement = null;
try {
Comment thread
mgaffigan marked this conversation as resolved.
String digestedPassword = configurationController.getDigester().digest(password);

statement = getConnection().prepareStatement(
"INSERT INTO PERSON_PASSWORD (PERSON_ID, PASSWORD, PASSWORD_DATE) "
+ "SELECT ID, ?, ? FROM PERSON WHERE USERNAME = ?");
statement.setString(1, digestedPassword);
statement.setTimestamp(2, new Timestamp(System.currentTimeMillis()));
statement.setString(3, INITIAL_ADMIN_USERNAME);

if (statement.executeUpdate() != 1) {
throw new MigrationException("Could not set the initial password for the \"" + INITIAL_ADMIN_USERNAME + "\" user.");
}
} catch (SQLException e) {
throw new MigrationException(e);
} finally {
DbUtils.closeQuietly(statement);
}
}

/**
* In case multiple servers startup and initialize the database at the same time, this inserts a
* row into a custom table as a simple lock mechanism.
Expand Down
Loading