aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-webserver-auth
diff options
context:
space:
mode:
authorDuarte Meneses <duarte.meneses@sonarsource.com>2019-10-23 15:33:39 -0500
committerSonarTech <sonartech@sonarsource.com>2020-01-31 20:46:09 +0100
commitace9a50d55d831ec71b7db421aa04d1198392c6c (patch)
tree3bf598bfe3f760d45310b2a65d014a53370a9930 /server/sonar-webserver-auth
parent1ff9a01fd6e822793ef223f9ce259b15d17eecc4 (diff)
downloadsonarqube-ace9a50d55d831ec71b7db421aa04d1198392c6c.tar.gz
sonarqube-ace9a50d55d831ec71b7db421aa04d1198392c6c.zip
SONAR-12689 Separate storage of projects/apps from their components and branches
Diffstat (limited to 'server/sonar-webserver-auth')
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/user/AbstractUserSession.java35
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ServerUserSession.java3
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java15
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/user/UserSession.java13
-rw-r--r--server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/tester/AbstractMockUserSession.java28
-rw-r--r--server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/tester/UserSessionRule.java19
6 files changed, 111 insertions, 2 deletions
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 5689072bc1c..8ba3e53e1fc 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
@@ -32,6 +32,7 @@ import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.permission.OrganizationPermission;
+import org.sonar.db.project.ProjectDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.UnauthorizedException;
@@ -98,6 +99,14 @@ public abstract class AbstractUserSession implements UserSession {
}
@Override
+ public final boolean hasProjectPermission(String permission, ProjectDto project) {
+ if (isRoot()) {
+ return true;
+ }
+ return hasProjectUuidPermission(permission, project.getUuid());
+ }
+
+ @Override
public final boolean hasComponentUuidPermission(String permission, String componentUuid) {
if (isRoot()) {
return true;
@@ -127,6 +136,24 @@ public abstract class AbstractUserSession implements UserSession {
return doKeepAuthorizedComponents(permission, components);
}
+ @Override
+ public List<ProjectDto> keepAuthorizedProjects(String permission, Collection<ProjectDto> projects) {
+ if (isRoot()) {
+ return new ArrayList<>(projects);
+ }
+ return doKeepAuthorizedProjects(permission, projects);
+ }
+
+ /**
+ * Naive implementation, to be overridden if needed
+ */
+ protected List<ProjectDto> doKeepAuthorizedProjects(String permission, Collection<ProjectDto> projects) {
+ boolean allowPublicComponent = PUBLIC_PERMISSIONS.contains(permission);
+ return projects.stream()
+ .filter(c -> (allowPublicComponent && !c.isPrivate()) || hasProjectPermission(permission, c))
+ .collect(MoreCollectors.toList());
+ }
+
/**
* Naive implementation, to be overridden if needed
*/
@@ -174,6 +201,14 @@ public abstract class AbstractUserSession implements UserSession {
return this;
}
+ @Override public UserSession checkProjectPermission(String projectPermission, ProjectDto project) {
+ if (isRoot() || hasProjectUuidPermission(projectPermission, project.getUuid())) {
+ return this;
+ }
+
+ throw new ForbiddenException(INSUFFICIENT_PRIVILEGES_MESSAGE);
+ }
+
@Override
public final UserSession checkComponentUuidPermission(String permission, String componentUuid) {
if (!hasComponentUuidPermission(permission, componentUuid)) {
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 1fbbe17116f..c62055870d6 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
@@ -183,6 +183,9 @@ public class ServerUserSession extends AbstractUserSession {
return permissions.contains(permission);
}
+ /**
+ * Also applies to views
+ */
private Set<String> loadProjectPermissions(String projectUuid) {
try (DbSession dbSession = dbClient.openSession(false)) {
Optional<ComponentDto> component = dbClient.componentDao().selectByUuid(dbSession, projectUuid);
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 771a434cc23..d310e17dd1c 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
@@ -26,6 +26,7 @@ import javax.annotation.CheckForNull;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.permission.OrganizationPermission;
+import org.sonar.db.project.ProjectDto;
import org.sonar.db.user.GroupDto;
import org.sonar.server.exceptions.UnauthorizedException;
@@ -134,6 +135,12 @@ public class ThreadLocalUserSession implements UserSession {
}
@Override
+ public UserSession checkProjectPermission(String projectPermission, ProjectDto project) {
+ get().checkProjectPermission(projectPermission, project);
+ return this;
+ }
+
+ @Override
public UserSession checkComponentUuidPermission(String permission, String componentUuid) {
get().checkComponentUuidPermission(permission, componentUuid);
return this;
@@ -155,6 +162,10 @@ public class ThreadLocalUserSession implements UserSession {
return get().hasComponentPermission(permission, component);
}
+ @Override public boolean hasProjectPermission(String permission, ProjectDto project) {
+ return get().hasProjectPermission(permission, project);
+ }
+
@Override
public boolean hasComponentUuidPermission(String permission, String componentUuid) {
return get().hasComponentUuidPermission(permission, componentUuid);
@@ -176,6 +187,10 @@ public class ThreadLocalUserSession implements UserSession {
return get().keepAuthorizedComponents(permission, components);
}
+ @Override public List<ProjectDto> keepAuthorizedProjects(String permission, Collection<ProjectDto> projects) {
+ return get().keepAuthorizedProjects(permission, projects);
+ }
+
@Override
public boolean hasMembership(OrganizationDto organizationDto) {
return get().hasMembership(organizationDto);
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 7fb907e4b9b..6c160f26a71 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
@@ -29,6 +29,7 @@ import javax.annotation.concurrent.Immutable;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.permission.OrganizationPermission;
+import org.sonar.db.project.ProjectDto;
import org.sonar.db.user.GroupDto;
import static java.util.Objects.requireNonNull;
@@ -98,8 +99,7 @@ public interface UserSession {
*/
Optional<IdentityProvider> getIdentityProvider();
- @Immutable
- final class ExternalIdentity {
+ @Immutable final class ExternalIdentity {
private final String id;
private final String login;
@@ -206,6 +206,8 @@ public interface UserSession {
*/
boolean hasComponentPermission(String permission, ComponentDto component);
+ boolean hasProjectPermission(String permission, ProjectDto project);
+
/**
* Using {@link #hasComponentPermission(String, ComponentDto)} is recommended
* because it does not have to load project if the referenced component
@@ -225,6 +227,7 @@ public interface UserSession {
*/
List<ComponentDto> keepAuthorizedComponents(String permission, Collection<ComponentDto> components);
+ List<ProjectDto> keepAuthorizedProjects(String permission, Collection<ProjectDto> projects);
/**
* Ensures that {@link #hasComponentPermission(String, ComponentDto)} is {@code true},
* otherwise throws a {@link org.sonar.server.exceptions.ForbiddenException}.
@@ -232,6 +235,12 @@ public interface UserSession {
UserSession checkComponentPermission(String projectPermission, ComponentDto component);
/**
+ * Ensures that {@link #hasProjectPermission(String, ProjectDto)} is {@code true},
+ * otherwise throws a {@link org.sonar.server.exceptions.ForbiddenException}.
+ */
+ UserSession checkProjectPermission(String projectPermission, ProjectDto project);
+
+ /**
* Ensures that {@link #hasComponentUuidPermission(String, String)} is {@code true},
* otherwise throws a {@link org.sonar.server.exceptions.ForbiddenException}.
*
diff --git a/server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/tester/AbstractMockUserSession.java b/server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/tester/AbstractMockUserSession.java
index 22e9e3ab9c5..00968fe8362 100644
--- a/server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/tester/AbstractMockUserSession.java
+++ b/server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/tester/AbstractMockUserSession.java
@@ -31,6 +31,7 @@ import org.sonar.api.web.UserRole;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.permission.OrganizationPermission;
+import org.sonar.db.project.ProjectDto;
import org.sonar.server.user.AbstractUserSession;
import static com.google.common.base.Preconditions.checkArgument;
@@ -78,6 +79,20 @@ public abstract class AbstractMockUserSession<T extends AbstractMockUserSession>
return clazz.cast(this);
}
+ public T registerProjects(ProjectDto... projects) {
+ Arrays.stream(projects)
+ .forEach(project -> {
+ if (!project.isPrivate()) {
+ this.projectUuidByPermission.put(UserRole.USER, project.getUuid());
+ this.projectUuidByPermission.put(UserRole.CODEVIEWER, project.getUuid());
+ this.projectPermissions.add(UserRole.USER);
+ this.projectPermissions.add(UserRole.CODEVIEWER);
+ }
+ this.projectUuidByComponentUuid.put(project.getUuid(), project.getUuid());
+ });
+ return clazz.cast(this);
+ }
+
public T addProjectPermission(String permission, ComponentDto... components) {
Arrays.stream(components).forEach(component -> {
checkArgument(
@@ -91,6 +106,19 @@ public abstract class AbstractMockUserSession<T extends AbstractMockUserSession>
return clazz.cast(this);
}
+ public T addProjectPermission(String permission, ProjectDto... projects) {
+ Arrays.stream(projects).forEach(component -> {
+ checkArgument(
+ component.isPrivate() || !PUBLIC_PERMISSIONS.contains(permission),
+ "public component %s can't be granted public permission %s", component.getUuid(), permission);
+ });
+ registerProjects(projects);
+ this.projectPermissions.add(permission);
+ Arrays.stream(projects)
+ .forEach(component -> this.projectUuidByPermission.put(permission, component.getUuid()));
+ return clazz.cast(this);
+ }
+
@Override
protected Optional<String> componentUuidToProjectUuid(String componentUuid) {
return Optional.ofNullable(projectUuidByComponentUuid.get(componentUuid));
diff --git a/server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/tester/UserSessionRule.java b/server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/tester/UserSessionRule.java
index c72088db1ae..e243f3870d4 100644
--- a/server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/tester/UserSessionRule.java
+++ b/server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/tester/UserSessionRule.java
@@ -31,6 +31,7 @@ import org.junit.runners.model.Statement;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.permission.OrganizationPermission;
+import org.sonar.db.project.ProjectDto;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.user.UserSession;
@@ -192,6 +193,11 @@ public class UserSessionRule implements TestRule, UserSession {
return this;
}
+ public UserSessionRule addProjectPermission(String projectPermission, ProjectDto projectDto) {
+ ensureAbstractMockUserSession().addProjectPermission(projectPermission, projectDto);
+ return this;
+ }
+
public UserSessionRule addPermission(OrganizationPermission permission, String organizationUuid) {
ensureAbstractMockUserSession().addPermission(permission, organizationUuid);
return this;
@@ -240,6 +246,10 @@ public class UserSessionRule implements TestRule, UserSession {
return currentUserSession.hasComponentPermission(permission, component);
}
+ @Override public boolean hasProjectPermission(String permission, ProjectDto project) {
+ return currentUserSession.hasProjectPermission(permission, project);
+ }
+
@Override
public boolean hasComponentUuidPermission(String permission, String componentUuid) {
return currentUserSession.hasComponentUuidPermission(permission, componentUuid);
@@ -250,6 +260,10 @@ public class UserSessionRule implements TestRule, UserSession {
return currentUserSession.keepAuthorizedComponents(permission, components);
}
+ @Override public List<ProjectDto> keepAuthorizedProjects(String permission, Collection<ProjectDto> projects) {
+ return currentUserSession.keepAuthorizedProjects(permission, projects);
+ }
+
@Override
@CheckForNull
public String getLogin() {
@@ -338,6 +352,11 @@ public class UserSessionRule implements TestRule, UserSession {
return this;
}
+ @Override public UserSession checkProjectPermission(String projectPermission, ProjectDto project) {
+ currentUserSession.checkProjectPermission(projectPermission, project);
+ return this;
+ }
+
@Override
public UserSession checkComponentUuidPermission(String permission, String componentUuid) {
currentUserSession.checkComponentUuidPermission(permission, componentUuid);