public int hashCode() {
return Objects.hash(uuid);
}
+
+ public <T extends EntityDto> T setPrivate(boolean aPrivate) {
+ isPrivate = aPrivate;
+ return (T) this;
+ }
}
return setKee(key);
}
+ @Override
public PortfolioDto setPrivate(boolean aPrivate) {
isPrivate = aPrivate;
return this;
return setKee(key);
}
+ @Override
public ProjectDto setPrivate(boolean aPrivate) {
isPrivate = aPrivate;
return this;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Arrays.stream;
+import static java.util.stream.Collectors.toSet;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.apache.commons.lang.math.RandomUtils.nextLong;
import static org.sonar.db.permission.GlobalPermission.ADMINISTER;
return insertPermissionOnAnyone(permission.getKey());
}
+ public Set<GroupPermissionDto> insertPermissionsOnGroup(GroupDto group, String... permissions) {
+ return stream(permissions)
+ .map(p -> insertPermissionOnGroup(group, p))
+ .collect(toSet());
+ }
+
public GroupPermissionDto insertPermissionOnGroup(GroupDto group, String permission) {
GroupPermissionDto dto = new GroupPermissionDto()
.setUuid(Uuids.createFast())
.setGroupUuid(group.getUuid())
.setRole(permission);
- db.getDbClient().groupPermissionDao().insert(db.getSession(), dto, (EntityDto) null, null);
+ db.getDbClient().groupPermissionDao().insert(db.getSession(), dto, null, null);
db.commit();
return dto;
}
return dto;
}
+ public Set<GroupPermissionDto> insertEntityPermissionsOnGroup(GroupDto group, EntityDto entity, String... permissions) {
+ return stream(permissions)
+ .map(permission -> insertEntityPermissionOnGroup(group, permission, entity))
+ .collect(toSet());
+ }
+
public GroupPermissionDto insertEntityPermissionOnGroup(GroupDto group, String permission, EntityDto entity) {
checkArgument(entity.isPrivate() || !PUBLIC_PERMISSIONS.contains(permission),
"%s can't be granted on a public entity (project or portfolio)", permission);
return db.getDbClient().userPermissionDao().selectEntityPermissionsOfUser(db.getSession(), user.getUuid(), entityUuid);
}
-
private static List<GlobalPermission> toListOfGlobalPermissions(List<String> keys) {
return keys
.stream()
this.indexers = indexers;
this.uuidFactory = uuidFactory;
}
- public void changeVisibility(String entityUuid, boolean isPrivate) {
- try (DbSession dbSession = dbClient.openSession(false)) {
- EntityDto entityDto = dbClient.entityDao().selectByUuid(dbSession, entityUuid)
- .orElseThrow(() -> new IllegalStateException("Component must be a project, a portfolio or an application"));
- changeVisibility(entityDto, isPrivate);
- }
- }
public void changeVisibility(EntityDto entityDto, boolean isPrivate) {
try (DbSession dbSession = dbClient.openSession(false)) {
if (entity.isProjectOrApp()) {
dbClient.projectDao().updateVisibility(dbSession, entity.getUuid(), newIsPrivate);
-
dbClient.branchDao().selectByProjectUuid(dbSession, entity.getUuid()).stream()
.filter(branch -> !branch.isMain())
.forEach(branch -> dbClient.componentDao().setPrivateForBranchUuidWithoutAuditLog(dbSession, branch.getUuid(), newIsPrivate));
} else {
dbClient.portfolioDao().updateVisibilityByPortfolioUuid(dbSession, entity.getUuid(), newIsPrivate);
}
+ entity.setPrivate(newIsPrivate);
}
private void updatePermissionsToPrivate(DbSession dbSession, EntityDto entity) {
*/
package org.sonar.server.permission;
+import java.util.Objects;
+import java.util.Optional;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
return uuid;
}
- public static GroupUuidOrAnyone from(GroupDto dto) {
- return new GroupUuidOrAnyone(dto.getUuid());
+ public static GroupUuidOrAnyone from(@Nullable GroupDto dto) {
+ String groupUuid = Optional.ofNullable(dto).map(GroupDto::getUuid).orElse(null);
+ return new GroupUuidOrAnyone(groupUuid);
}
public static GroupUuidOrAnyone forAnyone() {
return new GroupUuidOrAnyone(null);
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ GroupUuidOrAnyone that = (GroupUuidOrAnyone) o;
+ return Objects.equals(uuid, that.uuid);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(uuid);
+ }
}
*/
package org.sonar.server.permission;
+import java.util.Collections;
+import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Set;
import javax.annotation.concurrent.Immutable;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.ResourceTypes;
@Immutable
public class PermissionServiceImpl implements PermissionService {
- private static final List<String> ALL_PROJECT_PERMISSIONS = List.of(
+ public static final Set<String> ALL_PROJECT_PERMISSIONS = Collections.unmodifiableSet(new LinkedHashSet<>(List.of(
UserRole.ADMIN,
UserRole.CODEVIEWER,
UserRole.ISSUE_ADMIN,
UserRole.SECURITYHOTSPOT_ADMIN,
UserRole.SCAN,
UserRole.USER
- );
+ )));
private static final List<GlobalPermission> ALL_GLOBAL_PERMISSIONS = List.of(GlobalPermission.values());
*/
package org.sonar.server.permission;
+import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.junit.Before;
import org.junit.Rule;
import org.sonar.api.web.UserRole;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.core.util.Uuids;
+import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.component.ResourceTypesRule;
import org.sonar.db.permission.GlobalPermission;
@Test
public void apply_adds_global_permission_to_group() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
-
- apply(new GroupPermissionChange(PermissionChange.Operation.ADD, ADMINISTER_QUALITY_PROFILES.getKey(), null, groupUuid, permissionService));
+ apply(new GroupPermissionChange(PermissionChange.Operation.ADD, ADMINISTER_QUALITY_PROFILES.getKey(), null, group, permissionService));
assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(ADMINISTER_QUALITY_PROFILES.getKey());
}
@Test
public void apply_adds_global_permission_to_group_AnyOne() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
-
- apply(new GroupPermissionChange(PermissionChange.Operation.ADD, ADMINISTER_QUALITY_PROFILES.getKey(), null, groupUuid, permissionService));
+ apply(new GroupPermissionChange(PermissionChange.Operation.ADD, ADMINISTER_QUALITY_PROFILES.getKey(), null, null, permissionService));
assertThat(db.users().selectAnyonePermissions(null)).containsOnly(ADMINISTER_QUALITY_PROFILES.getKey());
}
@Test
public void apply_fails_with_BadRequestException_when_adding_any_permission_to_group_AnyOne_on_private_project() {
- GroupUuidOrAnyone anyOneGroup = GroupUuidOrAnyone.forAnyone();
permissionService.getAllProjectPermissions()
.forEach(perm -> {
- GroupPermissionChange change = new GroupPermissionChange(PermissionChange.Operation.ADD, perm, privateProject, anyOneGroup, permissionService);
+ GroupPermissionChange change = new GroupPermissionChange(PermissionChange.Operation.ADD, perm, privateProject, null, permissionService);
try {
apply(change);
fail("a BadRequestException should have been thrown");
permissionService.getAllProjectPermissions()
.forEach(this::unsafeInsertProjectPermissionOnAnyone);
- GroupUuidOrAnyone anyOneGroup = GroupUuidOrAnyone.forAnyone();
permissionService.getAllProjectPermissions()
.forEach(perm -> {
- apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, perm, privateProject, anyOneGroup, permissionService));
+ apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, perm, privateProject, null, permissionService));
assertThat(db.users().selectAnyonePermissions(privateProject.getUuid())).contains(perm);
});
}
private void applyAddsPermissionToGroupOnPrivateProject(String permission) {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
- apply(new GroupPermissionChange(PermissionChange.Operation.ADD, permission, privateProject, groupUuid, permissionService));
+ apply(new GroupPermissionChange(PermissionChange.Operation.ADD, permission, privateProject, group, permissionService));
assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
assertThat(db.users().selectGroupPermissions(group, privateProject)).containsOnly(permission);
}
private void applyRemovesPermissionFromGroupOnPrivateProject(String permission) {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
db.users().insertEntityPermissionOnGroup(group, permission, privateProject);
- apply(new GroupPermissionChange(PermissionChange.Operation.ADD, permission, privateProject, groupUuid, permissionService));
+ apply(new GroupPermissionChange(PermissionChange.Operation.ADD, permission, privateProject, group, permissionService), permission);
assertThat(db.users().selectGroupPermissions(group, privateProject)).containsOnly(permission);
}
@Test
public void apply_has_no_effect_when_adding_USER_permission_to_group_AnyOne_on_a_public_project() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
-
- apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.USER, publicProject, groupUuid, permissionService));
+ apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.USER, publicProject, null, permissionService));
assertThat(db.users().selectAnyonePermissions(publicProject.getUuid())).isEmpty();
}
@Test
public void apply_has_no_effect_when_adding_CODEVIEWER_permission_to_group_AnyOne_on_a_public_project() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
-
- apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.CODEVIEWER, publicProject, groupUuid, permissionService));
+ apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.CODEVIEWER, publicProject, null, permissionService));
assertThat(db.users().selectAnyonePermissions(publicProject.getUuid())).isEmpty();
}
@Test
public void apply_fails_with_BadRequestException_when_adding_permission_ADMIN_to_group_AnyOne_on_a_public_project() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
-
- assertThatThrownBy(() -> apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.ADMIN, publicProject, groupUuid, permissionService)))
+ GroupPermissionChange change = new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.ADMIN, publicProject, null, permissionService);
+ assertThatThrownBy(() -> apply(change))
.isInstanceOf(BadRequestException.class)
.hasMessage("It is not possible to add the 'admin' permission to group 'Anyone'.");
}
@Test
public void apply_adds_permission_ISSUE_ADMIN_to_group_AnyOne_on_a_public_project() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
-
- apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.ISSUE_ADMIN, publicProject, groupUuid, permissionService));
+ apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.ISSUE_ADMIN, publicProject, null, permissionService));
assertThat(db.users().selectAnyonePermissions(publicProject.getUuid())).containsOnly(UserRole.ISSUE_ADMIN);
}
@Test
public void apply_adds_permission_SCAN_EXECUTION_to_group_AnyOne_on_a_public_project() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
-
- apply(new GroupPermissionChange(PermissionChange.Operation.ADD, GlobalPermission.SCAN.getKey(), publicProject, groupUuid, permissionService));
+ apply(new GroupPermissionChange(PermissionChange.Operation.ADD, GlobalPermission.SCAN.getKey(), publicProject, null, permissionService));
assertThat(db.users().selectAnyonePermissions(publicProject.getUuid())).containsOnly(GlobalPermission.SCAN.getKey());
}
@Test
public void apply_fails_with_BadRequestException_when_removing_USER_permission_from_group_AnyOne_on_a_public_project() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
-
- assertThatThrownBy(() -> apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.USER, publicProject, groupUuid, permissionService)))
+ GroupPermissionChange change = new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.USER, publicProject, null, permissionService);
+ assertThatThrownBy(() -> apply(change))
.isInstanceOf(BadRequestException.class)
.hasMessage("Permission user can't be removed from a public component");
}
@Test
public void apply_fails_with_BadRequestException_when_removing_CODEVIEWER_permission_from_group_AnyOne_on_a_public_project() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
-
- assertThatThrownBy(() -> apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.CODEVIEWER, publicProject, groupUuid, permissionService)))
+ GroupPermissionChange change = new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.CODEVIEWER, publicProject, null, permissionService);
+ assertThatThrownBy(() -> apply(change))
.isInstanceOf(BadRequestException.class)
.hasMessage("Permission codeviewer can't be removed from a public component");
}
}
private void applyRemovesPermissionFromGroupAnyOneOnAPublicProject(String permission) {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
db.users().insertEntityPermissionOnAnyone(permission, publicProject);
- apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, permission, publicProject, groupUuid, permissionService));
+ apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, permission, publicProject, null, permissionService), permission);
assertThat(db.users().selectAnyonePermissions(publicProject.getUuid())).isEmpty();
}
@Test
public void apply_fails_with_BadRequestException_when_removing_USER_permission_from_a_group_on_a_public_project() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
-
- assertThatThrownBy(() -> apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.USER, publicProject, groupUuid, permissionService)))
+ GroupPermissionChange change = new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.USER, publicProject, group, permissionService);
+ assertThatThrownBy(() -> apply(change))
.isInstanceOf(BadRequestException.class)
.hasMessage("Permission user can't be removed from a public component");
}
@Test
public void apply_fails_with_BadRequestException_when_removing_CODEVIEWER_permission_from_a_group_on_a_public_project() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
-
- assertThatThrownBy(() -> apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.CODEVIEWER, publicProject, groupUuid, permissionService)))
+ GroupPermissionChange change = new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.CODEVIEWER, publicProject, group, permissionService);
+ assertThatThrownBy(() -> apply(change))
.isInstanceOf(BadRequestException.class)
.hasMessage("Permission codeviewer can't be removed from a public component");
}
@Test
public void add_permission_to_anyone() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
-
- apply(new GroupPermissionChange(PermissionChange.Operation.ADD, ADMINISTER_QUALITY_PROFILES.getKey(), null, groupUuid, permissionService));
+ apply(new GroupPermissionChange(PermissionChange.Operation.ADD, ADMINISTER_QUALITY_PROFILES.getKey(), null, null, permissionService));
assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
assertThat(db.users().selectAnyonePermissions(null)).containsOnly(ADMINISTER_QUALITY_PROFILES.getKey());
@Test
public void do_nothing_when_adding_permission_that_already_exists() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
db.users().insertPermissionOnGroup(group, ADMINISTER_QUALITY_GATES);
- apply(new GroupPermissionChange(PermissionChange.Operation.ADD, ADMINISTER_QUALITY_GATES.getKey(), null, groupUuid, permissionService));
+ apply(new GroupPermissionChange(PermissionChange.Operation.ADD, ADMINISTER_QUALITY_GATES.getKey(), null, group, permissionService));
assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(ADMINISTER_QUALITY_GATES.getKey());
}
@Test
public void fail_to_add_global_permission_but_SCAN_and_ADMIN_on_private_project() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
-
permissionService.getGlobalPermissions().stream()
.map(GlobalPermission::getKey)
.filter(perm -> !UserRole.ADMIN.equals(perm) && !GlobalPermission.SCAN.getKey().equals(perm))
.forEach(perm -> {
try {
- new GroupPermissionChange(PermissionChange.Operation.ADD, perm, privateProject, groupUuid, permissionService);
+ new GroupPermissionChange(PermissionChange.Operation.ADD, perm, privateProject, group, permissionService);
fail("a BadRequestException should have been thrown for permission " + perm);
} catch (BadRequestException e) {
assertThat(e).hasMessage("Invalid project permission '" + perm +
@Test
public void fail_to_add_global_permission_but_SCAN_and_ADMIN_on_public_project() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
-
permissionService.getGlobalPermissions().stream()
.map(GlobalPermission::getKey)
.filter(perm -> !UserRole.ADMIN.equals(perm) && !GlobalPermission.SCAN.getKey().equals(perm))
.forEach(perm -> {
try {
- new GroupPermissionChange(PermissionChange.Operation.ADD, perm, publicProject, groupUuid, permissionService);
+ new GroupPermissionChange(PermissionChange.Operation.ADD, perm, publicProject, group, permissionService);
fail("a BadRequestException should have been thrown for permission " + perm);
} catch (BadRequestException e) {
assertThat(e).hasMessage("Invalid project permission '" + perm +
@Test
public void fail_to_add_project_permission_but_SCAN_and_ADMIN_on_global_group() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
-
permissionService.getAllProjectPermissions()
.stream()
.filter(perm -> !GlobalPermission.SCAN.getKey().equals(perm) && !GlobalPermission.ADMINISTER.getKey().equals(perm))
.forEach(permission -> {
try {
- new GroupPermissionChange(PermissionChange.Operation.ADD, permission, null, groupUuid, permissionService);
+ new GroupPermissionChange(PermissionChange.Operation.ADD, permission, null, group, permissionService);
fail("a BadRequestException should have been thrown for permission " + permission);
} catch (BadRequestException e) {
assertThat(e).hasMessage("Invalid global permission '" + permission + "'. Valid values are [admin, gateadmin, profileadmin, provisioning, scan]");
@Test
public void remove_permission_from_group() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
db.users().insertPermissionOnGroup(group, ADMINISTER_QUALITY_GATES);
db.users().insertPermissionOnGroup(group, PROVISION_PROJECTS);
- apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, ADMINISTER_QUALITY_GATES.getKey(), null, groupUuid, permissionService));
+ apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, ADMINISTER_QUALITY_GATES.getKey(), null, group, permissionService), ADMINISTER_QUALITY_GATES.getKey(),
+ PROVISION_PROJECTS.getKey());
assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(PROVISION_PROJECTS.getKey());
}
@Test
public void remove_project_permission_from_group() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
db.users().insertPermissionOnGroup(group, ADMINISTER_QUALITY_GATES);
db.users().insertEntityPermissionOnGroup(group, UserRole.ISSUE_ADMIN, privateProject);
db.users().insertEntityPermissionOnGroup(group, UserRole.CODEVIEWER, privateProject);
- apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.ISSUE_ADMIN, privateProject, groupUuid, permissionService));
+ apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.ISSUE_ADMIN, privateProject, group, permissionService), UserRole.ISSUE_ADMIN,
+ UserRole.CODEVIEWER);
assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(ADMINISTER_QUALITY_GATES.getKey());
assertThat(db.users().selectGroupPermissions(group, privateProject)).containsOnly(UserRole.CODEVIEWER);
@Test
public void do_not_fail_if_removing_a_permission_that_does_not_exist() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
-
- apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.ISSUE_ADMIN, privateProject, groupUuid, permissionService));
+ apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.ISSUE_ADMIN, privateProject, group, permissionService));
assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
assertThat(db.users().selectGroupPermissions(group, privateProject)).isEmpty();
@Test
public void fail_to_remove_admin_permission_if_no_more_admins() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
db.users().insertPermissionOnGroup(group, ADMINISTER);
- assertThatThrownBy(() -> underTest.apply(db.getSession(), new GroupPermissionChange(PermissionChange.Operation.REMOVE, ADMINISTER.getKey(), null, groupUuid, permissionService)))
+ GroupPermissionChange change = new GroupPermissionChange(PermissionChange.Operation.REMOVE, ADMINISTER.getKey(), null, group, permissionService);
+ Set<String> permission = Set.of("admin");
+ DbSession session = db.getSession();
+ assertThatThrownBy(() -> underTest.apply(session, permission, change))
.isInstanceOf(BadRequestException.class)
.hasMessage("Last group with permission 'admin'. Permission cannot be removed.");
}
@Test
public void remove_admin_group_if_still_other_admins() {
- GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
db.users().insertPermissionOnGroup(group, ADMINISTER);
UserDto admin = db.users().insertUser();
db.users().insertGlobalPermissionOnUser(admin, ADMINISTER);
- apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, ADMINISTER.getKey(), null, groupUuid, permissionService));
+ apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, ADMINISTER.getKey(), null, group, permissionService), ADMINISTER.getKey());
assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
}
- private void apply(GroupPermissionChange change) {
- underTest.apply(db.getSession(), change);
+ private void apply(GroupPermissionChange change, String... existingPermissions) {
+ underTest.apply(db.getSession(), Set.of(existingPermissions), change);
db.commit();
}
return new PermissionUpdater(
new IndexersImpl(new PermissionIndexer(db.getDbClient(), es.client())),
new UserPermissionChanger(db.getDbClient(), new SequenceUuidFactory()),
- new GroupPermissionChanger(db.getDbClient(), new SequenceUuidFactory()));
+ new GroupPermissionChanger(db.getDbClient(), new SequenceUuidFactory()), db.getDbClient());
}
protected TestRequest newRequest() {
*/
package org.sonar.server.permission;
+import java.util.Optional;
import javax.annotation.Nullable;
import org.sonar.db.entity.EntityDto;
+import org.sonar.db.user.GroupDto;
public class GroupPermissionChange extends PermissionChange {
- private final GroupUuidOrAnyone group;
+ private final GroupDto groupDto;
public GroupPermissionChange(Operation operation, String permission, @Nullable EntityDto entityDto,
- GroupUuidOrAnyone group, PermissionService permissionService) {
+ @Nullable GroupDto groupDto, PermissionService permissionService) {
super(operation, permission, entityDto, permissionService);
- this.group = group;
+ this.groupDto = groupDto;
}
public GroupUuidOrAnyone getGroupUuidOrAnyone() {
- return group;
+ return GroupUuidOrAnyone.from(groupDto);
+ }
+
+ public Optional<String> getGroupName() {
+ return Optional.ofNullable(groupDto).map(GroupDto::getName);
}
}
*/
package org.sonar.server.permission;
-import java.util.List;
-import java.util.Optional;
+import java.util.Set;
import org.sonar.api.web.UserRole;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbClient;
import org.sonar.db.entity.EntityDto;
import org.sonar.db.permission.GlobalPermission;
import org.sonar.db.permission.GroupPermissionDto;
-import org.sonar.db.user.GroupDto;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.String.format;
this.uuidFactory = uuidFactory;
}
- public boolean apply(DbSession dbSession, GroupPermissionChange change) {
+ public boolean apply(DbSession dbSession, Set<String> existingPermissions, GroupPermissionChange change) {
ensureConsistencyWithVisibility(change);
if (isImplicitlyAlreadyDone(change)) {
return false;
}
switch (change.getOperation()) {
case ADD:
+ if (existingPermissions.contains(change.getPermission())) {
+ return false;
+ }
return addPermission(dbSession, change);
case REMOVE:
+ if (!existingPermissions.contains(change.getPermission())) {
+ return false;
+ }
return removePermission(dbSession, change);
default:
throw new UnsupportedOperationException("Unsupported permission change: " + change.getOperation());
}
private boolean addPermission(DbSession dbSession, GroupPermissionChange change) {
- if (loadExistingPermissions(dbSession, change).contains(change.getPermission())) {
- return false;
- }
-
validateNotAnyoneAndAdminPermission(change.getPermission(), change.getGroupUuidOrAnyone());
String groupUuid = change.getGroupUuidOrAnyone().getUuid();
+ String groupName = change.getGroupName().orElse(null);
+
GroupPermissionDto addedDto = new GroupPermissionDto()
.setUuid(uuidFactory.create())
.setRole(change.getPermission())
.setGroupUuid(groupUuid)
.setEntityName(change.getProjectName())
- .setEntityUuid(change.getProjectUuid());
-
- Optional.ofNullable(groupUuid)
- .map(uuid -> dbClient.groupDao().selectByUuid(dbSession, groupUuid))
- .map(GroupDto::getName)
- .ifPresent(addedDto::setGroupName);
+ .setEntityUuid(change.getProjectUuid())
+ .setGroupName(groupName);
dbClient.groupPermissionDao().insert(dbSession, addedDto, change.getEntity(), null);
return true;
}
private boolean removePermission(DbSession dbSession, GroupPermissionChange change) {
- if (!loadExistingPermissions(dbSession, change).contains(change.getPermission())) {
- return false;
- }
checkIfRemainingGlobalAdministrators(dbSession, change);
String groupUuid = change.getGroupUuidOrAnyone().getUuid();
- String groupName = Optional.ofNullable(groupUuid)
- .map(uuid -> dbClient.groupDao().selectByUuid(dbSession, uuid))
- .map(GroupDto::getName)
- .orElse(null);
-
+ String groupName = change.getGroupName().orElse(null);
dbClient.groupPermissionDao().delete(dbSession,
change.getPermission(),
groupUuid,
return true;
}
- private List<String> loadExistingPermissions(DbSession dbSession, GroupPermissionChange change) {
- String projectUuid = change.getProjectUuid();
- if (projectUuid != null) {
- return dbClient.groupPermissionDao().selectEntityPermissionsOfGroup(dbSession,
- change.getGroupUuidOrAnyone().getUuid(),
- projectUuid);
- }
- return dbClient.groupPermissionDao().selectGlobalPermissionsOfGroup(dbSession,
- change.getGroupUuidOrAnyone().getUuid());
- }
-
private void checkIfRemainingGlobalAdministrators(DbSession dbSession, GroupPermissionChange change) {
GroupUuidOrAnyone groupUuidOrAnyone = change.getGroupUuidOrAnyone();
if (GlobalPermission.ADMINISTER.getKey().equals(change.getPermission()) &&
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.server.es.Indexers;
+import static java.util.stream.Collectors.groupingBy;
+import static org.sonar.api.utils.Preconditions.checkState;
+import static org.sonar.server.es.Indexers.EntityEvent.PERMISSION_CHANGE;
+
/**
* Add or remove global/project permissions to a group. This class does not verify that caller has administration right on the related project.
*/
private final Indexers indexers;
private final UserPermissionChanger userPermissionChanger;
private final GroupPermissionChanger groupPermissionChanger;
+ private final DbClient dbClient;
public PermissionUpdater(Indexers indexers,
- UserPermissionChanger userPermissionChanger, GroupPermissionChanger groupPermissionChanger) {
+ UserPermissionChanger userPermissionChanger, GroupPermissionChanger groupPermissionChanger, DbClient dbClient) {
this.indexers = indexers;
this.userPermissionChanger = userPermissionChanger;
this.groupPermissionChanger = groupPermissionChanger;
+ this.dbClient = dbClient;
}
- public void apply(DbSession dbSession, Collection<PermissionChange> changes) {
+ public void applyForUser(DbSession dbSession, Collection<UserPermissionChange> changes) {
List<String> projectOrViewUuids = new ArrayList<>();
- for (PermissionChange change : changes) {
- boolean changed = doApply(dbSession, change);
+ for (UserPermissionChange change : changes) {
+ boolean changed = userPermissionChanger.apply(dbSession, change);
String projectUuid = change.getProjectUuid();
if (changed && projectUuid != null) {
projectOrViewUuids.add(projectUuid);
}
}
- indexers.commitAndIndexOnEntityEvent(dbSession, projectOrViewUuids, Indexers.EntityEvent.PERMISSION_CHANGE);
+ indexers.commitAndIndexOnEntityEvent(dbSession, projectOrViewUuids, PERMISSION_CHANGE);
}
- private boolean doApply(DbSession dbSession, PermissionChange change) {
- if (change instanceof UserPermissionChange userPermissionChange) {
- return userPermissionChanger.apply(dbSession, userPermissionChange);
- }
- if (change instanceof GroupPermissionChange groupPermissionChange) {
- return groupPermissionChanger.apply(dbSession, groupPermissionChange);
+ public void applyForGroups(DbSession dbSession, Collection<GroupPermissionChange> groupsPermissionChanges) {
+ checkState(groupsPermissionChanges.stream().map(PermissionChange::getProjectUuid).distinct().count() <= 1,
+ "Only one project per group of changes is supported");
+
+ List<String> projectOrViewUuids = new ArrayList<>();
+ Map<GroupUuidOrAnyone, List<GroupPermissionChange>> groupUuidToChanges = groupsPermissionChanges.stream().collect(groupingBy(GroupPermissionChange::getGroupUuidOrAnyone));
+ groupUuidToChanges.values().forEach(groupPermissionChanges -> applyForSingleGroup(dbSession, projectOrViewUuids, groupPermissionChanges));
+
+ indexers.commitAndIndexOnEntityEvent(dbSession, projectOrViewUuids, PERMISSION_CHANGE);
+ }
+
+ private void applyForSingleGroup(DbSession dbSession, List<String> projectOrViewUuids, List<GroupPermissionChange> groupPermissionChanges) {
+ GroupPermissionChange anyGroupPermissionChange = groupPermissionChanges.iterator().next();
+ Set<String> existingPermissions = loadExistingEntityPermissions(dbSession, anyGroupPermissionChange);
+ for (GroupPermissionChange groupPermissionChange : groupPermissionChanges) {
+ if (doApplyForGroup(dbSession, existingPermissions, groupPermissionChange) && groupPermissionChange.getProjectUuid() != null) {
+ projectOrViewUuids.add(groupPermissionChange.getProjectUuid());
+ }
}
- throw new UnsupportedOperationException("Unsupported permission change: " + change.getClass());
+ }
+ private boolean doApplyForGroup(DbSession dbSession, Set<String> existingPermissions, GroupPermissionChange change) {
+ return groupPermissionChanger.apply(dbSession, existingPermissions, change);
+ }
+
+ private Set<String> loadExistingEntityPermissions(DbSession dbSession, GroupPermissionChange change) {
+ String projectUuid = change.getProjectUuid();
+ String groupUuid = change.getGroupUuidOrAnyone().getUuid();
+ if (projectUuid != null) {
+ return new HashSet<>(dbClient.groupPermissionDao().selectEntityPermissionsOfGroup(dbSession, groupUuid, projectUuid));
+ }
+ return new HashSet<>(dbClient.groupPermissionDao().selectGlobalPermissionsOfGroup(dbSession, groupUuid));
}
}
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.entity.EntityDto;
+import org.sonar.db.user.GroupDto;
import org.sonar.server.permission.GroupPermissionChange;
-import org.sonar.server.permission.GroupUuidOrAnyone;
import org.sonar.server.permission.PermissionChange;
import org.sonar.server.permission.PermissionService;
import org.sonar.server.permission.PermissionUpdater;
@Override
public void handle(Request request, Response response) throws Exception {
try (DbSession dbSession = dbClient.openSession(false)) {
- GroupUuidOrAnyone group = wsSupport.findGroup(dbSession, request);
+ GroupDto groupDto = wsSupport.findGroupDtoOrNullIfAnyone(dbSession, request);
EntityDto project = wsSupport.findEntity(dbSession, request);
wsSupport.checkPermissionManagementAccess(userSession, project);
- PermissionChange change = new GroupPermissionChange(
+ GroupPermissionChange change = new GroupPermissionChange(
PermissionChange.Operation.ADD,
request.mandatoryParam(PARAM_PERMISSION),
project,
- group, permissionService);
- permissionUpdater.apply(dbSession, List.of(change));
+ groupDto,
+ permissionService);
+ permissionUpdater.applyForGroups(dbSession, List.of(change));
}
response.noContent();
}
checkProjectAdmin(userSession, configuration, entity);
UserId user = wsSupport.findUser(dbSession, userLogin);
- PermissionChange change = new UserPermissionChange(
+ UserPermissionChange change = new UserPermissionChange(
PermissionChange.Operation.ADD,
request.mandatoryParam(PARAM_PERMISSION),
entity,
user, permissionService);
- permissionUpdater.apply(dbSession, singletonList(change));
+ permissionUpdater.applyForUser(dbSession, singletonList(change));
}
response.noContent();
}
package org.sonar.server.permission.ws;
import java.util.Optional;
-import javax.annotation.CheckForNull;
import java.util.Set;
+import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.config.Configuration;
import org.sonar.api.resources.Qualifiers;
return null;
}
- public GroupUuidOrAnyone findGroup(DbSession dbSession, Request request) {
+ public GroupUuidOrAnyone findGroupUuidOrAnyone(DbSession dbSession, Request request) {
String groupName = request.mandatoryParam(PARAM_GROUP_NAME);
return groupWsSupport.findGroupOrAnyone(dbSession, groupName);
}
+ @CheckForNull
+ public GroupDto findGroupDtoOrNullIfAnyone(DbSession dbSession, Request request) {
+ String groupName = request.mandatoryParam(PARAM_GROUP_NAME);
+ return groupWsSupport.findGroupDtoOrNullIfAnyone(dbSession, groupName);
+ }
+
public UserId findUser(DbSession dbSession, String login) {
UserDto dto = ofNullable(dbClient.userDao().selectActiveUserByLogin(dbSession, login))
.orElseThrow(() -> new NotFoundException(format("User with login '%s' is not found'", login)));
}
public static boolean isUpdatingBrowsePermissionOnPrivateProject(String permission, @Nullable EntityDto entityDto) {
- return entityDto != null && entityDto.isPrivate() && permission.equals(UserRole.USER) ;
+ return entityDto != null && entityDto.isPrivate() && permission.equals(UserRole.USER);
}
}
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.entity.EntityDto;
+import org.sonar.db.user.GroupDto;
import org.sonar.server.permission.GroupPermissionChange;
import org.sonar.server.permission.GroupUuidOrAnyone;
import org.sonar.server.permission.PermissionChange;
private final PermissionService permissionService;
public RemoveGroupAction(DbClient dbClient, UserSession userSession, PermissionUpdater permissionUpdater, PermissionWsSupport wsSupport,
- WsParameters wsParameters, PermissionService permissionService) {
+ WsParameters wsParameters, PermissionService permissionService) {
this.dbClient = dbClient;
this.userSession = userSession;
this.permissionUpdater = permissionUpdater;
@Override
public void handle(Request request, Response response) throws Exception {
try (DbSession dbSession = dbClient.openSession(false)) {
- GroupUuidOrAnyone group = wsSupport.findGroup(dbSession, request);
EntityDto entity = wsSupport.findEntity(dbSession, request);
+ GroupDto groupDto = wsSupport.findGroupDtoOrNullIfAnyone(dbSession, request);
wsSupport.checkPermissionManagementAccess(userSession, entity);
String permission = request.mandatoryParam(PARAM_PERMISSION);
- wsSupport.checkRemovingOwnBrowsePermissionOnPrivateProject(dbSession, userSession, entity, permission, group);
+ wsSupport.checkRemovingOwnBrowsePermissionOnPrivateProject(dbSession, userSession, entity, permission, GroupUuidOrAnyone.from(groupDto));
- PermissionChange change = new GroupPermissionChange(
+ GroupPermissionChange change = new GroupPermissionChange(
PermissionChange.Operation.REMOVE,
permission,
entity,
- group,
+ groupDto,
permissionService);
- permissionUpdater.apply(dbSession, singletonList(change));
+ permissionUpdater.applyForGroups(dbSession, singletonList(change));
}
response.noContent();
}
EntityDto entity = wsSupport.findEntity(dbSession, request);
wsSupport.checkRemovingOwnBrowsePermissionOnPrivateProject(userSession, entity, permission, user);
wsSupport.checkPermissionManagementAccess(userSession, entity);
- PermissionChange change = new UserPermissionChange(
+ UserPermissionChange change = new UserPermissionChange(
PermissionChange.Operation.REMOVE,
permission,
entity,
user, permissionService);
- permissionUpdater.apply(dbSession, singletonList(change));
+ permissionUpdater.applyForUser(dbSession, singletonList(change));
response.noContent();
}
}
public void handle(Request request, Response response) {
try (DbSession dbSession = dbClient.openSession(false)) {
String permission = request.mandatoryParam(PARAM_PERMISSION);
- GroupUuidOrAnyone group = support.findGroup(dbSession, request);
+ GroupUuidOrAnyone group = support.findGroupUuidOrAnyone(dbSession, request);
checkRequest(!ADMINISTER.getKey().equals(permission) || !group.isAnyone(),
format("It is not possible to add the '%s' permission to the group 'Anyone'.", permission));
String permission = request.mandatoryParam(PARAM_PERMISSION);
PermissionTemplateDto template = wsSupport.findTemplate(dbSession, WsTemplateRef.fromRequest(request));
checkGlobalAdmin(userSession);
- GroupUuidOrAnyone group = wsSupport.findGroup(dbSession, request);
+ GroupUuidOrAnyone group = wsSupport.findGroupUuidOrAnyone(dbSession, request);
dbClient.permissionTemplateDao().deleteGroupPermission(dbSession, template.getUuid(), group.getUuid(), permission,
template.getName(), request.param(PARAM_GROUP_NAME));
package org.sonar.server.usergroups.ws;
import java.util.Optional;
+import javax.annotation.CheckForNull;
import org.sonar.api.security.DefaultGroups;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.WebService;
*/
public class GroupWsSupport {
- static final String PARAM_GROUP_ID = "id";
static final String PARAM_GROUP_NAME = "name";
static final String PARAM_GROUP_CURRENT_NAME = "currentName";
static final String PARAM_GROUP_DESCRIPTION = "description";
return findGroupDto(dbSession, groupName);
}
- public GroupDto findGroupDto(DbSession dbSession, String groupName) {
+ @CheckForNull
+ public GroupDto findGroupDtoOrNullIfAnyone(DbSession dbSession, String groupName) {
+ if (DefaultGroups.isAnyone(groupName)) {
+ return null;
+ }
+ return findGroupDto(dbSession, groupName);
+ }
+ public GroupDto findGroupDto(DbSession dbSession, String groupName) {
Optional<GroupDto> group = dbClient.groupDao().selectByName(dbSession, groupName);
checkFoundWithOptional(group, "No group with name '%s'", groupName);
return group.get();