@@ -1,4 +1,4 @@ | |||
INSERT INTO USERS(ID, UUID, LOGIN, NAME, EMAIL, EXTERNAL_IDENTITY, EXTERNAL_IDENTITY_PROVIDER, USER_LOCAL, CRYPTED_PASSWORD, SALT, HASH_METHOD, IS_ROOT, ONBOARDED, CREATED_AT, UPDATED_AT) VALUES (1, 'UuidnciQUUs7Zd3KPvFD', 'admin', 'Administrator', '', 'admin', 'sonarqube', true, '$2a$12$uCkkXmhW5ThVK8mpBvnXOOJRLd64LJeHTeCkSuB3lfaR2N0AYBaSi', null, 'BCRYPT', false, false, '1418215735482', '1418215735482'); | |||
INSERT INTO USERS(ID, UUID, LOGIN, NAME, EMAIL, EXTERNAL_ID, EXTERNAL_LOGIN, EXTERNAL_IDENTITY_PROVIDER, USER_LOCAL, CRYPTED_PASSWORD, SALT, HASH_METHOD, IS_ROOT, ONBOARDED, CREATED_AT, UPDATED_AT) VALUES (1, 'UuidnciQUUs7Zd3KPvFD', 'admin', 'Administrator', '', 'admin', 'admin', 'sonarqube', true, '$2a$12$uCkkXmhW5ThVK8mpBvnXOOJRLd64LJeHTeCkSuB3lfaR2N0AYBaSi', null, 'BCRYPT', false, false, '1418215735482', '1418215735482'); | |||
ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2; | |||
INSERT INTO GROUPS(ID, ORGANIZATION_UUID, NAME, DESCRIPTION, CREATED_AT, UPDATED_AT) VALUES (1, 'AVdqnciQUUs7Zd3KPvFD', 'sonar-administrators', 'System administrators', '2011-09-26 22:27:51.0', '2011-09-26 22:27:51.0'); |
@@ -454,8 +454,8 @@ CREATE INDEX "IX_ARP_ON_ACTIVE_RULE_ID" ON "ACTIVE_RULE_PARAMETERS" ("ACTIVE_RUL | |||
CREATE TABLE "USERS" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"UUID" VARCHAR(40), | |||
"LOGIN" VARCHAR(255), | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"LOGIN" VARCHAR(255) NOT NULL, | |||
"NAME" VARCHAR(200), | |||
"EMAIL" VARCHAR(100), | |||
"CRYPTED_PASSWORD" VARCHAR(100), | |||
@@ -463,8 +463,9 @@ CREATE TABLE "USERS" ( | |||
"HASH_METHOD" VARCHAR(10), | |||
"ACTIVE" BOOLEAN DEFAULT TRUE, | |||
"SCM_ACCOUNTS" VARCHAR(4000), | |||
"EXTERNAL_IDENTITY" VARCHAR(255), | |||
"EXTERNAL_IDENTITY_PROVIDER" VARCHAR(100), | |||
"EXTERNAL_ID" VARCHAR(255) NOT NULL, | |||
"EXTERNAL_LOGIN" VARCHAR(255) NOT NULL, | |||
"EXTERNAL_IDENTITY_PROVIDER" VARCHAR(100) NOT NULL, | |||
"IS_ROOT" BOOLEAN NOT NULL, | |||
"USER_LOCAL" BOOLEAN, | |||
"ONBOARDED" BOOLEAN NOT NULL, | |||
@@ -473,7 +474,9 @@ CREATE TABLE "USERS" ( | |||
"HOMEPAGE_TYPE" VARCHAR(40), | |||
"HOMEPAGE_PARAMETER" VARCHAR(40) | |||
); | |||
CREATE UNIQUE INDEX "USERS_UUID" ON "USERS" ("UUID"); | |||
CREATE UNIQUE INDEX "USERS_LOGIN" ON "USERS" ("LOGIN"); | |||
CREATE UNIQUE INDEX "UNIQ_EXTERNAL_ID" ON "USERS" ("EXTERNAL_IDENTITY_PROVIDER", "EXTERNAL_ID"); | |||
CREATE INDEX "USERS_UPDATED_AT" ON "USERS" ("UPDATED_AT"); | |||
@@ -38,8 +38,8 @@ public class OrganizationMemberDao implements Dao { | |||
return Optional.ofNullable(mapper(dbSession).select(organizationUuid, userId)); | |||
} | |||
public List<String> selectLoginsByOrganizationUuid(DbSession dbSession, String organizationUuid) { | |||
return mapper(dbSession).selectLogins(organizationUuid); | |||
public List<String> selectUserUuidsByOrganizationUuid(DbSession dbSession, String organizationUuid) { | |||
return mapper(dbSession).selectUserUuids(organizationUuid); | |||
} | |||
public List<Integer> selectUserIdsByOrganizationUuid(DbSession dbSession, String organizationUuid) { | |||
@@ -67,20 +67,19 @@ public class OrganizationMemberDao implements Dao { | |||
} | |||
/** | |||
* | |||
* @param loginOrganizationConsumer {@link BiConsumer}<String,String> (login, organization uuid) | |||
* @param userUuidOrganizationConsumer {@link BiConsumer}<String,String> (uuid, organization uuid) | |||
*/ | |||
public void selectForUserIndexing(DbSession dbSession, Collection<String> logins, BiConsumer<String, String> loginOrganizationConsumer) { | |||
executeLargeInputsWithoutOutput(logins, list -> mapper(dbSession).selectForIndexing(list) | |||
.forEach(row -> loginOrganizationConsumer.accept(row.get("login"), row.get("organizationUuid")))); | |||
public void selectForUserIndexing(DbSession dbSession, Collection<String> uuids, BiConsumer<String, String> userUuidOrganizationConsumer) { | |||
executeLargeInputsWithoutOutput(uuids, list -> mapper(dbSession).selectForIndexing(list) | |||
.forEach(row -> userUuidOrganizationConsumer.accept(row.get("uuid"), row.get("organizationUuid")))); | |||
} | |||
/** | |||
* | |||
* @param loginOrganizationConsumer {@link BiConsumer}<String,String> (login, organization uuid) | |||
* @param userUuidOrganizationConsumer {@link BiConsumer}<String,String> (uuid, organization uuid) | |||
*/ | |||
public void selectAllForUserIndexing(DbSession dbSession, BiConsumer<String, String> loginOrganizationConsumer) { | |||
public void selectAllForUserIndexing(DbSession dbSession, BiConsumer<String, String> userUuidOrganizationConsumer) { | |||
mapper(dbSession).selectAllForIndexing() | |||
.forEach(row -> loginOrganizationConsumer.accept(row.get("login"), row.get("organizationUuid"))); | |||
.forEach(row -> userUuidOrganizationConsumer.accept(row.get("uuid"), row.get("organizationUuid"))); | |||
} | |||
} |
@@ -29,11 +29,11 @@ public interface OrganizationMemberMapper { | |||
Set<String> selectOrganizationUuidsByUser(@Param("userId") int userId); | |||
List<String> selectLogins(String organizationUuid); | |||
List<String> selectUserUuids(String organizationUuid); | |||
List<Integer> selectUserIds(String organizationUuid); | |||
List<Map<String, String>> selectForIndexing(@Param("logins") List<String> logins); | |||
List<Map<String, String>> selectForIndexing(@Param("uuids") List<String> uuids); | |||
List<Map<String, String>> selectAllForIndexing(); | |||
@@ -161,6 +161,10 @@ public class PropertiesDao implements Dao { | |||
return executeLargeInputs(componentIds, getMapper(session)::selectByComponentIds); | |||
} | |||
public List<PropertyDto> selectByKeyAndMatchingValue(DbSession session, String key, String value) { | |||
return getMapper(session).selectByKeyAndMatchingValue(key, value); | |||
} | |||
/** | |||
* Saves the specified property and its value. | |||
* <p> |
@@ -42,6 +42,8 @@ public interface PropertiesMapper { | |||
List<PropertyDto> selectByQuery(@Param("query") PropertyQuery query); | |||
List<PropertyDto> selectByKeyAndMatchingValue(@Param("key") String key, @Param("value") String value); | |||
List<PropertyDto> selectDescendantModuleProperties(@Param("moduleUuid") String moduleUuid, @Param(value = "scope") String scope, | |||
@Param(value = "excludeDisabled") boolean excludeDisabled); | |||
@@ -58,6 +58,11 @@ public class UserDao implements Dao { | |||
return mapper(session).selectUser(userId); | |||
} | |||
@CheckForNull | |||
public UserDto selectByUuid(DbSession session, String uuid) { | |||
return mapper(session).selectByUuid(uuid); | |||
} | |||
/** | |||
* Select users by ids, including disabled users. An empty list is returned | |||
* if list of ids is empty, without any db round trips. | |||
@@ -82,6 +87,14 @@ public class UserDao implements Dao { | |||
return executeLargeInputs(logins, mapper(session)::selectByLogins); | |||
} | |||
/** | |||
* Select users by uuids, including disabled users. An empty list is returned | |||
* if list of uuids is empty, without any db round trips. | |||
*/ | |||
public List<UserDto> selectByUuids(DbSession session, Collection<String> uuids) { | |||
return executeLargeInputs(uuids, mapper(session)::selectByUuids); | |||
} | |||
/** | |||
* Gets a list users by their logins. The result does NOT contain {@code null} values for users not found, so | |||
* the size of result may be less than the number of keys. | |||
@@ -165,12 +178,17 @@ public class UserDao implements Dao { | |||
return mapper(dbSession).selectByEmail(email.toLowerCase(Locale.ENGLISH)); | |||
} | |||
public void scrollByLogins(DbSession dbSession, Collection<String> logins, Consumer<UserDto> consumer) { | |||
@CheckForNull | |||
public UserDto selectByExternalIdAndIdentityProvider(DbSession dbSession, String externalId, String externalIdentityProvider) { | |||
return mapper(dbSession).selectByExternalIdAndIdentityProvider(externalId, externalIdentityProvider); | |||
} | |||
public void scrollByUuids(DbSession dbSession, Collection<String> uuids, Consumer<UserDto> consumer) { | |||
UserMapper mapper = mapper(dbSession); | |||
executeLargeInputsWithoutOutput(logins, | |||
pageOfLogins -> mapper | |||
.selectByLogins(pageOfLogins) | |||
executeLargeInputsWithoutOutput(uuids, | |||
pageOfUuids -> mapper | |||
.selectByUuids(pageOfUuids) | |||
.forEach(consumer)); | |||
} | |||
@@ -41,7 +41,8 @@ public class UserDto { | |||
private String email; | |||
private boolean active = true; | |||
private String scmAccounts; | |||
private String externalIdentity; | |||
private String externalId; | |||
private String externalLogin; | |||
private String externalIdentityProvider; | |||
// Hashed password that may be null in case of external authentication | |||
private String cryptedPassword; | |||
@@ -151,12 +152,21 @@ public class UserDto { | |||
} | |||
} | |||
public String getExternalIdentity() { | |||
return externalIdentity; | |||
public String getExternalId() { | |||
return externalId; | |||
} | |||
public UserDto setExternalIdentity(String authorithy) { | |||
this.externalIdentity = authorithy; | |||
public UserDto setExternalId(String externalId) { | |||
this.externalId = externalId; | |||
return this; | |||
} | |||
public String getExternalLogin() { | |||
return externalLogin; | |||
} | |||
public UserDto setExternalLogin(String externalLogin) { | |||
this.externalLogin = externalLogin; | |||
return this; | |||
} | |||
@@ -27,6 +27,9 @@ import org.sonar.api.user.UserQuery; | |||
public interface UserMapper { | |||
@CheckForNull | |||
UserDto selectByUuid(String uuid); | |||
@CheckForNull | |||
UserDto selectByLogin(String login); | |||
@@ -50,11 +53,16 @@ public interface UserMapper { | |||
List<UserDto> selectByLogins(List<String> logins); | |||
List<UserDto> selectByUuids(List<String> uuids); | |||
List<UserDto> selectByIds(@Param("ids") List<Integer> ids); | |||
@CheckForNull | |||
UserDto selectByEmail(String email); | |||
@CheckForNull | |||
UserDto selectByExternalIdAndIdentityProvider(@Param("externalId") String externalId, @Param("externalIdentityProvider") String externalExternalIdentityProvider); | |||
void scrollAll(ResultHandler<UserDto> handler); | |||
/** |
@@ -17,8 +17,8 @@ | |||
and om.user_id = #{userId, jdbcType=INTEGER} | |||
</select> | |||
<select id="selectLogins" resultType="string"> | |||
select u.login | |||
<select id="selectUserUuids" resultType="string"> | |||
select u.uuid | |||
from organization_members om | |||
inner join users u on om.user_id = u.id | |||
where om.organization_uuid=#{organizationUuid,jdbcType=VARCHAR} | |||
@@ -37,17 +37,17 @@ | |||
</select> | |||
<select id="selectForIndexing" resultType="hashmap"> | |||
select u.login as "login", om.organization_uuid as "organizationUuid" | |||
select u.uuid as "uuid", om.organization_uuid as "organizationUuid" | |||
from organization_members om | |||
inner join users u on om.user_id=u.id | |||
where u.login in | |||
<foreach collection="logins" open="(" close=")" item="login" separator=","> | |||
#{login, jdbcType=VARCHAR} | |||
where u.uuid in | |||
<foreach collection="uuids" open="(" close=")" item="uuid" separator=","> | |||
#{uuid, jdbcType=VARCHAR} | |||
</foreach> | |||
</select> | |||
<select id="selectAllForIndexing" resultType="hashmap"> | |||
select u.login as "login", om.organization_uuid as "organizationUuid" | |||
select u.uuid as "uuid", om.organization_uuid as "organizationUuid" | |||
from organization_members om | |||
inner join users u on om.user_id=u.id | |||
</select> |
@@ -179,6 +179,16 @@ | |||
and ps.organization_uuid=#{organizationUuid,jdbcType=VARCHAR} | |||
</select> | |||
<select id="selectByKeyAndMatchingValue" parameterType="map" resultType="ScrapProperty"> | |||
select | |||
<include refid="columnsToScrapPropertyDto"/> | |||
from properties p | |||
<where> | |||
p.prop_key = #{key,jdbcType=VARCHAR} | |||
and p.text_value like #{value,jdbcType=VARCHAR} | |||
</where> | |||
</select> | |||
<insert id="insertAsEmpty" parameterType="Map" useGeneratedKeys="false"> | |||
insert into properties | |||
( |
@@ -14,7 +14,8 @@ | |||
u.salt as "salt", | |||
u.crypted_password as "cryptedPassword", | |||
u.hash_method as "hashMethod", | |||
u.external_identity as "externalIdentity", | |||
u.external_id as "externalId", | |||
u.external_login as "externalLogin", | |||
u.external_identity_provider as "externalIdentityProvider", | |||
u.user_local as "local", | |||
u.is_root as "root", | |||
@@ -25,6 +26,13 @@ | |||
u.homepage_parameter as "homepageParameter" | |||
</sql> | |||
<select id="selectByUuid" parameterType="String" resultType="User"> | |||
SELECT | |||
<include refid="userColumns"/> | |||
FROM users u | |||
WHERE u.uuid=#{uuid} | |||
</select> | |||
<select id="selectByLogin" parameterType="String" resultType="User"> | |||
SELECT | |||
<include refid="userColumns"/> | |||
@@ -66,6 +74,16 @@ | |||
</foreach> | |||
</select> | |||
<select id="selectByUuids" parameterType="string" resultType="User"> | |||
SELECT | |||
<include refid="userColumns"/> | |||
FROM users u | |||
WHERE u.uuid in | |||
<foreach collection="list" open="(" close=")" item="uuid" separator=","> | |||
#{uuid} | |||
</foreach> | |||
</select> | |||
<select id="scrollAll" resultType="User" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY"> | |||
select | |||
<include refid="userColumns"/> | |||
@@ -117,6 +135,13 @@ | |||
AND u.active=${_true} | |||
</select> | |||
<select id="selectByExternalIdAndIdentityProvider" parameterType="map" resultType="User"> | |||
SELECT | |||
<include refid="userColumns"/> | |||
FROM users u | |||
WHERE u.external_id=#{externalId} AND u.external_identity_provider=#{externalIdentityProvider} | |||
</select> | |||
<select id="countRootUsersButLogin" parameterType="String" resultType="long"> | |||
select | |||
count(1) | |||
@@ -133,8 +158,6 @@ | |||
active = ${_false}, | |||
email = null, | |||
scm_accounts = null, | |||
external_identity = null, | |||
external_identity_provider = null, | |||
salt = null, | |||
crypted_password = null, | |||
updated_at = #{now, jdbcType=BIGINT} | |||
@@ -178,7 +201,8 @@ | |||
email, | |||
active, | |||
scm_accounts, | |||
external_identity, | |||
external_id, | |||
external_login, | |||
external_identity_provider, | |||
user_local, | |||
salt, | |||
@@ -197,7 +221,8 @@ | |||
#{user.email,jdbcType=VARCHAR}, | |||
#{user.active,jdbcType=BOOLEAN}, | |||
#{user.scmAccounts,jdbcType=VARCHAR}, | |||
#{user.externalIdentity,jdbcType=VARCHAR}, | |||
#{user.externalId,jdbcType=VARCHAR}, | |||
#{user.externalLogin,jdbcType=VARCHAR}, | |||
#{user.externalIdentityProvider,jdbcType=VARCHAR}, | |||
#{user.local,jdbcType=BOOLEAN}, | |||
#{user.salt,jdbcType=VARCHAR}, | |||
@@ -214,11 +239,13 @@ | |||
<update id="update" parameterType="map"> | |||
update users set | |||
login = #{user.login, jdbcType=VARCHAR}, | |||
name = #{user.name, jdbcType=VARCHAR}, | |||
email = #{user.email, jdbcType=VARCHAR}, | |||
active = #{user.active, jdbcType=BOOLEAN}, | |||
scm_accounts = #{user.scmAccounts, jdbcType=VARCHAR}, | |||
external_identity = #{user.externalIdentity, jdbcType=VARCHAR}, | |||
external_id = #{user.externalId, jdbcType=VARCHAR}, | |||
external_login = #{user.externalLogin, jdbcType=VARCHAR}, | |||
external_identity_provider = #{user.externalIdentityProvider, jdbcType=VARCHAR}, | |||
user_local = #{user.local, jdbcType=BOOLEAN}, | |||
onboarded = #{user.onboarded, jdbcType=BOOLEAN}, | |||
@@ -229,7 +256,7 @@ | |||
homepage_type = #{user.homepageType, jdbcType=VARCHAR}, | |||
homepage_parameter = #{user.homepageParameter, jdbcType=VARCHAR} | |||
where | |||
login = #{user.login, jdbcType=VARCHAR} | |||
uuid = #{user.uuid, jdbcType=VARCHAR} | |||
</update> | |||
</mapper> |
@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.db.organization; | |||
import java.util.Arrays; | |||
import java.util.function.Consumer; | |||
import javax.annotation.Nullable; | |||
import org.sonar.db.DbSession; | |||
@@ -87,9 +88,8 @@ public class OrganizationDbTester { | |||
dbSession.commit(); | |||
} | |||
public void addMember(OrganizationDto organization, UserDto user) { | |||
checkArgument(user.getId() != null, "User must be saved in database"); | |||
dbTester.getDbClient().organizationMemberDao().insert(dbTester.getSession(), new OrganizationMemberDto().setOrganizationUuid(organization.getUuid()).setUserId(user.getId())); | |||
public void addMember(OrganizationDto organization, UserDto... users) { | |||
Arrays.stream(users).forEach(u -> dbTester.getDbClient().organizationMemberDao().insert(dbTester.getSession(), new OrganizationMemberDto().setOrganizationUuid(organization.getUuid()).setUserId(u.getId()))); | |||
dbTester.commit(); | |||
} | |||
@@ -20,7 +20,6 @@ | |||
package org.sonar.db.organization; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
@@ -34,6 +33,7 @@ import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.user.UserDto; | |||
import static java.util.Arrays.asList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.entry; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
@@ -62,7 +62,7 @@ public class OrganizationMemberDaoTest { | |||
} | |||
@Test | |||
public void select_logins() { | |||
public void select_user_uuids_by_organization_uuid() { | |||
OrganizationDto organization = db.organizations().insert(); | |||
OrganizationDto anotherOrganization = db.organizations().insert(); | |||
UserDto user = db.users().insertUser(); | |||
@@ -72,9 +72,9 @@ public class OrganizationMemberDaoTest { | |||
db.organizations().addMember(organization, anotherUser); | |||
db.organizations().addMember(anotherOrganization, userInAnotherOrganization); | |||
List<String> result = underTest.selectLoginsByOrganizationUuid(dbSession, organization.getUuid()); | |||
List<String> result = underTest.selectUserUuidsByOrganizationUuid(dbSession, organization.getUuid()); | |||
assertThat(result).containsOnly(user.getLogin(), anotherUser.getLogin()); | |||
assertThat(result).containsOnly(user.getUuid(), anotherUser.getUuid()); | |||
} | |||
@Test | |||
@@ -110,24 +110,24 @@ public class OrganizationMemberDaoTest { | |||
public void select_for_indexing() { | |||
OrganizationDto org1 = db.organizations().insert(o -> o.setUuid("ORG_1")); | |||
OrganizationDto org2 = db.organizations().insert(o -> o.setUuid("ORG_2")); | |||
UserDto user1 = db.users().insertUser("L_1"); | |||
UserDto user2 = db.users().insertUser("L_2"); | |||
UserDto user1 = db.users().insertUser(); | |||
UserDto user2 = db.users().insertUser(); | |||
db.organizations().addMember(org1, user1); | |||
db.organizations().addMember(org1, user2); | |||
db.organizations().addMember(org2, user1); | |||
List<Tuple> result = new ArrayList<>(); | |||
underTest.selectForUserIndexing(dbSession, Arrays.asList("L_1", "L_2"), (login, org) -> result.add(tuple(login, org))); | |||
underTest.selectForUserIndexing(dbSession, asList(user1.getUuid(), user2.getUuid()), (login, org) -> result.add(tuple(login, org))); | |||
assertThat(result).containsOnly(tuple("L_1", "ORG_1"), tuple("L_1", "ORG_2"), tuple("L_2", "ORG_1")); | |||
assertThat(result).containsOnly(tuple(user1.getUuid(), "ORG_1"), tuple(user1.getUuid(), "ORG_2"), tuple(user2.getUuid(), "ORG_1")); | |||
} | |||
@Test | |||
public void select_all_for_indexing() { | |||
OrganizationDto org1 = db.organizations().insert(o -> o.setUuid("ORG_1")); | |||
OrganizationDto org2 = db.organizations().insert(o -> o.setUuid("ORG_2")); | |||
UserDto user1 = db.users().insertUser("L_1"); | |||
UserDto user2 = db.users().insertUser("L_2"); | |||
UserDto user1 = db.users().insertUser(); | |||
UserDto user2 = db.users().insertUser(); | |||
db.organizations().addMember(org1, user1); | |||
db.organizations().addMember(org1, user2); | |||
db.organizations().addMember(org2, user1); | |||
@@ -135,7 +135,7 @@ public class OrganizationMemberDaoTest { | |||
underTest.selectAllForUserIndexing(dbSession, (login, org) -> result.add(tuple(login, org))); | |||
assertThat(result).containsOnly(tuple("L_1", "ORG_1"), tuple("L_1", "ORG_2"), tuple("L_2", "ORG_1")); | |||
assertThat(result).containsOnly(tuple(user1.getUuid(), "ORG_1"), tuple(user1.getUuid(), "ORG_2"), tuple(user2.getUuid(), "ORG_1")); | |||
} | |||
@Test |
@@ -20,135 +20,217 @@ | |||
package org.sonar.db.permission.template; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.permission.PermissionQuery; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.user.UserDto; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.sonar.api.web.UserRole.ADMIN; | |||
import static org.sonar.api.web.UserRole.CODEVIEWER; | |||
import static org.sonar.api.web.UserRole.USER; | |||
import static org.sonar.db.permission.PermissionQuery.builder; | |||
public class UserWithPermissionTemplateDaoTest { | |||
private static final Long TEMPLATE_ID = 50L; | |||
@Rule | |||
public DbTester dbTester = DbTester.create(System2.INSTANCE); | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
private DbSession dbSession = dbTester.getSession(); | |||
private DbSession dbSession = db.getSession(); | |||
private PermissionTemplateDao underTest = dbTester.getDbClient().permissionTemplateDao(); | |||
private PermissionTemplateDao underTest = db.getDbClient().permissionTemplateDao(); | |||
@Test | |||
public void select_logins() { | |||
dbTester.prepareDbUnit(getClass(), "users_with_permissions.xml"); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate(dbSession, newQuery().build(), TEMPLATE_ID)).containsOnly("user1", "user2", "user3"); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate(dbSession, newQuery().withAtLeastOnePermission().setPermission("user").build(), | |||
TEMPLATE_ID)).containsOnly("user1", "user2"); | |||
OrganizationDto organization = db.organizations().insert(); | |||
UserDto user1 = db.users().insertUser(); | |||
UserDto user2 = db.users().insertUser(); | |||
UserDto user3 = db.users().insertUser(); | |||
db.organizations().addMember(organization, user1, user2, user3); | |||
PermissionTemplateDto permissionTemplate = db.permissionTemplates().insertTemplate(); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user1, USER); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user1, ADMIN); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user1, CODEVIEWER); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user2, USER); | |||
PermissionTemplateDto anotherPermissionTemplate = db.permissionTemplates().insertTemplate(); | |||
db.permissionTemplates().addUserToTemplate(anotherPermissionTemplate, user1, USER); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate(dbSession, | |||
builder().setOrganizationUuid(organization.getUuid()).build(), | |||
permissionTemplate.getId())) | |||
.containsExactlyInAnyOrder(user1.getLogin(), user2.getLogin(), user3.getLogin()); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate(dbSession, | |||
builder().setOrganizationUuid(organization.getUuid()).withAtLeastOnePermission().setPermission(USER).build(), | |||
permissionTemplate.getId())) | |||
.containsExactlyInAnyOrder(user1.getLogin(), user2.getLogin()); | |||
} | |||
@Test | |||
public void return_no_logins_on_unknown_template_key() { | |||
dbTester.prepareDbUnit(getClass(), "users_with_permissions.xml"); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate(dbSession, newQuery().setPermission("user").withAtLeastOnePermission().build(), 999L)).isEmpty(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
UserDto user = db.users().insertUser(); | |||
db.organizations().addMember(organization, user); | |||
PermissionTemplateDto permissionTemplate = db.permissionTemplates().insertTemplate(); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user, USER); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate(dbSession, | |||
builder().setOrganizationUuid(organization.getUuid()).setPermission(USER).withAtLeastOnePermission().build(), 999L)) | |||
.isEmpty(); | |||
} | |||
@Test | |||
public void select_only_logins_with_permission() { | |||
dbTester.prepareDbUnit(getClass(), "users_with_permissions.xml"); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate( | |||
dbSession, | |||
newQuery().setPermission("user").withAtLeastOnePermission().build(), | |||
TEMPLATE_ID)).containsOnly("user1", "user2"); | |||
OrganizationDto organization = db.organizations().insert(); | |||
UserDto user1 = db.users().insertUser(); | |||
UserDto user2 = db.users().insertUser(); | |||
UserDto user3 = db.users().insertUser(); | |||
db.organizations().addMember(organization, user1, user2, user3); | |||
PermissionTemplateDto permissionTemplate = db.permissionTemplates().insertTemplate(); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user1, USER); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user1, ADMIN); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user1, CODEVIEWER); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user2, USER); | |||
PermissionTemplateDto anotherPermissionTemplate = db.permissionTemplates().insertTemplate(); | |||
db.permissionTemplates().addUserToTemplate(anotherPermissionTemplate, user1, USER); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate(dbSession, | |||
builder().setOrganizationUuid(organization.getUuid()).setPermission(USER).withAtLeastOnePermission().build(), | |||
permissionTemplate.getId())) | |||
.containsExactlyInAnyOrder(user1.getLogin(), user2.getLogin()); | |||
} | |||
@Test | |||
public void select_only_enable_users() { | |||
dbTester.prepareDbUnit(getClass(), "select_only_enable_users.xml"); | |||
List<String> result = underTest.selectUserLoginsByQueryAndTemplate(dbSession, newQuery().setPermission("user").build(), TEMPLATE_ID); | |||
assertThat(result).hasSize(2); | |||
// Disabled user should not be returned | |||
assertThat(result.stream().filter(input -> input.equals("disabledUser")).findFirst()).isEmpty(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
UserDto user = db.users().insertUser(); | |||
UserDto disabledUser = db.users().insertUser(u -> u.setActive(false)); | |||
db.organizations().addMember(organization, user, disabledUser); | |||
PermissionTemplateDto permissionTemplate = db.permissionTemplates().insertTemplate(); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user, USER); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, disabledUser, USER); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate(dbSession, | |||
builder().setOrganizationUuid(organization.getUuid()).setPermission(USER).build(), permissionTemplate.getId())) | |||
.containsExactlyInAnyOrder(user.getLogin()); | |||
} | |||
@Test | |||
public void search_by_user_name() { | |||
dbTester.prepareDbUnit(getClass(), "users_with_permissions.xml"); | |||
OrganizationDto organization = db.organizations().insert(); | |||
UserDto user1 = db.users().insertUser(u -> u.setName("User1")); | |||
UserDto user2 = db.users().insertUser(u -> u.setName("User2")); | |||
UserDto user3 = db.users().insertUser(u -> u.setName("User3")); | |||
db.organizations().addMember(organization, user1, user2, user3); | |||
PermissionTemplateDto permissionTemplate = db.permissionTemplates().insertTemplate(); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user1, USER); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user2, USER); | |||
List<String> result = underTest.selectUserLoginsByQueryAndTemplate( | |||
dbSession, newQuery().withAtLeastOnePermission().setPermission("user").setSearchQuery("SEr1").build(), | |||
TEMPLATE_ID); | |||
assertThat(result).containsOnly("user1"); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate( | |||
dbSession, builder().setOrganizationUuid(organization.getUuid()).withAtLeastOnePermission().setPermission(USER).setSearchQuery("SEr1").build(), | |||
permissionTemplate.getId())) | |||
.containsExactlyInAnyOrder(user1.getLogin()); | |||
result = underTest.selectUserLoginsByQueryAndTemplate( | |||
dbSession, newQuery().withAtLeastOnePermission().setPermission("user").setSearchQuery("user").build(), | |||
TEMPLATE_ID); | |||
assertThat(result).hasSize(2); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate( | |||
dbSession, builder().setOrganizationUuid(organization.getUuid()).withAtLeastOnePermission().setPermission(USER).setSearchQuery("user").build(), | |||
permissionTemplate.getId())) | |||
.containsExactlyInAnyOrder(user1.getLogin(), user2.getLogin()); | |||
} | |||
@Test | |||
public void should_be_sorted_by_user_name() { | |||
dbTester.prepareDbUnit(getClass(), "users_with_permissions_should_be_sorted_by_user_name.xml"); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate(dbSession, newQuery().build(), TEMPLATE_ID)).containsOnly("user1", "user2", "user3"); | |||
OrganizationDto organization = db.organizations().insert(); | |||
UserDto user1 = db.users().insertUser(u -> u.setName("User3")); | |||
UserDto user2 = db.users().insertUser(u -> u.setName("User1")); | |||
UserDto user3 = db.users().insertUser(u -> u.setName("User2")); | |||
db.organizations().addMember(organization, user1, user2, user3); | |||
PermissionTemplateDto permissionTemplate = db.permissionTemplates().insertTemplate(); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user1, USER); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user2, USER); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate(dbSession, | |||
builder().setOrganizationUuid(organization.getUuid()).build(), permissionTemplate.getId())) | |||
.containsExactly(user2.getLogin(), user3.getLogin(), user1.getLogin()); | |||
} | |||
@Test | |||
public void should_be_paginated() { | |||
dbTester.prepareDbUnit(getClass(), "users_with_permissions.xml"); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate(dbSession, newQuery().setPageIndex(1).setPageSize(2).build(), TEMPLATE_ID)).containsOnly("user1", "user2"); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate(dbSession, newQuery().setPageIndex(2).setPageSize(2).build(), TEMPLATE_ID)).containsOnly("user3"); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate(dbSession, newQuery().setPageIndex(3).setPageSize(1).build(), TEMPLATE_ID)).containsOnly("user3"); | |||
OrganizationDto organization = db.organizations().insert(); | |||
UserDto user1 = db.users().insertUser(u -> u.setName("User1")); | |||
UserDto user2 = db.users().insertUser(u -> u.setName("User2")); | |||
UserDto user3 = db.users().insertUser(u -> u.setName("User3")); | |||
db.organizations().addMember(organization, user1, user2, user3); | |||
PermissionTemplateDto permissionTemplate = db.permissionTemplates().insertTemplate(); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user1, USER); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user2, USER); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate(dbSession, | |||
builder().setOrganizationUuid(organization.getUuid()).setPageIndex(1).setPageSize(2).build(), permissionTemplate.getId())) | |||
.containsExactlyInAnyOrder(user1.getLogin(), user2.getLogin()); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate(dbSession, | |||
builder().setOrganizationUuid(organization.getUuid()).setPageIndex(2).setPageSize(2).build(), permissionTemplate.getId())) | |||
.containsExactlyInAnyOrder(user3.getLogin()); | |||
assertThat(underTest.selectUserLoginsByQueryAndTemplate(dbSession, | |||
builder().setOrganizationUuid(organization.getUuid()).setPageIndex(3).setPageSize(1).build(), permissionTemplate.getId())) | |||
.containsExactlyInAnyOrder(user3.getLogin()); | |||
} | |||
@Test | |||
public void count_users() { | |||
dbTester.prepareDbUnit(getClass(), "users_with_permissions.xml"); | |||
assertThat(underTest.countUserLoginsByQueryAndTemplate(dbSession, newQuery().build(), TEMPLATE_ID)).isEqualTo(3); | |||
assertThat(underTest.countUserLoginsByQueryAndTemplate(dbSession, newQuery().withAtLeastOnePermission().setPermission("user").build(), TEMPLATE_ID)).isEqualTo(2); | |||
OrganizationDto organization = db.organizations().insert(); | |||
UserDto user1 = db.users().insertUser(); | |||
UserDto user2 = db.users().insertUser(); | |||
UserDto user3 = db.users().insertUser(); | |||
db.organizations().addMember(organization, user1, user2, user3); | |||
PermissionTemplateDto permissionTemplate = db.permissionTemplates().insertTemplate(); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user1, USER); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user2, USER); | |||
assertThat(underTest.countUserLoginsByQueryAndTemplate(dbSession, | |||
builder().setOrganizationUuid(organization.getUuid()).build(), permissionTemplate.getId())) | |||
.isEqualTo(3); | |||
assertThat(underTest.countUserLoginsByQueryAndTemplate(dbSession, | |||
builder().setOrganizationUuid(organization.getUuid()).withAtLeastOnePermission().setPermission("user").build(), permissionTemplate.getId())) | |||
.isEqualTo(2); | |||
} | |||
@Test | |||
public void select_user_permission_templates_by_template_and_logins() { | |||
dbTester.prepareDbUnit(getClass(), "users_with_permissions.xml"); | |||
assertThat(underTest.selectUserPermissionsByTemplateIdAndUserLogins(dbSession, 50L, singletonList("user1"))) | |||
OrganizationDto organization = db.organizations().insert(); | |||
UserDto user1 = db.users().insertUser(); | |||
UserDto user2 = db.users().insertUser(); | |||
UserDto user3 = db.users().insertUser(); | |||
db.organizations().addMember(organization, user1, user2, user3); | |||
PermissionTemplateDto permissionTemplate = db.permissionTemplates().insertTemplate(); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user1, USER); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user1, ADMIN); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user1, CODEVIEWER); | |||
db.permissionTemplates().addUserToTemplate(permissionTemplate, user2, USER); | |||
PermissionTemplateDto anotherPermissionTemplate = db.permissionTemplates().insertTemplate(); | |||
db.permissionTemplates().addUserToTemplate(anotherPermissionTemplate, user1, USER); | |||
assertThat(underTest.selectUserPermissionsByTemplateIdAndUserLogins(dbSession, permissionTemplate.getId(), singletonList(user1.getLogin()))) | |||
.extracting(PermissionTemplateUserDto::getUserLogin, PermissionTemplateUserDto::getPermission) | |||
.containsOnly( | |||
tuple("user1", UserRole.USER), | |||
tuple("user1", UserRole.ADMIN), | |||
tuple("user1", UserRole.CODEVIEWER) | |||
); | |||
.containsExactlyInAnyOrder( | |||
tuple(user1.getLogin(), USER), | |||
tuple(user1.getLogin(), ADMIN), | |||
tuple(user1.getLogin(), CODEVIEWER)); | |||
assertThat(underTest.selectUserPermissionsByTemplateIdAndUserLogins(dbSession, 50L, asList("user1", "user2", "user3"))) | |||
assertThat(underTest.selectUserPermissionsByTemplateIdAndUserLogins(dbSession, permissionTemplate.getId(), asList(user1.getLogin(), user2.getLogin(), user2.getLogin()))) | |||
.extracting(PermissionTemplateUserDto::getUserLogin, PermissionTemplateUserDto::getPermission) | |||
.containsOnly( | |||
tuple("user1", UserRole.USER), | |||
tuple("user1", UserRole.ADMIN), | |||
tuple("user1", UserRole.CODEVIEWER), | |||
tuple("user2", UserRole.USER) | |||
); | |||
assertThat(underTest.selectUserPermissionsByTemplateIdAndUserLogins(dbSession, 50L, singletonList("unknown"))).isEmpty(); | |||
assertThat(underTest.selectUserPermissionsByTemplateIdAndUserLogins(dbSession, 50L, Collections.emptyList())).isEmpty(); | |||
assertThat(underTest.selectUserPermissionsByTemplateIdAndUserLogins(dbSession, 123L, singletonList("user1"))).isEmpty(); | |||
} | |||
private PermissionQuery.Builder newQuery() { | |||
return builder().setOrganizationUuid("ORG_UUID"); | |||
.containsExactlyInAnyOrder( | |||
tuple(user1.getLogin(), USER), | |||
tuple(user1.getLogin(), ADMIN), | |||
tuple(user1.getLogin(), CODEVIEWER), | |||
tuple(user2.getLogin(), USER)); | |||
assertThat(underTest.selectUserPermissionsByTemplateIdAndUserLogins(dbSession, permissionTemplate.getId(), singletonList("unknown"))).isEmpty(); | |||
assertThat(underTest.selectUserPermissionsByTemplateIdAndUserLogins(dbSession, permissionTemplate.getId(), Collections.emptyList())).isEmpty(); | |||
assertThat(underTest.selectUserPermissionsByTemplateIdAndUserLogins(dbSession, 123L, singletonList(user1.getLogin()))).isEmpty(); | |||
} | |||
} |
@@ -55,7 +55,6 @@ import static org.mockito.Mockito.when; | |||
import static org.sonar.db.property.PropertyTesting.newComponentPropertyDto; | |||
import static org.sonar.db.property.PropertyTesting.newGlobalPropertyDto; | |||
import static org.sonar.db.property.PropertyTesting.newUserPropertyDto; | |||
import static org.sonar.db.user.UserTesting.newUserDto; | |||
@RunWith(DataProviderRunner.class) | |||
public class PropertiesDaoTest { | |||
@@ -72,28 +71,28 @@ public class PropertiesDaoTest { | |||
@Rule | |||
public ExpectedException thrown = ExpectedException.none(); | |||
@Rule | |||
public DbTester dbTester = DbTester.create(system2); | |||
public DbTester db = DbTester.create(system2); | |||
private DbClient dbClient = dbTester.getDbClient(); | |||
private DbSession session = dbTester.getSession(); | |||
private DbClient dbClient = db.getDbClient(); | |||
private DbSession session = db.getSession(); | |||
private PropertiesDao underTest = dbTester.getDbClient().propertiesDao(); | |||
private PropertiesDao underTest = db.getDbClient().propertiesDao(); | |||
@Test | |||
public void shouldFindUsersForNotification() throws SQLException { | |||
public void shouldFindUsersForNotification() { | |||
ComponentDto project1 = insertPrivateProject("uuid_45"); | |||
ComponentDto project2 = insertPrivateProject("uuid_56"); | |||
UserDto user1 = dbTester.users().insertUser(u -> u.setLogin("user1")); | |||
UserDto user2 = dbTester.users().insertUser(u -> u.setLogin("user2")); | |||
UserDto user3 = dbTester.users().insertUser(u -> u.setLogin("user3")); | |||
UserDto user1 = db.users().insertUser(u -> u.setLogin("user1")); | |||
UserDto user2 = db.users().insertUser(u -> u.setLogin("user2")); | |||
UserDto user3 = db.users().insertUser(u -> u.setLogin("user3")); | |||
insertProperty("notification.NewViolations.Email", "true", project1.getId(), user2.getId()); | |||
insertProperty("notification.NewViolations.Twitter", "true", null, user3.getId()); | |||
insertProperty("notification.NewViolations.Twitter", "true", project2.getId(), user1.getId()); | |||
insertProperty("notification.NewViolations.Twitter", "true", project1.getId(), user2.getId()); | |||
insertProperty("notification.NewViolations.Twitter", "true", project2.getId(), user3.getId()); | |||
dbTester.users().insertProjectPermissionOnUser(user2, UserRole.USER, project1); | |||
dbTester.users().insertProjectPermissionOnUser(user3, UserRole.USER, project2); | |||
dbTester.users().insertProjectPermissionOnUser(user1, UserRole.USER, project2); | |||
db.users().insertProjectPermissionOnUser(user2, UserRole.USER, project1); | |||
db.users().insertProjectPermissionOnUser(user3, UserRole.USER, project2); | |||
db.users().insertProjectPermissionOnUser(user1, UserRole.USER, project2); | |||
assertThat(underTest.findUsersForNotification("NewViolations", "Email", null)) | |||
.isEmpty(); | |||
@@ -121,9 +120,9 @@ public class PropertiesDaoTest { | |||
} | |||
@Test | |||
public void hasNotificationSubscribers() throws SQLException { | |||
int userId1 = dbTester.users().insertUser(u -> u.setLogin("user1")).getId(); | |||
int userId2 = dbTester.users().insertUser(u -> u.setLogin("user2")).getId(); | |||
public void hasNotificationSubscribers() { | |||
int userId1 = db.users().insertUser(u -> u.setLogin("user1")).getId(); | |||
int userId2 = db.users().insertUser(u -> u.setLogin("user2")).getId(); | |||
Long projectId = insertPrivateProject("PROJECT_A").getId(); | |||
// global subscription | |||
insertProperty("notification.DispatcherWithGlobalSubscribers.Email", "true", null, userId2); | |||
@@ -156,7 +155,7 @@ public class PropertiesDaoTest { | |||
} | |||
@Test | |||
public void selectGlobalProperties() throws SQLException { | |||
public void selectGlobalProperties() { | |||
// global | |||
long id1 = insertProperty("global.one", "one", null, null); | |||
long id2 = insertProperty("global.two", "two", null, null); | |||
@@ -180,7 +179,7 @@ public class PropertiesDaoTest { | |||
@Test | |||
@UseDataProvider("allValuesForSelect") | |||
public void selectGlobalProperties_supports_all_values(String dbValue, String expected) throws SQLException { | |||
public void selectGlobalProperties_supports_all_values(String dbValue, String expected) { | |||
insertProperty("global.one", dbValue, null, null); | |||
List<PropertyDto> dtos = underTest.selectGlobalProperties(); | |||
@@ -194,7 +193,7 @@ public class PropertiesDaoTest { | |||
} | |||
@Test | |||
public void selectGlobalProperty() throws SQLException { | |||
public void selectGlobalProperty() { | |||
// global | |||
insertProperty("global.one", "one", null, null); | |||
insertProperty("global.two", "two", null, null); | |||
@@ -215,7 +214,7 @@ public class PropertiesDaoTest { | |||
@Test | |||
@UseDataProvider("allValuesForSelect") | |||
public void selectGlobalProperty_supports_all_values(String dbValue, String expected) throws SQLException { | |||
public void selectGlobalProperty_supports_all_values(String dbValue, String expected) { | |||
insertProperty("global.one", dbValue, null, null); | |||
assertThatDto(underTest.selectGlobalProperty("global.one")) | |||
@@ -225,7 +224,7 @@ public class PropertiesDaoTest { | |||
} | |||
@Test | |||
public void selectProjectProperties() throws SQLException { | |||
public void selectProjectProperties() { | |||
ComponentDto projectDto = insertPrivateProject("A"); | |||
long projectId = projectDto.getId(); | |||
// global | |||
@@ -250,7 +249,7 @@ public class PropertiesDaoTest { | |||
@Test | |||
@UseDataProvider("allValuesForSelect") | |||
public void selectProjectProperties_supports_all_values(String dbValue, String expected) throws SQLException { | |||
public void selectProjectProperties_supports_all_values(String dbValue, String expected) { | |||
ComponentDto projectDto = insertPrivateProject("A"); | |||
insertProperty("project.one", dbValue, projectDto.getId(), null); | |||
@@ -274,7 +273,7 @@ public class PropertiesDaoTest { | |||
} | |||
@Test | |||
public void selectProjectProperty() throws SQLException { | |||
public void selectProjectProperty() { | |||
insertProperty("project.one", "one", 10L, null); | |||
PropertyDto property = underTest.selectProjectProperty(10L, "project.one"); | |||
@@ -288,34 +287,34 @@ public class PropertiesDaoTest { | |||
@Test | |||
public void selectEnabledDescendantModuleProperties() { | |||
dbTester.prepareDbUnit(getClass(), "select_module_properties_tree.xml"); | |||
db.prepareDbUnit(getClass(), "select_module_properties_tree.xml"); | |||
List<PropertyDto> properties = underTest.selectEnabledDescendantModuleProperties("ABCD", dbTester.getSession()); | |||
List<PropertyDto> properties = underTest.selectEnabledDescendantModuleProperties("ABCD", db.getSession()); | |||
assertThat(properties.size()).isEqualTo(4); | |||
assertThat(properties).extracting("key").containsOnly("struts.one", "core.one", "core.two", "data.one"); | |||
assertThat(properties).extracting("value").containsOnly("one", "two"); | |||
properties = underTest.selectEnabledDescendantModuleProperties("EFGH", dbTester.getSession()); | |||
properties = underTest.selectEnabledDescendantModuleProperties("EFGH", db.getSession()); | |||
assertThat(properties.size()).isEqualTo(3); | |||
assertThat(properties).extracting("key").containsOnly("core.one", "core.two", "data.one"); | |||
properties = underTest.selectEnabledDescendantModuleProperties("FGHI", dbTester.getSession()); | |||
properties = underTest.selectEnabledDescendantModuleProperties("FGHI", db.getSession()); | |||
assertThat(properties.size()).isEqualTo(1); | |||
assertThat(properties).extracting("key").containsOnly("data.one"); | |||
assertThat(underTest.selectEnabledDescendantModuleProperties("unknown-result.xml", dbTester.getSession()).size()).isEqualTo(0); | |||
assertThat(underTest.selectEnabledDescendantModuleProperties("unknown-result.xml", db.getSession()).size()).isEqualTo(0); | |||
} | |||
@Test | |||
@UseDataProvider("allValuesForSelect") | |||
public void selectEnabledDescendantModuleProperties_supports_all_values(String dbValue, String expected) throws SQLException { | |||
public void selectEnabledDescendantModuleProperties_supports_all_values(String dbValue, String expected) { | |||
String projectUuid = "A"; | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(OrganizationTesting.newOrganizationDto(), projectUuid); | |||
dbClient.componentDao().insert(session, project); | |||
long projectId = project.getId(); | |||
insertProperty("project.one", dbValue, projectId, null); | |||
List<PropertyDto> dtos = underTest.selectEnabledDescendantModuleProperties(projectUuid, dbTester.getSession()); | |||
List<PropertyDto> dtos = underTest.selectEnabledDescendantModuleProperties(projectUuid, db.getSession()); | |||
assertThat(dtos) | |||
.hasSize(1); | |||
assertThatDto(dtos.iterator().next()) | |||
@@ -326,7 +325,7 @@ public class PropertiesDaoTest { | |||
} | |||
@Test | |||
public void select_by_query() throws SQLException { | |||
public void select_by_query() { | |||
// global | |||
insertProperty("global.one", "one", null, null); | |||
insertProperty("global.two", "two", null, null); | |||
@@ -340,19 +339,19 @@ public class PropertiesDaoTest { | |||
// other | |||
insertProperty("other.one", "one", 12L, null); | |||
List<PropertyDto> results = underTest.selectByQuery(PropertyQuery.builder().setKey("user.two").setComponentId(10L).setUserId(100).build(), dbTester.getSession()); | |||
List<PropertyDto> results = underTest.selectByQuery(PropertyQuery.builder().setKey("user.two").setComponentId(10L).setUserId(100).build(), db.getSession()); | |||
assertThat(results).hasSize(1); | |||
assertThat(results.get(0).getValue()).isEqualTo("two"); | |||
results = underTest.selectByQuery(PropertyQuery.builder().setKey("user.one").setUserId(100).build(), dbTester.getSession()); | |||
results = underTest.selectByQuery(PropertyQuery.builder().setKey("user.one").setUserId(100).build(), db.getSession()); | |||
assertThat(results).hasSize(1); | |||
assertThat(results.get(0).getValue()).isEqualTo("one"); | |||
} | |||
@Test | |||
public void select_global_properties_by_keys() throws Exception { | |||
public void select_global_properties_by_keys() { | |||
insertPrivateProject("A"); | |||
int userId = dbTester.users().insertUser(u -> u.setLogin("B")).getId(); | |||
int userId = db.users().insertUser(u -> u.setLogin("B")).getId(); | |||
String key = "key"; | |||
String anotherKey = "anotherKey"; | |||
@@ -376,9 +375,9 @@ public class PropertiesDaoTest { | |||
@Test | |||
public void select_component_properties_by_ids() { | |||
ComponentDto project = dbTester.components().insertPrivateProject(); | |||
ComponentDto project2 = dbTester.components().insertPrivateProject(); | |||
UserDto user = dbTester.users().insertUser(); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto project2 = db.components().insertPrivateProject(); | |||
UserDto user = db.users().insertUser(); | |||
String key = "key"; | |||
String anotherKey = "anotherKey"; | |||
@@ -402,9 +401,9 @@ public class PropertiesDaoTest { | |||
@Test | |||
public void select_properties_by_keys_and_component_ids() { | |||
ComponentDto project = dbTester.components().insertPrivateProject(); | |||
ComponentDto project2 = dbTester.components().insertPrivateProject(); | |||
UserDto user = dbTester.users().insertUser(); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto project2 = db.components().insertPrivateProject(); | |||
UserDto user = db.users().insertUser(); | |||
String key = "key"; | |||
String anotherKey = "anotherKey"; | |||
@@ -432,6 +431,25 @@ public class PropertiesDaoTest { | |||
assertThat(underTest.selectPropertiesByKeysAndComponentIds(session, newHashSet("unknown"), newHashSet(123456789L))).isEmpty(); | |||
} | |||
@Test | |||
public void select_by_key_and_matching_value() { | |||
ComponentDto project1 = db.components().insertPrivateProject(); | |||
ComponentDto project2 = db.components().insertPrivateProject(); | |||
db.properties().insertProperties( | |||
newComponentPropertyDto("key", "value", project1), | |||
newComponentPropertyDto("key", "value", project2), | |||
newGlobalPropertyDto("key", "value"), | |||
newComponentPropertyDto("another key", "value", project1)); | |||
assertThat(underTest.selectByKeyAndMatchingValue(db.getSession(), "key", "value")) | |||
.extracting(PropertyDto::getValue, PropertyDto::getResourceId) | |||
.containsExactlyInAnyOrder( | |||
tuple("value", project1.getId()), | |||
tuple("value", project2.getId()), | |||
tuple("value", null) | |||
); | |||
} | |||
@Test | |||
public void saveProperty_inserts_global_properties_when_they_do_not_exist_in_db() { | |||
when(system2.now()).thenReturn(DATE_1, DATE_2, DATE_3, DATE_4, DATE_5); | |||
@@ -654,7 +672,7 @@ public class PropertiesDaoTest { | |||
} | |||
@Test | |||
public void delete_project_property() throws SQLException { | |||
public void delete_project_property() { | |||
long projectId1 = insertPrivateProject("A").getId(); | |||
long projectId2 = insertPrivateProject("B").getId(); | |||
long projectId3 = insertPrivateProject("C").getId(); | |||
@@ -703,7 +721,7 @@ public class PropertiesDaoTest { | |||
} | |||
@Test | |||
public void delete_project_properties() throws SQLException { | |||
public void delete_project_properties() { | |||
long id1 = insertProperty("sonar.profile.java", "Sonar Way", 1L, null); | |||
long id2 = insertProperty("sonar.profile.java", "Sonar Way", 2L, null); | |||
@@ -742,7 +760,7 @@ public class PropertiesDaoTest { | |||
} | |||
@Test | |||
public void deleteGlobalProperty() throws SQLException { | |||
public void deleteGlobalProperty() { | |||
// global | |||
long id1 = insertProperty("global.key", "new_global", null, null); | |||
long id2 = insertProperty("to_be_deleted", "xxx", null, null); | |||
@@ -775,13 +793,13 @@ public class PropertiesDaoTest { | |||
} | |||
@Test | |||
public void delete_by_organization_and_user() throws SQLException { | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
OrganizationDto anotherOrganization = dbTester.organizations().insert(); | |||
ComponentDto project = dbTester.components().insertPrivateProject(organization); | |||
ComponentDto anotherProject = dbTester.components().insertPrivateProject(anotherOrganization); | |||
UserDto user = dbTester.users().insertUser(); | |||
UserDto anotherUser = dbTester.users().insertUser(); | |||
public void delete_by_organization_and_user() { | |||
OrganizationDto organization = db.organizations().insert(); | |||
OrganizationDto anotherOrganization = db.organizations().insert(); | |||
ComponentDto project = db.components().insertPrivateProject(organization); | |||
ComponentDto anotherProject = db.components().insertPrivateProject(anotherOrganization); | |||
UserDto user = db.users().insertUser(); | |||
UserDto anotherUser = db.users().insertUser(); | |||
insertProperty("KEY_11", "VALUE", project.getId(), user.getId()); | |||
insertProperty("KEY_12", "VALUE", project.getId(), user.getId()); | |||
insertProperty("KEY_11", "VALUE", project.getId(), anotherUser.getId()); | |||
@@ -797,13 +815,13 @@ public class PropertiesDaoTest { | |||
} | |||
@Test | |||
public void delete_by_organization_and_matching_login() throws SQLException { | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
OrganizationDto anotherOrganization = dbTester.organizations().insert(); | |||
ComponentDto project = dbTester.components().insertPrivateProject(organization); | |||
ComponentDto anotherProject = dbTester.components().insertPrivateProject(anotherOrganization); | |||
UserDto user = dbTester.users().insertUser(); | |||
UserDto anotherUser = dbTester.users().insertUser(); | |||
public void delete_by_organization_and_matching_login() { | |||
OrganizationDto organization = db.organizations().insert(); | |||
OrganizationDto anotherOrganization = db.organizations().insert(); | |||
ComponentDto project = db.components().insertPrivateProject(organization); | |||
ComponentDto anotherProject = db.components().insertPrivateProject(anotherOrganization); | |||
UserDto user = db.users().insertUser(); | |||
UserDto anotherUser = db.users().insertUser(); | |||
insertProperty("KEY_11", user.getLogin(), project.getId(), null); | |||
insertProperty("KEY_12", user.getLogin(), project.getId(), null); | |||
insertProperty("KEY_11", anotherUser.getLogin(), project.getId(), null); | |||
@@ -819,9 +837,9 @@ public class PropertiesDaoTest { | |||
} | |||
@Test | |||
public void delete_by_key_and_value() throws SQLException { | |||
ComponentDto project = dbTester.components().insertPrivateProject(); | |||
ComponentDto anotherProject = dbTester.components().insertPrivateProject(); | |||
public void delete_by_key_and_value() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto anotherProject = db.components().insertPrivateProject(); | |||
insertProperty("KEY", "VALUE", null, null); | |||
insertProperty("KEY", "VALUE", project.getId(), null); | |||
insertProperty("KEY", "VALUE", null, 100); | |||
@@ -832,9 +850,9 @@ public class PropertiesDaoTest { | |||
insertProperty("ANOTHER_KEY", "VALUE", project.getId(), 100); | |||
underTest.deleteByKeyAndValue(session, "KEY", "VALUE"); | |||
dbTester.commit(); | |||
db.commit(); | |||
assertThat(dbTester.select("select prop_key as \"key\", text_value as \"value\", resource_id as \"projectId\", user_id as \"userId\" from properties")) | |||
assertThat(db.select("select prop_key as \"key\", text_value as \"value\", resource_id as \"projectId\", user_id as \"userId\" from properties")) | |||
.extracting((row) -> row.get("key"), (row) -> row.get("value"), (row) -> row.get("projectId"), (row) -> row.get("userId")) | |||
.containsOnly(tuple("KEY", "ANOTHER_VALUE", null, null), tuple("ANOTHER_KEY", "VALUE", project.getId(), 100L)); | |||
} | |||
@@ -999,7 +1017,7 @@ public class PropertiesDaoTest { | |||
session.commit(); | |||
} | |||
private long insertProperty(String key, @Nullable String value, @Nullable Long resourceId, @Nullable Integer userId, long createdAt) throws SQLException { | |||
private long insertProperty(String key, @Nullable String value, @Nullable Long resourceId, @Nullable Integer userId, long createdAt) { | |||
when(system2.now()).thenReturn(createdAt); | |||
return insertProperty(key, value, resourceId, userId); | |||
} | |||
@@ -1009,20 +1027,16 @@ public class PropertiesDaoTest { | |||
.setResourceId(resourceId) | |||
.setUserId(userId) | |||
.setValue(value); | |||
dbTester.properties().insertProperty(dto); | |||
db.properties().insertProperty(dto); | |||
return (long) dbTester.selectFirst(session, "select id as \"id\" from properties" + | |||
return (long) db.selectFirst(session, "select id as \"id\" from properties" + | |||
" where prop_key='" + key + "'" + | |||
" and user_id" + (userId == null ? " is null" : "='" + userId + "'") + | |||
" and resource_id" + (resourceId == null ? " is null" : "='" + resourceId + "'")).get("id"); | |||
} | |||
private ComponentDto insertPrivateProject(String uuid) { | |||
String key = "project" + uuid; | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization(), uuid).setDbKey(key); | |||
dbClient.componentDao().insert(session, project); | |||
dbTester.commit(); | |||
return project; | |||
return db.components().insertPrivateProject(db.getDefaultOrganization(), uuid); | |||
} | |||
private static PropertyDtoAssert assertThatDto(@Nullable PropertyDto dto) { | |||
@@ -1030,15 +1044,15 @@ public class PropertiesDaoTest { | |||
} | |||
private PropertiesRowAssert assertThatPropertiesRow(String key, @Nullable Integer userId, @Nullable Integer componentId) { | |||
return new PropertiesRowAssert(dbTester, key, userId, componentId); | |||
return new PropertiesRowAssert(db, key, userId, componentId); | |||
} | |||
private PropertiesRowAssert assertThatPropertiesRow(String key) { | |||
return new PropertiesRowAssert(dbTester, key); | |||
return new PropertiesRowAssert(db, key); | |||
} | |||
private PropertiesRowAssert assertThatPropertiesRow(long id) { | |||
return new PropertiesRowAssert(dbTester, id); | |||
return new PropertiesRowAssert(db, id); | |||
} | |||
} |
@@ -34,8 +34,6 @@ import static org.assertj.core.data.MapEntry.entry; | |||
import static org.sonar.db.user.GroupMembershipQuery.IN; | |||
import static org.sonar.db.user.GroupMembershipQuery.OUT; | |||
import static org.sonar.db.user.GroupMembershipQuery.builder; | |||
import static org.sonar.db.user.UserTesting.newDisabledUser; | |||
import static org.sonar.db.user.UserTesting.newUserDto; | |||
public class GroupMembershipDaoTest { | |||
@@ -55,9 +53,9 @@ public class GroupMembershipDaoTest { | |||
@Before | |||
public void setUp() throws Exception { | |||
organizationDto = db.organizations().insert(); | |||
user1 = db.users().insertUser(newUserDto("admin login", "Admin name", "admin@email.com")); | |||
user2 = db.users().insertUser(newUserDto("not.admin", "Not Admin", "Not Admin")); | |||
user3 = db.users().insertUser(newDisabledUser("inactive")); | |||
user1 = db.users().insertUser(u -> u.setLogin("admin login").setName("Admin name").setEmail("admin@email.com")); | |||
user2 = db.users().insertUser(u -> u.setLogin("not.admin").setName("Not Admin").setEmail("Not Admin")); | |||
user3 = db.users().insertUser(u -> u.setLogin("inactive").setActive(false)); | |||
group1 = db.users().insertGroup(organizationDto, "sonar-administrators"); | |||
group2 = db.users().insertGroup(organizationDto, "sonar-users"); | |||
group3 = db.users().insertGroup(organizationDto, "sonar-reviewers"); |
@@ -21,6 +21,7 @@ package org.sonar.db.user; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
@@ -67,6 +68,16 @@ public class UserDaoTest { | |||
when(system2.now()).thenReturn(NOW); | |||
} | |||
@Test | |||
public void selectByUuid() { | |||
UserDto user1 = db.users().insertUser(); | |||
UserDto user2 = db.users().insertUser(user -> user.setActive(false)); | |||
assertThat(underTest.selectByUuid(session, user1.getUuid())).isNotNull(); | |||
assertThat(underTest.selectByUuid(session, user2.getUuid())).isNotNull(); | |||
assertThat(underTest.selectByUuid(session, "unknown")).isNull(); | |||
} | |||
@Test | |||
public void selectUsersIds() { | |||
UserDto user1 = db.users().insertUser(user -> user.setLogin("user1")); | |||
@@ -109,6 +120,17 @@ public class UserDaoTest { | |||
assertThat(users).extracting("login").containsExactlyInAnyOrder("user1", "inactive_user"); | |||
} | |||
@Test | |||
public void selectUsersByUuids() { | |||
UserDto user1 = db.users().insertUser(); | |||
UserDto user2 = db.users().insertUser(); | |||
UserDto user3 = db.users().insertUser(user -> user.setActive(false)); | |||
assertThat((Collection<UserDto>) underTest.selectByUuids(session, asList(user1.getUuid(), user2.getUuid(), user3.getUuid()))).hasSize(3); | |||
assertThat((Collection<UserDto>) underTest.selectByUuids(session, asList(user1.getUuid(), "unknown"))).hasSize(1); | |||
assertThat((Collection<UserDto>) underTest.selectByUuids(session, Collections.emptyList())).isEmpty(); | |||
} | |||
@Test | |||
public void selectUsersByLogins_empty_logins() { | |||
// no need to access db | |||
@@ -320,8 +342,9 @@ public class UserDaoTest { | |||
.setSalt("1234") | |||
.setCryptedPassword("abcd") | |||
.setHashMethod("SHA1") | |||
.setExternalIdentity("johngithub") | |||
.setExternalLogin("johngithub") | |||
.setExternalIdentityProvider("github") | |||
.setExternalId("EXT_ID") | |||
.setLocal(true) | |||
.setCreatedAt(date) | |||
.setUpdatedAt(date) | |||
@@ -342,8 +365,9 @@ public class UserDaoTest { | |||
assertThat(user.getSalt()).isEqualTo("1234"); | |||
assertThat(user.getCryptedPassword()).isEqualTo("abcd"); | |||
assertThat(user.getHashMethod()).isEqualTo("SHA1"); | |||
assertThat(user.getExternalIdentity()).isEqualTo("johngithub"); | |||
assertThat(user.getExternalLogin()).isEqualTo("johngithub"); | |||
assertThat(user.getExternalIdentityProvider()).isEqualTo("github"); | |||
assertThat(user.getExternalId()).isEqualTo("EXT_ID"); | |||
assertThat(user.isLocal()).isTrue(); | |||
assertThat(user.isRoot()).isFalse(); | |||
assertThat(user.getHomepageType()).isEqualTo("project"); | |||
@@ -360,9 +384,9 @@ public class UserDaoTest { | |||
.setLocal(true) | |||
.setOnboarded(false)); | |||
UserDto userUpdate = newUserDto() | |||
.setId(1) | |||
.setLogin("john") | |||
underTest.update(db.getSession(), newUserDto() | |||
.setUuid(user.getUuid()) | |||
.setLogin("johnDoo") | |||
.setName("John Doo") | |||
.setEmail("jodoo@hn.com") | |||
.setScmAccounts(",jo.hn,john2,johndoo,") | |||
@@ -371,17 +395,17 @@ public class UserDaoTest { | |||
.setSalt("12345") | |||
.setCryptedPassword("abcde") | |||
.setHashMethod("BCRYPT") | |||
.setExternalIdentity("johngithub") | |||
.setExternalLogin("johngithub") | |||
.setExternalIdentityProvider("github") | |||
.setExternalId("EXT_ID") | |||
.setLocal(false) | |||
.setHomepageType("project") | |||
.setHomepageParameter("OB1"); | |||
underTest.update(db.getSession(), userUpdate); | |||
.setHomepageParameter("OB1")); | |||
UserDto reloaded = underTest.selectByLogin(db.getSession(), user.getLogin()); | |||
UserDto reloaded = underTest.selectByUuid(db.getSession(), user.getUuid()); | |||
assertThat(reloaded).isNotNull(); | |||
assertThat(reloaded.getId()).isEqualTo(user.getId()); | |||
assertThat(reloaded.getLogin()).isEqualTo(user.getLogin()); | |||
assertThat(reloaded.getLogin()).isEqualTo("johnDoo"); | |||
assertThat(reloaded.getName()).isEqualTo("John Doo"); | |||
assertThat(reloaded.getEmail()).isEqualTo("jodoo@hn.com"); | |||
assertThat(reloaded.isActive()).isFalse(); | |||
@@ -390,8 +414,9 @@ public class UserDaoTest { | |||
assertThat(reloaded.getSalt()).isEqualTo("12345"); | |||
assertThat(reloaded.getCryptedPassword()).isEqualTo("abcde"); | |||
assertThat(reloaded.getHashMethod()).isEqualTo("BCRYPT"); | |||
assertThat(reloaded.getExternalIdentity()).isEqualTo("johngithub"); | |||
assertThat(reloaded.getExternalLogin()).isEqualTo("johngithub"); | |||
assertThat(reloaded.getExternalIdentityProvider()).isEqualTo("github"); | |||
assertThat(reloaded.getExternalId()).isEqualTo("EXT_ID"); | |||
assertThat(reloaded.isLocal()).isFalse(); | |||
assertThat(reloaded.isRoot()).isFalse(); | |||
assertThat(reloaded.getHomepageType()).isEqualTo("project"); | |||
@@ -409,12 +434,14 @@ public class UserDaoTest { | |||
UserDto userReloaded = underTest.selectUserById(session, user.getId()); | |||
assertThat(userReloaded.isActive()).isFalse(); | |||
assertThat(userReloaded.getLogin()).isNotNull(); | |||
assertThat(userReloaded.getExternalId()).isNotNull(); | |||
assertThat(userReloaded.getExternalLogin()).isNotNull(); | |||
assertThat(userReloaded.getExternalIdentityProvider()).isNotNull(); | |||
assertThat(userReloaded.getEmail()).isNull(); | |||
assertThat(userReloaded.getScmAccounts()).isNull(); | |||
assertThat(userReloaded.getSalt()).isNull(); | |||
assertThat(userReloaded.getCryptedPassword()).isNull(); | |||
assertThat(userReloaded.getExternalIdentity()).isNull(); | |||
assertThat(userReloaded.getExternalIdentityProvider()).isNull(); | |||
assertThat(userReloaded.isRoot()).isFalse(); | |||
assertThat(userReloaded.getUpdatedAt()).isEqualTo(NOW); | |||
assertThat(userReloaded.getHomepageType()).isNull(); | |||
@@ -576,6 +603,16 @@ public class UserDaoTest { | |||
assertThat(underTest.selectByEmail(session, "unknown")).isNull(); | |||
} | |||
@Test | |||
public void select_by_external_id_and_identity_provider() { | |||
UserDto activeUser = db.users().insertUser(); | |||
UserDto disableUser = db.users().insertUser(u -> u.setActive(false)); | |||
assertThat(underTest.selectByExternalIdAndIdentityProvider(session, activeUser.getExternalId(), activeUser.getExternalIdentityProvider())).isNotNull(); | |||
assertThat(underTest.selectByExternalIdAndIdentityProvider(session, disableUser.getExternalId(), disableUser.getExternalIdentityProvider())).isNotNull(); | |||
assertThat(underTest.selectByExternalIdAndIdentityProvider(session, "unknown", "unknown")).isNull(); | |||
} | |||
@Test | |||
public void setRoot_does_not_fail_on_non_existing_login() { | |||
underTest.setRoot(session, "unkown", true); | |||
@@ -640,31 +677,31 @@ public class UserDaoTest { | |||
} | |||
@Test | |||
public void scrollByLogins() { | |||
public void scrollByLUuids() { | |||
UserDto u1 = insertUser(true); | |||
UserDto u2 = insertUser(false); | |||
UserDto u3 = insertUser(false); | |||
List<UserDto> result = new ArrayList<>(); | |||
underTest.scrollByLogins(db.getSession(), asList(u2.getLogin(), u3.getLogin(), "does not exist"), result::add); | |||
underTest.scrollByUuids(db.getSession(), asList(u2.getUuid(), u3.getUuid(), "does not exist"), result::add); | |||
assertThat(result).extracting(UserDto::getLogin, UserDto::getName) | |||
.containsExactlyInAnyOrder(tuple(u2.getLogin(), u2.getName()), tuple(u3.getLogin(), u3.getName())); | |||
assertThat(result).extracting(UserDto::getUuid, UserDto::getName) | |||
.containsExactlyInAnyOrder(tuple(u2.getUuid(), u2.getName()), tuple(u3.getUuid(), u3.getName())); | |||
} | |||
@Test | |||
public void scrollByLogins_scrolls_by_pages_of_1000_logins() { | |||
List<String> logins = new ArrayList<>(); | |||
public void scrollByUuids_scrolls_by_pages_of_1000_uuids() { | |||
List<String> uuids = new ArrayList<>(); | |||
for (int i = 0; i < DatabaseUtils.PARTITION_SIZE_FOR_ORACLE + 10; i++) { | |||
logins.add(insertUser(true).getLogin()); | |||
uuids.add(insertUser(true).getUuid()); | |||
} | |||
List<UserDto> result = new ArrayList<>(); | |||
underTest.scrollByLogins(db.getSession(), logins, result::add); | |||
underTest.scrollByUuids(db.getSession(), uuids, result::add); | |||
assertThat(result) | |||
.extracting(UserDto::getLogin) | |||
.containsExactlyInAnyOrder(logins.toArray(new String[0])); | |||
.extracting(UserDto::getUuid) | |||
.containsExactlyInAnyOrder(uuids.toArray(new String[0])); | |||
} | |||
@Test |
@@ -37,8 +37,10 @@ import org.sonar.db.permission.UserPermissionDto; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static java.lang.String.format; | |||
import static java.util.Arrays.stream; | |||
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER; | |||
import static org.sonar.db.user.GroupTesting.newGroupDto; | |||
import static org.sonar.db.user.UserTesting.newDisabledUser; | |||
import static org.sonar.db.user.UserTesting.newUserDto; | |||
public class UserDbTester { | |||
@@ -61,9 +63,17 @@ public class UserDbTester { | |||
return insertUser(dto); | |||
} | |||
public UserDto insertUser(Consumer<UserDto> populateUserDto) { | |||
@SafeVarargs | |||
public final UserDto insertUser(Consumer<UserDto>... populators) { | |||
UserDto dto = newUserDto().setActive(true); | |||
populateUserDto.accept(dto); | |||
stream(populators).forEach(p -> p.accept(dto)); | |||
return insertUser(dto); | |||
} | |||
@SafeVarargs | |||
public final UserDto insertDisabledUser(Consumer<UserDto>... populators) { | |||
UserDto dto = newDisabledUser(); | |||
stream(populators).forEach(p -> p.accept(dto)); | |||
return insertUser(dto); | |||
} | |||
@@ -39,7 +39,8 @@ public class UserTesting { | |||
.setEmail(randomAlphanumeric(30)) | |||
.setOnboarded(nextBoolean()) | |||
.setScmAccounts(singletonList(randomAlphanumeric(40))) | |||
.setExternalIdentity(randomAlphanumeric(40)) | |||
.setExternalId(randomAlphanumeric(40)) | |||
.setExternalLogin(randomAlphanumeric(40)) | |||
.setExternalIdentityProvider(randomAlphanumeric(40)) | |||
.setSalt(randomAlphanumeric(40)) | |||
.setCryptedPassword(randomAlphanumeric(40)) | |||
@@ -60,7 +61,8 @@ public class UserTesting { | |||
.setName(name) | |||
.setEmail(email) | |||
.setLogin(login) | |||
.setExternalIdentity(login) | |||
.setExternalId(login) | |||
.setExternalLogin(login) | |||
.setExternalIdentityProvider("sonarqube"); | |||
} | |||
@@ -70,18 +72,16 @@ public class UserTesting { | |||
.setName(name) | |||
.setEmail(email) | |||
.setLogin(login) | |||
.setExternalIdentity(randomAlphanumeric(40)) | |||
.setExternalId(randomAlphanumeric(40)) | |||
.setExternalLogin(randomAlphanumeric(40)) | |||
.setExternalIdentityProvider(randomAlphanumeric(40)); | |||
} | |||
public static UserDto newDisabledUser(String login) { | |||
public static UserDto newDisabledUser() { | |||
return newUserDto() | |||
.setLogin(login) | |||
.setActive(false) | |||
// All these fields are reset when disabling a user | |||
.setScmAccounts((String) null) | |||
.setExternalIdentity(null) | |||
.setExternalIdentityProvider(null) | |||
.setEmail(null) | |||
.setCryptedPassword(null) | |||
.setSalt(null); |
@@ -1,65 +0,0 @@ | |||
<dataset> | |||
<users id="200" | |||
uuid="user1uuid" | |||
login="user1" | |||
name="User1" | |||
active="[true]" | |||
is_root="[false]" | |||
onboarded="[true]"/> | |||
<users id="201" | |||
uuid="user2uuid" | |||
login="user2" | |||
name="User2" | |||
active="[true]" | |||
is_root="[false]" | |||
onboarded="[true]"/> | |||
<users id="202" | |||
uuid="user3uuid" | |||
login="user3" | |||
name="User3" | |||
active="[true]" | |||
is_root="[false]" | |||
onboarded="[true]"/> | |||
<users id="999" | |||
uuid="user999uuid" | |||
login="disabledUser" | |||
name="disabledUser" | |||
active="[false]" | |||
is_root="[false]" | |||
onboarded="[true]"/> | |||
<organization_members | |||
user_id="200" | |||
organization_uuid="ORG_UUID" | |||
/> | |||
<organization_members | |||
user_id="201" | |||
organization_uuid="ORG_UUID" | |||
/> | |||
<organization_members | |||
user_id="202" | |||
organization_uuid="ORG_UUID" | |||
/> | |||
<perm_templates_users id="1" | |||
user_id="200" | |||
permission_reference="user" | |||
template_id="50"/> | |||
<perm_templates_users id="2" | |||
user_id="200" | |||
permission_reference="admin" | |||
template_id="50"/> | |||
<perm_templates_users id="3" | |||
user_id="200" | |||
permission_reference="codeviewer" | |||
template_id="50"/> | |||
<perm_templates_users id="4" | |||
user_id="201" | |||
permission_reference="user" | |||
template_id="50"/> | |||
</dataset> |
@@ -1,62 +0,0 @@ | |||
<dataset> | |||
<users id="200" | |||
uuid="user1uuid" | |||
login="user1" | |||
name="User1" | |||
active="[true]" | |||
is_root="[false]" | |||
onboarded="[true]"/> | |||
<users id="201" | |||
uuid="user2uuid" | |||
login="user2" | |||
name="User2" | |||
active="[true]" | |||
is_root="[false]" | |||
onboarded="[true]"/> | |||
<users id="202" | |||
uuid="user3uuid" | |||
login="user3" | |||
name="User3" | |||
active="[true]" | |||
is_root="[false]" | |||
onboarded="[true]"/> | |||
<organization_members | |||
user_id="200" | |||
organization_uuid="ORG_UUID" | |||
/> | |||
<organization_members | |||
user_id="201" | |||
organization_uuid="ORG_UUID" | |||
/> | |||
<organization_members | |||
user_id="202" | |||
organization_uuid="ORG_UUID" | |||
/> | |||
<perm_templates_users id="1" | |||
user_id="200" | |||
permission_reference="user" | |||
template_id="50"/> | |||
<perm_templates_users id="2" | |||
user_id="200" | |||
permission_reference="admin" | |||
template_id="50"/> | |||
<perm_templates_users id="3" | |||
user_id="200" | |||
permission_reference="codeviewer" | |||
template_id="50"/> | |||
<perm_templates_users id="4" | |||
user_id="200" | |||
permission_reference="user" | |||
template_id="51"/> | |||
<perm_templates_users id="5" | |||
user_id="201" | |||
permission_reference="user" | |||
template_id="50"/> | |||
</dataset> |
@@ -1,58 +0,0 @@ | |||
<dataset> | |||
<users id="200" | |||
uuid="user3uuid" | |||
login="user3" | |||
name="User3" | |||
active="[true]" | |||
is_root="[false]" | |||
onboarded="[true]"/> | |||
<users id="201" | |||
uuid="user1uuid" | |||
login="user1" | |||
name="User1" | |||
active="[true]" | |||
is_root="[false]" | |||
onboarded="[true]"/> | |||
<users id="202" | |||
uuid="user2uuid" | |||
login="user2" | |||
name="User2" | |||
active="[true]" | |||
is_root="[false]" | |||
onboarded="[true]"/> | |||
<organization_members | |||
user_id="200" | |||
organization_uuid="ORG_UUID" | |||
/> | |||
<organization_members | |||
user_id="201" | |||
organization_uuid="ORG_UUID" | |||
/> | |||
<organization_members | |||
user_id="202" | |||
organization_uuid="ORG_UUID" | |||
/> | |||
<perm_templates_users id="1" | |||
user_id="200" | |||
permission_reference="user" | |||
template_id="50"/> | |||
<perm_templates_users id="2" | |||
user_id="200" | |||
permission_reference="admin" | |||
template_id="50"/> | |||
<perm_templates_users id="3" | |||
user_id="200" | |||
permission_reference="codeviewer" | |||
template_id="50"/> | |||
<perm_templates_users id="4" | |||
user_id="201" | |||
permission_reference="user" | |||
template_id="50"/> | |||
</dataset> |
@@ -0,0 +1,46 @@ | |||
/* | |||
* 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.sql.AddColumnsBuilder; | |||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; | |||
public class AddExternalIdToUsers extends DdlChange { | |||
public AddExternalIdToUsers(Database db) { | |||
super(db); | |||
} | |||
@Override | |||
public void execute(Context context) throws SQLException { | |||
context.execute(new AddColumnsBuilder(getDialect(), "users") | |||
.addColumn(newVarcharColumnDefBuilder() | |||
.setColumnName("external_id") | |||
.setLimit(255) | |||
.setIsNullable(true) | |||
.build()) | |||
.build()); | |||
} | |||
} |
@@ -0,0 +1,62 @@ | |||
/* | |||
* 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.CreateIndexBuilder; | |||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; | |||
public class AddUniqueIndexesOnUsers extends DdlChange { | |||
public AddUniqueIndexesOnUsers(Database db) { | |||
super(db); | |||
} | |||
@Override | |||
public void execute(Context context) throws SQLException { | |||
context.execute(new CreateIndexBuilder(getDialect()) | |||
.setTable("users") | |||
.setName("users_uuid") | |||
.setUnique(true) | |||
.addColumn(notNullableColumn("uuid", 40)) | |||
.build()); | |||
context.execute(new CreateIndexBuilder(getDialect()) | |||
.setTable("users") | |||
.setName("uniq_external_id") | |||
.setUnique(true) | |||
.addColumn(notNullableColumn("external_identity_provider", 100)) | |||
.addColumn(notNullableColumn("external_id", 255)) | |||
.build()); | |||
} | |||
private static VarcharColumnDef notNullableColumn(String columnName, int limit) { | |||
return newVarcharColumnDefBuilder() | |||
.setColumnName(columnName) | |||
.setLimit(limit) | |||
.setIsNullable(false) | |||
.build(); | |||
} | |||
} |
@@ -36,6 +36,13 @@ public class DbVersion72 implements DbVersion { | |||
.add(2106, "Create PROJECT_MAPPINGS table", CreateProjectMappingsTable.class) | |||
.add(2107, "Add UUID on table USERS", AddUUIDtoUsers.class) | |||
.add(2108, "Populate USERS.UUID with USERS.LOGIN", PopulateUUIDOnUsers.class) | |||
.add(2109, "Add EXTERNAL_ID on table users", AddExternalIdToUsers.class) | |||
.add(2110, "Rename EXTERNAL_IDENTITY to EXTERNAL_LOGIN on table users", RenameExternalIdentityToExternalLoginOnUsers.class) | |||
.add(2111, "Update null values from external columns and login of users", UpdateNullValuesFromExternalColumnsAndLoginOfUsers.class) | |||
.add(2112, "Populate EXTERNAL_ID on table users", PopulateExternalIdOnUsers.class) | |||
.add(2113, "Makes same columns of table users not nullable", MakeSomeColumnsOfUsersNotNullable.class) | |||
.add(2114, "Add unique indexes on table users", AddUniqueIndexesOnUsers.class) | |||
; | |||
} | |||
} |
@@ -0,0 +1,72 @@ | |||
/* | |||
* 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.AlterColumnsBuilder; | |||
import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder; | |||
import org.sonar.server.platform.db.migration.sql.DropIndexBuilder; | |||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; | |||
public class MakeSomeColumnsOfUsersNotNullable extends DdlChange { | |||
public static final String USERS_TABLE = "users"; | |||
public static final String USERS_LOGIN_INDEX = "users_login"; | |||
public MakeSomeColumnsOfUsersNotNullable(Database db) { | |||
super(db); | |||
} | |||
@Override | |||
public void execute(Context context) throws SQLException { | |||
context.execute(new DropIndexBuilder(getDialect()) | |||
.setTable(USERS_TABLE) | |||
.setName(USERS_LOGIN_INDEX) | |||
.build()); | |||
context.execute(new AlterColumnsBuilder(getDialect(), USERS_TABLE) | |||
.updateColumn(notNullableColumn("uuid", 40)) | |||
.updateColumn(notNullableColumn("login", 255)) | |||
.updateColumn(notNullableColumn("external_id", 255)) | |||
.updateColumn(notNullableColumn("external_login", 255)) | |||
.updateColumn(notNullableColumn("external_identity_provider", 100)) | |||
.build()); | |||
context.execute(new CreateIndexBuilder(getDialect()) | |||
.setTable(USERS_TABLE) | |||
.setName(USERS_LOGIN_INDEX) | |||
.addColumn(notNullableColumn("login", 255)) | |||
.setUnique(true) | |||
.build()); | |||
} | |||
private static VarcharColumnDef notNullableColumn(String columnName, int limit) { | |||
return newVarcharColumnDefBuilder() | |||
.setColumnName(columnName) | |||
.setLimit(limit) | |||
.setIsNullable(false) | |||
.build(); | |||
} | |||
} |
@@ -0,0 +1,53 @@ | |||
/* | |||
* 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; | |||
import org.sonar.server.platform.db.migration.step.MassUpdate; | |||
public class PopulateExternalIdOnUsers extends DataChange { | |||
private final System2 system2; | |||
public PopulateExternalIdOnUsers(Database db, System2 system2) { | |||
super(db); | |||
this.system2 = system2; | |||
} | |||
@Override | |||
public void execute(Context context) throws SQLException { | |||
MassUpdate massUpdate = context.prepareMassUpdate().rowPluralName("users"); | |||
massUpdate.select("SELECT id, external_login FROM users WHERE external_id IS NULL"); | |||
massUpdate.update("UPDATE users SET external_id=?, updated_at=? WHERE id=?"); | |||
long now = system2.now(); | |||
massUpdate.execute((row, update) -> { | |||
long id = row.getLong(1); | |||
String externalLogin = row.getString(2); | |||
update.setString(1, externalLogin); | |||
update.setLong(2, now); | |||
update.setLong(3, id); | |||
return true; | |||
}); | |||
} | |||
} |
@@ -0,0 +1,46 @@ | |||
/* | |||
* 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.sql.RenameColumnsBuilder; | |||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; | |||
public class RenameExternalIdentityToExternalLoginOnUsers extends DdlChange { | |||
public RenameExternalIdentityToExternalLoginOnUsers(Database db) { | |||
super(db); | |||
} | |||
@Override | |||
public void execute(Context context) throws SQLException { | |||
context.execute(new RenameColumnsBuilder(getDialect(), "users") | |||
.renameColumn("external_identity", | |||
newVarcharColumnDefBuilder() | |||
.setColumnName("external_login") | |||
.setLimit(255) | |||
.build()) | |||
.build()); | |||
} | |||
} |
@@ -0,0 +1,75 @@ | |||
/* | |||
* 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.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.core.util.UuidFactory; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.step.DataChange; | |||
import org.sonar.server.platform.db.migration.step.MassUpdate; | |||
/** | |||
* The goal of this migration is to sanitize disabled USERS, regarding new way of authentication users. | |||
* Indeed, authentication will search for user but LOGIN but also buy using EXTERNAL_ID and EXTERNAL_PROVIDER. | |||
* | |||
* As a consequence, these columns must be set as NOT NULL in order to add a UNIQUE index on them. | |||
* | |||
* Unfortunately, these columns were previously set as null when disabling a user, that's why we need to populate them. | |||
*/ | |||
public class UpdateNullValuesFromExternalColumnsAndLoginOfUsers extends DataChange { | |||
private static final Logger LOG = Loggers.get(UpdateNullValuesFromExternalColumnsAndLoginOfUsers.class); | |||
private final System2 system2; | |||
private UuidFactory uuidFactory; | |||
public UpdateNullValuesFromExternalColumnsAndLoginOfUsers(Database db, System2 system2, UuidFactory uuidFactory) { | |||
super(db); | |||
this.system2 = system2; | |||
this.uuidFactory = uuidFactory; | |||
} | |||
@Override | |||
public void execute(Context context) throws SQLException { | |||
MassUpdate massUpdate = context.prepareMassUpdate().rowPluralName("users"); | |||
massUpdate.select("SELECT id, login FROM users WHERE login IS NULL OR external_login IS NULL OR external_identity_provider IS NULL"); | |||
massUpdate.update("UPDATE users SET login=?, external_login=?, external_identity_provider=?, updated_at=? WHERE id=?"); | |||
long now = system2.now(); | |||
massUpdate.execute((row, update) -> { | |||
long id = row.getLong(1); | |||
String login = row.getString(2); | |||
if (login == null) { | |||
LOG.warn("No login has been found for user id '{}'. A UUID has been generated to not have null value.", id); | |||
login = uuidFactory.create(); | |||
} | |||
update.setString(1, login); | |||
update.setString(2, login); | |||
update.setString(3, "sonarqube"); | |||
update.setLong(4, now); | |||
update.setLong(5, id); | |||
return true; | |||
}); | |||
} | |||
} |
@@ -0,0 +1,55 @@ | |||
/* | |||
* 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 AddExternalIdToUsersTest { | |||
@Rule | |||
public final CoreDbTester db = CoreDbTester.createForSchema(AddExternalIdToUsersTest.class, "users.sql"); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private AddExternalIdToUsers underTest = new AddExternalIdToUsers(db.database()); | |||
@Test | |||
public void column_is_added_to_table() throws SQLException { | |||
underTest.execute(); | |||
db.assertColumnDefinition("users", "external_id", VARCHAR, 255, true); | |||
} | |||
@Test | |||
public void migration_is_reentrant() throws SQLException { | |||
underTest.execute(); | |||
expectedException.expect(IllegalStateException.class); | |||
underTest.execute(); | |||
} | |||
} |
@@ -0,0 +1,56 @@ | |||
/* | |||
* 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; | |||
public class AddUniqueIndexesOnUsersTest { | |||
@Rule | |||
public final CoreDbTester db = CoreDbTester.createForSchema(AddUniqueIndexesOnUsersTest.class, "users.sql"); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private AddUniqueIndexesOnUsers underTest = new AddUniqueIndexesOnUsers(db.database()); | |||
@Test | |||
public void add_unique_indexes() throws SQLException { | |||
underTest.execute(); | |||
db.assertUniqueIndex("users", "users_uuid", "uuid"); | |||
db.assertUniqueIndex("users", "uniq_external_id", "external_identity_provider", "external_id"); | |||
} | |||
@Test | |||
public void migration_is_not_reentrant() throws SQLException { | |||
underTest.execute(); | |||
expectedException.expect(IllegalStateException.class); | |||
underTest.execute(); | |||
} | |||
} |
@@ -34,7 +34,7 @@ public class DbVersion72Test { | |||
@Test | |||
public void verify_migration_count() { | |||
verifyMigrationCount(underTest, 9); | |||
verifyMigrationCount(underTest, 15); | |||
} | |||
} |
@@ -0,0 +1,62 @@ | |||
/* | |||
* 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.sonar.db.CoreDbTester; | |||
import static java.sql.Types.VARCHAR; | |||
public class MakeSomeColumnsOfUsersNotNullableTest { | |||
@Rule | |||
public final CoreDbTester db = CoreDbTester.createForSchema(MakeSomeColumnsOfUsersNotNullableTest.class, "users.sql"); | |||
private MakeSomeColumnsOfUsersNotNullable underTest = new MakeSomeColumnsOfUsersNotNullable(db.database()); | |||
@Test | |||
public void columns_are_set_as_not_nullable() throws SQLException { | |||
underTest.execute(); | |||
db.assertColumnDefinition("users", "uuid", VARCHAR, 40, false); | |||
db.assertColumnDefinition("users", "login", VARCHAR, 255, false); | |||
db.assertColumnDefinition("users", "external_id", VARCHAR, 255, false); | |||
db.assertColumnDefinition("users", "external_login", VARCHAR, 255, false); | |||
db.assertColumnDefinition("users", "external_identity_provider", VARCHAR, 100, false); | |||
db.assertUniqueIndex("users", "users_login", "login"); | |||
} | |||
@Test | |||
public void migration_is_reentrant() throws SQLException { | |||
underTest.execute(); | |||
underTest.execute(); | |||
db.assertColumnDefinition("users", "uuid", VARCHAR, 40, false); | |||
db.assertColumnDefinition("users", "login", VARCHAR, 255, false); | |||
db.assertColumnDefinition("users", "external_id", VARCHAR, 255, false); | |||
db.assertColumnDefinition("users", "external_login", VARCHAR, 255, false); | |||
db.assertColumnDefinition("users", "external_identity_provider", VARCHAR, 100, false); | |||
db.assertUniqueIndex("users", "users_login", "login"); | |||
} | |||
} |
@@ -0,0 +1,95 @@ | |||
/* | |||
* 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.Collectors; | |||
import javax.annotation.Nullable; | |||
import org.assertj.core.groups.Tuple; | |||
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.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
public class PopulateExternalIdOnUsersTest { | |||
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(PopulateExternalIdOnUsersTest.class, "users.sql"); | |||
private System2 system2 = new TestSystem2().setNow(NOW); | |||
private PopulateExternalIdOnUsers underTest = new PopulateExternalIdOnUsers(db.database(), system2); | |||
@Test | |||
public void update_users() throws SQLException { | |||
insertUser("USER_1", "user1", null); | |||
insertUser("USER_2", "user2", "1234"); | |||
underTest.execute(); | |||
assertUsers( | |||
tuple("USER_1", "user1", NOW), | |||
tuple("USER_2", "1234", PAST)); | |||
} | |||
@Test | |||
public void migration_is_reentrant() throws SQLException { | |||
insertUser("USER_1", "user1", null); | |||
insertUser("USER_2", "user2", "1234"); | |||
underTest.execute(); | |||
underTest.execute(); | |||
assertUsers( | |||
tuple("USER_1", "user1", NOW), | |||
tuple("USER_2", "1234", PAST)); | |||
} | |||
private void assertUsers(Tuple... expectedTuples) { | |||
assertThat(db.select("SELECT LOGIN, EXTERNAL_ID, UPDATED_AT FROM USERS") | |||
.stream() | |||
.map(map -> new Tuple(map.get("LOGIN"), map.get("EXTERNAL_ID"), map.get("UPDATED_AT"))) | |||
.collect(Collectors.toList())) | |||
.containsExactlyInAnyOrder(expectedTuples); | |||
} | |||
private void insertUser(String login, String externalLogin, @Nullable String externalId) { | |||
db.executeInsert("USERS", | |||
"LOGIN", login, | |||
"EXTERNAL_ID", externalId, | |||
"EXTERNAL_LOGIN", externalLogin, | |||
"CREATED_AT", PAST, | |||
"UPDATED_AT", PAST, | |||
"IS_ROOT", false, | |||
"ONBOARDED", false); | |||
} | |||
} |
@@ -0,0 +1,58 @@ | |||
/* | |||
* 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 RenameExternalIdentityToExternalLoginOnUsersTest { | |||
@Rule | |||
public final CoreDbTester db = CoreDbTester.createForSchema(RenameExternalIdentityToExternalLoginOnUsersTest.class, "users.sql"); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private RenameExternalIdentityToExternalLoginOnUsers underTest = new RenameExternalIdentityToExternalLoginOnUsers(db.database()); | |||
@Test | |||
public void column_is_renamed() throws SQLException { | |||
underTest.execute(); | |||
db.assertColumnDefinition("users", "external_login", VARCHAR, 255, true); | |||
db.assertColumnDoesNotExist("users", "external_identity"); | |||
} | |||
@Test | |||
public void migration_is_not_reentrant() throws SQLException { | |||
underTest.execute(); | |||
expectedException.expect(IllegalStateException.class); | |||
underTest.execute(); | |||
} | |||
} |
@@ -0,0 +1,119 @@ | |||
/* | |||
* 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 javax.annotation.Nullable; | |||
import org.assertj.core.groups.Tuple; | |||
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.api.utils.log.LogTester; | |||
import org.sonar.api.utils.log.LoggerLevel; | |||
import org.sonar.core.util.SequenceUuidFactory; | |||
import org.sonar.db.CoreDbTester; | |||
import static java.lang.String.format; | |||
import static java.util.stream.Collectors.toList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
public class UpdateNullValuesFromExternalColumnsAndLoginOfUsersTest { | |||
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(UpdateNullValuesFromExternalColumnsAndLoginOfUsersTest.class, "users.sql"); | |||
@Rule | |||
public LogTester logTester = new LogTester(); | |||
private System2 system2 = new TestSystem2().setNow(NOW); | |||
private UpdateNullValuesFromExternalColumnsAndLoginOfUsers underTest = new UpdateNullValuesFromExternalColumnsAndLoginOfUsers(db.database(), system2, new SequenceUuidFactory()); | |||
@Test | |||
public void update_users() throws SQLException { | |||
insertUser("USER_1", "user1", "github"); | |||
insertUser("USER_2", null, null); | |||
insertUser("USER_3", "user", null); | |||
insertUser("USER_4", null, "github"); | |||
insertUser(null, "user", "bitbucket"); | |||
insertUser(null, null, null); | |||
underTest.execute(); | |||
assertUsers( | |||
tuple("USER_1", "user1", "github", PAST), | |||
tuple("USER_2", "USER_2", "sonarqube", NOW), | |||
tuple("USER_3", "USER_3", "sonarqube", NOW), | |||
tuple("USER_4", "USER_4", "sonarqube", NOW), | |||
tuple("1", "1", "sonarqube", NOW), | |||
tuple("2", "2", "sonarqube", NOW)); | |||
} | |||
@Test | |||
public void log_warning_when_login_is_null() throws SQLException { | |||
insertUser(null, "user", "bitbucket"); | |||
long id = (long) db.selectFirst("SELECT ID FROM USERS").get("ID"); | |||
underTest.execute(); | |||
assertThat(logTester.logs(LoggerLevel.WARN)) | |||
.containsExactlyInAnyOrder(format("No login has been found for user id '%s'. A UUID has been generated to not have null value.", id)); | |||
} | |||
@Test | |||
public void is_reentrant() throws SQLException { | |||
insertUser("USER_1", null, null); | |||
underTest.execute(); | |||
underTest.execute(); | |||
assertUsers(tuple("USER_1", "USER_1", "sonarqube", NOW)); | |||
} | |||
private void assertUsers(Tuple... expectedTuples) { | |||
assertThat(db.select("SELECT LOGIN, EXTERNAL_LOGIN, EXTERNAL_IDENTITY_PROVIDER, UPDATED_AT FROM USERS") | |||
.stream() | |||
.map(map -> new Tuple(map.get("LOGIN"), map.get("EXTERNAL_LOGIN"), map.get("EXTERNAL_IDENTITY_PROVIDER"), map.get("UPDATED_AT"))) | |||
.collect(toList())) | |||
.containsExactlyInAnyOrder(expectedTuples); | |||
} | |||
private void insertUser(@Nullable String login, @Nullable String externalLogin, @Nullable String externalIdentityProvider) { | |||
db.executeInsert("USERS", | |||
"LOGIN", login, | |||
"EXTERNAL_LOGIN", externalLogin, | |||
"EXTERNAL_IDENTITY_PROVIDER", externalIdentityProvider, | |||
"CREATED_AT", PAST, | |||
"UPDATED_AT", PAST, | |||
"IS_ROOT", false, | |||
"ONBOARDED", false); | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
CREATE TABLE "USERS" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"UUID" VARCHAR(40), | |||
"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"); |
@@ -0,0 +1,23 @@ | |||
CREATE TABLE "USERS" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"UUID" VARCHAR(40), | |||
"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_ID" VARCHAR(255), | |||
"EXTERNAL_LOGIN" 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"); |
@@ -0,0 +1,23 @@ | |||
CREATE TABLE "USERS" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"UUID" VARCHAR(40), | |||
"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_ID" VARCHAR(255), | |||
"EXTERNAL_LOGIN" 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"); |
@@ -0,0 +1,23 @@ | |||
CREATE TABLE "USERS" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"UUID" VARCHAR(40), | |||
"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_ID" VARCHAR(255), | |||
"EXTERNAL_LOGIN" 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"); |
@@ -0,0 +1,23 @@ | |||
CREATE TABLE "USERS" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"UUID" VARCHAR(40), | |||
"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_ID" VARCHAR(255), | |||
"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"); |
@@ -0,0 +1,23 @@ | |||
CREATE TABLE "USERS" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"UUID" VARCHAR(40), | |||
"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_ID" VARCHAR(255), | |||
"EXTERNAL_LOGIN" 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"); |
@@ -57,6 +57,11 @@ public class GroupTester { | |||
return session.wsClient().userGroups().create(request).getGroup(); | |||
} | |||
@SafeVarargs | |||
public final UserGroups.Group generate(Consumer<CreateRequest>... populators) { | |||
return generate(null, populators); | |||
} | |||
public List<Group> getGroupsOfUser(@Nullable Organizations.Organization organization, String userLogin) { | |||
GroupsRequest request = new GroupsRequest() | |||
.setOrganization(organization != null ? organization.getKey() : null) |
@@ -52,7 +52,7 @@ public class UserTester { | |||
.filter(u -> !"admin".equals(u.getLogin())) | |||
.forEach(u -> { | |||
PostRequest request = new PostRequest("api/users/deactivate").setParam("login", u.getLogin()); | |||
session.wsClient().wsConnector().call(request); | |||
session.wsClient().wsConnector().call(request).failIfNotSuccessful(); | |||
}); | |||
} | |||
@@ -52,7 +52,7 @@ public class EmailAlreadyExistsException extends RuntimeException { | |||
encodeMessage(email), | |||
encodeMessage(userIdentity.getProviderLogin()), | |||
encodeMessage(provider.getKey()), | |||
encodeMessage(existingUser.getExternalIdentity()), | |||
encodeMessage(existingUser.getExternalLogin()), | |||
encodeMessage(existingUser.getExternalIdentityProvider())); | |||
} | |||
} |
@@ -27,6 +27,8 @@ import java.util.Map; | |||
import java.util.Objects; | |||
import java.util.Optional; | |||
import java.util.Set; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.server.authentication.IdentityProvider; | |||
import org.sonar.api.server.authentication.UserIdentity; | |||
import org.sonar.api.utils.log.Logger; | |||
@@ -88,47 +90,50 @@ public class UserIdentityAuthenticator { | |||
this.defaultGroupFinder = defaultGroupFinder; | |||
} | |||
public UserDto authenticate(UserIdentity user, IdentityProvider provider, AuthenticationEvent.Source source, ExistingEmailStrategy existingEmailStrategy) { | |||
public UserDto authenticate(UserIdentity userIdentity, IdentityProvider provider, AuthenticationEvent.Source source, ExistingEmailStrategy existingEmailStrategy) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
String userLogin = user.getLogin(); | |||
UserDto userDto = dbClient.userDao().selectByLogin(dbSession, userLogin); | |||
if (userDto != null && userDto.isActive()) { | |||
registerExistingUser(dbSession, userDto, user, provider, source, existingEmailStrategy); | |||
return userDto; | |||
UserDto userDto = getUser(dbSession, userIdentity, provider); | |||
if (userDto == null) { | |||
return registerNewUser(dbSession, null, userIdentity, provider, source, existingEmailStrategy); | |||
} | |||
return registerNewUser(dbSession, user, provider, source, existingEmailStrategy); | |||
if (!userDto.isActive()) { | |||
return registerNewUser(dbSession, userDto, userIdentity, provider, source, existingEmailStrategy); | |||
} | |||
return registerExistingUser(dbSession, userDto, userIdentity, provider, source, existingEmailStrategy); | |||
} | |||
} | |||
private void registerExistingUser(DbSession dbSession, UserDto userDto, UserIdentity identity, IdentityProvider provider, AuthenticationEvent.Source source, | |||
@CheckForNull | |||
private UserDto getUser(DbSession dbSession, UserIdentity userIdentity, IdentityProvider provider) { | |||
String externalId = userIdentity.getProviderId(); | |||
UserDto user = dbClient.userDao().selectByExternalIdAndIdentityProvider(dbSession, externalId == null ? userIdentity.getProviderLogin() : externalId, provider.getKey()); | |||
// We need to search by login because : | |||
// 1. external id may have not been set before, | |||
// 2. user may have been provisioned, | |||
// 3. user may have been disabled. | |||
return user != null ? user : dbClient.userDao().selectByLogin(dbSession, userIdentity.getLogin()); | |||
} | |||
private UserDto registerExistingUser(DbSession dbSession, UserDto userDto, UserIdentity identity, IdentityProvider provider, AuthenticationEvent.Source source, | |||
ExistingEmailStrategy existingEmailStrategy) { | |||
UpdateUser update = UpdateUser.create(userDto.getLogin()) | |||
UpdateUser update = new UpdateUser() | |||
.setLogin(identity.getLogin()) | |||
.setEmail(identity.getEmail()) | |||
.setName(identity.getName()) | |||
.setExternalIdentity(new ExternalIdentity(provider.getKey(), identity.getProviderLogin())); | |||
.setExternalIdentity(new ExternalIdentity(provider.getKey(), identity.getProviderLogin(), identity.getProviderId())); | |||
Optional<UserDto> otherUserToIndex = validateEmail(dbSession, identity, provider, source, existingEmailStrategy); | |||
userUpdater.updateAndCommit(dbSession, update, u -> syncGroups(dbSession, identity, u), toArray(otherUserToIndex)); | |||
userUpdater.updateAndCommit(dbSession, userDto, update, u -> syncGroups(dbSession, identity, u), toArray(otherUserToIndex)); | |||
return userDto; | |||
} | |||
private UserDto registerNewUser(DbSession dbSession, UserIdentity identity, IdentityProvider provider, AuthenticationEvent.Source source, | |||
private UserDto registerNewUser(DbSession dbSession, @Nullable UserDto disabledUser, UserIdentity identity, IdentityProvider provider, AuthenticationEvent.Source source, | |||
ExistingEmailStrategy existingEmailStrategy) { | |||
if (!provider.allowsUsersToSignUp()) { | |||
throw AuthenticationException.newBuilder() | |||
.setSource(source) | |||
.setLogin(identity.getLogin()) | |||
.setMessage(format("User signup disabled for provider '%s'", provider.getKey())) | |||
.setPublicMessage(format("'%s' users are not allowed to sign up", provider.getKey())) | |||
.build(); | |||
} | |||
Optional<UserDto> otherUserToIndex = validateEmail(dbSession, identity, provider, source, existingEmailStrategy); | |||
return userUpdater.createAndCommit(dbSession, NewUser.builder() | |||
.setLogin(identity.getLogin()) | |||
.setEmail(identity.getEmail()) | |||
.setName(identity.getName()) | |||
.setExternalIdentity(new ExternalIdentity(provider.getKey(), identity.getProviderLogin())) | |||
.build(), | |||
u -> syncGroups(dbSession, identity, u), | |||
toArray(otherUserToIndex)); | |||
NewUser newUser = createNewUser(identity, provider, source); | |||
if (disabledUser == null) { | |||
return userUpdater.createAndCommit(dbSession, newUser, u -> syncGroups(dbSession, identity, u), toArray(otherUserToIndex)); | |||
} | |||
return userUpdater.reactivateAndCommit(dbSession, disabledUser, newUser, u -> syncGroups(dbSession, identity, u), toArray(otherUserToIndex)); | |||
} | |||
private Optional<UserDto> validateEmail(DbSession dbSession, UserIdentity identity, IdentityProvider provider, AuthenticationEvent.Source source, | |||
@@ -138,7 +143,9 @@ public class UserIdentityAuthenticator { | |||
return Optional.empty(); | |||
} | |||
UserDto existingUser = dbClient.userDao().selectByEmail(dbSession, email); | |||
if (existingUser == null || existingUser.getLogin().equals(identity.getLogin())) { | |||
if (existingUser == null | |||
|| Objects.equals(existingUser.getLogin(), identity.getLogin()) | |||
|| (Objects.equals(existingUser.getExternalId(), identity.getProviderId()) && Objects.equals(existingUser.getExternalIdentityProvider(), provider.getKey()))) { | |||
return Optional.empty(); | |||
} | |||
switch (existingEmailStrategy) { | |||
@@ -209,8 +216,25 @@ public class UserIdentityAuthenticator { | |||
return organizationFlags.isEnabled(dbSession) ? Optional.empty() : Optional.of(defaultGroupFinder.findDefaultGroup(dbSession, defaultOrganizationProvider.get().getUuid())); | |||
} | |||
private static NewUser createNewUser(UserIdentity identity, IdentityProvider provider, AuthenticationEvent.Source source) { | |||
if (!provider.allowsUsersToSignUp()) { | |||
throw AuthenticationException.newBuilder() | |||
.setSource(source) | |||
.setLogin(identity.getLogin()) | |||
.setMessage(format("User signup disabled for provider '%s'", provider.getKey())) | |||
.setPublicMessage(format("'%s' users are not allowed to sign up", provider.getKey())) | |||
.build(); | |||
} | |||
return NewUser.builder() | |||
.setLogin(identity.getLogin()) | |||
.setEmail(identity.getEmail()) | |||
.setName(identity.getName()) | |||
.setExternalIdentity(new ExternalIdentity(provider.getKey(), identity.getProviderLogin(), identity.getProviderId())) | |||
.build(); | |||
} | |||
private static UserDto[] toArray(Optional<UserDto> userDto) { | |||
return userDto.map(u -> new UserDto[]{u}).orElse(new UserDto[]{}); | |||
return userDto.map(u -> new UserDto[] {u}).orElse(new UserDto[] {}); | |||
} | |||
} |
@@ -137,7 +137,7 @@ public class SendIssueNotificationsStep implements ComputationStep { | |||
private void sendNewIssuesNotification(NewIssuesStatistics statistics, Component project, long analysisDate) { | |||
NewIssuesStatistics.Stats globalStatistics = statistics.globalStatistics(); | |||
NewIssuesNotification notification = newIssuesNotificationFactory | |||
.newNewIssuesNotication() | |||
.newNewIssuesNotification() | |||
.setProject(project.getPublicKey(), project.getName(), getBranchName(), getPullRequest()) | |||
.setProjectVersion(project.getReportAttributes().getVersion()) | |||
.setAnalysisDate(new Date(analysisDate)) |
@@ -21,7 +21,6 @@ package org.sonar.server.issue.notification; | |||
import org.sonar.api.utils.Durations; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.server.user.index.UserIndex; | |||
import static org.sonar.server.issue.notification.AbstractNewIssuesEmailTemplate.FIELD_ASSIGNEE; | |||
@@ -29,8 +28,8 @@ public class MyNewIssuesNotification extends NewIssuesNotification { | |||
public static final String MY_NEW_ISSUES_NOTIF_TYPE = "my-new-issues"; | |||
MyNewIssuesNotification(UserIndex userIndex, DbClient dbClient, Durations durations) { | |||
super(MY_NEW_ISSUES_NOTIF_TYPE, userIndex, dbClient, durations); | |||
MyNewIssuesNotification(DbClient dbClient, Durations durations) { | |||
super(MY_NEW_ISSUES_NOTIF_TYPE, dbClient, durations); | |||
} | |||
public MyNewIssuesNotification setAssignee(String assignee) { |
@@ -40,9 +40,8 @@ import org.sonar.db.DbSession; | |||
import org.sonar.db.RowNotFoundException; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.rule.RuleDefinitionDto; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.server.issue.notification.NewIssuesStatistics.Metric; | |||
import org.sonar.server.user.index.UserDoc; | |||
import org.sonar.server.user.index.UserIndex; | |||
import static org.sonar.server.issue.notification.AbstractNewIssuesEmailTemplate.FIELD_BRANCH; | |||
import static org.sonar.server.issue.notification.AbstractNewIssuesEmailTemplate.FIELD_PROJECT_VERSION; | |||
@@ -60,17 +59,15 @@ public class NewIssuesNotification extends Notification { | |||
private static final String LABEL = ".label"; | |||
private static final String DOT = "."; | |||
private final transient UserIndex userIndex; | |||
private final transient DbClient dbClient; | |||
private final transient Durations durations; | |||
NewIssuesNotification(UserIndex userIndex, DbClient dbClient, Durations durations) { | |||
this(TYPE, userIndex, dbClient, durations); | |||
NewIssuesNotification(DbClient dbClient, Durations durations) { | |||
this(TYPE, dbClient, durations); | |||
} | |||
protected NewIssuesNotification(String type, UserIndex userIndex, DbClient dbClient, Durations durations) { | |||
protected NewIssuesNotification(String type, DbClient dbClient, Durations durations) { | |||
super(type); | |||
this.userIndex = userIndex; | |||
this.dbClient = dbClient; | |||
this.durations = durations; | |||
} | |||
@@ -104,7 +101,7 @@ public class NewIssuesNotification extends Notification { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
setRuleTypeStatistics(stats); | |||
setAssigneesStatistics(stats); | |||
setAssigneesStatistics(dbSession, stats); | |||
setTagsStatistics(stats); | |||
setComponentsStatistics(dbSession, stats); | |||
setRuleStatistics(dbSession, stats); | |||
@@ -168,13 +165,13 @@ public class NewIssuesNotification extends Notification { | |||
} | |||
} | |||
private void setAssigneesStatistics(NewIssuesStatistics.Stats stats) { | |||
private void setAssigneesStatistics(DbSession dbSession, NewIssuesStatistics.Stats stats) { | |||
Metric metric = Metric.ASSIGNEE; | |||
int i = 1; | |||
for (Map.Entry<String, MetricStatsInt> assigneeStats : fiveBiggest(stats.getDistributedMetricStats(metric), MetricStatsInt::getOnLeak)) { | |||
String login = assigneeStats.getKey(); | |||
UserDoc user = userIndex.getNullableByLogin(login); | |||
String name = user == null ? login : user.name(); | |||
UserDto user = dbClient.userDao().selectByLogin(dbSession, login); | |||
String name = user == null ? login : user.getName(); | |||
setFieldValue(metric + DOT + i + LABEL, name); | |||
setFieldValue(metric + DOT + i + COUNT, String.valueOf(assigneeStats.getValue().getOnLeak())); | |||
i++; |
@@ -23,26 +23,23 @@ import org.sonar.api.ce.ComputeEngineSide; | |||
import org.sonar.api.server.ServerSide; | |||
import org.sonar.api.utils.Durations; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.server.user.index.UserIndex; | |||
@ServerSide | |||
@ComputeEngineSide | |||
public class NewIssuesNotificationFactory { | |||
private final UserIndex userIndex; | |||
private final DbClient dbClient; | |||
private final Durations durations; | |||
public NewIssuesNotificationFactory(UserIndex userIndex, DbClient dbClient, Durations durations) { | |||
this.userIndex = userIndex; | |||
public NewIssuesNotificationFactory(DbClient dbClient, Durations durations) { | |||
this.dbClient = dbClient; | |||
this.durations = durations; | |||
} | |||
public MyNewIssuesNotification newMyNewIssuesNotification() { | |||
return new MyNewIssuesNotification(userIndex, dbClient, durations); | |||
return new MyNewIssuesNotification(dbClient, durations); | |||
} | |||
public NewIssuesNotification newNewIssuesNotication() { | |||
return new NewIssuesNotification(userIndex, dbClient, durations); | |||
public NewIssuesNotification newNewIssuesNotification() { | |||
return new NewIssuesNotification(dbClient, durations); | |||
} | |||
} |
@@ -34,6 +34,7 @@ import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.qualitygate.QualityGateDto; | |||
import org.sonar.db.qualityprofile.QProfileDto; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.server.component.ComponentCleanerService; | |||
import org.sonar.server.organization.BillingValidations; | |||
import org.sonar.server.organization.BillingValidationsProxy; | |||
@@ -177,14 +178,15 @@ public class DeleteAction implements OrganizationsWsAction { | |||
} | |||
private void deleteOrganization(DbSession dbSession, OrganizationDto organization) { | |||
Collection<String> logins = dbClient.organizationMemberDao().selectLoginsByOrganizationUuid(dbSession, organization.getUuid()); | |||
Collection<String> uuids = dbClient.organizationMemberDao().selectUserUuidsByOrganizationUuid(dbSession, organization.getUuid()); | |||
dbClient.organizationMemberDao().deleteByOrganizationUuid(dbSession, organization.getUuid()); | |||
dbClient.organizationDao().deleteByUuid(dbSession, organization.getUuid()); | |||
dbClient.userDao().cleanHomepage(dbSession, organization); | |||
dbClient.webhookDao().selectByOrganizationUuid(dbSession, organization.getUuid()) | |||
.forEach(wh -> dbClient.webhookDeliveryDao().deleteByWebhook(dbSession, wh)); | |||
dbClient.webhookDao().deleteByOrganization(dbSession, organization); | |||
userIndexer.commitAndIndexByLogins(dbSession, logins); | |||
List<UserDto> users = dbClient.userDao().selectByUuids(dbSession, uuids); | |||
userIndexer.commitAndIndex(dbSession, users); | |||
} | |||
private static void preventDeletionOfDefaultOrganization(String key, DefaultOrganization defaultOrganization) { |
@@ -19,6 +19,8 @@ | |||
*/ | |||
package org.sonar.server.user; | |||
import javax.annotation.Nullable; | |||
import static java.util.Objects.requireNonNull; | |||
public class ExternalIdentity { | |||
@@ -26,17 +28,23 @@ public class ExternalIdentity { | |||
public static final String SQ_AUTHORITY = "sonarqube"; | |||
private String provider; | |||
private String login; | |||
private String id; | |||
public ExternalIdentity(String provider, String id) { | |||
public ExternalIdentity(String provider, String login, @Nullable String id) { | |||
this.provider = requireNonNull(provider, "Identity provider cannot be null"); | |||
this.id = requireNonNull(id, "Identity id cannot be null"); | |||
this.login = requireNonNull(login, "Identity login cannot be null"); | |||
this.id = id == null ? login : id; | |||
} | |||
public String getProvider() { | |||
return provider; | |||
} | |||
public String getLogin() { | |||
return login; | |||
} | |||
public String getId() { | |||
return id; | |||
} |
@@ -19,8 +19,6 @@ | |||
*/ | |||
package org.sonar.server.user; | |||
import static com.google.common.base.Preconditions.checkNotNull; | |||
import java.util.List; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
@@ -34,21 +32,24 @@ public class UpdateUser { | |||
private String password; | |||
private ExternalIdentity externalIdentity; | |||
private boolean loginChanged; | |||
private boolean nameChanged; | |||
private boolean emailChanged; | |||
private boolean scmAccountsChanged; | |||
private boolean passwordChanged; | |||
private boolean externalIdentityChanged; | |||
private UpdateUser(String login) { | |||
// No direct call to this constructor | |||
this.login = login; | |||
} | |||
@CheckForNull | |||
public String login() { | |||
return login; | |||
} | |||
public UpdateUser setLogin(@Nullable String login) { | |||
this.login = login; | |||
loginChanged = true; | |||
return this; | |||
} | |||
@CheckForNull | |||
public String name() { | |||
return name; | |||
@@ -107,6 +108,10 @@ public class UpdateUser { | |||
return this; | |||
} | |||
public boolean isLoginChanged() { | |||
return loginChanged; | |||
} | |||
public boolean isNameChanged() { | |||
return nameChanged; | |||
} | |||
@@ -127,8 +132,4 @@ public class UpdateUser { | |||
return externalIdentityChanged; | |||
} | |||
public static UpdateUser create(String login) { | |||
checkNotNull(login); | |||
return new UpdateUser(login); | |||
} | |||
} |
@@ -52,9 +52,9 @@ import static com.google.common.collect.Lists.newArrayList; | |||
import static java.lang.String.format; | |||
import static java.util.Arrays.stream; | |||
import static java.util.stream.Stream.concat; | |||
import static org.sonar.api.CoreProperties.DEFAULT_ISSUE_ASSIGNEE; | |||
import static org.sonar.core.config.CorePropertyDefinitions.ONBOARDING_TUTORIAL_SHOW_TO_NEW_USERS; | |||
import static org.sonar.core.util.stream.MoreCollectors.toList; | |||
import static org.sonar.server.ws.WsUtils.checkFound; | |||
import static org.sonar.server.ws.WsUtils.checkRequest; | |||
@ServerSide | |||
@@ -97,23 +97,19 @@ public class UserUpdater { | |||
} | |||
public UserDto createAndCommit(DbSession dbSession, NewUser newUser, Consumer<UserDto> beforeCommit, UserDto... otherUsersToIndex) { | |||
String login = newUser.login(); | |||
UserDto userDto = dbClient.userDao().selectByLogin(dbSession, newUser.login()); | |||
if (userDto == null) { | |||
userDto = saveUser(dbSession, createDto(dbSession, newUser)); | |||
} else { | |||
reactivateUser(dbSession, userDto, login, newUser); | |||
} | |||
beforeCommit.accept(userDto); | |||
userIndexer.commitAndIndex(dbSession, concat(Stream.of(userDto), stream(otherUsersToIndex)).collect(toList())); | |||
UserDto userDto = saveUser(dbSession, createDto(dbSession, newUser)); | |||
return commitUser(dbSession, userDto, beforeCommit, otherUsersToIndex); | |||
} | |||
notifyNewUser(userDto.getLogin(), userDto.getName(), newUser.email()); | |||
return userDto; | |||
public UserDto reactivateAndCommit(DbSession dbSession, UserDto disabledUser, NewUser newUser, Consumer<UserDto> beforeCommit, UserDto... otherUsersToIndex) { | |||
checkArgument(!disabledUser.isActive(), "An active user with login '%s' already exists", disabledUser.getLogin()); | |||
reactivateUser(dbSession, disabledUser, newUser); | |||
return commitUser(dbSession, disabledUser, beforeCommit, otherUsersToIndex); | |||
} | |||
private void reactivateUser(DbSession dbSession, UserDto existingUser, String login, NewUser newUser) { | |||
checkArgument(!existingUser.isActive(), "An active user with login '%s' already exists", login); | |||
UpdateUser updateUser = UpdateUser.create(login) | |||
private void reactivateUser(DbSession dbSession, UserDto disabledUser, NewUser newUser) { | |||
UpdateUser updateUser = new UpdateUser() | |||
.setLogin(newUser.login()) | |||
.setName(newUser.name()) | |||
.setEmail(newUser.email()) | |||
.setScmAccounts(newUser.scmAccounts()) | |||
@@ -121,22 +117,18 @@ public class UserUpdater { | |||
if (newUser.password() != null) { | |||
updateUser.setPassword(newUser.password()); | |||
} | |||
setOnboarded(existingUser); | |||
updateDto(dbSession, updateUser, existingUser); | |||
updateUser(dbSession, existingUser); | |||
addUserToDefaultOrganizationAndDefaultGroup(dbSession, existingUser); | |||
setOnboarded(disabledUser); | |||
updateDto(dbSession, updateUser, disabledUser); | |||
updateUser(dbSession, disabledUser); | |||
addUserToDefaultOrganizationAndDefaultGroup(dbSession, disabledUser); | |||
} | |||
public void updateAndCommit(DbSession dbSession, UpdateUser updateUser, Consumer<UserDto> beforeCommit, UserDto... otherUsersToIndex) { | |||
UserDto dto = dbClient.userDao().selectByLogin(dbSession, updateUser.login()); | |||
checkFound(dto, "User with login '%s' has not been found", updateUser.login()); | |||
public void updateAndCommit(DbSession dbSession, UserDto dto, UpdateUser updateUser, Consumer<UserDto> beforeCommit, UserDto... otherUsersToIndex) { | |||
boolean isUserUpdated = updateDto(dbSession, updateUser, dto); | |||
if (isUserUpdated) { | |||
// at least one change. Database must be updated and Elasticsearch re-indexed | |||
updateUser(dbSession, dto); | |||
beforeCommit.accept(dto); | |||
userIndexer.commitAndIndex(dbSession, concat(Stream.of(dto), stream(otherUsersToIndex)).collect(toList())); | |||
notifyNewUser(dto.getLogin(), dto.getName(), dto.getEmail()); | |||
commitUser(dbSession, dto, beforeCommit, otherUsersToIndex); | |||
} else { | |||
// no changes but still execute the consumer | |||
beforeCommit.accept(dto); | |||
@@ -144,12 +136,20 @@ public class UserUpdater { | |||
} | |||
} | |||
private UserDto commitUser(DbSession dbSession, UserDto userDto, Consumer<UserDto> beforeCommit, UserDto... otherUsersToIndex) { | |||
beforeCommit.accept(userDto); | |||
userIndexer.commitAndIndex(dbSession, concat(Stream.of(userDto), stream(otherUsersToIndex)).collect(toList())); | |||
notifyNewUser(userDto.getLogin(), userDto.getName(), userDto.getEmail()); | |||
return userDto; | |||
} | |||
private UserDto createDto(DbSession dbSession, NewUser newUser) { | |||
UserDto userDto = new UserDto(); | |||
List<String> messages = new ArrayList<>(); | |||
String login = newUser.login(); | |||
if (validateLoginFormat(login, messages)) { | |||
checkLoginUniqueness(dbSession, login); | |||
userDto.setLogin(login); | |||
} | |||
@@ -173,7 +173,7 @@ public class UserUpdater { | |||
userDto.setScmAccounts(scmAccounts); | |||
} | |||
setExternalIdentity(userDto, newUser.externalIdentity()); | |||
setExternalIdentity(dbSession, userDto, newUser.externalIdentity()); | |||
setOnboarded(userDto); | |||
checkRequest(messages.isEmpty(), messages); | |||
@@ -182,15 +182,28 @@ public class UserUpdater { | |||
private boolean updateDto(DbSession dbSession, UpdateUser update, UserDto dto) { | |||
List<String> messages = newArrayList(); | |||
boolean changed = updateName(update, dto, messages); | |||
boolean changed = updateLogin(dbSession, update, dto, messages); | |||
changed |= updateName(update, dto, messages); | |||
changed |= updateEmail(update, dto, messages); | |||
changed |= updateExternalIdentity(update, dto); | |||
changed |= updateExternalIdentity(dbSession, update, dto); | |||
changed |= updatePassword(update, dto, messages); | |||
changed |= updateScmAccounts(dbSession, update, dto, messages); | |||
checkRequest(messages.isEmpty(), messages); | |||
return changed; | |||
} | |||
private boolean updateLogin(DbSession dbSession, UpdateUser updateUser, UserDto userDto, List<String> messages) { | |||
String newLogin = updateUser.login(); | |||
if (updateUser.isLoginChanged() && validateLoginFormat(newLogin, messages) && !Objects.equals(userDto.getLogin(), newLogin)) { | |||
checkLoginUniqueness(dbSession, newLogin); | |||
dbClient.propertiesDao().selectByKeyAndMatchingValue(dbSession, DEFAULT_ISSUE_ASSIGNEE, userDto.getLogin()) | |||
.forEach(p -> dbClient.propertiesDao().saveProperty(p.setValue(newLogin))); | |||
userDto.setLogin(newLogin); | |||
return true; | |||
} | |||
return false; | |||
} | |||
private static boolean updateName(UpdateUser updateUser, UserDto userDto, List<String> messages) { | |||
String name = updateUser.name(); | |||
if (updateUser.isNameChanged() && validateNameFormat(name, messages) && !Objects.equals(userDto.getName(), name)) { | |||
@@ -209,10 +222,10 @@ public class UserUpdater { | |||
return false; | |||
} | |||
private static boolean updateExternalIdentity(UpdateUser updateUser, UserDto userDto) { | |||
private boolean updateExternalIdentity(DbSession dbSession, UpdateUser updateUser, UserDto userDto) { | |||
ExternalIdentity externalIdentity = updateUser.externalIdentity(); | |||
if (updateUser.isExternalIdentityChanged() && !isSameExternalIdentity(userDto, externalIdentity)) { | |||
setExternalIdentity(userDto, externalIdentity); | |||
setExternalIdentity(dbSession, userDto, externalIdentity); | |||
return true; | |||
} | |||
return false; | |||
@@ -247,22 +260,29 @@ public class UserUpdater { | |||
private static boolean isSameExternalIdentity(UserDto dto, @Nullable ExternalIdentity externalIdentity) { | |||
return externalIdentity != null | |||
&& Objects.equals(dto.getExternalIdentity(), externalIdentity.getId()) | |||
&& !dto.isLocal() | |||
&& Objects.equals(dto.getExternalId(), externalIdentity.getId()) | |||
&& Objects.equals(dto.getExternalLogin(), externalIdentity.getLogin()) | |||
&& Objects.equals(dto.getExternalIdentityProvider(), externalIdentity.getProvider()); | |||
} | |||
private static void setExternalIdentity(UserDto dto, @Nullable ExternalIdentity externalIdentity) { | |||
private void setExternalIdentity(DbSession dbSession, UserDto dto, @Nullable ExternalIdentity externalIdentity) { | |||
if (externalIdentity == null) { | |||
dto.setExternalIdentity(dto.getLogin()); | |||
dto.setExternalLogin(dto.getLogin()); | |||
dto.setExternalIdentityProvider(SQ_AUTHORITY); | |||
dto.setExternalId(dto.getLogin()); | |||
dto.setLocal(true); | |||
} else { | |||
dto.setExternalIdentity(externalIdentity.getId()); | |||
dto.setExternalLogin(externalIdentity.getLogin()); | |||
dto.setExternalIdentityProvider(externalIdentity.getProvider()); | |||
dto.setExternalId(externalIdentity.getId()); | |||
dto.setLocal(false); | |||
dto.setSalt(null); | |||
dto.setCryptedPassword(null); | |||
} | |||
UserDto existingUser = dbClient.userDao().selectByExternalIdAndIdentityProvider(dbSession, dto.getExternalId(), dto.getExternalIdentityProvider()); | |||
checkArgument(existingUser == null || Objects.equals(dto.getUuid(), existingUser.getUuid()), | |||
"A user with provider id '%s' and identity provider '%s' already exists", dto.getExternalId(), dto.getExternalIdentityProvider()); | |||
} | |||
private void setOnboarded(UserDto userDto) { | |||
@@ -364,6 +384,11 @@ public class UserUpdater { | |||
return Collections.emptyList(); | |||
} | |||
private void checkLoginUniqueness(DbSession dbSession, String login) { | |||
UserDto existingUser = dbClient.userDao().selectByLogin(dbSession, login); | |||
checkArgument(existingUser == null, "A user with login '%s' already exists", login); | |||
} | |||
private UserDto saveUser(DbSession dbSession, UserDto userDto) { | |||
userDto.setActive(true); | |||
UserDto res = dbClient.userDao().insert(dbSession, userDto); |
@@ -40,7 +40,7 @@ public class UserDoc extends BaseDoc implements User { | |||
@Override | |||
public String getId() { | |||
return login(); | |||
return uuid(); | |||
} | |||
@Override | |||
@@ -53,6 +53,10 @@ public class UserDoc extends BaseDoc implements User { | |||
return null; | |||
} | |||
public String uuid() { | |||
return getField(UserIndexDefinition.FIELD_UUID); | |||
} | |||
@Override | |||
public String login() { | |||
return getField(UserIndexDefinition.FIELD_LOGIN); | |||
@@ -82,6 +86,11 @@ public class UserDoc extends BaseDoc implements User { | |||
return getField(FIELD_ORGANIZATION_UUIDS); | |||
} | |||
public UserDoc setUuid(@Nullable String s) { | |||
setField(UserIndexDefinition.FIELD_UUID, s); | |||
return this; | |||
} | |||
public UserDoc setLogin(@Nullable String s) { | |||
setField(UserIndexDefinition.FIELD_LOGIN, s); | |||
return this; |
@@ -22,10 +22,7 @@ package org.sonar.server.user.index; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.Optional; | |||
import javax.annotation.CheckForNull; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.elasticsearch.action.get.GetRequestBuilder; | |||
import org.elasticsearch.action.get.GetResponse; | |||
import org.elasticsearch.action.search.SearchRequestBuilder; | |||
import org.elasticsearch.index.query.BoolQueryBuilder; | |||
import org.elasticsearch.index.query.Operator; | |||
@@ -65,18 +62,6 @@ public class UserIndex { | |||
this.system2 = system2; | |||
} | |||
@CheckForNull | |||
public UserDoc getNullableByLogin(String login) { | |||
GetRequestBuilder request = esClient.prepareGet(UserIndexDefinition.INDEX_TYPE_USER, login) | |||
.setFetchSource(true) | |||
.setRouting(login); | |||
GetResponse response = request.get(); | |||
if (response.isExists()) { | |||
return new UserDoc(response.getSource()); | |||
} | |||
return null; | |||
} | |||
/** | |||
* Returns the active users (at most 3) who are associated to the given SCM account. This method can be used | |||
* to detect user conflicts. |
@@ -34,6 +34,7 @@ import static org.sonar.server.es.NewIndex.SettingsConfiguration.newBuilder; | |||
public class UserIndexDefinition implements IndexDefinition { | |||
public static final IndexType INDEX_TYPE_USER = new IndexType("users", "user"); | |||
public static final String FIELD_UUID = "uuid"; | |||
public static final String FIELD_LOGIN = "login"; | |||
public static final String FIELD_NAME = "name"; | |||
public static final String FIELD_EMAIL = "email"; | |||
@@ -56,6 +57,7 @@ public class UserIndexDefinition implements IndexDefinition { | |||
// type "user" | |||
NewIndex.NewIndexType mapping = index.createType(INDEX_TYPE_USER.getType()); | |||
mapping.keywordFieldBuilder(FIELD_UUID).disableNorms().build(); | |||
mapping.keywordFieldBuilder(FIELD_LOGIN).addSubFields(USER_SEARCH_GRAMS_ANALYZER).build(); | |||
mapping.keywordFieldBuilder(FIELD_NAME).addSubFields(USER_SEARCH_GRAMS_ANALYZER).build(); | |||
mapping.keywordFieldBuilder(FIELD_EMAIL).addSubFields(USER_SEARCH_GRAMS_ANALYZER, SORTABLE_ANALYZER).build(); |
@@ -20,7 +20,6 @@ | |||
package org.sonar.server.user.index; | |||
import com.google.common.collect.ArrayListMultimap; | |||
import com.google.common.collect.Collections2; | |||
import com.google.common.collect.ImmutableSet; | |||
import com.google.common.collect.ListMultimap; | |||
import com.google.common.collect.Maps; | |||
@@ -44,6 +43,7 @@ import org.sonar.server.es.ResilientIndexer; | |||
import static java.util.Collections.singletonList; | |||
import static org.sonar.core.util.stream.MoreCollectors.toHashSet; | |||
import static org.sonar.core.util.stream.MoreCollectors.toList; | |||
import static org.sonar.server.user.index.UserIndexDefinition.INDEX_TYPE_USER; | |||
public class UserIndexer implements ResilientIndexer { | |||
@@ -64,35 +64,32 @@ public class UserIndexer implements ResilientIndexer { | |||
@Override | |||
public void indexOnStartup(Set<IndexType> uninitializedIndexTypes) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
ListMultimap<String, String> organizationUuidsByLogin = ArrayListMultimap.create(); | |||
dbClient.organizationMemberDao().selectAllForUserIndexing(dbSession, organizationUuidsByLogin::put); | |||
ListMultimap<String, String> organizationUuidsByUserUuid = ArrayListMultimap.create(); | |||
dbClient.organizationMemberDao().selectAllForUserIndexing(dbSession, organizationUuidsByUserUuid::put); | |||
BulkIndexer bulkIndexer = newBulkIndexer(Size.LARGE, IndexingListener.FAIL_ON_ERROR); | |||
bulkIndexer.start(); | |||
dbClient.userDao().scrollAll(dbSession, | |||
// only index requests, no deletion requests. | |||
// Deactivated users are not deleted but updated. | |||
u -> bulkIndexer.add(newIndexRequest(u, organizationUuidsByLogin))); | |||
u -> bulkIndexer.add(newIndexRequest(u, organizationUuidsByUserUuid))); | |||
bulkIndexer.stop(); | |||
} | |||
} | |||
public void commitAndIndex(DbSession dbSession, UserDto user) { | |||
commitAndIndexByLogins(dbSession, singletonList(user.getLogin())); | |||
commitAndIndex(dbSession, singletonList(user)); | |||
} | |||
public void commitAndIndex(DbSession dbSession, Collection<UserDto> users) { | |||
commitAndIndexByLogins(dbSession, Collections2.transform(users, UserDto::getLogin)); | |||
} | |||
public void commitAndIndexByLogins(DbSession dbSession, Collection<String> logins) { | |||
List<EsQueueDto> items = logins.stream() | |||
.map(l -> EsQueueDto.create(INDEX_TYPE_USER.format(), l)) | |||
List<String> uuids = users.stream().map(UserDto::getUuid).collect(toList()); | |||
List<EsQueueDto> items = uuids.stream() | |||
.map(uuid -> EsQueueDto.create(INDEX_TYPE_USER.format(), uuid)) | |||
.collect(MoreCollectors.toArrayList()); | |||
dbClient.esQueueDao().insert(dbSession, items); | |||
dbSession.commit(); | |||
postCommit(dbSession, logins, items); | |||
postCommit(dbSession, users.stream().map(UserDto::getLogin).collect(toList()), items); | |||
} | |||
/** | |||
@@ -111,27 +108,27 @@ public class UserIndexer implements ResilientIndexer { | |||
if (items.isEmpty()) { | |||
return new IndexingResult(); | |||
} | |||
Set<String> logins = items | |||
Set<String> uuids = items | |||
.stream() | |||
.map(EsQueueDto::getDocId) | |||
.collect(toHashSet(items.size())); | |||
ListMultimap<String, String> organizationUuidsByLogin = ArrayListMultimap.create(); | |||
dbClient.organizationMemberDao().selectForUserIndexing(dbSession, logins, organizationUuidsByLogin::put); | |||
ListMultimap<String, String> organizationUuidsByUserUuid = ArrayListMultimap.create(); | |||
dbClient.organizationMemberDao().selectForUserIndexing(dbSession, uuids, organizationUuidsByUserUuid::put); | |||
BulkIndexer bulkIndexer = newBulkIndexer(Size.REGULAR, new OneToOneResilientIndexingListener(dbClient, dbSession, items)); | |||
bulkIndexer.start(); | |||
dbClient.userDao().scrollByLogins(dbSession, logins, | |||
dbClient.userDao().scrollByUuids(dbSession, uuids, | |||
// only index requests, no deletion requests. | |||
// Deactivated users are not deleted but updated. | |||
u -> { | |||
logins.remove(u.getLogin()); | |||
bulkIndexer.add(newIndexRequest(u, organizationUuidsByLogin)); | |||
uuids.remove(u.getUuid()); | |||
bulkIndexer.add(newIndexRequest(u, organizationUuidsByUserUuid)); | |||
}); | |||
// the remaining logins reference rows that don't exist in db. They must | |||
// the remaining uuids reference rows that don't exist in db. They must | |||
// be deleted from index. | |||
logins.forEach(l -> bulkIndexer.addDeletion(INDEX_TYPE_USER, l)); | |||
uuids.forEach(uuid -> bulkIndexer.addDeletion(INDEX_TYPE_USER, uuid)); | |||
return bulkIndexer.stop(); | |||
} | |||
@@ -139,15 +136,16 @@ public class UserIndexer implements ResilientIndexer { | |||
return new BulkIndexer(esClient, INDEX_TYPE_USER, bulkSize, listener); | |||
} | |||
private static IndexRequest newIndexRequest(UserDto user, ListMultimap<String, String> organizationUuidsByLogins) { | |||
private static IndexRequest newIndexRequest(UserDto user, ListMultimap<String, String> organizationUuidsByUserUuid) { | |||
UserDoc doc = new UserDoc(Maps.newHashMapWithExpectedSize(8)); | |||
// all the keys must be present, even if value is null | |||
doc.setUuid(user.getUuid()); | |||
doc.setLogin(user.getLogin()); | |||
doc.setName(user.getName()); | |||
doc.setEmail(user.getEmail()); | |||
doc.setActive(user.isActive()); | |||
doc.setScmAccounts(UserDto.decodeScmAccounts(user.getScmAccounts())); | |||
doc.setOrganizationUuids(organizationUuidsByLogins.get(user.getLogin())); | |||
doc.setOrganizationUuids(organizationUuidsByUserUuid.get(user.getUuid())); | |||
return new IndexRequest(INDEX_TYPE_USER.getIndex(), INDEX_TYPE_USER.getType()) | |||
.id(doc.getId()) |
@@ -28,10 +28,13 @@ import org.sonar.db.user.UserDto; | |||
import org.sonar.server.authentication.LocalAuthentication; | |||
import org.sonar.server.authentication.event.AuthenticationEvent; | |||
import org.sonar.server.authentication.event.AuthenticationException; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.user.UpdateUser; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonar.server.user.UserUpdater; | |||
import static java.lang.String.format; | |||
public class ChangePasswordAction implements UsersWsAction { | |||
private static final String PARAM_LOGIN = "login"; | |||
@@ -82,23 +85,31 @@ public class ChangePasswordAction implements UsersWsAction { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
String login = request.mandatoryParam(PARAM_LOGIN); | |||
UserDto user = getUser(dbSession, login); | |||
if (login.equals(userSession.getLogin())) { | |||
String previousPassword = request.mandatoryParam(PARAM_PREVIOUS_PASSWORD); | |||
checkCurrentPassword(dbSession, login, previousPassword); | |||
checkCurrentPassword(dbSession, user, previousPassword); | |||
} else { | |||
userSession.checkIsSystemAdministrator(); | |||
} | |||
String password = request.mandatoryParam(PARAM_PASSWORD); | |||
UpdateUser updateUser = UpdateUser.create(login).setPassword(password); | |||
userUpdater.updateAndCommit(dbSession, updateUser, u -> {}); | |||
UpdateUser updateUser = new UpdateUser().setPassword(password); | |||
userUpdater.updateAndCommit(dbSession, user, updateUser, u -> { | |||
}); | |||
} | |||
response.noContent(); | |||
} | |||
private void checkCurrentPassword(DbSession dbSession, String login, String password) { | |||
UserDto user = dbClient.userDao().selectOrFailByLogin(dbSession, login); | |||
private UserDto getUser(DbSession dbSession, String login) { | |||
UserDto user = dbClient.userDao().selectByLogin(dbSession, login); | |||
if (user == null || !user.isActive()) { | |||
throw new NotFoundException(format("User with login '%s' has not been found", login)); | |||
} | |||
return user; | |||
} | |||
private void checkCurrentPassword(DbSession dbSession, UserDto user, String password) { | |||
try { | |||
localAuthentication.authenticate(dbSession, user, password, AuthenticationEvent.Method.BASIC); | |||
} catch (AuthenticationException ex) { |
@@ -132,17 +132,24 @@ public class CreateAction implements UsersWsAction { | |||
private CreateWsResponse doHandle(CreateRequest request) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
String login = request.getLogin(); | |||
NewUser.Builder newUser = NewUser.builder() | |||
.setLogin(request.getLogin()) | |||
.setLogin(login) | |||
.setName(request.getName()) | |||
.setEmail(request.getEmail()) | |||
.setScmAccounts(request.getScmAccounts()) | |||
.setPassword(request.getPassword()); | |||
if (!request.isLocal()) { | |||
newUser.setExternalIdentity(new ExternalIdentity(SQ_AUTHORITY, request.getLogin())); | |||
newUser.setExternalIdentity(new ExternalIdentity(SQ_AUTHORITY, login, login)); | |||
} | |||
UserDto createdUser = userUpdater.createAndCommit(dbSession, newUser.build(), u -> {}); | |||
return buildResponse(createdUser); | |||
UserDto existingUser = dbClient.userDao().selectByLogin(dbSession, login); | |||
if (existingUser == null) { | |||
return buildResponse(userUpdater.createAndCommit(dbSession, newUser.build(), u -> { | |||
})); | |||
} | |||
checkArgument(!existingUser.isActive(), "An active user with login '%s' already exists", login); | |||
return buildResponse(userUpdater.reactivateAndCommit(dbSession, existingUser, newUser.build(), u -> { | |||
})); | |||
} | |||
} | |||
@@ -123,7 +123,7 @@ public class CurrentAction implements UsersWsAction { | |||
.setShowOnboardingTutorial(!user.isOnboarded()); | |||
setNullable(emptyToNull(user.getEmail()), builder::setEmail); | |||
setNullable(emptyToNull(user.getEmail()), u -> builder.setAvatar(avatarResolver.create(user))); | |||
setNullable(user.getExternalIdentity(), builder::setExternalIdentity); | |||
setNullable(user.getExternalLogin(), builder::setExternalIdentity); | |||
setNullable(user.getExternalIdentityProvider(), builder::setExternalProvider); | |||
return builder.build(); | |||
} |
@@ -150,7 +150,7 @@ public class SearchAction implements UsersWsAction { | |||
setIfNeeded(FIELD_AVATAR, fields, emptyToNull(user.getEmail()), u -> userBuilder.setAvatar(avatarResolver.create(user))); | |||
setIfNeeded(FIELD_ACTIVE, fields, user.isActive(), userBuilder::setActive); | |||
setIfNeeded(FIELD_LOCAL, fields, user.isLocal(), userBuilder::setLocal); | |||
setIfNeeded(FIELD_EXTERNAL_IDENTITY, fields, user.getExternalIdentity(), userBuilder::setExternalIdentity); | |||
setIfNeeded(FIELD_EXTERNAL_IDENTITY, fields, user.getExternalLogin(), userBuilder::setExternalIdentity); | |||
setIfNeeded(FIELD_EXTERNAL_PROVIDER, fields, user.getExternalIdentityProvider(), userBuilder::setExternalProvider); | |||
setIfNeeded(FIELD_TOKENS_COUNT, fields, tokensCount, userBuilder::setTokensCount); | |||
setIfNeeded(isNeeded(FIELD_SCM_ACCOUNTS, fields) && !user.getScmAccountsAsList().isEmpty(), user.getScmAccountsAsList(), |
@@ -33,20 +33,22 @@ import org.sonar.api.utils.text.JsonWriter; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.user.UpdateUser; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonar.server.user.UserUpdater; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static com.google.common.base.Preconditions.checkState; | |||
import static com.google.common.base.Strings.emptyToNull; | |||
import static com.google.common.base.Strings.isNullOrEmpty; | |||
import static java.lang.String.format; | |||
import static java.util.Collections.emptyList; | |||
import static java.util.Collections.singletonList; | |||
import static org.sonar.server.user.UserUpdater.EMAIL_MAX_LENGTH; | |||
import static org.sonar.server.user.UserUpdater.LOGIN_MAX_LENGTH; | |||
import static org.sonar.server.user.UserUpdater.NAME_MAX_LENGTH; | |||
import static org.sonar.server.user.ws.EmailValidator.isValidIfPresent; | |||
import static org.sonar.server.ws.WsUtils.checkFound; | |||
import static org.sonarqube.ws.client.user.UsersWsParameters.ACTION_UPDATE; | |||
import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_EMAIL; | |||
import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_LOGIN; | |||
@@ -113,14 +115,16 @@ public class UpdateAction implements UsersWsAction { | |||
UpdateRequest updateRequest = toWsRequest(request); | |||
checkArgument(isValidIfPresent(updateRequest.getEmail()), "Email '%s' is not valid", updateRequest.getEmail()); | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
doHandle(dbSession, toWsRequest(request)); | |||
writeUser(dbSession, response, updateRequest.getLogin()); | |||
UserDto user = getUser(dbSession, updateRequest.getLogin()); | |||
doHandle(dbSession, updateRequest); | |||
writeUser(dbSession, response, user.getUuid()); | |||
} | |||
} | |||
private void doHandle(DbSession dbSession, UpdateRequest request) { | |||
String login = request.getLogin(); | |||
UpdateUser updateUser = UpdateUser.create(login); | |||
UserDto user = getUser(dbSession, login); | |||
UpdateUser updateUser = new UpdateUser(); | |||
if (request.getName() != null) { | |||
updateUser.setName(request.getName()); | |||
} | |||
@@ -130,17 +134,25 @@ public class UpdateAction implements UsersWsAction { | |||
if (!request.getScmAccounts().isEmpty()) { | |||
updateUser.setScmAccounts(request.getScmAccounts()); | |||
} | |||
userUpdater.updateAndCommit(dbSession, updateUser, u -> { | |||
userUpdater.updateAndCommit(dbSession, user, updateUser, u -> { | |||
}); | |||
} | |||
private void writeUser(DbSession dbSession, Response response, String login) { | |||
private UserDto getUser(DbSession dbSession, String login) { | |||
UserDto user = dbClient.userDao().selectByLogin(dbSession, login); | |||
if (user == null || !user.isActive()) { | |||
throw new NotFoundException(format("User '%s' doesn't exist", login)); | |||
} | |||
return user; | |||
} | |||
private void writeUser(DbSession dbSession, Response response, String uuid) { | |||
try (JsonWriter json = response.newJsonWriter()) { | |||
json.beginObject(); | |||
json.name("user"); | |||
Set<String> groups = new HashSet<>(); | |||
UserDto user = checkFound(dbClient.userDao().selectByLogin(dbSession, login), "User '%s' doesn't exist", login); | |||
groups.addAll(dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, singletonList(login)).get(login)); | |||
UserDto user = dbClient.userDao().selectByUuid(dbSession, uuid); | |||
checkState(user != null, "User with uuid '%s' doesn't exist", uuid); | |||
Set<String> groups = new HashSet<>(dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, singletonList(uuid)).get(uuid)); | |||
userWriter.write(json, user, groups, UserJsonWriter.FIELDS); | |||
json.endObject().close(); | |||
} |
@@ -66,7 +66,7 @@ public class UserJsonWriter { | |||
writeIfNeeded(json, user.getEmail(), FIELD_EMAIL, fields); | |||
writeIfNeeded(json, user.isActive(), FIELD_ACTIVE, fields); | |||
writeIfNeeded(json, user.isLocal(), FIELD_LOCAL, fields); | |||
writeIfNeeded(json, user.getExternalIdentity(), FIELD_EXTERNAL_IDENTITY, fields); | |||
writeIfNeeded(json, user.getExternalLogin(), FIELD_EXTERNAL_IDENTITY, fields); | |||
writeIfNeeded(json, user.getExternalIdentityProvider(), FIELD_EXTERNAL_PROVIDER, fields); | |||
writeGroupsIfNeeded(json, groups, fields); | |||
writeScmAccountsIfNeeded(json, fields, user); |
@@ -218,7 +218,7 @@ public class InitFilterTest { | |||
@Test | |||
public void redirect_when_failing_because_of_EmailAlreadyExistException() throws Exception { | |||
UserDto existingUser = newUserDto().setEmail("john@email.com").setExternalIdentity("john.bitbucket").setExternalIdentityProvider("bitbucket"); | |||
UserDto existingUser = newUserDto().setEmail("john@email.com").setExternalLogin("john.bitbucket").setExternalIdentityProvider("bitbucket"); | |||
FailWithEmailAlreadyExistException identityProvider = new FailWithEmailAlreadyExistException("failing", existingUser); | |||
when(request.getRequestURI()).thenReturn("/sessions/init/" + identityProvider.getKey()); | |||
identityProviderRepository.addIdentityProvider(identityProvider); |
@@ -29,7 +29,6 @@ import org.junit.rules.ExpectedException; | |||
import org.mindrot.jbcrypt.BCrypt; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.db.user.UserTesting; | |||
import org.sonar.server.authentication.event.AuthenticationEvent; | |||
import org.sonar.server.authentication.event.AuthenticationException; | |||
@@ -123,8 +122,8 @@ public class LocalAuthenticationTest { | |||
String salt = DigestUtils.sha1Hex(saltRandom); | |||
UserDto user = newUserDto() | |||
.setHashMethod(SHA1.name()) | |||
.setCryptedPassword(null) | |||
.setHashMethod(SHA1.name()) | |||
.setSalt(salt); | |||
expectedException.expect(AuthenticationException.class); | |||
@@ -138,9 +137,9 @@ public class LocalAuthenticationTest { | |||
String password = randomAlphanumeric(60); | |||
UserDto user = newUserDto() | |||
.setSalt(null) | |||
.setHashMethod(SHA1.name()) | |||
.setCryptedPassword(DigestUtils.sha1Hex("--0242b0b4c0a93ddfe09dd886de50bc25ba000b51--" + password + "--")); | |||
.setCryptedPassword(DigestUtils.sha1Hex("--0242b0b4c0a93ddfe09dd886de50bc25ba000b51--" + password + "--")) | |||
.setSalt(null); | |||
expectedException.expect(AuthenticationException.class); | |||
expectedException.expectMessage("null salt"); |
@@ -194,7 +194,7 @@ public class OAuth2CallbackFilterTest { | |||
@Test | |||
public void redirect_when_failing_because_of_EmailAlreadyExistException() throws Exception { | |||
UserDto existingUser = newUserDto().setEmail("john@email.com").setExternalIdentity("john.bitbucket").setExternalIdentityProvider("bitbucket"); | |||
UserDto existingUser = newUserDto().setEmail("john@email.com").setExternalLogin("john.bitbucket").setExternalIdentityProvider("bitbucket"); | |||
FailWithEmailAlreadyExistException identityProvider = new FailWithEmailAlreadyExistException(existingUser); | |||
when(request.getRequestURI()).thenReturn("/oauth2/callback/" + identityProvider.getKey()); | |||
identityProviderRepository.addIdentityProvider(identityProvider); |
@@ -89,7 +89,7 @@ public class SsoAuthenticatorTest { | |||
.setLogin(DEFAULT_LOGIN) | |||
.setName(DEFAULT_NAME) | |||
.setEmail(DEFAULT_EMAIL) | |||
.setExternalIdentity(DEFAULT_LOGIN) | |||
.setExternalLogin(DEFAULT_LOGIN) | |||
.setExternalIdentityProvider("sonarqube"); | |||
private GroupDto group1; | |||
@@ -423,7 +423,7 @@ public class SsoAuthenticatorTest { | |||
assertThat(userDto.isActive()).isTrue(); | |||
assertThat(userDto.getName()).isEqualTo(expectedName); | |||
assertThat(userDto.getEmail()).isEqualTo(expectedEmail); | |||
assertThat(userDto.getExternalIdentity()).isEqualTo(expectedLogin); | |||
assertThat(userDto.getExternalLogin()).isEqualTo(expectedLogin); | |||
assertThat(userDto.getExternalIdentityProvider()).isEqualTo("sonarqube"); | |||
verityUserGroups(expectedLogin, expectedGroups); | |||
} |
@@ -60,6 +60,7 @@ public class UserIdentityAuthenticatorTest { | |||
private static String USER_LOGIN = "github-johndoo"; | |||
private static UserIdentity USER_IDENTITY = UserIdentity.builder() | |||
.setProviderId("ABCD") | |||
.setProviderLogin("johndoo") | |||
.setLogin(USER_LOGIN) | |||
.setName("John") | |||
@@ -110,8 +111,9 @@ public class UserIdentityAuthenticatorTest { | |||
assertThat(user.isActive()).isTrue(); | |||
assertThat(user.getName()).isEqualTo("John"); | |||
assertThat(user.getEmail()).isEqualTo("john@email.com"); | |||
assertThat(user.getExternalIdentity()).isEqualTo("johndoo"); | |||
assertThat(user.getExternalLogin()).isEqualTo("johndoo"); | |||
assertThat(user.getExternalIdentityProvider()).isEqualTo("github"); | |||
assertThat(user.getExternalId()).isEqualTo("ABCD"); | |||
assertThat(user.isRoot()).isFalse(); | |||
checkGroupMembership(user); | |||
} | |||
@@ -195,6 +197,23 @@ public class UserIdentityAuthenticatorTest { | |||
assertThat(existingUserReloaded.getEmail()).isNull(); | |||
} | |||
@Test | |||
public void external_id_is_set_to_provider_login_when_null() { | |||
organizationFlags.setEnabled(true); | |||
UserIdentity newUser = UserIdentity.builder() | |||
.setProviderId(null) | |||
.setLogin("john") | |||
.setProviderLogin("johndoo") | |||
.setName("JOhn") | |||
.build(); | |||
underTest.authenticate(newUser, IDENTITY_PROVIDER, Source.local(Method.BASIC), ALLOW); | |||
assertThat(db.users().selectUserByLogin(newUser.getLogin()).get()) | |||
.extracting(UserDto::getLogin, UserDto::getExternalId, UserDto::getExternalLogin) | |||
.contains("john", "johndoo", "johndoo"); | |||
} | |||
@Test | |||
public void throw_EmailAlreadyExistException_when_authenticating_new_user_when_email_already_exists_and_strategy_is_WARN() { | |||
organizationFlags.setEnabled(true); | |||
@@ -243,23 +262,84 @@ public class UserIdentityAuthenticatorTest { | |||
} | |||
@Test | |||
public void authenticate_existing_user() { | |||
public void authenticate_existing_user_matching_login() { | |||
db.users().insertUser(u -> u | |||
.setLogin(USER_LOGIN) | |||
.setName("Old name") | |||
.setEmail("Old email") | |||
.setExternalIdentity("old identity") | |||
.setExternalId("old id") | |||
.setExternalLogin("old identity") | |||
.setExternalIdentityProvider("old provide")); | |||
underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER, Source.local(Method.BASIC), FORBID); | |||
UserDto userDto = db.users().selectUserByLogin(USER_LOGIN).get(); | |||
assertThat(userDto.isActive()).isTrue(); | |||
assertThat(userDto.getName()).isEqualTo("John"); | |||
assertThat(userDto.getEmail()).isEqualTo("john@email.com"); | |||
assertThat(userDto.getExternalIdentity()).isEqualTo("johndoo"); | |||
assertThat(userDto.getExternalIdentityProvider()).isEqualTo("github"); | |||
assertThat(userDto.isRoot()).isFalse(); | |||
assertThat(db.users().selectUserByLogin(USER_LOGIN).get()) | |||
.extracting(UserDto::getName, UserDto::getEmail, UserDto::getExternalId, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider, UserDto::isActive) | |||
.contains("John", "john@email.com", "ABCD", "johndoo", "github", true); | |||
} | |||
@Test | |||
public void authenticate_existing_user_matching_external_id() { | |||
UserDto user = db.users().insertUser(u -> u | |||
.setLogin("Old login") | |||
.setName("Old name") | |||
.setEmail("Old email") | |||
.setExternalId(USER_IDENTITY.getProviderId()) | |||
.setExternalLogin("old identity") | |||
.setExternalIdentityProvider(IDENTITY_PROVIDER.getKey())); | |||
underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER, Source.local(Method.BASIC), FORBID); | |||
assertThat(db.users().selectUserByLogin("Old login")).isNotPresent(); | |||
assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid())) | |||
.extracting(UserDto::getLogin, UserDto::getName, UserDto::getEmail, UserDto::getExternalId, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider, | |||
UserDto::isActive) | |||
.contains(USER_LOGIN, "John", "john@email.com", "ABCD", "johndoo", "github", true); | |||
} | |||
@Test | |||
public void authenticate_existing_user_and_update_only_login() { | |||
UserDto user = db.users().insertUser(u -> u | |||
.setLogin("old login") | |||
.setName(USER_IDENTITY.getName()) | |||
.setEmail(USER_IDENTITY.getEmail()) | |||
.setExternalId(USER_IDENTITY.getProviderId()) | |||
.setExternalLogin("old identity") | |||
.setExternalIdentityProvider(IDENTITY_PROVIDER.getKey())); | |||
underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER, Source.local(Method.BASIC), FORBID); | |||
assertThat(db.users().selectUserByLogin("Old login")).isNotPresent(); | |||
assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid())) | |||
.extracting(UserDto::getLogin, UserDto::getName, UserDto::getEmail, UserDto::getExternalId, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider, | |||
UserDto::isActive) | |||
.containsExactlyInAnyOrder(USER_LOGIN, USER_IDENTITY.getName(), USER_IDENTITY.getEmail(), USER_IDENTITY.getProviderId(), USER_IDENTITY.getProviderLogin(), IDENTITY_PROVIDER.getKey(), | |||
true); | |||
} | |||
@Test | |||
public void authenticate_existing_user_matching_login_when_external_id_is_null() { | |||
UserDto user = db.users().insertUser(u -> u | |||
.setLogin(USER_LOGIN) | |||
.setName("Old name") | |||
.setEmail("Old email") | |||
.setExternalId("Old id") | |||
.setExternalLogin("old identity") | |||
.setExternalIdentityProvider(IDENTITY_PROVIDER.getKey())); | |||
underTest.authenticate(UserIdentity.builder() | |||
.setProviderId(null) | |||
.setProviderLogin("johndoo") | |||
.setLogin(USER_LOGIN) | |||
.setName("John") | |||
.setEmail("john@email.com") | |||
.build(), | |||
IDENTITY_PROVIDER, Source.local(Method.BASIC), FORBID); | |||
assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid())) | |||
.extracting(UserDto::getLogin, UserDto::getName, UserDto::getEmail, UserDto::getExternalId, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider, | |||
UserDto::isActive) | |||
.contains(user.getLogin(), "John", "john@email.com", "johndoo", "johndoo", "github", true); | |||
} | |||
@Test | |||
@@ -270,7 +350,8 @@ public class UserIdentityAuthenticatorTest { | |||
.setActive(false) | |||
.setName("Old name") | |||
.setEmail("Old email") | |||
.setExternalIdentity("old identity") | |||
.setExternalId("old id") | |||
.setExternalLogin("old identity") | |||
.setExternalIdentityProvider("old provide")); | |||
underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER, Source.local(Method.BASIC_TOKEN), FORBID); | |||
@@ -279,7 +360,8 @@ public class UserIdentityAuthenticatorTest { | |||
assertThat(userDto.isActive()).isTrue(); | |||
assertThat(userDto.getName()).isEqualTo("John"); | |||
assertThat(userDto.getEmail()).isEqualTo("john@email.com"); | |||
assertThat(userDto.getExternalIdentity()).isEqualTo("johndoo"); | |||
assertThat(userDto.getExternalId()).isEqualTo("ABCD"); | |||
assertThat(userDto.getExternalLogin()).isEqualTo("johndoo"); | |||
assertThat(userDto.getExternalIdentityProvider()).isEqualTo("github"); | |||
assertThat(userDto.isRoot()).isFalse(); | |||
} |
@@ -25,16 +25,16 @@ 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.organization.OrganizationDto; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Organization; | |||
import org.sonar.server.es.EsTester; | |||
import org.sonar.server.user.index.UserDoc; | |||
import org.sonar.server.user.index.UserIndex; | |||
import org.sonar.server.user.index.UserIndexDefinition; | |||
import org.sonar.server.user.index.UserIndexer; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.junit.Assert.fail; | |||
@@ -42,52 +42,41 @@ public class ScmAccountToUserLoaderTest { | |||
private static final String ORGANIZATION_UUID = "my-organization"; | |||
@Rule | |||
public DbTester db = DbTester.create(); | |||
@Rule | |||
public EsTester es = EsTester.create(); | |||
@Rule | |||
public LogTester logTester = new LogTester(); | |||
@Rule | |||
public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule() | |||
.setOrganization(Organization.from(new OrganizationDto().setUuid(ORGANIZATION_UUID).setKey("Key").setName("Name").setDefaultQualityGateUuid("QGate"))); | |||
public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule(); | |||
private UserIndexer userIndexer = new UserIndexer(db.getDbClient(), es.client()); | |||
@Test | |||
public void load_login_for_scm_account() { | |||
UserDoc user = new UserDoc() | |||
.setLogin("charlie") | |||
.setName("Charlie") | |||
.setEmail("charlie@hebdo.com") | |||
.setActive(true) | |||
.setScmAccounts(asList("charlie", "jesuis@charlie.com")) | |||
.setOrganizationUuids(singletonList(ORGANIZATION_UUID)); | |||
es.putDocuments(UserIndexDefinition.INDEX_TYPE_USER.getIndex(), UserIndexDefinition.INDEX_TYPE_USER.getType(), user); | |||
UserDto user = db.users().insertUser(u -> u.setScmAccounts(asList("charlie", "jesuis@charlie.com"))); | |||
OrganizationDto organization = db.organizations().insert(o -> o.setUuid(ORGANIZATION_UUID)); | |||
analysisMetadataHolder.setOrganization(Organization.from(organization)); | |||
db.organizations().addMember(organization, user); | |||
userIndexer.indexOnStartup(null); | |||
UserIndex index = new UserIndex(es.client(), System2.INSTANCE); | |||
ScmAccountToUserLoader underTest = new ScmAccountToUserLoader(index, analysisMetadataHolder); | |||
assertThat(underTest.load("missing")).isNull(); | |||
assertThat(underTest.load("jesuis@charlie.com")).isEqualTo("charlie"); | |||
assertThat(underTest.load("jesuis@charlie.com")).isEqualTo(user.getLogin()); | |||
} | |||
@Test | |||
public void warn_if_multiple_users_share_the_same_scm_account() { | |||
UserDoc user1 = new UserDoc() | |||
.setLogin("charlie") | |||
.setName("Charlie") | |||
.setEmail("charlie@hebdo.com") | |||
.setActive(true) | |||
.setScmAccounts(asList("charlie", "jesuis@charlie.com")) | |||
.setOrganizationUuids(singletonList(ORGANIZATION_UUID)); | |||
es.putDocuments(UserIndexDefinition.INDEX_TYPE_USER.getIndex(), UserIndexDefinition.INDEX_TYPE_USER.getType(), user1); | |||
UserDoc user2 = new UserDoc() | |||
.setLogin("another.charlie") | |||
.setName("Another Charlie") | |||
.setActive(true) | |||
.setScmAccounts(singletonList("charlie")) | |||
.setOrganizationUuids(singletonList(ORGANIZATION_UUID)); | |||
es.putDocuments(UserIndexDefinition.INDEX_TYPE_USER.getIndex(), UserIndexDefinition.INDEX_TYPE_USER.getType(), user2); | |||
UserDto user1 = db.users().insertUser(u -> u.setLogin("charlie").setScmAccounts(asList("charlie", "jesuis@charlie.com"))); | |||
UserDto user2 = db.users().insertUser(u -> u.setLogin("another.charlie").setScmAccounts(asList("charlie"))); | |||
OrganizationDto organization = db.organizations().insert(o -> o.setUuid(ORGANIZATION_UUID)); | |||
analysisMetadataHolder.setOrganization(Organization.from(organization)); | |||
db.organizations().addMember(organization, user1, user2); | |||
userIndexer.indexOnStartup(null); | |||
UserIndex index = new UserIndex(es.client(), System2.INSTANCE); | |||
ScmAccountToUserLoader underTest = new ScmAccountToUserLoader(index, analysisMetadataHolder); |
@@ -121,7 +121,7 @@ public class SendIssueNotificationsStepTest extends BaseStepTest { | |||
underTest = new SendIssueNotificationsStep(issueCache, ruleRepository, treeRootHolder, notificationService, analysisMetadataHolder, | |||
newIssuesNotificationFactory); | |||
when(newIssuesNotificationFactory.newNewIssuesNotication()).thenReturn(newIssuesNotificationMock); | |||
when(newIssuesNotificationFactory.newNewIssuesNotification()).thenReturn(newIssuesNotificationMock); | |||
when(newIssuesNotificationFactory.newMyNewIssuesNotification()).thenReturn(myNewIssuesNotificationMock); | |||
} | |||
@@ -21,25 +21,16 @@ package org.sonar.server.issue.notification; | |||
import java.io.IOException; | |||
import java.nio.charset.StandardCharsets; | |||
import java.util.Date; | |||
import java.util.Locale; | |||
import org.apache.commons.io.IOUtils; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.mockito.stubbing.Answer; | |||
import org.sonar.api.config.EmailSettings; | |||
import org.sonar.api.config.internal.MapSettings; | |||
import org.sonar.api.notifications.Notification; | |||
import org.sonar.core.i18n.DefaultI18n; | |||
import org.sonar.plugins.emailnotifications.api.EmailMessage; | |||
import org.sonar.server.user.index.UserDoc; | |||
import org.sonar.server.user.index.UserIndex; | |||
import org.sonar.server.i18n.I18nRule; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.anyString; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.COMPONENT; | |||
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.EFFORT; | |||
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.RULE; | |||
@@ -48,27 +39,15 @@ import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.TAG | |||
public class MyNewIssuesEmailTemplateTest { | |||
MyNewIssuesEmailTemplate underTest; | |||
DefaultI18n i18n; | |||
UserIndex userIndex; | |||
Date date; | |||
@Before | |||
public void setUp() { | |||
EmailSettings settings = mock(EmailSettings.class); | |||
when(settings.getServerBaseURL()).thenReturn("http://nemo.sonarsource.org"); | |||
i18n = mock(DefaultI18n.class); | |||
date = new Date(); | |||
userIndex = mock(UserIndex.class); | |||
// returns the login passed in parameter | |||
when(userIndex.getNullableByLogin(anyString())) | |||
.thenAnswer((Answer<UserDoc>) invocationOnMock -> new UserDoc().setName((String) invocationOnMock.getArguments()[0])); | |||
when(i18n.message(any(Locale.class), eq("issue.type.BUG"), anyString())).thenReturn("Bug"); | |||
when(i18n.message(any(Locale.class), eq("issue.type.CODE_SMELL"), anyString())).thenReturn("Code Smell"); | |||
when(i18n.message(any(Locale.class), eq("issue.type.VULNERABILITY"), anyString())).thenReturn("Vulnerability"); | |||
underTest = new MyNewIssuesEmailTemplate(settings, i18n); | |||
} | |||
@Rule | |||
public I18nRule i18n = new I18nRule() | |||
.put("issue.type.BUG", "Bug") | |||
.put("issue.type.CODE_SMELL", "Code Smell") | |||
.put("issue.type.VULNERABILITY", "Vulnerability"); | |||
private MapSettings settings = new MapSettings() | |||
.setProperty("sonar.core.serverBaseURL", "http://nemo.sonarsource.org"); | |||
private MyNewIssuesEmailTemplate underTest = new MyNewIssuesEmailTemplate(new EmailSettings(settings.asConfig()), i18n); | |||
@Test | |||
public void no_format_if_not_the_correct_notif() { |
@@ -22,7 +22,6 @@ package org.sonar.server.issue.notification; | |||
import org.junit.Test; | |||
import org.sonar.api.utils.Durations; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.server.user.index.UserIndex; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
@@ -30,7 +29,7 @@ import static org.sonar.server.issue.notification.AbstractNewIssuesEmailTemplate | |||
public class MyNewIssuesNotificationTest { | |||
MyNewIssuesNotification underTest = new MyNewIssuesNotification(mock(UserIndex.class), mock(DbClient.class), mock(Durations.class)); | |||
MyNewIssuesNotification underTest = new MyNewIssuesNotification(mock(DbClient.class), mock(Durations.class)); | |||
@Test | |||
public void set_assignee() { |
@@ -21,24 +21,16 @@ package org.sonar.server.issue.notification; | |||
import java.io.IOException; | |||
import java.nio.charset.StandardCharsets; | |||
import java.util.Locale; | |||
import org.apache.commons.io.IOUtils; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.mockito.stubbing.Answer; | |||
import org.sonar.api.config.EmailSettings; | |||
import org.sonar.api.config.internal.MapSettings; | |||
import org.sonar.api.notifications.Notification; | |||
import org.sonar.core.i18n.DefaultI18n; | |||
import org.sonar.plugins.emailnotifications.api.EmailMessage; | |||
import org.sonar.server.user.index.UserDoc; | |||
import org.sonar.server.user.index.UserIndex; | |||
import org.sonar.server.i18n.I18nRule; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.anyString; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.ASSIGNEE; | |||
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.COMPONENT; | |||
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.EFFORT; | |||
@@ -48,25 +40,15 @@ import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.TAG | |||
public class NewIssuesEmailTemplateTest { | |||
NewIssuesEmailTemplate template; | |||
DefaultI18n i18n; | |||
UserIndex userIndex; | |||
@Before | |||
public void setUp() { | |||
EmailSettings settings = mock(EmailSettings.class); | |||
when(settings.getServerBaseURL()).thenReturn("http://nemo.sonarsource.org"); | |||
i18n = mock(DefaultI18n.class); | |||
userIndex = mock(UserIndex.class); | |||
// returns the login passed in parameter | |||
when(userIndex.getNullableByLogin(anyString())) | |||
.thenAnswer((Answer<UserDoc>) invocationOnMock -> new UserDoc().setName((String) invocationOnMock.getArguments()[0])); | |||
when(i18n.message(any(Locale.class), eq("issue.type.CODE_SMELL"), anyString())).thenReturn("Code Smell"); | |||
when(i18n.message(any(Locale.class), eq("issue.type.VULNERABILITY"), anyString())).thenReturn("Vulnerability"); | |||
when(i18n.message(any(Locale.class), eq("issue.type.BUG"), anyString())).thenReturn("Bug"); | |||
template = new NewIssuesEmailTemplate(settings, i18n); | |||
} | |||
@Rule | |||
public I18nRule i18n = new I18nRule() | |||
.put("issue.type.BUG", "Bug") | |||
.put("issue.type.CODE_SMELL", "Code Smell") | |||
.put("issue.type.VULNERABILITY", "Vulnerability"); | |||
private MapSettings settings = new MapSettings() | |||
.setProperty("sonar.core.serverBaseURL", "http://nemo.sonarsource.org"); | |||
private NewIssuesEmailTemplate template = new NewIssuesEmailTemplate(new EmailSettings(settings.asConfig()), i18n); | |||
@Test | |||
public void no_format_is_not_the_correct_notification() { |
@@ -19,40 +19,27 @@ | |||
*/ | |||
package org.sonar.server.issue.notification; | |||
import com.google.common.collect.ImmutableList; | |||
import com.google.common.collect.ImmutableSet; | |||
import com.google.common.collect.Lists; | |||
import java.util.Arrays; | |||
import java.util.Collections; | |||
import java.util.Date; | |||
import java.util.Random; | |||
import java.util.stream.Collectors; | |||
import java.util.stream.IntStream; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.rules.RuleType; | |||
import org.sonar.api.utils.DateUtils; | |||
import org.sonar.api.utils.Duration; | |||
import org.sonar.api.utils.Durations; | |||
import org.sonar.core.issue.DefaultIssue; | |||
import org.sonar.core.util.stream.MoreCollectors; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDao; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.rule.RuleDao; | |||
import org.sonar.db.issue.IssueDto; | |||
import org.sonar.db.rule.RuleDefinitionDto; | |||
import org.sonar.server.user.index.UserIndex; | |||
import org.sonar.db.user.UserDto; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Collections.singletonList; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.anyBoolean; | |||
import static org.mockito.ArgumentMatchers.anyCollection; | |||
import static org.mockito.ArgumentMatchers.same; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.api.rules.RuleType.BUG; | |||
import static org.sonar.api.rules.RuleType.CODE_SMELL; | |||
import static org.sonar.db.component.ComponentTesting.newDirectory; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.ASSIGNEE; | |||
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.COMPONENT; | |||
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.EFFORT; | |||
@@ -62,24 +49,10 @@ import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.TAG | |||
public class NewIssuesNotificationTest { | |||
private final Random random = new Random(); | |||
private final RuleType randomRuleType = RuleType.values()[random.nextInt(RuleType.values().length)]; | |||
private NewIssuesStatistics.Stats stats = new NewIssuesStatistics.Stats(i -> true); | |||
private UserIndex userIndex = mock(UserIndex.class); | |||
private DbClient dbClient = mock(DbClient.class); | |||
private DbSession dbSession = mock(DbSession.class); | |||
private ComponentDao componentDao = mock(ComponentDao.class); | |||
private RuleDao ruleDao = mock(RuleDao.class); | |||
private Durations durations = mock(Durations.class); | |||
private NewIssuesNotification underTest = new NewIssuesNotification(userIndex, dbClient, durations); | |||
@Before | |||
public void setUp() throws Exception { | |||
when(dbClient.openSession(anyBoolean())).thenReturn(dbSession); | |||
when(dbClient.componentDao()).thenReturn(componentDao); | |||
when(dbClient.ruleDao()).thenReturn(ruleDao); | |||
when(componentDao.selectByUuids(same(dbSession), anyCollection())).thenReturn(Collections.emptyList()); | |||
} | |||
@Rule | |||
public DbTester db = DbTester.create(); | |||
private NewIssuesNotification underTest = new NewIssuesNotification(db.getDbClient(), new Durations()); | |||
@Test | |||
public void set_project_without_branch() { | |||
@@ -122,7 +95,6 @@ public class NewIssuesNotificationTest { | |||
underTest.setProjectVersion(null); | |||
assertThat(underTest.getFieldValue(NewIssuesEmailTemplate.FIELD_PROJECT_VERSION)).isNull(); | |||
} | |||
@Test | |||
@@ -136,19 +108,18 @@ public class NewIssuesNotificationTest { | |||
@Test | |||
public void set_statistics() { | |||
addIssueNTimes(newIssue1(), 5); | |||
addIssueNTimes(newIssue2(), 3); | |||
when(componentDao.selectByUuids(dbSession, ImmutableSet.of("file-uuid", "directory-uuid"))) | |||
.thenReturn(Arrays.asList( | |||
new ComponentDto().setUuid("file-uuid").setName("file-name"), | |||
new ComponentDto().setUuid("directory-uuid").setName("directory-name"))); | |||
RuleKey rule1 = RuleKey.of("SonarQube", "rule-the-world"); | |||
RuleKey rule2 = RuleKey.of("SonarQube", "rule-the-universe"); | |||
when(ruleDao.selectDefinitionByKeys(dbSession, ImmutableSet.of(rule1, rule2))) | |||
.thenReturn( | |||
ImmutableList.of(newRule(rule1, "Rule the World", "Java"), newRule(rule2, "Rule the Universe", "Clojure"))); | |||
underTest.setStatistics("project-long-name", stats); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto directory = db.components().insertComponent(newDirectory(project, "path")); | |||
ComponentDto file = db.components().insertComponent(newFileDto(directory)); | |||
RuleDefinitionDto rule1 = db.rules().insert(r -> r.setRepositoryKey("SonarQube").setRuleKey("rule1-the-world").setName("Rule the World").setLanguage("Java")); | |||
RuleDefinitionDto rule2 = db.rules().insert(r -> r.setRepositoryKey("SonarQube").setRuleKey("rule1-the-universe").setName("Rule the Universe").setLanguage("Clojure")); | |||
IssueDto issue1 = db.issues().insert(rule1, project, file, i -> i.setType(BUG).setAssignee("maynard").setTags(asList("bug", "owasp"))); | |||
IssueDto issue2 = db.issues().insert(rule2, project, directory, i -> i.setType(CODE_SMELL).setAssignee("keenan").setTags(singletonList("owasp"))); | |||
NewIssuesStatistics.Stats stats = new NewIssuesStatistics.Stats(i -> true); | |||
IntStream.rangeClosed(1, 5).forEach(i -> stats.add(issue1.toDefaultIssue())); | |||
IntStream.rangeClosed(1, 3).forEach(i -> stats.add(issue2.toDefaultIssue())); | |||
underTest.setStatistics(project.longName(), stats); | |||
assertThat(underTest.getFieldValue(RULE_TYPE + ".BUG.count")).isEqualTo("5"); | |||
assertThat(underTest.getFieldValue(RULE_TYPE + ".CODE_SMELL.count")).isEqualTo("3"); | |||
@@ -160,130 +131,150 @@ public class NewIssuesNotificationTest { | |||
assertThat(underTest.getFieldValue(TAG + ".1.count")).isEqualTo("8"); | |||
assertThat(underTest.getFieldValue(TAG + ".2.label")).isEqualTo("bug"); | |||
assertThat(underTest.getFieldValue(TAG + ".2.count")).isEqualTo("5"); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".1.label")).isEqualTo("file-name"); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".1.label")).isEqualTo(file.name()); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".1.count")).isEqualTo("5"); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".2.label")).isEqualTo("directory-name"); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".2.label")).isEqualTo(directory.name()); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".2.count")).isEqualTo("3"); | |||
assertThat(underTest.getFieldValue(RULE + ".1.label")).isEqualTo("Rule the World (Java)"); | |||
assertThat(underTest.getFieldValue(RULE + ".1.count")).isEqualTo("5"); | |||
assertThat(underTest.getFieldValue(RULE + ".2.label")).isEqualTo("Rule the Universe (Clojure)"); | |||
assertThat(underTest.getFieldValue(RULE + ".2.count")).isEqualTo("3"); | |||
assertThat(underTest.getDefaultMessage()).startsWith("8 new issues on project-long-name"); | |||
assertThat(underTest.getDefaultMessage()).startsWith("8 new issues on " + project.longName()); | |||
} | |||
@Test | |||
public void set_assignee() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | |||
RuleDefinitionDto rule = db.rules().insert(); | |||
UserDto user = db.users().insertUser(); | |||
IssueDto issue1 = db.issues().insert(rule, project, file, i -> i.setAssignee(user.getLogin())); | |||
IssueDto issue2 = db.issues().insert(rule, project, file, i -> i.setAssignee("no_user")); | |||
NewIssuesStatistics.Stats stats = new NewIssuesStatistics.Stats(i -> true); | |||
IntStream.rangeClosed(1, 5).forEach(i -> stats.add(issue1.toDefaultIssue())); | |||
IntStream.rangeClosed(1, 3).forEach(i -> stats.add(issue2.toDefaultIssue())); | |||
underTest.setStatistics(project.longName(), stats); | |||
assertThat(underTest.getFieldValue(ASSIGNEE + ".1.label")).isEqualTo(user.getName()); | |||
assertThat(underTest.getFieldValue(ASSIGNEE + ".1.count")).isEqualTo("5"); | |||
assertThat(underTest.getFieldValue(ASSIGNEE + ".2.label")).isEqualTo("no_user"); | |||
assertThat(underTest.getFieldValue(ASSIGNEE + ".2.count")).isEqualTo("3"); | |||
} | |||
@Test | |||
public void add_only_5_assignees_with_biggest_issue_counts() { | |||
String[] assignees = IntStream.range(0, 6 + random.nextInt(10)).mapToObj(s -> "assignee" + s).toArray(String[]::new); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | |||
RuleDefinitionDto rule = db.rules().insert(); | |||
NewIssuesStatistics.Stats stats = new NewIssuesStatistics.Stats(i -> true); | |||
int i = assignees.length; | |||
for (String assignee : assignees) { | |||
IntStream.range(0, i).mapToObj(j -> new DefaultIssue().setType(randomRuleType).setAssignee(assignee)).forEach(stats::add); | |||
i--; | |||
} | |||
underTest.setStatistics(randomAlphanumeric(20), stats); | |||
for (int j = 0; j < 5; j++) { | |||
String fieldBase = ASSIGNEE + "." + (j + 1); | |||
assertThat(underTest.getFieldValue(fieldBase + ".label")).as("label of %s", fieldBase).isEqualTo(assignees[j]); | |||
assertThat(underTest.getFieldValue(fieldBase + ".count")).as("count of %s", fieldBase).isEqualTo(String.valueOf(assignees.length - j)); | |||
} | |||
IntStream.rangeClosed(1, 10).forEach(i -> stats.add(db.issues().insert(rule, project, file, issue -> issue.setAssignee("assignee_1")).toDefaultIssue())); | |||
IntStream.rangeClosed(1, 9).forEach(i -> stats.add(db.issues().insert(rule, project, file, issue -> issue.setAssignee("assignee_2")).toDefaultIssue())); | |||
IntStream.rangeClosed(1, 8).forEach(i -> stats.add(db.issues().insert(rule, project, file, issue -> issue.setAssignee("assignee_3")).toDefaultIssue())); | |||
IntStream.rangeClosed(1, 7).forEach(i -> stats.add(db.issues().insert(rule, project, file, issue -> issue.setAssignee("assignee_4")).toDefaultIssue())); | |||
IntStream.rangeClosed(1, 6).forEach(i -> stats.add(db.issues().insert(rule, project, file, issue -> issue.setAssignee("assignee_5")).toDefaultIssue())); | |||
IntStream.rangeClosed(1, 5).forEach(i -> stats.add(db.issues().insert(rule, project, file, issue -> issue.setAssignee("assignee_6")).toDefaultIssue())); | |||
IntStream.rangeClosed(1, 4).forEach(i -> stats.add(db.issues().insert(rule, project, file, issue -> issue.setAssignee("assignee_7")).toDefaultIssue())); | |||
IntStream.rangeClosed(1, 3).forEach(i -> stats.add(db.issues().insert(rule, project, file, issue -> issue.setAssignee("assignee_8")).toDefaultIssue())); | |||
underTest.setStatistics(project.longName(), stats); | |||
assertThat(underTest.getFieldValue(ASSIGNEE + ".1.label")).isEqualTo("assignee_1"); | |||
assertThat(underTest.getFieldValue(ASSIGNEE + ".1.count")).isEqualTo("10"); | |||
assertThat(underTest.getFieldValue(ASSIGNEE + ".2.label")).isEqualTo("assignee_2"); | |||
assertThat(underTest.getFieldValue(ASSIGNEE + ".2.count")).isEqualTo("9"); | |||
assertThat(underTest.getFieldValue(ASSIGNEE + ".3.label")).isEqualTo("assignee_3"); | |||
assertThat(underTest.getFieldValue(ASSIGNEE + ".3.count")).isEqualTo("8"); | |||
assertThat(underTest.getFieldValue(ASSIGNEE + ".4.label")).isEqualTo("assignee_4"); | |||
assertThat(underTest.getFieldValue(ASSIGNEE + ".4.count")).isEqualTo("7"); | |||
assertThat(underTest.getFieldValue(ASSIGNEE + ".5.label")).isEqualTo("assignee_5"); | |||
assertThat(underTest.getFieldValue(ASSIGNEE + ".5.count")).isEqualTo("6"); | |||
assertThat(underTest.getFieldValue(ASSIGNEE + ".6.label")).isNull(); | |||
assertThat(underTest.getFieldValue(ASSIGNEE + ".6.count")).isNull(); | |||
} | |||
@Test | |||
public void add_only_5_components_with_biggest_issue_counts() { | |||
String[] componentUuids = IntStream.range(0, 6 + random.nextInt(10)).mapToObj(s -> "component_uuid_" + s).toArray(String[]::new); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
RuleDefinitionDto rule = db.rules().insert(); | |||
NewIssuesStatistics.Stats stats = new NewIssuesStatistics.Stats(i -> true); | |||
int i = componentUuids.length; | |||
for (String component : componentUuids) { | |||
IntStream.range(0, i).mapToObj(j -> new DefaultIssue().setType(randomRuleType).setComponentUuid(component)).forEach(stats::add); | |||
i--; | |||
} | |||
when(componentDao.selectByUuids(dbSession, Arrays.stream(componentUuids).limit(5).collect(Collectors.toSet()))) | |||
.thenReturn( | |||
Arrays.stream(componentUuids).map(uuid -> new ComponentDto().setUuid(uuid).setName("name_" + uuid)).collect(MoreCollectors.toList())); | |||
underTest.setStatistics(randomAlphanumeric(20), stats); | |||
for (int j = 0; j < 5; j++) { | |||
String fieldBase = COMPONENT + "." + (j + 1); | |||
assertThat(underTest.getFieldValue(fieldBase + ".label")).as("label of %s", fieldBase).isEqualTo("name_" + componentUuids[j]); | |||
assertThat(underTest.getFieldValue(fieldBase + ".count")).as("count of %s", fieldBase).isEqualTo(String.valueOf(componentUuids.length - j)); | |||
} | |||
ComponentDto file1 = db.components().insertComponent(newFileDto(project)); | |||
IntStream.rangeClosed(1, 10).forEach(i -> stats.add(db.issues().insert(rule, project, file1).toDefaultIssue())); | |||
ComponentDto file2 = db.components().insertComponent(newFileDto(project)); | |||
IntStream.rangeClosed(1, 9).forEach(i -> stats.add(db.issues().insert(rule, project, file2).toDefaultIssue())); | |||
ComponentDto file3 = db.components().insertComponent(newFileDto(project)); | |||
IntStream.rangeClosed(1, 8).forEach(i -> stats.add(db.issues().insert(rule, project, file3).toDefaultIssue())); | |||
ComponentDto file4 = db.components().insertComponent(newFileDto(project)); | |||
IntStream.rangeClosed(1, 7).forEach(i -> stats.add(db.issues().insert(rule, project, file4).toDefaultIssue())); | |||
ComponentDto file5 = db.components().insertComponent(newFileDto(project)); | |||
IntStream.rangeClosed(1, 6).forEach(i -> stats.add(db.issues().insert(rule, project, file5).toDefaultIssue())); | |||
ComponentDto file6 = db.components().insertComponent(newFileDto(project)); | |||
IntStream.rangeClosed(1, 5).forEach(i -> stats.add(db.issues().insert(rule, project, file6).toDefaultIssue())); | |||
ComponentDto file7 = db.components().insertComponent(newFileDto(project)); | |||
IntStream.rangeClosed(1, 4).forEach(i -> stats.add(db.issues().insert(rule, project, file7).toDefaultIssue())); | |||
ComponentDto file8 = db.components().insertComponent(newFileDto(project)); | |||
IntStream.rangeClosed(1, 3).forEach(i -> stats.add(db.issues().insert(rule, project, file8).toDefaultIssue())); | |||
underTest.setStatistics(project.longName(), stats); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".1.label")).isEqualTo(file1.name()); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".1.count")).isEqualTo("10"); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".2.label")).isEqualTo(file2.name()); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".2.count")).isEqualTo("9"); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".3.label")).isEqualTo(file3.name()); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".3.count")).isEqualTo("8"); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".4.label")).isEqualTo(file4.name()); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".4.count")).isEqualTo("7"); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".5.label")).isEqualTo(file5.name()); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".5.count")).isEqualTo("6"); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".6.label")).isNull(); | |||
assertThat(underTest.getFieldValue(COMPONENT + ".6.count")).isNull(); | |||
} | |||
@Test | |||
public void add_only_5_rules_with_biggest_issue_counts() { | |||
String repository = randomAlphanumeric(4); | |||
String[] ruleKeys = IntStream.range(0, 6 + random.nextInt(10)).mapToObj(s -> "rule_" + s).toArray(String[]::new); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | |||
NewIssuesStatistics.Stats stats = new NewIssuesStatistics.Stats(i -> true); | |||
int i = ruleKeys.length; | |||
for (String ruleKey : ruleKeys) { | |||
IntStream.range(0, i).mapToObj(j -> new DefaultIssue().setType(randomRuleType).setRuleKey(RuleKey.of(repository, ruleKey))).forEach(stats::add); | |||
i--; | |||
} | |||
when(ruleDao.selectDefinitionByKeys(dbSession, Arrays.stream(ruleKeys).limit(5).map(s -> RuleKey.of(repository, s)).collect(MoreCollectors.toSet(5)))) | |||
.thenReturn( | |||
Arrays.stream(ruleKeys).limit(5).map(ruleKey -> new RuleDefinitionDto() | |||
.setRuleKey(RuleKey.of(repository, ruleKey)) | |||
.setName("name_" + ruleKey) | |||
.setLanguage("language_" + ruleKey)) | |||
.collect(MoreCollectors.toList(5))); | |||
underTest.setStatistics(randomAlphanumeric(20), stats); | |||
for (int j = 0; j < 5; j++) { | |||
String fieldBase = RULE + "." + (j + 1); | |||
assertThat(underTest.getFieldValue(fieldBase + ".label")).as("label of %s", fieldBase).isEqualTo("name_" + ruleKeys[j] + " (language_" + ruleKeys[j] + ")"); | |||
assertThat(underTest.getFieldValue(fieldBase + ".count")).as("count of %s", fieldBase).isEqualTo(String.valueOf(ruleKeys.length - j)); | |||
} | |||
RuleDefinitionDto rule1 = db.rules().insert(r -> r.setLanguage("Java")); | |||
IntStream.rangeClosed(1, 10).forEach(i -> stats.add(db.issues().insert(rule1, project, file).toDefaultIssue())); | |||
RuleDefinitionDto rule2 = db.rules().insert(r -> r.setLanguage("Java")); | |||
IntStream.rangeClosed(1, 9).forEach(i -> stats.add(db.issues().insert(rule2, project, file).toDefaultIssue())); | |||
RuleDefinitionDto rule3 = db.rules().insert(r -> r.setLanguage("Java")); | |||
IntStream.rangeClosed(1, 8).forEach(i -> stats.add(db.issues().insert(rule3, project, file).toDefaultIssue())); | |||
RuleDefinitionDto rule4 = db.rules().insert(r -> r.setLanguage("Java")); | |||
IntStream.rangeClosed(1, 7).forEach(i -> stats.add(db.issues().insert(rule4, project, file).toDefaultIssue())); | |||
RuleDefinitionDto rule5 = db.rules().insert(r -> r.setLanguage("Java")); | |||
IntStream.rangeClosed(1, 6).forEach(i -> stats.add(db.issues().insert(rule5, project, file).toDefaultIssue())); | |||
RuleDefinitionDto rule6 = db.rules().insert(r -> r.setLanguage("Java")); | |||
IntStream.rangeClosed(1, 5).forEach(i -> stats.add(db.issues().insert(rule6, project, file).toDefaultIssue())); | |||
RuleDefinitionDto rule7 = db.rules().insert(r -> r.setLanguage("Java")); | |||
IntStream.rangeClosed(1, 4).forEach(i -> stats.add(db.issues().insert(rule7, project, file).toDefaultIssue())); | |||
RuleDefinitionDto rule8 = db.rules().insert(r -> r.setLanguage("Java")); | |||
IntStream.rangeClosed(1, 3).forEach(i -> stats.add(db.issues().insert(rule8, project, file).toDefaultIssue())); | |||
underTest.setStatistics(project.longName(), stats); | |||
String javaSuffix = " (Java)"; | |||
assertThat(underTest.getFieldValue(RULE + ".1.label")).isEqualTo(rule1.getName() + javaSuffix); | |||
assertThat(underTest.getFieldValue(RULE + ".1.count")).isEqualTo("10"); | |||
assertThat(underTest.getFieldValue(RULE + ".2.label")).isEqualTo(rule2.getName() + javaSuffix); | |||
assertThat(underTest.getFieldValue(RULE + ".2.count")).isEqualTo("9"); | |||
assertThat(underTest.getFieldValue(RULE + ".3.label")).isEqualTo(rule3.getName() + javaSuffix); | |||
assertThat(underTest.getFieldValue(RULE + ".3.count")).isEqualTo("8"); | |||
assertThat(underTest.getFieldValue(RULE + ".4.label")).isEqualTo(rule4.getName() + javaSuffix); | |||
assertThat(underTest.getFieldValue(RULE + ".4.count")).isEqualTo("7"); | |||
assertThat(underTest.getFieldValue(RULE + ".5.label")).isEqualTo(rule5.getName() + javaSuffix); | |||
assertThat(underTest.getFieldValue(RULE + ".5.count")).isEqualTo("6"); | |||
assertThat(underTest.getFieldValue(RULE + ".6.label")).isNull(); | |||
assertThat(underTest.getFieldValue(RULE + ".6.count")).isNull(); | |||
} | |||
@Test | |||
public void set_debt() { | |||
when(durations.format(any(Duration.class))).thenReturn("55 min"); | |||
underTest.setDebt(Duration.create(55)); | |||
assertThat(underTest.getFieldValue(EFFORT + ".count")).isEqualTo("55 min"); | |||
} | |||
private void addIssueNTimes(DefaultIssue issue, int times) { | |||
for (int i = 0; i < times; i++) { | |||
stats.add(issue); | |||
} | |||
assertThat(underTest.getFieldValue(EFFORT + ".count")).isEqualTo("55min"); | |||
} | |||
private DefaultIssue newIssue1() { | |||
return new DefaultIssue() | |||
.setAssignee("maynard") | |||
.setComponentUuid("file-uuid") | |||
.setType(RuleType.BUG) | |||
.setTags(Lists.newArrayList("bug", "owasp")) | |||
.setRuleKey(RuleKey.of("SonarQube", "rule-the-world")) | |||
.setEffort(Duration.create(5L)); | |||
} | |||
private DefaultIssue newIssue2() { | |||
return new DefaultIssue() | |||
.setAssignee("keenan") | |||
.setComponentUuid("directory-uuid") | |||
.setType(RuleType.CODE_SMELL) | |||
.setTags(Lists.newArrayList("owasp")) | |||
.setRuleKey(RuleKey.of("SonarQube", "rule-the-universe")) | |||
.setEffort(Duration.create(10L)); | |||
} | |||
private RuleDefinitionDto newRule(RuleKey ruleKey, String name, String language) { | |||
return new RuleDefinitionDto() | |||
.setRuleKey(ruleKey) | |||
.setName(name) | |||
.setLanguage(language); | |||
} | |||
} |
@@ -51,7 +51,6 @@ import org.sonar.db.protobuf.DbIssues; | |||
import org.sonar.db.rule.RuleDto; | |||
import org.sonar.db.rule.RuleTesting; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.db.user.UserTesting; | |||
import org.sonar.server.es.EsTester; | |||
import org.sonar.server.es.SearchOptions; | |||
import org.sonar.server.es.StartupIndexer; | |||
@@ -77,7 +76,6 @@ import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.groups.Tuple.tuple; | |||
import static org.sonar.api.web.UserRole.ISSUE_ADMIN; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
import static org.sonar.db.user.UserTesting.newUserDto; | |||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BRANCH; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.DEPRECATED_FACET_MODE_DEBT; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.FACET_MODE_EFFORT; | |||
@@ -570,7 +568,7 @@ public class SearchActionTest { | |||
@Test | |||
public void filter_by_assigned_to_me() { | |||
dbClient.userDao().insert(session, newUserDto().setLogin("john").setName("John").setEmail("john@email.com")); | |||
db.users().insertUser(u -> u.setLogin("john").setName("John").setEmail("john@email.com")); | |||
ComponentDto project = insertComponent(ComponentTesting.newPublicProjectDto(defaultOrganization, "PROJECT_ID").setDbKey("PROJECT_KEY")); | |||
indexPermissions(); | |||
@@ -644,7 +642,7 @@ public class SearchActionTest { | |||
@Test | |||
public void assigned_to_me_facet_is_sticky_relative_to_assignees() { | |||
dbClient.userDao().insert(session, newUserDto().setLogin("alice").setName("Alice").setEmail("alice@email.com")); | |||
db.users().insertUser(u -> u.setLogin("alice").setName("Alice").setEmail("alice@email.com")); | |||
ComponentDto project = insertComponent(ComponentTesting.newPublicProjectDto(otherOrganization2, "PROJECT_ID").setDbKey("PROJECT_KEY")); | |||
indexPermissions(); |
@@ -40,8 +40,6 @@ import org.sonar.db.metric.MetricDto; | |||
import org.sonar.db.metric.MetricTesting; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.permission.OrganizationPermission; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.db.user.UserTesting; | |||
import org.sonar.server.component.TestComponentFinder; | |||
import org.sonar.server.es.EsTester; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
@@ -60,7 +58,6 @@ import static org.sonar.api.measures.Metric.ValueType.INT; | |||
import static org.sonar.api.measures.Metric.ValueType.LEVEL; | |||
import static org.sonar.api.measures.Metric.ValueType.STRING; | |||
import static org.sonar.api.measures.Metric.ValueType.WORK_DUR; | |||
import static org.sonar.db.user.UserTesting.newUserDto; | |||
import static org.sonar.server.util.TypeValidationsTesting.newFullTypeValidations; | |||
public class CreateActionTest { | |||
@@ -87,12 +84,10 @@ public class CreateActionTest { | |||
ws = new WsTester(new CustomMeasuresWs(new CreateAction(dbClient, userSession, System2.INSTANCE, new CustomMeasureValidator(newFullTypeValidations()), | |||
new CustomMeasureJsonWriter(new UserJsonWriter(userSession)), TestComponentFinder.from(db)))); | |||
db.getDbClient().userDao().insert(dbSession, newUserDto() | |||
.setLogin("login") | |||
db.users().insertUser(u -> u.setLogin("login") | |||
.setName("Login") | |||
.setEmail("login@login.com") | |||
.setActive(true)); | |||
dbSession.commit(); | |||
OrganizationDto organizationDto = db.organizations().insert(); | |||
project = ComponentTesting.newPrivateProjectDto(organizationDto, DEFAULT_PROJECT_UUID).setDbKey(DEFAULT_PROJECT_KEY); |
@@ -37,8 +37,6 @@ import org.sonar.server.component.TestComponentFinder; | |||
import org.sonar.server.es.EsTester; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.user.index.UserDoc; | |||
import org.sonar.server.user.index.UserIndexDefinition; | |||
import org.sonar.server.ws.WsTester; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
@@ -47,7 +45,6 @@ import static org.sonar.db.metric.MetricTesting.newMetricDto; | |||
import static org.sonar.server.measure.custom.ws.CustomMeasuresWs.ENDPOINT; | |||
import static org.sonar.server.measure.custom.ws.MetricsAction.ACTION; | |||
public class MetricsActionTest { | |||
private static final String DEFAULT_PROJECT_UUID = "project-uuid"; | |||
private static final String DEFAULT_PROJECT_KEY = "project-key"; | |||
@@ -63,19 +60,14 @@ public class MetricsActionTest { | |||
private final DbClient dbClient = db.getDbClient(); | |||
private final DbSession dbSession = db.getSession(); | |||
private WsTester ws; | |||
private ComponentDto defaultProject; | |||
private WsTester ws; | |||
@Before | |||
public void setUp() throws Exception { | |||
es.putDocuments(UserIndexDefinition.INDEX_TYPE_USER.getIndex(), UserIndexDefinition.INDEX_TYPE_USER.getType(), new UserDoc() | |||
.setLogin("login") | |||
.setName("Login") | |||
.setEmail("login@login.com") | |||
.setActive(true)); | |||
ws = new WsTester(new CustomMeasuresWs(new MetricsAction(dbClient, userSession, TestComponentFinder.from(db)))); | |||
defaultProject = insertDefaultProject(); | |||
userSession.logIn().addProjectPermission(UserRole.ADMIN, defaultProject); | |||
ws = new WsTester(new CustomMeasuresWs(new MetricsAction(dbClient, userSession, TestComponentFinder.from(db)))); | |||
} | |||
@Test |
@@ -38,8 +38,6 @@ import org.sonar.db.component.ComponentTesting; | |||
import org.sonar.db.component.SnapshotTesting; | |||
import org.sonar.db.measure.custom.CustomMeasureDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.db.user.UserTesting; | |||
import org.sonar.server.component.TestComponentFinder; | |||
import org.sonar.server.es.EsTester; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
@@ -51,7 +49,6 @@ import org.sonar.server.ws.WsTester; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.db.measure.custom.CustomMeasureTesting.newCustomMeasureDto; | |||
import static org.sonar.db.metric.MetricTesting.newMetricDto; | |||
import static org.sonar.db.user.UserTesting.newUserDto; | |||
public class SearchActionTest { | |||
@@ -79,14 +76,10 @@ public class SearchActionTest { | |||
ws = new WsTester(new CustomMeasuresWs(new SearchAction(dbClient, customMeasureJsonWriter, userSessionRule, TestComponentFinder.from(db)))); | |||
defaultProject = insertDefaultProject(); | |||
userSessionRule.logIn().addProjectPermission(UserRole.ADMIN, defaultProject); | |||
db.getDbClient().userDao().insert(dbSession, newUserDto() | |||
.setLogin("login") | |||
db.users().insertUser(u -> u.setLogin("login") | |||
.setName("Login") | |||
.setEmail("login@login.com") | |||
.setActive(true) | |||
); | |||
dbSession.commit(); | |||
.setActive(true)); | |||
} | |||
@Test |
@@ -36,8 +36,6 @@ import org.sonar.db.measure.custom.CustomMeasureDto; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.db.metric.MetricTesting; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.db.user.UserTesting; | |||
import org.sonar.server.es.EsTester; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.exceptions.ServerException; | |||
@@ -51,7 +49,6 @@ import static org.assertj.core.data.Offset.offset; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.db.measure.custom.CustomMeasureTesting.newCustomMeasureDto; | |||
import static org.sonar.db.user.UserTesting.newUserDto; | |||
import static org.sonar.server.measure.custom.ws.UpdateAction.PARAM_DESCRIPTION; | |||
import static org.sonar.server.measure.custom.ws.UpdateAction.PARAM_ID; | |||
import static org.sonar.server.measure.custom.ws.UpdateAction.PARAM_VALUE; | |||
@@ -78,8 +75,7 @@ public class UpdateActionTest { | |||
ws = new WsTester(new CustomMeasuresWs(new UpdateAction(dbClient, userSessionRule, system, validator, new CustomMeasureJsonWriter(new UserJsonWriter(userSessionRule))))); | |||
db.getDbClient().userDao().insert(dbSession, newUserDto() | |||
.setLogin("login") | |||
db.users().insertUser(u -> u.setLogin("login") | |||
.setName("Login") | |||
.setEmail("login@login.com") | |||
.setActive(true) |
@@ -55,6 +55,7 @@ import org.sonar.server.organization.TestOrganizationFlags; | |||
import org.sonar.server.qualityprofile.BuiltInQProfileRepository; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.user.index.UserIndex; | |||
import org.sonar.server.user.index.UserIndexDefinition; | |||
import org.sonar.server.user.index.UserIndexer; | |||
import org.sonar.server.usergroups.DefaultGroupCreatorImpl; | |||
import org.sonar.server.ws.TestRequest; | |||
@@ -65,12 +66,16 @@ import org.sonarqube.ws.Organizations.Organization; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.elasticsearch.index.query.QueryBuilders.boolQuery; | |||
import static org.elasticsearch.index.query.QueryBuilders.termQuery; | |||
import static org.mockito.Mockito.mock; | |||
import static org.sonar.core.config.CorePropertyDefinitions.ORGANIZATIONS_ANYONE_CAN_CREATE; | |||
import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_KEY; | |||
import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_NAME; | |||
import static org.sonar.server.organization.ws.OrganizationsWsTestSupport.STRING_257_CHARS_LONG; | |||
import static org.sonar.server.organization.ws.OrganizationsWsTestSupport.STRING_65_CHARS_LONG; | |||
import static org.sonar.server.user.index.UserIndexDefinition.FIELD_ORGANIZATION_UUIDS; | |||
import static org.sonar.server.user.index.UserIndexDefinition.FIELD_UUID; | |||
import static org.sonar.test.JsonAssert.assertJson; | |||
public class CreateActionTest { | |||
@@ -362,7 +367,7 @@ public class CreateActionTest { | |||
} | |||
@Test | |||
public void request_set_user_as_member_of_organization() { | |||
public void set_user_as_member_of_organization() { | |||
UserDto user = dbTester.users().insertUser(); | |||
userSession.logIn(user).setSystemAdministrator(); | |||
dbTester.qualityGates().insertBuiltInQualityGate(); | |||
@@ -371,7 +376,10 @@ public class CreateActionTest { | |||
OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, "bar").get(); | |||
assertThat(dbClient.organizationMemberDao().select(dbSession, organization.getUuid(), user.getId())).isPresent(); | |||
assertThat(userIndex.getNullableByLogin(user.getLogin()).organizationUuids()).contains(organization.getUuid()); | |||
assertThat(es.client().prepareSearch(UserIndexDefinition.INDEX_TYPE_USER) | |||
.setQuery(boolQuery() | |||
.must(termQuery(FIELD_ORGANIZATION_UUIDS, organization.getUuid())) | |||
.must(termQuery(FIELD_UUID, user.getUuid()))).get().getHits().getHits()).hasSize(1); | |||
} | |||
@Test | |||
@@ -603,7 +611,7 @@ public class CreateActionTest { | |||
} | |||
private static void populateRequest(@Nullable String name, @Nullable String key, @Nullable String description, @Nullable String url, @Nullable String avatar, | |||
TestRequest request) { | |||
TestRequest request) { | |||
OrganizationsWsTestSupport.setParam(request, "name", name); | |||
OrganizationsWsTestSupport.setParam(request, "key", key); | |||
OrganizationsWsTestSupport.setParam(request, "description", description); |
@@ -21,6 +21,7 @@ package org.sonar.server.organization.ws; | |||
import java.util.HashSet; | |||
import javax.annotation.Nullable; | |||
import org.elasticsearch.action.search.SearchRequestBuilder; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
@@ -47,6 +48,7 @@ import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.user.index.UserIndex; | |||
import org.sonar.server.user.index.UserIndexDefinition; | |||
import org.sonar.server.user.index.UserIndexer; | |||
import org.sonar.server.user.index.UserQuery; | |||
import org.sonar.server.ws.TestRequest; | |||
@@ -57,6 +59,8 @@ import static java.net.HttpURLConnection.HTTP_NO_CONTENT; | |||
import static java.util.Arrays.asList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.groups.Tuple.tuple; | |||
import static org.elasticsearch.index.query.QueryBuilders.boolQuery; | |||
import static org.elasticsearch.index.query.QueryBuilders.termQuery; | |||
import static org.sonar.api.CoreProperties.DEFAULT_ISSUE_ASSIGNEE; | |||
import static org.sonar.api.web.UserRole.CODEVIEWER; | |||
import static org.sonar.api.web.UserRole.USER; | |||
@@ -65,6 +69,8 @@ import static org.sonar.db.permission.OrganizationPermission.ADMINISTER; | |||
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_GATES; | |||
import static org.sonar.db.permission.OrganizationPermission.SCAN; | |||
import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_ORGANIZATION; | |||
import static org.sonar.server.user.index.UserIndexDefinition.FIELD_ORGANIZATION_UUIDS; | |||
import static org.sonar.server.user.index.UserIndexDefinition.FIELD_UUID; | |||
public class RemoveMemberActionTest { | |||
@Rule | |||
@@ -367,12 +373,30 @@ public class RemoveMemberActionTest { | |||
private void assertNotAMember(String organizationUuid, UserDto user) { | |||
assertThat(dbClient.organizationMemberDao().select(dbSession, organizationUuid, user.getId())).isNotPresent(); | |||
assertThat(userIndex.search(UserQuery.builder().setOrganizationUuid(organizationUuid).setTextQuery(user.getLogin()).build(), new SearchOptions()).getDocs()).isEmpty(); | |||
assertMemberInIndex(organizationUuid, user, false); | |||
} | |||
private void assertMember(String organizationUuid, UserDto user) { | |||
assertThat(dbClient.organizationMemberDao().select(dbSession, organizationUuid, user.getId())).isPresent(); | |||
assertThat(userIndex.getNullableByLogin(user.getLogin()).organizationUuids()).contains(organizationUuid); | |||
assertThat(userIndex.search(UserQuery.builder() | |||
.setOrganizationUuid(organizationUuid) | |||
.setTextQuery(user.getLogin()) | |||
.build(), | |||
new SearchOptions()).getDocs()) | |||
.hasSize(1); | |||
assertMemberInIndex(organizationUuid, user, true); | |||
} | |||
private void assertMemberInIndex(String organizationUuid, UserDto user, boolean isMember) { | |||
SearchRequestBuilder request = es.client().prepareSearch(UserIndexDefinition.INDEX_TYPE_USER) | |||
.setQuery(boolQuery() | |||
.must(termQuery(FIELD_ORGANIZATION_UUIDS, organizationUuid)) | |||
.must(termQuery(FIELD_UUID, user.getUuid()))); | |||
if (isMember) { | |||
assertThat(request.get().getHits().getHits()).hasSize(1); | |||
} else { | |||
assertThat(request.get().getHits().getHits()).isEmpty(); | |||
} | |||
} | |||
private void assertOrgPermissionsOfUser(UserDto user, OrganizationDto organization, OrganizationPermission... permissions) { |
@@ -26,58 +26,41 @@ import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.user.UserDto; | |||
import static org.hamcrest.CoreMatchers.is; | |||
import static org.hamcrest.CoreMatchers.nullValue; | |||
import static org.junit.Assert.assertThat; | |||
import static org.sonar.db.DbTester.create; | |||
import static org.assertj.core.api.Java6Assertions.assertThat; | |||
public class DeprecatedUserFinderTest { | |||
@Rule | |||
public DbTester dbTester = create(System2.INSTANCE); | |||
private DeprecatedUserFinder underTest = new DeprecatedUserFinder(dbTester.getDbClient()); | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
private DeprecatedUserFinder underTest = new DeprecatedUserFinder(db.getDbClient()); | |||
@Test | |||
public void shouldFindUserByLogin() { | |||
UserDto user1 = db.users().insertUser(); | |||
UserDto user2 = db.users().insertUser(); | |||
UserDto simon = dbTester.users().insertUser(u -> u.setLogin("simon").setName("Simon Brandhof").setEmail("simon.brandhof@sonarsource.com")); | |||
UserDto evgeny = dbTester.users().insertUser(u -> u.setLogin("godin").setName("Evgeny Mandrikov").setEmail("evgeny.mandrikov@sonarsource.com")); | |||
User user = underTest.findByLogin(simon.getLogin()); | |||
assertThat(user.getId(), is(simon.getId())); | |||
assertThat(user.getLogin(), is("simon")); | |||
assertThat(user.getName(), is("Simon Brandhof")); | |||
assertThat(user.getEmail(), is("simon.brandhof@sonarsource.com")); | |||
User user = underTest.findByLogin(user1.getLogin()); | |||
assertThat(user.getId()).isEqualTo(user1.getId()); | |||
assertThat(user.getLogin()).isEqualTo(user1.getLogin()); | |||
assertThat(user.getName()).isEqualTo(user1.getName()); | |||
assertThat(user.getEmail()).isEqualTo(user1.getEmail()); | |||
user = underTest.findByLogin(evgeny.getLogin()); | |||
assertThat(user.getId(), is(evgeny.getId())); | |||
assertThat(user.getLogin(), is("godin")); | |||
assertThat(user.getName(), is("Evgeny Mandrikov")); | |||
assertThat(user.getEmail(), is("evgeny.mandrikov@sonarsource.com")); | |||
user = underTest.findByLogin("user"); | |||
assertThat(user, nullValue()); | |||
assertThat(underTest.findByLogin("unknown")).isNull(); | |||
} | |||
@Test | |||
public void shouldFindUserById() { | |||
UserDto simon = dbTester.users().insertUser(u -> u.setLogin("simon").setName("Simon Brandhof").setEmail("simon.brandhof@sonarsource.com")); | |||
UserDto evgeny = dbTester.users().insertUser(u -> u.setLogin("godin").setName("Evgeny Mandrikov").setEmail("evgeny.mandrikov@sonarsource.com")); | |||
User user = underTest.findById(simon.getId()); | |||
assertThat(user.getId(), is(simon.getId())); | |||
assertThat(user.getLogin(), is("simon")); | |||
assertThat(user.getName(), is("Simon Brandhof")); | |||
assertThat(user.getEmail(), is("simon.brandhof@sonarsource.com")); | |||
UserDto user1 = db.users().insertUser(); | |||
UserDto user2 = db.users().insertUser(); | |||
user = underTest.findById(evgeny.getId()); | |||
assertThat(user.getId(), is(evgeny.getId())); | |||
assertThat(user.getLogin(), is("godin")); | |||
assertThat(user.getName(), is("Evgeny Mandrikov")); | |||
assertThat(user.getEmail(), is("evgeny.mandrikov@sonarsource.com")); | |||
User user = underTest.findById(user1.getId()); | |||
assertThat(user.getId()).isEqualTo(user1.getId()); | |||
assertThat(user.getLogin()).isEqualTo(user1.getLogin()); | |||
assertThat(user.getName()).isEqualTo(user1.getName()); | |||
assertThat(user.getEmail()).isEqualTo(user1.getEmail()); | |||
user = underTest.findById(999); | |||
assertThat(user, nullValue()); | |||
assertThat(underTest.findById(321)).isNull(); | |||
} | |||
} |
@@ -32,9 +32,18 @@ public class ExternalIdentityTest { | |||
@Test | |||
public void create_external_identity() { | |||
ExternalIdentity externalIdentity = new ExternalIdentity("github", "login"); | |||
assertThat(externalIdentity.getId()).isEqualTo("login"); | |||
ExternalIdentity externalIdentity = new ExternalIdentity("github", "login", "ABCD"); | |||
assertThat(externalIdentity.getLogin()).isEqualTo("login"); | |||
assertThat(externalIdentity.getProvider()).isEqualTo("github"); | |||
assertThat(externalIdentity.getId()).isEqualTo("ABCD"); | |||
} | |||
@Test | |||
public void login_is_used_when_id_is_not_provided() { | |||
ExternalIdentity externalIdentity = new ExternalIdentity("github", "login", null); | |||
assertThat(externalIdentity.getLogin()).isEqualTo("login"); | |||
assertThat(externalIdentity.getProvider()).isEqualTo("github"); | |||
assertThat(externalIdentity.getId()).isEqualTo("login"); | |||
} | |||
@Test | |||
@@ -42,15 +51,15 @@ public class ExternalIdentityTest { | |||
thrown.expect(NullPointerException.class); | |||
thrown.expectMessage("Identity provider cannot be null"); | |||
new ExternalIdentity(null, "login"); | |||
new ExternalIdentity(null, "login", "ABCD"); | |||
} | |||
@Test | |||
public void fail_with_NPE_when_identity_id_is_null() { | |||
public void fail_with_NPE_when_identity_login_is_null() { | |||
thrown.expect(NullPointerException.class); | |||
thrown.expectMessage("Identity id cannot be null"); | |||
thrown.expectMessage("Identity login cannot be null"); | |||
new ExternalIdentity("github", null); | |||
new ExternalIdentity("github", null, "ABCD"); | |||
} | |||
} |
@@ -66,11 +66,12 @@ public class NewUserTest { | |||
.setLogin("login") | |||
.setName("name") | |||
.setEmail("email") | |||
.setExternalIdentity(new ExternalIdentity("github", "github_login")) | |||
.setExternalIdentity(new ExternalIdentity("github", "github_login", "ABCD")) | |||
.build(); | |||
assertThat(newUser.externalIdentity().getProvider()).isEqualTo("github"); | |||
assertThat(newUser.externalIdentity().getId()).isEqualTo("github_login"); | |||
assertThat(newUser.externalIdentity().getLogin()).isEqualTo("github_login"); | |||
assertThat(newUser.externalIdentity().getId()).isEqualTo("ABCD"); | |||
} | |||
@Test | |||
@@ -83,7 +84,7 @@ public class NewUserTest { | |||
.setName("name") | |||
.setEmail("email") | |||
.setPassword("password") | |||
.setExternalIdentity(new ExternalIdentity("github", "github_login")) | |||
.setExternalIdentity(new ExternalIdentity("github", "github_login", "ABCD")) | |||
.build(); | |||
} | |||
} |
@@ -21,7 +21,6 @@ package org.sonar.server.user; | |||
import java.util.Arrays; | |||
import javax.annotation.Nullable; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
@@ -30,9 +29,7 @@ import org.sonar.api.web.UserRole; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentTesting; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.permission.OrganizationPermission; | |||
import org.sonar.db.user.GroupDto; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
@@ -45,27 +42,12 @@ import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.core.permission.GlobalPermissions.PROVISIONING; | |||
import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN; | |||
import static org.sonar.db.component.ComponentTesting.newChildComponent; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER; | |||
import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS; | |||
import static org.sonar.db.permission.OrganizationPermission.SCAN; | |||
public class ServerUserSessionTest { | |||
private static final String LOGIN = "marius"; | |||
private static final String PUBLIC_PROJECT_UUID = "public_project"; | |||
private static final String PRIVATE_PROJECT_UUID = "private_project"; | |||
private static final String FILE_KEY = "com.foo:Bar:BarFile.xoo"; | |||
private static final String FILE_UUID = "BCDE"; | |||
private static final UserDto ROOT_USER_DTO = new UserDto() { | |||
{ | |||
setRoot(true); | |||
} | |||
}.setLogin("root_user"); | |||
private static final UserDto NON_ROOT_USER_DTO = new UserDto() { | |||
{ | |||
setRoot(false); | |||
} | |||
}.setLogin("regular_user"); | |||
@Rule | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
@@ -73,23 +55,8 @@ public class ServerUserSessionTest { | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private DbClient dbClient = db.getDbClient(); | |||
private UserDto user; | |||
private GroupDto groupOfUser; | |||
private TestOrganizationFlags organizationFlags = TestOrganizationFlags.standalone(); | |||
private TestDefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); | |||
private OrganizationDto organization; | |||
private ComponentDto publicProject; | |||
private ComponentDto privateProject; | |||
@Before | |||
public void setUp() throws Exception { | |||
organization = db.organizations().insert(); | |||
publicProject = db.components().insertPublicProject(organization, PUBLIC_PROJECT_UUID); | |||
privateProject = db.components().insertPrivateProject(organization, dto -> dto.setUuid(PRIVATE_PROJECT_UUID).setProjectUuid(PRIVATE_PROJECT_UUID).setPrivate(true)); | |||
db.components().insertComponent(ComponentTesting.newFileDto(publicProject, null, FILE_UUID).setDbKey(FILE_KEY)); | |||
user = db.users().insertUser(LOGIN); | |||
groupOfUser = db.users().insertGroup(organization); | |||
} | |||
@Test | |||
public void anonymous_is_not_logged_in_and_does_not_have_login() { | |||
@@ -106,11 +73,13 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void getGroups_is_empty_if_user_is_not_member_of_any_group() { | |||
UserDto user = db.users().insertUser(); | |||
assertThat(newUserSession(user).getGroups()).isEmpty(); | |||
} | |||
@Test | |||
public void getGroups_returns_the_groups_of_logged_in_user() { | |||
UserDto user = db.users().insertUser(); | |||
GroupDto group1 = db.users().insertGroup(); | |||
GroupDto group2 = db.users().insertGroup(); | |||
db.users().insertMember(group1, user); | |||
@@ -121,6 +90,7 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void getGroups_keeps_groups_in_cache() { | |||
UserDto user = db.users().insertUser(); | |||
GroupDto group1 = db.users().insertGroup(); | |||
GroupDto group2 = db.users().insertGroup(); | |||
db.users().insertMember(group1, user); | |||
@@ -135,13 +105,18 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void isRoot_is_false_is_flag_root_is_false_on_UserDto() { | |||
assertThat(newUserSession(ROOT_USER_DTO).isRoot()).isTrue(); | |||
assertThat(newUserSession(NON_ROOT_USER_DTO).isRoot()).isFalse(); | |||
UserDto root = db.users().insertUser(); | |||
root = db.users().makeRoot(root); | |||
assertThat(newUserSession(root).isRoot()).isTrue(); | |||
UserDto notRoot = db.users().insertUser(); | |||
assertThat(newUserSession(notRoot).isRoot()).isFalse(); | |||
} | |||
@Test | |||
public void checkIsRoot_throws_IPFE_if_flag_root_is_false_on_UserDto() { | |||
UserSession underTest = newUserSession(NON_ROOT_USER_DTO); | |||
UserDto user = db.users().insertUser(); | |||
UserSession underTest = newUserSession(user); | |||
expectInsufficientPrivilegesForbiddenException(); | |||
@@ -150,32 +125,49 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void checkIsRoot_does_not_fail_if_flag_root_is_true_on_UserDto() { | |||
UserSession underTest = newUserSession(ROOT_USER_DTO); | |||
UserDto root = db.users().insertUser(); | |||
root = db.users().makeRoot(root); | |||
UserSession underTest = newUserSession(root); | |||
assertThat(underTest.checkIsRoot()).isSameAs(underTest); | |||
} | |||
@Test | |||
public void hasComponentUuidPermission_returns_true_when_flag_root_is_true_on_UserDto_no_matter_if_user_has_project_permission_for_given_uuid() { | |||
UserSession underTest = newUserSession(ROOT_USER_DTO); | |||
UserDto root = db.users().insertUser(); | |||
root = db.users().makeRoot(root); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto project = db.components().insertPrivateProject(organization); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | |||
UserSession underTest = newUserSession(root); | |||
assertThat(underTest.hasComponentUuidPermission(UserRole.USER, FILE_UUID)).isTrue(); | |||
assertThat(underTest.hasComponentUuidPermission(UserRole.CODEVIEWER, FILE_UUID)).isTrue(); | |||
assertThat(underTest.hasComponentUuidPermission(UserRole.ADMIN, FILE_UUID)).isTrue(); | |||
assertThat(underTest.hasComponentUuidPermission(UserRole.USER, file.uuid())).isTrue(); | |||
assertThat(underTest.hasComponentUuidPermission(UserRole.CODEVIEWER, file.uuid())).isTrue(); | |||
assertThat(underTest.hasComponentUuidPermission(UserRole.ADMIN, file.uuid())).isTrue(); | |||
assertThat(underTest.hasComponentUuidPermission("whatever", "who cares?")).isTrue(); | |||
} | |||
@Test | |||
public void checkComponentUuidPermission_succeeds_if_user_has_permission_for_specified_uuid_in_db() { | |||
UserSession underTest = newUserSession(ROOT_USER_DTO); | |||
UserDto root = db.users().insertUser(); | |||
root = db.users().makeRoot(root); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto project = db.components().insertPrivateProject(organization); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | |||
assertThat(underTest.checkComponentUuidPermission(UserRole.USER, FILE_UUID)).isSameAs(underTest); | |||
UserSession underTest = newUserSession(root); | |||
assertThat(underTest.checkComponentUuidPermission(UserRole.USER, file.uuid())).isSameAs(underTest); | |||
assertThat(underTest.checkComponentUuidPermission("whatever", "who cares?")).isSameAs(underTest); | |||
} | |||
@Test | |||
public void checkComponentUuidPermission_fails_with_FE_when_user_has_not_permission_for_specified_uuid_in_db() { | |||
addProjectPermissions(privateProject, UserRole.USER); | |||
UserDto user = db.users().insertUser(); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
db.users().insertProjectPermissionOnUser(user, UserRole.USER, project); | |||
UserSession session = newUserSession(user); | |||
expectInsufficientPrivilegesForbiddenException(); | |||
@@ -186,33 +178,37 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void checkPermission_throws_ForbiddenException_when_user_doesnt_have_the_specified_permission_on_organization() { | |||
OrganizationDto org = db.organizations().insert(); | |||
db.users().insertUser(NON_ROOT_USER_DTO); | |||
UserDto user = db.users().insertUser(); | |||
expectInsufficientPrivilegesForbiddenException(); | |||
newUserSession(NON_ROOT_USER_DTO).checkPermission(PROVISION_PROJECTS, org); | |||
newUserSession(user).checkPermission(PROVISION_PROJECTS, org); | |||
} | |||
@Test | |||
public void checkPermission_succeeds_when_user_has_the_specified_permission_on_organization() { | |||
OrganizationDto org = db.organizations().insert(); | |||
db.users().insertUser(NON_ROOT_USER_DTO); | |||
db.users().insertPermissionOnUser(org, NON_ROOT_USER_DTO, PROVISIONING); | |||
UserDto root = db.users().insertUser(); | |||
root = db.users().makeRoot(root); | |||
db.users().insertPermissionOnUser(org, root, PROVISIONING); | |||
newUserSession(NON_ROOT_USER_DTO).checkPermission(PROVISION_PROJECTS, org); | |||
newUserSession(root).checkPermission(PROVISION_PROJECTS, org); | |||
} | |||
@Test | |||
public void checkPermission_succeeds_when_user_is_root() { | |||
OrganizationDto org = db.organizations().insert(); | |||
UserDto root = db.users().insertUser(); | |||
root = db.users().makeRoot(root); | |||
newUserSession(ROOT_USER_DTO).checkPermission(PROVISION_PROJECTS, org); | |||
newUserSession(root).checkPermission(PROVISION_PROJECTS, org); | |||
} | |||
@Test | |||
public void test_hasPermission_on_organization_for_logged_in_user() { | |||
OrganizationDto org = db.organizations().insert(); | |||
ComponentDto project = db.components().insertPrivateProject(org); | |||
UserDto user = db.users().insertUser(); | |||
db.users().insertPermissionOnUser(org, user, PROVISION_PROJECTS); | |||
db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, project); | |||
@@ -236,6 +232,7 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void hasPermission_on_organization_keeps_cache_of_permissions_of_logged_in_user() { | |||
OrganizationDto org = db.organizations().insert(); | |||
UserDto user = db.users().insertUser(); | |||
db.users().insertPermissionOnUser(org, user, PROVISIONING); | |||
UserSession session = newUserSession(user); | |||
@@ -269,6 +266,9 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void hasComponentPermissionByDtoOrUuid_returns_true_for_anonymous_user_for_permissions_USER_and_CODEVIEWER_on_public_projects_without_permissions() { | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto publicProject = db.components().insertPublicProject(organization); | |||
ServerUserSession underTest = newAnonymousSession(); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, UserRole.USER, publicProject)).isTrue(); | |||
@@ -277,33 +277,45 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void hasComponentPermissionByDtoOrUuid_returns_true_for_anonymous_user_for_permissions_USER_and_CODEVIEWER_on_public_projects_with_global_permissions() { | |||
ServerUserSession underTest = newAnonymousSession(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto publicProject = db.components().insertPublicProject(organization); | |||
db.users().insertProjectPermissionOnAnyone("p1", publicProject); | |||
ServerUserSession underTest = newAnonymousSession(); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, UserRole.USER, publicProject)).isTrue(); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, UserRole.CODEVIEWER, publicProject)).isTrue(); | |||
} | |||
@Test | |||
public void hasComponentPermissionByDtoOrUuid_returns_true_for_anonymous_user_for_permissions_USER_and_CODEVIEWER_on_public_projects_with_group_permissions() { | |||
ServerUserSession underTest = newAnonymousSession(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto publicProject = db.components().insertPublicProject(organization); | |||
db.users().insertProjectPermissionOnGroup(db.users().insertGroup(organization), "p1", publicProject); | |||
ServerUserSession underTest = newAnonymousSession(); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, UserRole.USER, publicProject)).isTrue(); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, UserRole.CODEVIEWER, publicProject)).isTrue(); | |||
} | |||
@Test | |||
public void hasComponentPermissionByDtoOrUuid_returns_true_for_anonymous_user_for_permissions_USER_and_CODEVIEWER_on_public_projects_with_user_permissions() { | |||
ServerUserSession underTest = newAnonymousSession(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto publicProject = db.components().insertPublicProject(organization); | |||
db.users().insertProjectPermissionOnUser(db.users().insertUser(), "p1", publicProject); | |||
ServerUserSession underTest = newAnonymousSession(); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, UserRole.USER, publicProject)).isTrue(); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, UserRole.CODEVIEWER, publicProject)).isTrue(); | |||
} | |||
@Test | |||
public void hasComponentPermissionByDtoOrUuid_returns_false_for_authenticated_user_for_permissions_USER_and_CODEVIEWER_on_private_projects_without_permissions() { | |||
UserDto user = db.users().insertUser(); | |||
ComponentDto privateProject = db.components().insertPrivateProject(); | |||
ServerUserSession underTest = newUserSession(user); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, UserRole.USER, privateProject)).isFalse(); | |||
@@ -312,71 +324,104 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void hasComponentPermissionByDtoOrUuid_returns_false_for_authenticated_user_for_permissions_USER_and_CODEVIEWER_on_private_projects_with_group_permissions() { | |||
ServerUserSession underTest = newUserSession(user); | |||
UserDto user = db.users().insertUser(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto privateProject = db.components().insertPrivateProject(organization); | |||
db.users().insertProjectPermissionOnGroup(db.users().insertGroup(organization), "p1", privateProject); | |||
ServerUserSession underTest = newUserSession(user); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, UserRole.USER, privateProject)).isFalse(); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, UserRole.CODEVIEWER, privateProject)).isFalse(); | |||
} | |||
@Test | |||
public void hasComponentPermissionByDtoOrUuid_returns_false_for_authenticated_user_for_permissions_USER_and_CODEVIEWER_on_private_projects_with_user_permissions() { | |||
ServerUserSession underTest = newUserSession(user); | |||
UserDto user = db.users().insertUser(); | |||
ComponentDto privateProject = db.components().insertPrivateProject(); | |||
db.users().insertProjectPermissionOnUser(db.users().insertUser(), "p1", privateProject); | |||
ServerUserSession underTest = newUserSession(user); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, UserRole.USER, privateProject)).isFalse(); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, UserRole.CODEVIEWER, privateProject)).isFalse(); | |||
} | |||
@Test | |||
public void hasComponentPermissionByDtoOrUuid_returns_true_for_anonymous_user_for_inserted_permissions_on_group_AnyOne_on_public_projects() { | |||
ServerUserSession underTest = newAnonymousSession(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto publicProject = db.components().insertPublicProject(organization); | |||
db.users().insertProjectPermissionOnAnyone("p1", publicProject); | |||
ServerUserSession underTest = newAnonymousSession(); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, "p1", publicProject)).isTrue(); | |||
} | |||
@Test | |||
public void hasComponentPermissionByDtoOrUuid_returns_false_for_anonymous_user_for_inserted_permissions_on_group_on_public_projects() { | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto publicProject = db.components().insertPublicProject(organization); | |||
GroupDto group = db.users().insertGroup(organization); | |||
db.users().insertProjectPermissionOnGroup(group, "p1", publicProject); | |||
ServerUserSession underTest = newAnonymousSession(); | |||
db.users().insertProjectPermissionOnGroup(groupOfUser, "p1", publicProject); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, "p1", publicProject)).isFalse(); | |||
} | |||
@Test | |||
public void hasComponentPermissionByDtoOrUuid_returns_false_for_anonymous_user_for_inserted_permissions_on_group_on_private_projects() { | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto privateProject = db.components().insertPrivateProject(organization); | |||
GroupDto group = db.users().insertGroup(organization); | |||
db.users().insertProjectPermissionOnGroup(group, "p1", privateProject); | |||
ServerUserSession underTest = newAnonymousSession(); | |||
db.users().insertProjectPermissionOnGroup(groupOfUser, "p1", privateProject); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, "p1", privateProject)).isFalse(); | |||
} | |||
@Test | |||
public void hasComponentPermissionByDtoOrUuid_returns_false_for_anonymous_user_for_inserted_permissions_on_user_on_public_projects() { | |||
ServerUserSession underTest = newAnonymousSession(); | |||
UserDto user = db.users().insertUser(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto publicProject = db.components().insertPublicProject(organization); | |||
db.users().insertProjectPermissionOnUser(user, "p1", publicProject); | |||
ServerUserSession underTest = newAnonymousSession(); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, "p1", publicProject)).isFalse(); | |||
} | |||
@Test | |||
public void hasComponentPermissionByDtoOrUuid_returns_false_for_anonymous_user_for_inserted_permissions_on_user_on_private_projects() { | |||
UserDto user = db.users().insertUser(); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
db.users().insertProjectPermissionOnUser(user, "p1", project); | |||
ServerUserSession underTest = newAnonymousSession(); | |||
db.users().insertProjectPermissionOnUser(user, "p1", privateProject); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, "p1", privateProject)).isFalse(); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, "p1", project)).isFalse(); | |||
} | |||
@Test | |||
public void hasComponentPermissionByDtoOrUuid_returns_true_for_any_project_or_permission_for_root_user() { | |||
ServerUserSession underTest = newUserSession(ROOT_USER_DTO); | |||
UserDto root = db.users().insertUser(); | |||
root = db.users().makeRoot(root); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto publicProject = db.components().insertPublicProject(organization); | |||
ServerUserSession underTest = newUserSession(root); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, "does not matter", publicProject)).isTrue(); | |||
} | |||
@Test | |||
public void hasComponentPermissionByDtoOrUuid_keeps_cache_of_permissions_of_logged_in_user() { | |||
UserDto user = db.users().insertUser(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto publicProject = db.components().insertPublicProject(organization); | |||
db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, publicProject); | |||
UserSession underTest = newUserSession(user); | |||
@@ -393,6 +438,8 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void hasComponentPermissionByDtoOrUuid_keeps_cache_of_permissions_of_anonymous_user() { | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto publicProject = db.components().insertPublicProject(organization); | |||
db.users().insertProjectPermissionOnAnyone(UserRole.ADMIN, publicProject); | |||
UserSession underTest = newAnonymousSession(); | |||
@@ -416,6 +463,10 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void keepAuthorizedComponents_returns_empty_list_if_no_permissions_are_granted() { | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto publicProject = db.components().insertPublicProject(organization); | |||
ComponentDto privateProject = db.components().insertPrivateProject(organization); | |||
UserSession underTest = newAnonymousSession(); | |||
assertThat(underTest.keepAuthorizedComponents(UserRole.ADMIN, Arrays.asList(privateProject, publicProject))).isEmpty(); | |||
@@ -423,26 +474,40 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void keepAuthorizedComponents_filters_components_with_granted_permissions_for_logged_in_user() { | |||
UserSession underTest = newUserSession(user); | |||
UserDto user = db.users().insertUser(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto publicProject = db.components().insertPublicProject(organization); | |||
ComponentDto privateProject = db.components().insertPrivateProject(organization); | |||
db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, privateProject); | |||
UserSession underTest = newUserSession(user); | |||
assertThat(underTest.keepAuthorizedComponents(UserRole.ISSUE_ADMIN, Arrays.asList(privateProject, publicProject))).isEmpty(); | |||
assertThat(underTest.keepAuthorizedComponents(UserRole.ADMIN, Arrays.asList(privateProject, publicProject))).containsExactly(privateProject); | |||
} | |||
@Test | |||
public void keepAuthorizedComponents_filters_components_with_granted_permissions_for_anonymous() { | |||
UserSession underTest = newAnonymousSession(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto publicProject = db.components().insertPublicProject(organization); | |||
ComponentDto privateProject = db.components().insertPrivateProject(organization); | |||
db.users().insertProjectPermissionOnAnyone(UserRole.ISSUE_ADMIN, publicProject); | |||
UserSession underTest = newAnonymousSession(); | |||
assertThat(underTest.keepAuthorizedComponents(UserRole.ADMIN, Arrays.asList(privateProject, publicProject))).isEmpty(); | |||
assertThat(underTest.keepAuthorizedComponents(UserRole.ISSUE_ADMIN, Arrays.asList(privateProject, publicProject))).containsExactly(publicProject); | |||
} | |||
@Test | |||
public void keepAuthorizedComponents_returns_all_specified_components_if_root() { | |||
user = db.users().makeRoot(user); | |||
UserSession underTest = newUserSession(user); | |||
UserDto root = db.users().insertUser(); | |||
root = db.users().makeRoot(root); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto publicProject = db.components().insertPublicProject(organization); | |||
ComponentDto privateProject = db.components().insertPrivateProject(organization); | |||
UserSession underTest = newUserSession(root); | |||
assertThat(underTest.keepAuthorizedComponents(UserRole.ADMIN, Arrays.asList(privateProject, publicProject))) | |||
.containsExactly(privateProject, publicProject); | |||
@@ -450,9 +515,11 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void keepAuthorizedComponents_on_branches() { | |||
user = db.users().insertUser(); | |||
UserDto user = db.users().insertUser(); | |||
ComponentDto privateProject = db.components().insertPrivateProject(); | |||
db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, privateProject); | |||
ComponentDto privateBranchProject = db.components().insertProjectBranch(privateProject); | |||
UserSession underTest = newUserSession(user); | |||
assertThat(underTest.keepAuthorizedComponents(UserRole.ADMIN, asList(privateProject, privateBranchProject))) | |||
@@ -462,8 +529,10 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void isSystemAdministrator_returns_true_if_org_feature_is_enabled_and_user_is_root() { | |||
organizationFlags.setEnabled(true); | |||
user = db.users().makeRoot(user); | |||
UserSession session = newUserSession(user); | |||
UserDto root = db.users().insertUser(); | |||
root = db.users().makeRoot(root); | |||
UserSession session = newUserSession(root); | |||
assertThat(session.isSystemAdministrator()).isTrue(); | |||
} | |||
@@ -471,7 +540,8 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void isSystemAdministrator_returns_false_if_org_feature_is_enabled_and_user_is_not_root() { | |||
organizationFlags.setEnabled(true); | |||
user = db.users().makeNotRoot(user); | |||
UserDto user = db.users().insertUser(); | |||
UserSession session = newUserSession(user); | |||
assertThat(session.isSystemAdministrator()).isFalse(); | |||
@@ -480,8 +550,9 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void isSystemAdministrator_returns_false_if_org_feature_is_enabled_and_user_is_administrator_of_default_organization() { | |||
organizationFlags.setEnabled(true); | |||
user = db.users().makeNotRoot(user); | |||
UserDto user = db.users().insertUser(); | |||
db.users().insertPermissionOnUser(db.getDefaultOrganization(), user, SYSTEM_ADMIN); | |||
UserSession session = newUserSession(user); | |||
assertThat(session.isSystemAdministrator()).isFalse(); | |||
@@ -490,8 +561,9 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void isSystemAdministrator_returns_true_if_org_feature_is_disabled_and_user_is_administrator_of_default_organization() { | |||
organizationFlags.setEnabled(false); | |||
user = db.users().makeNotRoot(user); | |||
UserDto user = db.users().insertUser(); | |||
db.users().insertPermissionOnUser(db.getDefaultOrganization(), user, SYSTEM_ADMIN); | |||
UserSession session = newUserSession(user); | |||
assertThat(session.isSystemAdministrator()).isTrue(); | |||
@@ -500,8 +572,9 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void isSystemAdministrator_returns_false_if_org_feature_is_disabled_and_user_is_not_administrator_of_default_organization() { | |||
organizationFlags.setEnabled(true); | |||
user = db.users().makeNotRoot(user); | |||
UserDto user = db.users().insertUser(); | |||
db.users().insertPermissionOnUser(db.getDefaultOrganization(), user, PROVISIONING); | |||
UserSession session = newUserSession(user); | |||
assertThat(session.isSystemAdministrator()).isFalse(); | |||
@@ -510,8 +583,9 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void keep_isSystemAdministrator_flag_in_cache() { | |||
organizationFlags.setEnabled(false); | |||
user = db.users().makeNotRoot(user); | |||
UserDto user = db.users().insertUser(); | |||
db.users().insertPermissionOnUser(db.getDefaultOrganization(), user, SYSTEM_ADMIN); | |||
UserSession session = newUserSession(user); | |||
session.checkIsSystemAdministrator(); | |||
@@ -526,8 +600,10 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void checkIsSystemAdministrator_succeeds_if_system_administrator() { | |||
organizationFlags.setEnabled(true); | |||
user = db.users().makeRoot(user); | |||
UserSession session = newUserSession(user); | |||
UserDto root = db.users().insertUser(); | |||
root = db.users().makeRoot(root); | |||
UserSession session = newUserSession(root); | |||
session.checkIsSystemAdministrator(); | |||
} | |||
@@ -535,7 +611,8 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void checkIsSystemAdministrator_throws_ForbiddenException_if_not_system_administrator() { | |||
organizationFlags.setEnabled(true); | |||
user = db.users().makeNotRoot(user); | |||
UserDto user = db.users().insertUser(); | |||
UserSession session = newUserSession(user); | |||
expectedException.expect(ForbiddenException.class); | |||
@@ -546,6 +623,8 @@ public class ServerUserSessionTest { | |||
@Test | |||
public void hasComponentPermission_on_branch_checks_permissions_of_its_project() { | |||
UserDto user = db.users().insertUser(); | |||
ComponentDto privateProject = db.components().insertPrivateProject(); | |||
ComponentDto branch = db.components().insertProjectBranch(privateProject, b -> b.setKey("feature/foo")); | |||
ComponentDto fileInBranch = db.components().insertComponent(newChildComponent("fileUuid", branch, branch)); | |||
@@ -553,6 +632,7 @@ public class ServerUserSessionTest { | |||
db.users().insertProjectPermissionOnUser(user, "p1", privateProject); | |||
UserSession underTest = newUserSession(user); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, "p1", privateProject)).isTrue(); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, "p1", branch)).isTrue(); | |||
assertThat(hasComponentPermissionByDtoOrUuid(underTest, "p1", fileInBranch)).isTrue(); | |||
@@ -566,20 +646,6 @@ public class ServerUserSessionTest { | |||
return newUserSession(null); | |||
} | |||
private void addProjectPermissions(ComponentDto component, String... permissions) { | |||
addPermissions(component, permissions); | |||
} | |||
private void addPermissions(@Nullable ComponentDto component, String... permissions) { | |||
for (String permission : permissions) { | |||
if (component == null) { | |||
db.users().insertPermissionOnUser(user, OrganizationPermission.fromKey(permission)); | |||
} else { | |||
db.users().insertProjectPermissionOnUser(user, permission, component); | |||
} | |||
} | |||
} | |||
private void expectInsufficientPrivilegesForbiddenException() { | |||
expectedException.expect(ForbiddenException.class); | |||
expectedException.expectMessage("Insufficient privileges"); |
@@ -36,7 +36,6 @@ import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.user.GroupDto; | |||
import org.sonar.db.user.GroupTesting; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.server.authentication.LocalAuthentication; | |||
import org.sonar.server.authentication.LocalAuthentication.HashMethod; | |||
@@ -60,7 +59,6 @@ import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.sonar.core.config.CorePropertyDefinitions.ONBOARDING_TUTORIAL_SHOW_TO_NEW_USERS; | |||
import static org.sonar.db.user.UserTesting.newDisabledUser; | |||
import static org.sonar.db.user.UserTesting.newLocalUser; | |||
import static org.sonar.server.user.ExternalIdentity.SQ_AUTHORITY; | |||
@@ -103,7 +101,7 @@ public class UserUpdaterCreateTest { | |||
.setPassword("PASSWORD") | |||
.setScmAccounts(ImmutableList.of("u1", "u_1", "User 1")) | |||
.build(), u -> { | |||
}); | |||
}); | |||
assertThat(dto.getId()).isNotNull(); | |||
assertThat(dto.getLogin()).isEqualTo("user"); | |||
@@ -138,7 +136,7 @@ public class UserUpdaterCreateTest { | |||
.setLogin("us") | |||
.setName("User") | |||
.build(), u -> { | |||
}); | |||
}); | |||
UserDto dto = dbClient.userDao().selectByLogin(session, "us"); | |||
assertThat(dto.getId()).isNotNull(); | |||
@@ -158,10 +156,10 @@ public class UserUpdaterCreateTest { | |||
.setName("User") | |||
.setPassword("password") | |||
.build(), u -> { | |||
}); | |||
}); | |||
UserDto dto = dbClient.userDao().selectByLogin(session, "user"); | |||
assertThat(dto.getExternalIdentity()).isEqualTo("user"); | |||
assertThat(dto.getExternalLogin()).isEqualTo("user"); | |||
assertThat(dto.getExternalIdentityProvider()).isEqualTo("sonarqube"); | |||
assertThat(dto.isLocal()).isTrue(); | |||
} | |||
@@ -173,13 +171,14 @@ public class UserUpdaterCreateTest { | |||
underTest.createAndCommit(db.getSession(), NewUser.builder() | |||
.setLogin("user") | |||
.setName("User") | |||
.setExternalIdentity(new ExternalIdentity("github", "github-user")) | |||
.setExternalIdentity(new ExternalIdentity("github", "github-user", "ABCD")) | |||
.build(), u -> { | |||
}); | |||
}); | |||
UserDto dto = dbClient.userDao().selectByLogin(session, "user"); | |||
assertThat(dto.isLocal()).isFalse(); | |||
assertThat(dto.getExternalIdentity()).isEqualTo("github-user"); | |||
assertThat(dto.getExternalId()).isEqualTo("ABCD"); | |||
assertThat(dto.getExternalLogin()).isEqualTo("github-user"); | |||
assertThat(dto.getExternalIdentityProvider()).isEqualTo("github"); | |||
assertThat(dto.getCryptedPassword()).isNull(); | |||
assertThat(dto.getSalt()).isNull(); | |||
@@ -192,13 +191,14 @@ public class UserUpdaterCreateTest { | |||
underTest.createAndCommit(db.getSession(), NewUser.builder() | |||
.setLogin("user") | |||
.setName("User") | |||
.setExternalIdentity(new ExternalIdentity(SQ_AUTHORITY, "user")) | |||
.setExternalIdentity(new ExternalIdentity(SQ_AUTHORITY, "user", null)) | |||
.build(), u -> { | |||
}); | |||
}); | |||
UserDto dto = dbClient.userDao().selectByLogin(session, "user"); | |||
assertThat(dto.isLocal()).isFalse(); | |||
assertThat(dto.getExternalIdentity()).isEqualTo("user"); | |||
assertThat(dto.getExternalId()).isEqualTo("user"); | |||
assertThat(dto.getExternalLogin()).isEqualTo("user"); | |||
assertThat(dto.getExternalIdentityProvider()).isEqualTo("sonarqube"); | |||
assertThat(dto.getCryptedPassword()).isNull(); | |||
assertThat(dto.getSalt()).isNull(); | |||
@@ -214,7 +214,7 @@ public class UserUpdaterCreateTest { | |||
.setPassword("password") | |||
.setScmAccounts(asList("u1", "", null)) | |||
.build(), u -> { | |||
}); | |||
}); | |||
assertThat(dbClient.userDao().selectByLogin(session, "user").getScmAccountsAsList()).containsOnly("u1"); | |||
} | |||
@@ -229,7 +229,7 @@ public class UserUpdaterCreateTest { | |||
.setPassword("password") | |||
.setScmAccounts(asList("")) | |||
.build(), u -> { | |||
}); | |||
}); | |||
assertThat(dbClient.userDao().selectByLogin(session, "user").getScmAccounts()).isNull(); | |||
} | |||
@@ -244,7 +244,7 @@ public class UserUpdaterCreateTest { | |||
.setPassword("password") | |||
.setScmAccounts(asList("u1", "u1")) | |||
.build(), u -> { | |||
}); | |||
}); | |||
assertThat(dbClient.userDao().selectByLogin(session, "user").getScmAccountsAsList()).containsOnly("u1"); | |||
} | |||
@@ -258,7 +258,7 @@ public class UserUpdaterCreateTest { | |||
.setLogin("user") | |||
.setName("User") | |||
.build(), u -> { | |||
}); | |||
}); | |||
assertThat(dbClient.userDao().selectByLogin(session, "user").isOnboarded()).isTrue(); | |||
} | |||
@@ -272,7 +272,7 @@ public class UserUpdaterCreateTest { | |||
.setLogin("user") | |||
.setName("User") | |||
.build(), u -> { | |||
}); | |||
}); | |||
assertThat(dbClient.userDao().selectByLogin(session, "user").isOnboarded()).isFalse(); | |||
} | |||
@@ -288,9 +288,9 @@ public class UserUpdaterCreateTest { | |||
.setEmail("user@mail.com") | |||
.setPassword("PASSWORD") | |||
.build(), u -> { | |||
}, otherUser); | |||
}, otherUser); | |||
assertThat(es.getIds(UserIndexDefinition.INDEX_TYPE_USER)).containsExactlyInAnyOrder(created.getLogin(), otherUser.getLogin()); | |||
assertThat(es.getIds(UserIndexDefinition.INDEX_TYPE_USER)).containsExactlyInAnyOrder(created.getUuid(), otherUser.getUuid()); | |||
} | |||
@Test | |||
@@ -304,7 +304,7 @@ public class UserUpdaterCreateTest { | |||
.setEmail("marius@mail.com") | |||
.setPassword("password") | |||
.build(), u -> { | |||
}); | |||
}); | |||
} | |||
@Test | |||
@@ -318,7 +318,7 @@ public class UserUpdaterCreateTest { | |||
.setEmail("marius@mail.com") | |||
.setPassword("password") | |||
.build(), u -> { | |||
}); | |||
}); | |||
} | |||
@Test | |||
@@ -332,7 +332,7 @@ public class UserUpdaterCreateTest { | |||
.setEmail("marius@mail.com") | |||
.setPassword("password") | |||
.build(), u -> { | |||
}); | |||
}); | |||
} | |||
@Test | |||
@@ -346,7 +346,7 @@ public class UserUpdaterCreateTest { | |||
.setEmail("marius@mail.com") | |||
.setPassword("password") | |||
.build(), u -> { | |||
}); | |||
}); | |||
} | |||
@Test | |||
@@ -360,7 +360,7 @@ public class UserUpdaterCreateTest { | |||
.setEmail("marius@mail.com") | |||
.setPassword("password") | |||
.build(), u -> { | |||
}); | |||
}); | |||
} | |||
@Test | |||
@@ -374,7 +374,7 @@ public class UserUpdaterCreateTest { | |||
.setEmail("marius@mail.com") | |||
.setPassword("password") | |||
.build(), u -> { | |||
}); | |||
}); | |||
} | |||
@Test | |||
@@ -388,7 +388,7 @@ public class UserUpdaterCreateTest { | |||
.setEmail("marius@mail.com") | |||
.setPassword("password") | |||
.build(), u -> { | |||
}); | |||
}); | |||
} | |||
@Test | |||
@@ -402,7 +402,7 @@ public class UserUpdaterCreateTest { | |||
.setEmail(Strings.repeat("m", 101)) | |||
.setPassword("password") | |||
.build(), u -> { | |||
}); | |||
}); | |||
} | |||
@Test | |||
@@ -414,7 +414,7 @@ public class UserUpdaterCreateTest { | |||
.setEmail("marius@mail.com") | |||
.setPassword("") | |||
.build(), u -> { | |||
}); | |||
}); | |||
fail(); | |||
} catch (BadRequestException e) { | |||
assertThat(e.errors()).hasSize(3); | |||
@@ -435,7 +435,7 @@ public class UserUpdaterCreateTest { | |||
.setPassword("password") | |||
.setScmAccounts(asList("jo")) | |||
.build(), u -> { | |||
}); | |||
}); | |||
} | |||
@Test | |||
@@ -453,7 +453,7 @@ public class UserUpdaterCreateTest { | |||
.setPassword("password") | |||
.setScmAccounts(asList("john@email.com")) | |||
.build(), u -> { | |||
}); | |||
}); | |||
} | |||
@Test | |||
@@ -468,7 +468,7 @@ public class UserUpdaterCreateTest { | |||
.setPassword("password2") | |||
.setScmAccounts(asList(DEFAULT_LOGIN)) | |||
.build(), u -> { | |||
}); | |||
}); | |||
} | |||
@Test | |||
@@ -483,6 +483,38 @@ public class UserUpdaterCreateTest { | |||
.setPassword("password2") | |||
.setScmAccounts(asList("marius2@mail.com")) | |||
.build(), u -> { | |||
}); | |||
} | |||
@Test | |||
public void fail_to_create_user_when_login_already_exists() { | |||
createDefaultGroup(); | |||
UserDto existingUser = db.users().insertUser(u -> u.setLogin("existing_login")); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("A user with login 'existing_login' already exists"); | |||
underTest.createAndCommit(db.getSession(), NewUser.builder() | |||
.setLogin(existingUser.getLogin()) | |||
.setName("User") | |||
.setPassword("PASSWORD") | |||
.build(), u -> { | |||
}); | |||
} | |||
@Test | |||
public void fail_to_create_user_when_external_id_and_external_provider_already_exists() { | |||
createDefaultGroup(); | |||
UserDto existingUser = db.users().insertUser(u -> u.setExternalId("existing_external_id").setExternalIdentityProvider("existing_external_provider")); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("A user with provider id 'existing_external_id' and identity provider 'existing_external_provider' already exists"); | |||
underTest.createAndCommit(db.getSession(), NewUser.builder() | |||
.setLogin("new_login") | |||
.setName("User") | |||
.setExternalIdentity(new ExternalIdentity(existingUser.getExternalIdentityProvider(), existingUser.getExternalLogin(), existingUser.getExternalId())) | |||
.build(), u -> { | |||
}); | |||
} | |||
@@ -497,7 +529,7 @@ public class UserUpdaterCreateTest { | |||
.setPassword("password") | |||
.setScmAccounts(asList("u1", "u_1")) | |||
.build(), u -> { | |||
}); | |||
}); | |||
verify(newUserNotifier).onNewUser(newUserHandler.capture()); | |||
assertThat(newUserHandler.getValue().getLogin()).isEqualTo("user"); | |||
@@ -516,7 +548,7 @@ public class UserUpdaterCreateTest { | |||
.setEmail("user@mail.com") | |||
.setPassword("password") | |||
.build(), u -> { | |||
}); | |||
}); | |||
Multimap<String, String> groups = dbClient.groupMembershipDao().selectGroupsByLogins(session, asList("user")); | |||
assertThat(groups.get("user")).containsOnly(defaultGroup.getName()); | |||
@@ -533,7 +565,7 @@ public class UserUpdaterCreateTest { | |||
.setEmail("user@mail.com") | |||
.setPassword("password") | |||
.build(), u -> { | |||
}); | |||
}); | |||
Multimap<String, String> groups = dbClient.groupMembershipDao().selectGroupsByLogins(session, asList("user")); | |||
assertThat(groups.get("user")).isEmpty(); | |||
@@ -551,7 +583,7 @@ public class UserUpdaterCreateTest { | |||
.setPassword("password") | |||
.setScmAccounts(asList("u1", "u_1")) | |||
.build(), u -> { | |||
}); | |||
}); | |||
} | |||
@Test | |||
@@ -564,7 +596,7 @@ public class UserUpdaterCreateTest { | |||
.setEmail("user@mail.com") | |||
.setPassword("PASSWORD") | |||
.build(), u -> { | |||
}); | |||
}); | |||
verify(organizationCreation).createForUser(any(DbSession.class), eq(dto)); | |||
} | |||
@@ -580,7 +612,7 @@ public class UserUpdaterCreateTest { | |||
.setEmail("user@mail.com") | |||
.setPassword("PASSWORD") | |||
.build(), u -> { | |||
}); | |||
}); | |||
assertThat(dbClient.organizationMemberDao().select(db.getSession(), defaultOrganizationProvider.get().getUuid(), dto.getId())).isPresent(); | |||
} | |||
@@ -596,230 +628,11 @@ public class UserUpdaterCreateTest { | |||
.setEmail("user@mail.com") | |||
.setPassword("PASSWORD") | |||
.build(), u -> { | |||
}); | |||
assertThat(dbClient.organizationMemberDao().select(db.getSession(), defaultOrganizationProvider.get().getUuid(), dto.getId())).isNotPresent(); | |||
} | |||
@Test | |||
public void reactivate_user_when_creating_user_with_existing_login() { | |||
UserDto user = db.users().insertUser(newDisabledUser(DEFAULT_LOGIN) | |||
.setLocal(false)); | |||
createDefaultGroup(); | |||
UserDto dto = underTest.createAndCommit(db.getSession(), NewUser.builder() | |||
.setLogin(DEFAULT_LOGIN) | |||
.setName("Marius2") | |||
.setEmail("marius2@mail.com") | |||
.setPassword("password2") | |||
.build(), u -> { | |||
}); | |||
session.commit(); | |||
assertThat(dto.isActive()).isTrue(); | |||
assertThat(dto.getName()).isEqualTo("Marius2"); | |||
assertThat(dto.getEmail()).isEqualTo("marius2@mail.com"); | |||
assertThat(dto.getScmAccounts()).isNull(); | |||
assertThat(dto.isLocal()).isTrue(); | |||
assertThat(dto.getSalt()).isNull(); | |||
assertThat(dto.getHashMethod()).isEqualTo(HashMethod.BCRYPT.name()); | |||
assertThat(dto.getCryptedPassword()).isNotNull().isNotEqualTo("650d2261c98361e2f67f90ce5c65a95e7d8ea2fg"); | |||
assertThat(dto.getCreatedAt()).isEqualTo(user.getCreatedAt()); | |||
assertThat(dto.getUpdatedAt()).isGreaterThan(user.getCreatedAt()); | |||
assertThat(dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN).isActive()).isTrue(); | |||
} | |||
@Test | |||
public void reactivate_user_not_having_password() { | |||
UserDto user = db.users().insertUser(newDisabledUser("marius").setName("Marius").setEmail("marius@lesbronzes.fr") | |||
.setSalt(null) | |||
.setCryptedPassword(null)); | |||
createDefaultGroup(); | |||
UserDto dto = underTest.createAndCommit(db.getSession(), NewUser.builder() | |||
.setLogin(DEFAULT_LOGIN) | |||
.setName("Marius2") | |||
.setEmail("marius2@mail.com") | |||
.build(), u -> { | |||
}); | |||
session.commit(); | |||
assertThat(dto.isActive()).isTrue(); | |||
assertThat(dto.getName()).isEqualTo("Marius2"); | |||
assertThat(dto.getEmail()).isEqualTo("marius2@mail.com"); | |||
assertThat(dto.getScmAccounts()).isNull(); | |||
assertThat(dto.getSalt()).isNull(); | |||
assertThat(dto.getCryptedPassword()).isNull(); | |||
assertThat(dto.getCreatedAt()).isEqualTo(user.getCreatedAt()); | |||
assertThat(dto.getUpdatedAt()).isGreaterThan(user.getCreatedAt()); | |||
} | |||
@Test | |||
public void reactivate_user_with_external_provider() { | |||
db.users().insertUser(newDisabledUser(DEFAULT_LOGIN) | |||
.setLocal(true)); | |||
createDefaultGroup(); | |||
underTest.createAndCommit(db.getSession(), NewUser.builder() | |||
.setLogin(DEFAULT_LOGIN) | |||
.setName("Marius2") | |||
.setExternalIdentity(new ExternalIdentity("github", "john")) | |||
.build(), u -> { | |||
}); | |||
session.commit(); | |||
UserDto dto = dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN); | |||
assertThat(dto.isLocal()).isFalse(); | |||
assertThat(dto.getExternalIdentity()).isEqualTo("john"); | |||
assertThat(dto.getExternalIdentityProvider()).isEqualTo("github"); | |||
} | |||
@Test | |||
public void reactivate_user_with_local_provider() { | |||
db.users().insertUser(newDisabledUser(DEFAULT_LOGIN) | |||
.setLocal(true)); | |||
createDefaultGroup(); | |||
underTest.createAndCommit(db.getSession(), NewUser.builder() | |||
.setLogin(DEFAULT_LOGIN) | |||
.setName("Marius2") | |||
.setPassword("password") | |||
.build(), u -> { | |||
}); | |||
session.commit(); | |||
UserDto dto = dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN); | |||
assertThat(dto.isLocal()).isTrue(); | |||
assertThat(dto.getExternalIdentity()).isEqualTo(DEFAULT_LOGIN); | |||
assertThat(dto.getExternalIdentityProvider()).isEqualTo("sonarqube"); | |||
} | |||
@Test | |||
public void fail_to_reactivate_user_if_not_disabled() { | |||
db.users().insertUser(newLocalUser("marius", "Marius", "marius@lesbronzes.fr")); | |||
createDefaultGroup(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("An active user with login 'marius' already exists"); | |||
underTest.createAndCommit(db.getSession(), NewUser.builder() | |||
.setLogin(DEFAULT_LOGIN) | |||
.setName("Marius2") | |||
.setEmail("marius2@mail.com") | |||
.setPassword("password2") | |||
.build(), u -> { | |||
}); | |||
} | |||
@Test | |||
public void associate_default_groups_when_reactivating_user_and_organizations_are_disabled() { | |||
organizationFlags.setEnabled(false); | |||
UserDto userDto = db.users().insertUser(newDisabledUser(DEFAULT_LOGIN) | |||
.setLocal(true)); | |||
db.organizations().insertForUuid("org1"); | |||
GroupDto groupDto = db.users().insertGroup(GroupTesting.newGroupDto().setName("sonar-devs").setOrganizationUuid("org1")); | |||
db.users().insertMember(groupDto, userDto); | |||
GroupDto defaultGroup = createDefaultGroup(); | |||
underTest.createAndCommit(db.getSession(), NewUser.builder() | |||
.setLogin(DEFAULT_LOGIN) | |||
.setName("Marius2") | |||
.setEmail("marius2@mail.com") | |||
.setPassword("password2") | |||
.build(), u -> { | |||
}); | |||
session.commit(); | |||
Multimap<String, String> groups = dbClient.groupMembershipDao().selectGroupsByLogins(session, asList(DEFAULT_LOGIN)); | |||
assertThat(groups.get(DEFAULT_LOGIN).stream().anyMatch(g -> g.equals(defaultGroup.getName()))).isTrue(); | |||
} | |||
@Test | |||
public void does_not_associate_default_groups_when_reactivating_user_and_organizations_are_enabled() { | |||
organizationFlags.setEnabled(true); | |||
UserDto userDto = db.users().insertUser(newDisabledUser(DEFAULT_LOGIN) | |||
.setLocal(true)); | |||
db.organizations().insertForUuid("org1"); | |||
GroupDto groupDto = db.users().insertGroup(GroupTesting.newGroupDto().setName("sonar-devs").setOrganizationUuid("org1")); | |||
db.users().insertMember(groupDto, userDto); | |||
GroupDto defaultGroup = createDefaultGroup(); | |||
underTest.createAndCommit(db.getSession(), NewUser.builder() | |||
.setLogin(DEFAULT_LOGIN) | |||
.setName("Marius2") | |||
.setEmail("marius2@mail.com") | |||
.setPassword("password2") | |||
.build(), u -> { | |||
}); | |||
session.commit(); | |||
Multimap<String, String> groups = dbClient.groupMembershipDao().selectGroupsByLogins(session, asList(DEFAULT_LOGIN)); | |||
assertThat(groups.get(DEFAULT_LOGIN).stream().anyMatch(g -> g.equals(defaultGroup.getName()))).isFalse(); | |||
} | |||
@Test | |||
public void add_user_as_member_of_default_organization_when_reactivating_user_and_organizations_are_disabled() { | |||
organizationFlags.setEnabled(false); | |||
db.users().insertUser(newDisabledUser(DEFAULT_LOGIN)); | |||
createDefaultGroup(); | |||
UserDto dto = underTest.createAndCommit(db.getSession(), NewUser.builder().setLogin(DEFAULT_LOGIN).setName("Name").build(), u -> { | |||
}); | |||
session.commit(); | |||
assertThat(dbClient.organizationMemberDao().select(db.getSession(), defaultOrganizationProvider.get().getUuid(), dto.getId())).isPresent(); | |||
} | |||
@Test | |||
public void does_not_add_user_as_member_of_default_organization_when_reactivating_user_and_organizations_are_enabled() { | |||
organizationFlags.setEnabled(true); | |||
db.users().insertUser(newDisabledUser(DEFAULT_LOGIN)); | |||
createDefaultGroup(); | |||
UserDto dto = underTest.createAndCommit(db.getSession(), NewUser.builder().setLogin(DEFAULT_LOGIN).setName("Name").build(), u -> { | |||
}); | |||
session.commit(); | |||
}); | |||
assertThat(dbClient.organizationMemberDao().select(db.getSession(), defaultOrganizationProvider.get().getUuid(), dto.getId())).isNotPresent(); | |||
} | |||
@Test | |||
public void reactivate_not_onboarded_user_if_onboarding_setting_is_set_to_false() { | |||
settings.setProperty(ONBOARDING_TUTORIAL_SHOW_TO_NEW_USERS, false); | |||
UserDto user = db.users().insertUser(u -> u | |||
.setActive(false) | |||
.setOnboarded(false)); | |||
createDefaultGroup(); | |||
underTest.createAndCommit(db.getSession(), NewUser.builder() | |||
.setLogin(user.getLogin()) | |||
.setName("name") | |||
.build(), u -> { | |||
}); | |||
assertThat(dbClient.userDao().selectByLogin(session, user.getLogin()).isOnboarded()).isTrue(); | |||
} | |||
@Test | |||
public void reactivate_onboarded_user_if_onboarding_setting_is_set_to_true() { | |||
settings.setProperty(ONBOARDING_TUTORIAL_SHOW_TO_NEW_USERS, true); | |||
UserDto user = db.users().insertUser(u -> u | |||
.setActive(false) | |||
.setOnboarded(true)); | |||
createDefaultGroup(); | |||
underTest.createAndCommit(db.getSession(), NewUser.builder() | |||
.setLogin(user.getLogin()) | |||
.setName("name") | |||
.build(), u -> { | |||
}); | |||
assertThat(dbClient.userDao().selectByLogin(session, user.getLogin()).isOnboarded()).isFalse(); | |||
} | |||
private GroupDto createDefaultGroup() { | |||
return db.users().insertDefaultGroup(db.getDefaultOrganization()); | |||
} |
@@ -0,0 +1,339 @@ | |||
/* | |||
* 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.user; | |||
import com.google.common.collect.Multimap; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.config.internal.MapSettings; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.utils.internal.AlwaysIncreasingSystem2; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.user.GroupDto; | |||
import org.sonar.db.user.GroupTesting; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.server.authentication.LocalAuthentication; | |||
import org.sonar.server.authentication.LocalAuthentication.HashMethod; | |||
import org.sonar.server.es.EsTester; | |||
import org.sonar.server.organization.DefaultOrganizationProvider; | |||
import org.sonar.server.organization.OrganizationCreation; | |||
import org.sonar.server.organization.TestDefaultOrganizationProvider; | |||
import org.sonar.server.organization.TestOrganizationFlags; | |||
import org.sonar.server.user.index.UserIndexer; | |||
import org.sonar.server.usergroups.DefaultGroupFinder; | |||
import static java.lang.String.format; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.sonar.core.config.CorePropertyDefinitions.ONBOARDING_TUTORIAL_SHOW_TO_NEW_USERS; | |||
public class UserUpdaterReactivateTest { | |||
private System2 system2 = new AlwaysIncreasingSystem2(); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public EsTester es = EsTester.create(); | |||
@Rule | |||
public DbTester db = DbTester.create(system2); | |||
private DbClient dbClient = db.getDbClient(); | |||
private NewUserNotifier newUserNotifier = mock(NewUserNotifier.class); | |||
private DbSession session = db.getSession(); | |||
private UserIndexer userIndexer = new UserIndexer(dbClient, es.client()); | |||
private OrganizationCreation organizationCreation = mock(OrganizationCreation.class); | |||
private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); | |||
private TestOrganizationFlags organizationFlags = TestOrganizationFlags.standalone(); | |||
private MapSettings settings = new MapSettings(); | |||
private LocalAuthentication localAuthentication = new LocalAuthentication(db.getDbClient()); | |||
private UserUpdater underTest = new UserUpdater(newUserNotifier, dbClient, userIndexer, organizationFlags, defaultOrganizationProvider, organizationCreation, | |||
new DefaultGroupFinder(dbClient), settings.asConfig(), localAuthentication); | |||
@Test | |||
public void reactivate_user() { | |||
UserDto user = db.users().insertUser(u -> u.setActive(false)); | |||
createDefaultGroup(); | |||
underTest.reactivateAndCommit(db.getSession(), user, NewUser.builder() | |||
.setLogin("marius") | |||
.setName("Marius2") | |||
.setEmail("marius2@mail.com") | |||
.setPassword("password2") | |||
.build(), | |||
u -> { | |||
}); | |||
UserDto reloaded = dbClient.userDao().selectByUuid(session, user.getUuid()); | |||
assertThat(reloaded.isActive()).isTrue(); | |||
assertThat(reloaded.getLogin()).isEqualTo("marius"); | |||
assertThat(reloaded.getName()).isEqualTo("Marius2"); | |||
assertThat(reloaded.getEmail()).isEqualTo("marius2@mail.com"); | |||
assertThat(reloaded.getScmAccounts()).isNull(); | |||
assertThat(reloaded.isLocal()).isTrue(); | |||
assertThat(reloaded.getSalt()).isNull(); | |||
assertThat(reloaded.getHashMethod()).isEqualTo(HashMethod.BCRYPT.name()); | |||
assertThat(reloaded.getCryptedPassword()).isNotNull().isNotEqualTo("650d2261c98361e2f67f90ce5c65a95e7d8ea2fg"); | |||
assertThat(reloaded.getCreatedAt()).isEqualTo(user.getCreatedAt()); | |||
assertThat(reloaded.getUpdatedAt()).isGreaterThan(user.getCreatedAt()); | |||
} | |||
@Test | |||
public void reactivate_user_not_having_password() { | |||
UserDto user = db.users().insertDisabledUser(u -> u.setSalt(null).setCryptedPassword(null)); | |||
createDefaultGroup(); | |||
UserDto dto = underTest.reactivateAndCommit(db.getSession(), user, NewUser.builder() | |||
.setLogin(user.getLogin()) | |||
.setName(user.getName()) | |||
.build(), | |||
u -> { | |||
}); | |||
assertThat(dto.isActive()).isTrue(); | |||
assertThat(dto.getName()).isEqualTo(user.getName()); | |||
assertThat(dto.getScmAccounts()).isNull(); | |||
assertThat(dto.getSalt()).isNull(); | |||
assertThat(dto.getCryptedPassword()).isNull(); | |||
assertThat(dto.getCreatedAt()).isEqualTo(user.getCreatedAt()); | |||
assertThat(dto.getUpdatedAt()).isGreaterThan(user.getCreatedAt()); | |||
} | |||
@Test | |||
public void reactivate_user_with_external_provider() { | |||
UserDto user = db.users().insertDisabledUser(u -> u.setLocal(true)); | |||
createDefaultGroup(); | |||
underTest.reactivateAndCommit(db.getSession(), user, NewUser.builder() | |||
.setLogin(user.getLogin()) | |||
.setName(user.getName()) | |||
.setExternalIdentity(new ExternalIdentity("github", "john", "ABCD")) | |||
.build(), u -> { | |||
}); | |||
session.commit(); | |||
UserDto dto = dbClient.userDao().selectByUuid(session, user.getUuid()); | |||
assertThat(dto.isLocal()).isFalse(); | |||
assertThat(dto.getExternalId()).isEqualTo("ABCD"); | |||
assertThat(dto.getExternalLogin()).isEqualTo("john"); | |||
assertThat(dto.getExternalIdentityProvider()).isEqualTo("github"); | |||
} | |||
@Test | |||
public void reactivate_user_using_same_external_info_but_was_local() { | |||
UserDto user = db.users().insertDisabledUser(u -> u.setLocal(true) | |||
.setExternalId("ABCD") | |||
.setExternalLogin("john") | |||
.setExternalIdentityProvider("github")); | |||
createDefaultGroup(); | |||
underTest.reactivateAndCommit(db.getSession(), user, NewUser.builder() | |||
.setLogin(user.getLogin()) | |||
.setName(user.getName()) | |||
.setExternalIdentity(new ExternalIdentity("github", "john", "ABCD")) | |||
.build(), u -> { | |||
}); | |||
session.commit(); | |||
UserDto dto = dbClient.userDao().selectByUuid(session, user.getUuid()); | |||
assertThat(dto.isLocal()).isFalse(); | |||
assertThat(dto.getExternalId()).isEqualTo("ABCD"); | |||
assertThat(dto.getExternalLogin()).isEqualTo("john"); | |||
assertThat(dto.getExternalIdentityProvider()).isEqualTo("github"); | |||
} | |||
@Test | |||
public void reactivate_user_with_local_provider() { | |||
UserDto user = db.users().insertDisabledUser(u -> u.setLocal(false) | |||
.setExternalId("ABCD") | |||
.setExternalLogin("john") | |||
.setExternalIdentityProvider("github")); | |||
createDefaultGroup(); | |||
underTest.reactivateAndCommit(db.getSession(), user, NewUser.builder() | |||
.setLogin(user.getLogin()) | |||
.setName(user.getName()) | |||
.build(), u -> { | |||
}); | |||
session.commit(); | |||
UserDto dto = dbClient.userDao().selectByUuid(session, user.getUuid()); | |||
assertThat(dto.isLocal()).isTrue(); | |||
assertThat(dto.getExternalId()).isEqualTo(user.getLogin()); | |||
assertThat(dto.getExternalLogin()).isEqualTo(user.getLogin()); | |||
assertThat(dto.getExternalIdentityProvider()).isEqualTo("sonarqube"); | |||
} | |||
@Test | |||
public void fail_to_reactivate_user_if_active() { | |||
UserDto user = db.users().insertUser(); | |||
createDefaultGroup(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage(format("An active user with login '%s' already exists", user.getLogin())); | |||
underTest.reactivateAndCommit(db.getSession(), user, NewUser.builder() | |||
.setLogin(user.getLogin()) | |||
.setName(user.getName()) | |||
.build(), u -> { | |||
}); | |||
} | |||
@Test | |||
public void associate_default_groups_when_reactivating_user_and_organizations_are_disabled() { | |||
organizationFlags.setEnabled(false); | |||
UserDto userDto = db.users().insertDisabledUser(); | |||
db.organizations().insertForUuid("org1"); | |||
GroupDto groupDto = db.users().insertGroup(GroupTesting.newGroupDto().setName("sonar-devs").setOrganizationUuid("org1")); | |||
db.users().insertMember(groupDto, userDto); | |||
GroupDto defaultGroup = createDefaultGroup(); | |||
underTest.reactivateAndCommit(db.getSession(), userDto, NewUser.builder() | |||
.setLogin(userDto.getLogin()) | |||
.setName(userDto.getName()) | |||
.build(), u -> { | |||
}); | |||
session.commit(); | |||
Multimap<String, String> groups = dbClient.groupMembershipDao().selectGroupsByLogins(session, singletonList(userDto.getLogin())); | |||
assertThat(groups.get(userDto.getLogin()).stream().anyMatch(g -> g.equals(defaultGroup.getName()))).isTrue(); | |||
} | |||
@Test | |||
public void does_not_associate_default_groups_when_reactivating_user_and_organizations_are_enabled() { | |||
organizationFlags.setEnabled(true); | |||
UserDto userDto = db.users().insertDisabledUser(); | |||
db.organizations().insertForUuid("org1"); | |||
GroupDto groupDto = db.users().insertGroup(GroupTesting.newGroupDto().setName("sonar-devs").setOrganizationUuid("org1")); | |||
db.users().insertMember(groupDto, userDto); | |||
GroupDto defaultGroup = createDefaultGroup(); | |||
underTest.reactivateAndCommit(db.getSession(), userDto, NewUser.builder() | |||
.setLogin(userDto.getLogin()) | |||
.setName(userDto.getName()) | |||
.build(), u -> { | |||
}); | |||
session.commit(); | |||
Multimap<String, String> groups = dbClient.groupMembershipDao().selectGroupsByLogins(session, singletonList(userDto.getLogin())); | |||
assertThat(groups.get(userDto.getLogin()).stream().anyMatch(g -> g.equals(defaultGroup.getName()))).isFalse(); | |||
} | |||
@Test | |||
public void add_user_as_member_of_default_organization_when_reactivating_user_and_organizations_are_disabled() { | |||
organizationFlags.setEnabled(false); | |||
UserDto user = db.users().insertDisabledUser(); | |||
createDefaultGroup(); | |||
UserDto dto = underTest.reactivateAndCommit(db.getSession(), user, NewUser.builder().setLogin(user.getLogin()).setName(user.getName()).build(), u -> { | |||
}); | |||
assertThat(dbClient.organizationMemberDao().select(db.getSession(), defaultOrganizationProvider.get().getUuid(), dto.getId())).isPresent(); | |||
} | |||
@Test | |||
public void does_not_add_user_as_member_of_default_organization_when_reactivating_user_and_organizations_are_enabled() { | |||
organizationFlags.setEnabled(true); | |||
UserDto user = db.users().insertDisabledUser(); | |||
createDefaultGroup(); | |||
UserDto dto = underTest.reactivateAndCommit(db.getSession(), user, NewUser.builder().setLogin(user.getLogin()).setName(user.getName()).build(), u -> { | |||
}); | |||
assertThat(dbClient.organizationMemberDao().select(db.getSession(), defaultOrganizationProvider.get().getUuid(), dto.getId())).isNotPresent(); | |||
} | |||
@Test | |||
public void reactivate_not_onboarded_user_if_onboarding_setting_is_set_to_false() { | |||
settings.setProperty(ONBOARDING_TUTORIAL_SHOW_TO_NEW_USERS, false); | |||
UserDto user = db.users().insertDisabledUser(u -> u.setOnboarded(false)); | |||
createDefaultGroup(); | |||
underTest.reactivateAndCommit(db.getSession(), user, NewUser.builder() | |||
.setLogin(user.getLogin()) | |||
.setName(user.getName()) | |||
.build(), u -> { | |||
}); | |||
assertThat(dbClient.userDao().selectByLogin(session, user.getLogin()).isOnboarded()).isTrue(); | |||
} | |||
@Test | |||
public void reactivate_onboarded_user_if_onboarding_setting_is_set_to_true() { | |||
settings.setProperty(ONBOARDING_TUTORIAL_SHOW_TO_NEW_USERS, true); | |||
UserDto user = db.users().insertDisabledUser(u -> u.setOnboarded(true)); | |||
createDefaultGroup(); | |||
underTest.reactivateAndCommit(db.getSession(), user, NewUser.builder() | |||
.setLogin(user.getLogin()) | |||
.setName(user.getName()) | |||
.build(), u -> { | |||
}); | |||
assertThat(dbClient.userDao().selectByLogin(session, user.getLogin()).isOnboarded()).isFalse(); | |||
} | |||
@Test | |||
public void fail_to_reactivate_user_when_login_already_exists() { | |||
createDefaultGroup(); | |||
UserDto user = db.users().insertUser(u -> u.setActive(false)); | |||
UserDto existingUser = db.users().insertUser(u -> u.setLogin("existing_login")); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("A user with login 'existing_login' already exists"); | |||
underTest.reactivateAndCommit(db.getSession(), user, NewUser.builder() | |||
.setLogin(existingUser.getLogin()) | |||
.setName("Marius2") | |||
.setPassword("password2") | |||
.build(), | |||
u -> { | |||
}); | |||
} | |||
@Test | |||
public void fail_to_reactivate_user_when_external_id_and_external_provider_already_exists() { | |||
createDefaultGroup(); | |||
UserDto user = db.users().insertUser(u -> u.setActive(false)); | |||
UserDto existingUser = db.users().insertUser(u -> u.setExternalId("existing_external_id").setExternalIdentityProvider("existing_external_provider")); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("A user with provider id 'existing_external_id' and identity provider 'existing_external_provider' already exists"); | |||
underTest.reactivateAndCommit(db.getSession(), user, NewUser.builder() | |||
.setLogin(user.getLogin()) | |||
.setName("Marius2") | |||
.setExternalIdentity(new ExternalIdentity(existingUser.getExternalIdentityProvider(), existingUser.getExternalLogin(), existingUser.getExternalId())) | |||
.build(), | |||
u -> { | |||
}); | |||
} | |||
private GroupDto createDefaultGroup() { | |||
return db.users().insertDefaultGroup(db.getDefaultOrganization()); | |||
} | |||
} |
@@ -25,14 +25,15 @@ import org.elasticsearch.search.SearchHit; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.mockito.ArgumentCaptor; | |||
import org.sonar.api.config.internal.MapSettings; | |||
import org.sonar.api.platform.NewUserHandler; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.utils.internal.AlwaysIncreasingSystem2; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.property.PropertyDto; | |||
import org.sonar.db.property.PropertyQuery; | |||
import org.sonar.db.user.GroupDto; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.db.user.UserTesting; | |||
@@ -50,8 +51,10 @@ import org.sonar.server.usergroups.DefaultGroupFinder; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.assertj.core.data.MapEntry.entry; | |||
import static org.mockito.Mockito.mock; | |||
import static org.sonar.api.CoreProperties.DEFAULT_ISSUE_ASSIGNEE; | |||
import static org.sonar.db.user.UserTesting.newLocalUser; | |||
import static org.sonar.db.user.UserTesting.newUserDto; | |||
@@ -85,26 +88,21 @@ public class UserUpdaterUpdateTest { | |||
@Test | |||
public void update_user() { | |||
UserDto user = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@email.com") | |||
.setScmAccounts(asList("ma", "marius33")) | |||
.setSalt("79bd6a8e79fb8c76ac8b121cc7e8e11ad1af8365") | |||
.setCryptedPassword("650d2261c98361e2f67f90ce5c65a95e7d8ea2fg")); | |||
.setScmAccounts(asList("ma", "marius33"))); | |||
createDefaultGroup(); | |||
userIndexer.indexOnStartup(null); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN) | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setName("Marius2") | |||
.setEmail("marius2@mail.com") | |||
.setPassword("password2") | |||
.setScmAccounts(asList("ma2")), u -> { | |||
}); | |||
.setScmAccounts(singletonList("ma2")), u -> { | |||
}); | |||
UserDto updatedUser = dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN); | |||
assertThat(updatedUser.isActive()).isTrue(); | |||
assertThat(updatedUser.getName()).isEqualTo("Marius2"); | |||
assertThat(updatedUser.getEmail()).isEqualTo("marius2@mail.com"); | |||
assertThat(updatedUser.getScmAccountsAsList()).containsOnly("ma2"); | |||
assertThat(updatedUser.getSalt()).isNotEqualTo(user.getSalt()); | |||
assertThat(updatedUser.getCryptedPassword()).isNotEqualTo(user.getCryptedPassword()); | |||
assertThat(updatedUser.getCreatedAt()).isEqualTo(user.getCreatedAt()); | |||
assertThat(updatedUser.getUpdatedAt()).isGreaterThan(user.getCreatedAt()); | |||
@@ -122,14 +120,15 @@ public class UserUpdaterUpdateTest { | |||
UserDto user = db.users().insertUser(UserTesting.newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com")); | |||
createDefaultGroup(); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN) | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setName("Marius2") | |||
.setEmail("marius2@email.com") | |||
.setExternalIdentity(new ExternalIdentity("github", "john")), u -> { | |||
}); | |||
.setExternalIdentity(new ExternalIdentity("github", "john", "ABCD")), u -> { | |||
}); | |||
UserDto dto = dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN); | |||
assertThat(dto.getExternalIdentity()).isEqualTo("john"); | |||
assertThat(dto.getExternalId()).isEqualTo("ABCD"); | |||
assertThat(dto.getExternalLogin()).isEqualTo("john"); | |||
assertThat(dto.getExternalIdentityProvider()).isEqualTo("github"); | |||
assertThat(dto.getUpdatedAt()).isGreaterThan(user.getCreatedAt()); | |||
} | |||
@@ -139,14 +138,15 @@ public class UserUpdaterUpdateTest { | |||
UserDto user = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@email.com")); | |||
createDefaultGroup(); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN) | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setName("Marius2") | |||
.setEmail("marius2@email.com") | |||
.setExternalIdentity(new ExternalIdentity("github", "john")), u -> { | |||
}); | |||
.setExternalIdentity(new ExternalIdentity("github", "john", "ABCD")), u -> { | |||
}); | |||
UserDto dto = dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN); | |||
assertThat(dto.getExternalIdentity()).isEqualTo("john"); | |||
assertThat(dto.getExternalId()).isEqualTo("ABCD"); | |||
assertThat(dto.getExternalLogin()).isEqualTo("john"); | |||
assertThat(dto.getExternalIdentityProvider()).isEqualTo("github"); | |||
// Password must be removed | |||
assertThat(dto.getCryptedPassword()).isNull(); | |||
@@ -155,68 +155,98 @@ public class UserUpdaterUpdateTest { | |||
} | |||
@Test | |||
public void reactivate_user_on_update() { | |||
public void update_user_with_scm_accounts_containing_blank_entry() { | |||
UserDto user = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr") | |||
.setScmAccounts(asList("ma", "marius33")) | |||
.setSalt("salt") | |||
.setCryptedPassword("crypted password")); | |||
.setScmAccounts(asList("ma", "marius33"))); | |||
createDefaultGroup(); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN) | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setName("Marius2") | |||
.setEmail("marius2@mail.com") | |||
.setPassword("password2") | |||
.setScmAccounts(asList("ma2")), u -> { | |||
}); | |||
.setScmAccounts(asList("ma2", "", null)), u -> { | |||
}); | |||
UserDto dto = dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN); | |||
assertThat(dto.isActive()).isTrue(); | |||
assertThat(dto.getName()).isEqualTo("Marius2"); | |||
assertThat(dto.getEmail()).isEqualTo("marius2@mail.com"); | |||
assertThat(dto.getScmAccountsAsList()).containsOnly("ma2"); | |||
} | |||
@Test | |||
public void update_only_login() { | |||
UserDto oldUser = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr")); | |||
createDefaultGroup(); | |||
underTest.updateAndCommit(session, oldUser, new UpdateUser() | |||
.setLogin("new_login"), u -> { | |||
}); | |||
assertThat(dto.getSalt()).isNotEqualTo(user.getSalt()); | |||
assertThat(dto.getCryptedPassword()).isNotEqualTo(user.getCryptedPassword()); | |||
assertThat(dto.getCreatedAt()).isEqualTo(user.getCreatedAt()); | |||
assertThat(dto.getUpdatedAt()).isGreaterThan(user.getUpdatedAt()); | |||
assertThat(dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN)).isNull(); | |||
UserDto dto = dbClient.userDao().selectByUuid(session, oldUser.getUuid()); | |||
assertThat(dto.getLogin()).isEqualTo("new_login"); | |||
// Following fields has not changed | |||
assertThat(dto.getName()).isEqualTo(oldUser.getName()); | |||
assertThat(dto.getEmail()).isEqualTo(oldUser.getEmail()); | |||
assertThat(dto.getScmAccountsAsList()).containsAll(oldUser.getScmAccountsAsList()); | |||
assertThat(dto.getSalt()).isEqualTo(oldUser.getSalt()); | |||
assertThat(dto.getCryptedPassword()).isEqualTo(oldUser.getCryptedPassword()); | |||
} | |||
@Test | |||
public void update_index_when_updating_user_login() { | |||
UserDto oldUser = db.users().insertUser(); | |||
createDefaultGroup(); | |||
userIndexer.indexOnStartup(null); | |||
underTest.updateAndCommit(session, oldUser, new UpdateUser() | |||
.setLogin("new_login"), u -> { | |||
}); | |||
List<SearchHit> indexUsers = es.getDocuments(UserIndexDefinition.INDEX_TYPE_USER); | |||
assertThat(indexUsers).hasSize(1); | |||
assertThat(indexUsers.get(0).getSource()) | |||
.contains( | |||
entry("login", DEFAULT_LOGIN), | |||
entry("name", "Marius2"), | |||
entry("email", "marius2@mail.com")); | |||
.contains(entry("login", "new_login")); | |||
} | |||
@Test | |||
public void update_user_with_scm_accounts_containing_blank_entry() { | |||
db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr") | |||
.setScmAccounts(asList("ma", "marius33"))); | |||
public void update_default_assignee_when_updating_login() { | |||
createDefaultGroup(); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN) | |||
.setName("Marius2") | |||
.setEmail("marius2@mail.com") | |||
.setPassword("password2") | |||
.setScmAccounts(asList("ma2", "", null)), u -> { | |||
}); | |||
UserDto dto = dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN); | |||
assertThat(dto.getScmAccountsAsList()).containsOnly("ma2"); | |||
UserDto oldUser = db.users().insertUser(); | |||
ComponentDto project1 = db.components().insertPrivateProject(); | |||
ComponentDto project2 = db.components().insertPrivateProject(); | |||
ComponentDto anotherProject = db.components().insertPrivateProject(); | |||
db.properties().insertProperties( | |||
new PropertyDto().setKey(DEFAULT_ISSUE_ASSIGNEE).setValue(oldUser.getLogin()), | |||
new PropertyDto().setKey(DEFAULT_ISSUE_ASSIGNEE).setValue(oldUser.getLogin()).setResourceId(project1.getId()), | |||
new PropertyDto().setKey(DEFAULT_ISSUE_ASSIGNEE).setValue(oldUser.getLogin()).setResourceId(project2.getId()), | |||
new PropertyDto().setKey(DEFAULT_ISSUE_ASSIGNEE).setValue("another login").setResourceId(anotherProject.getId()) | |||
); | |||
userIndexer.indexOnStartup(null); | |||
underTest.updateAndCommit(session, oldUser, new UpdateUser() | |||
.setLogin("new_login"), u -> { | |||
}); | |||
assertThat(db.getDbClient().propertiesDao().selectByQuery(PropertyQuery.builder().setKey(DEFAULT_ISSUE_ASSIGNEE).build(), db.getSession())) | |||
.extracting(PropertyDto::getValue, PropertyDto::getResourceId) | |||
.containsOnly( | |||
tuple("new_login", null), | |||
tuple("new_login", project1.getId()), | |||
tuple("new_login", project2.getId()), | |||
tuple("another login", anotherProject.getId()) | |||
); | |||
} | |||
@Test | |||
public void update_only_user_name() { | |||
db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr") | |||
UserDto user = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr") | |||
.setScmAccounts(asList("ma", "marius33")) | |||
.setSalt("salt") | |||
.setCryptedPassword("crypted password")); | |||
createDefaultGroup(); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN) | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setName("Marius2"), u -> { | |||
}); | |||
}); | |||
UserDto dto = dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN); | |||
assertThat(dto.getName()).isEqualTo("Marius2"); | |||
@@ -230,15 +260,15 @@ public class UserUpdaterUpdateTest { | |||
@Test | |||
public void update_only_user_email() { | |||
db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr") | |||
UserDto user = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr") | |||
.setScmAccounts(asList("ma", "marius33")) | |||
.setSalt("salt") | |||
.setCryptedPassword("crypted password")); | |||
createDefaultGroup(); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN) | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setEmail("marius2@mail.com"), u -> { | |||
}); | |||
}); | |||
UserDto dto = dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN); | |||
assertThat(dto.getEmail()).isEqualTo("marius2@mail.com"); | |||
@@ -252,15 +282,15 @@ public class UserUpdaterUpdateTest { | |||
@Test | |||
public void update_only_scm_accounts() { | |||
db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr") | |||
UserDto user = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr") | |||
.setScmAccounts(asList("ma", "marius33")) | |||
.setSalt("salt") | |||
.setCryptedPassword("crypted password")); | |||
createDefaultGroup(); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN) | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setScmAccounts(asList("ma2")), u -> { | |||
}); | |||
}); | |||
UserDto dto = dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN); | |||
assertThat(dto.getScmAccountsAsList()).containsOnly("ma2"); | |||
@@ -274,13 +304,13 @@ public class UserUpdaterUpdateTest { | |||
@Test | |||
public void update_scm_accounts_with_same_values() { | |||
db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr") | |||
UserDto user = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr") | |||
.setScmAccounts(asList("ma", "marius33"))); | |||
createDefaultGroup(); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN) | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setScmAccounts(asList("ma", "marius33")), u -> { | |||
}); | |||
}); | |||
UserDto dto = dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN); | |||
assertThat(dto.getScmAccountsAsList()).containsOnly("ma", "marius33"); | |||
@@ -288,13 +318,13 @@ public class UserUpdaterUpdateTest { | |||
@Test | |||
public void remove_scm_accounts() { | |||
db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr") | |||
UserDto user = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr") | |||
.setScmAccounts(asList("ma", "marius33"))); | |||
createDefaultGroup(); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN) | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setScmAccounts(null), u -> { | |||
}); | |||
}); | |||
UserDto dto = dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN); | |||
assertThat(dto.getScmAccounts()).isNull(); | |||
@@ -302,15 +332,15 @@ public class UserUpdaterUpdateTest { | |||
@Test | |||
public void update_only_user_password() { | |||
db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr") | |||
UserDto user = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr") | |||
.setScmAccounts(asList("ma", "marius33")) | |||
.setSalt("salt") | |||
.setCryptedPassword("crypted password")); | |||
createDefaultGroup(); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN) | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setPassword("password2"), u -> { | |||
}); | |||
}); | |||
UserDto dto = dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN); | |||
assertThat(dto.getSalt()).isNotEqualTo("salt"); | |||
@@ -323,50 +353,66 @@ public class UserUpdaterUpdateTest { | |||
} | |||
@Test | |||
public void update_only_external_identity_id() { | |||
db.users().insertUser(UserTesting.newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com") | |||
.setExternalIdentity("john") | |||
public void update_only_external_id() { | |||
UserDto user = db.users().insertUser(UserTesting.newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com") | |||
.setExternalId("1234") | |||
.setExternalLogin("john.smith") | |||
.setExternalIdentityProvider("github")); | |||
createDefaultGroup(); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN).setExternalIdentity(new ExternalIdentity("github", "john.smith")), u -> { | |||
underTest.updateAndCommit(session, user, new UpdateUser().setExternalIdentity(new ExternalIdentity("github", "john.smith", "ABCD")), u -> { | |||
}); | |||
assertThat(dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN)) | |||
.extracting(UserDto::getExternalIdentity, UserDto::getExternalIdentityProvider) | |||
.extracting(UserDto::getExternalId) | |||
.containsOnly("ABCD"); | |||
} | |||
@Test | |||
public void update_only_external_login() { | |||
UserDto user = db.users().insertUser(UserTesting.newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com") | |||
.setExternalId("ABCD") | |||
.setExternalLogin("john") | |||
.setExternalIdentityProvider("github")); | |||
createDefaultGroup(); | |||
underTest.updateAndCommit(session, user, new UpdateUser().setExternalIdentity(new ExternalIdentity("github", "john.smith", "ABCD")), u -> { | |||
}); | |||
assertThat(dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN)) | |||
.extracting(UserDto::getExternalLogin, UserDto::getExternalIdentityProvider) | |||
.containsOnly("john.smith", "github"); | |||
} | |||
@Test | |||
public void update_only_external_identity_provider() { | |||
db.users().insertUser(UserTesting.newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com") | |||
.setExternalIdentity("john") | |||
UserDto user = db.users().insertUser(UserTesting.newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com") | |||
.setExternalId("ABCD") | |||
.setExternalLogin("john") | |||
.setExternalIdentityProvider("github")); | |||
createDefaultGroup(); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN).setExternalIdentity(new ExternalIdentity("bitbucket", "john")), u -> { | |||
underTest.updateAndCommit(session, user, new UpdateUser().setExternalIdentity(new ExternalIdentity("bitbucket", "john", "ABCD")), u -> { | |||
}); | |||
assertThat(dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN)) | |||
.extracting(UserDto::getExternalIdentity, UserDto::getExternalIdentityProvider) | |||
.extracting(UserDto::getExternalLogin, UserDto::getExternalIdentityProvider) | |||
.containsOnly("john", "bitbucket"); | |||
} | |||
@Test | |||
public void does_not_update_user_when_no_change() { | |||
UserDto user = UserTesting.newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com") | |||
.setExternalIdentity("john") | |||
.setExternalIdentityProvider("github") | |||
.setScmAccounts(asList("ma1", "ma2")); | |||
db.users().insertUser(user); | |||
createDefaultGroup(); | |||
underTest.updateAndCommit(session, UpdateUser.create(user.getLogin()) | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setName(user.getName()) | |||
.setEmail(user.getEmail()) | |||
.setScmAccounts(user.getScmAccountsAsList()) | |||
.setExternalIdentity(new ExternalIdentity(user.getExternalIdentityProvider(), user.getExternalIdentity())), u -> { | |||
}); | |||
.setExternalIdentity(new ExternalIdentity(user.getExternalIdentityProvider(), user.getExternalLogin(), user.getExternalId())), u -> { | |||
}); | |||
assertThat(dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN).getUpdatedAt()).isEqualTo(user.getUpdatedAt()); | |||
} | |||
@@ -374,18 +420,16 @@ public class UserUpdaterUpdateTest { | |||
@Test | |||
public void does_not_update_user_when_no_change_and_scm_account_reordered() { | |||
UserDto user = UserTesting.newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com") | |||
.setExternalIdentity("john") | |||
.setExternalIdentityProvider("github") | |||
.setScmAccounts(asList("ma1", "ma2")); | |||
db.users().insertUser(user); | |||
createDefaultGroup(); | |||
underTest.updateAndCommit(session, UpdateUser.create(user.getLogin()) | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setName(user.getName()) | |||
.setEmail(user.getEmail()) | |||
.setScmAccounts(asList("ma2", "ma1")) | |||
.setExternalIdentity(new ExternalIdentity(user.getExternalIdentityProvider(), user.getExternalIdentity())), u -> { | |||
}); | |||
.setExternalIdentity(new ExternalIdentity(user.getExternalIdentityProvider(), user.getExternalLogin(), user.getExternalId())), u -> { | |||
}); | |||
assertThat(dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN).getUpdatedAt()).isEqualTo(user.getUpdatedAt()); | |||
} | |||
@@ -397,52 +441,52 @@ public class UserUpdaterUpdateTest { | |||
.setScmAccounts(asList("ma", "marius33"))); | |||
UserDto otherUser = db.users().insertUser(); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN) | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setName("Marius2") | |||
.setEmail("marius2@mail.com") | |||
.setPassword("password2") | |||
.setScmAccounts(asList("ma2")), u -> { | |||
}, otherUser); | |||
}, otherUser); | |||
assertThat(es.getIds(UserIndexDefinition.INDEX_TYPE_USER)).containsExactlyInAnyOrder(user.getLogin(), otherUser.getLogin()); | |||
assertThat(es.getIds(UserIndexDefinition.INDEX_TYPE_USER)).containsExactlyInAnyOrder(user.getUuid(), otherUser.getUuid()); | |||
} | |||
@Test | |||
public void fail_to_set_null_password_when_local_user() { | |||
db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@email.com")); | |||
UserDto user = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@email.com")); | |||
createDefaultGroup(); | |||
expectedException.expect(BadRequestException.class); | |||
expectedException.expectMessage("Password can't be empty"); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN).setPassword(null), u -> { | |||
underTest.updateAndCommit(session, user, new UpdateUser().setPassword(null), u -> { | |||
}); | |||
} | |||
@Test | |||
public void fail_to_update_password_when_user_is_not_local() { | |||
db.users().insertUser(newUserDto() | |||
UserDto user = db.users().insertUser(newUserDto() | |||
.setLogin(DEFAULT_LOGIN) | |||
.setLocal(false)); | |||
createDefaultGroup(); | |||
expectedException.expect(BadRequestException.class); | |||
expectedException.expectMessage("Password cannot be changed when external authentication is used"); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN).setPassword("password2"), u -> { | |||
underTest.updateAndCommit(session, user, new UpdateUser().setPassword("password2"), u -> { | |||
}); | |||
} | |||
@Test | |||
public void not_associate_default_group_when_updating_user() { | |||
db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@email.com")); | |||
UserDto user = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@email.com")); | |||
GroupDto defaultGroup = createDefaultGroup(); | |||
// Existing user, he has no group, and should not be associated to the default one | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN) | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setName("Marius2") | |||
.setEmail("marius2@mail.com") | |||
.setPassword("password2") | |||
.setScmAccounts(asList("ma2")), u -> { | |||
}); | |||
}); | |||
Multimap<String, String> groups = dbClient.groupMembershipDao().selectGroupsByLogins(session, asList(DEFAULT_LOGIN)); | |||
assertThat(groups.get(DEFAULT_LOGIN).stream().anyMatch(g -> g.equals(defaultGroup.getName()))).isFalse(); | |||
@@ -458,12 +502,12 @@ public class UserUpdaterUpdateTest { | |||
Multimap<String, String> groups = dbClient.groupMembershipDao().selectGroupsByLogins(session, asList(DEFAULT_LOGIN)); | |||
assertThat(groups.get(DEFAULT_LOGIN).stream().anyMatch(g -> g.equals(defaultGroup.getName()))).as("Current user groups : %s", groups.get(defaultGroup.getName())).isTrue(); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN) | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setName("Marius2") | |||
.setEmail("marius2@mail.com") | |||
.setPassword("password2") | |||
.setScmAccounts(asList("ma2")), u -> { | |||
}); | |||
}); | |||
// Nothing as changed | |||
groups = dbClient.groupMembershipDao().selectGroupsByLogins(session, asList(DEFAULT_LOGIN)); | |||
@@ -472,56 +516,95 @@ public class UserUpdaterUpdateTest { | |||
@Test | |||
public void fail_to_update_user_when_scm_account_is_already_used() { | |||
db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@email.com").setScmAccounts(singletonList("ma"))); | |||
UserDto user = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@email.com").setScmAccounts(singletonList("ma"))); | |||
db.users().insertUser(newLocalUser("john", "John", "john@email.com").setScmAccounts(singletonList("jo"))); | |||
createDefaultGroup(); | |||
expectedException.expect(BadRequestException.class); | |||
expectedException.expectMessage("The scm account 'jo' is already used by user(s) : 'John (john)'"); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN) | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setName("Marius2") | |||
.setEmail("marius2@mail.com") | |||
.setPassword("password2") | |||
.setScmAccounts(asList("jo")), u -> { | |||
}); | |||
}); | |||
} | |||
@Test | |||
public void fail_to_update_user_when_scm_account_is_user_login() { | |||
db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr")); | |||
UserDto user = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr")); | |||
createDefaultGroup(); | |||
expectedException.expect(BadRequestException.class); | |||
expectedException.expectMessage("Login and email are automatically considered as SCM accounts"); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN).setScmAccounts(asList(DEFAULT_LOGIN)), u -> { | |||
underTest.updateAndCommit(session, user, new UpdateUser().setScmAccounts(asList(DEFAULT_LOGIN)), u -> { | |||
}); | |||
} | |||
@Test | |||
public void fail_to_update_user_when_scm_account_is_existing_user_email() { | |||
db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr")); | |||
UserDto user = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr")); | |||
createDefaultGroup(); | |||
expectedException.expect(BadRequestException.class); | |||
expectedException.expectMessage("Login and email are automatically considered as SCM accounts"); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN).setScmAccounts(asList("marius@lesbronzes.fr")), u -> { | |||
underTest.updateAndCommit(session, user, new UpdateUser().setScmAccounts(asList("marius@lesbronzes.fr")), u -> { | |||
}); | |||
} | |||
@Test | |||
public void fail_to_update_user_when_scm_account_is_new_user_email() { | |||
db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr")); | |||
UserDto user = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr")); | |||
createDefaultGroup(); | |||
expectedException.expect(BadRequestException.class); | |||
expectedException.expectMessage("Login and email are automatically considered as SCM accounts"); | |||
underTest.updateAndCommit(session, UpdateUser.create(DEFAULT_LOGIN) | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setEmail("marius@newmail.com") | |||
.setScmAccounts(asList("marius@newmail.com")), u -> { | |||
}); | |||
} | |||
@Test | |||
public void fail_to_update_login_when_format_is_invalid() { | |||
UserDto user = db.users().insertUser(); | |||
createDefaultGroup(); | |||
expectedException.expect(BadRequestException.class); | |||
expectedException.expectMessage("Use only letters, numbers, and .-_@ please."); | |||
underTest.updateAndCommit(session, user, new UpdateUser().setLogin("With space"), u -> { | |||
}); | |||
} | |||
@Test | |||
public void fail_to_update_user_when_login_already_exists() { | |||
createDefaultGroup(); | |||
UserDto user = db.users().insertUser(u -> u.setActive(false)); | |||
UserDto existingUser = db.users().insertUser(u -> u.setLogin("existing_login")); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("A user with login 'existing_login' already exists"); | |||
underTest.updateAndCommit(session, user, new UpdateUser().setLogin(existingUser.getLogin()), u -> { | |||
}); | |||
} | |||
@Test | |||
public void fail_to_update_user_when_external_id_and_external_provider_already_exists() { | |||
createDefaultGroup(); | |||
UserDto user = db.users().insertUser(u -> u.setActive(false)); | |||
UserDto existingUser = db.users().insertUser(u -> u.setExternalId("existing_external_id").setExternalIdentityProvider("existing_external_provider")); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("A user with provider id 'existing_external_id' and identity provider 'existing_external_provider' already exists"); | |||
underTest.updateAndCommit(session, user, new UpdateUser() | |||
.setExternalIdentity(new ExternalIdentity(existingUser.getExternalIdentityProvider(), existingUser.getExternalLogin(), existingUser.getExternalId())), u -> { | |||
}); | |||
} | |||
private GroupDto createDefaultGroup() { | |||
return db.users().insertDefaultGroup(db.getDefaultOrganization()); | |||
} |
@@ -25,6 +25,7 @@ import java.util.Locale; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.core.util.Uuids; | |||
import org.sonar.server.es.EsTester; | |||
import org.sonar.server.es.SearchOptions; | |||
@@ -47,33 +48,6 @@ public class UserIndexTest { | |||
private UserIndex underTest = new UserIndex(es.client(), System2.INSTANCE); | |||
private UserQuery.Builder userQuery = UserQuery.builder(); | |||
@Test | |||
public void get_nullable_by_login() { | |||
UserDoc user1 = newUser(USER1_LOGIN, asList("scmA", "scmB")); | |||
es.putDocuments(INDEX_TYPE_USER, user1); | |||
es.putDocuments(INDEX_TYPE_USER, newUser(USER2_LOGIN, Collections.emptyList())); | |||
UserDoc userDoc = underTest.getNullableByLogin(USER1_LOGIN); | |||
assertThat(userDoc).isNotNull(); | |||
assertThat(userDoc.login()).isEqualTo(user1.login()); | |||
assertThat(userDoc.name()).isEqualTo(user1.name()); | |||
assertThat(userDoc.email()).isEqualTo(user1.email()); | |||
assertThat(userDoc.active()).isTrue(); | |||
assertThat(userDoc.scmAccounts()).isEqualTo(user1.scmAccounts()); | |||
assertThat(underTest.getNullableByLogin("")).isNull(); | |||
assertThat(underTest.getNullableByLogin("unknown")).isNull(); | |||
} | |||
@Test | |||
public void getNullableByLogin_is_case_sensitive() { | |||
UserDoc user1 = newUser(USER1_LOGIN, asList("scmA", "scmB")); | |||
es.putDocuments(INDEX_TYPE_USER, user1); | |||
assertThat(underTest.getNullableByLogin(USER1_LOGIN)).isNotNull(); | |||
assertThat(underTest.getNullableByLogin("UsEr1")).isNull(); | |||
} | |||
@Test | |||
public void getAtMostThreeActiveUsersForScmAccount_returns_the_users_with_specified_scm_account() { | |||
UserDoc user1 = newUser("user1", asList("user_1", "u1")); | |||
@@ -199,6 +173,7 @@ public class UserIndexTest { | |||
private static UserDoc newUser(String login, List<String> scmAccounts) { | |||
return new UserDoc() | |||
.setUuid(Uuids.createFast()) | |||
.setLogin(login) | |||
.setName(login.toUpperCase(Locale.ENGLISH)) | |||
.setEmail(login + "@mail.com") | |||
@@ -209,6 +184,7 @@ public class UserIndexTest { | |||
private static UserDoc newUser(String login, String email, List<String> scmAccounts) { | |||
return new UserDoc() | |||
.setUuid(Uuids.createFast()) | |||
.setLogin(login) | |||
.setName(login.toUpperCase(Locale.ENGLISH)) | |||
.setEmail(email) |
@@ -25,12 +25,14 @@ import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.db.user.UserTesting; | |||
import org.sonar.server.es.EsTester; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
public class UserIndexerTest { | |||
@@ -53,19 +55,38 @@ public class UserIndexerTest { | |||
@Test | |||
public void indexOnStartup_adds_all_users_to_index() { | |||
UserDto user = db.users().insertUser(u -> u | |||
.setScmAccounts(asList("user_1", "u1"))); | |||
UserDto user = db.users().insertUser(u -> u.setScmAccounts(asList("user_1", "u1"))); | |||
underTest.indexOnStartup(new HashSet<>()); | |||
List<UserDoc> docs = es.getDocuments(UserIndexDefinition.INDEX_TYPE_USER, UserDoc.class); | |||
assertThat(docs).hasSize(1); | |||
UserDoc doc = docs.get(0); | |||
assertThat(doc.uuid()).isEqualTo(user.getUuid()); | |||
assertThat(doc.login()).isEqualTo(user.getLogin()); | |||
assertThat(doc.name()).isEqualTo(user.getName()); | |||
assertThat(doc.email()).isEqualTo(user.getEmail()); | |||
assertThat(doc.active()).isEqualTo(user.isActive()); | |||
assertThat(doc.scmAccounts()).isEqualTo(user.getScmAccountsAsList()); | |||
assertThat(doc.organizationUuids()).isEmpty(); | |||
} | |||
@Test | |||
public void indexOnStartup_adds_all_users_with_organizations() { | |||
OrganizationDto organization1 = db.organizations().insert(); | |||
OrganizationDto organization2 = db.organizations().insert(); | |||
UserDto user = db.users().insertUser(); | |||
db.organizations().addMember(organization1, user); | |||
db.organizations().addMember(organization2, user); | |||
underTest.indexOnStartup(new HashSet<>()); | |||
List<UserDoc> docs = es.getDocuments(UserIndexDefinition.INDEX_TYPE_USER, UserDoc.class); | |||
assertThat(docs).hasSize(1); | |||
UserDoc doc = docs.get(0); | |||
assertThat(doc.uuid()).isEqualTo(user.getUuid()); | |||
assertThat(doc.login()).isEqualTo(user.getLogin()); | |||
assertThat(doc.organizationUuids()).containsExactlyInAnyOrder(organization1.getUuid(), organization2.getUuid()); | |||
} | |||
@Test | |||
@@ -76,21 +97,47 @@ public class UserIndexerTest { | |||
underTest.commitAndIndex(db.getSession(), user); | |||
List<UserDoc> docs = es.getDocuments(UserIndexDefinition.INDEX_TYPE_USER, UserDoc.class); | |||
assertThat(docs).hasSize(1); | |||
assertThat(docs).extracting(UserDoc::login) | |||
.containsExactly(user.getLogin()) | |||
.doesNotContain(anotherUser.getLogin()); | |||
assertThat(docs) | |||
.extracting(UserDoc::uuid) | |||
.containsExactlyInAnyOrder(user.getUuid()) | |||
.doesNotContain(anotherUser.getUuid()); | |||
} | |||
@Test | |||
public void commitAndIndex_single_user_belonging_to_organizations() { | |||
OrganizationDto organization1 = db.organizations().insert(); | |||
OrganizationDto organization2 = db.organizations().insert(); | |||
UserDto user = db.users().insertUser(); | |||
db.organizations().addMember(organization1, user); | |||
db.organizations().addMember(organization2, user); | |||
UserDto anotherUser = db.users().insertUser(); | |||
db.organizations().addMember(organization1, anotherUser); | |||
underTest.commitAndIndex(db.getSession(), user); | |||
List<UserDoc> docs = es.getDocuments(UserIndexDefinition.INDEX_TYPE_USER, UserDoc.class); | |||
assertThat(docs) | |||
.extracting(UserDoc::uuid, UserDoc::organizationUuids) | |||
.containsExactlyInAnyOrder(tuple(user.getUuid(), asList(organization1.getUuid(), organization2.getUuid()))); | |||
} | |||
@Test | |||
public void commitAndIndex_multiple_users() { | |||
UserDto user1 = db.getDbClient().userDao().insert(db.getSession(), UserTesting.newUserDto()); | |||
UserDto user2 = db.getDbClient().userDao().insert(db.getSession(), UserTesting.newUserDto()); | |||
OrganizationDto organization1 = db.organizations().insert(); | |||
UserDto user1 = db.users().insertUser(); | |||
db.organizations().addMember(organization1, user1); | |||
OrganizationDto organization2 = db.organizations().insert(); | |||
UserDto user2 = db.users().insertUser(); | |||
db.organizations().addMember(organization2, user2); | |||
underTest.commitAndIndex(db.getSession(), asList(user1, user2)); | |||
List<UserDoc> docs = es.getDocuments(UserIndexDefinition.INDEX_TYPE_USER, UserDoc.class); | |||
assertThat(docs).extracting(UserDoc::login).containsExactlyInAnyOrder(user1.getLogin(), user2.getLogin()); | |||
assertThat(docs) | |||
.extracting(UserDoc::login, UserDoc::organizationUuids) | |||
.containsExactlyInAnyOrder( | |||
tuple(user1.getLogin(), singletonList(organization1.getUuid())), | |||
tuple(user2.getLogin(), singletonList(organization2.getUuid()))); | |||
assertThat(db.countRowsOfTable(db.getSession(), "users")).isEqualTo(2); | |||
} | |||
} |
@@ -34,17 +34,18 @@ import org.sonar.server.organization.OrganizationCreation; | |||
import org.sonar.server.organization.TestDefaultOrganizationProvider; | |||
import org.sonar.server.organization.TestOrganizationFlags; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.user.ExternalIdentity; | |||
import org.sonar.server.user.NewUser; | |||
import org.sonar.server.user.NewUserNotifier; | |||
import org.sonar.server.user.UserUpdater; | |||
import org.sonar.server.user.index.UserIndexer; | |||
import org.sonar.server.usergroups.DefaultGroupFinder; | |||
import org.sonar.server.ws.WsTester; | |||
import org.sonar.server.ws.TestResponse; | |||
import org.sonar.server.ws.WsActionTester; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.sonar.db.user.UserTesting.newExternalUser; | |||
import static org.sonar.db.user.UserTesting.newLocalUser; | |||
public class ChangePasswordActionTest { | |||
@Rule | |||
@@ -67,7 +68,7 @@ public class ChangePasswordActionTest { | |||
new MapSettings().asConfig(), | |||
localAuthentication); | |||
private WsTester tester = new WsTester(new UsersWs(new ChangePasswordAction(db.getDbClient(), userUpdater, userSessionRule, localAuthentication))); | |||
private WsActionTester tester = new WsActionTester(new ChangePasswordAction(db.getDbClient(), userUpdater, userSessionRule, localAuthentication)); | |||
@Before | |||
public void setUp() { | |||
@@ -75,80 +76,102 @@ public class ChangePasswordActionTest { | |||
} | |||
@Test | |||
public void fail_on_missing_permission() throws Exception { | |||
createUser(); | |||
userSessionRule.logIn("polop"); | |||
public void a_user_can_update_his_password() { | |||
userUpdater.createAndCommit(db.getSession(), NewUser.builder() | |||
.setEmail("john@email.com") | |||
.setLogin("john") | |||
.setName("John") | |||
.setPassword("Valar Dohaeris") | |||
.build(), u -> { | |||
}); | |||
String oldCryptedPassword = db.getDbClient().userDao().selectOrFailByLogin(db.getSession(), "john").getCryptedPassword(); | |||
userSessionRule.logIn("john"); | |||
expectedException.expect(ForbiddenException.class); | |||
tester.newPostRequest("api/users", "change_password") | |||
TestResponse response = tester.newRequest() | |||
.setParam("login", "john") | |||
.setParam("previousPassword", "Valar Dohaeris") | |||
.setParam("password", "Valar Morghulis") | |||
.execute(); | |||
} | |||
@Test | |||
public void fail_on_unknown_user() throws Exception { | |||
userSessionRule.logIn().setSystemAdministrator(); | |||
expectedException.expect(NotFoundException.class); | |||
tester.newPostRequest("api/users", "change_password") | |||
.setParam("login", "polop") | |||
.setParam("password", "polop") | |||
.execute(); | |||
assertThat(response.getStatus()).isEqualTo(204); | |||
String newCryptedPassword = db.getDbClient().userDao().selectOrFailByLogin(db.getSession(), "john").getCryptedPassword(); | |||
assertThat(newCryptedPassword).isNotEqualTo(oldCryptedPassword); | |||
} | |||
@Test | |||
public void system_administrator_can_update_password_of_user() throws Exception { | |||
public void system_administrator_can_update_password_of_user() { | |||
userSessionRule.logIn().setSystemAdministrator(); | |||
createUser(); | |||
createLocalUser(); | |||
String originalPassword = db.getDbClient().userDao().selectOrFailByLogin(db.getSession(), "john").getCryptedPassword(); | |||
tester.newPostRequest("api/users", "change_password") | |||
tester.newRequest() | |||
.setParam("login", "john") | |||
.setParam("password", "Valar Morghulis") | |||
.execute() | |||
.assertNoContent(); | |||
.execute(); | |||
String newPassword = db.getDbClient().userDao().selectOrFailByLogin(db.getSession(), "john").getCryptedPassword(); | |||
assertThat(newPassword).isNotEqualTo(originalPassword); | |||
} | |||
@Test | |||
public void a_user_can_update_his_password() throws Exception { | |||
createUser(); | |||
String originalPassword = db.getDbClient().userDao().selectOrFailByLogin(db.getSession(), "john").getCryptedPassword(); | |||
public void fail_on_missing_permission() { | |||
createLocalUser(); | |||
userSessionRule.logIn("polop"); | |||
userSessionRule.logIn("john"); | |||
tester.newPostRequest("api/users", "change_password") | |||
expectedException.expect(ForbiddenException.class); | |||
tester.newRequest() | |||
.setParam("login", "john") | |||
.setParam("previousPassword", "Valar Dohaeris") | |||
.setParam("password", "Valar Morghulis") | |||
.execute() | |||
.assertNoContent(); | |||
.execute(); | |||
} | |||
String newPassword = db.getDbClient().userDao().selectOrFailByLogin(db.getSession(), "john").getCryptedPassword(); | |||
assertThat(newPassword).isNotEqualTo(originalPassword); | |||
@Test | |||
public void fail_on_unknown_user() { | |||
userSessionRule.logIn().setSystemAdministrator(); | |||
expectedException.expect(NotFoundException.class); | |||
expectedException.expectMessage("User with login 'polop' has not been found"); | |||
tester.newRequest() | |||
.setParam("login", "polop") | |||
.setParam("password", "polop") | |||
.execute(); | |||
} | |||
@Test | |||
public void fail_on_disabled_user() { | |||
db.users().insertUser(u -> u.setLogin( "polop").setActive(false)); | |||
userSessionRule.logIn().setSystemAdministrator(); | |||
expectedException.expect(NotFoundException.class); | |||
expectedException.expectMessage("User with login 'polop' has not been found"); | |||
tester.newRequest() | |||
.setParam("login", "polop") | |||
.setParam("password", "polop") | |||
.execute(); | |||
} | |||
@Test | |||
public void fail_to_update_password_on_self_without_old_password() throws Exception { | |||
createUser(); | |||
public void fail_to_update_password_on_self_without_old_password() { | |||
createLocalUser(); | |||
userSessionRule.logIn("john"); | |||
expectedException.expect(IllegalArgumentException.class); | |||
tester.newPostRequest("api/users", "change_password") | |||
tester.newRequest() | |||
.setParam("login", "john") | |||
.setParam("password", "Valar Morghulis") | |||
.execute(); | |||
} | |||
@Test | |||
public void fail_to_update_password_on_self_with_bad_old_password() throws Exception { | |||
createUser(); | |||
public void fail_to_update_password_on_self_with_bad_old_password() { | |||
createLocalUser(); | |||
userSessionRule.logIn("john"); | |||
expectedException.expect(IllegalArgumentException.class); | |||
tester.newPostRequest("api/users", "change_password") | |||
tester.newRequest() | |||
.setParam("login", "john") | |||
.setParam("previousPassword", "I dunno") | |||
.setParam("password", "Valar Morghulis") | |||
@@ -156,34 +179,19 @@ public class ChangePasswordActionTest { | |||
} | |||
@Test | |||
public void fail_to_update_password_on_external_auth() throws Exception { | |||
public void fail_to_update_password_on_external_auth() { | |||
userSessionRule.logIn().setSystemAdministrator(); | |||
NewUser newUser = NewUser.builder() | |||
.setEmail("john@email.com") | |||
.setLogin("john") | |||
.setName("John") | |||
.setScmAccounts(newArrayList("jn")) | |||
.setExternalIdentity(new ExternalIdentity("gihhub", "john")) | |||
.build(); | |||
userUpdater.createAndCommit(db.getSession(), newUser, u -> { | |||
}); | |||
db.users().insertUser(newExternalUser("john", "John", "john@email.com")); | |||
expectedException.expect(BadRequestException.class); | |||
tester.newPostRequest("api/users", "change_password") | |||
tester.newRequest() | |||
.setParam("login", "john") | |||
.setParam("password", "Valar Morghulis") | |||
.execute(); | |||
} | |||
private void createUser() { | |||
userUpdater.createAndCommit(db.getSession(), NewUser.builder() | |||
.setEmail("john@email.com") | |||
.setLogin("john") | |||
.setName("John") | |||
.setScmAccounts(newArrayList("jn")) | |||
.setPassword("Valar Dohaeris") | |||
.build(), u -> { | |||
}); | |||
private void createLocalUser() { | |||
db.users().insertUser(newLocalUser("john", "John", "john@email.com")); | |||
} | |||
} |
@@ -44,8 +44,8 @@ import org.sonar.server.organization.TestOrganizationFlags; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.user.NewUserNotifier; | |||
import org.sonar.server.user.UserUpdater; | |||
import org.sonar.server.user.index.UserDoc; | |||
import org.sonar.server.user.index.UserIndex; | |||
import org.sonar.server.user.index.UserIndexDefinition; | |||
import org.sonar.server.user.index.UserIndexer; | |||
import org.sonar.server.user.ws.CreateAction.CreateRequest; | |||
import org.sonar.server.usergroups.DefaultGroupFinder; | |||
@@ -54,13 +54,20 @@ import org.sonar.server.ws.WsActionTester; | |||
import org.sonarqube.ws.Users.CreateWsResponse; | |||
import org.sonarqube.ws.Users.CreateWsResponse.User; | |||
import static java.lang.String.format; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.elasticsearch.index.query.QueryBuilders.boolQuery; | |||
import static org.elasticsearch.index.query.QueryBuilders.termQuery; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.sonar.core.util.Protobuf.setNullable; | |||
import static org.sonar.db.user.UserTesting.newUserDto; | |||
import static org.sonar.server.user.index.UserIndexDefinition.FIELD_EMAIL; | |||
import static org.sonar.server.user.index.UserIndexDefinition.FIELD_LOGIN; | |||
import static org.sonar.server.user.index.UserIndexDefinition.FIELD_NAME; | |||
import static org.sonar.server.user.index.UserIndexDefinition.FIELD_SCM_ACCOUNTS; | |||
public class CreateActionTest { | |||
@@ -111,11 +118,14 @@ public class CreateActionTest { | |||
.extracting(User::getLogin, User::getName, User::getEmail, User::getScmAccountsList, User::getLocal) | |||
.containsOnly("john", "John", "john@email.com", singletonList("jn"), true); | |||
UserDoc user = index.getNullableByLogin("john"); | |||
assertThat(user.login()).isEqualTo("john"); | |||
assertThat(user.name()).isEqualTo("John"); | |||
assertThat(user.email()).isEqualTo("john@email.com"); | |||
assertThat(user.scmAccounts()).containsOnly("jn"); | |||
// exists in index | |||
assertThat(es.client().prepareSearch(UserIndexDefinition.INDEX_TYPE_USER) | |||
.setQuery(boolQuery() | |||
.must(termQuery(FIELD_LOGIN, "john")) | |||
.must(termQuery(FIELD_NAME, "John")) | |||
.must(termQuery(FIELD_EMAIL, "john@email.com")) | |||
.must(termQuery(FIELD_SCM_ACCOUNTS, "jn"))) | |||
.get().getHits().getHits()).hasSize(1); | |||
// exists in db | |||
Optional<UserDto> dbUser = db.users().selectUserByLogin("john"); | |||
@@ -168,7 +178,7 @@ public class CreateActionTest { | |||
.build()); | |||
assertThat(db.users().selectUserByLogin("john").get()) | |||
.extracting(UserDto::isLocal, UserDto::getExternalIdentityProvider, UserDto::getExternalIdentity, UserDto::isRoot) | |||
.extracting(UserDto::isLocal, UserDto::getExternalIdentityProvider, UserDto::getExternalLogin, UserDto::isRoot) | |||
.containsOnly(true, "sonarqube", "john", false); | |||
} | |||
@@ -183,7 +193,7 @@ public class CreateActionTest { | |||
.build()); | |||
assertThat(db.users().selectUserByLogin("john").get()) | |||
.extracting(UserDto::isLocal, UserDto::getExternalIdentityProvider, UserDto::getExternalIdentity, UserDto::isRoot) | |||
.extracting(UserDto::isLocal, UserDto::getExternalIdentityProvider, UserDto::getExternalLogin, UserDto::isRoot) | |||
.containsOnly(false, "sonarqube", "john", false); | |||
} | |||
@@ -214,7 +224,7 @@ public class CreateActionTest { | |||
.build()); | |||
assertThat(db.users().selectUserByLogin("john").get()) | |||
.extracting(UserDto::getExternalIdentity) | |||
.extracting(UserDto::getExternalLogin) | |||
.containsOnly("john"); | |||
} | |||
@@ -264,6 +274,21 @@ public class CreateActionTest { | |||
assertThat(db.users().selectUserByLogin("john").get().isActive()).isTrue(); | |||
} | |||
@Test | |||
public void fail_to_reactivate_user_when_active_user_exists() { | |||
logInAsSystemAdministrator(); | |||
UserDto user = db.users().insertUser(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage(format("An active user with login '%s' already exists", user.getLogin())); | |||
call(CreateRequest.builder() | |||
.setLogin(user.getLogin()) | |||
.setName("John") | |||
.setPassword("1234") | |||
.build()); | |||
} | |||
@Test | |||
public void fail_when_missing_login() { | |||
logInAsSystemAdministrator(); | |||
@@ -343,10 +368,6 @@ public class CreateActionTest { | |||
executeRequest("john"); | |||
} | |||
private void setDefaultGroupProperty(GroupDto adminGroup) { | |||
settings.setProperty("sonar.defaultGroup", adminGroup.getName()); | |||
} | |||
private CreateWsResponse executeRequest(String login) { | |||
return call(CreateRequest.builder() | |||
.setLogin(login) |
@@ -79,7 +79,7 @@ public class CurrentActionTest { | |||
.setName("Obiwan Kenobi") | |||
.setEmail("obiwan.kenobi@starwars.com") | |||
.setLocal(true) | |||
.setExternalIdentity("obiwan") | |||
.setExternalLogin("obiwan") | |||
.setExternalIdentityProvider("sonarqube") | |||
.setScmAccounts(newArrayList("obiwan:github", "obiwan:bitbucket")) | |||
.setOnboarded(false)); | |||
@@ -102,7 +102,7 @@ public class CurrentActionTest { | |||
.setName("Obiwan Kenobi") | |||
.setEmail(null) | |||
.setLocal(true) | |||
.setExternalIdentity("obiwan") | |||
.setExternalLogin("obiwan") | |||
.setExternalIdentityProvider("sonarqube") | |||
.setScmAccounts((String) null)); | |||
userSessionRule.logIn("obiwan.kenobi"); | |||
@@ -336,7 +336,7 @@ public class CurrentActionTest { | |||
.setName("Obiwan Kenobi") | |||
.setEmail("obiwan.kenobi@starwars.com") | |||
.setLocal(true) | |||
.setExternalIdentity("obiwan.kenobi") | |||
.setExternalLogin("obiwan.kenobi") | |||
.setExternalIdentityProvider("sonarqube") | |||
.setScmAccounts(newArrayList("obiwan:github", "obiwan:bitbucket")) | |||
.setOnboarded(true) |
@@ -45,13 +45,15 @@ import org.sonar.server.exceptions.UnauthorizedException; | |||
import org.sonar.server.organization.DefaultOrganizationProvider; | |||
import org.sonar.server.organization.TestDefaultOrganizationProvider; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.user.index.UserIndex; | |||
import org.sonar.server.user.index.UserIndexDefinition; | |||
import org.sonar.server.user.index.UserIndexer; | |||
import org.sonar.server.ws.TestResponse; | |||
import org.sonar.server.ws.WsActionTester; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.elasticsearch.index.query.QueryBuilders.boolQuery; | |||
import static org.elasticsearch.index.query.QueryBuilders.termQuery; | |||
import static org.sonar.api.web.UserRole.CODEVIEWER; | |||
import static org.sonar.api.web.UserRole.USER; | |||
import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN; | |||
@@ -62,6 +64,8 @@ import static org.sonar.db.permission.OrganizationPermission.SCAN; | |||
import static org.sonar.db.property.PropertyTesting.newUserPropertyDto; | |||
import static org.sonar.db.user.UserTesting.newUserDto; | |||
import static org.sonar.db.user.UserTokenTesting.newUserToken; | |||
import static org.sonar.server.user.index.UserIndexDefinition.FIELD_ACTIVE; | |||
import static org.sonar.server.user.index.UserIndexDefinition.FIELD_UUID; | |||
import static org.sonar.test.JsonAssert.assertJson; | |||
public class DeactivateActionTest { | |||
@@ -81,7 +85,6 @@ public class DeactivateActionTest { | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); | |||
private UserIndex index = new UserIndex(es.client(), system2); | |||
private DbClient dbClient = db.getDbClient(); | |||
private UserIndexer userIndexer = new UserIndexer(dbClient, es.client()); | |||
private DbSession dbSession = db.getSession(); | |||
@@ -101,7 +104,11 @@ public class DeactivateActionTest { | |||
deactivate(user.getLogin()).getInput(); | |||
verifyThatUserIsDeactivated(user.getLogin()); | |||
assertThat(index.getNullableByLogin(user.getLogin()).active()).isFalse(); | |||
assertThat(es.client().prepareSearch(UserIndexDefinition.INDEX_TYPE_USER) | |||
.setQuery(boolQuery() | |||
.must(termQuery(FIELD_UUID, user.getUuid())) | |||
.must(termQuery(FIELD_ACTIVE, "false"))) | |||
.get().getHits().getHits()).hasSize(1); | |||
} | |||
@Test | |||
@@ -173,7 +180,8 @@ public class DeactivateActionTest { | |||
deactivate(user.getLogin()).getInput(); | |||
assertThat(db.getDbClient().permissionTemplateDao().selectUserPermissionsByTemplateId(dbSession, template.getId())).extracting(PermissionTemplateUserDto::getUserId).isEmpty(); | |||
assertThat(db.getDbClient().permissionTemplateDao().selectUserPermissionsByTemplateId(dbSession, anotherTemplate.getId())).extracting(PermissionTemplateUserDto::getUserId).isEmpty(); | |||
assertThat(db.getDbClient().permissionTemplateDao().selectUserPermissionsByTemplateId(dbSession, anotherTemplate.getId())).extracting(PermissionTemplateUserDto::getUserId) | |||
.isEmpty(); | |||
} | |||
@Test |
@@ -45,7 +45,6 @@ import static java.util.Collections.emptyList; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.db.user.GroupTesting.newGroupDto; | |||
import static org.sonar.db.user.UserTesting.newUserDto; | |||
import static org.sonar.db.user.UserTokenTesting.newUserToken; | |||
import static org.sonar.test.JsonAssert.assertJson; | |||
@@ -70,16 +69,16 @@ public class SearchActionTest { | |||
@Test | |||
public void test_json_example() throws Exception { | |||
UserDto fmallet = db.users().insertUser(newUserDto("fmallet", "Freddy Mallet", "f@m.com") | |||
UserDto fmallet = db.users().insertUser(u -> u.setLogin("fmallet").setName("Freddy Mallet").setEmail("f@m.com") | |||
.setActive(true) | |||
.setLocal(true) | |||
.setScmAccounts(emptyList()) | |||
.setExternalIdentity("fmallet") | |||
.setExternalLogin("fmallet") | |||
.setExternalIdentityProvider("sonarqube")); | |||
UserDto simon = db.users().insertUser(newUserDto("sbrandhof", "Simon", "s.brandhof@company.tld") | |||
UserDto simon = db.users().insertUser(u -> u.setLogin("sbrandhof").setName("Simon").setEmail("s.brandhof@company.tld") | |||
.setActive(true) | |||
.setLocal(false) | |||
.setExternalIdentity("sbrandhof@ldap.com") | |||
.setExternalLogin("sbrandhof@ldap.com") | |||
.setExternalIdentityProvider("LDAP") | |||
.setScmAccounts(newArrayList("simon.brandhof", "s.brandhof@company.tld"))); | |||
GroupDto sonarUsers = db.users().insertGroup(newGroupDto().setName("sonar-users")); | |||
@@ -263,7 +262,7 @@ public class SearchActionTest { | |||
public void only_return_login_and_name_when_not_logged() throws Exception { | |||
userSession.anonymous(); | |||
dbClient.userDao().insert(dbSession, newUserDto("john", "John", "john@email.com")); | |||
db.users().insertUser(u -> u.setLogin("john").setName("John").setEmail("john@email.com")); | |||
dbSession.commit(); | |||
userIndexer.indexOnStartup(null); | |||
@@ -288,14 +287,13 @@ public class SearchActionTest { | |||
String name = String.format("User %d", index); | |||
List<String> scmAccounts = singletonList(String.format("user-%d", index)); | |||
UserDto userDto = dbClient.userDao().insert(dbSession, newUserDto() | |||
.setActive(true) | |||
UserDto userDto = db.users().insertUser(u -> u.setActive(true) | |||
.setEmail(email) | |||
.setLogin(login) | |||
.setName(name) | |||
.setScmAccounts(scmAccounts) | |||
.setLocal(true) | |||
.setExternalIdentity(login) | |||
.setExternalLogin(login) | |||
.setExternalIdentityProvider("sonarqube")); | |||
userDtos.add(userDto); | |||
@@ -240,6 +240,19 @@ public class UpdateActionTest { | |||
@Test | |||
public void fail_on_unknown_user() { | |||
expectedException.expect(NotFoundException.class); | |||
expectedException.expectMessage("User 'john' doesn't exist"); | |||
ws.newRequest() | |||
.setParam("login", "john") | |||
.execute(); | |||
} | |||
@Test | |||
public void fail_on_disabled_user() { | |||
db.users().insertUser(u -> u.setLogin("john").setActive(false)); | |||
expectedException.expect(NotFoundException.class); | |||
expectedException.expectMessage("User 'john' doesn't exist"); | |||
ws.newRequest() | |||
.setParam("login", "john") | |||
@@ -267,7 +280,7 @@ public class UpdateActionTest { | |||
.setScmAccounts(newArrayList("jn")) | |||
.setActive(true) | |||
.setLocal(true) | |||
.setExternalIdentity("jo") | |||
.setExternalLogin("jo") | |||
.setExternalIdentityProvider("sonarqube"); | |||
dbClient.userDao().insert(dbSession, userDto); | |||
userIndexer.commitAndIndex(dbSession, userDto); |
@@ -38,6 +38,7 @@ import static org.apache.commons.lang.StringUtils.isNotBlank; | |||
@Immutable | |||
public final class UserIdentity { | |||
private final String id; | |||
private final String providerLogin; | |||
private final String login; | |||
private final String name; | |||
@@ -46,6 +47,7 @@ public final class UserIdentity { | |||
private final Set<String> groups; | |||
private UserIdentity(Builder builder) { | |||
this.id = builder.id; | |||
this.providerLogin = builder.providerLogin; | |||
this.login = builder.login; | |||
this.name = builder.name; | |||
@@ -54,6 +56,19 @@ public final class UserIdentity { | |||
this.groups = builder.groups; | |||
} | |||
/** | |||
* Optional unique ID for the related {@link IdentityProvider}. | |||
* If two {@link IdentityProvider} define two users with the same ID, then users are considered as identical. | |||
* | |||
* When the ID is not provided, the provider login {@link #getProviderLogin()} is used. | |||
* | |||
* @since 7.2 | |||
*/ | |||
@CheckForNull | |||
public String getProviderId() { | |||
return id; | |||
} | |||
/** | |||
* Non-blank user login for the related {@link IdentityProvider}. | |||
*/ | |||
@@ -109,6 +124,7 @@ public final class UserIdentity { | |||
} | |||
public static class Builder { | |||
private String id; | |||
private String providerLogin; | |||
private String login; | |||
private String name; | |||
@@ -119,6 +135,15 @@ public final class UserIdentity { | |||
private Builder() { | |||
} | |||
/** | |||
* @see UserIdentity#getProviderId() | |||
* @since 7.2 | |||
*/ | |||
public Builder setProviderId(@Nullable String id) { | |||
this.id = id; | |||
return this; | |||
} | |||
/** | |||
* @see UserIdentity#getProviderLogin() | |||
*/ | |||
@@ -175,6 +200,7 @@ public final class UserIdentity { | |||
} | |||
public UserIdentity build() { | |||
validateId(id); | |||
validateProviderLogin(providerLogin); | |||
validateLogin(login); | |||
validateName(name); | |||
@@ -182,6 +208,10 @@ public final class UserIdentity { | |||
return new UserIdentity(this); | |||
} | |||
private static void validateId(@Nullable String id) { | |||
checkArgument(id == null || id.length() <= 255, "ID is too big (255 characters max)"); | |||
} | |||
private static void validateProviderLogin(String providerLogin) { | |||
checkArgument(isNotBlank(providerLogin), "Provider login must not be blank"); | |||
checkArgument(providerLogin.length() <= 255, "Provider login size is incorrect (maximum 255 characters)"); |