diff options
author | klaudio-sinani-sonarsource <92299827+klaudio-sinani-sonarsource@users.noreply.github.com> | 2022-01-11 12:49:37 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-01-20 20:02:43 +0000 |
commit | 110208dd8037b2cbf63df1ae17fb523c057d2046 (patch) | |
tree | b1503539eb1e3cbdf51cf729f29dabcc77be7163 /server/sonar-webserver-auth/src/main | |
parent | 5dd324c60877c4445460bde30ab3e3cc25fc7a7f (diff) | |
download | sonarqube-110208dd8037b2cbf63df1ae17fb523c057d2046.tar.gz sonarqube-110208dd8037b2cbf63df1ae17fb523c057d2046.zip |
SONAR-15877 Flag portfolios that contain inaccessible components (#5239)
Diffstat (limited to 'server/sonar-webserver-auth/src/main')
6 files changed, 81 insertions, 0 deletions
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/SafeModeUserSession.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/SafeModeUserSession.java index 7bc12dd1ef4..c14babcfdc4 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/SafeModeUserSession.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/SafeModeUserSession.java @@ -51,6 +51,11 @@ public class SafeModeUserSession extends AbstractUserSession { return false; } + @Override + protected boolean hasPortfolioChildProjectsPermission(String permission, String portfolioUuid) { + return false; + } + @CheckForNull @Override public String getLogin() { diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/AbstractUserSession.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/AbstractUserSession.java index 9fec50125fc..29914eb211f 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/AbstractUserSession.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/AbstractUserSession.java @@ -131,6 +131,15 @@ public abstract class AbstractUserSession implements UserSession { } @Override + public final boolean hasPortfolioChildProjectsPermission(String permission, ComponentDto portfolio) { + if (isRoot()) { + return true; + } + + return hasPortfolioChildProjectsPermission(permission, portfolio.uuid()); + } + + @Override public final boolean hasComponentUuidPermission(String permission, String componentUuid) { if (isRoot()) { return true; @@ -147,6 +156,8 @@ public abstract class AbstractUserSession implements UserSession { protected abstract boolean hasChildProjectsPermission(String permission, String applicationUuid); + protected abstract boolean hasPortfolioChildProjectsPermission(String permission, String portfolioUuid); + @Override public final List<ComponentDto> keepAuthorizedComponents(String permission, Collection<ComponentDto> components) { if (isRoot()) { diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/DoPrivileged.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/DoPrivileged.java index ed2770c08c0..c4a504d7a7b 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/DoPrivileged.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/DoPrivileged.java @@ -133,6 +133,11 @@ public final class DoPrivileged { } @Override + protected boolean hasPortfolioChildProjectsPermission(String permission, String applicationUuid) { + return true; + } + + @Override public boolean isSystemAdministrator() { return true; } diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ServerUserSession.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ServerUserSession.java index 0131f2ab492..7acb465d77d 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ServerUserSession.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ServerUserSession.java @@ -19,6 +19,7 @@ */ package org.sonar.server.user; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -27,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.sonar.api.resources.Qualifiers; @@ -181,6 +183,22 @@ public class ServerUserSession extends AbstractUserSession { .allMatch(Boolean::valueOf); } + @Override + protected boolean hasPortfolioChildProjectsPermission(String permission, String portfolioUuid) { + if (permissionsByProjectUuid == null) { + permissionsByProjectUuid = new HashMap<>(); + } + + Set<ComponentDto> portfolioHierarchyComponents = resolvePortfolioHierarchyComponents(portfolioUuid); + + Set<String> portfolioHierarchyComponentUuids = portfolioHierarchyComponents.stream().map(ComponentDto::getCopyComponentUuid).collect(Collectors.toSet()); + + return portfolioHierarchyComponentUuids + .stream() + .map(uuid -> hasPermission(permission, uuid)) + .allMatch(Boolean::valueOf); + } + private boolean hasPermission(String permission, String projectUuid) { Set<String> projectPermissions = permissionsByProjectUuid.computeIfAbsent(projectUuid, this::loadProjectPermissions); return projectPermissions.contains(permission); @@ -219,6 +237,41 @@ public class ServerUserSession extends AbstractUserSession { } } + private List<ComponentDto> getDirectChildComponents(String portfolioUuid) { + try (DbSession dbSession = dbClient.openSession(false)) { + return dbClient.componentDao().selectDescendants(dbSession, ComponentTreeQuery.builder() + .setBaseUuid(portfolioUuid) + .setQualifiers(Arrays.asList(Qualifiers.PROJECT, Qualifiers.SUBVIEW)) + .setStrategy(Strategy.CHILDREN).build()); + } + } + + private Set<ComponentDto> resolvePortfolioHierarchyComponents(String parentComponentUuid) { + Set<ComponentDto> portfolioHierarchyProjects = new HashSet<>(); + + resolvePortfolioHierarchyComponents(parentComponentUuid, portfolioHierarchyProjects); + + return portfolioHierarchyProjects; + } + + private void resolvePortfolioHierarchyComponents(String parentComponentUuid, Set<ComponentDto> hierarchyChildComponents) { + List<ComponentDto> childComponents = getDirectChildComponents(parentComponentUuid); + + if (childComponents.isEmpty()) { + return; + } + + childComponents.forEach(c -> { + if (c.getCopyComponentUuid() != null) { + hierarchyChildComponents.add(c); + } + + if (Qualifiers.SUBVIEW.equals(c.qualifier())) { + resolvePortfolioHierarchyComponents(c.uuid(), hierarchyChildComponents); + } + }); + } + private Set<GlobalPermission> loadGlobalPermissions() { Set<String> permissionKeys; try (DbSession dbSession = dbClient.openSession(false)) { diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java index 96096ccefe1..3dec0032d96 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java @@ -199,6 +199,11 @@ public class ThreadLocalUserSession implements UserSession { } @Override + public boolean hasPortfolioChildProjectsPermission(String permission, ComponentDto portfolio) { + return get().hasPortfolioChildProjectsPermission(permission, portfolio); + } + + @Override public boolean hasComponentUuidPermission(String permission, String componentUuid) { return get().hasComponentUuidPermission(permission, componentUuid); } diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/UserSession.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/UserSession.java index 61992db77cc..5350e578539 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/UserSession.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/UserSession.java @@ -201,6 +201,8 @@ public interface UserSession { boolean hasChildProjectsPermission(String permission, ProjectDto component); + boolean hasPortfolioChildProjectsPermission(String permission, ComponentDto component); + /** * Using {@link #hasComponentPermission(String, ComponentDto)} is recommended * because it does not have to load project if the referenced component |