CREATE TABLE "USER_TOKENS" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
- "LOGIN" VARCHAR(255) NOT NULL,
+ "USER_UUID" VARCHAR(255) NOT NULL,
"NAME" VARCHAR(100) NOT NULL,
"TOKEN_HASH" VARCHAR(255) NOT NULL,
"CREATED_AT" BIGINT NOT NULL
);
CREATE UNIQUE INDEX "USER_TOKENS_TOKEN_HASH" ON "USER_TOKENS" ("TOKEN_HASH");
-CREATE UNIQUE INDEX "USER_TOKENS_LOGIN_NAME" ON "USER_TOKENS" ("LOGIN", "NAME");
+CREATE UNIQUE INDEX "USER_TOKENS_USER_UUID_NAME" ON "USER_TOKENS" ("USER_UUID", "NAME");
CREATE TABLE "ES_QUEUE" (
package org.sonar.db.user;
public class UserTokenCount {
- private String login;
+ private String userUuid;
private Integer tokenCount;
- public String getLogin() {
- return login;
+ public String getUserUuid() {
+ return userUuid;
}
- public UserTokenCount setLogin(String login) {
- this.login = login;
+ public UserTokenCount setUserUuid(String userUuid) {
+ this.userUuid = userUuid;
return this;
}
*/
package org.sonar.db.user;
-import com.google.common.base.Optional;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import javax.annotation.CheckForNull;
import org.sonar.db.Dao;
import org.sonar.db.DbSession;
-import org.sonar.db.RowNotFoundException;
-import static java.lang.String.format;
+import static org.sonar.core.util.stream.MoreCollectors.toList;
import static org.sonar.db.DatabaseUtils.executeLargeInputs;
public class UserTokenDao implements Dao {
mapper(dbSession).insert(userTokenDto);
}
- public UserTokenDto selectOrFailByTokenHash(DbSession dbSession, String tokenHash) {
- UserTokenDto userToken = mapper(dbSession).selectByTokenHash(tokenHash);
- if (userToken == null) {
- throw new RowNotFoundException(format("User token with token hash '%s' not found", tokenHash));
- }
-
- return userToken;
- }
-
- public Optional<UserTokenDto> selectByTokenHash(DbSession dbSession, String tokenHash) {
- return Optional.fromNullable(mapper(dbSession).selectByTokenHash(tokenHash));
+ @CheckForNull
+ public UserTokenDto selectByTokenHash(DbSession dbSession, String tokenHash) {
+ return mapper(dbSession).selectByTokenHash(tokenHash);
}
- public Optional<UserTokenDto> selectByLoginAndName(DbSession dbSession, String login, String name) {
- return Optional.fromNullable(mapper(dbSession).selectByLoginAndName(login, name));
+ @CheckForNull
+ public UserTokenDto selectByUserAndName(DbSession dbSession, UserDto user, String name) {
+ return mapper(dbSession).selectByUserUuidAndName(user.getUuid(), name);
}
- public List<UserTokenDto> selectByLogin(DbSession dbSession, String login) {
- return mapper(dbSession).selectByLogin(login);
+ public List<UserTokenDto> selectByUser(DbSession dbSession, UserDto user) {
+ return mapper(dbSession).selectByUserUuid(user.getUuid());
}
- public Map<String, Integer> countTokensByLogins(DbSession dbSession, List<String> logins) {
- Map<String, Integer> result = new HashMap<>(logins.size());
+ public Map<String, Integer> countTokensByUsers(DbSession dbSession, Collection<UserDto> users) {
+ Map<String, Integer> result = new HashMap<>(users.size());
executeLargeInputs(
- logins,
+ users.stream().map(UserDto::getUuid).collect(toList()),
input -> {
- List<UserTokenCount> userTokenCounts = mapper(dbSession).countTokensByLogins(input);
+ List<UserTokenCount> userTokenCounts = mapper(dbSession).countTokensByUserUuids(input);
for (UserTokenCount userTokenCount : userTokenCounts) {
- result.put(userTokenCount.getLogin(), userTokenCount.tokenCount());
+ result.put(userTokenCount.getUserUuid(), userTokenCount.tokenCount());
}
return userTokenCounts;
});
return result;
}
- public void deleteByLogin(DbSession dbSession, String login) {
- mapper(dbSession).deleteByLogin(login);
+ public void deleteByUser(DbSession dbSession, UserDto user) {
+ mapper(dbSession).deleteByUserUuid(user.getUuid());
}
- public void deleteByLoginAndName(DbSession dbSession, String login, String name) {
- mapper(dbSession).deleteByLoginAndName(login, name);
+ public void deleteByUserAndName(DbSession dbSession, UserDto user, String name) {
+ mapper(dbSession).deleteByUserUuidAndName(user.getUuid(), name);
}
private static UserTokenMapper mapper(DbSession dbSession) {
import static org.sonar.db.user.UserTokenValidator.checkTokenHash;
public class UserTokenDto {
- private String login;
+ private String userUuid;
private String name;
private String tokenHash;
private Long createdAt;
- public String getLogin() {
- return login;
+ public String getUserUuid() {
+ return userUuid;
}
- public UserTokenDto setLogin(String login) {
- this.login = login;
+ public UserTokenDto setUserUuid(String userUuid) {
+ this.userUuid = userUuid;
return this;
}
UserTokenDto selectByTokenHash(String tokenHash);
- UserTokenDto selectByLoginAndName(@Param("login") String login, @Param("name") String name);
+ UserTokenDto selectByUserUuidAndName(@Param("userUuid") String userUuid, @Param("name") String name);
- List<UserTokenDto> selectByLogin(String login);
+ List<UserTokenDto> selectByUserUuid(String userUuid);
- void deleteByLogin(String login);
+ void deleteByUserUuid(String userUuid);
- void deleteByLoginAndName(@Param("login") String login, @Param("name") String name);
+ void deleteByUserUuidAndName(@Param("userUuid") String userUuid, @Param("name") String name);
- List<UserTokenCount> countTokensByLogins(@Param("logins") List<String> logins);
+ List<UserTokenCount> countTokensByUserUuids(@Param("userUuids") List<String> userUuids);
}
<mapper namespace="org.sonar.db.user.UserTokenMapper">
<sql id="userTokensColumns">
- t.login as "login",
+ t.user_uuid as "userUuid",
t.name as "name",
t.token_hash as "tokenHash",
t.created_at as "createdAt"
<insert id="insert" parameterType="UserToken" keyColumn="id" useGeneratedKeys="false" keyProperty="id">
insert into user_tokens (
- login,
+ user_uuid,
name,
token_hash,
created_at
) values (
- #{login,jdbcType=VARCHAR},
+ #{userUuid,jdbcType=VARCHAR},
#{name,jdbcType=VARCHAR},
#{tokenHash,jdbcType=VARCHAR},
#{createdAt,jdbcType=BIGINT}
WHERE t.token_hash=#{tokenHash}
</select>
- <select id="selectByLoginAndName" parameterType="map" resultType="UserToken">
+ <select id="selectByUserUuidAndName" parameterType="map" resultType="UserToken">
SELECT
<include refid="userTokensColumns"/>
FROM user_tokens t
- WHERE t.login=#{login} and t.name=#{name}
+ WHERE t.user_uuid=#{userUuid} and t.name=#{name}
</select>
- <select id="selectByLogin" parameterType="map" resultType="UserToken">
+ <select id="selectByUserUuid" parameterType="map" resultType="UserToken">
SELECT
<include refid="userTokensColumns"/>
FROM user_tokens t
- WHERE t.login=#{login}
+ WHERE t.user_uuid=#{userUuid}
</select>
- <select id="countTokensByLogins" parameterType="map" resultType="UserTokenCount">
- SELECT t.login as "login", count(t.name) as "tokenCount"
+ <select id="countTokensByUserUuids" parameterType="map" resultType="UserTokenCount">
+ SELECT t.user_uuid as "userUuid", count(t.name) as "tokenCount"
FROM user_tokens t
- WHERE t.login in
- <foreach collection="logins" open="(" close=")" item="login" separator=",">
- #{login}
+ WHERE t.user_uuid in
+ <foreach collection="userUuids" open="(" close=")" item="userUuid" separator=",">
+ #{userUuid}
</foreach>
- GROUP BY t.login
+ GROUP BY t.user_uuid
</select>
- <delete id="deleteByLogin">
- DELETE FROM user_tokens WHERE login=#{login}
+ <delete id="deleteByUserUuid">
+ DELETE FROM user_tokens WHERE user_uuid=#{userUuid}
</delete>
- <delete id="deleteByLoginAndName">
- DELETE FROM user_tokens WHERE login=#{login} and name=#{name}
+ <delete id="deleteByUserUuidAndName">
+ DELETE FROM user_tokens WHERE user_uuid=#{userUuid} and name=#{name}
</delete>
</mapper>
import static org.sonar.db.user.GroupTesting.newGroupDto;
import static org.sonar.db.user.UserTesting.newDisabledUser;
import static org.sonar.db.user.UserTesting.newUserDto;
+import static org.sonar.db.user.UserTokenTesting.newUserToken;
public class UserDbTester {
private final DbTester db;
checkArgument(!project.isPrivate(), "No permission to group AnyOne can be granted on a private project");
checkArgument(!ProjectPermissions.PUBLIC_PERMISSIONS.contains(permission),
"permission %s can't be granted on a public project", permission);
- checkArgument(project.getMainBranchProjectUuid()==null, "Permissions can't be granted on branches");
+ checkArgument(project.getMainBranchProjectUuid() == null, "Permissions can't be granted on branches");
GroupPermissionDto dto = new GroupPermissionDto()
.setOrganizationUuid(project.getOrganizationUuid())
.setGroupId(null)
checkArgument(group.getOrganizationUuid().equals(project.getOrganizationUuid()), "Different organizations");
checkArgument(project.isPrivate() || !ProjectPermissions.PUBLIC_PERMISSIONS.contains(permission),
"%s can't be granted on a public project", permission);
- checkArgument(project.getMainBranchProjectUuid()==null, "Permissions can't be granted on branches");
+ checkArgument(project.getMainBranchProjectUuid() == null, "Permissions can't be granted on branches");
GroupPermissionDto dto = new GroupPermissionDto()
.setOrganizationUuid(group.getOrganizationUuid())
.setGroupId(group.getId())
public UserPermissionDto insertProjectPermissionOnUser(UserDto user, String permission, ComponentDto project) {
checkArgument(project.isPrivate() || !ProjectPermissions.PUBLIC_PERMISSIONS.contains(permission),
"%s can't be granted on a public project", permission);
- checkArgument(project.getMainBranchProjectUuid()==null, "Permissions can't be granted on branches");
+ checkArgument(project.getMainBranchProjectUuid() == null, "Permissions can't be granted on branches");
UserPermissionDto dto = new UserPermissionDto(project.getOrganizationUuid(), permission, user.getId(), project.getId());
db.getDbClient().userPermissionDao().insert(db.getSession(), dto);
db.commit();
.map(OrganizationPermission::fromKey)
.collect(MoreCollectors.toList());
}
+
+ @SafeVarargs
+ public final UserTokenDto insertToken(UserDto user, Consumer<UserTokenDto>... populators) {
+ UserTokenDto dto = newUserToken().setUserUuid(user.getUuid());
+ stream(populators).forEach(p -> p.accept(dto));
+ db.getDbClient().userTokenDao().insert(db.getSession(), dto);
+ db.commit();
+ return dto;
+ }
+
}
*/
package org.sonar.db.user;
-import com.google.common.base.Optional;
import java.util.Map;
-import org.assertj.guava.api.Assertions;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
-import org.sonar.db.RowNotFoundException;
-import static com.google.common.collect.Lists.newArrayList;
+import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.db.user.UserTokenTesting.newUserToken;
-
public class UserTokenDaoTest {
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
@Rule
public ExpectedException expectedException = ExpectedException.none();
- DbSession dbSession;
-
- UserTokenDao underTest;
+ private DbSession dbSession = db.getSession();
- @Before
- public void setUp() {
- underTest = db.getDbClient().userTokenDao();
- dbSession = db.getSession();
- }
+ private UserTokenDao underTest = db.getDbClient().userTokenDao();
@Test
public void insert_token() {
UserTokenDto userToken = newUserToken();
- insertToken(userToken);
+ underTest.insert(db.getSession(), userToken);
- UserTokenDto userTokenFromDb = underTest.selectOrFailByTokenHash(dbSession, userToken.getTokenHash());
+ UserTokenDto userTokenFromDb = underTest.selectByTokenHash(db.getSession(), userToken.getTokenHash());
assertThat(userTokenFromDb).isNotNull();
assertThat(userTokenFromDb.getName()).isEqualTo(userToken.getName());
assertThat(userTokenFromDb.getCreatedAt()).isEqualTo(userToken.getCreatedAt());
assertThat(userTokenFromDb.getTokenHash()).isEqualTo(userToken.getTokenHash());
- assertThat(userTokenFromDb.getLogin()).isEqualTo(userToken.getLogin());
+ assertThat(userTokenFromDb.getUserUuid()).isEqualTo(userToken.getUserUuid());
}
@Test
public void select_by_token_hash() {
+ UserDto user = db.users().insertUser();
String tokenHash = "123456789";
- insertToken(newUserToken().setTokenHash(tokenHash));
+ db.users().insertToken(user, t -> t.setTokenHash(tokenHash));
- Optional<UserTokenDto> result = underTest.selectByTokenHash(dbSession, tokenHash);
+ UserTokenDto result = underTest.selectByTokenHash(db.getSession(), tokenHash);
- Assertions.assertThat(result).isPresent();
+ assertThat(result).isNotNull();
}
@Test
- public void fail_if_token_is_not_found() {
- expectedException.expect(RowNotFoundException.class);
- expectedException.expectMessage("User token with token hash 'unknown-token-hash' not found");
+ public void select_by_user_and_name() {
+ UserDto user = db.users().insertUser();
+ UserTokenDto userToken = db.users().insertToken(user, t -> t.setName("name").setTokenHash("token"));
- underTest.selectOrFailByTokenHash(dbSession, "unknown-token-hash");
- }
-
- @Test
- public void select_by_login_and_name() {
- UserTokenDto userToken = newUserToken().setLogin("login").setName("name").setTokenHash("token");
- insertToken(userToken);
-
- Optional<UserTokenDto> optionalResultByLoginAndName = underTest.selectByLoginAndName(dbSession, userToken.getLogin(), userToken.getName());
- UserTokenDto resultByLoginAndName = optionalResultByLoginAndName.get();
- Optional<UserTokenDto> unfoundResult1 = underTest.selectByLoginAndName(dbSession, "unknown-login", userToken.getName());
- Optional<UserTokenDto> unfoundResult2 = underTest.selectByLoginAndName(dbSession, userToken.getLogin(), "unknown-name");
-
- Assertions.assertThat(unfoundResult1).isAbsent();
- Assertions.assertThat(unfoundResult2).isAbsent();
- assertThat(resultByLoginAndName.getLogin()).isEqualTo(userToken.getLogin());
+ UserTokenDto resultByLoginAndName = underTest.selectByUserAndName(db.getSession(), user, userToken.getName());
+ assertThat(resultByLoginAndName.getUserUuid()).isEqualTo(user.getUuid());
assertThat(resultByLoginAndName.getName()).isEqualTo(userToken.getName());
assertThat(resultByLoginAndName.getCreatedAt()).isEqualTo(userToken.getCreatedAt());
assertThat(resultByLoginAndName.getTokenHash()).isEqualTo(userToken.getTokenHash());
+
+ assertThat(underTest.selectByUserAndName(db.getSession(), user, "unknown-name")).isNull();
}
@Test
- public void delete_tokens_by_login() {
- insertToken(newUserToken().setLogin("login-to-delete"));
- insertToken(newUserToken().setLogin("login-to-delete"));
- insertToken(newUserToken().setLogin("login-to-keep"));
-
- underTest.deleteByLogin(dbSession, "login-to-delete");
+ public void delete_tokens_by_user() {
+ UserDto user1 = db.users().insertUser();
+ UserDto user2 = db.users().insertUser();
+ db.users().insertToken(user1);
+ db.users().insertToken(user1);
+ db.users().insertToken(user2);
+
+ underTest.deleteByUser(dbSession, user1);
db.commit();
- assertThat(underTest.selectByLogin(dbSession, "login-to-delete")).isEmpty();
- assertThat(underTest.selectByLogin(dbSession, "login-to-keep")).hasSize(1);
+ assertThat(underTest.selectByUser(dbSession, user1)).isEmpty();
+ assertThat(underTest.selectByUser(dbSession, user2)).hasSize(1);
}
@Test
- public void delete_token_by_login_and_name() {
- insertToken(newUserToken().setLogin("login").setName("name"));
- insertToken(newUserToken().setLogin("login").setName("another-name"));
- insertToken(newUserToken().setLogin("another-login").setName("name"));
-
- underTest.deleteByLoginAndName(dbSession, "login", "name");
- db.commit();
-
- Assertions.assertThat(underTest.selectByLoginAndName(dbSession, "login", "name")).isAbsent();
- Assertions.assertThat(underTest.selectByLoginAndName(dbSession, "login", "another-name")).isPresent();
- Assertions.assertThat(underTest.selectByLoginAndName(dbSession, "another-login", "name")).isPresent();
+ public void delete_token_by_user_and_name() {
+ UserDto user1 = db.users().insertUser();
+ UserDto user2 = db.users().insertUser();
+ db.users().insertToken(user1, t -> t.setName("name"));
+ db.users().insertToken(user1, t -> t.setName("another-name"));
+ db.users().insertToken(user2, t -> t.setName("name"));
+
+ underTest.deleteByUserAndName(dbSession, user1, "name");
+
+ assertThat(underTest.selectByUserAndName(dbSession, user1, "name")).isNull();
+ assertThat(underTest.selectByUserAndName(dbSession, user1, "another-name")).isNotNull();
+ assertThat(underTest.selectByUserAndName(dbSession, user2, "name")).isNotNull();
}
@Test
- public void count_tokens_by_login() {
- insertToken(newUserToken().setLogin("login").setName("name"));
- insertToken(newUserToken().setLogin("login").setName("another-name"));
-
- Map<String, Integer> result = underTest.countTokensByLogins(dbSession, newArrayList("login"));
+ public void count_tokens_by_user() {
+ UserDto user = db.users().insertUser();
+ db.users().insertToken(user, t -> t.setName("name"));
+ db.users().insertToken(user, t -> t.setName("another-name"));
- assertThat(result.get("login")).isEqualTo(2);
- assertThat(result.get("unknown-login")).isNull();
- }
+ Map<String, Integer> result = underTest.countTokensByUsers(dbSession, singletonList(user));
- private void insertToken(UserTokenDto userToken) {
- underTest.insert(dbSession, userToken);
- dbSession.commit();
+ assertThat(result.get(user.getUuid())).isEqualTo(2);
+ assertThat(result.get("unknown-user_uuid")).isNull();
}
}
public class UserTokenTesting {
public static UserTokenDto newUserToken() {
return new UserTokenDto()
- .setLogin(randomAlphanumeric(255))
- .setName(randomAlphanumeric(100))
- .setTokenHash(randomAlphanumeric(40))
+ .setUserUuid("userUuid_" + randomAlphanumeric(40))
+ .setName("name_" + randomAlphanumeric(20))
+ .setTokenHash("hash_" + randomAlphanumeric(30))
.setCreatedAt(nextLong());
}
}
.add(2116, "Populate ORGANIZATION_UUID in table users", PopulateOrganizationUuidOnUsers.class)
.add(2117, "Drop USER_ID from table organizations", DropUserIdFromOrganizations.class)
.add(2118, "Rename USER_LOGIN TO USER_UUID on table QPROFILE_CHANGES", RenameUserLoginToUserUuidOnTableQProfileChanges.class)
+ .add(2119, "Rename LOGIN TO USER_UUID on table USER_TOKENS", RenameLoginToUserUuidOnTableUserTokens.class)
;
}
}
--- /dev/null
+/*
+ * 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.sql.DropIndexBuilder;
+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 RenameLoginToUserUuidOnTableUserTokens extends DdlChange {
+
+ private static final String USER_TOKENS_TABLE = "user_tokens";
+
+ public RenameLoginToUserUuidOnTableUserTokens(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ context.execute(new DropIndexBuilder(getDialect())
+ .setTable(USER_TOKENS_TABLE)
+ .setName("user_tokens_login_name")
+ .build());
+
+ VarcharColumnDef userUuidColumn = newVarcharColumnDefBuilder()
+ .setColumnName("user_uuid")
+ .setLimit(255)
+ .setIsNullable(false)
+ .build();
+ context.execute(new RenameColumnsBuilder(getDialect(), USER_TOKENS_TABLE)
+ .renameColumn("login",
+ userUuidColumn)
+ .build());
+
+ context.execute(new CreateIndexBuilder(getDialect())
+ .setTable(USER_TOKENS_TABLE)
+ .setName("user_tokens_user_uuid_name")
+ .setUnique(true)
+ .addColumn(userUuidColumn)
+ .addColumn(newVarcharColumnDefBuilder()
+ .setColumnName("name")
+ .setLimit(100)
+ .setIsNullable(false)
+ .build())
+ .build());
+ }
+}
@Test
public void verify_migration_count() {
- verifyMigrationCount(underTest, 19);
+ verifyMigrationCount(underTest, 20);
}
}
--- /dev/null
+/*
+ * 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 RenameLoginToUserUuidOnTableUserTokensTest {
+
+ @Rule
+ public final CoreDbTester db = CoreDbTester.createForSchema(RenameLoginToUserUuidOnTableUserTokensTest.class, "user_tokens.sql");
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private RenameLoginToUserUuidOnTableUserTokens underTest = new RenameLoginToUserUuidOnTableUserTokens(db.database());
+
+ @Test
+ public void rename_column() throws SQLException {
+ underTest.execute();
+
+ db.assertColumnDefinition("user_tokens", "user_uuid", VARCHAR, 255, false);
+ db.assertColumnDoesNotExist("user_tokens", "login");
+ db.assertUniqueIndex("user_tokens", "user_tokens_user_uuid_name", "user_uuid", "name");
+ db.assertIndexDoesNotExist("user_tokens", "user_tokens_login_name");
+ }
+
+ public void migration_is_not_reentrant() throws SQLException {
+ underTest.execute();
+
+ expectedException.expect(IllegalStateException.class);
+
+ underTest.execute();
+ }
+
+}
--- /dev/null
+CREATE TABLE "USER_TOKENS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "LOGIN" VARCHAR(255) NOT NULL,
+ "NAME" VARCHAR(100) NOT NULL,
+ "TOKEN_HASH" VARCHAR(255) NOT NULL,
+ "CREATED_AT" BIGINT NOT NULL
+);
+CREATE UNIQUE INDEX "USER_TOKENS_TOKEN_HASH" ON "USER_TOKENS" ("TOKEN_HASH");
+CREATE UNIQUE INDEX "USER_TOKENS_LOGIN_NAME" ON "USER_TOKENS" ("LOGIN", "NAME");
\ No newline at end of file
}
private UserDto authenticateFromUserToken(String token) {
- Optional<String> authenticatedLogin = userTokenAuthenticator.authenticate(token);
- if (!authenticatedLogin.isPresent()) {
+ Optional<String> authenticatedUserUuid = userTokenAuthenticator.authenticate(token);
+ if (!authenticatedUserUuid.isPresent()) {
throw AuthenticationException.newBuilder()
.setSource(Source.local(Method.BASIC_TOKEN))
.setMessage("Token doesn't exist")
.build();
}
try (DbSession dbSession = dbClient.openSession(false)) {
- UserDto userDto = dbClient.userDao().selectActiveUserByLogin(dbSession, authenticatedLogin.get());
- if (userDto == null) {
+ UserDto userDto = dbClient.userDao().selectByUuid(dbSession, authenticatedUserUuid.get());
+ if (userDto == null || !userDto.isActive()) {
throw AuthenticationException.newBuilder()
.setSource(Source.local(Method.BASIC_TOKEN))
.setMessage("User doesn't exist")
ensureNotLastAdministrator(dbSession, user);
Integer userId = user.getId();
- dbClient.userTokenDao().deleteByLogin(dbSession, login);
+ dbClient.userTokenDao().deleteByUser(dbSession, user);
dbClient.propertiesDao().deleteByKeyAndValue(dbSession, DEFAULT_ISSUE_ASSIGNEE, user.getLogin());
dbClient.propertiesDao().deleteByQuery(dbSession, PropertyQuery.builder().setUserId(userId).build());
dbClient.userGroupDao().deleteByUserId(dbSession, userId);
try (DbSession dbSession = dbClient.openSession(false)) {
List<String> logins = result.getDocs().stream().map(UserDoc::login).collect(toList());
Multimap<String, String> groupsByLogin = dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, logins);
- Map<String, Integer> tokenCountsByLogin = dbClient.userTokenDao().countTokensByLogins(dbSession, logins);
List<UserDto> users = dbClient.userDao().selectByOrderedLogins(dbSession, logins);
+ Map<String, Integer> tokenCountsByLogin = dbClient.userTokenDao().countTokensByUsers(dbSession, users);
Paging paging = forPageIndex(request.getPage()).withPageSize(request.getPageSize()).andTotal((int) result.getTotal());
return buildResponse(users, groupsByLogin, tokenCountsByLogin, fields, paging);
}
private SearchWsResponse buildResponse(List<UserDto> users, Multimap<String, String> groupsByLogin, Map<String, Integer> tokenCountsByLogin,
@Nullable List<String> fields, Paging paging) {
SearchWsResponse.Builder responseBuilder = newBuilder();
- users.forEach(user -> responseBuilder.addUsers(towsUser(user, firstNonNull(tokenCountsByLogin.get(user.getLogin()), 0), groupsByLogin.get(user.getLogin()), fields)));
+ users.forEach(user -> responseBuilder.addUsers(towsUser(user, firstNonNull(tokenCountsByLogin.get(user.getUuid()), 0), groupsByLogin.get(user.getLogin()), fields)));
responseBuilder.getPagingBuilder()
.setPageIndex(paging.pageIndex())
.setPageSize(paging.pageSize())
*/
package org.sonar.server.usertoken;
-import com.google.common.base.Optional;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.user.UserTokenDto;
+import static java.util.Optional.empty;
+import static java.util.Optional.of;
+
public class UserTokenAuthenticator {
private final TokenGenerator tokenGenerator;
private final DbClient dbClient;
}
/**
- * Returns the user login if the token hash is found, else {@code Optional.absent()}.
- * The returned login is not validated. If database is corrupted (table USER_TOKENS badly purged
- * for instance), then the login may not relate to a valid user.
+ * Returns the user uuid if the token hash is found, else {@code Optional.absent()}.
+ * The returned uuid is not validated. If database is corrupted (table USER_TOKENS badly purged
+ * for instance), then the uuid may not relate to a valid user.
*/
public java.util.Optional<String> authenticate(String token) {
String tokenHash = tokenGenerator.hash(token);
try (DbSession dbSession = dbClient.openSession(false)) {
- Optional<UserTokenDto> userToken = dbClient.userTokenDao().selectByTokenHash(dbSession, tokenHash);
- if (userToken.isPresent()) {
- return java.util.Optional.of(userToken.get().getLogin());
+ UserTokenDto userToken = dbClient.userTokenDao().selectByTokenHash(dbSession, tokenHash);
+ if (userToken == null) {
+ return empty();
}
- return java.util.Optional.empty();
+ return of(userToken.getUserUuid());
}
}
}
import org.sonar.server.usertoken.ws.GenerateAction;
import org.sonar.server.usertoken.ws.RevokeAction;
import org.sonar.server.usertoken.ws.SearchAction;
+import org.sonar.server.usertoken.ws.UserTokenSupport;
import org.sonar.server.usertoken.ws.UserTokensWs;
public class UserTokenModule extends Module {
protected void configureModule() {
add(
UserTokensWs.class,
+ UserTokenSupport.class,
GenerateAction.class,
RevokeAction.class,
SearchAction.class,
*/
package org.sonar.server.usertoken.ws;
-import com.google.common.base.Optional;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserTokenDto;
import org.sonar.server.exceptions.ServerException;
-import org.sonar.server.user.UserSession;
import org.sonar.server.usertoken.TokenGenerator;
import org.sonarqube.ws.UserTokens;
import org.sonarqube.ws.UserTokens.GenerateWsResponse;
import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR;
import static org.sonar.api.utils.DateUtils.formatDateTime;
-import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
-import static org.sonar.server.usertoken.ws.UserTokensWsParameters.ACTION_GENERATE;
-import static org.sonar.server.usertoken.ws.UserTokensWsParameters.PARAM_LOGIN;
-import static org.sonar.server.usertoken.ws.UserTokensWsParameters.PARAM_NAME;
+import static org.sonar.server.usertoken.ws.UserTokenSupport.ACTION_GENERATE;
+import static org.sonar.server.usertoken.ws.UserTokenSupport.PARAM_LOGIN;
+import static org.sonar.server.usertoken.ws.UserTokenSupport.PARAM_NAME;
import static org.sonar.server.ws.WsUtils.checkRequest;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
public class GenerateAction implements UserTokensWsAction {
+
private static final int MAX_TOKEN_NAME_LENGTH = 100;
+
private final DbClient dbClient;
- private final UserSession userSession;
private final System2 system;
private final TokenGenerator tokenGenerator;
+ private final UserTokenSupport userTokenSupport;
- public GenerateAction(DbClient dbClient, UserSession userSession, System2 system, TokenGenerator tokenGenerator) {
- this.userSession = userSession;
+ public GenerateAction(DbClient dbClient, System2 system, TokenGenerator tokenGenerator, UserTokenSupport userTokenSupport) {
this.dbClient = dbClient;
this.system = system;
this.tokenGenerator = tokenGenerator;
+ this.userTokenSupport = userTokenSupport;
}
@Override
@Override
public void handle(Request request, Response response) throws Exception {
- UserTokens.GenerateWsResponse generateWsResponse = doHandle(toCreateWsRequest(request));
+ UserTokens.GenerateWsResponse generateWsResponse = doHandle(request);
writeProtobuf(generateWsResponse, request, response);
}
- private UserTokens.GenerateWsResponse doHandle(GenerateRequest request) {
+ private UserTokens.GenerateWsResponse doHandle(Request request) {
try (DbSession dbSession = dbClient.openSession(false)) {
- checkWsRequest(dbSession, request);
- TokenPermissionsValidator.validate(userSession, request.getLogin());
+ String name = getName(request);
+ UserDto user = userTokenSupport.getUser(dbSession, request);
+ checkTokenDoesNotAlreadyExists(dbSession, user, name);
String token = tokenGenerator.generate();
String tokenHash = hashToken(dbSession, token);
-
- UserTokenDto userTokenDto = insertTokenInDb(dbSession, request, tokenHash);
-
- return buildResponse(userTokenDto, token);
+ UserTokenDto userTokenDto = insertTokenInDb(dbSession, user, name, tokenHash);
+ return buildResponse(userTokenDto, token, user);
}
}
private String hashToken(DbSession dbSession, String token) {
String tokenHash = tokenGenerator.hash(token);
- Optional<UserTokenDto> userToken = dbClient.userTokenDao().selectByTokenHash(dbSession, tokenHash);
- if (userToken.isPresent()) {
- throw new ServerException(HTTP_INTERNAL_ERROR, "Error while generating token. Please try again.");
+ UserTokenDto userToken = dbClient.userTokenDao().selectByTokenHash(dbSession, tokenHash);
+ if (userToken == null) {
+ return tokenHash;
}
-
- return tokenHash;
+ throw new ServerException(HTTP_INTERNAL_ERROR, "Error while generating token. Please try again.");
}
- private void checkWsRequest(DbSession dbSession, GenerateRequest request) {
- checkLoginExists(dbSession, request);
-
- Optional<UserTokenDto> userTokenDto = dbClient.userTokenDao().selectByLoginAndName(dbSession, request.getLogin(), request.getName());
- checkRequest(!userTokenDto.isPresent(), "A user token with login '%s' and name '%s' already exists", request.getLogin(), request.getName());
+ private void checkTokenDoesNotAlreadyExists(DbSession dbSession, UserDto user, String name) {
+ UserTokenDto userTokenDto = dbClient.userTokenDao().selectByUserAndName(dbSession, user, name);
+ checkRequest(userTokenDto == null, "A user token for login '%s' and name '%s' already exists", user.getLogin(), name);
}
- private void checkLoginExists(DbSession dbSession, GenerateRequest request) {
- UserDto user = dbClient.userDao().selectByLogin(dbSession, request.getLogin());
- if (user == null) {
- throw insufficientPrivilegesException();
- }
+ private static String getName(Request request) {
+ String name = request.mandatoryParam(PARAM_NAME).trim();
+ checkRequest(!name.isEmpty(), "The '%s' parameter must not be blank", PARAM_NAME);
+ return name;
}
- private UserTokenDto insertTokenInDb(DbSession dbSession, GenerateRequest request, String tokenHash) {
+ private UserTokenDto insertTokenInDb(DbSession dbSession, UserDto user, String name, String tokenHash) {
UserTokenDto userTokenDto = new UserTokenDto()
- .setLogin(request.getLogin())
- .setName(request.getName())
+ .setUserUuid(user.getUuid())
+ .setName(name)
.setTokenHash(tokenHash)
.setCreatedAt(system.now());
-
dbClient.userTokenDao().insert(dbSession, userTokenDto);
dbSession.commit();
return userTokenDto;
}
- private GenerateRequest toCreateWsRequest(Request request) {
- GenerateRequest generateWsRequest = new GenerateRequest()
- .setLogin(request.param(PARAM_LOGIN))
- .setName(request.mandatoryParam(PARAM_NAME).trim());
- if (generateWsRequest.getLogin() == null) {
- generateWsRequest.setLogin(userSession.getLogin());
- }
-
- checkRequest(!generateWsRequest.getName().isEmpty(), "The '%s' parameter must not be blank", PARAM_NAME);
-
- return generateWsRequest;
- }
-
- private static GenerateWsResponse buildResponse(UserTokenDto userTokenDto, String token) {
+ private static GenerateWsResponse buildResponse(UserTokenDto userTokenDto, String token, UserDto user) {
return UserTokens.GenerateWsResponse.newBuilder()
- .setLogin(userTokenDto.getLogin())
+ .setLogin(user.getLogin())
.setName(userTokenDto.getName())
.setCreatedAt(formatDateTime(userTokenDto.getCreatedAt()))
.setToken(token)
.build();
}
- private static class GenerateRequest {
-
- private String login;
- private String name;
-
- public GenerateRequest setLogin(String login) {
- this.login = login;
- return this;
- }
-
- public String getLogin() {
- return login;
- }
-
- public GenerateRequest setName(String name) {
- this.name = name;
- return this;
- }
-
- public String getName() {
- return name;
- }
- }
}
import org.sonar.api.server.ws.WebService;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
-import org.sonar.server.user.UserSession;
+import org.sonar.db.user.UserDto;
-import static org.sonar.server.usertoken.ws.UserTokensWsParameters.ACTION_REVOKE;
-import static org.sonar.server.usertoken.ws.UserTokensWsParameters.PARAM_LOGIN;
-import static org.sonar.server.usertoken.ws.UserTokensWsParameters.PARAM_NAME;
+import static org.sonar.server.usertoken.ws.UserTokenSupport.ACTION_REVOKE;
+import static org.sonar.server.usertoken.ws.UserTokenSupport.PARAM_LOGIN;
+import static org.sonar.server.usertoken.ws.UserTokenSupport.PARAM_NAME;
public class RevokeAction implements UserTokensWsAction {
+
private final DbClient dbClient;
- private final UserSession userSession;
+ private final UserTokenSupport userTokenSupport;
- public RevokeAction(DbClient dbClient, UserSession userSession) {
+ public RevokeAction(DbClient dbClient, UserTokenSupport userTokenSupport) {
this.dbClient = dbClient;
- this.userSession = userSession;
+ this.userTokenSupport = userTokenSupport;
}
@Override
public void define(WebService.NewController context) {
WebService.NewAction action = context.createAction(ACTION_REVOKE)
- .setDescription("Revoke a user access token. <br/>"+
+ .setDescription("Revoke a user access token. <br/>" +
"If the login is set, it requires administration permissions. Otherwise, a token is generated for the authenticated user.")
.setSince("5.3")
.setPost(true)
@Override
public void handle(Request request, Response response) throws Exception {
- String login = request.param(PARAM_LOGIN);
- if (login == null) {
- login = userSession.getLogin();
- }
String name = request.mandatoryParam(PARAM_NAME);
-
- TokenPermissionsValidator.validate(userSession, login);
-
try (DbSession dbSession = dbClient.openSession(false)) {
- dbClient.userTokenDao().deleteByLoginAndName(dbSession, login, name);
+ UserDto user = userTokenSupport.getUser(dbSession, request);
+ dbClient.userTokenDao().deleteByUserAndName(dbSession, user, name);
dbSession.commit();
}
response.noContent();
import org.sonar.api.server.ws.WebService;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
+import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserTokenDto;
-import org.sonar.server.user.UserSession;
import org.sonarqube.ws.UserTokens.SearchWsResponse;
import static org.sonar.api.utils.DateUtils.formatDateTime;
-import static org.sonar.server.usertoken.ws.UserTokensWsParameters.ACTION_SEARCH;
-import static org.sonar.server.usertoken.ws.UserTokensWsParameters.PARAM_LOGIN;
-import static org.sonar.server.ws.WsUtils.checkFound;
+import static org.sonar.server.usertoken.ws.UserTokenSupport.ACTION_SEARCH;
+import static org.sonar.server.usertoken.ws.UserTokenSupport.PARAM_LOGIN;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
public class SearchAction implements UserTokensWsAction {
+
private final DbClient dbClient;
- private final UserSession userSession;
+ private final UserTokenSupport userTokenSupport;
- public SearchAction(DbClient dbClient, UserSession userSession) {
+ public SearchAction(DbClient dbClient, UserTokenSupport userTokenSupport) {
this.dbClient = dbClient;
- this.userSession = userSession;
+ this.userTokenSupport = userTokenSupport;
}
@Override
@Override
public void handle(Request request, Response response) throws Exception {
- String login = request.param(PARAM_LOGIN);
- if (login == null) {
- login = userSession.getLogin();
- }
- SearchWsResponse searchWsResponse = doHandle(login);
+ SearchWsResponse searchWsResponse = doHandle(request);
writeProtobuf(searchWsResponse, request, response);
}
- private SearchWsResponse doHandle(String login) {
- TokenPermissionsValidator.validate(userSession, login);
-
+ private SearchWsResponse doHandle(Request request) {
try (DbSession dbSession = dbClient.openSession(false)) {
- checkLoginExists(dbSession, login);
- List<UserTokenDto> userTokens = dbClient.userTokenDao().selectByLogin(dbSession, login);
- return buildResponse(login, userTokens);
+ UserDto user = userTokenSupport.getUser(dbSession, request);
+ List<UserTokenDto> userTokens = dbClient.userTokenDao().selectByUser(dbSession, user);
+ return buildResponse(user, userTokens);
}
}
- private static SearchWsResponse buildResponse(String login, List<UserTokenDto> userTokensDto) {
+ private static SearchWsResponse buildResponse(UserDto user, List<UserTokenDto> userTokensDto) {
SearchWsResponse.Builder searchWsResponse = SearchWsResponse.newBuilder();
SearchWsResponse.UserToken.Builder userTokenBuilder = SearchWsResponse.UserToken.newBuilder();
- searchWsResponse.setLogin(login);
+ searchWsResponse.setLogin(user.getLogin());
for (UserTokenDto userTokenDto : userTokensDto) {
userTokenBuilder
.clear()
return searchWsResponse.build();
}
- private void checkLoginExists(DbSession dbSession, String login) {
- checkFound(dbClient.userDao().selectByLogin(dbSession, login), "User with login '%s' not found", login);
- }
}
+++ /dev/null
-/*
- * 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.usertoken.ws;
-
-import javax.annotation.Nullable;
-import org.sonar.server.user.UserSession;
-
-import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
-
-class TokenPermissionsValidator {
- private TokenPermissionsValidator() {
- // prevent instantiation
- }
-
- static void validate(UserSession userSession, @Nullable String requestLogin) {
- userSession.checkLoggedIn();
- if (!userSession.isSystemAdministrator() && !isLoggedInUser(userSession, requestLogin)) {
- throw insufficientPrivilegesException();
- }
- }
-
- private static boolean isLoggedInUser(UserSession userSession, @Nullable String requestLogin) {
- return requestLogin != null && requestLogin.equals(userSession.getLogin());
- }
-}
--- /dev/null
+/*
+ * 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.usertoken.ws;
+
+import javax.annotation.Nullable;
+import org.sonar.api.server.ws.Request;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.user.UserDto;
+import org.sonar.server.user.UserSession;
+
+import static java.util.Objects.requireNonNull;
+import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
+import static org.sonar.server.ws.WsUtils.checkFound;
+
+public class UserTokenSupport {
+
+ static final String CONTROLLER = "api/user_tokens";
+ static final String ACTION_SEARCH = "search";
+ static final String ACTION_REVOKE = "revoke";
+ static final String ACTION_GENERATE = "generate";
+ static final String PARAM_LOGIN = "login";
+ static final String PARAM_NAME = "name";
+
+ private final DbClient dbClient;
+ private final UserSession userSession;
+
+ public UserTokenSupport(DbClient dbClient, UserSession userSession) {
+ this.dbClient = dbClient;
+ this.userSession = userSession;
+ }
+
+ UserDto getUser(DbSession dbSession, Request request) {
+ String login = request.param(PARAM_LOGIN);
+ login = login == null ? userSession.getLogin() : login;
+ validate(userSession, login);
+ UserDto user = dbClient.userDao().selectByLogin(dbSession, requireNonNull(login, "Login should not be null"));
+ checkFound(user, "User with login '%s' doesn't exist", login);
+ return user;
+ }
+
+ private static void validate(UserSession userSession, @Nullable String requestLogin) {
+ userSession.checkLoggedIn();
+ if (userSession.isSystemAdministrator() || isLoggedInUser(userSession, requestLogin)) {
+ return;
+ }
+ throw insufficientPrivilegesException();
+ }
+
+ private static boolean isLoggedInUser(UserSession userSession, @Nullable String requestLogin) {
+ return requestLogin != null && requestLogin.equals(userSession.getLogin());
+ }
+}
import org.sonar.api.server.ws.WebService;
-import static org.sonar.server.usertoken.ws.UserTokensWsParameters.CONTROLLER;
+import static org.sonar.server.usertoken.ws.UserTokenSupport.CONTROLLER;
public class UserTokensWs implements WebService {
private final UserTokensWsAction[] actions;
package org.sonar.server.usertoken.ws;
public class UserTokensWsParameters {
- public static final String CONTROLLER = "api/user_tokens";
- public static final String ACTION_GENERATE = "generate";
- public static final String ACTION_REVOKE = "revoke";
- public static final String ACTION_SEARCH = "search";
-
- public static final String PARAM_LOGIN = "login";
- public static final String PARAM_NAME = "name";
private UserTokensWsParameters() {
// constants only
public ExpectedException expectedException = none();
@Rule
- public DbTester dbTester = DbTester.create(System2.INSTANCE);
+ public DbTester db = DbTester.create(System2.INSTANCE);
- private DbClient dbClient = dbTester.getDbClient();
+ private DbClient dbClient = db.getDbClient();
- private DbSession dbSession = dbTester.getSession();
+ private DbSession dbSession = db.getSession();
private CredentialsAuthenticator credentialsAuthenticator = mock(CredentialsAuthenticator.class);
private UserTokenAuthenticator userTokenAuthenticator = mock(UserTokenAuthenticator.class);
@Test
public void authenticate_from_user_token() {
- insertUser(UserTesting.newUserDto().setLogin(LOGIN));
- when(userTokenAuthenticator.authenticate("token")).thenReturn(Optional.of(LOGIN));
+ UserDto user = db.users().insertUser();
+ when(userTokenAuthenticator.authenticate("token")).thenReturn(Optional.of(user.getUuid()));
when(request.getHeader("Authorization")).thenReturn("Basic " + toBase64("token:"));
- Optional<UserDto> userDto = underTest.authenticate(request);
+ Optional<UserDto> userAuthenticated = underTest.authenticate(request);
- assertThat(userDto.isPresent()).isTrue();
- assertThat(userDto.get().getLogin()).isEqualTo(LOGIN);
- verify(authenticationEvent).loginSuccess(request, LOGIN, Source.local(BASIC_TOKEN));
+ assertThat(userAuthenticated.isPresent()).isTrue();
+ assertThat(userAuthenticated.get().getLogin()).isEqualTo(user.getLogin());
+ verify(authenticationEvent).loginSuccess(request, user.getLogin(), Source.local(BASIC_TOKEN));
}
@Test
public void does_not_authenticate_from_user_token_when_token_is_invalid() {
- insertUser(UserTesting.newUserDto().setLogin(LOGIN));
when(userTokenAuthenticator.authenticate("token")).thenReturn(Optional.empty());
when(request.getHeader("Authorization")).thenReturn("Basic " + toBase64("token:"));
}
@Test
- public void does_not_authenticate_from_user_token_when_token_does_not_match_active_user() {
- insertUser(UserTesting.newUserDto().setLogin(LOGIN));
+ public void does_not_authenticate_from_user_token_when_token_does_not_match_existing_user() {
when(userTokenAuthenticator.authenticate("token")).thenReturn(Optional.of("Unknown user"));
when(request.getHeader("Authorization")).thenReturn("Basic " + toBase64("token:"));
}
}
- private UserDto insertUser(UserDto userDto) {
- dbClient.userDao().insert(dbSession, userDto);
- dbSession.commit();
- return userDto;
+ @Test
+ public void does_not_authenticate_from_user_token_when_token_does_not_match_active_user() {
+ UserDto user = db.users().insertDisabledUser();
+ when(userTokenAuthenticator.authenticate("token")).thenReturn(Optional.of(user.getUuid()));
+ when(request.getHeader("Authorization")).thenReturn("Basic " + toBase64("token:"));
+
+ expectedException.expect(authenticationException().from(Source.local(Method.BASIC_TOKEN)).withoutLogin().andNoPublicMessage());
+ try {
+ underTest.authenticate(request);
+ } finally {
+ verifyZeroInteractions(authenticationEvent);
+ }
}
private static String toBase64(String text) {
package org.sonar.server.user.ws;
import java.util.Optional;
+import java.util.function.Consumer;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES;
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;
@Test
public void deactivate_user_and_delete_his_related_data() {
- UserDto user = insertUser(newUserDto()
+ UserDto user = insertUser(u -> u
.setLogin("ada.lovelace")
.setEmail("ada.lovelace@noteg.com")
.setName("Ada Lovelace")
@Test
public void deactivate_user_deletes_his_group_membership() {
logInAsSystemAdministrator();
- UserDto user = insertUser(newUserDto());
+ UserDto user = insertUser();
GroupDto group1 = db.users().insertGroup();
db.users().insertGroup();
db.users().insertMember(group1, user);
@Test
public void deactivate_user_deletes_his_tokens() {
logInAsSystemAdministrator();
- UserDto user = insertUser(newUserDto());
- db.getDbClient().userTokenDao().insert(dbSession, newUserToken().setLogin(user.getLogin()));
- db.getDbClient().userTokenDao().insert(dbSession, newUserToken().setLogin(user.getLogin()));
+ UserDto user = insertUser();
+ db.users().insertToken(user);
+ db.users().insertToken(user);
db.commit();
deactivate(user.getLogin()).getInput();
- assertThat(db.getDbClient().userTokenDao().selectByLogin(dbSession, user.getLogin())).isEmpty();
+ assertThat(db.getDbClient().userTokenDao().selectByUser(dbSession, user)).isEmpty();
}
@Test
public void deactivate_user_deletes_his_properties() {
logInAsSystemAdministrator();
- UserDto user = insertUser(newUserDto());
+ UserDto user = insertUser();
ComponentDto project = db.components().insertPrivateProject();
db.properties().insertProperty(newUserPropertyDto(user));
db.properties().insertProperty(newUserPropertyDto(user));
@Test
public void deactivate_user_deletes_his_permissions() {
logInAsSystemAdministrator();
- UserDto user = insertUser(newUserDto());
+ UserDto user = insertUser();
ComponentDto project = db.components().insertPrivateProject();
db.users().insertPermissionOnUser(user, SCAN);
db.users().insertPermissionOnUser(user, ADMINISTER_QUALITY_PROFILES);
@Test
public void deactivate_user_deletes_his_permission_templates() {
logInAsSystemAdministrator();
- UserDto user = insertUser(newUserDto());
+ UserDto user = insertUser();
PermissionTemplateDto template = db.permissionTemplates().insertTemplate();
PermissionTemplateDto anotherTemplate = db.permissionTemplates().insertTemplate();
db.permissionTemplates().addUserToTemplate(template.getId(), user.getId(), USER);
@Test
public void deactivate_user_deletes_his_qprofiles_permissions() {
logInAsSystemAdministrator();
- UserDto user = insertUser(newUserDto());
+ UserDto user = insertUser();
QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization());
db.qualityProfiles().addUserPermission(profile, user);
@Test
public void deactivate_user_deletes_his_default_assignee_settings() {
logInAsSystemAdministrator();
- UserDto user = insertUser(newUserDto());
+ UserDto user = insertUser();
ComponentDto project = db.components().insertPrivateProject();
ComponentDto anotherProject = db.components().insertPrivateProject();
db.properties().insertProperty(new PropertyDto().setKey("sonar.issues.defaultAssigneeLogin").setValue(user.getLogin()).setResourceId(project.getId()));
@Test
public void deactivate_user_deletes_his_organization_membership() {
logInAsSystemAdministrator();
- UserDto user = insertUser(newUserDto());
+ UserDto user = insertUser();
OrganizationDto organization = db.organizations().insert();
db.organizations().addMember(organization, user);
OrganizationDto anotherOrganization = db.organizations().insert();
public void fail_to_deactivate_last_administrator_of_organization() {
// user1 is the unique administrator of org1 and org2.
// user1 and user2 are both administrators of org3
- UserDto user1 = insertUser(newUserDto().setLogin("test"));
+ UserDto user1 = insertUser(u -> u.setLogin("test"));
OrganizationDto org1 = db.organizations().insert(newOrganizationDto().setKey("org1"));
OrganizationDto org2 = db.organizations().insert(newOrganizationDto().setKey("org2"));
OrganizationDto org3 = db.organizations().insert(newOrganizationDto().setKey("org3"));
@Test
public void test_example() {
- UserDto user = insertUser(newUserDto()
+ UserDto user = insertUser(u -> u
.setLogin("ada.lovelace")
.setEmail("ada.lovelace@noteg.com")
.setName("Ada Lovelace")
}
private UserDto createUser() {
- return insertUser(newUserDto());
+ return insertUser();
}
- private UserDto insertUser(UserDto user) {
- dbClient.userDao().insert(dbSession, user);
- dbClient.userTokenDao().insert(dbSession, newUserToken().setLogin(user.getLogin()));
- dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto().setUserId(user.getId()).setKey("foo").setValue("bar"));
+ @SafeVarargs
+ private final UserDto insertUser(Consumer<UserDto>... populators) {
+ UserDto user = db.users().insertUser(populators);
+ db.users().insertToken(user);
+ db.properties().insertProperties(new PropertyDto().setUserId(user.getId()).setKey("foo").setValue("bar"));
userIndexer.commitAndIndex(dbSession, user);
return user;
}
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
+import java.util.stream.IntStream;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserGroupDto;
-import org.sonar.db.user.UserTesting;
import org.sonar.server.es.EsTester;
import org.sonar.server.issue.ws.AvatarResolverImpl;
import org.sonar.server.tester.UserSessionRule;
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.UserTokenTesting.newUserToken;
import static org.sonar.test.JsonAssert.assertJson;
public class SearchActionTest {
dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setUserId(simon.getId()).setGroupId(sonarUsers.getId()));
dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setUserId(fmallet.getId()).setGroupId(sonarUsers.getId()));
dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setUserId(fmallet.getId()).setGroupId(sonarAdministrators.getId()));
-
+ db.commit();
for (int i = 0; i < 3; i++) {
- dbClient.userTokenDao().insert(dbSession, newUserToken().setLogin(simon.getLogin()));
+ db.users().insertToken(simon);
}
- dbClient.userTokenDao().insert(dbSession, newUserToken().setLogin(fmallet.getLogin()));
- db.commit();
+ db.users().insertToken(fmallet);
userIndexer.indexOnStartup(null);
loginAsSystemAdministrator();
.setExternalIdentityProvider("sonarqube"));
userDtos.add(userDto);
- for (int tokenIndex = 0; tokenIndex < index; tokenIndex++) {
- dbClient.userTokenDao().insert(dbSession, newUserToken()
- .setLogin(login)
- .setName(String.format("%s-%d", login, tokenIndex)));
- }
+ IntStream.range(0, index).forEach(i -> db.users().insertToken(userDto, t -> t.setName(String.format("%s-%d", login, i))));
db.users().insertMember(group1, userDto);
db.users().insertMember(group2, userDto);
}
- dbSession.commit();
userIndexer.indexOnStartup(null);
return userDtos;
}
*/
package org.sonar.server.usertoken;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.sonar.db.user.UserTokenTesting.newUserToken;
-
import java.util.Optional;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
+import org.sonar.db.user.UserDto;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class UserTokenAuthenticatorTest {
- static final String GRACE_HOPPER = "grace.hopper";
- static final String ADA_LOVELACE = "ada.lovelace";
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
- DbClient dbClient = db.getDbClient();
- DbSession dbSession = db.getSession();
- TokenGenerator tokenGenerator = mock(TokenGenerator.class);
- UserTokenAuthenticator underTest = new UserTokenAuthenticator(tokenGenerator, db.getDbClient());
+ private TokenGenerator tokenGenerator = mock(TokenGenerator.class);
+
+ private UserTokenAuthenticator underTest = new UserTokenAuthenticator(tokenGenerator, db.getDbClient());
@Test
public void return_login_when_token_hash_found_in_db() {
String token = "known-token";
String tokenHash = "123456789";
when(tokenGenerator.hash(token)).thenReturn(tokenHash);
- dbClient.userTokenDao().insert(dbSession, newUserToken().setLogin(GRACE_HOPPER).setTokenHash(tokenHash));
- dbClient.userTokenDao().insert(dbSession, newUserToken().setLogin(ADA_LOVELACE).setTokenHash("another-token-hash"));
- db.commit();
+ UserDto user1 = db.users().insertUser();
+ db.users().insertToken(user1, t -> t.setTokenHash(tokenHash));
+ UserDto user2 = db.users().insertUser();
+ db.users().insertToken(user2, t -> t.setTokenHash("another-token-hash"));
Optional<String> login = underTest.authenticate(token);
assertThat(login.isPresent()).isTrue();
- assertThat(login.get()).isEqualTo(GRACE_HOPPER);
+ assertThat(login.get()).isEqualTo(user1.getUuid());
}
@Test
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new UserTokenModule().configure(container);
- assertThat(container.size()).isEqualTo(8);
+ assertThat(container.size()).isEqualTo(9);
}
}
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
+import org.sonar.db.user.UserDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.ServerException;
import org.sonar.server.exceptions.UnauthorizedException;
import org.sonar.server.tester.UserSessionRule;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import static org.sonar.db.user.UserTesting.newUserDto;
-import static org.sonar.db.user.UserTokenTesting.newUserToken;
+import static org.sonar.server.usertoken.ws.UserTokenSupport.PARAM_LOGIN;
+import static org.sonar.server.usertoken.ws.UserTokenSupport.PARAM_NAME;
import static org.sonar.test.JsonAssert.assertJson;
-import static org.sonar.server.usertoken.ws.UserTokensWsParameters.PARAM_LOGIN;
-import static org.sonar.server.usertoken.ws.UserTokensWsParameters.PARAM_NAME;
public class GenerateActionTest {
- private static final String GRACE_HOPPER = "grace.hopper";
- private static final String ADA_LOVELACE = "ada.lovelace";
+
private static final String TOKEN_NAME = "Third Party Application";
@Rule
public ExpectedException expectedException = ExpectedException.none();
private TokenGenerator tokenGenerator = mock(TokenGenerator.class);
- private WsActionTester ws;
+
+ private WsActionTester ws = new WsActionTester(
+ new GenerateAction(db.getDbClient(), System2.INSTANCE, tokenGenerator, new UserTokenSupport(db.getDbClient(), userSession)));
@Before
public void setUp() {
when(tokenGenerator.generate()).thenReturn("123456789");
when(tokenGenerator.hash(anyString())).thenReturn("987654321");
- db.users().insertUser(newUserDto().setLogin(GRACE_HOPPER));
- db.users().insertUser(newUserDto().setLogin(ADA_LOVELACE));
-
- ws = new WsActionTester(
- new GenerateAction(db.getDbClient(), userSession, System2.INSTANCE, tokenGenerator));
}
@Test
public void json_example() {
+ UserDto user1 = db.users().insertUser(u -> u.setLogin("grace.hopper"));
+ UserDto user2 = db.users().insertUser(u -> u.setLogin("ada.lovelace"));
logInAsSystemAdministrator();
String response = ws.newRequest()
.setMediaType(MediaTypes.JSON)
- .setParam(PARAM_LOGIN, GRACE_HOPPER)
+ .setParam(PARAM_LOGIN, user1.getLogin())
.setParam(PARAM_NAME, TOKEN_NAME)
.execute().getInput();
@Test
public void a_user_can_generate_token_for_himself() {
- userSession.logIn(GRACE_HOPPER);
+ UserDto user = db.users().insertUser();
+ userSession.logIn(user);
GenerateWsResponse response = newRequest(null, TOKEN_NAME);
- assertThat(response.getLogin()).isEqualTo(GRACE_HOPPER);
+ assertThat(response.getLogin()).isEqualTo(user.getLogin());
assertThat(response.getCreatedAt()).isNotEmpty();
}
public void fail_if_login_does_not_exist() {
logInAsSystemAdministrator();
- expectedException.expect(ForbiddenException.class);
+ expectedException.expect(NotFoundException.class);
+ expectedException.expectMessage("User with login 'unknown-login' doesn't exist");
newRequest("unknown-login", "any-name");
}
@Test
public void fail_if_name_is_blank() {
+ UserDto user = db.users().insertUser();
logInAsSystemAdministrator();
expectedException.expect(BadRequestException.class);
expectedException.expectMessage("The 'name' parameter must not be blank");
- newRequest(GRACE_HOPPER, " ");
+ newRequest(user.getLogin(), " ");
}
@Test
public void fail_if_token_with_same_login_and_name_exists() {
+ UserDto user = db.users().insertUser();
logInAsSystemAdministrator();
+ db.users().insertToken(user, t -> t.setName(TOKEN_NAME));
- newRequest(GRACE_HOPPER, TOKEN_NAME);
expectedException.expect(BadRequestException.class);
- expectedException.expectMessage("A user token with login 'grace.hopper' and name 'Third Party Application' already exists");
+ expectedException.expectMessage(String.format("A user token for login '%s' and name 'Third Party Application' already exists", user.getLogin()));
- newRequest(GRACE_HOPPER, TOKEN_NAME);
+ newRequest(user.getLogin(), TOKEN_NAME);
}
@Test
public void fail_if_token_hash_already_exists_in_db() {
+ UserDto user = db.users().insertUser();
logInAsSystemAdministrator();
-
when(tokenGenerator.hash(anyString())).thenReturn("987654321");
- db.getDbClient().userTokenDao().insert(db.getSession(), newUserToken().setTokenHash("987654321"));
- db.commit();
+ db.users().insertToken(user, t -> t.setTokenHash("987654321"));
+
expectedException.expect(ServerException.class);
expectedException.expectMessage("Error while generating token. Please try again.");
- newRequest(GRACE_HOPPER, TOKEN_NAME);
+ newRequest(user.getLogin(), TOKEN_NAME);
}
@Test
public void throw_ForbiddenException_if_non_administrator_creates_token_for_someone_else() {
+ UserDto user = db.users().insertUser();
userSession.logIn().setNonSystemAdministrator();
expectedException.expect(ForbiddenException.class);
- newRequest(GRACE_HOPPER, TOKEN_NAME);
+ newRequest(user.getLogin(), TOKEN_NAME);
}
@Test
public void throw_UnauthorizedException_if_not_logged_in() {
+ UserDto user = db.users().insertUser();
userSession.anonymous();
expectedException.expect(UnauthorizedException.class);
- newRequest(GRACE_HOPPER, TOKEN_NAME);
+ newRequest(user.getLogin(), TOKEN_NAME);
}
private GenerateWsResponse newRequest(@Nullable String login, String name) {
package org.sonar.server.usertoken.ws;
import javax.annotation.Nullable;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
+import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserTokenDto;
import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.UnauthorizedException;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.db.user.UserTokenTesting.newUserToken;
-import static org.sonar.server.usertoken.ws.UserTokensWsParameters.PARAM_LOGIN;
-import static org.sonar.server.usertoken.ws.UserTokensWsParameters.PARAM_NAME;
-
+import static org.sonar.server.usertoken.ws.UserTokenSupport.PARAM_LOGIN;
+import static org.sonar.server.usertoken.ws.UserTokenSupport.PARAM_NAME;
public class RevokeActionTest {
- private static final String GRACE_HOPPER = "grace.hopper";
- private static final String ADA_LOVELACE = "ada.lovelace";
- private static final String TOKEN_NAME = "token-name";
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
public ExpectedException expectedException = ExpectedException.none();
private DbClient dbClient = db.getDbClient();
- private final DbSession dbSession = db.getSession();
- private WsActionTester ws;
-
- @Before
- public void setUp() {
- ws = new WsActionTester(
- new RevokeAction(dbClient, userSession));
- }
+ private DbSession dbSession = db.getSession();
+ private WsActionTester ws = new WsActionTester(new RevokeAction(dbClient, new UserTokenSupport(db.getDbClient(), userSession)));
@Test
public void delete_token_in_db() {
logInAsSystemAdministrator();
- insertUserToken(newUserToken().setLogin(GRACE_HOPPER).setName("token-to-delete"));
- insertUserToken(newUserToken().setLogin(GRACE_HOPPER).setName("token-to-keep-1"));
- insertUserToken(newUserToken().setLogin(GRACE_HOPPER).setName("token-to-keep-2"));
- insertUserToken(newUserToken().setLogin(ADA_LOVELACE).setName("token-to-delete"));
+ UserDto user1 = db.users().insertUser();
+ UserDto user2 = db.users().insertUser();
+ UserTokenDto tokenToDelete = db.users().insertToken(user1);
+ UserTokenDto tokenToKeep1 = db.users().insertToken(user1);
+ UserTokenDto tokenToKeep2 = db.users().insertToken(user1);
+ UserTokenDto tokenFromAnotherUser = db.users().insertToken(user2);
- String response = newRequest(GRACE_HOPPER, "token-to-delete");
+ String response = newRequest(user1.getLogin(), tokenToDelete.getName());
assertThat(response).isEmpty();
- assertThat(dbClient.userTokenDao().selectByLogin(dbSession, GRACE_HOPPER)).extracting("name").containsOnly("token-to-keep-1", "token-to-keep-2");
- assertThat(dbClient.userTokenDao().selectByLogin(dbSession, ADA_LOVELACE)).extracting("name").containsOnly("token-to-delete");
+ assertThat(dbClient.userTokenDao().selectByUser(dbSession, user1))
+ .extracting(UserTokenDto::getName)
+ .containsExactlyInAnyOrder(tokenToKeep1.getName(), tokenToKeep2.getName());
+ assertThat(dbClient.userTokenDao().selectByUser(dbSession, user2))
+ .extracting(UserTokenDto::getName)
+ .containsExactlyInAnyOrder(tokenFromAnotherUser.getName());
}
@Test
public void user_can_delete_its_own_tokens() {
- userSession.logIn(GRACE_HOPPER);
- insertUserToken(newUserToken().setLogin(GRACE_HOPPER).setName("token-to-delete"));
+ UserDto user = db.users().insertUser();
+ UserTokenDto token = db.users().insertToken(user);
+ userSession.logIn(user);
- String response = newRequest(null, "token-to-delete");
+ String response = newRequest(null, token.getName());
assertThat(response).isEmpty();
- assertThat(dbClient.userTokenDao().selectByLogin(dbSession, GRACE_HOPPER)).isEmpty();
+ assertThat(dbClient.userTokenDao().selectByUser(dbSession, user)).isEmpty();
}
@Test
public void does_not_fail_when_incorrect_login_or_name() {
+ UserDto user = db.users().insertUser();
+ db.users().insertToken(user);
+
logInAsSystemAdministrator();
- insertUserToken(newUserToken().setLogin(GRACE_HOPPER).setName(TOKEN_NAME));
- newRequest(ADA_LOVELACE, "another-token-name");
+ newRequest(user.getLogin(), "another-token-name");
}
@Test
public void throw_ForbiddenException_if_non_administrator_revokes_token_of_someone_else() {
+ UserDto user = db.users().insertUser();
+ UserTokenDto token = db.users().insertToken(user);
userSession.logIn();
- insertUserToken(newUserToken().setLogin(GRACE_HOPPER).setName(TOKEN_NAME));
expectedException.expect(ForbiddenException.class);
- newRequest(GRACE_HOPPER, TOKEN_NAME);
+ newRequest(user.getLogin(), token.getName());
}
@Test
public void throw_UnauthorizedException_if_not_logged_in() {
+ UserDto user = db.users().insertUser();
+ UserTokenDto token = db.users().insertToken(user);
userSession.anonymous();
- insertUserToken(newUserToken().setLogin(GRACE_HOPPER).setName(TOKEN_NAME));
expectedException.expect(UnauthorizedException.class);
- newRequest(GRACE_HOPPER, TOKEN_NAME);
+ newRequest(user.getLogin(), token.getName());
+ }
+
+ @Test
+ public void fail_if_login_does_not_exist() {
+ logInAsSystemAdministrator();
+
+ expectedException.expect(NotFoundException.class);
+ expectedException.expectMessage("User with login 'unknown-login' doesn't exist");
+
+ newRequest("unknown-login", "any-name");
}
private String newRequest(@Nullable String login, String name) {
return testRequest.execute().getInput();
}
- private void insertUserToken(UserTokenDto userToken) {
- dbClient.userTokenDao().insert(dbSession, userToken);
- dbSession.commit();
- }
-
private void logInAsSystemAdministrator() {
userSession.logIn().setSystemAdministrator();
}
package org.sonar.server.usertoken.ws;
import javax.annotation.Nullable;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
+import org.sonar.db.user.UserDto;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.UnauthorizedException;
import org.sonarqube.ws.UserTokens.SearchWsResponse;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.db.user.UserTesting.newUserDto;
-import static org.sonar.db.user.UserTokenTesting.newUserToken;
+import static org.sonar.server.usertoken.ws.UserTokenSupport.PARAM_LOGIN;
import static org.sonar.test.JsonAssert.assertJson;
-import static org.sonar.server.usertoken.ws.UserTokensWsParameters.PARAM_LOGIN;
public class SearchActionTest {
- private static final String GRACE_HOPPER = "grace.hopper";
- private static final String ADA_LOVELACE = "ada.lovelace";
@Rule
public ExpectedException expectedException = ExpectedException.none();
public UserSessionRule userSession = UserSessionRule.standalone();
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
- private DbClient dbClient = db.getDbClient();
- private DbSession dbSession = db.getSession();
- private WsActionTester ws = new WsActionTester(new SearchAction(dbClient, userSession));
- @Before
- public void setUp() {
- db.users().insertUser(newUserDto().setLogin(GRACE_HOPPER));
- db.users().insertUser(newUserDto().setLogin(ADA_LOVELACE));
- }
+ private DbClient dbClient = db.getDbClient();
+ private WsActionTester ws = new WsActionTester(new SearchAction(dbClient, new UserTokenSupport(db.getDbClient(), userSession)));
@Test
public void search_json_example() {
+ UserDto user1 = db.users().insertUser(u -> u.setLogin("grace.hopper"));
+ UserDto user2 = db.users().insertUser(u -> u.setLogin("ada.lovelace"));
+ db.users().insertToken(user1, t -> t.setName("Project scan on Travis").setCreatedAt(1448523067221L));
+ db.users().insertToken(user1, t -> t.setName("Project scan on AppVeyor").setCreatedAt(1438523067221L));
+ db.users().insertToken(user1, t -> t.setName("Project scan on Jenkins").setCreatedAt(1428523067221L));
+ db.users().insertToken(user2, t -> t.setName("Project scan on Travis").setCreatedAt(141456787123L));
logInAsSystemAdministrator();
- dbClient.userTokenDao().insert(dbSession, newUserToken()
- .setCreatedAt(1448523067221L)
- .setName("Project scan on Travis")
- .setLogin(GRACE_HOPPER));
- dbClient.userTokenDao().insert(dbSession, newUserToken()
- .setCreatedAt(1438523067221L)
- .setName("Project scan on AppVeyor")
- .setLogin(GRACE_HOPPER));
- dbClient.userTokenDao().insert(dbSession, newUserToken()
- .setCreatedAt(1428523067221L)
- .setName("Project scan on Jenkins")
- .setLogin(GRACE_HOPPER));
- dbClient.userTokenDao().insert(dbSession, newUserToken()
- .setCreatedAt(141456787123L)
- .setName("Project scan on Travis")
- .setLogin(ADA_LOVELACE));
- dbSession.commit();
-
String response = ws.newRequest()
- .setParam(PARAM_LOGIN, GRACE_HOPPER)
+ .setParam(PARAM_LOGIN, user1.getLogin())
.execute().getInput();
assertJson(response).isSimilarTo(getClass().getResource("search-example.json"));
@Test
public void a_user_can_search_its_own_token() {
- userSession.logIn(GRACE_HOPPER);
- dbClient.userTokenDao().insert(dbSession, newUserToken()
- .setCreatedAt(1448523067221L)
- .setName("Project scan on Travis")
- .setLogin(GRACE_HOPPER));
- db.commit();
+ UserDto user = db.users().insertUser();
+ db.users().insertToken(user, t -> t.setName("Project scan on Travis").setCreatedAt(1448523067221L));
+ userSession.logIn(user);
SearchWsResponse response = newRequest(null);
logInAsSystemAdministrator();
expectedException.expect(NotFoundException.class);
- expectedException.expectMessage("User with login 'unknown-login' not found");
+ expectedException.expectMessage("User with login 'unknown-login' doesn't exist");
newRequest("unknown-login");
}
@Test
public void throw_ForbiddenException_if_a_non_root_administrator_searches_for_tokens_of_someone_else() {
+ UserDto user = db.users().insertUser();
userSession.logIn();
expectedException.expect(ForbiddenException.class);
- newRequest(GRACE_HOPPER);
+ newRequest(user.getLogin());
}
@Test
public void throw_UnauthorizedException_if_not_logged_in() {
+ UserDto user = db.users().insertUser();
userSession.anonymous();
expectedException.expect(UnauthorizedException.class);
- newRequest(GRACE_HOPPER);
+ newRequest(user.getLogin());
}
private SearchWsResponse newRequest(@Nullable String login) {
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
import org.sonar.db.DbClient;
-import org.sonar.server.user.UserSession;
import org.sonar.server.usertoken.TokenGenerator;
import org.sonar.server.ws.WsTester;
@Before
public void setUp() {
- UserSession userSession = mock(UserSession.class);
DbClient dbClient = mock(DbClient.class);
System2 system = mock(System2.class);
TokenGenerator tokenGenerator = mock(TokenGenerator.class);
+ UserTokenSupport userTokenSupport = mock(UserTokenSupport.class);
ws = new WsTester(new UserTokensWs(
- new GenerateAction(dbClient, userSession, system, tokenGenerator),
- new RevokeAction(dbClient, userSession),
- new SearchAction(dbClient, userSession)));
+ new GenerateAction(dbClient, system, tokenGenerator, userTokenSupport),
+ new RevokeAction(dbClient, userTokenSupport),
+ new SearchAction(dbClient, userTokenSupport)));
}
@Test
import org.sonarqube.ws.Projects;
import org.sonarqube.ws.Qualityprofiles;
import org.sonarqube.ws.Settings;
+import org.sonarqube.ws.UserTokens;
import org.sonarqube.ws.Users;
import org.sonarqube.ws.client.GetRequest;
+import org.sonarqube.ws.client.WsClient;
import org.sonarqube.ws.client.issues.AssignRequest;
import org.sonarqube.ws.client.organizations.AddMemberRequest;
import org.sonarqube.ws.client.organizations.SearchRequest;
false);
}
+ @Test
+ public void user_tokens_after_login_update() {
+ String providerId = tester.users().generateProviderId();
+ String oldLogin = tester.users().generateLogin();
+
+ // First authentication to create the user, then create a ws-client using a token
+ authenticate(oldLogin, providerId);
+ String userToken = tester.wsClient().userTokens().generate(new GenerateRequest().setLogin(oldLogin).setName("auth-token")).getToken();
+ WsClient userWsClient = tester.as(userToken, null).wsClient();
+
+ // Generate some user tokens
+ userWsClient.userTokens().generate(new GenerateRequest().setName("token1"));
+ userWsClient.userTokens().generate(new GenerateRequest().setName("token2"));
+ assertThat(userWsClient.userTokens().search(new org.sonarqube.ws.client.usertokens.SearchRequest()).getUserTokensList())
+ .extracting(UserTokens.SearchWsResponse.UserToken::getName)
+ .contains("token1", "token2");
+
+ // Update login during authentication, check user tokens are still there
+ String newLogin = tester.users().generateLogin();
+ authenticate(newLogin, providerId);
+
+ assertThat(userWsClient.userTokens().search(new org.sonarqube.ws.client.usertokens.SearchRequest()).getUserTokensList())
+ .extracting(UserTokens.SearchWsResponse.UserToken::getName)
+ .contains("token1", "token2");
+ }
+
private void authenticate(String login, String providerId) {
tester.settings().setGlobalSettings("sonar.auth.fake-base-id-provider.user", login + "," + providerId + ",fake-" + login + ",John,john@email.com");
tester.wsClient().wsConnector().call(
NotificationsWsTest.class,
OAuth2IdentityProviderTest.class,
RootUserInStandaloneModeTest.class,
- UsersPageTest.class
+ UsersPageTest.class,
+ UserTokensTest.class
})
public class UserSuite {
--- /dev/null
+/*
+ * 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.sonarqube.tests.user;
+
+import com.sonar.orchestrator.Orchestrator;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonarqube.qa.util.Tester;
+import org.sonarqube.ws.UserTokens.SearchWsResponse.UserToken;
+import org.sonarqube.ws.Users.CreateWsResponse.User;
+import org.sonarqube.ws.client.WsClient;
+import org.sonarqube.ws.client.usertokens.GenerateRequest;
+import org.sonarqube.ws.client.usertokens.RevokeRequest;
+import org.sonarqube.ws.client.usertokens.SearchRequest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class UserTokensTest {
+
+ @ClassRule
+ public static final Orchestrator orchestrator = UserSuite.ORCHESTRATOR;
+
+ @Rule
+ public Tester tester = new Tester(orchestrator).disableOrganizations();
+
+ @Test
+ public void generate_and_search_for_user_tokens() {
+ User user = tester.users().generate();
+ // Generate tokens for the user
+ WsClient userWsClient = tester.as(user.getLogin()).wsClient();
+ userWsClient.userTokens().generate(new GenerateRequest().setName("token1"));
+ userWsClient.userTokens().generate(new GenerateRequest().setName("token2"));
+ // Generate token for another user
+ User anotherUser = tester.users().generate();
+ tester.as(anotherUser.getLogin()).wsClient().userTokens().generate(new GenerateRequest().setName("token"));
+
+ assertThat(userWsClient.userTokens().search(new SearchRequest()).getUserTokensList())
+ .extracting(UserToken::getName)
+ .containsExactlyInAnyOrder("token1", "token2");
+ }
+
+ @Test
+ public void revoke_user_token() {
+ User user = tester.users().generate();
+ WsClient userWsClient = tester.as(user.getLogin()).wsClient();
+ userWsClient.userTokens().generate(new GenerateRequest().setName("token1"));
+ userWsClient.userTokens().generate(new GenerateRequest().setName("token2"));
+ assertThat(userWsClient.userTokens().search(new SearchRequest()).getUserTokensList())
+ .extracting(UserToken::getName)
+ .containsExactlyInAnyOrder("token1", "token2");
+
+ userWsClient.userTokens().revoke(new RevokeRequest().setName("token2"));
+
+ assertThat(userWsClient.userTokens().search(new SearchRequest()).getUserTokensList())
+ .extracting(UserToken::getName)
+ .containsExactlyInAnyOrder("token1");
+ }
+
+ @Test
+ public void admin_can_generate_and_search_for_any_user_tokens() {
+ User user = tester.users().generate();
+ User admin = tester.users().generateAdministrator();
+ WsClient adminWsClient = tester.as(admin.getLogin()).wsClient();
+
+ adminWsClient.userTokens().generate(new GenerateRequest().setLogin(user.getLogin()).setName("token1"));
+ adminWsClient.userTokens().generate(new GenerateRequest().setLogin(user.getLogin()).setName("token2"));
+
+ assertThat(adminWsClient.userTokens().search(new SearchRequest().setLogin(user.getLogin())).getUserTokensList())
+ .extracting(UserToken::getName)
+ .containsExactlyInAnyOrder("token1", "token2");
+ }
+
+ @Test
+ public void admin_can_revoke_token_from_any_user() {
+ User user = tester.users().generate();
+ WsClient userWsClient = tester.as(user.getLogin()).wsClient();
+ User admin = tester.users().generateAdministrator();
+ WsClient adminWsClient = tester.as(admin.getLogin()).wsClient();
+
+ userWsClient.userTokens().generate(new GenerateRequest().setName("token1"));
+ userWsClient.userTokens().generate(new GenerateRequest().setName("token2"));
+ assertThat(userWsClient.userTokens().search(new SearchRequest()).getUserTokensList())
+ .extracting(UserToken::getName)
+ .containsExactlyInAnyOrder("token1", "token2");
+
+ adminWsClient.userTokens().revoke(new RevokeRequest().setLogin(user.getLogin()).setName("token2"));
+
+ assertThat(userWsClient.userTokens().search(new SearchRequest()).getUserTokensList())
+ .extracting(UserToken::getName)
+ .containsExactlyInAnyOrder("token1");
+ }
+}