From f7adccdc63aa7b93ed20425a3224da0c5e6a5bba Mon Sep 17 00:00:00 2001 From: Eric Hartmann Date: Thu, 12 Apr 2018 18:30:05 +0200 Subject: [PATCH] SONAR-6949 Populate HASH_METHOD with SHA1 --- .../org/sonar/db/version/schema-h2.ddl | 1 + .../main/java/org/sonar/db/user/UserDto.java | 11 ++ .../org/sonar/db/user/UserMapper.xml | 3 + .../v72/AddHashMethodToUsersTable.java | 45 ++++++++ .../db/migration/version/v72/DbVersion72.java | 2 + .../v72/PopulateHashMethodOnUsers.java | 44 ++++++++ .../v72/AddHashMethodToUsersTableTest.java | 54 +++++++++ .../version/v72/DbVersion72Test.java | 2 +- .../v72/PopulateHashMethodOnUsersTest.java | 103 ++++++++++++++++++ .../AddHashMethodToUsersTableTest/users.sql | 21 ++++ .../PopulateHashMethodOnUsersTest/users.sql | 22 ++++ 11 files changed, 307 insertions(+), 1 deletion(-) create mode 100644 server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/AddHashMethodToUsersTable.java create mode 100644 server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/PopulateHashMethodOnUsers.java create mode 100644 server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/AddHashMethodToUsersTableTest.java create mode 100644 server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/PopulateHashMethodOnUsersTest.java create mode 100644 server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v72/AddHashMethodToUsersTableTest/users.sql create mode 100644 server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v72/PopulateHashMethodOnUsersTest/users.sql diff --git a/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl b/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl index 52eb5bea34e6..d15982719de2 100644 --- a/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl +++ b/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl @@ -463,6 +463,7 @@ CREATE TABLE "USERS" ( "EMAIL" VARCHAR(100), "CRYPTED_PASSWORD" VARCHAR(100), "SALT" VARCHAR(40), + "HASH_METHOD" VARCHAR(10), "ACTIVE" BOOLEAN DEFAULT TRUE, "SCM_ACCOUNTS" VARCHAR(4000), "EXTERNAL_IDENTITY" VARCHAR(255), diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDto.java index 7cf9be40d892..1baa5f728924 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDto.java @@ -46,6 +46,7 @@ public class UserDto { private String externalIdentityProvider; private String cryptedPassword; private String salt; + private String hashMethod; private Long createdAt; private Long updatedAt; private String homepageType; @@ -186,6 +187,16 @@ public UserDto setSalt(@Nullable String salt) { return this; } + @CheckForNull + public String getHashMethod() { + return hashMethod; + } + + public UserDto setHashMethod(String hashMethod) { + this.hashMethod = hashMethod; + return this; + } + public Long getCreatedAt() { return createdAt; } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/user/UserMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/user/UserMapper.xml index 9b6f5c9f5eeb..d699cf7ba2aa 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/user/UserMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/user/UserMapper.xml @@ -12,6 +12,7 @@ u.scm_accounts as "scmAccounts", u.salt as "salt", u.crypted_password as "cryptedPassword", + u.hash_method as "hashMethod", u.external_identity as "externalIdentity", u.external_identity_provider as "externalIdentityProvider", u.user_local as "local", @@ -180,6 +181,7 @@ user_local, salt, crypted_password, + hash_method, is_root, onboarded, created_at, @@ -197,6 +199,7 @@ #{user.local,jdbcType=BOOLEAN}, #{user.salt,jdbcType=VARCHAR}, #{user.cryptedPassword,jdbcType=VARCHAR}, + #{user.hashMethod,jdbcType=VARCHAR}, #{user.root,jdbcType=BOOLEAN}, #{user.onboarded,jdbcType=BOOLEAN}, #{now,jdbcType=BIGINT}, diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/AddHashMethodToUsersTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/AddHashMethodToUsersTable.java new file mode 100644 index 000000000000..5556d6c0ff89 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/AddHashMethodToUsersTable.java @@ -0,0 +1,45 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.platform.db.migration.version.v72; + +import java.sql.SQLException; +import org.sonar.db.Database; +import org.sonar.server.platform.db.migration.def.VarcharColumnDef; +import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder; +import org.sonar.server.platform.db.migration.step.DdlChange; + +public class AddHashMethodToUsersTable extends DdlChange { + + public AddHashMethodToUsersTable(Database db) { + super(db); + } + + @Override + public void execute(Context context) throws SQLException { + context.execute(new AddColumnsBuilder(getDialect(), "users") + .addColumn(VarcharColumnDef.newVarcharColumnDefBuilder() + .setColumnName("hash_method") + .setIsNullable(true) + .setLimit(10) + .build()) + .build()); + } + +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72.java index 6d42c8fb30d6..35c942769361 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72.java @@ -28,6 +28,8 @@ public class DbVersion72 implements DbVersion { public void addSteps(MigrationStepRegistry registry) { registry .add(2100, "Increase size of CRYPTED_PASSWORD", IncreaseCryptedPasswordSize.class) + .add(2101, "Add HASH_METHOD to table users", AddHashMethodToUsersTable.class) + .add(2102, "Populate HASH_METHOD on table users", PopulateHashMethodOnUsers.class) ; } } diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/PopulateHashMethodOnUsers.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/PopulateHashMethodOnUsers.java new file mode 100644 index 000000000000..55a50773bde8 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v72/PopulateHashMethodOnUsers.java @@ -0,0 +1,44 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.platform.db.migration.version.v72; + +import java.sql.SQLException; +import org.sonar.api.utils.System2; +import org.sonar.db.Database; +import org.sonar.server.platform.db.migration.step.DataChange; + +public class PopulateHashMethodOnUsers extends DataChange { + + private final System2 system2; + + public PopulateHashMethodOnUsers(Database db, System2 system2) { + super(db); + this.system2 = system2; + } + + @Override + public void execute(Context context) throws SQLException { + context.prepareUpsert("UPDATE users SET hash_method=?, updated_at=? WHERE crypted_password IS NOT NULL") + .setString(1, "SHA1") + .setLong(2, system2.now()) + .execute() + .commit(); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/AddHashMethodToUsersTableTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/AddHashMethodToUsersTableTest.java new file mode 100644 index 000000000000..fe2e747c5c1f --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/AddHashMethodToUsersTableTest.java @@ -0,0 +1,54 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.platform.db.migration.version.v72; + +import java.sql.SQLException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.db.CoreDbTester; + +import static java.sql.Types.VARCHAR; + +public class AddHashMethodToUsersTableTest { + @Rule + public final CoreDbTester dbTester = CoreDbTester.createForSchema(AddHashMethodToUsersTableTest.class, "users.sql"); + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private AddHashMethodToUsersTable underTest = new AddHashMethodToUsersTable(dbTester.database()); + + @Test + public void column_is_added_to_table() throws SQLException { + underTest.execute(); + + dbTester.assertColumnDefinition("users", "hash_method", VARCHAR, 10, true); + } + + @Test + public void migration_is_not_reentrant() throws SQLException { + underTest.execute(); + + expectedException.expect(IllegalStateException.class); + + underTest.execute(); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72Test.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72Test.java index 9b870fe49124..9af6646d5a1f 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72Test.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/DbVersion72Test.java @@ -34,7 +34,7 @@ public void migrationNumber_starts_at_2100() { @Test public void verify_migration_count() { - verifyMigrationCount(underTest, 1); + verifyMigrationCount(underTest, 3); } } diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/PopulateHashMethodOnUsersTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/PopulateHashMethodOnUsersTest.java new file mode 100644 index 000000000000..254e9da4f079 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/PopulateHashMethodOnUsersTest.java @@ -0,0 +1,103 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.platform.db.migration.version.v72; + +import java.sql.SQLException; +import java.util.stream.IntStream; +import javax.annotation.Nullable; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.System2; +import org.sonar.api.utils.internal.TestSystem2; +import org.sonar.db.CoreDbTester; + +import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; +import static org.assertj.core.api.Assertions.assertThat; + +public class PopulateHashMethodOnUsersTest { + + private static final long PAST = 5_000_000_000L; + private static final long NOW = 10_000_000_000L; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Rule + public CoreDbTester db = CoreDbTester.createForSchema(PopulateHashMethodOnUsersTest.class, "users.sql"); + + private System2 system2 = new TestSystem2().setNow(NOW); + + private PopulateHashMethodOnUsers underTest = new PopulateHashMethodOnUsers(db.database(), system2); + + @Test + public void should_update_only_local_users() throws SQLException { + IntStream.range(0, 99).forEach(i -> insertLocalUser(null)); + IntStream.range(0, 100).forEach(i -> insertExternalUser()); + + underTest.execute(); + + assertThat(db.countSql("select count(id) from users where hash_method='SHA1'")).isEqualTo(99); + assertThat(db.countSql("select count(id) from users where hash_method is not null and crypted_password is null")).isEqualTo(0); + } + + @Test + public void should_add_sha1_in_hash_method() throws SQLException { + IntStream.range(0, 99).forEach(i -> insertLocalUser(null)); + + underTest.execute(); + + assertThat(db.countSql("select count(id) from users where hash_method <> 'SHA1'")).isEqualTo(0); + } + + @Test + public void is_reentrant() throws SQLException { + IntStream.range(0, 99).forEach(i -> insertLocalUser(null)); + IntStream.range(0, 100).forEach(i -> insertExternalUser()); + + underTest.execute(); + underTest.execute(); + + assertThat(db.countSql("select count(id) from users where hash_method='SHA1'")).isEqualTo(99); + assertThat(db.countSql("select count(id) from users where hash_method is not null and crypted_password is null")).isEqualTo(0); + } + + private void insertExternalUser() { + insertUser(randomAlphanumeric(10), null, null, null, randomAlphanumeric(20), randomAlphanumeric(20)); + } + + private void insertLocalUser(@Nullable String hashMethod) { + insertUser(randomAlphanumeric(10), randomAlphanumeric(10), randomAlphanumeric(10), hashMethod, null, null); + } + + private void insertUser(String login, String cryptedPassword, String salt, String hashMethod, + @Nullable String externalIdentity, @Nullable String externalIdentityProvider) { + db.executeInsert("USERS", + "LOGIN", login, + "CRYPTED_PASSWORD", cryptedPassword, + "SALT", salt, + "HASH_METHOD", salt, + "EXTERNAL_IDENTITY", externalIdentity, + "EXTERNAL_IDENTITY_PROVIDER", externalIdentityProvider, + "IS_ROOT", false, + "ONBOARDED", false); + } +} diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v72/AddHashMethodToUsersTableTest/users.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v72/AddHashMethodToUsersTableTest/users.sql new file mode 100644 index 000000000000..c5103149b55b --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v72/AddHashMethodToUsersTableTest/users.sql @@ -0,0 +1,21 @@ +CREATE TABLE "USERS" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "LOGIN" VARCHAR(255), + "NAME" VARCHAR(200), + "EMAIL" VARCHAR(100), + "CRYPTED_PASSWORD" VARCHAR(100), + "SALT" VARCHAR(40), + "ACTIVE" BOOLEAN DEFAULT TRUE, + "SCM_ACCOUNTS" VARCHAR(4000), + "EXTERNAL_IDENTITY" VARCHAR(255), + "EXTERNAL_IDENTITY_PROVIDER" VARCHAR(100), + "IS_ROOT" BOOLEAN NOT NULL, + "USER_LOCAL" BOOLEAN, + "ONBOARDED" BOOLEAN NOT NULL, + "CREATED_AT" BIGINT, + "UPDATED_AT" BIGINT, + "HOMEPAGE_TYPE" VARCHAR(40), + "HOMEPAGE_PARAMETER" VARCHAR(40) +); +CREATE UNIQUE INDEX "USERS_LOGIN" ON "USERS" ("LOGIN"); +CREATE INDEX "USERS_UPDATED_AT" ON "USERS" ("UPDATED_AT"); diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v72/PopulateHashMethodOnUsersTest/users.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v72/PopulateHashMethodOnUsersTest/users.sql new file mode 100644 index 000000000000..7788824d1bcc --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v72/PopulateHashMethodOnUsersTest/users.sql @@ -0,0 +1,22 @@ +CREATE TABLE "USERS" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "LOGIN" VARCHAR(255), + "NAME" VARCHAR(200), + "EMAIL" VARCHAR(100), + "CRYPTED_PASSWORD" VARCHAR(100), + "SALT" VARCHAR(40), + "HASH_METHOD" VARCHAR(10), + "ACTIVE" BOOLEAN DEFAULT TRUE, + "SCM_ACCOUNTS" VARCHAR(4000), + "EXTERNAL_IDENTITY" VARCHAR(255), + "EXTERNAL_IDENTITY_PROVIDER" VARCHAR(100), + "IS_ROOT" BOOLEAN NOT NULL, + "USER_LOCAL" BOOLEAN, + "ONBOARDED" BOOLEAN NOT NULL, + "CREATED_AT" BIGINT, + "UPDATED_AT" BIGINT, + "HOMEPAGE_TYPE" VARCHAR(40), + "HOMEPAGE_PARAMETER" VARCHAR(40) +); +CREATE UNIQUE INDEX "USERS_LOGIN" ON "USERS" ("LOGIN"); +CREATE INDEX "USERS_UPDATED_AT" ON "USERS" ("UPDATED_AT");