diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2020-11-27 09:16:06 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2020-12-02 20:06:57 +0000 |
commit | 2c21bdec38460b793305079d65247cb548dd440a (patch) | |
tree | bdb6fe8c854b8165fffbc52023d8fafa9cef6a03 /server/sonar-webserver-core | |
parent | 89d9f0efa05022bb7577ff0d2014accc580da0a6 (diff) | |
download | sonarqube-2c21bdec38460b793305079d65247cb548dd440a.tar.gz sonarqube-2c21bdec38460b793305079d65247cb548dd440a.zip |
SONAR-14175 SONAR-14176 Detect usage of admin account with default credential
SONAR-14175 Add a startup task to detect admin default credential usage and set reset_password flag to true
SONAR-14176 Warn administrators when default admin credential is detected
Diffstat (limited to 'server/sonar-webserver-core')
2 files changed, 178 insertions, 0 deletions
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/startup/DetectActiveAdminAccountWithDefaultCredential.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/startup/DetectActiveAdminAccountWithDefaultCredential.java new file mode 100644 index 00000000000..09249a02a36 --- /dev/null +++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/startup/DetectActiveAdminAccountWithDefaultCredential.java @@ -0,0 +1,76 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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 3 of the License, or (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.startup; + +import org.picocontainer.Startable; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.user.UserDto; +import org.sonar.server.authentication.CredentialsLocalAuthentication; +import org.sonar.server.authentication.event.AuthenticationEvent; +import org.sonar.server.authentication.event.AuthenticationException; + +/** + * Detect usage of an active admin account with default credential in order to ask this account to reset its password during authentication. + */ +public class DetectActiveAdminAccountWithDefaultCredential implements Startable { + + private static final Logger LOGGER = Loggers.get(DetectActiveAdminAccountWithDefaultCredential.class); + + private final DbClient dbClient; + private final CredentialsLocalAuthentication localAuthentication; + + public DetectActiveAdminAccountWithDefaultCredential(DbClient dbClient, CredentialsLocalAuthentication localAuthentication) { + this.dbClient = dbClient; + this.localAuthentication = localAuthentication; + } + + @Override + public void start() { + try (DbSession dbSession = dbClient.openSession(false)) { + UserDto admin = dbClient.userDao().selectActiveUserByLogin(dbSession, "admin"); + if (admin == null || !isDefaultCredentialUser(dbSession, admin)) { + return; + } + LOGGER.warn("*******************************************************************************************************************"); + LOGGER.warn("Default Administrator credentials are still being used. Make sure to change the password or deactivate the account."); + LOGGER.warn("*******************************************************************************************************************"); + dbClient.userDao().update(dbSession, admin.setResetPassword(true)); + dbSession.commit(); + } + } + + private boolean isDefaultCredentialUser(DbSession dbSession, UserDto user) { + try { + localAuthentication.authenticate(dbSession, user, "admin", AuthenticationEvent.Method.BASIC); + return true; + } catch (AuthenticationException ex) { + return false; + } + } + + @Override + public void stop() { + // Nothing to do + } +} diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/startup/DetectActiveAdminAccountWithDefaultCredentialTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/startup/DetectActiveAdminAccountWithDefaultCredentialTest.java new file mode 100644 index 00000000000..5fee1484965 --- /dev/null +++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/startup/DetectActiveAdminAccountWithDefaultCredentialTest.java @@ -0,0 +1,102 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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 3 of the License, or (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.startup; + +import org.junit.After; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.utils.System2; +import org.sonar.api.utils.log.LogTester; +import org.sonar.api.utils.log.LoggerLevel; +import org.sonar.db.DbTester; +import org.sonar.db.user.UserDto; +import org.sonar.server.authentication.CredentialsLocalAuthentication; + +import static org.assertj.core.api.Assertions.assertThat; + +public class DetectActiveAdminAccountWithDefaultCredentialTest { + + private static final String ADMIN_LOGIN = "admin"; + + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + @Rule + public LogTester logTester = new LogTester(); + + private final CredentialsLocalAuthentication localAuthentication = new CredentialsLocalAuthentication(db.getDbClient()); + + private final DetectActiveAdminAccountWithDefaultCredential underTest = new DetectActiveAdminAccountWithDefaultCredential(db.getDbClient(), localAuthentication); + + @After + public void after() { + underTest.stop(); + } + + @Test + public void set_reset_flag_to_true_and_add_log_when_admin_account_with_default_credential_is_detected() { + UserDto admin = db.users().insertUser(u -> u.setLogin(ADMIN_LOGIN)); + changePassword(admin, "admin"); + + underTest.start(); + + assertThat(db.users().selectUserByLogin(admin.getLogin()).get().isResetPassword()).isTrue(); + assertThat(logTester.logs(LoggerLevel.WARN)).contains("Default Administrator credentials are still being used. Make sure to change the password or deactivate the account."); + } + + @Test + public void do_nothing_when_admin_is_not_using_default_credential() { + UserDto admin = db.users().insertUser(u -> u.setLogin(ADMIN_LOGIN)); + changePassword(admin, "something_else"); + + underTest.start(); + + assertThat(db.users().selectUserByLogin(admin.getLogin()).get().isResetPassword()).isFalse(); + assertThat(logTester.logs()).isEmpty(); + } + + @Test + public void do_nothing_when_no_admin_account_with_default_credential_detected() { + UserDto otherUser = db.users().insertUser(); + changePassword(otherUser, "admin"); + + underTest.start(); + + assertThat(db.users().selectUserByLogin(otherUser.getLogin()).get().isResetPassword()).isFalse(); + assertThat(logTester.logs()).isEmpty(); + } + + @Test + public void do_nothing_when_admin_account_with_default_credential_is_disabled() { + UserDto admin = db.users().insertUser(u -> u.setLogin(ADMIN_LOGIN).setActive(false)); + changePassword(admin, "admin"); + + underTest.start(); + + assertThat(db.users().selectUserByLogin(admin.getLogin()).get().isResetPassword()).isFalse(); + assertThat(logTester.logs()).isEmpty(); + } + + private void changePassword(UserDto user, String password) { + localAuthentication.storeHashPassword(user, password); + db.getDbClient().userDao().update(db.getSession(), user); + db.commit(); + } +} |