package org.sonar.server.user.ws;
import java.time.Instant;
+import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Set;
import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.server.ws.WebService;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.ServerException;
import org.sonar.server.issue.AvatarResolverImpl;
import org.sonar.server.management.ManagedInstanceService;
import org.sonar.server.tester.UserSessionRule;
import static java.util.stream.Collectors.toMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
.extracting(User::getLogin)
.containsExactlyInAnyOrder(user.getLogin());
- assertUserWithFilter("lastConnectedAfter", lastConnection.minus(1, ChronoUnit.DAYS), user.getLogin(), true);
- assertUserWithFilter("lastConnectedAfter", lastConnection.plus(1, ChronoUnit.DAYS), user.getLogin(), false);
- assertUserWithFilter("lastConnectedBefore", lastConnection.minus(1, ChronoUnit.DAYS), user.getLogin(), false);
- assertUserWithFilter("lastConnectedBefore", lastConnection.plus(1, ChronoUnit.DAYS), user.getLogin(), true);
+ assertUserWithFilter(SearchAction.LAST_CONNECTION_DATE_FROM, lastConnection.minus(1, ChronoUnit.DAYS), user.getLogin(), true);
+ assertUserWithFilter(SearchAction.LAST_CONNECTION_DATE_FROM, lastConnection.plus(1, ChronoUnit.DAYS), user.getLogin(), false);
+ assertUserWithFilter(SearchAction.LAST_CONNECTION_DATE_TO, lastConnection.minus(1, ChronoUnit.DAYS), user.getLogin(), false);
+ assertUserWithFilter(SearchAction.LAST_CONNECTION_DATE_TO, lastConnection.plus(1, ChronoUnit.DAYS), user.getLogin(), true);
- assertUserWithFilter("slLastConnectedAfter", lastConnection.minus(1, ChronoUnit.DAYS), user.getLogin(), true);
- assertUserWithFilter("slLastConnectedAfter", lastConnection.plus(1, ChronoUnit.DAYS), user.getLogin(), false);
- assertUserWithFilter("slLastConnectedBefore", lastConnection.minus(1, ChronoUnit.DAYS), user.getLogin(), false);
- assertUserWithFilter("slLastConnectedBefore", lastConnection.plus(1, ChronoUnit.DAYS), user.getLogin(), true);
+ assertUserWithFilter(SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_FROM, lastConnection.minus(1, ChronoUnit.DAYS), user.getLogin(), true);
+ assertUserWithFilter(SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_FROM, lastConnection.plus(1, ChronoUnit.DAYS), user.getLogin(), false);
+ assertUserWithFilter(SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_TO, lastConnection.minus(1, ChronoUnit.DAYS), user.getLogin(), false);
+ assertUserWithFilter(SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_TO, lastConnection.plus(1, ChronoUnit.DAYS), user.getLogin(), true);
- assertUserWithFilter("slLastConnectedAfter", lastConnection, user.getLogin(), true);
- assertUserWithFilter("slLastConnectedBefore", lastConnection, user.getLogin(), true);
+ assertUserWithFilter(SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_FROM, lastConnection, user.getLogin(), true);
+ assertUserWithFilter(SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_TO, lastConnection, user.getLogin(), true);
+ }
+
+ @Test
+ public void search_whenNotAdmin_shouldThrowForbidden() {
+ userSession.logIn();
+
+ Stream.of(SearchAction.LAST_CONNECTION_DATE_FROM, SearchAction.LAST_CONNECTION_DATE_TO,
+ SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_FROM, SearchAction.SONAR_LINT_LAST_CONNECTION_DATE_TO)
+ .map(param -> ws.newRequest().setParam(param, formatDateTime(OffsetDateTime.now())))
+ .forEach(SearchActionIT::assertForbiddenException);
+ }
+
+ private static void assertForbiddenException(TestRequest testRequest) {
+ assertThatThrownBy(() -> testRequest.executeProtobuf(SearchWsResponse.class))
+ .asInstanceOf(InstanceOfAssertFactories.type(ServerException.class))
+ .extracting(ServerException::httpCode)
+ .isEqualTo(403);
}
private void assertUserWithFilter(String field, Instant filterValue, String userLogin, boolean isExpectedToBeThere) {
private static final int MAX_PAGE_SIZE = 500;
- private static final String LAST_CONNECTION_DATE_FROM = "lastConnectedAfter";
- private static final String LAST_CONNECTION_DATE_TO = "lastConnectedBefore";
- private static final String SONAR_LINT_LAST_CONNECTION_DATE_FROM = "slLastConnectedAfter";
- private static final String SONAR_LINT_LAST_CONNECTION_DATE_TO = "slLastConnectedBefore";
+ static final String LAST_CONNECTION_DATE_FROM = "lastConnectedAfter";
+ static final String LAST_CONNECTION_DATE_TO = "lastConnectedBefore";
+ static final String SONAR_LINT_LAST_CONNECTION_DATE_FROM = "slLastConnectedAfter";
+ static final String SONAR_LINT_LAST_CONNECTION_DATE_TO = "slLastConnectedBefore";
private final UserSession userSession;
private final DbClient dbClient;
private final AvatarResolver avatarResolver;
.setSince("3.6")
.setChangelog(
new Change("10.1", "New optional parameters " + SONAR_LINT_LAST_CONNECTION_DATE_FROM +
- " and " + SONAR_LINT_LAST_CONNECTION_DATE_TO + " to filter users by SonarLint last connection date"),
+ " and " + SONAR_LINT_LAST_CONNECTION_DATE_TO + " to filter users by SonarLint last connection date. Only available with Administer System permission."),
new Change("10.1", "New optional parameters " + LAST_CONNECTION_DATE_FROM +
- " and " + LAST_CONNECTION_DATE_TO + " to filter users by SonarQube last connection date"),
+ " and " + LAST_CONNECTION_DATE_TO + " to filter users by SonarQube last connection date. Only available with Administer System permission."),
new Change("10.1", "New field 'sonarLintLastConnectionDate' is added to response"),
new Change("10.0", "'q' parameter values is now always performing a case insensitive match"),
new Change("10.0", "New parameter 'managed' to optionally search by managed status"),
private UserQuery buildUserQuery(SearchRequest request) {
UserQuery.UserQueryBuilder builder = UserQuery.builder();
+ if(!userSession.isSystemAdministrator()) {
+ request.getLastConnectionDateFrom().ifPresent(v -> throwForbiddenFor(LAST_CONNECTION_DATE_FROM));
+ request.getLastConnectionDateTo().ifPresent(v -> throwForbiddenFor(LAST_CONNECTION_DATE_TO));
+ request.getSonarLintLastConnectionDateFrom().ifPresent(v -> throwForbiddenFor(SONAR_LINT_LAST_CONNECTION_DATE_FROM));
+ request.getSonarLintLastConnectionDateTo().ifPresent(v -> throwForbiddenFor(SONAR_LINT_LAST_CONNECTION_DATE_TO));
+ }
request.getLastConnectionDateFrom().ifPresent(builder::lastConnectionDateFrom);
request.getLastConnectionDateTo().ifPresent(builder::lastConnectionDateTo);
request.getSonarLintLastConnectionDateFrom().ifPresent(builder::sonarLintLastConnectionDateFrom);
.build();
}
+ private static void throwForbiddenFor(String parameterName) {
+ throw new ServerException(403, "parameter " + parameterName + " requires Administer System permission.");
+ }
+
private List<UserDto> findUsersAndSortByLogin(SearchRequest request, DbSession dbSession, UserQuery userQuery) {
return dbClient.userDao().selectUsers(dbSession, userQuery, request.getPage(), request.getPageSize())
.stream()