Browse Source

Support organizations in permission web services

tags/6.2-RC1
Simon Brandhof 7 years ago
parent
commit
b05d763913
50 changed files with 1829 additions and 2194 deletions
  1. 38
    0
      server/sonar-server/src/main/java/org/sonar/server/permission/GroupPermissionChange.java
  2. 100
    0
      server/sonar-server/src/main/java/org/sonar/server/permission/GroupPermissionChanger.java
  3. 40
    83
      server/sonar-server/src/main/java/org/sonar/server/permission/PermissionChange.java
  4. 0
    10
      server/sonar-server/src/main/java/org/sonar/server/permission/PermissionPrivilegeChecker.java
  5. 3
    12
      server/sonar-server/src/main/java/org/sonar/server/permission/PermissionService.java
  6. 26
    160
      server/sonar-server/src/main/java/org/sonar/server/permission/PermissionUpdater.java
  7. 53
    0
      server/sonar-server/src/main/java/org/sonar/server/permission/ProjectRef.java
  8. 49
    0
      server/sonar-server/src/main/java/org/sonar/server/permission/UserId.java
  9. 39
    0
      server/sonar-server/src/main/java/org/sonar/server/permission/UserPermissionChange.java
  10. 78
    0
      server/sonar-server/src/main/java/org/sonar/server/permission/UserPermissionChanger.java
  11. 19
    36
      server/sonar-server/src/main/java/org/sonar/server/permission/ws/AddGroupAction.java
  12. 24
    35
      server/sonar-server/src/main/java/org/sonar/server/permission/ws/AddUserAction.java
  13. 32
    54
      server/sonar-server/src/main/java/org/sonar/server/permission/ws/GroupsAction.java
  14. 0
    65
      server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionChangeBuilder.java
  15. 0
    103
      server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionDependenciesFinder.java
  16. 4
    16
      server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionRequestValidator.java
  17. 111
    0
      server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionWsSupport.java
  18. 14
    2
      server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionsWsModule.java
  19. 9
    0
      server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionsWsParametersBuilder.java
  20. 18
    38
      server/sonar-server/src/main/java/org/sonar/server/permission/ws/RemoveGroupAction.java
  21. 24
    34
      server/sonar-server/src/main/java/org/sonar/server/permission/ws/RemoveUserAction.java
  22. 1
    4
      server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchGlobalPermissionsAction.java
  23. 3
    9
      server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchProjectPermissionsAction.java
  24. 2
    3
      server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchProjectPermissionsData.java
  25. 5
    8
      server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchProjectPermissionsDataLoader.java
  26. 49
    64
      server/sonar-server/src/main/java/org/sonar/server/permission/ws/UsersAction.java
  27. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/permission/ws/WsProjectRef.java
  28. 0
    6
      server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
  29. 46
    32
      server/sonar-server/src/main/java/org/sonar/server/startup/RegisterPermissionTemplates.java
  30. 1
    4
      server/sonar-server/src/main/resources/org/sonar/server/permission/ws/template/create_template-example.json
  31. 0
    0
      server/sonar-server/src/main/resources/org/sonar/server/permission/ws/template/template_groups-example.json
  32. 0
    0
      server/sonar-server/src/main/resources/org/sonar/server/permission/ws/template/template_users-example.json
  33. 218
    0
      server/sonar-server/src/test/java/org/sonar/server/permission/GroupPermissionChangerTest.java
  34. 0
    137
      server/sonar-server/src/test/java/org/sonar/server/permission/PermissionChangeTest.java
  35. 88
    121
      server/sonar-server/src/test/java/org/sonar/server/permission/ws/AddGroupActionTest.java
  36. 70
    94
      server/sonar-server/src/test/java/org/sonar/server/permission/ws/AddUserActionTest.java
  37. 88
    0
      server/sonar-server/src/test/java/org/sonar/server/permission/ws/BasePermissionWsTest.java
  38. 137
    159
      server/sonar-server/src/test/java/org/sonar/server/permission/ws/GroupsActionTest.java
  39. 1
    1
      server/sonar-server/src/test/java/org/sonar/server/permission/ws/PermissionsWsModuleTest.java
  40. 5
    4
      server/sonar-server/src/test/java/org/sonar/server/permission/ws/PermissionsWsTest.java
  41. 99
    106
      server/sonar-server/src/test/java/org/sonar/server/permission/ws/RemoveGroupActionTest.java
  42. 106
    93
      server/sonar-server/src/test/java/org/sonar/server/permission/ws/RemoveUserActionTest.java
  43. 23
    54
      server/sonar-server/src/test/java/org/sonar/server/permission/ws/SearchGlobalPermissionsActionTest.java
  44. 83
    150
      server/sonar-server/src/test/java/org/sonar/server/permission/ws/SearchProjectPermissionsActionTest.java
  45. 6
    7
      server/sonar-server/src/test/java/org/sonar/server/permission/ws/SearchProjectPermissionsDataTest.java
  46. 0
    358
      server/sonar-server/src/test/java/org/sonar/server/permission/ws/TemplateUsersActionTest.java
  47. 97
    130
      server/sonar-server/src/test/java/org/sonar/server/permission/ws/UsersActionTest.java
  48. 7
    1
      server/sonar-server/src/test/java/org/sonar/server/ws/WsTester.java
  49. 11
    0
      sonar-ws/src/main/java/org/sonarqube/ws/client/permission/AddGroupWsRequest.java
  50. 1
    0
      sonar-ws/src/main/java/org/sonarqube/ws/client/permission/PermissionsWsParameters.java

+ 38
- 0
server/sonar-server/src/main/java/org/sonar/server/permission/GroupPermissionChange.java View File

@@ -0,0 +1,38 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.permission;

import javax.annotation.Nullable;
import org.sonar.server.usergroups.ws.GroupIdOrAnyone;

public class GroupPermissionChange extends PermissionChange {

private final GroupIdOrAnyone groupId;

public GroupPermissionChange(Operation operation, String permission, @Nullable ProjectRef projectRef,
GroupIdOrAnyone groupId) {
super(operation, groupId.getOrganizationUuid(), permission, projectRef);
this.groupId = groupId;
}

public GroupIdOrAnyone getGroupIdOrAnyone() {
return groupId;
}
}

+ 100
- 0
server/sonar-server/src/main/java/org/sonar/server/permission/GroupPermissionChanger.java View File

@@ -0,0 +1,100 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.permission;

import java.util.List;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.permission.GroupPermissionDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.user.UserSession;

import static org.sonar.server.permission.ws.PermissionRequestValidator.validateNotAnyoneAndAdminPermission;

public class GroupPermissionChanger {

private final DbClient dbClient;
private final UserSession userSession;

public GroupPermissionChanger(DbClient dbClient, UserSession userSession) {
this.dbClient = dbClient;
this.userSession = userSession;
}

public boolean apply(DbSession dbSession, GroupPermissionChange change) {
PermissionPrivilegeChecker.checkProjectAdminUserByComponentUuid(userSession, change.getProjectUuid());

if (shouldSkip(dbSession, change)) {
return false;
}

switch (change.getOperation()) {
case ADD:
validateNotAnyoneAndAdminPermission(change.getPermission(), change.getGroupIdOrAnyone());
GroupPermissionDto addedDto = new GroupPermissionDto()
.setRole(change.getPermission())
// TODO support organizations
.setGroupId(change.getGroupIdOrAnyone().getId())
.setResourceId(change.getNullableProjectId());
dbClient.groupPermissionDao().insert(dbSession, addedDto);
break;
case REMOVE:
checkAdminUsersExistOutsideTheRemovedGroup(dbSession, change);
GroupPermissionDto deletedDto = new GroupPermissionDto()
.setRole(change.getPermission())
// TODO support organizations
.setGroupId(change.getGroupIdOrAnyone().getId())
.setResourceId(change.getNullableProjectId());
dbClient.roleDao().deleteGroupRole(deletedDto, dbSession);
break;
default:
throw new UnsupportedOperationException("Unsupported permission change: " + change.getOperation());
}
return true;
}

private boolean shouldSkip(DbSession dbSession, GroupPermissionChange change) {
List<String> existingPermissions;
if (change.getGroupIdOrAnyone().isAnyone()) {
existingPermissions = dbClient.groupPermissionDao().selectAnyonePermissions(dbSession, change.getNullableProjectId());
} else {
existingPermissions = dbClient.groupPermissionDao().selectGroupPermissions(dbSession, change.getGroupIdOrAnyone().getId(), change.getNullableProjectId());
}
switch (change.getOperation()) {
case ADD:
return existingPermissions.contains(change.getPermission());
case REMOVE:
return !existingPermissions.contains(change.getPermission());
default:
throw new UnsupportedOperationException("Unsupported operation: " + change.getOperation());
}
}

private void checkAdminUsersExistOutsideTheRemovedGroup(DbSession dbSession, GroupPermissionChange change) {
if (GlobalPermissions.SYSTEM_ADMIN.equals(change.getPermission()) &&
!change.getProjectRef().isPresent() &&
// TODO support organizations
dbClient.roleDao().countUserPermissions(dbSession, change.getPermission(), change.getGroupIdOrAnyone().getId()) <= 0) {
throw new BadRequestException(String.format("Last group with '%s' permission. Permission cannot be removed.", GlobalPermissions.SYSTEM_ADMIN));
}
}

}

+ 40
- 83
server/sonar-server/src/main/java/org/sonar/server/permission/PermissionChange.java View File

@@ -19,110 +19,67 @@
*/
package org.sonar.server.permission;

import com.google.common.base.Strings;
import java.util.Map;
import java.util.Optional;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.sonar.core.permission.ProjectPermissions;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.server.exceptions.BadRequestException;

public class PermissionChange {

static final String USER_KEY = "user";
static final String GROUP_KEY = "group";
static final String PERMISSION_KEY = "permission";
static final String COMPONENT_KEY = "component";

private String userLogin;
private String groupName;
private String componentKey;
private String permission;
import org.sonar.core.permission.ProjectPermissions;

public PermissionChange setUserLogin(@Nullable String login) {
this.userLogin = login;
return this;
}
import static java.util.Objects.requireNonNull;
import static org.sonar.server.ws.WsUtils.checkRequest;

public PermissionChange setGroupName(@Nullable String name) {
this.groupName = name;
return this;
}
public abstract class PermissionChange {

public PermissionChange setComponentKey(@Nullable String componentKey) {
this.componentKey = componentKey;
return this;
public enum Operation {
ADD, REMOVE
}

public PermissionChange setPermission(String permission) {
this.permission = permission;
return this;
private final Operation operation;
private final String organizationUuid;
private final String permission;
private final ProjectRef projectRef;

public PermissionChange(Operation operation, String organizationUuid, String permission, @Nullable ProjectRef projectRef) {
this.operation = requireNonNull(operation);
this.organizationUuid = requireNonNull(organizationUuid);
this.permission = requireNonNull(permission);
this.projectRef = projectRef;
if (projectRef == null) {
checkRequest(GlobalPermissions.ALL.contains(permission), "Invalid global permission '%s'. Valid values are %s", permission, GlobalPermissions.ALL);
} else {
checkRequest(ProjectPermissions.ALL.contains(permission), "Invalid project permission '%s'. Valid values are %s", permission, ProjectPermissions.ALL);
}
}

public static PermissionChange buildFromParams(Map<String, Object> params) {
return new PermissionChange()
.setUserLogin((String) params.get(USER_KEY))
.setGroupName((String) params.get(GROUP_KEY))
.setComponentKey((String) params.get(COMPONENT_KEY))
.setPermission((String) params.get(PERMISSION_KEY));
public Operation getOperation() {
return operation;
}

void validate() {
validatePermission();
validateUserGroup();
public String getOrganizationUuid() {
return organizationUuid;
}

private void validateUserGroup() {
if (StringUtils.isBlank(userLogin) && StringUtils.isBlank(groupName)) {
throw new BadRequestException("Missing user or group parameter");
}
if (StringUtils.isNotBlank(userLogin) && StringUtils.isNotBlank(groupName)) {
throw new BadRequestException("Only one of user or group parameter should be provided");
}
}

private void validatePermission() {
if (StringUtils.isBlank(permission)) {
throw new BadRequestException("Missing permission parameter");
}
if (Strings.isNullOrEmpty(componentKey)) {
if (!GlobalPermissions.ALL.contains(permission)) {
throw new BadRequestException(String.format("Invalid global permission key %s. Valid values are %s", permission, GlobalPermissions.ALL));
}
} else {
if (!ProjectPermissions.ALL.contains(permission)) {
throw new BadRequestException(String.format("Invalid component permission key %s. Valid values are %s", permission, ProjectPermissions.ALL));
}
}
public String getPermission() {
return permission;
}

@CheckForNull
public String userLogin() {
return userLogin;
public Optional<ProjectRef> getProjectRef() {
return Optional.ofNullable(projectRef);
}

/**
* Shortcut based on {@link #getProjectRef()}
*/
@CheckForNull
public String groupName() {
return groupName;
public String getProjectUuid() {
return projectRef == null ? null : projectRef.getUuid();
}

/**
* Shortcut based on {@link #getProjectRef()}
*/
@CheckForNull
public String componentKey() {
return componentKey;
}

public String permission() {
return permission;
}

@Override
public String toString() {
return "PermissionChange{" +
"user='" + userLogin + '\'' +
", group='" + groupName + '\'' +
", componentKey='" + componentKey + '\'' +
", permission='" + permission + '\'' +
'}';
public Long getNullableProjectId() {
return projectRef == null ? null : projectRef.getId();
}
}

+ 0
- 10
server/sonar-server/src/main/java/org/sonar/server/permission/PermissionPrivilegeChecker.java View File

@@ -19,11 +19,9 @@
*/
package org.sonar.server.permission;

import com.google.common.base.Optional;
import javax.annotation.Nullable;
import org.sonar.api.web.UserRole;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.component.ComponentDto;
import org.sonar.server.user.UserSession;

public class PermissionPrivilegeChecker {
@@ -50,12 +48,4 @@ public class PermissionPrivilegeChecker {
userSession.checkPermission(GlobalPermissions.SYSTEM_ADMIN);
}
}

public static void checkProjectAdminUserByComponentDto(UserSession userSession, Optional<ComponentDto> project) {
if (project.isPresent()) {
checkProjectAdminUserByComponentUuid(userSession, project.get().uuid());
} else {
checkGlobalAdminUser(userSession);
}
}
}

+ 3
- 12
server/sonar-server/src/main/java/org/sonar/server/permission/PermissionService.java View File

@@ -55,6 +55,9 @@ public class PermissionService {
this.componentFinder = componentFinder;
}

/**
* Used by Ruby on Rails
*/
public List<String> globalPermissions() {
return GlobalPermissions.ALL;
}
@@ -95,18 +98,6 @@ public class PermissionService {
return permissionRepository.wouldUserHavePermissionWithDefaultTemplate(dbSession, userId, permission, effectiveKey, qualifier);
}

/**
* Important - this method checks caller permissions
*/
public void applyPermissionTemplate(ApplyPermissionTemplateQuery query) {
DbSession dbSession = dbClient.openSession(false);
try {
applyPermissionTemplate(dbSession, query);
} finally {
dbClient.closeSession(dbSession);
}
}

public void applyPermissionTemplate(DbSession dbSession, ApplyPermissionTemplateQuery query) {
if (query.getComponentKeys().size() == 1) {
checkProjectAdminUserByComponentKey(userSession, query.getComponentKeys().get(0));

+ 26
- 160
server/sonar-server/src/main/java/org/sonar/server/permission/PermissionUpdater.java View File

@@ -20,189 +20,55 @@
package org.sonar.server.permission;

import java.util.Collection;
import java.util.List;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.permission.PermissionRepository;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.issue.index.IssueAuthorizationIndexer;
import org.sonar.server.user.UserSession;

import static org.sonar.api.security.DefaultGroups.isAnyone;
import static org.sonar.server.permission.PermissionPrivilegeChecker.checkProjectAdminUserByComponentKey;
import static org.sonar.server.permission.ws.PermissionRequestValidator.validateNotAnyoneAndAdminPermission;

public class PermissionUpdater {

private enum Operation {
ADD, REMOVE
}

private static final String OBJECT_TYPE_USER = "User";
private static final String OBJECT_TYPE_GROUP = "Group";
private static final String NOT_FOUND_FORMAT = "%s %s does not exist";

private final DbClient dbClient;
private final PermissionRepository permissionRepository;
private final IssueAuthorizationIndexer issueAuthorizationIndexer;
private final UserSession userSession;
private final ComponentFinder componentFinder;
private final UserPermissionChanger userPermissionChanger;
private final GroupPermissionChanger groupPermissionChanger;

public PermissionUpdater(DbClient dbClient, PermissionRepository permissionRepository,
IssueAuthorizationIndexer issueAuthorizationIndexer, UserSession userSession, ComponentFinder componentFinder) {
public PermissionUpdater(DbClient dbClient, IssueAuthorizationIndexer issueAuthorizationIndexer,
UserPermissionChanger userPermissionChanger, GroupPermissionChanger groupPermissionChanger) {
this.dbClient = dbClient;
this.permissionRepository = permissionRepository;
this.issueAuthorizationIndexer = issueAuthorizationIndexer;
this.userSession = userSession;
this.componentFinder = componentFinder;
}

public static List<String> globalPermissions() {
return GlobalPermissions.ALL;
}

public void addPermission(PermissionChange change) {
DbSession session = dbClient.openSession(false);
try {
applyChange(Operation.ADD, change, session);
} finally {
dbClient.closeSession(session);
}
}

public void removePermission(PermissionChange change) {
DbSession session = dbClient.openSession(false);
try {
applyChange(Operation.REMOVE, change, session);
} finally {
session.close();
}
this.userPermissionChanger = userPermissionChanger;
this.groupPermissionChanger = groupPermissionChanger;
}

private void applyChange(Operation operation, PermissionChange change, DbSession session) {
userSession.checkLoggedIn();
change.validate();
boolean changed;
if (change.userLogin() != null) {
changed = applyChangeOnUser(session, operation, change);
} else {
changed = applyChangeOnGroup(session, operation, change);
}
if (changed) {
session.commit();
if (change.componentKey() != null) {
indexProjectPermissions();
public void apply(DbSession dbSession, Collection<PermissionChange> changes) {
Set<Long> projectIds = new HashSet<>();
for (PermissionChange change : changes) {
boolean changed = doApply(dbSession, change);
Optional<ProjectRef> projectId = change.getProjectRef();
if (changed && projectId.isPresent()) {
projectIds.add(projectId.get().getId());
}
}
}

private boolean applyChangeOnGroup(DbSession session, Operation operation, PermissionChange permissionChange) {
ComponentDto project = getComponent(session, permissionChange.componentKey());
Long projectId = project != null ? project.getId() : null;
checkProjectAdminUserByComponentKey(userSession, permissionChange.componentKey());

List<String> existingPermissions = dbClient.roleDao().selectGroupPermissions(session, permissionChange.groupName(), projectId);
if (shouldSkipPermissionChange(operation, existingPermissions, permissionChange)) {
return false;
for (Long projectId : projectIds) {
dbClient.resourceDao().updateAuthorizationDate(projectId, dbSession);
}
dbSession.commit();

Long targetedGroup = getTargetedGroup(session, permissionChange.groupName());
String permission = permissionChange.permission();
if (Operation.ADD == operation) {
validateNotAnyoneAndAdminPermission(permission, permissionChange.groupName());
permissionRepository.insertGroupPermission(projectId, targetedGroup, permission, session);
} else {
checkAdminUsersExistOutsideTheRemovedGroup(session, permissionChange, targetedGroup);
permissionRepository.deleteGroupPermission(projectId, targetedGroup, permission, session);
if (!projectIds.isEmpty()) {
issueAuthorizationIndexer.index();
}
return true;
}

private boolean applyChangeOnUser(DbSession session, Operation operation, PermissionChange permissionChange) {
ComponentDto project = getComponent(session, permissionChange.componentKey());
Long projectId = project != null ? project.getId() : null;
String projectUuid = project != null ? project.uuid() : null;
checkProjectAdminUserByComponentKey(userSession, permissionChange.componentKey());

Set<String> existingPermissions = dbClient.userPermissionDao().selectPermissionsByLogin(session, permissionChange.userLogin(), projectUuid);
if (shouldSkipPermissionChange(operation, existingPermissions, permissionChange)) {
return false;
private boolean doApply(DbSession dbSession, PermissionChange change) {
if (change instanceof UserPermissionChange) {
return userPermissionChanger.apply(dbSession, (UserPermissionChange) change);
}

UserDto targetedUser = getTargetedUser(session, permissionChange.userLogin());
if (Operation.ADD == operation) {
permissionRepository.insertUserPermission(projectId, targetedUser.getId(), permissionChange.permission(), session);
} else {
checkOtherAdminUsersExist(session, permissionChange);
permissionRepository.deleteUserPermission(project, targetedUser.getLogin(), permissionChange.permission(), session);
if (change instanceof GroupPermissionChange) {
return groupPermissionChanger.apply(dbSession, (GroupPermissionChange) change);
}
return true;

}

private void checkOtherAdminUsersExist(DbSession session, PermissionChange permissionChange) {
if (GlobalPermissions.SYSTEM_ADMIN.equals(permissionChange.permission())
&& permissionChange.componentKey() == null
&& dbClient.roleDao().countUserPermissions(session, permissionChange.permission(), null) <= 1) {
throw new BadRequestException(String.format("Last user with '%s' permission. Permission cannot be removed.", GlobalPermissions.SYSTEM_ADMIN));
}
}

private void checkAdminUsersExistOutsideTheRemovedGroup(DbSession session, PermissionChange permissionChange, @Nullable Long groupIdToExclude) {
if (GlobalPermissions.SYSTEM_ADMIN.equals(permissionChange.permission())
&& groupIdToExclude != null
&& permissionChange.componentKey() == null
&& dbClient.roleDao().countUserPermissions(session, permissionChange.permission(), groupIdToExclude) <= 0) {
throw new BadRequestException(String.format("Last group with '%s' permission. Permission cannot be removed.", GlobalPermissions.SYSTEM_ADMIN));
}
}

private UserDto getTargetedUser(DbSession session, String userLogin) {
UserDto user = dbClient.userDao().selectActiveUserByLogin(session, userLogin);
badRequestIfNullResult(user, OBJECT_TYPE_USER, userLogin);
return user;
}

@Nullable
private Long getTargetedGroup(DbSession session, String group) {
if (isAnyone(group)) {
return null;
} else {
GroupDto groupDto = dbClient.groupDao().selectByName(session, group);
badRequestIfNullResult(groupDto, OBJECT_TYPE_GROUP, group);
return groupDto.getId();
}
}

private static boolean shouldSkipPermissionChange(Operation operation, Collection<String> existingPermissions, PermissionChange permissionChange) {
return (Operation.ADD == operation && existingPermissions.contains(permissionChange.permission())) ||
(Operation.REMOVE == operation && !existingPermissions.contains(permissionChange.permission()));
}

@CheckForNull
private ComponentDto getComponent(DbSession session, @Nullable String componentKey) {
if (componentKey == null) {
return null;
}
return componentFinder.getByKey(session, componentKey);
}

private static Object badRequestIfNullResult(@Nullable Object component, String objectType, String objectKey) {
if (component == null) {
throw new BadRequestException(String.format(NOT_FOUND_FORMAT, objectType, objectKey));
}
return component;
}
throw new UnsupportedOperationException("Unsupported permission change: " + change.getClass());

private void indexProjectPermissions() {
issueAuthorizationIndexer.index();
}
}

+ 53
- 0
server/sonar-server/src/main/java/org/sonar/server/permission/ProjectRef.java View File

@@ -0,0 +1,53 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.permission;

import javax.annotation.concurrent.Immutable;
import org.sonar.db.component.ComponentDto;

import static java.util.Objects.requireNonNull;

/**
* Reference to a project by its db id or uuid. Temporarily
* as long as permissions do not use only uuids.
*/
@Immutable
public class ProjectRef {

private final long id;
private final String uuid;

public ProjectRef(long projectId, String projectUuid) {
this.id = projectId;
this.uuid = requireNonNull(projectUuid);
}

public ProjectRef(ComponentDto dto) {
this(requireNonNull(dto.getId()), dto.uuid());
}

public long getId() {
return id;
}

public String getUuid() {
return uuid;
}
}

+ 49
- 0
server/sonar-server/src/main/java/org/sonar/server/permission/UserId.java View File

@@ -0,0 +1,49 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.permission;

import javax.annotation.concurrent.Immutable;

import static java.util.Objects.requireNonNull;

/**
* Reference a user by his technical (db) id or functional login.
* This is temporary class as long as services and DAOs do not
* use only technical id.
*/
@Immutable
public class UserId {

private final long id;
private final String login;

public UserId(long userId, String login) {
this.id = userId;
this.login = requireNonNull(login);
}

public long getId() {
return id;
}

public String getLogin() {
return login;
}
}

+ 39
- 0
server/sonar-server/src/main/java/org/sonar/server/permission/UserPermissionChange.java View File

@@ -0,0 +1,39 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.permission;

import javax.annotation.Nullable;

import static java.util.Objects.requireNonNull;

public class UserPermissionChange extends PermissionChange {

private final UserId userId;

public UserPermissionChange(Operation operation, String organizationUuid, String permission, @Nullable ProjectRef projectRef,
UserId userId) {
super(operation, organizationUuid, permission, projectRef);
this.userId = requireNonNull(userId);
}

public UserId getUserId() {
return userId;
}
}

+ 78
- 0
server/sonar-server/src/main/java/org/sonar/server/permission/UserPermissionChanger.java View File

@@ -0,0 +1,78 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.permission;

import java.util.Set;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.permission.UserPermissionDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.permission.PermissionChange.Operation;
import org.sonar.server.user.UserSession;

import static org.sonar.server.permission.PermissionPrivilegeChecker.checkProjectAdminUserByComponentUuid;

public class UserPermissionChanger {

private final DbClient dbClient;
private final UserSession userSession;

public UserPermissionChanger(DbClient dbClient, UserSession userSession) {
this.dbClient = dbClient;
this.userSession = userSession;
}

public boolean apply(DbSession dbSession, UserPermissionChange change) {
checkProjectAdminUserByComponentUuid(userSession, change.getProjectUuid());

if (shouldSkipChange(dbSession, change)) {
return false;
}

switch (change.getOperation()) {
case ADD:
UserPermissionDto dto = new UserPermissionDto(change.getOrganizationUuid(), change.getPermission(), change.getUserId().getId(), change.getNullableProjectId());
dbClient.userPermissionDao().insert(dbSession, dto);
break;
case REMOVE:
checkOtherAdminUsersExist(dbSession, change);
dbClient.userPermissionDao().delete(dbSession, change.getUserId().getLogin(), change.getProjectUuid(), change.getPermission());
break;
default:
throw new UnsupportedOperationException("Unsupported permission change: " + change.getOperation());
}
return true;
}

private boolean shouldSkipChange(DbSession dbSession, UserPermissionChange change) {
Set<String> existingPermissions = dbClient.userPermissionDao().selectPermissionsByLogin(dbSession, change.getUserId().getLogin(), change.getProjectUuid());
return (Operation.ADD == change.getOperation() && existingPermissions.contains(change.getPermission())) ||
(Operation.REMOVE == change.getOperation() && !existingPermissions.contains(change.getPermission()));
}

private void checkOtherAdminUsersExist(DbSession session, PermissionChange change) {
if (GlobalPermissions.SYSTEM_ADMIN.equals(change.getPermission()) &&
!change.getProjectRef().isPresent() &&
dbClient.roleDao().countUserPermissions(session, change.getPermission(), null) <= 1) {
throw new BadRequestException(String.format("Last user with '%s' permission. Permission cannot be removed.", GlobalPermissions.SYSTEM_ADMIN));
}
}
}

+ 19
- 36
server/sonar-server/src/main/java/org/sonar/server/permission/ws/AddGroupAction.java View File

@@ -19,39 +19,37 @@
*/
package org.sonar.server.permission.ws;

import java.util.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.DbClient;
import org.sonar.db.DbSession;
import org.sonar.server.permission.GroupPermissionChange;
import org.sonar.server.permission.PermissionChange;
import org.sonar.server.permission.PermissionUpdater;
import org.sonarqube.ws.client.permission.AddGroupWsRequest;
import org.sonar.server.permission.ProjectRef;
import org.sonar.server.usergroups.ws.GroupIdOrAnyone;

import static java.util.Arrays.asList;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createGroupIdParameter;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createGroupNameParameter;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createPermissionParameter;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createProjectParameters;
import static org.sonar.server.permission.ws.WsProjectRef.newOptionalWsProjectRef;
import static org.sonar.server.usergroups.ws.WsGroupRef.newWsGroupRef;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_GROUP_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_GROUP_NAME;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_KEY;

public class AddGroupAction implements PermissionsWsAction {

public static final String ACTION = "add_group";

private final DbClient dbClient;
private final PermissionChangeBuilder permissionChangeBuilder;
private final PermissionUpdater permissionUpdater;
private final PermissionWsSupport support;

public AddGroupAction(DbClient dbClient, PermissionChangeBuilder permissionChangeBuilder, PermissionUpdater permissionUpdater) {
this.permissionChangeBuilder = permissionChangeBuilder;
this.permissionUpdater = permissionUpdater;
public AddGroupAction(DbClient dbClient, PermissionUpdater permissionUpdater, PermissionWsSupport support) {
this.dbClient = dbClient;
this.permissionUpdater = permissionUpdater;
this.support = support;
}

@Override
@@ -73,33 +71,18 @@ public class AddGroupAction implements PermissionsWsAction {

@Override
public void handle(Request request, Response response) throws Exception {
AddGroupWsRequest addGroupWsRequest = toAddGroupWsRequest(request);
doHandle(addGroupWsRequest);
try (DbSession dbSession = dbClient.openSession(false)) {
GroupIdOrAnyone group = support.findGroup(dbSession, request);
Optional<ProjectRef> projectId = support.findProject(dbSession, request);

response.noContent();
}

private void doHandle(AddGroupWsRequest request) {
DbSession dbSession = dbClient.openSession(false);
try {
Long groupId = request.getGroupId() == null ? null : Long.valueOf(request.getGroupId());
PermissionChange permissionChange = permissionChangeBuilder.buildGroupPermissionChange(
dbSession,
request.getPermission(),
newOptionalWsProjectRef(request.getProjectId(), request.getProjectKey()),
newWsGroupRef(groupId, request.getGroupName()));
permissionUpdater.addPermission(permissionChange);
} finally {
dbClient.closeSession(dbSession);
PermissionChange change = new GroupPermissionChange(
PermissionChange.Operation.ADD,
request.mandatoryParam(PARAM_PERMISSION),
projectId.orElse(null),
group);
permissionUpdater.apply(dbSession, asList(change));
}
response.noContent();
}

private static AddGroupWsRequest toAddGroupWsRequest(Request request) {
return new AddGroupWsRequest()
.setPermission(request.mandatoryParam(PARAM_PERMISSION))
.setGroupId(request.param(PARAM_GROUP_ID))
.setGroupName(request.param(PARAM_GROUP_NAME))
.setProjectId(request.param(PARAM_PROJECT_ID))
.setProjectKey(request.param(PARAM_PROJECT_KEY));
}
}

+ 24
- 35
server/sonar-server/src/main/java/org/sonar/server/permission/ws/AddUserAction.java View File

@@ -19,24 +19,26 @@
*/
package org.sonar.server.permission.ws;

import com.google.common.base.Optional;
import java.util.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.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.server.permission.PermissionChange;
import org.sonar.server.permission.PermissionUpdater;
import org.sonarqube.ws.client.permission.AddUserWsRequest;
import org.sonar.server.permission.ProjectRef;
import org.sonar.server.permission.UserId;
import org.sonar.server.permission.UserPermissionChange;

import static org.sonar.server.permission.ws.PermissionRequestValidator.validatePermission;
import static java.util.Arrays.asList;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createOrganizationParameter;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createPermissionParameter;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createProjectParameters;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createUserLoginParameter;
import static org.sonar.server.permission.ws.WsProjectRef.newOptionalWsProjectRef;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_ORGANIZATION_KEY;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_KEY;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_USER_LOGIN;

public class AddUserAction implements PermissionsWsAction {
@@ -45,12 +47,12 @@ public class AddUserAction implements PermissionsWsAction {

private final DbClient dbClient;
private final PermissionUpdater permissionUpdater;
private final PermissionChangeBuilder permissionChangeBuilder;
private final PermissionWsSupport support;

public AddUserAction(DbClient dbClient, PermissionUpdater permissionUpdater, PermissionChangeBuilder permissionWsCommons) {
public AddUserAction(DbClient dbClient, PermissionUpdater permissionUpdater, PermissionWsSupport support) {
this.dbClient = dbClient;
this.permissionUpdater = permissionUpdater;
this.permissionChangeBuilder = permissionWsCommons;
this.support = support;
}

@Override
@@ -66,36 +68,23 @@ public class AddUserAction implements PermissionsWsAction {
createPermissionParameter(action);
createUserLoginParameter(action);
createProjectParameters(action);
createOrganizationParameter(action);
}

@Override
public void handle(Request request, Response response) throws Exception {
doHandle(toAddUserWsRequest(request));
response.noContent();
}

private void doHandle(AddUserWsRequest request) {
Optional<WsProjectRef> projectRef = newOptionalWsProjectRef(request.getProjectId(), request.getProjectKey());
validatePermission(request.getPermission(), projectRef);
DbSession dbSession = dbClient.openSession(false);
try {
PermissionChange permissionChange = permissionChangeBuilder.buildUserPermissionChange(
dbSession,
request.getPermission(),
projectRef,
request.getLogin());
permissionUpdater.addPermission(permissionChange);

} finally {
dbClient.closeSession(dbSession);
try (DbSession dbSession = dbClient.openSession(false)) {
UserId user = support.findUser(dbSession, request.mandatoryParam(PARAM_USER_LOGIN));
Optional<ProjectRef> projectId = support.findProject(dbSession, request);
OrganizationDto org = support.findOrganization(dbSession, request.param(PARAM_ORGANIZATION_KEY));
PermissionChange change = new UserPermissionChange(
PermissionChange.Operation.ADD,
org.getUuid(),
request.mandatoryParam(PARAM_PERMISSION),
projectId.orElse(null),
user);
permissionUpdater.apply(dbSession, asList(change));
}
}

private static AddUserWsRequest toAddUserWsRequest(Request request) {
return new AddUserWsRequest()
.setPermission(request.mandatoryParam(PARAM_PERMISSION))
.setLogin(request.mandatoryParam(PARAM_USER_LOGIN))
.setProjectId(request.param(PARAM_PROJECT_ID))
.setProjectKey(request.param(PARAM_PROJECT_KEY));
response.noContent();
}
}

+ 32
- 54
server/sonar-server/src/main/java/org/sonar/server/permission/ws/GroupsAction.java View File

@@ -19,12 +19,12 @@
*/
package org.sonar.server.permission.ws;

import com.google.common.base.Optional;
import com.google.common.collect.Multimap;
import com.google.common.collect.Ordering;
import com.google.common.collect.TreeMultimap;
import com.google.common.io.Resources;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.sonar.api.security.DefaultGroups;
import org.sonar.api.server.ws.Request;
@@ -34,38 +34,33 @@ import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.utils.Paging;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.permission.GroupPermissionDto;
import org.sonar.db.permission.PermissionQuery;
import org.sonar.db.user.GroupDto;
import org.sonar.db.permission.GroupPermissionDto;
import org.sonar.server.permission.ProjectRef;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.WsPermissions.Group;
import org.sonarqube.ws.WsPermissions.WsGroupsResponse;
import org.sonarqube.ws.client.permission.GroupsWsRequest;

import static java.util.Collections.emptyList;
import static org.sonar.db.permission.PermissionQuery.DEFAULT_PAGE_SIZE;
import static org.sonar.db.permission.PermissionQuery.RESULTS_MAX_SIZE;
import static org.sonar.db.permission.PermissionQuery.SEARCH_QUERY_MIN_LENGTH;
import static org.sonar.server.permission.PermissionPrivilegeChecker.checkProjectAdminUserByComponentDto;
import static org.sonar.server.permission.ws.PermissionRequestValidator.validatePermission;
import static org.sonar.server.permission.PermissionPrivilegeChecker.checkProjectAdminUserByComponentUuid;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createPermissionParameter;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createProjectParameters;
import static org.sonar.server.permission.ws.WsProjectRef.newOptionalWsProjectRef;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_KEY;

public class GroupsAction implements PermissionsWsAction {
private final DbClient dbClient;
private final UserSession userSession;
private final PermissionDependenciesFinder dependenciesFinder;
private final PermissionWsSupport support;

public GroupsAction(DbClient dbClient, UserSession userSession, PermissionDependenciesFinder dependenciesFinder) {
public GroupsAction(DbClient dbClient, UserSession userSession, PermissionWsSupport support) {
this.dbClient = dbClient;
this.userSession = userSession;
this.dependenciesFinder = dependenciesFinder;
this.support = support;
}

@Override
@@ -83,58 +78,39 @@ public class GroupsAction implements PermissionsWsAction {
.setResponseExample(Resources.getResource(getClass(), "groups-example.json"))
.setHandler(this);

createPermissionParameter(action)
.setRequired(false);
// TODO add orgKey
createPermissionParameter(action).setRequired(false);
createProjectParameters(action);
}

@Override
public void handle(Request wsRequest, Response wsResponse) throws Exception {
GroupsWsRequest groupsRequest = toGroupsWsRequest(wsRequest);
WsGroupsResponse groupsResponse = doHandle(groupsRequest);
writeProtobuf(groupsResponse, wsRequest, wsResponse);
}

private WsGroupsResponse doHandle(GroupsWsRequest request) {
DbSession dbSession = dbClient.openSession(false);
try {
Optional<ComponentDto> project = dependenciesFinder.searchProject(dbSession, newOptionalWsProjectRef(request.getProjectId(), request.getProjectKey()));
checkProjectAdminUserByComponentDto(userSession, project);

PermissionQuery dbQuery = buildPermissionQuery(request, project);
List<GroupDto> groups = findGroups(dbSession, dbQuery);
int total = dbClient.groupPermissionDao().countGroupsByPermissionQuery(dbSession, dbQuery);
List<GroupPermissionDto> groupsWithPermission = findGroupPermissions(dbSession, groups, project);
return buildResponse(groups, groupsWithPermission, Paging.forPageIndex(request.getPage()).withPageSize(request.getPageSize()).andTotal(total));
} finally {
dbClient.closeSession(dbSession);
public void handle(Request request, Response response) throws Exception {
try (DbSession dbSession = dbClient.openSession(false)) {
Optional<ProjectRef> projectId = support.findProject(dbSession, request);
checkProjectAdminUserByComponentUuid(userSession, projectId.isPresent() ? projectId.get().getUuid() : null);

PermissionQuery query = buildPermissionQuery(request, projectId);
// TODO validatePermission(groupsRequest.getPermission(), wsProjectRef);
List<GroupDto> groups = findGroups(dbSession, query);
int total = dbClient.groupPermissionDao().countGroupsByPermissionQuery(dbSession, query);
List<GroupPermissionDto> groupsWithPermission = findGroupPermissions(dbSession, groups, projectId);
Paging paging = Paging.forPageIndex(request.mandatoryParamAsInt(Param.PAGE)).withPageSize(query.getPageSize()).andTotal(total);
WsGroupsResponse groupsResponse = buildResponse(groups, groupsWithPermission, paging);
writeProtobuf(groupsResponse, request, response);
}
}

private static GroupsWsRequest toGroupsWsRequest(Request request) {
GroupsWsRequest groupsRequest = new GroupsWsRequest()
private static PermissionQuery buildPermissionQuery(Request request, Optional<ProjectRef> project) {
String textQuery = request.param(Param.TEXT_QUERY);
PermissionQuery.Builder permissionQuery = PermissionQuery.builder()
.setPermission(request.param(PARAM_PERMISSION))
.setProjectId(request.param(PARAM_PROJECT_ID))
.setProjectKey(request.param(PARAM_PROJECT_KEY))
.setPage(request.mandatoryParamAsInt(Param.PAGE))
.setPageIndex(request.mandatoryParamAsInt(Param.PAGE))
.setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE))
.setQuery(request.param(Param.TEXT_QUERY));

Optional<WsProjectRef> wsProjectRef = newOptionalWsProjectRef(groupsRequest.getProjectId(), groupsRequest.getProjectKey());
validatePermission(groupsRequest.getPermission(), wsProjectRef);
return groupsRequest;
}

private static PermissionQuery buildPermissionQuery(GroupsWsRequest request, Optional<ComponentDto> project) {
PermissionQuery.Builder permissionQuery = PermissionQuery.builder()
.setPermission(request.getPermission())
.setPageIndex(request.getPage())
.setPageSize(request.getPageSize())
.setSearchQuery(request.getQuery());
.setSearchQuery(textQuery);
if (project.isPresent()) {
permissionQuery.setComponentUuid(project.get().uuid());
permissionQuery.setComponentUuid(project.get().getUuid());
}
if (request.getQuery() == null) {
if (textQuery == null) {
permissionQuery.withAtLeastOnePermission();
}
return permissionQuery.build();
@@ -166,6 +142,7 @@ public class GroupsAction implements PermissionsWsAction {
}

private List<GroupDto> findGroups(DbSession dbSession, PermissionQuery dbQuery) {
// TODO support organizations
List<String> orderedNames = dbClient.groupPermissionDao().selectGroupNamesByPermissionQuery(dbSession, dbQuery);
List<GroupDto> groups = dbClient.groupDao().selectByNames(dbSession, orderedNames);
if (orderedNames.contains(DefaultGroups.ANYONE)) {
@@ -174,10 +151,11 @@ public class GroupsAction implements PermissionsWsAction {
return Ordering.explicit(orderedNames).onResultOf(GroupDto::getName).immutableSortedCopy(groups);
}

private List<GroupPermissionDto> findGroupPermissions(DbSession dbSession, List<GroupDto> groups, Optional<ComponentDto> project) {
private List<GroupPermissionDto> findGroupPermissions(DbSession dbSession, List<GroupDto> groups, Optional<ProjectRef> project) {
if (groups.isEmpty()) {
return emptyList();
}
// TODO use groupId
List<String> names = groups.stream().map(GroupDto::getName).collect(Collectors.toList());
return dbClient.groupPermissionDao().selectGroupPermissionsByGroupNamesAndProject(dbSession, names, project.isPresent() ? project.get().getId() : null);
}

+ 0
- 65
server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionChangeBuilder.java View File

@@ -1,65 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.permission.ws;

import com.google.common.base.Optional;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.server.permission.PermissionChange;
import org.sonar.server.usergroups.ws.WsGroupRef;

import static org.sonar.server.permission.ws.PermissionRequestValidator.validatePermission;

public class PermissionChangeBuilder {

private final PermissionDependenciesFinder dependenciesFinder;

public PermissionChangeBuilder(PermissionDependenciesFinder dependenciesFinder) {
this.dependenciesFinder = dependenciesFinder;
}

public PermissionChange buildUserPermissionChange(DbSession dbSession, String permission, Optional<WsProjectRef> projectRef, String login) {
PermissionChange permissionChange = new PermissionChange()
.setPermission(permission)
.setUserLogin(login);
addProjectToPermissionChange(dbSession, permissionChange, projectRef);

return permissionChange;
}

public PermissionChange buildGroupPermissionChange(DbSession dbSession, String permission, Optional<WsProjectRef> projectRef, WsGroupRef groupRef) {
validatePermission(permission, projectRef);
String groupName = dependenciesFinder.getGroupName(dbSession, groupRef);

PermissionChange permissionChange = new PermissionChange()
.setPermission(permission)
.setGroupName(groupName);
addProjectToPermissionChange(dbSession, permissionChange, projectRef);

return permissionChange;
}

private void addProjectToPermissionChange(DbSession dbSession, PermissionChange permissionChange, Optional<WsProjectRef> projectRef) {
Optional<ComponentDto> project = dependenciesFinder.searchProject(dbSession, projectRef);
if (project.isPresent()) {
permissionChange.setComponentKey(project.get().key());
}
}
}

+ 0
- 103
server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionDependenciesFinder.java View File

@@ -1,103 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.permission.ws;

import com.google.common.base.Optional;
import javax.annotation.CheckForNull;
import org.sonar.api.resources.ResourceTypes;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.permission.template.PermissionTemplateDto;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.usergroups.ws.UserGroupFinder;
import org.sonar.server.usergroups.ws.WsGroupRef;

import static org.sonar.api.security.DefaultGroups.ANYONE;
import static org.sonar.api.security.DefaultGroups.isAnyone;
import static org.sonar.server.ws.WsUtils.checkFound;

public class PermissionDependenciesFinder {
private final DbClient dbClient;
private final ComponentFinder componentFinder;
private final UserGroupFinder userGroupFinder;
private final ResourceTypes resourceTypes;

public PermissionDependenciesFinder(DbClient dbClient, ComponentFinder componentFinder, UserGroupFinder userGroupFinder, ResourceTypes resourceTypes) {
this.dbClient = dbClient;
this.componentFinder = componentFinder;
this.userGroupFinder = userGroupFinder;
this.resourceTypes = resourceTypes;
}

/**
* @throws org.sonar.server.exceptions.NotFoundException if a project identifier is provided but it's not found
*/
Optional<ComponentDto> searchProject(DbSession dbSession, Optional<WsProjectRef> optionalWsProjectRef) {
if (!optionalWsProjectRef.isPresent()) {
return Optional.absent();
}

WsProjectRef wsProjectRef = optionalWsProjectRef.get();
return Optional.of(componentFinder.getRootComponentOrModuleByUuidOrKey(dbSession, wsProjectRef.uuid(), wsProjectRef.key(), resourceTypes));
}

public ComponentDto getRootComponentOrModule(DbSession dbSession, WsProjectRef projectRef) {
return componentFinder.getRootComponentOrModuleByUuidOrKey(dbSession, projectRef.uuid(), projectRef.key(), resourceTypes);
}

String getGroupName(DbSession dbSession, WsGroupRef groupRef) {
GroupDto group = getGroup(dbSession, groupRef);

return group == null ? ANYONE : group.getName();
}

/**
*
* @return null if it's the anyone group
*/
@CheckForNull
public GroupDto getGroup(DbSession dbSession, WsGroupRef group) {
if (isAnyone(group.name())) {
return null;
}

return userGroupFinder.getGroup(dbSession, group);
}

public UserDto getUser(DbSession dbSession, String userLogin) {
return checkFound(dbClient.userDao().selectActiveUserByLogin(dbSession, userLogin),
"User with login '%s' is not found'", userLogin);
}

public PermissionTemplateDto getTemplate(DbSession dbSession, WsTemplateRef template) {
if (template.uuid() != null) {
return checkFound(
dbClient.permissionTemplateDao().selectByUuid(dbSession, template.uuid()),
"Permission template with id '%s' is not found", template.uuid());
} else {
return checkFound(
dbClient.permissionTemplateDao().selectByName(dbSession, template.name()),
"Permission template with name '%s' is not found (case insensitive)", template.name());
}
}
}

+ 4
- 16
server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionRequestValidator.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.server.permission.ws;

import com.google.common.base.Optional;
import com.google.common.collect.FluentIterable;
import java.util.Set;
import java.util.regex.Pattern;
@@ -29,11 +28,11 @@ import org.sonar.api.resources.ResourceTypes;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.permission.ProjectPermissions;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.usergroups.ws.GroupIdOrAnyone;

import static com.google.common.base.Strings.isNullOrEmpty;
import static java.lang.String.format;
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.sonar.api.security.DefaultGroups.isAnyone;
import static org.sonar.server.component.ResourceTypeFunctions.RESOURCE_TYPE_TO_QUALIFIER;
import static org.sonar.server.ws.WsUtils.checkRequest;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
@@ -48,17 +47,6 @@ public class PermissionRequestValidator {
// static methods only
}

public static void validatePermission(@Nullable String permission, Optional<WsProjectRef> projectRef) {
if (permission == null) {
return;
}
if (projectRef.isPresent()) {
validateProjectPermission(permission);
} else {
validateGlobalPermission(permission);
}
}

public static String validateProjectPermission(String permission) {
checkRequest(ProjectPermissions.ALL.contains(permission),
format("The '%s' parameter for project permissions must be one of %s. '%s' was passed.", PARAM_PERMISSION, ProjectPermissions.ALL_ON_ONE_LINE, permission));
@@ -70,9 +58,9 @@ public class PermissionRequestValidator {
format("The '%s' parameter for global permissions must be one of %s. '%s' was passed.", PARAM_PERMISSION, GlobalPermissions.ALL_ON_ONE_LINE, permission));
}

public static void validateNotAnyoneAndAdminPermission(String permission, @Nullable String groupName) {
checkRequest(!GlobalPermissions.SYSTEM_ADMIN.equals(permission) || !isAnyone(groupName),
format("It is not possible to add the '%s' permission to the '%s' group.", permission, groupName));
public static void validateNotAnyoneAndAdminPermission(String permission, GroupIdOrAnyone group) {
checkRequest(!GlobalPermissions.SYSTEM_ADMIN.equals(permission) || !group.isAnyone(),
format("It is not possible to add the '%s' permission to group 'Anyone'.", permission));
}

public static void validateTemplateNameFormat(String name) {

+ 111
- 0
server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionWsSupport.java View File

@@ -0,0 +1,111 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.permission.ws;

import java.util.Optional;
import javax.annotation.Nullable;
import org.sonar.api.resources.ResourceTypes;
import org.sonar.api.server.ws.Request;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.permission.template.PermissionTemplateDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.permission.ProjectRef;
import org.sonar.server.permission.UserId;
import org.sonar.server.permission.ws.template.WsTemplateRef;
import org.sonar.server.usergroups.ws.GroupIdOrAnyone;
import org.sonar.server.usergroups.ws.GroupWsRef;
import org.sonar.server.usergroups.ws.GroupWsSupport;
import org.sonarqube.ws.client.permission.PermissionsWsParameters;

import static org.sonar.server.ws.WsUtils.checkFound;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_GROUP_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_GROUP_NAME;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_ORGANIZATION_KEY;

public class PermissionWsSupport {

private final DbClient dbClient;
private final ComponentFinder componentFinder;
private final GroupWsSupport groupWsSupport;
private final ResourceTypes resourceTypes;

public PermissionWsSupport(DbClient dbClient, ComponentFinder componentFinder, GroupWsSupport groupWsSupport, ResourceTypes resourceTypes) {
this.dbClient = dbClient;
this.componentFinder = componentFinder;
this.groupWsSupport = groupWsSupport;
this.resourceTypes = resourceTypes;
}

public OrganizationDto findOrganization(DbSession dbSession, @Nullable String organizationKey) {
return groupWsSupport.findOrganizationByKey(dbSession, organizationKey);
}

/**
* @throws org.sonar.server.exceptions.NotFoundException if a project does not exist
*/
public ProjectRef findProject(DbSession dbSession, WsProjectRef ref) {
ComponentDto project = componentFinder.getRootComponentOrModuleByUuidOrKey(dbSession, ref.uuid(), ref.key(), resourceTypes);
return new ProjectRef(project.getId(), project.uuid());
}

public Optional<ProjectRef> findProject(DbSession dbSession, Request request) {
String uuid = request.param(PermissionsWsParameters.PARAM_PROJECT_ID);
String key = request.param(PermissionsWsParameters.PARAM_PROJECT_KEY);
if (uuid != null || key != null) {
WsProjectRef ref = WsProjectRef.newWsProjectRef(uuid, key);
return Optional.of(findProject(dbSession, ref));
}
return Optional.empty();
}

public ComponentDto getRootComponentOrModule(DbSession dbSession, WsProjectRef projectRef) {
return componentFinder.getRootComponentOrModuleByUuidOrKey(dbSession, projectRef.uuid(), projectRef.key(), resourceTypes);
}

public GroupIdOrAnyone findGroup(DbSession dbSession, Request request) {
Long groupId = request.paramAsLong(PARAM_GROUP_ID);
String orgKey = request.param(PARAM_ORGANIZATION_KEY);
String groupName = request.param(PARAM_GROUP_NAME);
GroupWsRef groupRef = GroupWsRef.create(groupId, orgKey, groupName);
return groupWsSupport.findGroupOrAnyone(dbSession, groupRef);
}

public UserId findUser(DbSession dbSession, String login) {
UserDto dto = dbClient.userDao().selectActiveUserByLogin(dbSession, login);
checkFound(dto, "User with login '%s' is not found'", login);
return new UserId(dto.getId(), dto.getLogin());
}

public PermissionTemplateDto findTemplate(DbSession dbSession, WsTemplateRef ref) {
if (ref.uuid() != null) {
return checkFound(
dbClient.permissionTemplateDao().selectByUuid(dbSession, ref.uuid()),
"Permission template with id '%s' is not found", ref.uuid());
} else {
return checkFound(
dbClient.permissionTemplateDao().selectByName(dbSession, ref.name()),
"Permission template with name '%s' is not found (case insensitive)", ref.name());
}
}
}

+ 14
- 2
server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionsWsModule.java View File

@@ -20,6 +20,11 @@
package org.sonar.server.permission.ws;

import org.sonar.core.platform.Module;
import org.sonar.db.permission.PermissionRepository;
import org.sonar.server.permission.GroupPermissionChanger;
import org.sonar.server.permission.PermissionService;
import org.sonar.server.permission.PermissionUpdater;
import org.sonar.server.permission.UserPermissionChanger;
import org.sonar.server.permission.ws.template.AddGroupToTemplateAction;
import org.sonar.server.permission.ws.template.AddProjectCreatorToTemplateAction;
import org.sonar.server.permission.ws.template.AddUserToTemplateAction;
@@ -27,12 +32,15 @@ import org.sonar.server.permission.ws.template.ApplyTemplateAction;
import org.sonar.server.permission.ws.template.BulkApplyTemplateAction;
import org.sonar.server.permission.ws.template.CreateTemplateAction;
import org.sonar.server.permission.ws.template.DefaultPermissionTemplateFinder;
import org.sonar.server.permission.ws.template.DeleteTemplateAction;
import org.sonar.server.permission.ws.template.RemoveGroupFromTemplateAction;
import org.sonar.server.permission.ws.template.RemoveProjectCreatorFromTemplateAction;
import org.sonar.server.permission.ws.template.RemoveUserFromTemplateAction;
import org.sonar.server.permission.ws.template.SearchTemplatesAction;
import org.sonar.server.permission.ws.template.SearchTemplatesDataLoader;
import org.sonar.server.permission.ws.template.SetDefaultTemplateAction;
import org.sonar.server.permission.ws.template.TemplateGroupsAction;
import org.sonar.server.permission.ws.template.TemplateUsersAction;
import org.sonar.server.permission.ws.template.UpdateTemplateAction;

public class PermissionsWsModule extends Module {
@@ -65,10 +73,14 @@ public class PermissionsWsModule extends Module {
TemplateGroupsAction.class,
BulkApplyTemplateAction.class,
// utility classes
PermissionChangeBuilder.class,
PermissionRepository.class,
PermissionService.class,
PermissionUpdater.class,
UserPermissionChanger.class,
GroupPermissionChanger.class,
SearchProjectPermissionsDataLoader.class,
SearchTemplatesDataLoader.class,
PermissionDependenciesFinder.class,
PermissionWsSupport.class,
DefaultPermissionTemplateFinder.class);
}
}

+ 9
- 0
server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionsWsParametersBuilder.java View File

@@ -31,6 +31,7 @@ import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_D
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_GROUP_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_GROUP_NAME;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_ORGANIZATION_KEY;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_KEY;
@@ -67,15 +68,23 @@ public class PermissionsWsParametersBuilder {
public static NewParam createProjectPermissionParameter(NewAction action) {
return action.createParam(PARAM_PERMISSION)
.setDescription(PROJECT_PERMISSION_PARAM_DESCRIPTION)
.setPossibleValues(ProjectPermissions.ALL)
.setRequired(true);
}

public static void createGroupNameParameter(NewAction action) {
createOrganizationParameter(action);
action.createParam(PARAM_GROUP_NAME)
.setDescription("Group name or 'anyone' (case insensitive)")
.setExampleValue("sonar-administrators");
}

public static void createOrganizationParameter(NewAction action) {
action.createParam(PARAM_ORGANIZATION_KEY)
.setDescription("Key of organization, used when group name is set")
.setExampleValue("my-org");
}

public static void createGroupIdParameter(NewAction action) {
action.createParam(PARAM_GROUP_ID)
.setDescription("Group id")

+ 18
- 38
server/sonar-server/src/main/java/org/sonar/server/permission/ws/RemoveGroupAction.java View File

@@ -19,41 +19,37 @@
*/
package org.sonar.server.permission.ws;

import com.google.common.base.Optional;
import java.util.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.DbClient;
import org.sonar.db.DbSession;
import org.sonar.server.permission.GroupPermissionChange;
import org.sonar.server.permission.PermissionChange;
import org.sonar.server.permission.PermissionUpdater;
import org.sonarqube.ws.client.permission.RemoveGroupWsRequest;
import org.sonar.server.permission.ProjectRef;
import org.sonar.server.usergroups.ws.GroupIdOrAnyone;

import static org.sonar.server.permission.ws.PermissionRequestValidator.validatePermission;
import static java.util.Arrays.asList;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createGroupIdParameter;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createGroupNameParameter;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createPermissionParameter;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createProjectParameters;
import static org.sonar.server.permission.ws.WsProjectRef.newOptionalWsProjectRef;
import static org.sonar.server.usergroups.ws.WsGroupRef.newWsGroupRef;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_GROUP_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_GROUP_NAME;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_KEY;

public class RemoveGroupAction implements PermissionsWsAction {

public static final String ACTION = "remove_group";

private final DbClient dbClient;
private final PermissionChangeBuilder permissionChangeBuilder;
private final PermissionUpdater permissionUpdater;
private final PermissionWsSupport support;

public RemoveGroupAction(DbClient dbClient, PermissionChangeBuilder permissionChangeBuilder, PermissionUpdater permissionUpdater) {
public RemoveGroupAction(DbClient dbClient, PermissionUpdater permissionUpdater, PermissionWsSupport support) {
this.dbClient = dbClient;
this.permissionChangeBuilder = permissionChangeBuilder;
this.permissionUpdater = permissionUpdater;
this.support = support;
}

@Override
@@ -75,33 +71,17 @@ public class RemoveGroupAction implements PermissionsWsAction {

@Override
public void handle(Request request, Response response) throws Exception {
doHandle(toRemoveGroupWsRequest(request));
response.noContent();
}
try (DbSession dbSession = dbClient.openSession(false)) {
GroupIdOrAnyone group = support.findGroup(dbSession, request);
Optional<ProjectRef> projectId = support.findProject(dbSession, request);

private void doHandle(RemoveGroupWsRequest request) {
DbSession dbSession = dbClient.openSession(false);
try {
Optional<WsProjectRef> projectRef = newOptionalWsProjectRef(request.getProjectId(), request.getProjectKey());
Long groupId = request.getGroupId() == null ? null : Long.valueOf(request.getGroupId());
validatePermission(request.getPermission(), projectRef);
PermissionChange permissionChange = permissionChangeBuilder.buildGroupPermissionChange(
dbSession,
request.getPermission(),
projectRef,
newWsGroupRef(groupId, request.getGroupName()));
permissionUpdater.removePermission(permissionChange);
} finally {
dbClient.closeSession(dbSession);
PermissionChange change = new GroupPermissionChange(
PermissionChange.Operation.REMOVE,
request.mandatoryParam(PARAM_PERMISSION),
projectId.orElse(null),
group);
permissionUpdater.apply(dbSession, asList(change));
}
}

private static RemoveGroupWsRequest toRemoveGroupWsRequest(Request request) {
return new RemoveGroupWsRequest()
.setPermission(request.mandatoryParam(PARAM_PERMISSION))
.setGroupId(request.param(PARAM_GROUP_ID))
.setGroupName(request.param(PARAM_GROUP_NAME))
.setProjectId(request.param(PARAM_PROJECT_ID))
.setProjectKey(request.param(PARAM_PROJECT_KEY));
response.noContent();
}
}

+ 24
- 34
server/sonar-server/src/main/java/org/sonar/server/permission/ws/RemoveUserAction.java View File

@@ -19,24 +19,26 @@
*/
package org.sonar.server.permission.ws;

import com.google.common.base.Optional;
import java.util.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.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.server.permission.PermissionChange;
import org.sonar.server.permission.PermissionUpdater;
import org.sonarqube.ws.client.permission.RemoveUserWsRequest;
import org.sonar.server.permission.ProjectRef;
import org.sonar.server.permission.UserId;
import org.sonar.server.permission.UserPermissionChange;

import static org.sonar.server.permission.ws.PermissionRequestValidator.validatePermission;
import static java.util.Arrays.asList;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createOrganizationParameter;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createPermissionParameter;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createProjectParameters;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createUserLoginParameter;
import static org.sonar.server.permission.ws.WsProjectRef.newOptionalWsProjectRef;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_ORGANIZATION_KEY;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_KEY;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_USER_LOGIN;

public class RemoveUserAction implements PermissionsWsAction {
@@ -45,12 +47,12 @@ public class RemoveUserAction implements PermissionsWsAction {

private final DbClient dbClient;
private final PermissionUpdater permissionUpdater;
private final PermissionChangeBuilder permissionChangeBuilder;
private final PermissionWsSupport support;

public RemoveUserAction(DbClient dbClient, PermissionUpdater permissionUpdater, PermissionChangeBuilder permissionChangeBuilder) {
public RemoveUserAction(DbClient dbClient, PermissionUpdater permissionUpdater, PermissionWsSupport support) {
this.dbClient = dbClient;
this.permissionUpdater = permissionUpdater;
this.permissionChangeBuilder = permissionChangeBuilder;
this.support = support;
}

@Override
@@ -66,36 +68,24 @@ public class RemoveUserAction implements PermissionsWsAction {
createPermissionParameter(action);
createUserLoginParameter(action);
createProjectParameters(action);
createOrganizationParameter(action);
}

@Override
public void handle(Request request, Response response) throws Exception {
doHandle(toRemoveUserWsRequest(request));
response.noContent();
}

private void doHandle(RemoveUserWsRequest request) {
DbSession dbSession = dbClient.openSession(false);
try {
Optional<WsProjectRef> projectRef = newOptionalWsProjectRef(request.getProjectId(), request.getProjectKey());
validatePermission(request.getPermission(), projectRef);
PermissionChange permissionChange = permissionChangeBuilder.buildUserPermissionChange(
dbSession,
request.getPermission(),
projectRef,
request.getLogin());
permissionUpdater.removePermission(permissionChange);
try (DbSession dbSession = dbClient.openSession(false)) {
UserId user = support.findUser(dbSession, request.mandatoryParam(PARAM_USER_LOGIN));
Optional<ProjectRef> projectId = support.findProject(dbSession, request);
OrganizationDto org = support.findOrganization(dbSession, request.param(PARAM_ORGANIZATION_KEY));

} finally {
dbClient.closeSession(dbSession);
PermissionChange change = new UserPermissionChange(
PermissionChange.Operation.REMOVE,
org.getUuid(),
request.mandatoryParam(PARAM_PERMISSION),
projectId.orElse(null),
user);
permissionUpdater.apply(dbSession, asList(change));
response.noContent();
}
}

private static RemoveUserWsRequest toRemoveUserWsRequest(Request request) {
return new RemoveUserWsRequest()
.setPermission(request.mandatoryParam(PARAM_PERMISSION))
.setLogin(request.mandatoryParam(PARAM_USER_LOGIN))
.setProjectId(request.param(PARAM_PROJECT_ID))
.setProjectKey(request.param(PARAM_PROJECT_KEY));
}
}

+ 1
- 4
server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchGlobalPermissionsAction.java View File

@@ -64,12 +64,9 @@ public class SearchGlobalPermissionsAction implements PermissionsWsAction {
public void handle(Request wsRequest, Response wsResponse) throws Exception {
checkGlobalAdminUser(userSession);

DbSession dbSession = dbClient.openSession(false);
try {
try (DbSession dbSession = dbClient.openSession(false)) {
WsSearchGlobalPermissionsResponse response = buildResponse(dbSession);
writeProtobuf(response, wsRequest, wsResponse);
} finally {
dbClient.closeSession(dbSession);
}
}


+ 3
- 9
server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchProjectPermissionsAction.java View File

@@ -30,7 +30,6 @@ import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.utils.Paging;
import org.sonar.core.permission.ProjectPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.Common;
@@ -99,14 +98,9 @@ public class SearchProjectPermissionsAction implements PermissionsWsAction {

private SearchProjectPermissionsWsResponse doHandle(SearchProjectPermissionsWsRequest request) {
checkRequestAndPermissions(request);
DbSession dbSession = dbClient.openSession(false);
try {
validateQualifier(request.getQualifier(), resourceTypes);
SearchProjectPermissionsData data = dataLoader.load(request);
return buildResponse(data);
} finally {
dbClient.closeSession(dbSession);
}
validateQualifier(request.getQualifier(), resourceTypes);
SearchProjectPermissionsData data = dataLoader.load(request);
return buildResponse(data);
}

private static SearchProjectPermissionsWsRequest toSearchProjectPermissionsWsRequest(Request request) {

+ 2
- 3
server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchProjectPermissionsData.java View File

@@ -70,9 +70,8 @@ class SearchProjectPermissionsData {
return FluentIterable.from(
Iterables.concat(
userCountByProjectIdAndPermission.row(rootComponentId).keySet(),
groupCountByProjectIdAndPermission.row(rootComponentId).keySet()
)
).toSortedSet(Ordering.natural());
groupCountByProjectIdAndPermission.row(rootComponentId).keySet()))
.toSortedSet(Ordering.natural());
}

static class Builder {

+ 5
- 8
server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchProjectPermissionsDataLoader.java View File

@@ -43,18 +43,17 @@ import static org.sonar.server.permission.ws.WsProjectRef.newOptionalWsProjectRe

public class SearchProjectPermissionsDataLoader {
private final DbClient dbClient;
private final PermissionDependenciesFinder finder;
private final PermissionWsSupport wsSupport;
private final String[] rootQualifiers;

public SearchProjectPermissionsDataLoader(DbClient dbClient, PermissionDependenciesFinder finder, ResourceTypes resourceTypes) {
public SearchProjectPermissionsDataLoader(DbClient dbClient, PermissionWsSupport wsSupport, ResourceTypes resourceTypes) {
this.dbClient = dbClient;
this.finder = finder;
this.wsSupport = wsSupport;
this.rootQualifiers = Collections2.transform(resourceTypes.getRoots(), RESOURCE_TYPE_TO_QUALIFIER).toArray(new String[resourceTypes.getRoots().size()]);
}

SearchProjectPermissionsData load(SearchProjectPermissionsWsRequest request) {
DbSession dbSession = dbClient.openSession(false);
try {
try (DbSession dbSession = dbClient.openSession(false)) {
SearchProjectPermissionsData.Builder data = newBuilder();
int countRootComponents = countRootComponents(dbSession, request);
List<ComponentDto> rootComponents = searchRootComponents(dbSession, request, paging(request, countRootComponents));
@@ -66,8 +65,6 @@ public class SearchProjectPermissionsDataLoader {
.groupCountByProjectIdAndPermission(groupCountByRootComponentIdAndPermission(dbSession, rootComponentIds));

return data.build();
} finally {
dbClient.closeSession(dbSession);
}
}

@@ -85,7 +82,7 @@ public class SearchProjectPermissionsDataLoader {
Optional<WsProjectRef> project = newOptionalWsProjectRef(request.getProjectId(), request.getProjectKey());

if (project.isPresent()) {
return singletonList(finder.getRootComponentOrModule(dbSession, project.get()));
return singletonList(wsSupport.getRootComponentOrModule(dbSession, project.get()));
}

return dbClient.componentDao().selectByQuery(dbSession, toDbQuery(request), paging.offset(), paging.pageSize());

+ 49
- 64
server/sonar-server/src/main/java/org/sonar/server/permission/ws/UsersAction.java View File

@@ -19,11 +19,11 @@
*/
package org.sonar.server.permission.ws;

import com.google.common.base.Optional;
import com.google.common.collect.Multimap;
import com.google.common.collect.Ordering;
import com.google.common.collect.TreeMultimap;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
@@ -32,40 +32,37 @@ import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.utils.Paging;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.permission.ExtendedUserPermissionDto;
import org.sonar.db.permission.PermissionQuery;
import org.sonar.db.user.UserDto;
import org.sonar.server.permission.ProjectRef;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.WsPermissions;
import org.sonarqube.ws.WsPermissions.UsersWsResponse;
import org.sonarqube.ws.client.permission.UsersWsRequest;

import static java.util.Collections.emptyList;
import static org.sonar.db.permission.PermissionQuery.DEFAULT_PAGE_SIZE;
import static org.sonar.db.permission.PermissionQuery.RESULTS_MAX_SIZE;
import static org.sonar.db.permission.PermissionQuery.SEARCH_QUERY_MIN_LENGTH;
import static org.sonar.server.permission.PermissionPrivilegeChecker.checkProjectAdminUserByComponentDto;
import static org.sonar.server.permission.ws.PermissionRequestValidator.validatePermission;
import static org.sonar.server.permission.PermissionPrivilegeChecker.checkProjectAdminUserByComponentUuid;
import static org.sonar.server.permission.ws.PermissionRequestValidator.validateGlobalPermission;
import static org.sonar.server.permission.ws.PermissionRequestValidator.validateProjectPermission;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createPermissionParameter;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createProjectParameters;
import static org.sonar.server.permission.ws.WsProjectRef.newOptionalWsProjectRef;
import static org.sonar.server.ws.WsUtils.checkRequest;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_KEY;

public class UsersAction implements PermissionsWsAction {

private final DbClient dbClient;
private final UserSession userSession;
private final PermissionDependenciesFinder dependenciesFinder;
private final PermissionWsSupport support;

public UsersAction(DbClient dbClient, UserSession userSession, PermissionDependenciesFinder dependenciesFinder) {
public UsersAction(DbClient dbClient, UserSession userSession, PermissionWsSupport support) {
this.dbClient = dbClient;
this.userSession = userSession;
this.dependenciesFinder = dependenciesFinder;
this.support = support;
}

@Override
@@ -90,42 +87,46 @@ public class UsersAction implements PermissionsWsAction {
}

@Override
public void handle(Request wsRequest, Response wsResponse) throws Exception {
UsersWsResponse usersWsResponse = doHandle(toUsersWsRequest(wsRequest));
writeProtobuf(usersWsResponse, wsRequest, wsResponse);
}

private UsersWsResponse doHandle(UsersWsRequest request) {
Optional<WsProjectRef> wsProjectRef = newOptionalWsProjectRef(request.getProjectId(), request.getProjectKey());
validatePermission(request.getPermission(), wsProjectRef);
DbSession dbSession = dbClient.openSession(false);
try {
Optional<ComponentDto> project = dependenciesFinder.searchProject(dbSession, wsProjectRef);
checkProjectAdminUserByComponentDto(userSession, project);
PermissionQuery dbQuery = buildPermissionQuery(request, project);
List<UserDto> users = findUsers(dbSession, dbQuery);
int total = dbClient.userPermissionDao().countUsers(dbSession, dbQuery);
List<ExtendedUserPermissionDto> userPermissions = findUserPermissions(dbSession, users, project);
Paging paging = Paging.forPageIndex(request.getPage()).withPageSize(request.getPageSize()).andTotal(total);
return buildResponse(users, userPermissions, paging);
} finally {
dbClient.closeSession(dbSession);
public void handle(Request request, Response response) throws Exception {
try (DbSession dbSession = dbClient.openSession(false)) {
Optional<ProjectRef> projectId = support.findProject(dbSession, request);
checkProjectAdminUserByComponentUuid(userSession, projectId.isPresent() ? projectId.get().getUuid() : null);

PermissionQuery query = buildPermissionQuery(request, projectId);
List<UserDto> users = findUsers(dbSession, query);
int total = dbClient.userPermissionDao().countUsers(dbSession, query);
List<ExtendedUserPermissionDto> userPermissions = findUserPermissions(dbSession, users, projectId);
Paging paging = Paging.forPageIndex(request.mandatoryParamAsInt(Param.PAGE)).withPageSize(query.getPageSize()).andTotal(total);
UsersWsResponse usersWsResponse = buildResponse(users, userPermissions, paging);
writeProtobuf(usersWsResponse, request, response);
}
}

private static UsersWsRequest toUsersWsRequest(Request request) {
UsersWsRequest usersRequest = new UsersWsRequest()
.setPermission(request.param(PARAM_PERMISSION))
.setProjectId(request.param(PARAM_PROJECT_ID))
.setProjectKey(request.param(PARAM_PROJECT_KEY))
.setQuery(request.param(Param.TEXT_QUERY))
.setPage(request.mandatoryParamAsInt(Param.PAGE))
.setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE));

String searchQuery = usersRequest.getQuery();
checkRequest(searchQuery == null || searchQuery.length() >= SEARCH_QUERY_MIN_LENGTH,
"The '%s' parameter must have at least %d characters", Param.TEXT_QUERY, SEARCH_QUERY_MIN_LENGTH);
return usersRequest;
private static PermissionQuery buildPermissionQuery(Request request, Optional<ProjectRef> project) {
String textQuery = request.param(Param.TEXT_QUERY);
String permission = request.param(PARAM_PERMISSION);
PermissionQuery.Builder permissionQuery = PermissionQuery.builder()
.setPermission(permission)
.setPageIndex(request.mandatoryParamAsInt(Param.PAGE))
.setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE))
.setSearchQuery(textQuery);
if (project.isPresent()) {
permissionQuery.setComponentUuid(project.get().getUuid());
}
if (permission != null) {
if (project.isPresent()) {
validateProjectPermission(permission);
} else {
validateGlobalPermission(permission);
}
}
if (textQuery == null) {
permissionQuery.withAtLeastOnePermission();
} else {
checkRequest(textQuery.length() >= SEARCH_QUERY_MIN_LENGTH,
"The '%s' parameter must have at least %d characters", Param.TEXT_QUERY, SEARCH_QUERY_MIN_LENGTH);
}
return permissionQuery.build();
}

private static UsersWsResponse buildResponse(List<UserDto> users, List<ExtendedUserPermissionDto> userPermissions, Paging paging) {
@@ -155,34 +156,18 @@ public class UsersAction implements PermissionsWsAction {
return response.build();
}

private static PermissionQuery buildPermissionQuery(UsersWsRequest request, Optional<ComponentDto> project) {
PermissionQuery.Builder dbQuery = PermissionQuery.builder()
.setPermission(request.getPermission())
.setPageIndex(request.getPage())
.setPageSize(request.getPageSize())
.setSearchQuery(request.getQuery());
if (project.isPresent()) {
dbQuery.setComponentUuid(project.get().uuid());
}
if (request.getQuery() == null) {
dbQuery.withAtLeastOnePermission();
}

return dbQuery.build();
}

private List<UserDto> findUsers(DbSession dbSession, PermissionQuery dbQuery) {
List<String> orderedLogins = dbClient.userPermissionDao().selectLogins(dbSession, dbQuery);
private List<UserDto> findUsers(DbSession dbSession, PermissionQuery query) {
List<String> orderedLogins = dbClient.userPermissionDao().selectLogins(dbSession, query);
return Ordering.explicit(orderedLogins).onResultOf(UserDto::getLogin).immutableSortedCopy(dbClient.userDao().selectByLogins(dbSession, orderedLogins));
}

private List<ExtendedUserPermissionDto> findUserPermissions(DbSession dbSession, List<UserDto> users, Optional<ComponentDto> project) {
private List<ExtendedUserPermissionDto> findUserPermissions(DbSession dbSession, List<UserDto> users, Optional<ProjectRef> project) {
if (users.isEmpty()) {
return emptyList();
}
List<String> logins = users.stream().map(UserDto::getLogin).collect(Collectors.toList());
PermissionQuery query = PermissionQuery.builder()
.setComponentUuid(project.isPresent() ? project.get().uuid() : null)
.setComponentUuid(project.isPresent() ? project.get().getUuid() : null)
.withAtLeastOnePermission()
.build();
return dbClient.userPermissionDao().select(dbSession, query, logins);

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/permission/ws/WsProjectRef.java View File

@@ -29,7 +29,7 @@ import static org.sonar.server.ws.WsUtils.checkRequest;
* Project identifiers from a WS request. Guaranties the project id and project key are not provided at the same time.
*/
public class WsProjectRef {
private static final String MSG_ID_OR_KEY_MUST_BE_PROVIDED = "Project id or project key must be provided, not both.";
private static final String MSG_ID_OR_KEY_MUST_BE_PROVIDED = "Project id or project key can be provided, not both.";
private final String uuid;
private final String key;


+ 0
- 6
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java View File

@@ -33,7 +33,6 @@ import org.sonar.ce.CeModule;
import org.sonar.ce.settings.ProjectSettingsFactory;
import org.sonar.core.component.DefaultResourceTypes;
import org.sonar.core.timemachine.Periods;
import org.sonar.db.permission.PermissionRepository;
import org.sonar.server.authentication.AuthenticationModule;
import org.sonar.server.batch.BatchWsModule;
import org.sonar.server.ce.ws.CeWsModule;
@@ -136,8 +135,6 @@ import org.sonar.server.notification.NotificationService;
import org.sonar.server.notification.email.AlertsEmailTemplate;
import org.sonar.server.notification.email.EmailNotificationChannel;
import org.sonar.server.organization.ws.OrganizationsWsModule;
import org.sonar.server.permission.PermissionService;
import org.sonar.server.permission.PermissionUpdater;
import org.sonar.server.permission.ws.PermissionsWsModule;
import org.sonar.server.platform.BackendCleanup;
import org.sonar.server.platform.PersistentSettings;
@@ -428,9 +425,6 @@ public class PlatformLevel4 extends PlatformLevel {
UserGroupsModule.class,

// permissions
PermissionRepository.class,
PermissionService.class,
PermissionUpdater.class,
PermissionsWsModule.class,

// components

+ 46
- 32
server/sonar-server/src/main/java/org/sonar/server/startup/RegisterPermissionTemplates.java View File

@@ -19,6 +19,9 @@
*/
package org.sonar.server.startup;

import java.util.Date;
import java.util.Optional;
import javax.annotation.Nullable;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.security.DefaultGroups;
import org.sonar.api.utils.log.Logger;
@@ -30,9 +33,11 @@ import org.sonar.db.DbSession;
import org.sonar.db.loadedtemplate.LoadedTemplateDto;
import org.sonar.db.permission.template.PermissionTemplateDto;
import org.sonar.db.user.GroupDto;
import org.sonar.server.permission.DefaultPermissionTemplates;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.platform.PersistentSettings;

import static org.sonar.db.loadedtemplate.LoadedTemplateDto.PERMISSION_TEMPLATE_TYPE;
import static org.sonar.server.permission.DefaultPermissionTemplates.DEFAULT_TEMPLATE_KEY;
import static org.sonar.server.permission.DefaultPermissionTemplates.DEFAULT_TEMPLATE_PROPERTY;
import static org.sonar.server.permission.DefaultPermissionTemplates.defaultRootQualifierTemplateProperty;

@@ -42,10 +47,12 @@ public class RegisterPermissionTemplates {

private final DbClient dbClient;
private final PersistentSettings settings;
private final DefaultOrganizationProvider defaultOrganizationProvider;

public RegisterPermissionTemplates(DbClient dbClient, PersistentSettings settings) {
public RegisterPermissionTemplates(DbClient dbClient, PersistentSettings settings, DefaultOrganizationProvider defaultOrganizationProvider) {
this.dbClient = dbClient;
this.settings = settings;
this.defaultOrganizationProvider = defaultOrganizationProvider;
}

public void start() {
@@ -57,8 +64,8 @@ public class RegisterPermissionTemplates {
String defaultProjectPermissionTemplateUuid = settings.getString(defaultRootQualifierTemplateProperty(Qualifiers.PROJECT));
setDefaultProperty(defaultProjectPermissionTemplateUuid);
} else if (shouldRegister) {
insertDefaultTemplate();
setDefaultProperty(DefaultPermissionTemplates.DEFAULT_TEMPLATE.getUuid());
PermissionTemplateDto template = insertDefaultTemplate();
setDefaultProperty(template.getUuid());
}

if (shouldRegister) {
@@ -73,43 +80,50 @@ public class RegisterPermissionTemplates {
}

private boolean shouldRegister() {
return dbClient.loadedTemplateDao().countByTypeAndKey(LoadedTemplateDto.PERMISSION_TEMPLATE_TYPE, DefaultPermissionTemplates.DEFAULT_TEMPLATE.getUuid()) == 0;
return dbClient.loadedTemplateDao().countByTypeAndKey(PERMISSION_TEMPLATE_TYPE, DEFAULT_TEMPLATE_KEY) == 0;
}

private void insertDefaultTemplate() {
DbSession dbSession = dbClient.openSession(false);
try {
PermissionTemplateDto defaultPermissionTemplate = dbClient.permissionTemplateDao().insert(dbSession, DefaultPermissionTemplates.DEFAULT_TEMPLATE);
addGroupPermission(defaultPermissionTemplate, UserRole.ADMIN, DefaultGroups.ADMINISTRATORS);
addGroupPermission(defaultPermissionTemplate, UserRole.ISSUE_ADMIN, DefaultGroups.ADMINISTRATORS);
addGroupPermission(defaultPermissionTemplate, UserRole.USER, DefaultGroups.ANYONE);
addGroupPermission(defaultPermissionTemplate, UserRole.CODEVIEWER, DefaultGroups.ANYONE);
} finally {
dbClient.closeSession(dbSession);
private PermissionTemplateDto insertDefaultTemplate() {
try (DbSession dbSession = dbClient.openSession(false)) {
String orgUuid = defaultOrganizationProvider.get().getUuid();

PermissionTemplateDto template = new PermissionTemplateDto()
.setOrganizationUuid(orgUuid)
.setName("Default template")
.setUuid(DEFAULT_TEMPLATE_KEY)
.setDescription("This permission template will be used as default when no other permission configuration is available")
.setCreatedAt(new Date())
.setUpdatedAt(new Date());

dbClient.permissionTemplateDao().insert(dbSession, template);
insertDefaultGroupPermissions(dbSession, template);
dbSession.commit();
return template;
}
}

private void addGroupPermission(PermissionTemplateDto template, String permission, String groupName) {
DbSession dbSession = dbClient.openSession(false);
try {
Long groupId = null;
if (!DefaultGroups.isAnyone(groupName)) {
GroupDto groupDto = dbClient.groupDao().selectByName(dbSession, groupName);
if (groupDto != null) {
groupId = groupDto.getId();
} else {
LOG.error("Cannot setup default permission for group: " + groupName);
}
}
dbClient.permissionTemplateDao().insertGroupPermission(dbSession, template.getId(), groupId, permission);
} finally {
dbClient.closeSession(dbSession);
private void insertDefaultGroupPermissions(DbSession dbSession, PermissionTemplateDto template) {
Optional<GroupDto> admins = dbClient.groupDao().selectByName(dbSession, template.getOrganizationUuid(), DefaultGroups.ADMINISTRATORS);
if (admins.isPresent()) {
insertGroupPermission(dbSession, template, UserRole.ADMIN, admins.get());
insertGroupPermission(dbSession, template, UserRole.ISSUE_ADMIN, admins.get());
} else {
LOG.error("Cannot setup default permission for group: " + DefaultGroups.ADMINISTRATORS);
}
insertGroupPermission(dbSession, template, UserRole.USER, null);
insertGroupPermission(dbSession, template, UserRole.CODEVIEWER, null);
}

private void insertGroupPermission(DbSession dbSession, PermissionTemplateDto template, String permission, @Nullable GroupDto group) {
if (group == null) {
dbClient.permissionTemplateDao().insertGroupPermission(dbSession, template.getId(), null, permission);
} else {
dbClient.permissionTemplateDao().insertGroupPermission(dbSession, template.getId(), group.getId(), permission);
}
}

private void registerInitialization() {
LoadedTemplateDto loadedTemplate = new LoadedTemplateDto(DefaultPermissionTemplates.DEFAULT_TEMPLATE.getUuid(),
LoadedTemplateDto.PERMISSION_TEMPLATE_TYPE);
LoadedTemplateDto loadedTemplate = new LoadedTemplateDto(DEFAULT_TEMPLATE_KEY, PERMISSION_TEMPLATE_TYPE);
dbClient.loadedTemplateDao().insert(loadedTemplate);
}


+ 1
- 4
server/sonar-server/src/main/resources/org/sonar/server/permission/ws/template/create_template-example.json View File

@@ -1,10 +1,7 @@
{
"permissionTemplate": {
"id": "af8cb8cc-1e78-4c4e-8c00-ee8e814009a5",
"name": "Finance",
"description": "Permissions for financially related projects",
"projectKeyPattern": ".*\\.finance\\..*",
"createdAt": "2015-08-25T16:18:48+0200",
"updatedAt": "2015-08-25T16:18:48+0200"
"projectKeyPattern": ".*\\.finance\\..*"
}
}

server/sonar-server/src/main/resources/org/sonar/server/permission/ws/template_groups-example.json → server/sonar-server/src/main/resources/org/sonar/server/permission/ws/template/template_groups-example.json View File


server/sonar-server/src/main/resources/org/sonar/server/permission/ws/template_users-example.json → server/sonar-server/src/main/resources/org/sonar/server/permission/ws/template/template_users-example.json View File


+ 218
- 0
server/sonar-server/src/test/java/org/sonar/server/permission/GroupPermissionChangerTest.java View File

@@ -0,0 +1,218 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.permission;

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.api.web.UserRole;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.organization.OrganizationTesting;
import org.sonar.db.user.GroupDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.usergroups.ws.GroupIdOrAnyone;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;

public class GroupPermissionChangerTest {

@Rule
public DbTester db = DbTester.create(System2.INSTANCE);

@Rule
public ExpectedException expectedException = ExpectedException.none();

private UserSessionRule userSession = UserSessionRule.standalone();
private GroupPermissionChanger underTest = new GroupPermissionChanger(db.getDbClient(), userSession);
private OrganizationDto org;
private GroupDto group;
private ComponentDto project;

@Before
public void setUp() throws Exception {
org = OrganizationTesting.insert(db, OrganizationTesting.newOrganizationDto());
group = db.users().insertGroup(org, "a-group");
project = new ComponentDbTester(db).insertComponent(ComponentTesting.newProjectDto());
}

@Test
public void add_permission_to_group() {
GroupIdOrAnyone groupId = new GroupIdOrAnyone(group);

loginAsAdmin();
apply(new GroupPermissionChange(PermissionChange.Operation.ADD, GlobalPermissions.QUALITY_GATE_ADMIN, null, groupId));

assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(GlobalPermissions.QUALITY_GATE_ADMIN);
}

@Test
public void add_project_permission_to_group() {
GroupIdOrAnyone groupId = new GroupIdOrAnyone(group);

loginAsAdmin();
apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.ISSUE_ADMIN, new ProjectRef(project), groupId));

assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
assertThat(db.users().selectGroupPermissions(group, project)).containsOnly(UserRole.ISSUE_ADMIN);
}

@Test
public void add_permission_to_anyone() {
GroupIdOrAnyone groupId = new GroupIdOrAnyone(db.getDefaultOrganization().getUuid(), null);

loginAsAdmin();
apply(new GroupPermissionChange(PermissionChange.Operation.ADD, GlobalPermissions.QUALITY_GATE_ADMIN, null, groupId));

assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
assertThat(db.users().selectAnyonePermissions(null)).containsOnly(GlobalPermissions.QUALITY_GATE_ADMIN);
}

@Test
public void add_project_permission_to_anyone() {
GroupIdOrAnyone groupId = new GroupIdOrAnyone(db.getDefaultOrganization().getUuid(), null);

loginAsAdmin();
apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.ISSUE_ADMIN, new ProjectRef(project), groupId));

assertThat(db.users().selectAnyonePermissions(null)).isEmpty();
assertThat(db.users().selectAnyonePermissions(project)).containsOnly(UserRole.ISSUE_ADMIN);
}

@Test
public void fail_to_add_permission_if_not_admin() {
GroupIdOrAnyone groupId = new GroupIdOrAnyone(db.getDefaultOrganization().getUuid(), null);

expectedException.expect(ForbiddenException.class);

userSession.login("a_guy");
underTest.apply(db.getSession(), new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.ISSUE_ADMIN, new ProjectRef(project), groupId));
}

@Test
public void do_nothing_when_adding_permission_that_already_exists() {
GroupIdOrAnyone groupId = new GroupIdOrAnyone(group);
db.users().insertPermissionOnGroup(group, GlobalPermissions.QUALITY_GATE_ADMIN);

loginAsAdmin();
apply(new GroupPermissionChange(PermissionChange.Operation.ADD, GlobalPermissions.QUALITY_GATE_ADMIN, null, groupId));

assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(GlobalPermissions.QUALITY_GATE_ADMIN);
}

@Test
public void fail_to_add_global_permission_on_project() {
GroupIdOrAnyone groupId = new GroupIdOrAnyone(group);

expectedException.expect(BadRequestException.class);
expectedException.expectMessage("Invalid project permission 'gateadmin'. Valid values are [admin, codeviewer, issueadmin, scan, user]");

loginAsAdmin();
apply(new GroupPermissionChange(PermissionChange.Operation.ADD, GlobalPermissions.QUALITY_GATE_ADMIN, new ProjectRef(project), groupId));
}

@Test
public void fail_to_add_project_permission_on_global_group() {
GroupIdOrAnyone groupId = new GroupIdOrAnyone(group);

expectedException.expect(BadRequestException.class);
expectedException.expectMessage("Invalid global permission 'issueadmin'. Valid values are [admin, profileadmin, gateadmin, scan, provisioning]");

loginAsAdmin();
apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.ISSUE_ADMIN, null, groupId));
}

@Test
public void remove_permission_from_group() {
GroupIdOrAnyone groupId = new GroupIdOrAnyone(group);
db.users().insertPermissionOnGroup(group, GlobalPermissions.QUALITY_GATE_ADMIN);
db.users().insertPermissionOnGroup(group, GlobalPermissions.PROVISIONING);

loginAsAdmin();
apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, GlobalPermissions.QUALITY_GATE_ADMIN, null, groupId));

assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(GlobalPermissions.PROVISIONING);
}

@Test
public void remove_project_permission_from_group() {
GroupIdOrAnyone groupId = new GroupIdOrAnyone(group);
db.users().insertPermissionOnGroup(group, GlobalPermissions.QUALITY_GATE_ADMIN);
db.users().insertProjectPermissionOnGroup(group, UserRole.ISSUE_ADMIN, project);
db.users().insertProjectPermissionOnGroup(group, UserRole.CODEVIEWER, project);

loginAsAdmin();
apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.ISSUE_ADMIN, new ProjectRef(project), groupId));

assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(GlobalPermissions.QUALITY_GATE_ADMIN);
assertThat(db.users().selectGroupPermissions(group, project)).containsOnly(UserRole.CODEVIEWER);
}

@Test
public void do_not_fail_if_removing_a_permission_that_does_not_exist() {
GroupIdOrAnyone groupId = new GroupIdOrAnyone(group);

loginAsAdmin();
apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.ISSUE_ADMIN, new ProjectRef(project), groupId));

assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
assertThat(db.users().selectGroupPermissions(group, project)).isEmpty();
}

@Test
public void fail_to_remove_permission_if_not_admin() {
GroupIdOrAnyone groupId = new GroupIdOrAnyone(db.getDefaultOrganization().getUuid(), null);

expectedException.expect(ForbiddenException.class);

userSession.login("a_guy");
underTest.apply(db.getSession(), new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.ISSUE_ADMIN, new ProjectRef(project), groupId));
}

@Test
public void fail_to_remove_sysadmin_permission_if_no_more_sysadmins() {
GroupIdOrAnyone groupId = new GroupIdOrAnyone(group);
db.users().insertPermissionOnGroup(group, GlobalPermissions.SYSTEM_ADMIN);

expectedException.expect(BadRequestException.class);
expectedException.expectMessage("Last group with 'admin' permission. Permission cannot be removed.");

loginAsAdmin();
underTest.apply(db.getSession(), new GroupPermissionChange(PermissionChange.Operation.REMOVE, GlobalPermissions.SYSTEM_ADMIN, null, groupId));
}

private void apply(GroupPermissionChange change) {
underTest.apply(db.getSession(), change);
db.commit();
}

private void loginAsAdmin() {
userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN);
}
}

+ 0
- 137
server/sonar-server/src/test/java/org/sonar/server/permission/PermissionChangeTest.java View File

@@ -1,137 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.permission;

import com.google.common.collect.Maps;
import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.server.exceptions.BadRequestException;

import static org.assertj.core.api.Assertions.assertThat;

public class PermissionChangeTest {

@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void populate_from_params() {
Map<String, Object> params = Maps.newHashMap();
params.put("user", "my_login");
params.put("group", "my_group");
params.put("component", "org.sample.Sample");
params.put("permission", GlobalPermissions.SYSTEM_ADMIN);

PermissionChange query = PermissionChange.buildFromParams(params);

assertThat(query.userLogin()).isEqualTo("my_login");
assertThat(query.groupName()).isEqualTo("my_group");
assertThat(query.componentKey()).isEqualTo("org.sample.Sample");
assertThat(query.permission()).isEqualTo(GlobalPermissions.SYSTEM_ADMIN);
}

@Test
public void validate_user_query() {
Map<String, Object> validUserParams = Maps.newHashMap();
validUserParams.put("user", "my_login");
validUserParams.put("permission", GlobalPermissions.SYSTEM_ADMIN);

PermissionChange query = PermissionChange.buildFromParams(validUserParams);
query.validate();
}

@Test
public void validate_group_query() {
Map<String, Object> validGroupParams = Maps.newHashMap();
validGroupParams.put("group", "my_group");
validGroupParams.put("permission", GlobalPermissions.SYSTEM_ADMIN);

PermissionChange query = PermissionChange.buildFromParams(validGroupParams);
query.validate();
}

@Test
public void reject_inconsistent_query() {
Map<String, Object> inconsistentParams = Maps.newHashMap();
inconsistentParams.put("user", "my_login");
inconsistentParams.put("group", "my_group");
inconsistentParams.put("permission", GlobalPermissions.SYSTEM_ADMIN);

PermissionChange query = PermissionChange.buildFromParams(inconsistentParams);

thrown.expect(BadRequestException.class);
thrown.expectMessage("Only one of user or group parameter should be provided");
query.validate();
}

@Test
public void detect_missing_user_or_group() {
Map<String, Object> inconsistentParams = Maps.newHashMap();
inconsistentParams.put("permission", "admin");

PermissionChange query = PermissionChange.buildFromParams(inconsistentParams);

thrown.expect(BadRequestException.class);
thrown.expectMessage("Missing user or group parameter");
query.validate();
}

@Test
public void detect_missing_permission() {
Map<String, Object> inconsistentParams = Maps.newHashMap();
inconsistentParams.put("user", "my_login");

PermissionChange query = PermissionChange.buildFromParams(inconsistentParams);

thrown.expect(BadRequestException.class);
thrown.expectMessage("Missing permission parameter");
query.validate();
}

@Test
public void validate_global_permission_reference() {
Map<String, Object> inconsistentParams = Maps.newHashMap();
inconsistentParams.put("user", "my_login");
inconsistentParams.put("permission", "invalid");

PermissionChange query = PermissionChange.buildFromParams(inconsistentParams);

thrown.expect(BadRequestException.class);
thrown.expectMessage("Invalid global permission key invalid. Valid values are [admin, profileadmin, gateadmin, scan, provisioning]");
query.validate();
}

@Test
public void validate_component_permission_reference() {
Map<String, Object> inconsistentParams = Maps.newHashMap();
inconsistentParams.put("user", "my_login");
inconsistentParams.put("component", "org.sample.Sample");
inconsistentParams.put("permission", "invalid");

PermissionChange query = PermissionChange.buildFromParams(inconsistentParams);

thrown.expect(BadRequestException.class);
thrown.expectMessage("Invalid component permission key invalid. Valid values are [admin, codeviewer, issueadmin, scan, user]");
query.validate();
}
}

+ 88
- 121
server/sonar-server/src/test/java/org/sonar/server/permission/ws/AddGroupActionTest.java View File

@@ -19,33 +19,18 @@
*/
package org.sonar.server.permission.ws;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.ArgumentCaptor;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.utils.System2;
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.component.ResourceTypesRule;
import org.sonar.db.user.GroupDto;
import org.sonar.server.component.ComponentFinder;
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.permission.PermissionChange;
import org.sonar.server.permission.PermissionUpdater;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.usergroups.ws.UserGroupFinder;
import org.sonar.server.ws.WsTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
import static org.sonar.db.component.ComponentTesting.newProjectDto;
import static org.sonar.db.component.ComponentTesting.newView;
@@ -57,170 +42,139 @@ import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_P
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_KEY;

public class AddGroupActionTest extends BasePermissionWsTest<AddGroupAction> {

public class AddGroupActionTest {
UserSessionRule userSession = UserSessionRule.standalone();
WsTester ws;
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
@Rule
public ExpectedException expectedException = ExpectedException.none();
ResourceTypesRule resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT, Qualifiers.VIEW, "DEV");
private PermissionUpdater permissionUpdater;
private DbClient dbClient;
private ArgumentCaptor<PermissionChange> permissionChangeCaptor;

@Before
public void setUp() {
permissionUpdater = mock(PermissionUpdater.class);
permissionChangeCaptor = ArgumentCaptor.forClass(PermissionChange.class);
dbClient = db.getDbClient();
ComponentFinder componentFinder = new ComponentFinder(dbClient);
ws = new WsTester(new PermissionsWs(
new AddGroupAction(dbClient, new PermissionChangeBuilder(new PermissionDependenciesFinder(
dbClient,
componentFinder,
new UserGroupFinder(dbClient),
resourceTypes)),
permissionUpdater)));
userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN);
private static final String A_PROJECT_UUID = "project-uuid";
private static final String A_PROJECT_KEY = "project-key";

@Override
protected AddGroupAction buildWsAction() {
return new AddGroupAction(db.getDbClient(), newPermissionUpdater(), newPermissionWsSupport());
}

@Test
public void call_permission_service_with_right_data() throws Exception {
insertGroup("sonar-administrators");
commit();
public void add_permission_to_group_referenced_by_its_name() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "sonar-administrators");

loginAsAdmin();
newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();

verify(permissionUpdater).addPermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.groupName()).isEqualTo("sonar-administrators");
assertThat(permissionChange.permission()).isEqualTo(SYSTEM_ADMIN);
assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(SYSTEM_ADMIN);
}

@Test
public void add_with_group_id() throws Exception {
GroupDto group = insertGroup("sonar-administrators");
commit();
public void add_permission_to_group_referenced_by_its_id() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "sonar-administrators");

loginAsAdmin();
newRequest()
.setParam(PARAM_GROUP_ID, group.getId().toString())
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();

verify(permissionUpdater).addPermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.groupName()).isEqualTo("sonar-administrators");
assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(SYSTEM_ADMIN);
}

@Test
public void add_with_project_uuid() throws Exception {
insertGroup("sonar-administrators");
insertComponent(newProjectDto("project-uuid").setKey("project-key"));
commit();
public void add_permission_to_project_referenced_by_its_id() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "sonar-administrators");
ComponentDto project = db.components().insertComponent(newProjectDto(A_PROJECT_UUID).setKey(A_PROJECT_KEY));

loginAsAdmin();
newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_PROJECT_ID, "project-uuid")
.setParam(PARAM_GROUP_NAME, group.getName())
.setParam(PARAM_PROJECT_ID, A_PROJECT_UUID)
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();

verify(permissionUpdater).addPermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.componentKey()).isEqualTo("project-key");
assertThat(permissionChange.groupName()).isEqualTo("sonar-administrators");
assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
assertThat(db.users().selectGroupPermissions(group, project)).containsOnly(SYSTEM_ADMIN);
}

@Test
public void add_with_project_key() throws Exception {
insertGroup("sonar-administrators");
insertComponent(newProjectDto("project-uuid").setKey("project-key"));
commit();
public void add_permission_to_project_referenced_by_its_key() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "sonar-administrators");
ComponentDto project = db.components().insertComponent(newProjectDto(A_PROJECT_UUID).setKey(A_PROJECT_KEY));

loginAsAdmin();
newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_PROJECT_KEY, "project-key")
.setParam(PARAM_GROUP_NAME, group.getName())
.setParam(PARAM_PROJECT_KEY, A_PROJECT_KEY)
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();

verify(permissionUpdater).addPermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.componentKey()).isEqualTo("project-key");
assertThat(permissionChange.groupName()).isEqualTo("sonar-administrators");
assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
assertThat(db.users().selectGroupPermissions(group, project)).containsOnly(SYSTEM_ADMIN);
}

@Test
public void add_with_view_uuid() throws Exception {
insertGroup("sonar-administrators");
insertComponent(newView("view-uuid").setKey("view-key"));
commit();
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "sonar-administrators");
ComponentDto view = db.components().insertComponent(newView("view-uuid").setKey("view-key"));

loginAsAdmin();
newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_PROJECT_ID, "view-uuid")
.setParam(PARAM_GROUP_NAME, group.getName())
.setParam(PARAM_PROJECT_ID, view.uuid())
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();

verify(permissionUpdater).addPermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.componentKey()).isEqualTo("view-key");
assertThat(permissionChange.groupName()).isEqualTo("sonar-administrators");
assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
assertThat(db.users().selectGroupPermissions(group, view)).containsOnly(SYSTEM_ADMIN);
}

@Test
public void fail_if_project_uuid_not_found() throws Exception {
expectedException.expect(NotFoundException.class);

insertGroup("sonar-administrators");
insertComponent(newProjectDto("project-uuid").setKey("project-key"));
commit();
public void fail_if_project_uuid_is_not_found() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "sonar-administrators");
loginAsAdmin();

expectedException.expect(NotFoundException.class);
newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_PROJECT_ID, "unknown-project-uuid")
.setParam(PARAM_GROUP_NAME, group.getName())
.setParam(PARAM_PROJECT_ID, "not-found")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();
}

@Test
public void fail_if_project_permission_without_project() throws Exception {
expectedException.expect(BadRequestException.class);
public void adding_a_project_permission_fails_if_project_is_not_set() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "sonar-administrators");
loginAsAdmin();

insertGroup("sonar-administrators");
commit();
expectedException.expect(BadRequestException.class);

newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_GROUP_NAME, group.getName())
.setParam(PARAM_PERMISSION, UserRole.ISSUE_ADMIN)
.execute();
}

@Test
public void fail_if_component_uuid_is_not_a_project() throws Exception {
expectedException.expect(BadRequestException.class);
public void adding_a_project_permission_fails_if_component_is_not_a_project() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "sonar-administrators");
ComponentDto project = db.components().insertComponent(newProjectDto(A_PROJECT_UUID).setKey(A_PROJECT_KEY));
ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project, null, "file-uuid"));
loginAsAdmin();

insertGroup("sonar-administrators");
ComponentDto project = newProjectDto("project-uuid").setKey("project-key");
insertComponent(project);
insertComponent(ComponentTesting.newFileDto(project, null, "file-uuid"));
commit();
expectedException.expect(BadRequestException.class);

newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_PROJECT_ID, "file-uuid")
.setParam(PARAM_GROUP_NAME, group.getName())
.setParam(PARAM_PROJECT_ID, file.uuid())
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();
}

@Test
public void fail_when_get_request() throws Exception {
loginAsAdmin();

expectedException.expect(ServerException.class);

ws.newGetRequest(CONTROLLER, ACTION)
wsTester.newGetRequest(CONTROLLER, ACTION)
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();
@@ -228,8 +182,10 @@ public class AddGroupActionTest {

@Test
public void fail_when_group_name_and_group_id_are_missing() throws Exception {
loginAsAdmin();

expectedException.expect(BadRequestException.class);
expectedException.expectMessage("Group name or group id must be provided, not both");
expectedException.expectMessage("Group name or group id must be provided");

newRequest()
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
@@ -238,41 +194,52 @@ public class AddGroupActionTest {

@Test
public void fail_when_permission_is_missing() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "sonar-administrators");
loginAsAdmin();

expectedException.expect(IllegalArgumentException.class);

newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_GROUP_NAME, group.getName())
.execute();
}

@Test
public void fail_when_project_uuid_and_project_key_are_provided() throws Exception {
db.users().insertGroup(defaultOrganizationProvider.getDto(), "sonar-administrators");
db.components().insertComponent(newProjectDto(A_PROJECT_UUID).setKey(A_PROJECT_KEY));
loginAsAdmin();

expectedException.expect(BadRequestException.class);
expectedException.expectMessage("Project id or project key can be provided, not both.");
insertComponent(newProjectDto("project-uuid").setKey("project-key"));
commit();

newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.setParam(PARAM_PROJECT_ID, "project-uuid")
.setParam(PARAM_PROJECT_KEY, "project-key")
.setParam(PARAM_PROJECT_KEY, A_PROJECT_KEY)
.execute();
}

private WsTester.TestRequest newRequest() {
return ws.newPostRequest(CONTROLLER, ACTION);
}
@Test(expected = ForbiddenException.class)
public void require_admin_permission() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "sonar-administrators");
ComponentDto project = db.components().insertComponent(newProjectDto(A_PROJECT_UUID).setKey(A_PROJECT_KEY));
userSession.login("not-admin");

private void commit() {
db.getSession().commit();
newRequest()
.setParam(PARAM_GROUP_NAME, group.getName())
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.setParam(PARAM_PROJECT_ID, project.uuid())
.execute();
}

private void insertComponent(ComponentDto component) {
dbClient.componentDao().insert(db.getSession(), component);
private WsTester.TestRequest newRequest() {
return wsTester.newPostRequest(CONTROLLER, ACTION);
}

private GroupDto insertGroup(String name) {
return dbClient.groupDao().insert(db.getSession(), new GroupDto().setName(name));
private void loginAsAdmin() {
userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN);
}

}

+ 70
- 94
server/sonar-server/src/test/java/org/sonar/server/permission/ws/AddUserActionTest.java View File

@@ -20,31 +20,15 @@
package org.sonar.server.permission.ws;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.ArgumentCaptor;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
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.component.ResourceTypesRule;
import org.sonar.server.component.ComponentFinder;
import org.sonar.db.user.UserDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.ServerException;
import org.sonar.server.permission.PermissionChange;
import org.sonar.server.permission.PermissionUpdater;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.usergroups.ws.UserGroupFinder;
import org.sonar.server.ws.WsTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
import static org.sonar.db.component.ComponentTesting.newFileDto;
import static org.sonar.db.component.ComponentTesting.newProjectDto;
@@ -56,101 +40,87 @@ import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_P
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_KEY;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_USER_LOGIN;

public class AddUserActionTest extends BasePermissionWsTest<AddUserAction> {

public class AddUserActionTest {
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
@Rule
public ExpectedException expectedException = ExpectedException.none();
ResourceTypesRule resourceTypes = new ResourceTypesRule()
.setRootQualifiers(Qualifiers.PROJECT, Qualifiers.VIEW, "DEV");
private static final String A_PROJECT_UUID = "project-uuid";
private static final String A_PROJECT_KEY = "project-key";

UserSessionRule userSession = UserSessionRule.standalone();
WsTester ws;
PermissionUpdater permissionUpdater;
DbClient dbClient;
DbSession dbSession;
ArgumentCaptor<PermissionChange> permissionChangeCaptor = ArgumentCaptor.forClass(PermissionChange.class);
private UserDto user;

@Before
public void setUp() {
permissionUpdater = mock(PermissionUpdater.class);
dbClient = db.getDbClient();
dbSession = db.getSession();
ComponentFinder componentFinder = new ComponentFinder(dbClient);
ws = new WsTester(new PermissionsWs(
new AddUserAction(dbClient, permissionUpdater, new PermissionChangeBuilder(new PermissionDependenciesFinder(dbClient, componentFinder, new UserGroupFinder(dbClient),
resourceTypes)))));
userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN);
user = db.users().insertUser("ray.bradbury");
}

@Override
protected AddUserAction buildWsAction() {
return new AddUserAction(db.getDbClient(), newPermissionUpdater(), newPermissionWsSupport());
}

@Test
public void call_permission_service_with_right_data() throws Exception {
ws.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "ray.bradbury")
public void add_permission_to_user() throws Exception {
loginAsAdmin();
wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, user.getLogin())
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();

verify(permissionUpdater).addPermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.userLogin()).isEqualTo("ray.bradbury");
assertThat(permissionChange.permission()).isEqualTo(SYSTEM_ADMIN);
assertThat(db.users().selectUserPermissions(user, null)).containsOnly(SYSTEM_ADMIN);
}

@Test
public void add_user_permission_with_project_uuid() throws Exception {
dbClient.componentDao().insert(dbSession, newProjectDto("project-uuid").setKey("project-key"));
commit();
public void add_permission_to_project_referenced_by_its_id() throws Exception {
ComponentDto project = db.components().insertComponent(newProjectDto("project-uuid").setKey("project-key"));

ws.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "ray.bradbury")
.setParam(PARAM_PROJECT_ID, "project-uuid")
loginAsAdmin();
wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, user.getLogin())
.setParam(PARAM_PROJECT_ID, project.uuid())
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();

verify(permissionUpdater).addPermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.componentKey()).isEqualTo("project-key");
assertThat(db.users().selectUserPermissions(user, null)).isEmpty();
assertThat(db.users().selectUserPermissions(user, project)).containsOnly(SYSTEM_ADMIN);
}

@Test
public void add_user_permissions_with_project_key() throws Exception {
dbClient.componentDao().insert(dbSession, newProjectDto("project-uuid").setKey("project-key"));
commit();
public void add_permission_to_project_referenced_by_its_key() throws Exception {
ComponentDto project = db.components().insertComponent(newProjectDto("project-uuid").setKey("project-key"));

ws.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "ray.bradbury")
.setParam(PARAM_PROJECT_KEY, "project-key")
loginAsAdmin();
wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, user.getLogin())
.setParam(PARAM_PROJECT_KEY, project.getKey())
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();

verify(permissionUpdater).addPermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.componentKey()).isEqualTo("project-key");
assertThat(db.users().selectUserPermissions(user, null)).isEmpty();
assertThat(db.users().selectUserPermissions(user, project)).containsOnly(SYSTEM_ADMIN);
}

@Test
public void add_user_permission_with_view_uuid() throws Exception {
dbClient.componentDao().insert(dbSession, newView("view-uuid").setKey("view-key"));
commit();
public void add_permission_to_view() throws Exception {
ComponentDto view = db.components().insertComponent(newView("view-uuid").setKey("view-key"));

ws.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "ray.bradbury")
.setParam(PARAM_PROJECT_ID, "view-uuid")
loginAsAdmin();
wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, user.getLogin())
.setParam(PARAM_PROJECT_ID, view.uuid())
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();

verify(permissionUpdater).addPermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.componentKey()).isEqualTo("view-key");
assertThat(db.users().selectUserPermissions(user, null)).isEmpty();
assertThat(db.users().selectUserPermissions(user, view)).containsOnly(SYSTEM_ADMIN);
}

@Test
public void fail_when_project_uuid_is_unknown() throws Exception {
loginAsAdmin();

expectedException.expect(NotFoundException.class);

ws.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "ray.bradbury")
wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, user.getLogin())
.setParam(PARAM_PROJECT_ID, "unknown-project-uuid")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();
@@ -158,22 +128,25 @@ public class AddUserActionTest {

@Test
public void fail_when_project_permission_without_project() throws Exception {
loginAsAdmin();

expectedException.expect(BadRequestException.class);

ws.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "ray.bradbury")
wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, user.getLogin())
.setParam(PARAM_PERMISSION, UserRole.ISSUE_ADMIN)
.execute();
}

@Test
public void fail_when_component_is_not_a_project() throws Exception {
db.components().insertComponent(newFileDto(newProjectDto("project-uuid"), null, "file-uuid"));
loginAsAdmin();

expectedException.expect(BadRequestException.class);
insertComponent(newFileDto(newProjectDto("project-uuid"), null, "file-uuid"));
commit();

ws.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "ray.bradbury")
wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, user.getLogin())
.setParam(PARAM_PROJECT_ID, "file-uuid")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();
@@ -181,9 +154,11 @@ public class AddUserActionTest {

@Test
public void fail_when_get_request() throws Exception {
loginAsAdmin();

expectedException.expect(ServerException.class);

ws.newGetRequest(CONTROLLER, ACTION)
wsTester.newGetRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "george.orwell")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();
@@ -191,42 +166,43 @@ public class AddUserActionTest {

@Test
public void fail_when_user_login_is_missing() throws Exception {
loginAsAdmin();

expectedException.expect(IllegalArgumentException.class);

ws.newPostRequest(CONTROLLER, ACTION)
wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();
}

@Test
public void fail_when_permission_is_missing() throws Exception {
expectedException.expect(IllegalArgumentException.class);
loginAsAdmin();

expectedException.expect(NotFoundException.class);

ws.newPostRequest(CONTROLLER, ACTION)
wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "jrr.tolkien")
.execute();
}

@Test
public void fail_when_project_uuid_and_project_key_are_provided() throws Exception {
db.components().insertComponent(newProjectDto(A_PROJECT_UUID).setKey(A_PROJECT_KEY));
loginAsAdmin();

expectedException.expect(BadRequestException.class);
expectedException.expectMessage("Project id or project key can be provided, not both.");
insertComponent(newProjectDto("project-uuid").setKey("project-key"));
commit();

ws.newPostRequest(CONTROLLER, ACTION)
wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.setParam(PARAM_USER_LOGIN, "ray.bradbury")
.setParam(PARAM_USER_LOGIN, user.getLogin())
.setParam(PARAM_PROJECT_ID, "project-uuid")
.setParam(PARAM_PROJECT_KEY, "project-key")
.execute();
}

private void insertComponent(ComponentDto component) {
dbClient.componentDao().insert(dbSession, component);
}

private void commit() {
dbSession.commit();
private void loginAsAdmin() {
userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN);
}
}

+ 88
- 0
server/sonar-server/src/test/java/org/sonar/server/permission/ws/BasePermissionWsTest.java View File

@@ -0,0 +1,88 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.permission.ws;

import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.ExpectedException;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.utils.System2;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
import org.sonar.db.component.ResourceTypesRule;
import org.sonar.db.permission.template.PermissionTemplateDto;
import org.sonar.db.permission.template.PermissionTemplateTesting;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.issue.index.IssueAuthorizationIndexer;
import org.sonar.server.organization.DefaultOrganizationProviderRule;
import org.sonar.server.permission.GroupPermissionChanger;
import org.sonar.server.permission.PermissionUpdater;
import org.sonar.server.permission.UserPermissionChanger;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.usergroups.ws.GroupWsSupport;
import org.sonar.server.ws.WsTester;

import static org.mockito.Mockito.mock;

public abstract class BasePermissionWsTest<A extends PermissionsWsAction> {

@Rule
public DbTester db = DbTester.create(System2.INSTANCE);

@Rule
public ExpectedException expectedException = ExpectedException.none();

protected DefaultOrganizationProviderRule defaultOrganizationProvider = DefaultOrganizationProviderRule.create(db);
protected UserSessionRule userSession = UserSessionRule.standalone();
protected WsTester wsTester;

@Before
public void initWsTester() {
wsTester = new WsTester(new PermissionsWs(buildWsAction()));
}

protected abstract A buildWsAction();

protected GroupWsSupport newGroupWsSupport() {
return new GroupWsSupport(db.getDbClient(), defaultOrganizationProvider);
}

protected PermissionWsSupport newPermissionWsSupport() {
DbClient dbClient = db.getDbClient();
return new PermissionWsSupport(dbClient, new ComponentFinder(dbClient), newGroupWsSupport(), newRootResourceTypes());
}

protected ResourceTypesRule newRootResourceTypes() {
return new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT, Qualifiers.VIEW, "DEV");
}

protected PermissionUpdater newPermissionUpdater() {
return new PermissionUpdater(db.getDbClient(),
mock(IssueAuthorizationIndexer.class),
new UserPermissionChanger(db.getDbClient(), userSession),
new GroupPermissionChanger(db.getDbClient(), userSession));
}

protected PermissionTemplateDto insertTemplate() {
PermissionTemplateDto dto = db.getDbClient().permissionTemplateDao().insert(db.getSession(), PermissionTemplateTesting.newPermissionTemplateDto());
db.commit();
return dto;
}
}

+ 137
- 159
server/sonar-server/src/test/java/org/sonar/server/permission/ws/GroupsActionTest.java View File

@@ -19,29 +19,16 @@
*/
package org.sonar.server.permission.ws;

import com.google.common.io.Resources;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.security.DefaultGroups;
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.component.ComponentDbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ResourceTypesRule;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.user.GroupDto;
import org.sonar.db.permission.GroupPermissionDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.UnauthorizedException;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.usergroups.ws.UserGroupFinder;
import org.sonar.server.ws.WsActionTester;
import org.sonar.server.ws.WsTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.api.server.ws.WebService.Param.PAGE;
@@ -53,75 +40,95 @@ import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
import static org.sonar.db.component.ComponentTesting.newProjectDto;
import static org.sonar.db.component.ComponentTesting.newView;
import static org.sonar.test.JsonAssert.assertJson;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.CONTROLLER;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_KEY;

public class GroupsActionTest {
public class GroupsActionTest extends BasePermissionWsTest<GroupsAction> {

@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule
public UserSessionRule userSession = UserSessionRule.standalone();
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
private GroupDto group1;
private GroupDto group2;
private GroupDto group3;

ComponentDbTester componentDb = new ComponentDbTester(db);
ResourceTypesRule resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT, Qualifiers.VIEW, "DEV");

DbClient dbClient;
DbSession dbSession;
WsActionTester ws;

GroupsAction underTest;
@Override
protected GroupsAction buildWsAction() {
return new GroupsAction(
db.getDbClient(),
userSession,
newPermissionWsSupport());
}

@Before
public void setUp() {
dbClient = db.getDbClient();
dbSession = db.getSession();
underTest = new GroupsAction(
dbClient,
userSession,
new PermissionDependenciesFinder(dbClient, new ComponentFinder(dbClient), new UserGroupFinder(dbClient), resourceTypes));
ws = new WsActionTester(underTest);

userSession.login("login").setGlobalPermissions(SYSTEM_ADMIN);

GroupDto group1 = insertGroup(new GroupDto().setName("group-1-name").setDescription("group-1-description"));
GroupDto group2 = insertGroup(new GroupDto().setName("group-2-name").setDescription("group-2-description"));
GroupDto group3 = insertGroup(new GroupDto().setName("group-3-name").setDescription("group-3-description"));
insertGroupRole(new GroupPermissionDto().setGroupId(group1.getId()).setRole(SCAN_EXECUTION));
insertGroupRole(new GroupPermissionDto().setGroupId(group2.getId()).setRole(SCAN_EXECUTION));
insertGroupRole(new GroupPermissionDto().setGroupId(null).setRole(SCAN_EXECUTION));
insertGroupRole(new GroupPermissionDto().setGroupId(group3.getId()).setRole(SYSTEM_ADMIN));
OrganizationDto defOrg = defaultOrganizationProvider.getDto();
group1 = db.users().insertGroup(defOrg, "group-1-name");
group2 = db.users().insertGroup(defOrg, "group-2-name");
group3 = db.users().insertGroup(defOrg, "group-3-name");
db.users().insertPermissionOnGroup(group1, SCAN_EXECUTION);
db.users().insertPermissionOnGroup(group2, SCAN_EXECUTION);
db.users().insertPermissionOnGroup(group3, SYSTEM_ADMIN);
db.users().insertPermissionOnAnyone(defOrg, SCAN_EXECUTION);
db.commit();
}

@Test
public void search_for_groups_with_one_permission() {
String result = ws.newRequest()
public void search_for_groups_with_one_permission() throws Exception {
loginAsAdmin();
newRequest()
.setParam(PARAM_PERMISSION, SCAN_EXECUTION)
.execute().getInput();

assertJson(result).isSimilarTo(Resources.getResource(getClass(), "GroupsActionTest/groups.json"));
.execute()
.assertJson("{\n" +
" \"paging\": {\n" +
" \"pageIndex\": 1,\n" +
" \"pageSize\": 20,\n" +
" \"total\": 3\n" +
" },\n" +
" \"groups\": [\n" +
" {\n" +
" \"name\": \"Anyone\",\n" +
" \"permissions\": [\n" +
" \"scan\"\n" +
" ]\n" +
" },\n" +
" {\n" +
" \"name\": \"group-1-name\",\n" +
" \"description\": \"" + group1.getDescription() + "\",\n" +
" \"permissions\": [\n" +
" \"scan\"\n" +
" ]\n" +
" },\n" +
" {\n" +
" \"name\": \"group-2-name\",\n" +
" \"description\": \"" + group2.getDescription() + "\",\n" +
" \"permissions\": [\n" +
" \"scan\"\n" +
" ]\n" +
" }\n" +
" ]\n" +
"}\n");
}

@Test
public void search_with_selection() {
String result = ws.newRequest()
public void search_with_selection() throws Exception {
loginAsAdmin();
String result = newRequest()
.setParam(PARAM_PERMISSION, SCAN_EXECUTION)
.execute().getInput();
.execute()
.outputAsString();

assertThat(result).containsSequence(DefaultGroups.ANYONE, "group-1", "group-2");
}

@Test
public void search_groups_with_pagination() {
String result = ws.newRequest()
public void search_groups_with_pagination() throws Exception {
loginAsAdmin();
String result = newRequest()
.setParam(PARAM_PERMISSION, SCAN_EXECUTION)
.setParam(PAGE_SIZE, "1")
.setParam(PAGE, "3")
.execute().getInput();
.execute()
.outputAsString();

assertThat(result).contains("group-2")
.doesNotContain("group-1")
@@ -129,11 +136,13 @@ public class GroupsActionTest {
}

@Test
public void search_groups_with_query() {
String result = ws.newRequest()
public void search_groups_with_query() throws Exception {
loginAsAdmin();
String result = newRequest()
.setParam(PARAM_PERMISSION, SCAN_EXECUTION)
.setParam(TEXT_QUERY, "group-")
.execute().getInput();
.execute()
.outputAsString();

assertThat(result)
.contains("group-1", "group-2")
@@ -141,29 +150,23 @@ public class GroupsActionTest {
}

@Test
public void search_groups_with_project_permissions() {
userSession.login().addProjectUuidPermissions(ADMIN, "project-uuid");

ComponentDto project = componentDb.insertComponent(newProjectDto("project-uuid"));
GroupDto group = insertGroup(new GroupDto().setName("project-group-name"));
insertGroupRole(new GroupPermissionDto()
.setGroupId(group.getId())
.setRole(ISSUE_ADMIN)
.setResourceId(project.getId()));
public void search_groups_with_project_permissions() throws Exception {
ComponentDto project = db.components().insertComponent(newProjectDto("project-uuid"));
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "project-group-name");
db.users().insertProjectPermissionOnGroup(group, ISSUE_ADMIN, project);

ComponentDto anotherProject = componentDb.insertComponent(newProjectDto());
GroupDto anotherGroup = insertGroup(new GroupDto().setName("another-project-group-name"));
insertGroupRole(new GroupPermissionDto()
.setGroupId(anotherGroup.getId())
.setRole(ISSUE_ADMIN)
.setResourceId(anotherProject.getId()));
ComponentDto anotherProject = db.components().insertComponent(newProjectDto());
GroupDto anotherGroup = db.users().insertGroup(defaultOrganizationProvider.getDto(), "another-project-group-name");
db.users().insertProjectPermissionOnGroup(anotherGroup, ISSUE_ADMIN, anotherProject);

GroupDto groupWithoutPermission = insertGroup(new GroupDto().setName("group-without-permission"));
GroupDto groupWithoutPermission = db.users().insertGroup(defaultOrganizationProvider.getDto(), "group-without-permission");

String result = ws.newRequest()
userSession.login().addProjectUuidPermissions(ADMIN, "project-uuid");
String result = newRequest()
.setParam(PARAM_PERMISSION, ISSUE_ADMIN)
.setParam(PARAM_PROJECT_ID, "project-uuid")
.execute().getInput();
.execute()
.outputAsString();

assertThat(result).contains(group.getName())
.doesNotContain(anotherGroup.getName())
@@ -171,24 +174,21 @@ public class GroupsActionTest {
}

@Test
public void return_also_groups_without_permission_when_search_query() {
userSession.login().setGlobalPermissions(SYSTEM_ADMIN);
public void return_also_groups_without_permission_when_search_query() throws Exception {
ComponentDto project = db.components().insertComponent(newProjectDto("project-uuid"));
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "group-with-permission");
db.users().insertProjectPermissionOnGroup(group, ISSUE_ADMIN, project);

ComponentDto project = componentDb.insertComponent(newProjectDto("project-uuid"));
GroupDto group = insertGroup(new GroupDto().setName("group-with-permission"));
insertGroupRole(new GroupPermissionDto()
.setGroupId(group.getId())
.setRole(ISSUE_ADMIN)
.setResourceId(project.getId()));
GroupDto groupWithoutPermission = db.users().insertGroup(defaultOrganizationProvider.getDto(), "group-without-permission");
GroupDto anotherGroup = db.users().insertGroup(defaultOrganizationProvider.getDto(), "another-group");

GroupDto groupWithoutPermission = insertGroup(new GroupDto().setName("group-without-permission"));
GroupDto anotherGroup = insertGroup(new GroupDto().setName("another-group"));

String result = ws.newRequest()
loginAsAdmin();
String result = newRequest()
.setParam(PARAM_PERMISSION, ISSUE_ADMIN)
.setParam(PARAM_PROJECT_ID, "project-uuid")
.setParam(TEXT_QUERY, "group-with")
.execute().getInput();
.execute()
.outputAsString();

assertThat(result).contains(group.getName())
.doesNotContain(groupWithoutPermission.getName())
@@ -196,59 +196,52 @@ public class GroupsActionTest {
}

@Test
public void return_only_groups_with_permission_when_no_search_query() {
userSession.login().setGlobalPermissions(SYSTEM_ADMIN);

ComponentDto project = componentDb.insertComponent(newProjectDto("project-uuid"));
GroupDto group = insertGroup(new GroupDto().setName("project-group-name"));
insertGroupRole(new GroupPermissionDto()
.setGroupId(group.getId())
.setRole(ISSUE_ADMIN)
.setResourceId(project.getId()));
public void return_only_groups_with_permission_when_no_search_query() throws Exception {
ComponentDto project = db.components().insertComponent(newProjectDto("project-uuid"));
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "project-group-name");
db.users().insertProjectPermissionOnGroup(group, ISSUE_ADMIN, project);

GroupDto groupWithoutPermission = insertGroup(new GroupDto().setName("group-without-permission"));
GroupDto groupWithoutPermission = db.users().insertGroup(defaultOrganizationProvider.getDto(), "group-without-permission");

String result = ws.newRequest()
loginAsAdmin();
String result = newRequest()
.setParam(PARAM_PERMISSION, ISSUE_ADMIN)
.setParam(PARAM_PROJECT_ID, "project-uuid")
.execute().getInput();
.setParam(PARAM_PROJECT_ID, project.uuid())
.execute()
.outputAsString();

assertThat(result).contains("project-group-name")
assertThat(result).contains(group.getName())
.doesNotContain(groupWithoutPermission.getName());
}

@Test
public void return_anyone_group_when_search_query_and_no_param_permission() {
userSession.login().setGlobalPermissions(SYSTEM_ADMIN);

ComponentDto project = componentDb.insertComponent(newProjectDto("project-uuid"));
GroupDto group = insertGroup(new GroupDto().setName("group-with-permission"));
insertGroupRole(new GroupPermissionDto()
.setGroupId(group.getId())
.setRole(ISSUE_ADMIN)
.setResourceId(project.getId()));

String result = ws.newRequest()
.setParam(PARAM_PROJECT_ID, "project-uuid")
public void return_anyone_group_when_search_query_and_no_param_permission() throws Exception {
ComponentDto project = db.components().insertComponent(newProjectDto("project-uuid"));
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "group-with-permission");
db.users().insertProjectPermissionOnGroup(group, ISSUE_ADMIN, project);

loginAsAdmin();
String result = newRequest()
.setParam(PARAM_PROJECT_ID, project.uuid())
.setParam(TEXT_QUERY, "nyo")
.execute().getInput();
.execute()
.outputAsString();

assertThat(result).contains("Anyone");
}

@Test
public void search_groups_on_views() {
ComponentDto view = componentDb.insertComponent(newView("view-uuid").setKey("view-key"));
GroupDto group = insertGroup(new GroupDto().setName("project-group-name"));
insertGroupRole(new GroupPermissionDto()
.setGroupId(group.getId())
.setRole(ISSUE_ADMIN)
.setResourceId(view.getId()));

String result = ws.newRequest()
public void search_groups_on_views() throws Exception {
ComponentDto view = db.components().insertComponent(newView("view-uuid").setKey("view-key"));
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "project-group-name");
db.users().insertProjectPermissionOnGroup(group, ISSUE_ADMIN, view);

loginAsAdmin();
String result = newRequest()
.setParam(PARAM_PERMISSION, ISSUE_ADMIN)
.setParam(PARAM_PROJECT_ID, "view-uuid")
.execute().getInput();
.execute()
.outputAsString();

assertThat(result).contains("project-group-name")
.doesNotContain("group-1")
@@ -257,59 +250,44 @@ public class GroupsActionTest {
}

@Test
public void fail_if_project_permission_without_project() {
expectedException.expect(BadRequestException.class);

ws.newRequest()
.setParam(PARAM_PERMISSION, ISSUE_ADMIN)
.execute();
}

@Test
public void fail_if_not_logged_in() {
public void fail_if_not_logged_in() throws Exception {
expectedException.expect(UnauthorizedException.class);
userSession.anonymous();

ws.newRequest()
newRequest()
.setParam(PARAM_PERMISSION, "scan")
.execute();
}

@Test
public void fail_if_insufficient_privileges() {
public void fail_if_insufficient_privileges() throws Exception {
expectedException.expect(ForbiddenException.class);
userSession.login("login");

ws.newRequest()
userSession.login("login");
newRequest()
.setParam(PARAM_PERMISSION, "scan")
.execute();
}

@Test
public void fail_if_project_uuid_and_project_key_are_provided() {
public void fail_if_project_uuid_and_project_key_are_provided() throws Exception {
db.components().insertComponent(newProjectDto("project-uuid").setKey("project-key"));

expectedException.expect(BadRequestException.class);
dbClient.componentDao().insert(dbSession, newProjectDto("project-uuid").setKey("project-key"));

ws.newRequest()
loginAsAdmin();
newRequest()
.setParam(PARAM_PERMISSION, SCAN_EXECUTION)
.setParam(PARAM_PROJECT_ID, "project-uuid")
.setParam(PARAM_PROJECT_KEY, "project-key")
.execute();
}

private GroupDto insertGroup(GroupDto group) {
GroupDto result = dbClient.groupDao().insert(dbSession, group);
commit();

return result;
}

private void insertGroupRole(GroupPermissionDto groupRole) {
dbClient.roleDao().insertGroupRole(dbSession, groupRole);
commit();
private WsTester.TestRequest newRequest() {
return wsTester.newPostRequest(CONTROLLER, "groups");
}

private void commit() {
dbSession.commit();
private void loginAsAdmin() {
userSession.login("login").setGlobalPermissions(SYSTEM_ADMIN);
}
}

+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/permission/ws/PermissionsWsModuleTest.java View File

@@ -29,6 +29,6 @@ public class PermissionsWsModuleTest {
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new PermissionsWsModule().configure(container);
assertThat(container.size()).isEqualTo(2 + 29);
assertThat(container.size()).isEqualTo(2 + 33);
}
}

+ 5
- 4
server/sonar-server/src/test/java/org/sonar/server/permission/ws/PermissionsWsTest.java View File

@@ -23,6 +23,8 @@ import org.junit.Before;
import org.junit.Test;
import org.sonar.api.server.ws.WebService;
import org.sonar.db.DbClient;
import org.sonar.server.permission.ws.template.TemplateGroupsAction;
import org.sonar.server.permission.ws.template.TemplateUsersAction;
import org.sonar.server.user.UserSession;
import org.sonar.server.ws.WsTester;

@@ -38,12 +40,11 @@ public class PermissionsWsTest {
public void setUp() {
DbClient dbClient = mock(DbClient.class);
UserSession userSession = mock(UserSession.class);
PermissionDependenciesFinder permissionDependenciesFinder = mock(PermissionDependenciesFinder.class);
PermissionWsSupport permissionWsSupport = mock(PermissionWsSupport.class);

ws = new WsTester(new PermissionsWs(
new TemplateUsersAction(dbClient, userSession, permissionDependenciesFinder),
new TemplateGroupsAction(dbClient, userSession, permissionDependenciesFinder)
));
new TemplateUsersAction(dbClient, userSession, permissionWsSupport),
new TemplateGroupsAction(dbClient, userSession, permissionWsSupport)));
}

@Test

+ 99
- 106
server/sonar-server/src/test/java/org/sonar/server/permission/ws/RemoveGroupActionTest.java View File

@@ -20,32 +20,18 @@
package org.sonar.server.permission.ws;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.ArgumentCaptor;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
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.component.ResourceTypesRule;
import org.sonar.db.user.GroupDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.ServerException;
import org.sonar.server.permission.PermissionChange;
import org.sonar.server.permission.PermissionUpdater;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.usergroups.ws.UserGroupFinder;
import org.sonar.server.ws.WsTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.sonar.api.web.UserRole.ADMIN;
import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
import static org.sonar.core.permission.GlobalPermissions.PROVISIONING;
import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
import static org.sonar.db.component.ComponentTesting.newFileDto;
import static org.sonar.db.component.ComponentTesting.newProjectDto;
@@ -58,117 +44,127 @@ import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_P
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_KEY;

public class RemoveGroupActionTest extends BasePermissionWsTest<RemoveGroupAction> {

public class RemoveGroupActionTest {
UserSessionRule userSession = UserSessionRule.standalone();
WsTester ws;
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
@Rule
public ExpectedException expectedException = ExpectedException.none();
ResourceTypesRule resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT, Qualifiers.VIEW, "DEV");
private PermissionUpdater permissionUpdater;
private ArgumentCaptor<PermissionChange> permissionChangeCaptor = ArgumentCaptor.forClass(PermissionChange.class);
final DbSession dbSession = db.getSession();
private static final String A_PROJECT_UUID = "project-uuid";
private static final String A_PROJECT_KEY = "project-key";

private GroupDto aGroup;

@Before
public void setUp() {
permissionUpdater = mock(PermissionUpdater.class);
DbClient dbClient = db.getDbClient();
ComponentFinder componentFinder = new ComponentFinder(dbClient);
ws = new WsTester(new PermissionsWs(
new RemoveGroupAction(dbClient, new PermissionChangeBuilder(new PermissionDependenciesFinder(dbClient, componentFinder, new UserGroupFinder(dbClient), resourceTypes)), permissionUpdater)));
userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN);
aGroup = db.users().insertGroup(defaultOrganizationProvider.getDto(), "sonar-administrators");
}

@Override
protected RemoveGroupAction buildWsAction() {
return new RemoveGroupAction(db.getDbClient(), newPermissionUpdater(), newPermissionWsSupport());
}

@Test
public void call_permission_service_with_right_data() throws Exception {
insertGroup("sonar-administrators");
commit();
public void remove_permission_using_group_name() throws Exception {
db.users().insertPermissionOnGroup(aGroup, SYSTEM_ADMIN);
db.users().insertPermissionOnGroup(aGroup, PROVISIONING);

loginAsAdmin();
newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.setParam(PARAM_GROUP_NAME, aGroup.getName())
.setParam(PARAM_PERMISSION, PROVISIONING)
.execute();

verify(permissionUpdater).removePermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.groupName()).isEqualTo("sonar-administrators");
assertThat(permissionChange.permission()).isEqualTo(SYSTEM_ADMIN);
assertThat(db.users().selectGroupPermissions(aGroup, null)).containsOnly(SYSTEM_ADMIN);
}

@Test
public void remove_by_group_id() throws Exception {
GroupDto group = insertGroup("sonar-administrators");
commit();
public void remove_permission_using_group_id() throws Exception {
db.users().insertPermissionOnGroup(aGroup, SYSTEM_ADMIN);
db.users().insertPermissionOnGroup(aGroup, PROVISIONING);

loginAsAdmin();
newRequest()
.setParam(PARAM_GROUP_ID, group.getId().toString())
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.setParam(PARAM_GROUP_ID, aGroup.getId().toString())
.setParam(PARAM_PERMISSION, PROVISIONING)
.execute();

verify(permissionUpdater).removePermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.groupName()).isEqualTo("sonar-administrators");
assertThat(db.users().selectGroupPermissions(aGroup, null)).containsOnly(SYSTEM_ADMIN);
}

@Test
public void remove_with_project_uuid() throws Exception {
insertComponent(newProjectDto("project-uuid").setKey("project-key"));
insertGroup("sonar-administrators");
commit();
public void remove_project_permission() throws Exception {
ComponentDto project = db.components().insertComponent(newProjectDto(A_PROJECT_UUID).setKey(A_PROJECT_KEY));
db.users().insertPermissionOnGroup(aGroup, SYSTEM_ADMIN);
db.users().insertProjectPermissionOnGroup(aGroup, ADMIN, project);
db.users().insertProjectPermissionOnGroup(aGroup, ISSUE_ADMIN, project);
loginAsAdmin();

newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_PROJECT_ID, "project-uuid")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.setParam(PARAM_GROUP_NAME, aGroup.getName())
.setParam(PARAM_PROJECT_ID, project.uuid())
.setParam(PARAM_PERMISSION, ADMIN)
.execute();

verify(permissionUpdater).removePermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.componentKey()).isEqualTo("project-key");
assertThat(db.users().selectGroupPermissions(aGroup, null)).containsOnly(SYSTEM_ADMIN);
assertThat(db.users().selectGroupPermissions(aGroup, project)).containsOnly(ISSUE_ADMIN);
}

@Test
public void remove_with_view_uuid() throws Exception {
insertComponent(newView("view-uuid").setKey("view-key"));
insertGroup("sonar-administrators");
db.commit();
ComponentDto view = db.components().insertComponent(newView("view-uuid").setKey("view-key"));
db.users().insertPermissionOnGroup(aGroup, SYSTEM_ADMIN);
db.users().insertProjectPermissionOnGroup(aGroup, ADMIN, view);
db.users().insertProjectPermissionOnGroup(aGroup, ISSUE_ADMIN, view);
loginAsAdmin();

newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_PROJECT_ID, "view-uuid")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.setParam(PARAM_GROUP_NAME, aGroup.getName())
.setParam(PARAM_PROJECT_ID, view.uuid())
.setParam(PARAM_PERMISSION, ADMIN)
.execute();

verify(permissionUpdater).removePermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.componentKey()).isEqualTo("view-key");
assertThat(db.users().selectGroupPermissions(aGroup, null)).containsOnly(SYSTEM_ADMIN);
assertThat(db.users().selectGroupPermissions(aGroup, view)).containsOnly(ISSUE_ADMIN);
}

@Test
public void remove_with_project_key() throws Exception {
insertComponent(newProjectDto("project-uuid").setKey("project-key"));
insertGroup("sonar-administrators");
db.commit();
ComponentDto project = db.components().insertComponent(newProjectDto(A_PROJECT_UUID).setKey(A_PROJECT_KEY));
db.users().insertPermissionOnGroup(aGroup, SYSTEM_ADMIN);
db.users().insertProjectPermissionOnGroup(aGroup, ADMIN, project);
db.users().insertProjectPermissionOnGroup(aGroup, ISSUE_ADMIN, project);
loginAsAdmin();

newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_PROJECT_KEY, "project-key")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.setParam(PARAM_GROUP_NAME, aGroup.getName())
.setParam(PARAM_PROJECT_KEY, project.getKey())
.setParam(PARAM_PERMISSION, ADMIN)
.execute();

verify(permissionUpdater).removePermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.componentKey()).isEqualTo("project-key");
assertThat(db.users().selectGroupPermissions(aGroup, null)).containsOnly(SYSTEM_ADMIN);
assertThat(db.users().selectGroupPermissions(aGroup, project)).containsOnly(ISSUE_ADMIN);
}

@Test
public void fail_to_remove_last_sysadmin_permission() throws Exception {
db.users().insertPermissionOnGroup(aGroup, SYSTEM_ADMIN);
db.users().insertPermissionOnGroup(aGroup, PROVISIONING);
loginAsAdmin();

expectedException.expect(BadRequestException.class);
expectedException.expectMessage("Last group with 'admin' permission. Permission cannot be removed.");

newRequest()
.setParam(PARAM_GROUP_NAME, aGroup.getName())
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();
}

@Test
public void fail_when_project_does_not_exist() throws Exception {
expectedException.expect(NotFoundException.class);
expectedException.expectMessage("Project id 'unknown-project-uuid' not found");

newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_GROUP_NAME, aGroup.getName())
.setParam(PARAM_PROJECT_ID, "unknown-project-uuid")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();
@@ -177,23 +173,24 @@ public class RemoveGroupActionTest {
@Test
public void fail_when_project_project_permission_without_project() throws Exception {
expectedException.expect(BadRequestException.class);
expectedException.expectMessage("Invalid global permission 'issueadmin'. Valid values are [admin, profileadmin, gateadmin, scan, provisioning]");

newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_PERMISSION, UserRole.ISSUE_ADMIN)
.setParam(PARAM_GROUP_NAME, aGroup.getName())
.setParam(PARAM_PERMISSION, ISSUE_ADMIN)
.execute();
}

@Test
public void fail_when_component_is_not_a_project() throws Exception {
ComponentDto file = db.components().insertComponent(newFileDto(newProjectDto(A_PROJECT_UUID), null, "file-uuid"));

expectedException.expect(BadRequestException.class);
insertComponent(newFileDto(newProjectDto("project-uuid"), null, "file-uuid"));
insertGroup("sonar-administrators");
commit();
expectedException.expectMessage("Component 'KEY_file-uuid' (id: file-uuid) must be a project or a module.");

newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_PROJECT_ID, "file-uuid")
.setParam(PARAM_GROUP_NAME, aGroup.getName())
.setParam(PARAM_PROJECT_ID, file.uuid())
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();
}
@@ -201,9 +198,10 @@ public class RemoveGroupActionTest {
@Test
public void fail_when_get_request() throws Exception {
expectedException.expect(ServerException.class);
expectedException.expectMessage("HTTP method POST is required");

ws.newGetRequest(CONTROLLER, ACTION)
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
wsTester.newGetRequest(CONTROLLER, ACTION)
.setParam(PARAM_GROUP_NAME, aGroup.getName())
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();
}
@@ -211,6 +209,7 @@ public class RemoveGroupActionTest {
@Test
public void fail_when_group_name_is_missing() throws Exception {
expectedException.expect(BadRequestException.class);
expectedException.expectMessage("Group name or group id must be provided");

newRequest()
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
@@ -220,16 +219,17 @@ public class RemoveGroupActionTest {
@Test
public void fail_when_permission_name_and_id_are_missing() throws Exception {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("The 'permission' parameter is missing");

newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_GROUP_NAME, aGroup.getName())
.execute();
}

@Test
public void fail_when_group_id_does_not_exist() throws Exception {
expectedException.expect(NotFoundException.class);
expectedException.expectMessage("Group with id '42' is not found");
expectedException.expectMessage("No group with id '42'");

newRequest()
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
@@ -239,32 +239,25 @@ public class RemoveGroupActionTest {

@Test
public void fail_when_project_uuid_and_project_key_are_provided() throws Exception {
ComponentDto project = db.components().insertComponent(newProjectDto(A_PROJECT_UUID).setKey(A_PROJECT_KEY));

expectedException.expect(BadRequestException.class);
expectedException.expectMessage("Project id or project key can be provided, not both.");
insertComponent(newProjectDto("project-uuid").setKey("project-key"));
commit();

newRequest()
.setParam(PARAM_GROUP_NAME, "sonar-administrators")
.setParam(PARAM_GROUP_NAME, aGroup.getName())
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.setParam(PARAM_PROJECT_ID, "project-uuid")
.setParam(PARAM_PROJECT_KEY, "project-key")
.setParam(PARAM_PROJECT_ID, project.uuid())
.setParam(PARAM_PROJECT_KEY, project.getKey())
.execute();
}

private WsTester.TestRequest newRequest() {
return ws.newPostRequest(CONTROLLER, ACTION);
}

private GroupDto insertGroup(String groupName) {
return db.getDbClient().groupDao().insert(dbSession, new GroupDto().setName(groupName));
return wsTester.newPostRequest(CONTROLLER, ACTION);
}

private void insertComponent(ComponentDto component) {
db.getDbClient().componentDao().insert(dbSession, component);
private void loginAsAdmin() {
userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN);
}

private void commit() {
dbSession.commit();
}
}

+ 106
- 93
server/sonar-server/src/test/java/org/sonar/server/permission/ws/RemoveUserActionTest.java View File

@@ -20,31 +20,19 @@
package org.sonar.server.permission.ws;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.ArgumentCaptor;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
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.component.ResourceTypesRule;
import org.sonar.server.component.ComponentFinder;
import org.sonar.db.user.UserDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.ServerException;
import org.sonar.server.permission.PermissionChange;
import org.sonar.server.permission.PermissionUpdater;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.usergroups.ws.UserGroupFinder;
import org.sonar.server.ws.WsTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.sonar.api.web.UserRole.ADMIN;
import static org.sonar.api.web.UserRole.CODEVIEWER;
import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
import static org.sonar.core.permission.GlobalPermissions.PROVISIONING;
import static org.sonar.core.permission.GlobalPermissions.QUALITY_GATE_ADMIN;
import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
import static org.sonar.db.component.ComponentTesting.newFileDto;
import static org.sonar.db.component.ComponentTesting.newProjectDto;
@@ -56,117 +44,135 @@ import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_P
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_KEY;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_USER_LOGIN;

public class RemoveUserActionTest extends BasePermissionWsTest<RemoveUserAction> {

public class RemoveUserActionTest {
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
@Rule
public ExpectedException expectedException = ExpectedException.none();
ResourceTypesRule resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT, Qualifiers.VIEW, "DEV");
UserSessionRule userSession = UserSessionRule.standalone();
WsTester ws;
PermissionUpdater permissionUpdater;
DbClient dbClient;
DbSession dbSession;
ArgumentCaptor<PermissionChange> permissionChangeCaptor = ArgumentCaptor.forClass(PermissionChange.class);
private static final String A_PROJECT_UUID = "project-uuid";
private static final String A_PROJECT_KEY = "project-key";
private static final String A_LOGIN = "ray.bradbury";

private UserDto user;

@Before
public void setUp() {
permissionUpdater = mock(PermissionUpdater.class);
dbClient = db.getDbClient();
dbSession = db.getSession();
ComponentFinder componentFinder = new ComponentFinder(dbClient);
ws = new WsTester(new PermissionsWs(
new RemoveUserAction(dbClient, permissionUpdater, new PermissionChangeBuilder(new PermissionDependenciesFinder(dbClient, componentFinder, new UserGroupFinder(dbClient), resourceTypes)))));
userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN);
user = db.users().insertUser(A_LOGIN);
}

@Override
protected RemoveUserAction buildWsAction() {
return new RemoveUserAction(db.getDbClient(), newPermissionUpdater(), newPermissionWsSupport());
}

@Test
public void call_permission_service_with_right_data() throws Exception {
ws.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "ray.bradbury")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
public void remove_permission_from_user() throws Exception {
db.users().insertPermissionOnUser(user, PROVISIONING);
db.users().insertPermissionOnUser(user, QUALITY_GATE_ADMIN);
loginAsAdmin();

wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, user.getLogin())
.setParam(PARAM_PERMISSION, QUALITY_GATE_ADMIN)
.execute();

verify(permissionUpdater).removePermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.userLogin()).isEqualTo("ray.bradbury");
assertThat(permissionChange.permission()).isEqualTo(SYSTEM_ADMIN);
assertThat(db.users().selectUserPermissions(user, null)).containsOnly(PROVISIONING);
}

@Test
public void remove_with_project_uuid() throws Exception {
insertComponent(newProjectDto("project-uuid").setKey("project-key"));
public void fail_to_remove_admin_permission_if_last_admin() throws Exception {
db.users().insertPermissionOnUser(user, CODEVIEWER);
db.users().insertPermissionOnUser(user, ADMIN);
loginAsAdmin();

ws.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "ray.bradbury")
.setParam(PARAM_PROJECT_ID, "project-uuid")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
expectedException.expect(BadRequestException.class);
expectedException.expectMessage("Last user with 'admin' permission. Permission cannot be removed.");

wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, user.getLogin())
.setParam(PARAM_PERMISSION, ADMIN)
.execute();
}

@Test
public void remove_permission_from_project() throws Exception {
ComponentDto project = db.components().insertComponent(newProjectDto(A_PROJECT_UUID).setKey(A_PROJECT_KEY));
db.users().insertProjectPermissionOnUser(user, CODEVIEWER, project);
db.users().insertProjectPermissionOnUser(user, ISSUE_ADMIN, project);
loginAsAdmin();

wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, user.getLogin())
.setParam(PARAM_PROJECT_ID, project.uuid())
.setParam(PARAM_PERMISSION, CODEVIEWER)
.execute();

verify(permissionUpdater).removePermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.componentKey()).isEqualTo("project-key");
assertThat(db.users().selectUserPermissions(user, project)).containsOnly(ISSUE_ADMIN);
}

@Test
public void remove_with_project_key() throws Exception {
insertComponent(newProjectDto("project-uuid").setKey("project-key"));

ws.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "ray.bradbury")
.setParam(PARAM_PROJECT_KEY, "project-key")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
ComponentDto project = db.components().insertComponent(newProjectDto(A_PROJECT_UUID).setKey(A_PROJECT_KEY));
db.users().insertProjectPermissionOnUser(user, ISSUE_ADMIN, project);
db.users().insertProjectPermissionOnUser(user, CODEVIEWER, project);
loginAsAdmin();

wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, user.getLogin())
.setParam(PARAM_PROJECT_KEY, project.getKey())
.setParam(PARAM_PERMISSION, ISSUE_ADMIN)
.execute();

verify(permissionUpdater).removePermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.componentKey()).isEqualTo("project-key");
assertThat(db.users().selectUserPermissions(user, project)).containsOnly(CODEVIEWER);
}

@Test
public void remove_with_view_uuid() throws Exception {
insertComponent(newView("view-uuid").setKey("view-key"));

ws.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "ray.bradbury")
.setParam(PARAM_PROJECT_ID, "view-uuid")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
ComponentDto view = db.components().insertComponent(newView("view-uuid").setKey("view-key"));
db.users().insertProjectPermissionOnUser(user, ISSUE_ADMIN, view);
db.users().insertProjectPermissionOnUser(user, CODEVIEWER, view);
loginAsAdmin();

wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, user.getLogin())
.setParam(PARAM_PROJECT_KEY, view.getKey())
.setParam(PARAM_PERMISSION, ISSUE_ADMIN)
.execute();

verify(permissionUpdater).removePermission(permissionChangeCaptor.capture());
PermissionChange permissionChange = permissionChangeCaptor.getValue();
assertThat(permissionChange.componentKey()).isEqualTo("view-key");
assertThat(db.users().selectUserPermissions(user, view)).containsOnly(CODEVIEWER);
}

@Test
public void fail_when_project_does_not_exist() throws Exception {
loginAsAdmin();

expectedException.expect(NotFoundException.class);

ws.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "ray.bradbury")
wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, user.getLogin())
.setParam(PARAM_PROJECT_ID, "unknown-project-uuid")
.setParam(PARAM_PERMISSION, UserRole.ISSUE_ADMIN)
.setParam(PARAM_PERMISSION, ISSUE_ADMIN)
.execute();
}

@Test
public void fail_when_project_permission_without_permission() throws Exception {
loginAsAdmin();

expectedException.expect(BadRequestException.class);

ws.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "ray.bradbury")
.setParam(PARAM_PERMISSION, UserRole.ISSUE_ADMIN)
wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, user.getLogin())
.setParam(PARAM_PERMISSION, ISSUE_ADMIN)
.execute();
}

@Test
public void fail_when_component_is_not_a_project() throws Exception {
db.components().insertComponent(newFileDto(newProjectDto(), null, "file-uuid"));
loginAsAdmin();

expectedException.expect(BadRequestException.class);
insertComponent(newFileDto(newProjectDto(), null, "file-uuid"));

ws.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "ray.bradbury")
wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, user.getLogin())
.setParam(PARAM_PROJECT_ID, "file-uuid")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();
@@ -174,9 +180,11 @@ public class RemoveUserActionTest {

@Test
public void fail_when_get_request() throws Exception {
loginAsAdmin();

expectedException.expect(ServerException.class);

ws.newGetRequest(CONTROLLER, ACTION)
wsTester.newGetRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "george.orwell")
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();
@@ -184,38 +192,43 @@ public class RemoveUserActionTest {

@Test
public void fail_when_user_login_is_missing() throws Exception {
loginAsAdmin();

expectedException.expect(IllegalArgumentException.class);

ws.newPostRequest(CONTROLLER, ACTION)
wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.execute();
}

@Test
public void fail_when_permission_is_missing() throws Exception {
loginAsAdmin();

expectedException.expect(IllegalArgumentException.class);

ws.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, "jrr.tolkien")
wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_USER_LOGIN, user.getLogin())
.execute();
}

@Test
public void fail_when_project_uuid_and_project_key_are_provided() throws Exception {
ComponentDto project = db.components().insertComponent(newProjectDto(A_PROJECT_UUID).setKey(A_PROJECT_KEY));
loginAsAdmin();

expectedException.expect(BadRequestException.class);
expectedException.expectMessage("Project id or project key can be provided, not both.");
insertComponent(newProjectDto("project-uuid").setKey("project-key"));

ws.newPostRequest(CONTROLLER, ACTION)
wsTester.newPostRequest(CONTROLLER, ACTION)
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.setParam(PARAM_USER_LOGIN, "ray.bradbury")
.setParam(PARAM_PROJECT_ID, "project-uuid")
.setParam(PARAM_PROJECT_KEY, "project-key")
.setParam(PARAM_USER_LOGIN, user.getLogin())
.setParam(PARAM_PROJECT_ID, project.uuid())
.setParam(PARAM_PROJECT_KEY, project.getKey())
.execute();
}

private void insertComponent(ComponentDto component) {
dbClient.componentDao().insert(dbSession, component);
dbSession.commit();
private void loginAsAdmin() {
userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN);
}
}

+ 23
- 54
server/sonar-server/src/test/java/org/sonar/server/permission/ws/SearchGlobalPermissionsActionTest.java View File

@@ -20,17 +20,16 @@
package org.sonar.server.permission.ws;

import java.io.IOException;
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.DbTester;
import org.sonar.db.permission.GroupPermissionDto;
import org.sonar.db.permission.UserPermissionDto;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.GroupTesting;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserTesting;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.UnauthorizedException;
import org.sonar.server.i18n.I18nRule;
@@ -55,8 +54,8 @@ public class SearchGlobalPermissionsActionTest {
public DbTester db = DbTester.create(System2.INSTANCE);
@Rule
public UserSessionRule userSession = UserSessionRule.standalone();
WsActionTester ws;
I18nRule i18n = new I18nRule();
private WsActionTester ws;
private I18nRule i18n = new I18nRule();

@Before
public void setUp() {
@@ -68,22 +67,19 @@ public class SearchGlobalPermissionsActionTest {

@Test
public void search() {
GroupDto adminGroup = insertGroup(newGroupDto("sonar-admins", "Administrators"));
GroupDto userGroup = insertGroup(newGroupDto("sonar-users", "Users"));
insertGroupRole(newGroupRole(SCAN_EXECUTION, null));
insertGroupRole(newGroupRole(SCAN_EXECUTION, userGroup.getId()));
insertGroupRole(newGroupRole(SYSTEM_ADMIN, adminGroup.getId()));
insertGroupRole(newGroupRole(PROVISIONING, userGroup.getId()));

UserDto user = insertUser(newUserDto("user", "user-name"));
UserDto adminUser = insertUser(newUserDto("admin", "admin-name"));
insertUserPermission(newUserPermission(PROVISIONING, user.getId()));
insertUserPermission(newUserPermission(QUALITY_PROFILE_ADMIN, user.getId()));
insertUserPermission(newUserPermission(QUALITY_PROFILE_ADMIN, adminUser.getId()));
insertUserPermission(newUserPermission(QUALITY_GATE_ADMIN, user.getId()));
insertUserPermission(newUserPermission(QUALITY_GATE_ADMIN, adminUser.getId()));

db.getSession().commit();
GroupDto adminGroup = db.users().insertGroup(newGroupDto("sonar-admins", "Administrators"));
GroupDto userGroup = db.users().insertGroup(newGroupDto("sonar-users", "Users"));
db.users().insertPermissionOnAnyone(SCAN_EXECUTION);
db.users().insertPermissionOnGroup(userGroup, SCAN_EXECUTION);
db.users().insertPermissionOnGroup(userGroup, PROVISIONING);
db.users().insertPermissionOnGroup(adminGroup, SYSTEM_ADMIN);
UserDto user = db.users().insertUser(newUserDto("user", "user-name"));
UserDto adminUser = db.users().insertUser(newUserDto("admin", "admin-name"));
db.users().insertPermissionOnUser(user, PROVISIONING);
db.users().insertPermissionOnUser(user, QUALITY_PROFILE_ADMIN);
db.users().insertPermissionOnUser(adminUser, QUALITY_PROFILE_ADMIN);
db.users().insertPermissionOnUser(user, QUALITY_GATE_ADMIN);
db.users().insertPermissionOnUser(adminUser, QUALITY_GATE_ADMIN);

String result = ws.newRequest().execute().getInput();

@@ -102,17 +98,19 @@ public class SearchGlobalPermissionsActionTest {

@Test
public void fail_if_insufficient_privileges() {
expectedException.expect(ForbiddenException.class);
userSession.login("login");

expectedException.expect(ForbiddenException.class);

ws.newRequest().execute();
}

@Test
public void fail_if_not_logged_in() {
expectedException.expect(UnauthorizedException.class);
userSession.anonymous();

expectedException.expect(UnauthorizedException.class);

ws.newRequest().execute();
}

@@ -131,40 +129,11 @@ public class SearchGlobalPermissionsActionTest {
i18n.put("global_permissions.provisioning.desc", "Ability to initialize project structure before first analysis.");
}

private UserDto insertUser(UserDto user) {
return db.getDbClient().userDao().insert(db.getSession(), user);
}

private void insertUserPermission(UserPermissionDto dto) {
db.getDbClient().userPermissionDao().insert(db.getSession(), dto);
}

private GroupDto insertGroup(GroupDto groupDto) {
return db.getDbClient().groupDao().insert(db.getSession(), groupDto);
}

private void insertGroupRole(GroupPermissionDto group) {
db.getDbClient().roleDao().insertGroupRole(db.getSession(), group);
}

private static UserDto newUserDto(String login, String name) {
return new UserDto().setLogin(login).setName(name).setActive(true);
return UserTesting.newUserDto().setLogin(login).setName(name).setActive(true);
}

private static GroupDto newGroupDto(String name, String description) {
return new GroupDto().setName(name).setDescription(description);
}

private static GroupPermissionDto newGroupRole(String role, @Nullable Long groupId) {
GroupPermissionDto groupRole = new GroupPermissionDto().setRole(role);
if (groupId != null) {
groupRole.setGroupId(groupId);
}

return groupRole;
}

private static UserPermissionDto newUserPermission(String permission, long userId) {
return new UserPermissionDto(permission, userId, null);
return GroupTesting.newGroupDto().setName(name).setDescription(description);
}
}

+ 83
- 150
server/sonar-server/src/test/java/org/sonar/server/permission/ws/SearchProjectPermissionsActionTest.java View File

@@ -19,36 +19,22 @@
*/
package org.sonar.server.permission.ws;

import java.io.IOException;
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.resources.Qualifiers;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ResourceTypesRule;
import org.sonar.db.permission.GroupPermissionDto;
import org.sonar.db.permission.UserPermissionDto;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.UnauthorizedException;
import org.sonar.server.i18n.I18nRule;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.usergroups.ws.UserGroupFinder;
import org.sonar.server.ws.TestResponse;
import org.sonar.server.ws.WsActionTester;
import org.sonar.server.ws.WsTester;
import org.sonarqube.ws.MediaTypes;
import org.sonarqube.ws.WsPermissions.SearchProjectPermissionsWsResponse;
import org.sonarqube.ws.WsPermissions;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.api.server.ws.WebService.Param.PAGE;
@@ -59,49 +45,35 @@ import static org.sonar.db.component.ComponentTesting.newProjectCopy;
import static org.sonar.db.component.ComponentTesting.newProjectDto;
import static org.sonar.db.component.ComponentTesting.newView;
import static org.sonar.db.user.GroupTesting.newGroupDto;
import static org.sonar.db.user.UserTesting.newUserDto;
import static org.sonar.test.JsonAssert.assertJson;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.CONTROLLER;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_QUALIFIER;

public class SearchProjectPermissionsActionTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule
public UserSessionRule userSession = UserSessionRule.standalone();
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
ComponentDbTester componentDb = new ComponentDbTester(db);
public class SearchProjectPermissionsActionTest extends BasePermissionWsTest<SearchProjectPermissionsAction> {

WsActionTester ws;
I18nRule i18n = new I18nRule();
DbClient dbClient = db.getDbClient();
final DbSession dbSession = db.getSession();
ResourceTypesRule resourceTypes = new ResourceTypesRule();
SearchProjectPermissionsDataLoader dataLoader;

SearchProjectPermissionsAction underTest;
private ComponentDbTester componentDb = new ComponentDbTester(db);
private I18nRule i18n = new I18nRule();

@Before
public void setUp() {
resourceTypes.setRootQualifiers(Qualifiers.PROJECT, Qualifiers.VIEW, "DEV");
ComponentFinder componentFinder = new ComponentFinder(dbClient);
PermissionDependenciesFinder finder = new PermissionDependenciesFinder(dbClient, componentFinder, new UserGroupFinder(dbClient), resourceTypes);
i18n.setProjectPermissions();

dataLoader = new SearchProjectPermissionsDataLoader(dbClient, finder, resourceTypes);
underTest = new SearchProjectPermissionsAction(dbClient, userSession, i18n, resourceTypes, dataLoader);

ws = new WsActionTester(underTest);

userSession.login().setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
}

@Override
protected SearchProjectPermissionsAction buildWsAction() {
i18n.setProjectPermissions();
ResourceTypesRule rootResourceTypes = newRootResourceTypes();
SearchProjectPermissionsDataLoader dataLoader = new SearchProjectPermissionsDataLoader(db.getDbClient(), newPermissionWsSupport(), rootResourceTypes);
return new SearchProjectPermissionsAction(db.getDbClient(), userSession, i18n, rootResourceTypes, dataLoader);
}

@Test
public void search_project_permissions() {
UserDto user1 = insertUser(newUserDto());
UserDto user2 = insertUser(newUserDto());
UserDto user3 = insertUser(newUserDto());
public void search_project_permissions() throws Exception {
UserDto user1 = db.users().insertUser();
UserDto user2 = db.users().insertUser();
UserDto user3 = db.users().insertUser();

ComponentDto jdk7 = insertJdk7();
ComponentDto project2 = insertClang();
@@ -109,30 +81,30 @@ public class SearchProjectPermissionsActionTest {
ComponentDto view = insertView();
insertProjectInView(jdk7, view);

insertUserPermission(UserRole.ISSUE_ADMIN, user1.getId(), jdk7.getId());
insertUserPermission(UserRole.ADMIN, user1.getId(), jdk7.getId());
insertUserPermission(UserRole.ADMIN, user2.getId(), jdk7.getId());
insertUserPermission(UserRole.ADMIN, user3.getId(), jdk7.getId());
insertUserPermission(UserRole.ISSUE_ADMIN, user1.getId(), project2.getId());
insertUserPermission(UserRole.ISSUE_ADMIN, user1.getId(), dev.getId());
insertUserPermission(UserRole.ISSUE_ADMIN, user1.getId(), view.getId());
db.users().insertProjectPermissionOnUser(user1, UserRole.ISSUE_ADMIN, jdk7);
db.users().insertProjectPermissionOnUser(user1, UserRole.ADMIN, jdk7);
db.users().insertProjectPermissionOnUser(user2, UserRole.ADMIN, jdk7);
db.users().insertProjectPermissionOnUser(user3, UserRole.ADMIN, jdk7);
db.users().insertProjectPermissionOnUser(user1, UserRole.ISSUE_ADMIN, project2);
db.users().insertProjectPermissionOnUser(user1, UserRole.ISSUE_ADMIN, dev);
db.users().insertProjectPermissionOnUser(user1, UserRole.ISSUE_ADMIN, view);
// global permission
insertUserPermission(GlobalPermissions.SYSTEM_ADMIN, user1.getId(), null);
db.users().insertPermissionOnUser(user1, GlobalPermissions.SYSTEM_ADMIN);

GroupDto group1 = insertGroup(newGroupDto());
GroupDto group2 = insertGroup(newGroupDto());
GroupDto group3 = insertGroup(newGroupDto());
GroupDto group1 = db.users().insertGroup(newGroupDto());
GroupDto group2 = db.users().insertGroup(newGroupDto());
GroupDto group3 = db.users().insertGroup(newGroupDto());

insertGroupRole(UserRole.ADMIN, jdk7.getId(), null);
insertGroupRole(UserRole.ADMIN, jdk7.getId(), group1.getId());
insertGroupRole(UserRole.ADMIN, jdk7.getId(), group2.getId());
insertGroupRole(UserRole.ADMIN, jdk7.getId(), group3.getId());
insertGroupRole(UserRole.ADMIN, dev.getId(), group2.getId());
insertGroupRole(UserRole.ADMIN, view.getId(), group2.getId());
db.users().insertProjectPermissionOnAnyone(defaultOrganizationProvider.getDto(), UserRole.ADMIN, jdk7);
db.users().insertProjectPermissionOnGroup(group1, UserRole.ADMIN, jdk7);
db.users().insertProjectPermissionOnGroup(group2, UserRole.ADMIN, jdk7);
db.users().insertProjectPermissionOnGroup(group3, UserRole.ADMIN, jdk7);
db.users().insertProjectPermissionOnGroup(group2, UserRole.ADMIN, dev);
db.users().insertProjectPermissionOnGroup(group2, UserRole.ADMIN, view);

commit();
db.commit();

String result = ws.newRequest().execute().getInput();
String result = newRequest().execute().outputAsString();

assertJson(result)
.ignoreFields("permissions")
@@ -140,8 +112,8 @@ public class SearchProjectPermissionsActionTest {
}

@Test
public void empty_result() {
String result = ws.newRequest().execute().getInput();
public void empty_result() throws Exception {
String result = newRequest().execute().outputAsString();

assertJson(result)
.ignoreFields("permissions")
@@ -149,30 +121,28 @@ public class SearchProjectPermissionsActionTest {
}

@Test
public void search_project_permissions_with_project_permission() {
public void search_project_permissions_with_project_permission() throws Exception {
userSession.login().addProjectUuidPermissions(UserRole.ADMIN, "project-uuid");
insertComponent(newProjectDto("project-uuid"));
commit();
db.components().insertComponent(newProjectDto("project-uuid"));

String result = ws.newRequest()
String result = newRequest()
.setParam(PARAM_PROJECT_ID, "project-uuid")
.execute().getInput();
.execute().outputAsString();

assertThat(result).contains("project-uuid");
}

@Test
public void has_projects_ordered_by_name() {
public void has_projects_ordered_by_name() throws Exception {
for (int i = 9; i >= 1; i--) {
insertComponent(newProjectDto()
db.components().insertComponent(newProjectDto()
.setName("project-name-" + i));
}
commit();

String result = ws.newRequest()
String result = newRequest()
.setParam(PAGE, "1")
.setParam(PAGE_SIZE, "3")
.execute().getInput();
.execute().outputAsString();

assertThat(result)
.contains("project-name-1", "project-name-2", "project-name-3")
@@ -180,80 +150,62 @@ public class SearchProjectPermissionsActionTest {
}

@Test
public void search_by_query_on_name() {
public void search_by_query_on_name() throws Exception {
componentDb.insertProjectAndSnapshot(newProjectDto().setName("project-name"));
componentDb.insertProjectAndSnapshot(newProjectDto().setName("another-name"));
componentDb.indexAllComponents();

String result = ws.newRequest()
String result = newRequest()
.setParam(TEXT_QUERY, "project")
.execute().getInput();
.execute().outputAsString();

assertThat(result).contains("project-name")
.doesNotContain("another-name");
}

@Test
public void search_by_query_on_key_must_match_exactly() {
public void search_by_query_on_key_must_match_exactly() throws Exception {
componentDb.insertProjectAndSnapshot(newProjectDto().setKey("project-key"));
componentDb.insertProjectAndSnapshot(newProjectDto().setKey("another-key"));
componentDb.indexAllComponents();

String result = ws.newRequest()
String result = newRequest()
.setParam(TEXT_QUERY, "project-key")
.execute().getInput();
.execute()
.outputAsString();

assertThat(result).contains("project-key")
.doesNotContain("another-key");
}

@Test
public void handle_more_than_1000_projects() {
public void handle_more_than_1000_projects() throws Exception {
for (int i = 1; i <= 1001; i++) {
componentDb.insertProjectAndSnapshot(newProjectDto("project-uuid-" + i));
}
componentDb.indexAllComponents();

String result = ws.newRequest()
String result = newRequest()
.setParam(TEXT_QUERY, "project")
.setParam(PAGE_SIZE, "1001")
.execute().getInput();
.execute()
.outputAsString();

assertThat(result).contains("project-uuid-1", "project-uuid-999", "project-uuid-1001");
}

@Test
public void result_depends_of_root_types() {
resourceTypes.setRootQualifiers(Qualifiers.PROJECT);
insertComponent(newView("view-uuid"));
insertComponent(newDeveloper("developer-name"));
insertComponent(newProjectDto("project-uuid"));
commit();
dataLoader = new SearchProjectPermissionsDataLoader(dbClient,
new PermissionDependenciesFinder(dbClient, new ComponentFinder(dbClient), new UserGroupFinder(dbClient), resourceTypes),
resourceTypes);
underTest = new SearchProjectPermissionsAction(dbClient, userSession, i18n, resourceTypes, dataLoader);
ws = new WsActionTester(underTest);

String result = ws.newRequest().execute().getInput();

assertThat(result).contains("project-uuid")
.doesNotContain("view-uuid")
.doesNotContain("developer-name");
}
public void filter_by_qualifier() throws Exception {
db.components().insertComponent(newView("view-uuid"));
db.components().insertComponent(newDeveloper("developer-name"));
db.components().insertComponent(newProjectDto("project-uuid"));

@Test
public void filter_by_qualifier() throws IOException {
insertComponent(newView("view-uuid"));
insertComponent(newDeveloper("developer-name"));
insertComponent(newProjectDto("project-uuid"));
commit();

TestResponse wsResponse = ws.newRequest()
byte[] wsResponse = newRequest()
.setMediaType(MediaTypes.PROTOBUF)
.setParam(PARAM_QUALIFIER, Qualifiers.PROJECT)
.execute();
SearchProjectPermissionsWsResponse result = SearchProjectPermissionsWsResponse.parseFrom(wsResponse.getInputStream());
.execute()
.output();
WsPermissions.SearchProjectPermissionsWsResponse result = WsPermissions.SearchProjectPermissionsWsResponse.parseFrom(wsResponse);

assertThat(result.getProjectsList())
.extracting("id")
@@ -263,24 +215,26 @@ public class SearchProjectPermissionsActionTest {
}

@Test
public void fail_if_not_logged_in() {
expectedException.expect(UnauthorizedException.class);
public void fail_if_not_logged_in() throws Exception {
userSession.anonymous();

ws.newRequest().execute();
expectedException.expect(UnauthorizedException.class);

newRequest().execute();
}

@Test
public void fail_if_not_admin() {
expectedException.expect(ForbiddenException.class);
public void fail_if_not_admin() throws Exception {
userSession.login();

ws.newRequest().execute();
expectedException.expect(ForbiddenException.class);

newRequest().execute();
}

@Test
public void display_all_project_permissions() {
String result = ws.newRequest().execute().getInput();
public void display_all_project_permissions() throws Exception {
String result = newRequest().execute().outputAsString();

assertJson(result)
.ignoreFields("permissions")
@@ -288,58 +242,37 @@ public class SearchProjectPermissionsActionTest {
}

private ComponentDto insertView() {
return insertComponent(newView()
return db.components().insertComponent(newView()
.setUuid("752d8bfd-420c-4a83-a4e5-8ab19b13c8fc")
.setName("Java")
.setKey("Java"));
}

private ComponentDto insertProjectInView(ComponentDto project, ComponentDto view) {
return insertComponent(newProjectCopy("project-in-view-uuid", project, view));
return db.components().insertComponent(newProjectCopy("project-in-view-uuid", project, view));
}

private ComponentDto insertDeveloper() {
return insertComponent(newDeveloper("Simon Brandhof")
return db.components().insertComponent(newDeveloper("Simon Brandhof")
.setUuid("4e607bf9-7ed0-484a-946d-d58ba7dab2fb")
.setKey("simon-brandhof"));
}

private ComponentDto insertClang() {
return insertComponent(newProjectDto("project-uuid-2")
return db.components().insertComponent(newProjectDto("project-uuid-2")
.setName("Clang")
.setKey("clang")
.setUuid("ce4c03d6-430f-40a9-b777-ad877c00aa4d"));
}

private ComponentDto insertJdk7() {
return insertComponent(newProjectDto("project-uuid-1")
return db.components().insertComponent(newProjectDto("project-uuid-1")
.setName("JDK 7")
.setKey("net.java.openjdk:jdk7")
.setUuid("0bd7b1e7-91d6-439e-a607-4a3a9aad3c6a"));
}

private UserDto insertUser(UserDto user) {
return dbClient.userDao().insert(dbSession, user.setActive(true));
}

private void insertUserPermission(String permission, long userId, @Nullable Long resourceId) {
dbClient.userPermissionDao().insert(dbSession, new UserPermissionDto(permission, userId, resourceId));
}

private GroupDto insertGroup(GroupDto group) {
return dbClient.groupDao().insert(dbSession, group);
}

private void insertGroupRole(String permission, @Nullable Long resourceId, @Nullable Long groupId) {
dbClient.roleDao().insertGroupRole(dbSession, new GroupPermissionDto().setRole(permission).setResourceId(resourceId).setGroupId(groupId));
}

private ComponentDto insertComponent(ComponentDto component) {
dbClient.componentDao().insert(dbSession, component.setEnabled(true));
return dbClient.componentDao().selectOrFailByUuid(dbSession, component.uuid());
}

private void commit() {
dbSession.commit();
private WsTester.TestRequest newRequest() {
return wsTester.newPostRequest(CONTROLLER, "search_project_permissions");
}
}

+ 6
- 7
server/sonar-server/src/test/java/org/sonar/server/permission/ws/SearchProjectPermissionsDataTest.java View File

@@ -25,7 +25,6 @@ import java.util.Collections;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.db.component.ComponentDto;

public class SearchProjectPermissionsDataTest {
@Rule
@@ -36,8 +35,8 @@ public class SearchProjectPermissionsDataTest {
expectedException.expect(IllegalStateException.class);

SearchProjectPermissionsData.newBuilder()
.groupCountByProjectIdAndPermission(HashBasedTable.<Long, String, Integer>create())
.userCountByProjectIdAndPermission(HashBasedTable.<Long, String, Integer>create())
.groupCountByProjectIdAndPermission(HashBasedTable.create())
.userCountByProjectIdAndPermission(HashBasedTable.create())
.build();
}

@@ -46,8 +45,8 @@ public class SearchProjectPermissionsDataTest {
expectedException.expect(IllegalStateException.class);

SearchProjectPermissionsData.newBuilder()
.rootComponents(Collections.<ComponentDto>emptyList())
.userCountByProjectIdAndPermission(HashBasedTable.<Long, String, Integer>create())
.rootComponents(Collections.emptyList())
.userCountByProjectIdAndPermission(HashBasedTable.create())
.build();
}

@@ -56,8 +55,8 @@ public class SearchProjectPermissionsDataTest {
expectedException.expect(IllegalStateException.class);

SearchProjectPermissionsData.newBuilder()
.rootComponents(Collections.<ComponentDto>emptyList())
.groupCountByProjectIdAndPermission(HashBasedTable.<Long, String, Integer>create())
.rootComponents(Collections.emptyList())
.groupCountByProjectIdAndPermission(HashBasedTable.create())
.build();
}
}

+ 0
- 358
server/sonar-server/src/test/java/org/sonar/server/permission/ws/TemplateUsersActionTest.java View File

@@ -1,358 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.permission.ws;

import java.io.IOException;
import java.io.InputStream;
import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.component.ResourceTypesRule;
import org.sonar.db.permission.template.PermissionTemplateDto;
import org.sonar.db.permission.template.PermissionTemplateUserDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.exceptions.BadRequestException;
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.usergroups.ws.UserGroupFinder;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;
import org.sonarqube.ws.WsPermissions;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.api.web.UserRole.ADMIN;
import static org.sonar.api.web.UserRole.CODEVIEWER;
import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
import static org.sonar.api.web.UserRole.USER;
import static org.sonar.db.permission.template.PermissionTemplateTesting.newPermissionTemplateDto;
import static org.sonar.db.permission.template.PermissionTemplateTesting.newPermissionTemplateUserDto;
import static org.sonar.test.JsonAssert.assertJson;
import static org.sonarqube.ws.MediaTypes.PROTOBUF;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_NAME;

public class TemplateUsersActionTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule
public UserSessionRule userSession = UserSessionRule.standalone();
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);

ResourceTypesRule resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT, Qualifiers.VIEW, "DEV");

DbClient dbClient = db.getDbClient();
DbSession dbSession = db.getSession();

PermissionDependenciesFinder dependenciesFinder = new PermissionDependenciesFinder(dbClient, new ComponentFinder(dbClient), new UserGroupFinder(dbClient), resourceTypes);

TemplateUsersAction underTest = new TemplateUsersAction(dbClient, userSession, dependenciesFinder);
WsActionTester ws = new WsActionTester(underTest);

@Test
public void search_for_users_with_response_example() {
setSysAdminUser();

UserDto user1 = insertUser(new UserDto().setLogin("admin").setName("Administrator").setEmail("admin@admin.com"));
UserDto user2 = insertUser(new UserDto().setLogin("george.orwell").setName("George Orwell").setEmail("george.orwell@1984.net"));

PermissionTemplateDto template1 = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1"));

addUserToTemplate(newPermissionTemplateUser(CODEVIEWER, template1.getId(), user1.getId()));
addUserToTemplate(newPermissionTemplateUser(CODEVIEWER, template1.getId(), user2.getId()));
addUserToTemplate(newPermissionTemplateUser(ADMIN, template1.getId(), user2.getId()));

commit();

String result = newRequest(null, template1.getUuid()).execute().getInput();
assertJson(result).isSimilarTo(getClass().getResource("template_users-example.json"));
}

@Test
public void search_for_users_by_template_name() throws IOException {
setSysAdminUser();

UserDto user1 = insertUser(new UserDto().setLogin("login-1").setName("name-1").setEmail("email-1"));
UserDto user2 = insertUser(new UserDto().setLogin("login-2").setName("name-2").setEmail("email-2"));
UserDto user3 = insertUser(new UserDto().setLogin("login-3").setName("name-3").setEmail("email-3"));

PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1"));
addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user1.getId()));
addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user2.getId()));
addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user1.getId()));
addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user3.getId()));

PermissionTemplateDto anotherTemplate = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-2"));
addUserToTemplate(newPermissionTemplateUser(USER, anotherTemplate.getId(), user1.getId()));
commit();

InputStream responseStream = newRequest(null, null)
.setParam(PARAM_TEMPLATE_NAME, template.getName())
.setMediaType(PROTOBUF)
.execute().getInputStream();

WsPermissions.UsersWsResponse response = WsPermissions.UsersWsResponse.parseFrom(responseStream);
assertThat(response.getUsersList()).extracting("login").containsExactly("login-1", "login-2", "login-3");
assertThat(response.getUsers(0).getPermissionsList()).containsOnly("issueadmin", "user");
assertThat(response.getUsers(1).getPermissionsList()).containsOnly("user");
assertThat(response.getUsers(2).getPermissionsList()).containsOnly("issueadmin");
}

@Test
public void search_using_text_query() throws IOException {
setSysAdminUser();

UserDto user1 = insertUser(new UserDto().setLogin("login-1").setName("name-1").setEmail("email-1"));
UserDto user2 = insertUser(new UserDto().setLogin("login-2").setName("name-2").setEmail("email-2"));
UserDto user3 = insertUser(new UserDto().setLogin("login-3").setName("name-3").setEmail("email-3"));

PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1"));
addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user1.getId()));
addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user2.getId()));
addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user1.getId()));
addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user3.getId()));

PermissionTemplateDto anotherTemplate = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-2"));
addUserToTemplate(newPermissionTemplateUser(USER, anotherTemplate.getId(), user1.getId()));
commit();

InputStream responseStream = newRequest(null, null)
.setParam(PARAM_TEMPLATE_NAME, template.getName())
.setParam(WebService.Param.TEXT_QUERY, "ame-1")
.setMediaType(PROTOBUF)
.execute().getInputStream();

WsPermissions.UsersWsResponse response = WsPermissions.UsersWsResponse.parseFrom(responseStream);
assertThat(response.getUsersList()).extracting("login").containsOnly("login-1");
}

@Test
public void search_using_permission() throws IOException {
setSysAdminUser();

UserDto user1 = insertUser(new UserDto().setLogin("login-1").setName("name-1").setEmail("email-1"));
UserDto user2 = insertUser(new UserDto().setLogin("login-2").setName("name-2").setEmail("email-2"));
UserDto user3 = insertUser(new UserDto().setLogin("login-3").setName("name-3").setEmail("email-3"));

PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1"));
addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user1.getId()));
addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user2.getId()));
addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user1.getId()));
addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user3.getId()));

PermissionTemplateDto anotherTemplate = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-2"));
addUserToTemplate(newPermissionTemplateUser(USER, anotherTemplate.getId(), user1.getId()));
commit();

InputStream responseStream = newRequest(USER, template.getUuid())
.setMediaType(PROTOBUF)
.execute().getInputStream();
WsPermissions.UsersWsResponse response = WsPermissions.UsersWsResponse.parseFrom(responseStream);
assertThat(response.getUsersList()).extracting("login").containsExactly("login-1", "login-2");
assertThat(response.getUsers(0).getPermissionsList()).containsOnly("issueadmin", "user");
assertThat(response.getUsers(1).getPermissionsList()).containsOnly("user");
}

@Test
public void search_with_pagination() throws IOException {
setSysAdminUser();

UserDto user1 = insertUser(new UserDto().setLogin("login-1").setName("name-1").setEmail("email-1"));
UserDto user2 = insertUser(new UserDto().setLogin("login-2").setName("name-2").setEmail("email-2"));
UserDto user3 = insertUser(new UserDto().setLogin("login-3").setName("name-3").setEmail("email-3"));

PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1"));
addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user1.getId()));
addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user2.getId()));
addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user1.getId()));
addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user3.getId()));

PermissionTemplateDto anotherTemplate = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-2"));
addUserToTemplate(newPermissionTemplateUser(USER, anotherTemplate.getId(), user1.getId()));
commit();

InputStream responseStream = newRequest(USER, null)
.setParam(PARAM_TEMPLATE_NAME, template.getName())
.setParam(WebService.Param.SELECTED, "all")
.setParam(WebService.Param.PAGE, "2")
.setParam(WebService.Param.PAGE_SIZE, "1")
.setMediaType(PROTOBUF)
.execute().getInputStream();

WsPermissions.UsersWsResponse response = WsPermissions.UsersWsResponse.parseFrom(responseStream);
assertThat(response.getUsersList()).extracting("login").containsOnly("login-2");
}

@Test
public void users_are_sorted_by_name() throws IOException {
setSysAdminUser();

UserDto user1 = insertUser(new UserDto().setLogin("login-2").setName("name-2"));
UserDto user2 = insertUser(new UserDto().setLogin("login-3").setName("name-3"));
UserDto user3 = insertUser(new UserDto().setLogin("login-1").setName("name-1"));

PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1"));
addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user1.getId()));
addUserToTemplate(newPermissionTemplateUser(USER, template.getId(), user2.getId()));
addUserToTemplate(newPermissionTemplateUser(ISSUE_ADMIN, template.getId(), user3.getId()));
commit();

InputStream responseStream = newRequest(null, null)
.setParam(PARAM_TEMPLATE_NAME, template.getName())
.setMediaType(PROTOBUF)
.execute().getInputStream();

WsPermissions.UsersWsResponse response = WsPermissions.UsersWsResponse.parseFrom(responseStream);
assertThat(response.getUsersList()).extracting("login").containsExactly("login-1", "login-2", "login-3");
}

@Test
public void empty_result_when_no_user_on_template() throws IOException {
setSysAdminUser();

UserDto user = insertUser(new UserDto().setLogin("login-1").setName("name-1").setEmail("email-1"));

PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1"));

PermissionTemplateDto anotherTemplate = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-2"));
addUserToTemplate(newPermissionTemplateUser(USER, anotherTemplate.getId(), user.getId()));
commit();

InputStream responseStream = newRequest(null, null)
.setParam(PARAM_TEMPLATE_NAME, template.getName())
.setMediaType(PROTOBUF)
.execute().getInputStream();

WsPermissions.UsersWsResponse response = WsPermissions.UsersWsResponse.parseFrom(responseStream);
assertThat(response.getUsersList()).isEmpty();
}

@Test
public void fail_if_not_a_project_permission() throws IOException {
setSysAdminUser();

PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1"));
commit();

expectedException.expect(BadRequestException.class);
newRequest(GlobalPermissions.PROVISIONING, template.getUuid())
.execute();
}

@Test
public void fail_if_no_template_param() {
setSysAdminUser();

expectedException.expect(BadRequestException.class);
newRequest(null, null)
.execute();
}

@Test
public void fail_if_template_does_not_exist() {
setSysAdminUser();

expectedException.expect(NotFoundException.class);
newRequest(null, "unknown-template-uuid")
.execute();
}

@Test
public void fail_if_template_uuid_and_name_provided() {
setSysAdminUser();

PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1"));
commit();

expectedException.expect(BadRequestException.class);
newRequest(null, template.getUuid())
.setParam(PARAM_TEMPLATE_NAME, template.getName())
.execute();
}

@Test
public void fail_if_not_logged_in() {
userSession.anonymous();

PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1"));
commit();

expectedException.expect(UnauthorizedException.class);
newRequest(null, template.getUuid()).execute();
}

@Test
public void fail_if_insufficient_privileges() {
userSession.login("login");

PermissionTemplateDto template = dbClient.permissionTemplateDao().insert(dbSession, newPermissionTemplateDto().setUuid("template-uuid-1"));
commit();

expectedException.expect(ForbiddenException.class);
newRequest(null, template.getUuid()).execute();
}

private UserDto insertUser(UserDto userDto) {
return dbClient.userDao().insert(dbSession, userDto.setActive(true));
}

private void addUserToTemplate(PermissionTemplateUserDto dto) {
dbClient.permissionTemplateDao().insertUserPermission(dbSession, dto.getTemplateId(), dto.getUserId(), dto.getPermission());
}

private void commit() {
dbSession.commit();
}

private static PermissionTemplateUserDto newPermissionTemplateUser(String permission, long permissionTemplateId, long userId) {
return newPermissionTemplateUserDto()
.setPermission(permission)
.setTemplateId(permissionTemplateId)
.setUserId(userId);
}

private TestRequest newRequest(@Nullable String permission, @Nullable String templateUuid) {
TestRequest request = ws.newRequest();
if (permission != null) {
request.setParam(PARAM_PERMISSION, permission);
}
if (templateUuid != null) {
request.setParam(PARAM_TEMPLATE_ID, templateUuid);
}
return request;
}

private void setSysAdminUser() {
userSession.login("login").setGlobalPermissions(ADMIN);
}
}

+ 97
- 130
server/sonar-server/src/test/java/org/sonar/server/permission/ws/UsersActionTest.java View File

@@ -19,32 +19,16 @@
*/
package org.sonar.server.permission.ws;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.server.ws.WebService.SelectionMode;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ResourceTypesRule;
import org.sonar.db.permission.PermissionDbTester;
import org.sonar.db.permission.UserPermissionDto;
import org.sonar.db.user.UserDbTester;
import org.sonar.db.user.UserDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.UnauthorizedException;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.usergroups.ws.UserGroupFinder;
import org.sonar.server.ws.WsActionTester;
import org.sonar.server.ws.WsTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY;
@@ -56,86 +40,64 @@ import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
import static org.sonar.db.component.ComponentTesting.newProjectDto;
import static org.sonar.db.user.UserTesting.newUserDto;
import static org.sonar.test.JsonAssert.assertJson;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.CONTROLLER;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_KEY;

public class UsersActionTest {
public class UsersActionTest extends BasePermissionWsTest<UsersAction> {

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Rule
public UserSessionRule userSession = UserSessionRule.standalone();

@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
DbClient dbClient = db.getDbClient();
DbSession dbSession = db.getSession();

UserDbTester userDb = new UserDbTester(db);
PermissionDbTester permissionDb = new PermissionDbTester(db);
ComponentDbTester componentDbTester = new ComponentDbTester(db);

WsActionTester ws;
ResourceTypesRule resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT, Qualifiers.VIEW, "DEV");

UsersAction underTest;

@Before
public void setUp() {
PermissionDependenciesFinder dependenciesFinder = new PermissionDependenciesFinder(dbClient, new ComponentFinder(dbClient), new UserGroupFinder(dbClient), resourceTypes);
underTest = new UsersAction(dbClient, userSession, dependenciesFinder);
ws = new WsActionTester(underTest);

userSession.login("login").setGlobalPermissions(SYSTEM_ADMIN);
@Override
protected UsersAction buildWsAction() {
return new UsersAction(db.getDbClient(), userSession, newPermissionWsSupport());
}

@Test
public void search_for_users_with_response_example() {
UserDto user2 = userDb.insertUser(new UserDto().setLogin("george.orwell").setName("George Orwell").setEmail("george.orwell@1984.net"));
UserDto user1 = userDb.insertUser(new UserDto().setLogin("admin").setName("Administrator").setEmail("admin@admin.com"));
permissionDb.addGlobalPermissionToUser(SCAN_EXECUTION, user2.getId());
permissionDb.addGlobalPermissionToUser(SYSTEM_ADMIN, user1.getId());
permissionDb.addGlobalPermissionToUser(QUALITY_GATE_ADMIN, user1.getId());
permissionDb.addGlobalPermissionToUser(QUALITY_PROFILE_ADMIN, user1.getId());
public void search_for_users_with_response_example() throws Exception {
UserDto user1 = db.users().insertUser(newUserDto().setLogin("admin").setName("Administrator").setEmail("admin@admin.com"));
UserDto user2 = db.users().insertUser(newUserDto().setLogin("george.orwell").setName("George Orwell").setEmail("george.orwell@1984.net"));
db.users().insertPermissionOnUser(user1, SYSTEM_ADMIN);
db.users().insertPermissionOnUser(user1, QUALITY_GATE_ADMIN);
db.users().insertPermissionOnUser(user1, QUALITY_PROFILE_ADMIN);
db.users().insertPermissionOnUser(user2, SCAN_EXECUTION);

String result = ws.newRequest().execute().getInput();
loginAsAdmin();
String result = newRequest().execute().outputAsString();

assertJson(result).withStrictArrayOrder().isSimilarTo(getClass().getResource("users-example.json"));
}

@Test
public void search_for_users_with_one_permission() {
public void search_for_users_with_one_permission() throws Exception {
insertUsersHavingGlobalPermissions();
String result = ws.newRequest().setParam("permission", "scan").execute().getInput();

loginAsAdmin();
String result = newRequest().setParam("permission", "scan").execute().outputAsString();

assertJson(result).withStrictArrayOrder().isSimilarTo(getClass().getResource("UsersActionTest/users.json"));
}

@Test
public void search_for_users_with_permission_on_project() {
userSession.login().addProjectUuidPermissions(SYSTEM_ADMIN, "project-uuid");

// User have permission on project
ComponentDto project = componentDbTester.insertComponent(newProjectDto("project-uuid").setKey("project-key"));
UserDto user = userDb.insertUser(newUserDto());
insertUserPermission(new UserPermissionDto(ISSUE_ADMIN, user.getId(), project.getId()));
public void search_for_users_with_permission_on_project() throws Exception {
// User has permission on project
ComponentDto project = db.components().insertComponent(newProjectDto());
UserDto user = db.users().insertUser(newUserDto());
db.users().insertProjectPermissionOnUser(user, ISSUE_ADMIN, project);

// User have permission on another project
ComponentDto anotherProject = componentDbTester.insertComponent(newProjectDto());
UserDto userHavePermissionOnAnotherProject = userDb.insertUser(newUserDto());
insertUserPermission(new UserPermissionDto(ISSUE_ADMIN, userHavePermissionOnAnotherProject.getId(), anotherProject.getId()));
// User has permission on another project
ComponentDto anotherProject = db.components().insertComponent(newProjectDto());
UserDto userHavePermissionOnAnotherProject = db.users().insertUser(newUserDto());
db.users().insertProjectPermissionOnUser(userHavePermissionOnAnotherProject, ISSUE_ADMIN, anotherProject);

// User has no permission
UserDto withoutPermission = userDb.insertUser(newUserDto());

dbSession.commit();
UserDto withoutPermission = db.users().insertUser(newUserDto());

String result = ws.newRequest()
userSession.login().addProjectUuidPermissions(SYSTEM_ADMIN, project.uuid());
String result = newRequest()
.setParam(PARAM_PERMISSION, ISSUE_ADMIN)
.setParam(PARAM_PROJECT_ID, "project-uuid")
.execute().getInput();
.setParam(PARAM_PROJECT_ID, project.uuid())
.execute()
.outputAsString();

assertThat(result).contains(user.getLogin())
.doesNotContain(userHavePermissionOnAnotherProject.getLogin())
@@ -143,46 +105,42 @@ public class UsersActionTest {
}

@Test
public void search_only_for_users_with_permission_when_no_search_query() {
userSession.login().setGlobalPermissions(SYSTEM_ADMIN);

public void search_only_for_users_with_permission_when_no_search_query() throws Exception {
// User have permission on project
ComponentDto project = componentDbTester.insertComponent(newProjectDto());
UserDto user = userDb.insertUser(newUserDto());
insertUserPermission(new UserPermissionDto(ISSUE_ADMIN, user.getId(), project.getId()));
ComponentDto project = db.components().insertComponent(newProjectDto());
UserDto user = db.users().insertUser(newUserDto());
db.users().insertProjectPermissionOnUser(user, ISSUE_ADMIN, project);

// User has no permission
UserDto withoutPermission = userDb.insertUser(newUserDto());

dbSession.commit();
UserDto withoutPermission = db.users().insertUser(newUserDto());

String result = ws.newRequest()
loginAsAdmin();
String result = newRequest()
.setParam(PARAM_PROJECT_ID, project.uuid())
.execute().getInput();
.execute()
.outputAsString();

assertThat(result).contains(user.getLogin())
.doesNotContain(withoutPermission.getLogin());
}

@Test
public void search_also_for_users_without_permission_when_search_query() {
userSession.login().setGlobalPermissions(SYSTEM_ADMIN);

public void search_also_for_users_without_permission_when_search_query() throws Exception {
// User with permission on project
ComponentDto project = componentDbTester.insertComponent(newProjectDto());
UserDto user = userDb.insertUser(newUserDto("with-permission", "with-permission", null));
insertUserPermission(new UserPermissionDto(ISSUE_ADMIN, user.getId(), project.getId()));
ComponentDto project = db.components().insertComponent(newProjectDto());
UserDto user = db.users().insertUser(newUserDto("with-permission", "with-permission", null));
db.users().insertProjectPermissionOnUser(user, ISSUE_ADMIN, project);

// User without permission
UserDto withoutPermission = userDb.insertUser(newUserDto("without-permission", "without-permission", null));
UserDto anotherUser = userDb.insertUser(newUserDto("another-user", "another-user", null));

dbSession.commit();
UserDto withoutPermission = db.users().insertUser(newUserDto("without-permission", "without-permission", null));
UserDto anotherUser = db.users().insertUser(newUserDto("another-user", "another-user", null));

String result = ws.newRequest()
loginAsAdmin();
String result = newRequest()
.setParam(PARAM_PROJECT_ID, project.uuid())
.setParam(TEXT_QUERY, "with")
.execute().getInput();
.execute()
.outputAsString();

assertThat(result).contains(user.getLogin())
.contains(withoutPermission.getLogin())
@@ -190,12 +148,15 @@ public class UsersActionTest {
}

@Test
public void search_for_users_with_query_as_a_parameter() {
public void search_for_users_with_query_as_a_parameter() throws Exception {
insertUsersHavingGlobalPermissions();
String result = ws.newRequest()

loginAsAdmin();
String result = newRequest()
.setParam("permission", "scan")
.setParam(TEXT_QUERY, "ame-1")
.execute().getInput();
.execute()
.outputAsString();

assertThat(result).contains("login-1")
.doesNotContain("login-2")
@@ -203,52 +164,60 @@ public class UsersActionTest {
}

@Test
public void search_for_users_with_select_as_a_parameter() {
public void search_for_users_with_select_as_a_parameter() throws Exception {
insertUsersHavingGlobalPermissions();
String result = ws.newRequest()
.execute().getInput();

loginAsAdmin();
String result = newRequest()
.execute()
.outputAsString();

assertThat(result).contains("login-1", "login-2", "login-3");
}

@Test
public void fail_if_project_permission_without_project() {
public void fail_if_project_permission_without_project() throws Exception {
loginAsAdmin();

expectedException.expect(BadRequestException.class);

ws.newRequest()
newRequest()
.setParam(PARAM_PERMISSION, UserRole.ISSUE_ADMIN)
.setParam(Param.SELECTED, SelectionMode.ALL.value())
.execute();
}

@Test
public void fail_if_insufficient_privileges() {
expectedException.expect(ForbiddenException.class);
public void fail_if_insufficient_privileges() throws Exception {
userSession.login("login");

ws.newRequest()
expectedException.expect(ForbiddenException.class);

newRequest()
.setParam("permission", SYSTEM_ADMIN)
.execute();
}

@Test
public void fail_if_not_logged_in() {
expectedException.expect(UnauthorizedException.class);
public void fail_if_not_logged_in() throws Exception {
userSession.anonymous();

ws.newRequest()
expectedException.expect(UnauthorizedException.class);

newRequest()
.setParam("permission", SYSTEM_ADMIN)
.execute();
}

@Test
public void fail_if_project_uuid_and_project_key_are_provided() {
public void fail_if_project_uuid_and_project_key_are_provided() throws Exception {
db.components().insertComponent(newProjectDto("project-uuid").setKey("project-key"));
loginAsAdmin();

expectedException.expect(BadRequestException.class);
expectedException.expectMessage("Project id or project key can be provided, not both.");
dbClient.componentDao().insert(dbSession, newProjectDto("project-uuid").setKey("project-key"));
dbSession.commit();

ws.newRequest()
newRequest()
.setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
.setParam(PARAM_PROJECT_ID, "project-uuid")
.setParam(PARAM_PROJECT_KEY, "project-key")
@@ -256,31 +225,29 @@ public class UsersActionTest {
}

@Test
public void fail_if_search_query_is_too_short() {
public void fail_if_search_query_is_too_short() throws Exception {
loginAsAdmin();

expectedException.expect(BadRequestException.class);
expectedException.expectMessage("The 'q' parameter must have at least 3 characters");

ws.newRequest().setParam(TEXT_QUERY, "ab").execute();
newRequest().setParam(TEXT_QUERY, "ab").execute();
}

private UserDto insertUser(UserDto userDto) {
UserDto user = dbClient.userDao().insert(dbSession, userDto.setActive(true));
dbSession.commit();
return user;
private void insertUsersHavingGlobalPermissions() {
UserDto user1 = db.users().insertUser(newUserDto("login-1", "name-1", "email-1"));
UserDto user2 = db.users().insertUser(newUserDto("login-2", "name-2", "email-2"));
UserDto user3 = db.users().insertUser(newUserDto("login-3", "name-3", "email-3"));
db.users().insertPermissionOnUser(user1, SCAN_EXECUTION);
db.users().insertPermissionOnUser(user2, SCAN_EXECUTION);
db.users().insertPermissionOnUser(user3, SYSTEM_ADMIN);
}

private void insertUserPermission(UserPermissionDto userPermissionDto) {
dbClient.userPermissionDao().insert(dbSession, userPermissionDto);
dbSession.commit();
private WsTester.TestRequest newRequest() {
return wsTester.newPostRequest(CONTROLLER, "users");
}

private void insertUsersHavingGlobalPermissions() {
UserDto user3 = insertUser(new UserDto().setLogin("login-3").setName("name-3").setEmail("email-3"));
UserDto user2 = insertUser(new UserDto().setLogin("login-2").setName("name-2").setEmail("email-2"));
UserDto user1 = insertUser(new UserDto().setLogin("login-1").setName("name-1").setEmail("email-1"));
insertUserPermission(new UserPermissionDto(SCAN_EXECUTION, user1.getId(), null));
insertUserPermission(new UserPermissionDto(SYSTEM_ADMIN, user3.getId(), null));
insertUserPermission(new UserPermissionDto(SCAN_EXECUTION, user2.getId(), null));
dbSession.commit();
private void loginAsAdmin() {
userSession.login("login").setGlobalPermissions(SYSTEM_ADMIN);
}
}

+ 7
- 1
server/sonar-server/src/test/java/org/sonar/server/ws/WsTester.java View File

@@ -57,6 +57,7 @@ public class WsTester {

private final String method;
private String path;
private String mediaType = MediaTypes.JSON;

private Map<String, String> params = Maps.newHashMap();
private final Map<String, Part> parts = Maps.newHashMap();
@@ -72,7 +73,12 @@ public class WsTester {

@Override
public String getMediaType() {
return MediaTypes.JSON;
return mediaType;
}

public TestRequest setMediaType(String s) {
this.mediaType = s;
return this;
}

@Override

+ 11
- 0
sonar-ws/src/main/java/org/sonarqube/ws/client/permission/AddGroupWsRequest.java View File

@@ -27,6 +27,7 @@ import static java.util.Objects.requireNonNull;
public class AddGroupWsRequest {
private String permission;
private String groupId;
private String organizationKey;
private String groupName;
private String projectId;
private String projectKey;
@@ -50,6 +51,16 @@ public class AddGroupWsRequest {
return this;
}

@CheckForNull
public String getOrganizationKey() {
return organizationKey;
}

public AddGroupWsRequest setOrganizationKey(@Nullable String s) {
this.organizationKey = s;
return this;
}

@CheckForNull
public String getGroupName() {
return groupName;

+ 1
- 0
sonar-ws/src/main/java/org/sonarqube/ws/client/permission/PermissionsWsParameters.java View File

@@ -23,6 +23,7 @@ public class PermissionsWsParameters {
public static final String CONTROLLER = "api/permissions";

public static final String PARAM_PERMISSION = "permission";
public static final String PARAM_ORGANIZATION_KEY = "organization";
public static final String PARAM_GROUP_NAME = "groupName";
public static final String PARAM_GROUP_ID = "groupId";
public static final String PARAM_PROJECT_ID = "projectId";

Loading…
Cancel
Save