import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.management.ManagedProjectService;
import org.sonar.server.permission.DefaultTemplatesResolver;
import org.sonar.server.permission.DefaultTemplatesResolverImpl;
import org.sonar.server.permission.PermissionTemplateService;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import static org.sonar.api.resources.Qualifiers.APP;
import static org.sonar.api.resources.Qualifiers.PROJECT;
import static org.sonar.api.resources.Qualifiers.VIEW;
private final PermissionTemplateService permissionTemplateService = new PermissionTemplateService(db.getDbClient(),
new TestIndexers(), userSession, defaultTemplatesResolver, new SequenceUuidFactory());
+ private final ManagedProjectService managedProjectService = mock(ManagedProjectService.class);
+ private final ManagedInstanceChecker managedInstanceChecker = new ManagedInstanceChecker(null, managedProjectService);
+
@Override
protected ApplyTemplateAction buildWsAction() {
- return new ApplyTemplateAction(db.getDbClient(), userSession, permissionTemplateService, newPermissionWsSupport());
+ return new ApplyTemplateAction(db.getDbClient(), userSession, permissionTemplateService, newPermissionWsSupport(), managedInstanceChecker);
}
@Before
.hasMessage("Project id or project key can be provided, not both.");
}
+ @Test
+ public void fail_when_project_is_managed() {
+ loginAsAdmin();
+
+ when(managedProjectService.isProjectManaged(any(), eq(project.getUuid()))).thenReturn(true);
+
+ String templateUuid = template1.getUuid();
+ String projectUuid = project.getUuid();
+ assertThatThrownBy(() -> newRequest(templateUuid, projectUuid, null))
+ .isInstanceOf(BadRequestException.class)
+ .hasMessage("Operation not allowed when the project is externally managed.");
+ }
+
@Test
public void fail_when_not_admin() {
userSession.logIn().addPermission(SCAN);
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.l18n.I18nRule;
+import org.sonar.server.management.ManagedProjectService;
import org.sonar.server.permission.DefaultTemplatesResolver;
import org.sonar.server.permission.DefaultTemplatesResolverImpl;
import org.sonar.server.permission.PermissionTemplateService;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import static org.sonar.api.resources.Qualifiers.APP;
import static org.sonar.api.resources.Qualifiers.PROJECT;
import static org.sonar.api.resources.Qualifiers.VIEW;
private final ResourceTypesRule resourceTypesRule = new ResourceTypesRule().setRootQualifiers(PROJECT, VIEW, APP);
private final DefaultTemplatesResolver defaultTemplatesResolver = new DefaultTemplatesResolverImpl(db.getDbClient(), resourceTypesRule);
+ private final ManagedProjectService managedProjectService = mock(ManagedProjectService.class);
+
@Override
protected BulkApplyTemplateAction buildWsAction() {
PermissionTemplateService permissionTemplateService = new PermissionTemplateService(db.getDbClient(),
indexers, userSession, defaultTemplatesResolver, new SequenceUuidFactory());
- return new BulkApplyTemplateAction(db.getDbClient(), userSession, permissionTemplateService, newPermissionWsSupport(), new I18nRule(), newRootResourceTypes());
+ return new BulkApplyTemplateAction(db.getDbClient(), userSession, permissionTemplateService, newPermissionWsSupport(), new I18nRule(), newRootResourceTypes(),
+ managedProjectService);
}
@Before
assertNoPermissionOnEntity(publicProject);
}
+ @Test
+ public void apply_template_filters_out_managed_projects() {
+ ProjectDto managedProject = db.components().insertPrivateProject().getProjectDto();
+ ProjectDto nonManagedProject = db.components().insertPrivateProject().getProjectDto();
+ when(managedProjectService.isProjectManaged(any(), eq(managedProject.getUuid()))).thenReturn(true);
+ loginAsAdmin();
+
+ newRequest()
+ .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
+ .setParam(PARAM_VISIBILITY, "private")
+ .execute();
+
+ assertNoPermissionOnEntity(managedProject);
+ assertTemplate1AppliedToPrivateProject(nonManagedProject);
+ }
+
@Test
public void fail_if_no_template_parameter() {
loginAsAdmin();
import org.sonar.db.entity.EntityDto;
import org.sonar.db.permission.template.PermissionTemplateDto;
import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.management.ManagedInstanceChecker;
import org.sonar.server.permission.PermissionTemplateService;
import org.sonar.server.permission.ws.PermissionWsSupport;
import org.sonar.server.permission.ws.PermissionsWsAction;
private final PermissionTemplateService permissionTemplateService;
private final PermissionWsSupport wsSupport;
+ private final ManagedInstanceChecker managedInstanceChecker;
+
public ApplyTemplateAction(DbClient dbClient, UserSession userSession, PermissionTemplateService permissionTemplateService,
- PermissionWsSupport wsSupport) {
+ PermissionWsSupport wsSupport, ManagedInstanceChecker managedInstanceChecker) {
this.dbClient = dbClient;
this.userSession = userSession;
this.permissionTemplateService = permissionTemplateService;
this.wsSupport = wsSupport;
+ this.managedInstanceChecker = managedInstanceChecker;
}
private static ApplyTemplateRequest toApplyTemplateWsRequest(Request request) {
EntityDto entityDto = getEntityByKeyOrUuid(request.getProjectId(), request.getProjectKey(), dbSession);
checkGlobalAdmin(userSession);
+ if (entityDto.isProject()) {
+ managedInstanceChecker.throwIfProjectIsManaged(dbSession, entityDto.getUuid());
+ }
permissionTemplateService.applyAndCommit(dbSession, template, Collections.singletonList(entityDto));
}
}
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.db.component.ComponentQuery;
import org.sonar.db.entity.EntityDto;
import org.sonar.db.permission.template.PermissionTemplateDto;
+import org.sonar.server.management.ManagedProjectService;
import org.sonar.server.permission.PermissionTemplateService;
import org.sonar.server.permission.ws.PermissionWsSupport;
import org.sonar.server.permission.ws.PermissionsWsAction;
import static org.sonar.server.permission.ws.template.WsTemplateRef.newTemplateRef;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_002;
-import static org.sonar.server.ws.WsParameterBuilder.createRootQualifiersParameter;
import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext;
+import static org.sonar.server.ws.WsParameterBuilder.createRootQualifiersParameter;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_ID;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_NAME;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ANALYZED_BEFORE;
private final PermissionWsSupport wsSupport;
private final I18n i18n;
private final ResourceTypes resourceTypes;
+ private final ManagedProjectService managedProjectService;
public BulkApplyTemplateAction(DbClient dbClient, UserSession userSession, PermissionTemplateService permissionTemplateService, PermissionWsSupport wsSupport, I18n i18n,
- ResourceTypes resourceTypes) {
+ ResourceTypes resourceTypes, ManagedProjectService managedProjectService) {
this.dbClient = dbClient;
this.userSession = userSession;
this.permissionTemplateService = permissionTemplateService;
this.wsSupport = wsSupport;
this.i18n = i18n;
this.resourceTypes = resourceTypes;
+ this.managedProjectService = managedProjectService;
}
@Override
public void define(WebService.NewController context) {
WebService.NewAction action = context.createAction("bulk_apply_template")
- .setDescription("Apply a permission template to several projects.<br />" +
+ .setDescription("Apply a permission template to several components. Managed projects will be ignored.<br />" +
"The template id or name must be provided.<br />" +
"Requires the following permission: 'Administer System'.")
.setPost(true)
action.createParam(PARAM_VISIBILITY)
.setDescription("Filter the projects that should be visible to everyone (%s), or only specific user/groups (%s).<br/>" +
- "If no visibility is specified, the default project visibility will be used.",
+ "If no visibility is specified, the default project visibility will be used.",
Visibility.PUBLIC.getLabel(), Visibility.PRIVATE.getLabel())
.setRequired(false)
.setInternal(true)
ComponentQuery componentQuery = buildDbQuery(request);
List<ComponentDto> components = dbClient.componentDao().selectByQuery(dbSession, componentQuery, 0, Integer.MAX_VALUE);
- List<EntityDto> entities = dbClient.entityDao().selectByKeys(dbSession, components.stream()
+ Set<String> entityUuids = components.stream()
.map(ComponentDto::getKey)
- .collect(Collectors.toSet()));
+ .collect(Collectors.toSet());
+ List<EntityDto> entities = dbClient.entityDao().selectByKeys(dbSession, entityUuids).stream()
+ .filter(entity -> !managedProjectService.isProjectManaged(dbSession, entity.getUuid()))
+ .toList();
permissionTemplateService.applyAndCommit(dbSession, template, entities);
}