aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2018-07-04 16:39:57 +0200
committerSonarTech <sonartech@sonarsource.com>2018-07-11 20:21:21 +0200
commit884cd785c870a40d804f445e27be5528a2940514 (patch)
tree062a6a9d619a5963cfa90f0d2ecb8c9a8472383c
parentf675d5865684706e6943bf74bdb96a7e1b7e1549 (diff)
downloadsonarqube-884cd785c870a40d804f445e27be5528a2940514.tar.gz
sonarqube-884cd785c870a40d804f445e27be5528a2940514.zip
SONAR-10945 Prevent access qgates and rules to none members of paid organization
* Add membership check for paid organization in api/qualitygates ws * Add membership check for paid organization in api/rules ws * Move membership check in UserSession * Use UserSession#checkMemebership in QGates and Rules ws
-rw-r--r--server/sonar-ce/src/main/java/org/sonar/ce/user/CeUserSession.java15
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/user/BaseUserSession.java7
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/user/UserSession.java16
-rw-r--r--server/sonar-server-common/src/test/java/org/sonar/server/user/LightUserSessionRule.java10
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/authentication/SafeModeUserSession.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java12
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileWsSupport.java13
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleQueryFactory.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleWsSupport.java14
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java11
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/DoPrivileged.java8
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/ServerUserSession.java33
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java13
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/authentication/SafeModeUserSessionTest.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ListActionTest.java103
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ShowActionTest.java112
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/BackupActionTest.java3
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionTest.java3
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/CompareActionTest.java3
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ExportActionTest.java3
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/InheritanceActionTest.java3
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java3
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/rule/ws/AppActionTest.java64
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/rule/ws/RuleQueryFactoryTest.java168
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java36
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/tester/AbstractMockUserSession.java22
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/tester/AnonymousMockUserSession.java6
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/tester/MockUserSession.java1
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/tester/UserSessionRule.java17
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/user/DoPrivilegedTest.java7
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/user/ServerUserSessionTest.java56
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/user/TestUserSessionFactory.java8
32 files changed, 601 insertions, 186 deletions
diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/user/CeUserSession.java b/server/sonar-ce/src/main/java/org/sonar/ce/user/CeUserSession.java
index 1d3126a4232..4dee6ad79fe 100644
--- a/server/sonar-ce/src/main/java/org/sonar/ce/user/CeUserSession.java
+++ b/server/sonar-ce/src/main/java/org/sonar/ce/user/CeUserSession.java
@@ -23,8 +23,8 @@ import java.util.Collection;
import java.util.List;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
-import org.sonar.db.user.GroupDto;
import org.sonar.db.permission.OrganizationPermission;
+import org.sonar.db.user.GroupDto;
import org.sonar.server.user.UserSession;
/**
@@ -42,7 +42,8 @@ public class CeUserSession implements UserSession {
throw notImplemented();
}
- @Override public String getUuid() {
+ @Override
+ public String getUuid() {
throw notImplemented();
}
@@ -136,6 +137,16 @@ public class CeUserSession implements UserSession {
throw notImplemented();
}
+ @Override
+ public boolean hasMembership(OrganizationDto organization) {
+ throw notImplemented();
+ }
+
+ @Override
+ public UserSession checkMembership(OrganizationDto organization) {
+ throw notImplemented();
+ }
+
private static RuntimeException notImplemented() {
throw new UnsupportedOperationException(UOE_MESSAGE);
}
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/user/BaseUserSession.java b/server/sonar-server-common/src/main/java/org/sonar/server/user/BaseUserSession.java
index 913f285ded4..51c591cd62f 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/user/BaseUserSession.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/user/BaseUserSession.java
@@ -69,6 +69,13 @@ public abstract class BaseUserSession implements UserSession {
protected abstract boolean hasProjectUuidPermission(String permission, String projectUuid);
@Override
+ public final boolean hasMembership(OrganizationDto organization) {
+ return isRoot() || hasMembershipImpl(organization);
+ }
+
+ protected abstract boolean hasMembershipImpl(OrganizationDto organization);
+
+ @Override
public final List<ComponentDto> keepAuthorizedComponents(String permission, Collection<ComponentDto> components) {
if (isRoot()) {
return new ArrayList<>(components);
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/user/UserSession.java b/server/sonar-server-common/src/main/java/org/sonar/server/user/UserSession.java
index 4eca7b6b46c..645254afcf3 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/user/UserSession.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/user/UserSession.java
@@ -173,4 +173,20 @@ public interface UserSession {
*/
UserSession checkIsSystemAdministrator();
+ /**
+ * Returns {@code true} if the user is member of the organization, otherwise {@code false}.
+ *
+ * If the organization does not exist, then returns {@code false}.
+ *
+ * Always returns {@code true} if {@link #isRoot()} is {@code true}, even if
+ * organization does not exist.
+ */
+ boolean hasMembership(OrganizationDto organization);
+
+ /**
+ * Ensures that {@link #hasMembership(OrganizationDto)} is {@code true},
+ * otherwise throws a {@link org.sonar.server.exceptions.ForbiddenException}.
+ */
+ UserSession checkMembership(OrganizationDto organization);
+
}
diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/user/LightUserSessionRule.java b/server/sonar-server-common/src/test/java/org/sonar/server/user/LightUserSessionRule.java
index 0c39a08164e..640dcb9aa91 100644
--- a/server/sonar-server-common/src/test/java/org/sonar/server/user/LightUserSessionRule.java
+++ b/server/sonar-server-common/src/test/java/org/sonar/server/user/LightUserSessionRule.java
@@ -146,6 +146,11 @@ public class LightUserSessionRule extends BaseUserSession implements TestRule {
}
@Override
+ protected boolean hasMembershipImpl(OrganizationDto organization) {
+ throw new UnsupportedOperationException("hasMembershipImpl not implemented");
+ }
+
+ @Override
protected Optional<String> componentUuidToProjectUuid(String componentUuid) {
return Optional.ofNullable(projectUuidByComponentUuid.get(componentUuid));
}
@@ -233,4 +238,9 @@ public class LightUserSessionRule extends BaseUserSession implements TestRule {
public UserSession checkIsSystemAdministrator() {
throw new UnsupportedOperationException("checkIsSystemAdministrator not implemented");
}
+
+ @Override
+ public UserSession checkMembership(OrganizationDto organization) {
+ throw new UnsupportedOperationException("checkMembership not implemented");
+ }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/SafeModeUserSession.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/SafeModeUserSession.java
index 177ce73ceb1..91330f3917e 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/authentication/SafeModeUserSession.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/SafeModeUserSession.java
@@ -24,6 +24,7 @@ import java.util.Collections;
import java.util.Optional;
import javax.annotation.CheckForNull;
import javax.annotation.concurrent.Immutable;
+import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.permission.OrganizationPermission;
import org.sonar.db.user.GroupDto;
import org.sonar.server.user.AbstractUserSession;
@@ -89,4 +90,9 @@ public class SafeModeUserSession extends AbstractUserSession {
public boolean isSystemAdministrator() {
return false;
}
+
+ @Override
+ public boolean hasMembershipImpl(OrganizationDto organization) {
+ return false;
+ }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java
index 58685554fbc..d50a8ca0c82 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java
@@ -39,6 +39,7 @@ import org.sonarqube.ws.Qualitygates;
import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static org.sonar.api.web.UserRole.ADMIN;
+import static org.sonar.db.organization.OrganizationDto.Subscription.PAID;
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_GATES;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ORGANIZATION;
import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
@@ -100,7 +101,9 @@ public class QualityGatesWsSupport {
String organizationKey = Optional.ofNullable(request.param(PARAM_ORGANIZATION))
.orElseGet(() -> defaultOrganizationProvider.get().getKey());
Optional<OrganizationDto> organizationDto = dbClient.organizationDao().selectByKey(dbSession, organizationKey);
- return checkFoundWithOptional(organizationDto, "No organization with key '%s'", organizationKey);
+ OrganizationDto organization = checkFoundWithOptional(organizationDto, "No organization with key '%s'", organizationKey);
+ checkMembershipOnPaidOrganization(organization);
+ return organization;
}
void checkCanEdit(QGateWithOrgDto qualityGate) {
@@ -127,4 +130,11 @@ public class QualityGatesWsSupport {
checkArgument(!qualityGate.isBuiltIn(), "Operation forbidden for built-in Quality Gate '%s'", qualityGate.getName());
}
+ private void checkMembershipOnPaidOrganization(OrganizationDto organization) {
+ if (!organization.getSubscription().equals(PAID)) {
+ return;
+ }
+ userSession.checkMembership(organization);
+ }
+
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileWsSupport.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileWsSupport.java
index 489f08f52e0..cc7a09fc15f 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileWsSupport.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileWsSupport.java
@@ -33,7 +33,6 @@ import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
-import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.user.UserSession;
@@ -74,7 +73,7 @@ public class QProfileWsSupport {
String organizationUuid = profile.getOrganizationUuid();
OrganizationDto organization = dbClient.organizationDao().selectByUuid(dbSession, organizationUuid)
.orElseThrow(() -> new IllegalStateException("Cannot load organization with uuid=" + organizationUuid));
- checkMembershipOnPaidOrganization(dbSession, organization);
+ checkMembershipOnPaidOrganization(organization);
return organization;
}
@@ -84,7 +83,7 @@ public class QProfileWsSupport {
OrganizationDto organization = checkFoundWithOptional(
dbClient.organizationDao().selectByKey(dbSession, organizationOrDefaultKey),
"No organization with key '%s'", organizationOrDefaultKey);
- checkMembershipOnPaidOrganization(dbSession, organization);
+ checkMembershipOnPaidOrganization(organization);
return organization;
}
@@ -174,15 +173,11 @@ public class QProfileWsSupport {
return dbClient.organizationMemberDao().select(dbSession, organization.getUuid(), userId).isPresent();
}
- private void checkMembershipOnPaidOrganization(DbSession dbSession, OrganizationDto organization) {
+ private void checkMembershipOnPaidOrganization(OrganizationDto organization) {
if (!organization.getSubscription().equals(PAID)) {
return;
}
- Integer userId = userSession.getUserId();
- if (userId != null && isMember(dbSession, organization, userId)) {
- return;
- }
- throw new ForbiddenException(String.format("You're not member of organization '%s'", organization.getKey()));
+ userSession.checkMembership(organization);
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleQueryFactory.java b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleQueryFactory.java
index 6755309c9bf..0df84c49176 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleQueryFactory.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleQueryFactory.java
@@ -34,16 +34,13 @@ import org.sonar.server.rule.index.RuleQuery;
import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
-import static org.sonar.server.util.EnumUtils.toEnums;
-import static org.sonar.server.ws.WsUtils.checkFound;
-import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ACTIVATION;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ACTIVE_SEVERITIES;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_AVAILABLE_SINCE;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_COMPARE_TO_PROFILE;
+import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_INCLUDE_EXTERNAL;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_INHERITANCE;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_IS_TEMPLATE;
-import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_INCLUDE_EXTERNAL;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_LANGUAGES;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ORGANIZATION;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_QPROFILE;
@@ -54,6 +51,9 @@ import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_STATUSES;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_TAGS;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_TEMPLATE_KEY;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_TYPES;
+import static org.sonar.server.util.EnumUtils.toEnums;
+import static org.sonar.server.ws.WsUtils.checkFound;
+import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
@ServerSide
public class RuleQueryFactory {
@@ -139,6 +139,7 @@ public class RuleQueryFactory {
checkArgument(organization.getUuid().equals(inputOrganization.getUuid()),
format("The specified quality profile '%s' is not part of the specified organization '%s'", profile.getKee(), organizationKey));
}
+ wsSupport.checkMembershipOnPaidOrganization(organization);
query.setOrganization(organization);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleWsSupport.java b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleWsSupport.java
index ecd4b1bf592..a54dea98130 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleWsSupport.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleWsSupport.java
@@ -33,11 +33,12 @@ import org.sonar.db.rule.RuleDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.user.UserSession;
-import org.sonar.server.ws.WsUtils;
import static org.sonar.core.util.stream.MoreCollectors.toSet;
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
+import static org.sonar.db.organization.OrganizationDto.Subscription.PAID;
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES;
+import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
@ServerSide
public class RuleWsSupport {
@@ -61,9 +62,11 @@ public class RuleWsSupport {
public OrganizationDto getOrganizationByKey(DbSession dbSession, @Nullable String organizationKey) {
String organizationOrDefaultKey = Optional.ofNullable(organizationKey)
.orElseGet(defaultOrganizationProvider.get()::getKey);
- return WsUtils.checkFoundWithOptional(
+ OrganizationDto organization = checkFoundWithOptional(
dbClient.organizationDao().selectByKey(dbSession, organizationOrDefaultKey),
"No organization with key '%s'", organizationOrDefaultKey);
+ checkMembershipOnPaidOrganization(organization);
+ return organization;
}
Map<String, UserDto> getUsersByUuid(DbSession dbSession, List<RuleDto> rules) {
@@ -71,4 +74,11 @@ public class RuleWsSupport {
return dbClient.userDao().selectByUuids(dbSession, userUuids).stream().collect(uniqueIndex(UserDto::getUuid));
}
+ void checkMembershipOnPaidOrganization(OrganizationDto organization) {
+ if (!organization.getSubscription().equals(PAID)) {
+ return;
+ }
+ userSession.checkMembership(organization);
+ }
+
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java b/server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java
index 2a24d1d19cd..ee54c942351 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java
@@ -25,6 +25,8 @@ import org.sonar.db.permission.OrganizationPermission;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.UnauthorizedException;
+import static java.lang.String.format;
+
public abstract class AbstractUserSession extends BaseUserSession {
private static final String INSUFFICIENT_PRIVILEGES_MESSAGE = "Insufficient privileges";
private static final ForbiddenException INSUFFICIENT_PRIVILEGES_EXCEPTION = new ForbiddenException(INSUFFICIENT_PRIVILEGES_MESSAGE);
@@ -86,4 +88,13 @@ public abstract class AbstractUserSession extends BaseUserSession {
}
return this;
}
+
+ @Override
+ public UserSession checkMembership(OrganizationDto organization) {
+ if (!hasMembership(organization)) {
+ throw new ForbiddenException(format("You're not member of organization '%s'", organization.getKey()));
+ }
+ return this;
+ }
+
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/DoPrivileged.java b/server/sonar-server/src/main/java/org/sonar/server/user/DoPrivileged.java
index a016a7347eb..4f1ccc5b97a 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/DoPrivileged.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/DoPrivileged.java
@@ -22,6 +22,7 @@ package org.sonar.server.user;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
+import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.permission.OrganizationPermission;
import org.sonar.db.user.GroupDto;
@@ -116,11 +117,16 @@ public final class DoPrivileged {
protected boolean hasProjectUuidPermission(String permission, String projectUuid) {
return true;
}
-
+
@Override
public boolean isSystemAdministrator() {
return true;
}
+
+ @Override
+ public boolean hasMembershipImpl(OrganizationDto organization) {
+ return true;
+ }
}
private void start() {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ServerUserSession.java b/server/sonar-server/src/main/java/org/sonar/server/user/ServerUserSession.java
index c148cd5945f..504b2929032 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/ServerUserSession.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/ServerUserSession.java
@@ -25,6 +25,7 @@ import com.google.common.collect.ImmutableSet;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -36,13 +37,15 @@ import org.sonar.core.util.stream.MoreCollectors;
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.organization.OrganizationMemberDto;
import org.sonar.db.permission.OrganizationPermission;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.organization.OrganizationFlags;
-import static com.google.common.collect.Maps.newHashMap;
+import static java.util.Objects.requireNonNull;
import static org.apache.commons.lang.StringUtils.defaultIfEmpty;
/**
@@ -56,9 +59,10 @@ public class ServerUserSession extends AbstractUserSession {
private final DefaultOrganizationProvider defaultOrganizationProvider;
private final Supplier<Collection<GroupDto>> groups = Suppliers.memoize(this::loadGroups);
private final Supplier<Boolean> isSystemAdministratorSupplier = Suppliers.memoize(this::loadIsSystemAdministrator);
- private final Map<String, String> projectUuidByComponentUuid = newHashMap();
+ private final Map<String, String> projectUuidByComponentUuid = new HashMap<>();
private Map<String, Set<OrganizationPermission>> permissionsByOrganizationUuid;
private Map<String, Set<String>> permissionsByProjectUuid;
+ private Set<String> organizationMembership = new HashSet<>();
ServerUserSession(DbClient dbClient, OrganizationFlags organizationFlags,
DefaultOrganizationProvider defaultOrganizationProvider, @Nullable UserDto userDto) {
@@ -222,4 +226,29 @@ public class ServerUserSession extends AbstractUserSession {
return false;
}
}
+
+ @Override
+ public boolean hasMembershipImpl(OrganizationDto organization) {
+ return isMember(organization);
+ }
+
+ private boolean isMember(OrganizationDto organization) {
+ if (!isLoggedIn()) {
+ return false;
+ }
+ if (isRoot()) {
+ return true;
+ }
+ String organizationUuid = organization.getUuid();
+ if (organizationMembership.contains(organizationUuid)) {
+ return true;
+ }
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ Optional<OrganizationMemberDto> organizationMemberDto = dbClient.organizationMemberDao().select(dbSession, organizationUuid, requireNonNull(getUserId()));
+ if (organizationMemberDto.isPresent()) {
+ organizationMembership.add(organizationUuid);
+ }
+ return organizationMembership.contains(organizationUuid);
+ }
+ }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java b/server/sonar-server/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java
index 0d522a628ad..79287e99fad 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java
@@ -24,9 +24,9 @@ import java.util.List;
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.user.GroupDto;
import org.sonar.server.exceptions.UnauthorizedException;
-import org.sonar.db.permission.OrganizationPermission;
/**
* Part of the current HTTP session
@@ -164,4 +164,15 @@ public class ThreadLocalUserSession implements UserSession {
public List<ComponentDto> keepAuthorizedComponents(String permission, Collection<ComponentDto> components) {
return get().keepAuthorizedComponents(permission, components);
}
+
+ @Override
+ public boolean hasMembership(OrganizationDto organization) {
+ return get().hasMembership(organization);
+ }
+
+ @Override
+ public UserSession checkMembership(OrganizationDto organization) {
+ get().checkMembership(organization);
+ return this;
+ }
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/SafeModeUserSessionTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/SafeModeUserSessionTest.java
index 89dc22cfbeb..27cd019b55b 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/authentication/SafeModeUserSessionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/authentication/SafeModeUserSessionTest.java
@@ -24,6 +24,7 @@ import org.sonar.api.web.UserRole;
import org.sonar.db.permission.OrganizationPermission;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto;
public class SafeModeUserSessionTest {
@@ -45,5 +46,6 @@ public class SafeModeUserSessionTest {
assertThat(underTest.isSystemAdministrator()).isFalse();
assertThat(underTest.hasPermissionImpl(OrganizationPermission.ADMINISTER, "foo")).isFalse();
assertThat(underTest.hasProjectUuidPermission(UserRole.USER, "foo")).isFalse();
+ assertThat(underTest.hasMembership(newOrganizationDto())).isFalse();
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ListActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ListActionTest.java
index 8f8b3abf63e..8613419f018 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ListActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ListActionTest.java
@@ -29,6 +29,8 @@ import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualitygate.QGateWithOrgDto;
import org.sonar.db.qualitygate.QualityGateDto;
+import org.sonar.db.user.UserDto;
+import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
import org.sonar.server.qualitygate.QualityGateFinder;
@@ -36,8 +38,10 @@ import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsActionTester;
import org.sonarqube.ws.Qualitygates.ListWsResponse.QualityGate;
+import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.tuple;
+import static org.sonar.db.organization.OrganizationDto.Subscription.PAID;
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_GATES;
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES;
import static org.sonar.test.JsonAssert.assertJson;
@@ -60,40 +64,6 @@ public class ListActionTest {
new QualityGatesWsSupport(dbClient, userSession, defaultOrganizationProvider), qualityGateFinder));
@Test
- public void verify_definition() {
- WebService.Action action = ws.getDef();
- assertThat(action.since()).isEqualTo("4.3");
- assertThat(action.key()).isEqualTo("list");
- assertThat(action.isPost()).isFalse();
- assertThat(action.isInternal()).isFalse();
- assertThat(action.changelog()).extracting(Change::getVersion, Change::getDescription)
- .containsExactlyInAnyOrder(
- tuple("7.0", "'isDefault' field is added on quality gate"),
- tuple("7.0", "'default' field on root level is deprecated"),
- tuple("7.0", "'isBuiltIn' field is added in the response"),
- tuple("7.0", "'actions' fields are added in the response"));
- assertThat(action.params()).extracting(WebService.Param::key, WebService.Param::isRequired)
- .containsExactlyInAnyOrder(tuple("organization", false));
- }
-
- @Test
- public void json_example() {
- OrganizationDto organization = db.organizations().insert();
- userSession.logIn("admin").addPermission(ADMINISTER_QUALITY_GATES, organization);
- QualityGateDto defaultQualityGate = db.qualityGates().insertQualityGate(organization, qualityGate -> qualityGate.setName("Sonar way").setBuiltIn(true));
- db.qualityGates().insertQualityGate(organization, qualityGate -> qualityGate.setName("Sonar way - Without Coverage").setBuiltIn(false));
- db.qualityGates().setDefaultQualityGate(organization, defaultQualityGate);
-
- String response = ws.newRequest()
- .setParam("organization", organization.getKey())
- .execute()
- .getInput();
-
- assertJson(response).ignoreFields("id", "default")
- .isSimilarTo(getClass().getResource("list-example.json"));
- }
-
- @Test
public void list_quality_gates() {
OrganizationDto organization = db.organizations().insert();
QualityGateDto defaultQualityGate = db.qualityGates().insertQualityGate(organization);
@@ -220,4 +190,69 @@ public class ListActionTest {
tuple(defaultQualityGate.getName(), false, false, false, false, false, false),
tuple(otherQualityGate.getName(), false, false, false, false, false, false));
}
+
+ @Test
+ public void list_quality_gates_on_paid_organization() {
+ OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
+ QualityGateDto qualityGate = db.qualityGates().insertQualityGate(organization);
+ db.qualityGates().setDefaultQualityGate(organization, qualityGate);
+ UserDto user = db.users().insertUser();
+ userSession.logIn(user).addMembership(organization);
+
+ ListWsResponse response = ws.newRequest()
+ .setParam("organization", organization.getKey())
+ .executeProtobuf(ListWsResponse.class);
+
+ assertThat(response.getQualitygatesList())
+ .extracting(QualityGate::getName)
+ .containsExactlyInAnyOrder(qualityGate.getName());
+ }
+
+ @Test
+ public void fail_on_paid_organization_when_not_member() {
+ OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
+ QGateWithOrgDto qualityGate = db.qualityGates().insertQualityGate(organization);
+
+ expectedException.expect(ForbiddenException.class);
+ expectedException.expectMessage(format("You're not member of organization '%s'", organization.getKey()));
+
+ ws.newRequest()
+ .setParam("organization", organization.getKey())
+ .execute();
+ }
+
+ @Test
+ public void json_example() {
+ OrganizationDto organization = db.organizations().insert();
+ userSession.logIn("admin").addPermission(ADMINISTER_QUALITY_GATES, organization);
+ QualityGateDto defaultQualityGate = db.qualityGates().insertQualityGate(organization, qualityGate -> qualityGate.setName("Sonar way").setBuiltIn(true));
+ db.qualityGates().insertQualityGate(organization, qualityGate -> qualityGate.setName("Sonar way - Without Coverage").setBuiltIn(false));
+ db.qualityGates().setDefaultQualityGate(organization, defaultQualityGate);
+
+ String response = ws.newRequest()
+ .setParam("organization", organization.getKey())
+ .execute()
+ .getInput();
+
+ assertJson(response).ignoreFields("id", "default")
+ .isSimilarTo(getClass().getResource("list-example.json"));
+ }
+
+ @Test
+ public void verify_definition() {
+ WebService.Action action = ws.getDef();
+ assertThat(action.since()).isEqualTo("4.3");
+ assertThat(action.key()).isEqualTo("list");
+ assertThat(action.isPost()).isFalse();
+ assertThat(action.isInternal()).isFalse();
+ assertThat(action.changelog()).extracting(Change::getVersion, Change::getDescription)
+ .containsExactlyInAnyOrder(
+ tuple("7.0", "'isDefault' field is added on quality gate"),
+ tuple("7.0", "'default' field on root level is deprecated"),
+ tuple("7.0", "'isBuiltIn' field is added in the response"),
+ tuple("7.0", "'actions' fields are added in the response"));
+ assertThat(action.params()).extracting(WebService.Param::key, WebService.Param::isRequired)
+ .containsExactlyInAnyOrder(tuple("organization", false));
+ }
+
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ShowActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ShowActionTest.java
index f12a1abf518..debea374c14 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ShowActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ShowActionTest.java
@@ -32,6 +32,8 @@ import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualitygate.QGateWithOrgDto;
import org.sonar.db.qualitygate.QualityGateConditionDto;
import org.sonar.db.qualitygate.QualityGateDto;
+import org.sonar.db.user.UserDto;
+import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
@@ -44,6 +46,7 @@ import org.sonarqube.ws.Qualitygates.ShowWsResponse.Condition;
import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.tuple;
+import static org.sonar.db.organization.OrganizationDto.Subscription.PAID;
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_GATES;
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES;
import static org.sonar.test.JsonAssert.assertJson;
@@ -65,44 +68,6 @@ public class ShowActionTest {
new QualityGatesWsSupport(db.getDbClient(), userSession, defaultOrganizationProvider)));
@Test
- public void verify_definition() {
- WebService.Action action = ws.getDef();
- assertThat(action.since()).isEqualTo("4.3");
- assertThat(action.changelog()).extracting(Change::getVersion, Change::getDescription)
- .containsExactlyInAnyOrder(
- tuple("7.0", "'isBuiltIn' field is added to the response"),
- tuple("7.0", "'actions' field is added in the response"));
- assertThat(action.params())
- .extracting(Param::key, Param::isRequired)
- .containsExactlyInAnyOrder(
- tuple("id", false),
- tuple("name", false),
- tuple("organization", false));
- }
-
- @Test
- public void json_example() {
- OrganizationDto organization = db.organizations().insert();
- userSession.logIn("admin").addPermission(ADMINISTER_QUALITY_GATES, organization);
- QGateWithOrgDto qualityGate = db.qualityGates().insertQualityGate(organization, qg -> qg.setName("My Quality Gate"));
- QGateWithOrgDto qualityGate2 = db.qualityGates().insertQualityGate(organization, qg -> qg.setName("My Quality Gate 2"));
- db.qualityGates().setDefaultQualityGate(organization, qualityGate2);
- MetricDto blockerViolationsMetric = db.measures().insertMetric(m -> m.setKey("blocker_violations"));
- MetricDto criticalViolationsMetric = db.measures().insertMetric(m -> m.setKey("critical_violations"));
- db.qualityGates().addCondition(qualityGate, blockerViolationsMetric, c -> c.setOperator("GT").setPeriod(null).setErrorThreshold("0").setWarningThreshold(null));
- db.qualityGates().addCondition(qualityGate, criticalViolationsMetric, c -> c.setOperator("LT").setPeriod(1).setErrorThreshold(null).setWarningThreshold("0"));
-
- String response = ws.newRequest()
- .setParam("name", qualityGate.getName())
- .setParam("organization", organization.getKey())
- .execute()
- .getInput();
-
- assertJson(response).ignoreFields("id")
- .isSimilarTo(getClass().getResource("show-example.json"));
- }
-
- @Test
public void show() {
OrganizationDto organization = db.organizations().insert();
QGateWithOrgDto qualityGate = db.qualityGates().insertQualityGate(organization);
@@ -273,6 +238,24 @@ public class ShowActionTest {
}
@Test
+ public void show_on_paid_organization() {
+ OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
+ QGateWithOrgDto qualityGate = db.qualityGates().insertQualityGate(organization);
+ db.qualityGates().setDefaultQualityGate(organization, qualityGate);
+ MetricDto metric = db.measures().insertMetric();
+ db.qualityGates().addCondition(qualityGate, metric);
+ UserDto user = db.users().insertUser();
+ userSession.logIn(user).addMembership(organization);
+
+ ShowWsResponse response = ws.newRequest()
+ .setParam("name", qualityGate.getName())
+ .setParam("organization", organization.getKey())
+ .executeProtobuf(ShowWsResponse.class);
+
+ assertThat(response.getConditionsList()).hasSize(1);
+ }
+
+ @Test
public void fail_when_no_name_or_id() {
OrganizationDto organization = db.organizations().insert();
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(organization);
@@ -390,4 +373,57 @@ public class ShowActionTest {
.setParam("organization", organization.getKey())
.execute();
}
+
+ @Test
+ public void fail_on_paid_organization_when_not_member() {
+ OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
+ QGateWithOrgDto qualityGate = db.qualityGates().insertQualityGate(organization);
+
+ expectedException.expect(ForbiddenException.class);
+ expectedException.expectMessage(format("You're not member of organization '%s'", organization.getKey()));
+
+ ws.newRequest()
+ .setParam("name", qualityGate.getName())
+ .setParam("organization", organization.getKey())
+ .execute();
+ }
+
+ @Test
+ public void json_example() {
+ OrganizationDto organization = db.organizations().insert();
+ userSession.logIn("admin").addPermission(ADMINISTER_QUALITY_GATES, organization);
+ QGateWithOrgDto qualityGate = db.qualityGates().insertQualityGate(organization, qg -> qg.setName("My Quality Gate"));
+ QGateWithOrgDto qualityGate2 = db.qualityGates().insertQualityGate(organization, qg -> qg.setName("My Quality Gate 2"));
+ db.qualityGates().setDefaultQualityGate(organization, qualityGate2);
+ MetricDto blockerViolationsMetric = db.measures().insertMetric(m -> m.setKey("blocker_violations"));
+ MetricDto criticalViolationsMetric = db.measures().insertMetric(m -> m.setKey("critical_violations"));
+ db.qualityGates().addCondition(qualityGate, blockerViolationsMetric, c -> c.setOperator("GT").setPeriod(null).setErrorThreshold("0").setWarningThreshold(null));
+ db.qualityGates().addCondition(qualityGate, criticalViolationsMetric, c -> c.setOperator("LT").setPeriod(1).setErrorThreshold(null).setWarningThreshold("0"));
+
+ String response = ws.newRequest()
+ .setParam("name", qualityGate.getName())
+ .setParam("organization", organization.getKey())
+ .execute()
+ .getInput();
+
+ assertJson(response).ignoreFields("id")
+ .isSimilarTo(getClass().getResource("show-example.json"));
+ }
+
+ @Test
+ public void verify_definition() {
+ WebService.Action action = ws.getDef();
+ assertThat(action.since()).isEqualTo("4.3");
+ assertThat(action.changelog()).extracting(Change::getVersion, Change::getDescription)
+ .containsExactlyInAnyOrder(
+ tuple("7.0", "'isBuiltIn' field is added to the response"),
+ tuple("7.0", "'actions' field is added in the response"));
+ assertThat(action.params())
+ .extracting(Param::key, Param::isRequired)
+ .containsExactlyInAnyOrder(
+ tuple("id", false),
+ tuple("name", false),
+ tuple("organization", false));
+ }
+
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/BackupActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/BackupActionTest.java
index 672d218c9fe..0524ea98fbe 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/BackupActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/BackupActionTest.java
@@ -116,8 +116,7 @@ public class BackupActionTest {
OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setLanguage(A_LANGUAGE));
UserDto user = db.users().insertUser();
- db.organizations().addMember(organization, user);
- userSession.logIn(user);
+ userSession.logIn(user).addMembership(organization);
TestResponse response = tester.newRequest()
.setParam("organization", organization.getKey())
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionTest.java
index 12498e06f90..3dee5f66033 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionTest.java
@@ -368,8 +368,7 @@ public class ChangelogActionTest {
public void changelog_on_paid_organization() {
OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
UserDto user = db.users().insertUser();
- db.organizations().addMember(organization, user);
- userSession.logIn(user);
+ userSession.logIn(user).addMembership(organization);
QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
RuleDefinitionDto rule = db.rules().insert();
insertChange(qualityProfile, ActiveRuleChange.Type.ACTIVATED, db.users().insertUser(),
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/CompareActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/CompareActionTest.java
index 250b6c86686..52585ca17b4 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/CompareActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/CompareActionTest.java
@@ -154,8 +154,7 @@ public class CompareActionTest {
QProfileDto left = db.qualityProfiles().insert(organization);
QProfileDto right = db.qualityProfiles().insert(organization);
UserDto user = db.users().insertUser();
- db.organizations().addMember(organization, user);
- userSession.logIn(user);
+ userSession.logIn(user).addMembership(organization);
ws.newRequest()
.setParam("leftKey", left.getKee())
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ExportActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ExportActionTest.java
index 85ae3a93525..e91f383e94a 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ExportActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ExportActionTest.java
@@ -185,8 +185,7 @@ public class ExportActionTest {
OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
QProfileDto profile = createProfile(organization, false);
UserDto user = db.users().insertUser();
- db.organizations().addMember(organization, user);
- userSession.logIn(user);
+ userSession.logIn(user).addMembership(organization);
WsActionTester tester = newWsActionTester(newExporter("polop"));
String result = tester.newRequest()
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/InheritanceActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/InheritanceActionTest.java
index 25b501a72bd..01d375228fe 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/InheritanceActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/InheritanceActionTest.java
@@ -217,8 +217,7 @@ public class InheritanceActionTest {
OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
UserDto user = db.users().insertUser();
- db.organizations().addMember(organization, user);
- userSession.logIn(user);
+ userSession.logIn(user).addMembership(organization);
ws.newRequest()
.setParam(PARAM_ORGANIZATION, organization.getKey())
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java
index 506f769c7ee..e1f84a71093 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java
@@ -424,8 +424,7 @@ public class SearchActionTest {
OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
QProfileDto qProfile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO1.getKey()));
UserDto user = db.users().insertUser();
- db.organizations().addMember(organization, user);
- userSession.logIn(user);
+ userSession.logIn(user).addMembership(organization);
SearchWsResponse result = call(ws.newRequest().setParam(PARAM_ORGANIZATION, organization.getKey()));
diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/AppActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/AppActionTest.java
index 0d219a03efb..d2e73661f75 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/AppActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/AppActionTest.java
@@ -30,15 +30,20 @@ import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.permission.OrganizationPermission;
import org.sonar.db.rule.RuleRepositoryDto;
+import org.sonar.db.user.UserDto;
+import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.language.LanguageTesting;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsActionTester;
+import org.sonarqube.ws.Rules;
+import static java.lang.String.format;
import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.db.organization.OrganizationDto.Subscription.PAID;
import static org.sonar.test.JsonAssert.assertJson;
public class AppActionTest {
@@ -57,11 +62,11 @@ public class AppActionTest {
private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
private RuleWsSupport wsSupport = new RuleWsSupport(db.getDbClient(), userSession, defaultOrganizationProvider);
private AppAction underTest = new AppAction(languages, db.getDbClient(), userSession, wsSupport);
- private WsActionTester tester = new WsActionTester(underTest);
+ private WsActionTester ws = new WsActionTester(underTest);
@Test
public void test_definition() {
- WebService.Action definition = tester.getDef();
+ WebService.Action definition = ws.getDef();
assertThat(definition.isInternal()).isTrue();
assertThat(definition.key()).isEqualTo("app");
@@ -76,7 +81,7 @@ public class AppActionTest {
public void response_contains_rule_repositories() {
insertRules();
- String json = tester.newRequest().execute().getInput();
+ String json = ws.newRequest().execute().getInput();
assertJson(json).isSimilarTo("{" +
"\"repositories\": [" +
" {" +
@@ -95,7 +100,7 @@ public class AppActionTest {
@Test
public void response_contains_languages() {
- String json = tester.newRequest().execute().getInput();
+ String json = ws.newRequest().execute().getInput();
assertJson(json).isSimilarTo("{" +
"\"languages\": {" +
@@ -106,20 +111,28 @@ public class AppActionTest {
}
@Test
- public void throw_NotFoundException_if_organization_does_not_exist() {
- expectedException.expect(NotFoundException.class);
- expectedException.expectMessage("No organization with key 'does_not_exist'");
+ public void response_on_paid_organization() {
+ OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
+ UserDto user = db.users().insertUser();
+ userSession.logIn(user).addMembership(organization);
- tester.newRequest()
- .setParam("organization", "does_not_exist")
- .execute();
+ String json = ws.newRequest()
+ .setParam("organization", organization.getKey())
+ .execute().getInput();;
+
+ assertJson(json).isSimilarTo("{" +
+ "\"languages\": {" +
+ " \"xoo\": \"Xoo\"," +
+ " \"ws\": \"Whitespace\"" +
+ " }" +
+ "}");
}
@Test
public void canWrite_is_true_if_user_is_profile_administrator_of_default_organization() {
userSession.addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, db.getDefaultOrganization());
- String json = tester.newRequest().execute().getInput();
+ String json = ws.newRequest().execute().getInput();
assertJson(json).isSimilarTo("{ \"canWrite\": true }");
}
@@ -129,7 +142,7 @@ public class AppActionTest {
OrganizationDto organization = db.organizations().insert();
userSession.addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization);
- String json = tester.newRequest()
+ String json = ws.newRequest()
.setParam("organization", organization.getKey())
.execute().getInput();
@@ -142,7 +155,7 @@ public class AppActionTest {
OrganizationDto organization2 = db.organizations().insert();
userSession.addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization1);
- String json = tester.newRequest()
+ String json = ws.newRequest()
.setParam("organization", organization2.getKey())
.execute().getInput();
@@ -154,11 +167,34 @@ public class AppActionTest {
OrganizationDto organization = db.organizations().insert();
userSession.addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization);
- String json = tester.newRequest().execute().getInput();
+ String json = ws.newRequest().execute().getInput();
assertJson(json).isSimilarTo("{ \"canWrite\": false }");
}
+ @Test
+ public void throw_NotFoundException_if_organization_does_not_exist() {
+ expectedException.expect(NotFoundException.class);
+ expectedException.expectMessage("No organization with key 'does_not_exist'");
+
+ ws.newRequest()
+ .setParam("organization", "does_not_exist")
+ .execute();
+ }
+
+ @Test
+ public void fail_on_paid_organization_when_not_member() {
+ OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
+ db.rules().insert();
+
+ expectedException.expect(ForbiddenException.class);
+ expectedException.expectMessage(format("You're not member of organization '%s'", organization.getKey()));
+
+ ws.newRequest()
+ .setParam("organization", organization.getKey())
+ .executeProtobuf(Rules.SearchResponse.class);
+ }
+
private void insertRules() {
RuleRepositoryDto repo1 = new RuleRepositoryDto("xoo", "xoo", "SonarQube");
RuleRepositoryDto repo2 = new RuleRepositoryDto("squid", "ws", "SonarQube");
diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/RuleQueryFactoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/RuleQueryFactoryTest.java
index 4296f924633..d18c61f35fc 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/RuleQueryFactoryTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/RuleQueryFactoryTest.java
@@ -19,7 +19,6 @@
*/
package org.sonar.server.rule.ws;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -32,13 +31,17 @@ import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.QProfileDto;
+import org.sonar.db.user.UserDto;
+import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
import org.sonar.server.rule.index.RuleQuery;
+import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsAction;
import org.sonar.server.ws.WsActionTester;
+import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.api.rule.RuleStatus.DEPRECATED;
import static org.sonar.api.rule.RuleStatus.READY;
@@ -50,14 +53,15 @@ import static org.sonar.api.rules.RuleType.CODE_SMELL;
import static org.sonar.api.server.ws.WebService.Param.ASCENDING;
import static org.sonar.api.server.ws.WebService.Param.SORT;
import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY;
+import static org.sonar.db.organization.OrganizationDto.Subscription.PAID;
import static org.sonar.db.qualityprofile.ActiveRuleDto.INHERITED;
import static org.sonar.db.qualityprofile.ActiveRuleDto.OVERRIDES;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ACTIVATION;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ACTIVE_SEVERITIES;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_AVAILABLE_SINCE;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_COMPARE_TO_PROFILE;
-import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_INHERITANCE;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_INCLUDE_EXTERNAL;
+import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_INHERITANCE;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_IS_TEMPLATE;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_LANGUAGES;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ORGANIZATION;
@@ -74,21 +78,17 @@ import static org.sonar.server.rule.ws.SearchAction.defineGenericRuleSearchParam
public class RuleQueryFactoryTest {
@Rule
- public DbTester dbTester = DbTester.create(System2.INSTANCE);
+ public DbTester db = DbTester.create(System2.INSTANCE);
@Rule
public ExpectedException expectedException = ExpectedException.none();
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
- private DbClient dbClient = dbTester.getDbClient();
+ private DbClient dbClient = db.getDbClient();
- private RuleQueryFactory underTest = new RuleQueryFactory(dbClient, new RuleWsSupport(dbClient, null, TestDefaultOrganizationProvider.from(dbTester)));
+ private RuleQueryFactory underTest = new RuleQueryFactory(dbClient, new RuleWsSupport(dbClient, userSession, TestDefaultOrganizationProvider.from(db)));
private FakeAction fakeAction = new FakeAction(underTest);
- private OrganizationDto organization;
-
- @Before
- public void before() {
- organization = dbTester.organizations().insert();
- }
@Test
public void create_empty_query() {
@@ -119,8 +119,9 @@ public class RuleQueryFactoryTest {
@Test
public void create_rule_search_query() {
- QProfileDto qualityProfile = dbTester.qualityProfiles().insert(organization);
- QProfileDto compareToQualityProfile = dbTester.qualityProfiles().insert(organization);
+ OrganizationDto organization = db.organizations().insert();
+ QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
+ QProfileDto compareToQualityProfile = db.qualityProfiles().insert(organization);
RuleQuery result = executeRuleSearchQuery(
PARAM_RULE_KEY, "ruleKey",
@@ -152,19 +153,21 @@ public class RuleQueryFactoryTest {
@Test
public void include_external_is_mandatory_for_rule_search_query() {
- dbTester.qualityProfiles().insert(organization);
- dbTester.qualityProfiles().insert(organization);
+ OrganizationDto organization = db.organizations().insert();
+ db.qualityProfiles().insert(organization);
+ db.qualityProfiles().insert(organization);
Request request = new SimpleGetRequest();
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("The 'include_external' parameter is missing");
- underTest.createRuleSearchQuery(dbTester.getSession(), request);
+ underTest.createRuleSearchQuery(db.getSession(), request);
}
@Test
public void create_query() {
- QProfileDto qualityProfile = dbTester.qualityProfiles().insert(organization);
- QProfileDto compareToQualityProfile = dbTester.qualityProfiles().insert(organization);
+ OrganizationDto organization = db.organizations().insert();
+ QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
+ QProfileDto compareToQualityProfile = db.qualityProfiles().insert(organization);
RuleQuery result = execute(
PARAM_RULE_KEY, "ruleKey",
@@ -194,33 +197,10 @@ public class RuleQueryFactoryTest {
assertThat(result.includeExternal()).isFalse();
}
- private void assertResult(RuleQuery result, QProfileDto qualityProfile, QProfileDto compareToQualityProfile) {
- assertThat(result.getKey()).isEqualTo("ruleKey");
-
- assertThat(result.getActivation()).isTrue();
- assertThat(result.getActiveSeverities()).containsOnly(MINOR, MAJOR);
- assertThat(result.isAscendingSort()).isFalse();
- assertThat(result.getAvailableSinceLong()).isNotNull();
- assertThat(result.getInheritance()).containsOnly(INHERITED, OVERRIDES);
- assertThat(result.isTemplate()).isTrue();
- assertThat(result.getLanguages()).containsOnly(qualityProfile.getLanguage());
- assertThat(result.getQueryText()).isEqualTo("S001");
- assertThat(result.getQProfile().getKee()).isEqualTo(qualityProfile.getKee());
- assertThat(result.getCompareToQProfile().getKee()).isEqualTo(compareToQualityProfile.getKee());
- assertThat(result.getOrganization().getUuid()).isEqualTo(organization.getUuid());
- assertThat(result.getRepositories()).containsOnly("pmd", "checkstyle");
- assertThat(result.getRuleKey()).isNull();
- assertThat(result.getSeverities()).containsOnly(MINOR, CRITICAL);
- assertThat(result.getStatuses()).containsOnly(DEPRECATED, READY);
- assertThat(result.getTags()).containsOnly("tag1", "tag2");
- assertThat(result.templateKey()).isEqualTo("architectural");
- assertThat(result.getTypes()).containsOnly(BUG, CODE_SMELL);
- assertThat(result.getSortField()).isEqualTo("updatedAt");
- }
-
@Test
public void use_quality_profiles_language_if_available() {
- QProfileDto qualityProfile = dbTester.qualityProfiles().insert(organization);
+ OrganizationDto organization = db.organizations().insert();
+ QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
String qualityProfileKey = qualityProfile.getKee();
RuleQuery result = execute(
@@ -241,7 +221,8 @@ public class RuleQueryFactoryTest {
@Test
public void create_query_add_language_from_profile() {
- QProfileDto profile = dbTester.qualityProfiles().insert(organization, p -> p.setName("Sonar way").setLanguage("xoo").setKee("sonar-way"));
+ OrganizationDto organization = db.organizations().insert();
+ QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setName("Sonar way").setLanguage("xoo").setKee("sonar-way"));
RuleQuery result = execute(
PARAM_QPROFILE, profile.getKee(),
@@ -253,7 +234,8 @@ public class RuleQueryFactoryTest {
@Test
public void filter_on_quality_profiles_organization_if_searching_for_actives_with_no_organization_specified() {
- QProfileDto profile = dbTester.qualityProfiles().insert(organization, p -> p.setName("Sonar way").setLanguage("xoo").setKee("sonar-way"));
+ OrganizationDto organization = db.organizations().insert();
+ QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setName("Sonar way").setLanguage("xoo").setKee("sonar-way"));
RuleQuery result = execute(
PARAM_ACTIVATION, "true",
@@ -264,7 +246,8 @@ public class RuleQueryFactoryTest {
@Test
public void filter_on_compare_to() {
- QProfileDto compareToProfile = dbTester.qualityProfiles().insert(organization);
+ OrganizationDto organization = db.organizations().insert();
+ QProfileDto compareToProfile = db.qualityProfiles().insert(organization);
RuleQuery result = execute(
PARAM_ORGANIZATION, organization.getKey(),
@@ -274,11 +257,35 @@ public class RuleQueryFactoryTest {
}
@Test
+ public void filter_by_qprofile_when_subscription_is_paid_and_user_is_member() {
+ OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
+ QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
+ UserDto user = db.users().insertUser();
+ userSession.logIn(user).addMembership(organization);
+
+ RuleQuery result = execute(PARAM_QPROFILE, qualityProfile.getKee());
+
+ assertThat(result.getOrganization().getUuid()).isEqualTo(organization.getUuid());
+ }
+
+ @Test
+ public void filter_by_organization_when_subscription_is_paid_and_user_is_member() {
+ OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
+ QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
+ UserDto user = db.users().insertUser();
+ userSession.logIn(user).addMembership(organization);
+
+ RuleQuery result = execute(PARAM_ORGANIZATION, organization.getKey());
+
+ assertThat(result.getOrganization().getUuid()).isEqualTo(organization.getUuid());
+ }
+
+ @Test
public void fail_if_organization_and_quality_profile_are_contradictory() {
- OrganizationDto organization1 = dbTester.organizations().insert();
- OrganizationDto organization2 = dbTester.organizations().insert();
+ OrganizationDto organization1 = db.organizations().insert();
+ OrganizationDto organization2 = db.organizations().insert();
- QProfileDto qualityProfile = dbTester.qualityProfiles().insert(organization1);
+ QProfileDto qualityProfile = db.qualityProfiles().insert(organization1);
String qualityProfileKey = qualityProfile.getKee();
String organization2Key = organization2.getKey();
@@ -292,11 +299,11 @@ public class RuleQueryFactoryTest {
@Test
public void fail_if_organization_and_compare_to_quality_profile_are_contradictory() {
- OrganizationDto organization = dbTester.organizations().insert();
- QProfileDto qualityProfile = dbTester.qualityProfiles().insert(organization);
+ OrganizationDto organization = db.organizations().insert();
+ QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
- OrganizationDto otherOrganization = dbTester.organizations().insert();
- QProfileDto compareToQualityProfile = dbTester.qualityProfiles().insert(otherOrganization);
+ OrganizationDto otherOrganization = db.organizations().insert();
+ QProfileDto compareToQualityProfile = db.qualityProfiles().insert(otherOrganization);
expectedException.expect(IllegalArgumentException.class);
expectedException
@@ -309,7 +316,8 @@ public class RuleQueryFactoryTest {
@Test
public void fail_when_organization_does_not_exist() {
- QProfileDto qualityProfile = dbTester.qualityProfiles().insert(organization);
+ OrganizationDto organization = db.organizations().insert();
+ QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
String qualityProfileKey = qualityProfile.getKee();
expectedException.expect(NotFoundException.class);
@@ -329,7 +337,8 @@ public class RuleQueryFactoryTest {
@Test
public void fail_when_compare_to_profile_does_not_exist() {
- QProfileDto qualityProfile = dbTester.qualityProfiles().insert(organization);
+ OrganizationDto organization = db.organizations().insert();
+ QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
expectedException.expect(NotFoundException.class);
expectedException.expectMessage("The specified qualityProfile 'unknown' does not exist");
@@ -338,6 +347,51 @@ public class RuleQueryFactoryTest {
PARAM_COMPARE_TO_PROFILE, "unknown");
}
+ @Test
+ public void fail_when_searching_by_organization_when_subscription_is_paid_and_user_is_not_member() {
+ OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
+
+ expectedException.expect(ForbiddenException.class);
+ expectedException.expectMessage(format("You're not member of organization '%s'", organization.getKey()));
+
+ execute(PARAM_ORGANIZATION, organization.getKey());
+ }
+
+ @Test
+ public void fail_when_searching_by_qprofile_when_subscription_is_paid_and_user_is_not_member() {
+ OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
+ QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
+
+ expectedException.expect(ForbiddenException.class);
+ expectedException.expectMessage(format("You're not member of organization '%s'", organization.getKey()));
+
+ execute(PARAM_QPROFILE, qualityProfile.getKee());
+ }
+
+ private void assertResult(RuleQuery result, QProfileDto qualityProfile, QProfileDto compareToQualityProfile) {
+ assertThat(result.getKey()).isEqualTo("ruleKey");
+
+ assertThat(result.getActivation()).isTrue();
+ assertThat(result.getActiveSeverities()).containsOnly(MINOR, MAJOR);
+ assertThat(result.isAscendingSort()).isFalse();
+ assertThat(result.getAvailableSinceLong()).isNotNull();
+ assertThat(result.getInheritance()).containsOnly(INHERITED, OVERRIDES);
+ assertThat(result.isTemplate()).isTrue();
+ assertThat(result.getLanguages()).containsOnly(qualityProfile.getLanguage());
+ assertThat(result.getQueryText()).isEqualTo("S001");
+ assertThat(result.getQProfile().getKee()).isEqualTo(qualityProfile.getKee());
+ assertThat(result.getCompareToQProfile().getKee()).isEqualTo(compareToQualityProfile.getKee());
+ assertThat(result.getOrganization().getUuid()).isEqualTo(qualityProfile.getOrganizationUuid());
+ assertThat(result.getRepositories()).containsOnly("pmd", "checkstyle");
+ assertThat(result.getRuleKey()).isNull();
+ assertThat(result.getSeverities()).containsOnly(MINOR, CRITICAL);
+ assertThat(result.getStatuses()).containsOnly(DEPRECATED, READY);
+ assertThat(result.getTags()).containsOnly("tag1", "tag2");
+ assertThat(result.templateKey()).isEqualTo("architectural");
+ assertThat(result.getTypes()).containsOnly(BUG, CODE_SMELL);
+ assertThat(result.getSortField()).isEqualTo("updatedAt");
+ }
+
private RuleQuery execute(String... paramsKeyAndValue) {
WsActionTester ws = new WsActionTester(fakeAction);
TestRequest request = ws.newRequest();
@@ -354,7 +408,7 @@ public class RuleQueryFactoryTest {
request.setParam(paramsKeyAndValue[i], paramsKeyAndValue[i + 1]);
}
- return underTest.createRuleSearchQuery(dbTester.getSession(), request);
+ return underTest.createRuleSearchQuery(db.getSession(), request);
}
private class FakeAction implements WsAction {
@@ -375,7 +429,7 @@ public class RuleQueryFactoryTest {
@Override
public void handle(Request request, Response response) {
- ruleQuery = ruleQueryFactory.createRuleQuery(dbTester.getSession(), request);
+ ruleQuery = ruleQueryFactory.createRuleQuery(db.getSession(), request);
}
RuleQuery getRuleQuery() {
diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java
index 61cade0fb54..6114ac6ab6e 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java
@@ -45,6 +45,7 @@ import org.sonar.db.rule.RuleMetadataDto;
import org.sonar.db.rule.RuleParamDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.es.EsTester;
+import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.language.LanguageTesting;
import org.sonar.server.organization.DefaultOrganizationProvider;
@@ -69,6 +70,7 @@ import org.sonarqube.ws.Rules;
import org.sonarqube.ws.Rules.Rule;
import org.sonarqube.ws.Rules.SearchResponse;
+import static java.lang.String.format;
import static java.util.Arrays.asList;
import static java.util.Arrays.stream;
import static java.util.Collections.singleton;
@@ -81,6 +83,7 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.sonar.api.rule.Severity.BLOCKER;
+import static org.sonar.db.organization.OrganizationDto.Subscription.PAID;
import static org.sonar.db.rule.RuleTesting.setSystemTags;
import static org.sonar.db.rule.RuleTesting.setTags;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ACTIVATION;
@@ -440,7 +443,7 @@ public class SearchActionTest {
}
@Test
- public void should_return_specified_fields() throws Exception {
+ public void should_return_specified_fields() {
RuleDefinitionDto rule = createJavaRule();
indexRules();
@@ -918,6 +921,37 @@ public class SearchActionTest {
.containsExactlyInAnyOrder(anotherProfileRule1.getKey().toString(), anotherProfileRule2.getKey().toString());
}
+ @Test
+ public void returns_rules_on_paid_organization() {
+ OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
+ RuleDefinitionDto rule = db.rules().insert();
+ indexRules();
+ UserDto user = db.users().insertUser();
+ userSession.logIn(user).addMembership(organization);
+
+ SearchResponse result = ws.newRequest()
+ .setParam("organization", organization.getKey())
+ .executeProtobuf(SearchResponse.class);
+
+ assertThat(result.getRulesList())
+ .extracting(Rule::getKey)
+ .containsExactlyInAnyOrder(rule.getKey().toString());
+ }
+
+ @Test
+ public void fail_on_paid_organization_when_not_member() {
+ OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
+ db.rules().insert();
+ indexRules();
+
+ expectedException.expect(ForbiddenException.class);
+ expectedException.expectMessage(format("You're not member of organization '%s'", organization.getKey()));
+
+ ws.newRequest()
+ .setParam("organization", organization.getKey())
+ .executeProtobuf(SearchResponse.class);
+ }
+
@SafeVarargs
private final <T> void checkField(RuleDefinitionDto rule, String fieldName, Extractor<Rule, T> responseExtractor, T... expected) {
SearchResponse result = ws.newRequest()
diff --git a/server/sonar-server/src/test/java/org/sonar/server/tester/AbstractMockUserSession.java b/server/sonar-server/src/test/java/org/sonar/server/tester/AbstractMockUserSession.java
index c252d0822e7..942f2336cef 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/tester/AbstractMockUserSession.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/tester/AbstractMockUserSession.java
@@ -28,6 +28,7 @@ import java.util.Set;
import org.sonar.api.web.UserRole;
import org.sonar.core.permission.ProjectPermissions;
import org.sonar.db.component.ComponentDto;
+import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.permission.OrganizationPermission;
import org.sonar.server.user.AbstractUserSession;
@@ -39,7 +40,8 @@ public abstract class AbstractMockUserSession<T extends AbstractMockUserSession>
private HashMultimap<String, String> projectUuidByPermission = HashMultimap.create();
private final HashMultimap<String, OrganizationPermission> permissionsByOrganizationUuid = HashMultimap.create();
private Map<String, String> projectUuidByComponentUuid = newHashMap();
- private Set<String> projectPermissionsCheckedByUuid = new HashSet<>();
+ private Set<String> projectPermissions = new HashSet<>();
+ private Set<String> organizationMembership = new HashSet<>();
private boolean systemAdministrator = false;
protected AbstractMockUserSession(Class<T> clazz) {
@@ -66,8 +68,8 @@ public abstract class AbstractMockUserSession<T extends AbstractMockUserSession>
if (component.projectUuid().equals(component.uuid()) && !component.isPrivate()) {
this.projectUuidByPermission.put(UserRole.USER, component.uuid());
this.projectUuidByPermission.put(UserRole.CODEVIEWER, component.uuid());
- this.projectPermissionsCheckedByUuid.add(UserRole.USER);
- this.projectPermissionsCheckedByUuid.add(UserRole.CODEVIEWER);
+ this.projectPermissions.add(UserRole.USER);
+ this.projectPermissions.add(UserRole.CODEVIEWER);
}
this.projectUuidByComponentUuid.put(component.uuid(), component.projectUuid());
});
@@ -81,7 +83,7 @@ public abstract class AbstractMockUserSession<T extends AbstractMockUserSession>
"public component %s can't be granted public permission %s", component.uuid(), permission);
});
registerComponents(components);
- this.projectPermissionsCheckedByUuid.add(permission);
+ this.projectPermissions.add(permission);
Arrays.stream(components)
.forEach(component -> this.projectUuidByPermission.put(permission, component.projectUuid()));
return clazz.cast(this);
@@ -94,7 +96,7 @@ public abstract class AbstractMockUserSession<T extends AbstractMockUserSession>
@Override
protected boolean hasProjectUuidPermission(String permission, String projectUuid) {
- return projectPermissionsCheckedByUuid.contains(permission) && projectUuidByPermission.get(permission).contains(projectUuid);
+ return projectPermissions.contains(permission) && projectUuidByPermission.get(permission).contains(projectUuid);
}
public T setSystemAdministrator(boolean b) {
@@ -106,4 +108,14 @@ public abstract class AbstractMockUserSession<T extends AbstractMockUserSession>
public boolean isSystemAdministrator() {
return isRoot() || systemAdministrator;
}
+
+ @Override
+ protected boolean hasMembershipImpl(OrganizationDto organization) {
+ return organizationMembership.contains(organization.getUuid());
+ }
+
+ public void addOrganizationMembership(OrganizationDto organization) {
+ this.organizationMembership.add(organization.getUuid());
+ }
+
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/tester/AnonymousMockUserSession.java b/server/sonar-server/src/test/java/org/sonar/server/tester/AnonymousMockUserSession.java
index d3d535e13c9..98af9348a66 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/tester/AnonymousMockUserSession.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/tester/AnonymousMockUserSession.java
@@ -21,6 +21,7 @@ package org.sonar.server.tester;
import java.util.Collection;
import java.util.Collections;
+import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.user.GroupDto;
public class AnonymousMockUserSession extends AbstractMockUserSession<AnonymousMockUserSession> {
@@ -62,4 +63,9 @@ public class AnonymousMockUserSession extends AbstractMockUserSession<AnonymousM
public Collection<GroupDto> getGroups() {
return Collections.emptyList();
}
+
+ @Override
+ public boolean hasMembershipImpl(OrganizationDto organization) {
+ return false;
+ }
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/tester/MockUserSession.java b/server/sonar-server/src/test/java/org/sonar/server/tester/MockUserSession.java
index 90aae92ae16..91afb2ea4dd 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/tester/MockUserSession.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/tester/MockUserSession.java
@@ -113,4 +113,5 @@ public class MockUserSession extends AbstractMockUserSession<MockUserSession> {
this.groups = asList(groups);
return this;
}
+
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/tester/UserSessionRule.java b/server/sonar-server/src/test/java/org/sonar/server/tester/UserSessionRule.java
index 2c9418aefd8..a3df41abed9 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/tester/UserSessionRule.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/tester/UserSessionRule.java
@@ -333,4 +333,21 @@ public class UserSessionRule implements TestRule, UserSession {
currentUserSession.checkIsSystemAdministrator();
return this;
}
+
+ @Override
+ public boolean hasMembership(OrganizationDto organization) {
+ return currentUserSession.hasMembership(organization);
+ }
+
+ @Override
+ public UserSession checkMembership(OrganizationDto organization) {
+ currentUserSession.checkMembership(organization);
+ return this;
+ }
+
+ public UserSessionRule addMembership(OrganizationDto organization) {
+ ensureAbstractMockUserSession().addOrganizationMembership(organization);
+ return this;
+ }
+
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/DoPrivilegedTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/DoPrivilegedTest.java
index 76f65454665..d1e57065cda 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/user/DoPrivilegedTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/user/DoPrivilegedTest.java
@@ -26,6 +26,7 @@ import org.sonar.server.tester.MockUserSession;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
+import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto;
public class DoPrivilegedTest {
@@ -40,7 +41,7 @@ public class DoPrivilegedTest {
}
@Test
- public void should_allow_everything_in_privileged_block_only() {
+ public void allow_everything_in_privileged_block_only() {
UserSessionCatcherTask catcher = new UserSessionCatcherTask();
DoPrivileged.execute(catcher);
@@ -49,13 +50,14 @@ public class DoPrivilegedTest {
assertThat(catcher.userSession.isLoggedIn()).isFalse();
assertThat(catcher.userSession.hasComponentPermission("any permission", new ComponentDto())).isTrue();
assertThat(catcher.userSession.isSystemAdministrator()).isTrue();
+ assertThat(catcher.userSession.hasMembership(newOrganizationDto())).isTrue();
// verify session in place after task is done
assertThat(threadLocalUserSession.get()).isSameAs(session);
}
@Test
- public void should_loose_privileges_on_exception() {
+ public void loose_privileges_on_exception() {
UserSessionCatcherTask catcher = new UserSessionCatcherTask() {
@Override
protected void doPrivileged() {
@@ -74,6 +76,7 @@ public class DoPrivilegedTest {
// verify the session used inside Privileged task
assertThat(catcher.userSession.isLoggedIn()).isFalse();
assertThat(catcher.userSession.hasComponentPermission("any permission", new ComponentDto())).isTrue();
+ assertThat(catcher.userSession.hasMembership(newOrganizationDto())).isTrue();
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/ServerUserSessionTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/ServerUserSessionTest.java
index 28eae3aaaa2..d1e865d81d4 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/user/ServerUserSessionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/user/ServerUserSessionTest.java
@@ -639,6 +639,62 @@ public class ServerUserSessionTest {
assertThat(hasComponentPermissionByDtoOrUuid(underTest, "p1", fileInBranch)).isTrue();
}
+ @Test
+ public void hasMembership() {
+ OrganizationDto organization = db.organizations().insert();
+ UserDto notMember = db.users().insertUser();
+ UserDto member = db.users().insertUser();
+ db.organizations().addMember(organization, member);
+ UserDto root = db.users().makeRoot(db.users().insertUser());
+
+ assertThat(newUserSession(member).hasMembership(organization)).isTrue();
+ assertThat(newUserSession(notMember).hasMembership(organization)).isFalse();
+ assertThat(newUserSession(root).hasMembership(organization)).isTrue();
+ }
+
+ @Test
+ public void hasMembership_keeps_membership_in_cache() {
+ OrganizationDto organization = db.organizations().insert();
+ UserDto user = db.users().insertUser();
+ db.organizations().addMember(organization, user);
+
+ ServerUserSession session = newUserSession(user);
+ assertThat(session.hasMembership(organization)).isTrue();
+
+ // membership updated but not cache
+ db.getDbClient().organizationMemberDao().delete(db.getSession(), organization.getUuid(), user.getId());
+ db.commit();
+ assertThat(session.hasMembership(organization)).isTrue();
+ }
+
+ @Test
+ public void checkMembership_throws_ForbiddenException_when_user_is_not_member_of_organization() {
+ OrganizationDto organization = db.organizations().insert();
+ UserDto notMember = db.users().insertUser();
+
+ expectedException.expect(ForbiddenException.class);
+ expectedException.expectMessage(String.format("You're not member of organization '%s'", organization.getKey()));
+
+ newUserSession(notMember).checkMembership(organization);
+ }
+
+ @Test
+ public void checkMembership_succeeds_when_user_is_member_of_organization() {
+ OrganizationDto organization = db.organizations().insert();
+ UserDto member = db.users().insertUser();
+ db.organizations().addMember(organization, member);
+
+ newUserSession(member).checkMembership(organization);
+ }
+
+ @Test
+ public void checkMembership_succeeds_when_user_is_not_member_of_organization_but_root() {
+ OrganizationDto organization = db.organizations().insert();
+ UserDto root = db.users().makeRoot(db.users().insertUser());
+
+ newUserSession(root).checkMembership(organization);
+ }
+
private ServerUserSession newUserSession(@Nullable UserDto userDto) {
return new ServerUserSession(dbClient, organizationFlags, defaultOrganizationProvider, userDto);
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/TestUserSessionFactory.java b/server/sonar-server/src/test/java/org/sonar/server/user/TestUserSessionFactory.java
index 09aa329b1f9..d714a8d0262 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/user/TestUserSessionFactory.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/user/TestUserSessionFactory.java
@@ -22,9 +22,10 @@ package org.sonar.server.user;
import java.util.Collection;
import java.util.Optional;
import javax.annotation.Nullable;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.permission.OrganizationPermission;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
-import org.sonar.db.permission.OrganizationPermission;
import static java.util.Objects.requireNonNull;
@@ -116,6 +117,11 @@ public class TestUserSessionFactory implements UserSessionFactory {
throw notImplemented();
}
+ @Override
+ public boolean hasMembershipImpl(OrganizationDto organization) {
+ throw notImplemented();
+ }
+
private static RuntimeException notImplemented() {
return new UnsupportedOperationException("not implemented");
}