diff options
32 files changed, 331 insertions, 250 deletions
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/workflow/IssueWorkflow.java b/sonar-core/src/main/java/org/sonar/core/issue/workflow/IssueWorkflow.java index c532611afea..39105951297 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/workflow/IssueWorkflow.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/workflow/IssueWorkflow.java @@ -27,6 +27,7 @@ import org.sonar.api.issue.Issue; import org.sonar.api.issue.condition.HasResolution; import org.sonar.api.issue.internal.DefaultIssue; import org.sonar.api.issue.internal.IssueChangeContext; +import org.sonar.api.web.UserRole; import org.sonar.core.issue.IssueUpdater; import java.util.List; @@ -83,23 +84,26 @@ public class IssueWorkflow implements BatchComponent, ServerComponent, Startable .functions(new SetResolution(null), new SetCloseDate(false)) .build()) - // resolve as false-positive + // resolve as false-positive .transition(Transition.builder(DefaultTransitions.FALSE_POSITIVE) .from(Issue.STATUS_OPEN).to(Issue.STATUS_RESOLVED) .functions(new SetResolution(Issue.RESOLUTION_FALSE_POSITIVE), SetAssignee.UNASSIGN) + .requiredProjectPermission(UserRole.ISSUE_ADMIN) .build()) .transition(Transition.builder(DefaultTransitions.FALSE_POSITIVE) .from(Issue.STATUS_REOPENED).to(Issue.STATUS_RESOLVED) .functions(new SetResolution(Issue.RESOLUTION_FALSE_POSITIVE), SetAssignee.UNASSIGN) + .requiredProjectPermission(UserRole.ISSUE_ADMIN) .build()) .transition(Transition.builder(DefaultTransitions.FALSE_POSITIVE) .from(Issue.STATUS_CONFIRMED).to(Issue.STATUS_RESOLVED) .functions(new SetResolution(Issue.RESOLUTION_FALSE_POSITIVE), SetAssignee.UNASSIGN) + .requiredProjectPermission(UserRole.ISSUE_ADMIN) .build()) - // automatic transitions + // automatic transitions - // Close the "end of life" issues (disabled/deleted rule, deleted component) + // Close the "end of life" issues (disabled/deleted rule, deleted component) .transition(Transition.builder("automaticclose") .from(Issue.STATUS_OPEN).to(Issue.STATUS_CLOSED) .conditions(new IsEndOfLife(true)) diff --git a/sonar-core/src/main/java/org/sonar/core/issue/workflow/Transition.java b/sonar-core/src/main/java/org/sonar/core/issue/workflow/Transition.java index de5565f3fc6..4ba2ad4c491 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/workflow/Transition.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/workflow/Transition.java @@ -35,6 +35,7 @@ public class Transition { private final Condition[] conditions; private final Function[] functions; private final boolean automatic; + private String requiredProjectPermission; private Transition(TransitionBuilder builder) { key = builder.key; @@ -43,6 +44,7 @@ public class Transition { conditions = builder.conditions.toArray(new Condition[builder.conditions.size()]); functions = builder.functions.toArray(new Function[builder.functions.size()]); automatic = builder.automatic; + requiredProjectPermission = builder.requiredProjectPermission; } public String key() { @@ -78,6 +80,10 @@ public class Transition { return true; } + public String requiredProjectPermission() { + return requiredProjectPermission; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -126,6 +132,7 @@ public class Transition { private List<Condition> conditions = Lists.newArrayList(); private List<Function> functions = Lists.newArrayList(); private boolean automatic = false; + private String requiredProjectPermission; private TransitionBuilder(String key) { this.key = key; @@ -156,6 +163,11 @@ public class Transition { return this; } + public TransitionBuilder requiredProjectPermission(String requiredProjectPermission) { + this.requiredProjectPermission = requiredProjectPermission; + return this; + } + public Transition build() { Preconditions.checkArgument(!Strings.isNullOrEmpty(key), "Transition key must be set"); Preconditions.checkArgument(StringUtils.isAllLowerCase(key), "Transition key must be lower-case"); diff --git a/sonar-core/src/main/java/org/sonar/core/user/AuthorizationDao.java b/sonar-core/src/main/java/org/sonar/core/user/AuthorizationDao.java index 81495ecc7b2..c7f16d637a1 100644 --- a/sonar-core/src/main/java/org/sonar/core/user/AuthorizationDao.java +++ b/sonar-core/src/main/java/org/sonar/core/user/AuthorizationDao.java @@ -27,7 +27,11 @@ import org.sonar.core.persistence.MyBatis; import javax.annotation.Nullable; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; import static com.google.common.collect.Maps.newHashMap; @@ -39,58 +43,58 @@ public class AuthorizationDao implements ServerComponent { this.mybatis = mybatis; } - public Set<Long> keepAuthorizedComponentIds(Set<Long> componentIds, @Nullable Integer userId, String role) { + public Set<String> keepAuthorizedComponentKeys(Set<String> componentKeys, @Nullable Integer userId, String role) { SqlSession session = mybatis.openSession(); try { - return keepAuthorizedComponentIds(componentIds, userId, role, session); + return keepAuthorizedComponentKeys(componentKeys, userId, role, session); } finally { MyBatis.closeQuietly(session); } } - public Set<Long> keepAuthorizedComponentIds(Set<Long> componentIds, @Nullable Integer userId, String role, SqlSession session) { - if (componentIds.isEmpty()) { + public Set<String> keepAuthorizedComponentKeys(Set<String> componentKeys, @Nullable Integer userId, String role, SqlSession session) { + if (componentKeys.isEmpty()) { return Collections.emptySet(); } String sql; Map<String, Object> params; if (userId == null) { - sql = "keepAuthorizedComponentIdsForAnonymous"; - params = ImmutableMap.of("role", role, "componentIds", componentIds); + sql = "keepAuthorizedComponentKeysForAnonymous"; + params = ImmutableMap.of("role", role, "componentKeys", componentKeys); } else { - sql = "keepAuthorizedComponentIdsForUser"; - params = ImmutableMap.of("userId", userId, "role", role, "componentIds", componentIds); + sql = "keepAuthorizedComponentKeysForUser"; + params = ImmutableMap.of("userId", userId, "role", role, "componentKeys", componentKeys); } - return Sets.newHashSet(session.<Long>selectList(sql, params)); + return Sets.newHashSet(session.<String>selectList(sql, params)); } - public boolean isAuthorizedComponentId(long componentId, @Nullable Integer userId, String role) { - return keepAuthorizedComponentIds(Sets.newHashSet(componentId), userId, role).size() == 1; + public boolean isAuthorizedComponentKey(String componentKey, @Nullable Integer userId, String role) { + return keepAuthorizedComponentKeys(Sets.newHashSet(componentKey), userId, role).size() == 1; } - public Collection<Long> selectAuthorizedRootProjectsIds(@Nullable Integer userId, String role) { + public Collection<String> selectAuthorizedRootProjectsKeys(@Nullable Integer userId, String role) { SqlSession session = mybatis.openSession(); try { - return selectAuthorizedRootProjectsIds(userId, role, session); + return selectAuthorizedRootProjectsKeys(userId, role, session); } finally { MyBatis.closeQuietly(session); } } - public Collection<Long> selectAuthorizedRootProjectsIds(@Nullable Integer userId, String role, SqlSession session) { + public Collection<String> selectAuthorizedRootProjectsKeys(@Nullable Integer userId, String role, SqlSession session) { String sql; Map<String, Object> params = newHashMap(); - sql = "selectAuthorizedRootProjectsIds"; + sql = "selectAuthorizedRootProjectsKeys"; params.put("userId", userId); params.put("role", role); return session.selectList(sql, params); } - public List<String> selectGlobalPermissions(@Nullable String userLogin){ + public List<String> selectGlobalPermissions(@Nullable String userLogin) { SqlSession session = mybatis.openSession(); try { Map<String, Object> params = newHashMap(); diff --git a/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml b/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml index 9cc0a285dcd..c733b5e4f1d 100644 --- a/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml @@ -222,7 +222,8 @@ <sql id="selectQueryConditions"> <if test="componentRootKeys.size() == 0 and role != null"> - inner join (<include refid="org.sonar.core.user.AuthorizationMapper.selectAuthorizedRootProjectsIdsQuery" />) authorizedProjects on authorizedProjects.root_project_id=i.root_component_id + inner join projects root_project on root_project.id=i.root_component_id and root_project.enabled=${_true} + inner join (<include refid="org.sonar.core.user.AuthorizationMapper.selectAuthorizedRootProjectsKeysQuery" />) authorizedProjects on authorizedProjects.root_project_kee=root_project.kee </if> <if test="componentRootKeys.size() > 0"> inner join (<include refid="org.sonar.core.resource.ResourceMapper.selectAuthorizedChildrenComponentIdsQuery" />) authorizedComponents on authorizedComponents.project_id=i.component_id diff --git a/sonar-core/src/main/resources/org/sonar/core/resource/ResourceMapper.xml b/sonar-core/src/main/resources/org/sonar/core/resource/ResourceMapper.xml index 0599168ed89..af2115f0ea8 100644 --- a/sonar-core/src/main/resources/org/sonar/core/resource/ResourceMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/resource/ResourceMapper.xml @@ -218,9 +218,10 @@ from projects project_components inner join snapshots snapshot_components on snapshot_components.project_id = project_components.id and snapshot_components.islast = ${_true} inner join snapshots root_snapshot_components on root_snapshot_components.project_id = snapshot_components.root_project_id and root_snapshot_components.islast = ${_true} + inner join projects root_project on root_project.id=root_snapshot_components.project_id inner join ( - <include refid="org.sonar.core.user.AuthorizationMapper.selectAuthorizedRootProjectsIdsQuery" /> - ) authorized_projects on authorized_projects.root_project_id = root_snapshot_components.project_id + <include refid="org.sonar.core.user.AuthorizationMapper.selectAuthorizedRootProjectsKeysQuery" /> + ) authorized_projects on authorized_projects.root_project_kee = root_project.kee <where> and <foreach item="componentRootKey" index="index" collection="componentRootKeys" open="(" separator=" or " close=")"> project_components.kee=#{componentRootKey}</foreach> and project_components.enabled = ${_true} diff --git a/sonar-core/src/main/resources/org/sonar/core/user/AuthorizationMapper.xml b/sonar-core/src/main/resources/org/sonar/core/user/AuthorizationMapper.xml index b686a35a6d1..c50e70a9caf 100644 --- a/sonar-core/src/main/resources/org/sonar/core/user/AuthorizationMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/user/AuthorizationMapper.xml @@ -3,41 +3,41 @@ <mapper namespace="org.sonar.core.user.AuthorizationMapper"> - <select id="keepAuthorizedComponentIdsForUser" parameterType="map" resultType="long"> - SELECT p.id + <select id="keepAuthorizedComponentKeysForUser" parameterType="map" resultType="string"> + SELECT p.kee FROM group_roles gr, projects p WHERE gr.role=#{role} and (gr.group_id is null or gr.group_id in (select gu.group_id from groups_users gu where gu.user_id=#{userId})) and (gr.resource_id = p.root_id or gr.resource_id = p.id) and - <foreach collection="componentIds" open="(" close=")" item="element" index="index" separator=" or " >p.id=#{element}</foreach> + <foreach collection="componentKeys" open="(" close=")" item="element" index="index" separator=" or " >p.kee=#{element}</foreach> UNION - SELECT p.id + SELECT p.kee FROM user_roles ur, projects p WHERE ur.role=#{role} and ur.user_id=#{userId} and - <foreach collection="componentIds" open="(" close=")" item="element" index="index" separator=" or " >p.id=#{element}</foreach> + <foreach collection="componentKeys" open="(" close=")" item="element" index="index" separator=" or " >p.kee=#{element}</foreach> </select> - <select id="keepAuthorizedComponentIdsForAnonymous" parameterType="map" resultType="long"> - SELECT p.id + <select id="keepAuthorizedComponentKeysForAnonymous" parameterType="map" resultType="string"> + SELECT p.kee FROM group_roles gr, projects p WHERE gr.role=#{role} and gr.group_id is null and (gr.resource_id = p.root_id or gr.resource_id = p.id) and - <foreach collection="componentIds" open="(" close=")" item="element" index="index" separator=" or " >p.id=#{element}</foreach> + <foreach collection="componentKeys" open="(" close=")" item="element" index="index" separator=" or " >p.kee=#{element}</foreach> </select> - <select id="selectAuthorizedRootProjectsIds" parameterType="map" resultType="long"> - <include refid="selectAuthorizedRootProjectsIdsQuery" /> + <select id="selectAuthorizedRootProjectsKeys" parameterType="map" resultType="string"> + <include refid="selectAuthorizedRootProjectsKeysQuery" /> </select> - <sql id="selectAuthorizedRootProjectsIdsQuery"> + <sql id="selectAuthorizedRootProjectsKeysQuery"> <choose> <when test="userId != null"> - SELECT p.id as root_project_id + SELECT p.kee as root_project_kee FROM group_roles gr INNER JOIN projects p on p.id = gr.resource_id AND p.scope = 'PRJ' AND p.qualifier = 'TRK' <where> @@ -45,7 +45,7 @@ and (gr.group_id is null or gr.group_id in (select gu.group_id from groups_users gu where gu.user_id=#{userId})) </where> UNION - SELECT p.id as root_project_id + SELECT p.kee as root_project_kee FROM user_roles ur INNER JOIN projects p on p.id = ur.resource_id AND p.scope = 'PRJ' AND p.qualifier = 'TRK' <where> @@ -54,7 +54,7 @@ </where> </when> <otherwise> - SELECT p.id as root_project_id + SELECT p.kee as root_project_kee FROM group_roles gr INNER JOIN projects p on p.id = gr.resource_id AND p.scope = 'PRJ' AND p.qualifier = 'TRK' <where> diff --git a/sonar-core/src/test/java/org/sonar/core/user/AuthorizationDaoTest.java b/sonar-core/src/test/java/org/sonar/core/user/AuthorizationDaoTest.java index 2ad4c6e3f77..89b307d437e 100644 --- a/sonar-core/src/test/java/org/sonar/core/user/AuthorizationDaoTest.java +++ b/sonar-core/src/test/java/org/sonar/core/user/AuthorizationDaoTest.java @@ -31,7 +31,8 @@ import static org.fest.assertions.Assertions.assertThat; public class AuthorizationDaoTest extends AbstractDaoTestCase { private static final int USER = 100; - private static final long PROJECT = 300l, PACKAGE = 301l, FILE = 302l, FILE_IN_OTHER_PROJECT = 999l, EMPTY_PROJECT=400l; + private static final String PROJECT = "pj-w-snapshot", PACKAGE = "pj-w-snapshot:package", FILE = "pj-w-snapshot:file", FILE_IN_OTHER_PROJECT = "another", + EMPTY_PROJECT = "pj-wo-snapshot"; @Test public void user_should_be_authorized() { @@ -39,15 +40,15 @@ public class AuthorizationDaoTest extends AbstractDaoTestCase { setupData("user_should_be_authorized"); AuthorizationDao authorization = new AuthorizationDao(getMyBatis()); - Set<Long> componentIds = authorization.keepAuthorizedComponentIds( - Sets.<Long>newHashSet(PROJECT, PACKAGE, FILE, FILE_IN_OTHER_PROJECT, EMPTY_PROJECT), + Set<String> componentIds = authorization.keepAuthorizedComponentKeys( + Sets.<String>newHashSet(PROJECT, PACKAGE, FILE, FILE_IN_OTHER_PROJECT, EMPTY_PROJECT), USER, "user"); assertThat(componentIds).containsOnly(PROJECT, PACKAGE, FILE, EMPTY_PROJECT); // user does not have the role "admin" - componentIds = authorization.keepAuthorizedComponentIds( - Sets.<Long>newHashSet(PROJECT, PACKAGE, FILE), + componentIds = authorization.keepAuthorizedComponentKeys( + Sets.<String>newHashSet(PROJECT, PACKAGE, FILE), USER, "admin"); assertThat(componentIds).isEmpty(); } @@ -58,15 +59,15 @@ public class AuthorizationDaoTest extends AbstractDaoTestCase { setupData("group_should_be_authorized"); AuthorizationDao authorization = new AuthorizationDao(getMyBatis()); - Set<Long> componentIds = authorization.keepAuthorizedComponentIds( - Sets.<Long>newHashSet(PROJECT, PACKAGE, FILE, FILE_IN_OTHER_PROJECT, EMPTY_PROJECT), + Set<String> componentIds = authorization.keepAuthorizedComponentKeys( + Sets.<String>newHashSet(PROJECT, PACKAGE, FILE, FILE_IN_OTHER_PROJECT, EMPTY_PROJECT), USER, "user"); assertThat(componentIds).containsOnly(PROJECT, PACKAGE, FILE, EMPTY_PROJECT); // group does not have the role "admin" - componentIds = authorization.keepAuthorizedComponentIds( - Sets.<Long>newHashSet(PROJECT, PACKAGE, FILE, FILE_IN_OTHER_PROJECT, EMPTY_PROJECT), + componentIds = authorization.keepAuthorizedComponentKeys( + Sets.<String>newHashSet(PROJECT, PACKAGE, FILE, FILE_IN_OTHER_PROJECT, EMPTY_PROJECT), USER, "admin"); assertThat(componentIds).isEmpty(); } @@ -77,15 +78,15 @@ public class AuthorizationDaoTest extends AbstractDaoTestCase { setupData("group_should_have_global_authorization"); AuthorizationDao authorization = new AuthorizationDao(getMyBatis()); - Set<Long> componentIds = authorization.keepAuthorizedComponentIds( - Sets.<Long>newHashSet(PROJECT, PACKAGE, FILE, FILE_IN_OTHER_PROJECT, EMPTY_PROJECT), + Set<String> componentIds = authorization.keepAuthorizedComponentKeys( + Sets.<String>newHashSet(PROJECT, PACKAGE, FILE, FILE_IN_OTHER_PROJECT, EMPTY_PROJECT), USER, "user"); assertThat(componentIds).containsOnly(PROJECT, PACKAGE, FILE, EMPTY_PROJECT); // group does not have the role "admin" - componentIds = authorization.keepAuthorizedComponentIds( - Sets.<Long>newHashSet(PROJECT, PACKAGE, FILE, FILE_IN_OTHER_PROJECT, EMPTY_PROJECT), + componentIds = authorization.keepAuthorizedComponentKeys( + Sets.<String>newHashSet(PROJECT, PACKAGE, FILE, FILE_IN_OTHER_PROJECT, EMPTY_PROJECT), USER, "admin"); assertThat(componentIds).isEmpty(); } @@ -95,59 +96,59 @@ public class AuthorizationDaoTest extends AbstractDaoTestCase { setupData("anonymous_should_be_authorized"); AuthorizationDao authorization = new AuthorizationDao(getMyBatis()); - Set<Long> componentIds = authorization.keepAuthorizedComponentIds( - Sets.<Long>newHashSet(PROJECT, PACKAGE, FILE, FILE_IN_OTHER_PROJECT, EMPTY_PROJECT), + Set<String> componentIds = authorization.keepAuthorizedComponentKeys( + Sets.<String>newHashSet(PROJECT, PACKAGE, FILE, FILE_IN_OTHER_PROJECT, EMPTY_PROJECT), null, "user"); assertThat(componentIds).containsOnly(PROJECT, PACKAGE, FILE, EMPTY_PROJECT); // group does not have the role "admin" - componentIds = authorization.keepAuthorizedComponentIds( - Sets.<Long>newHashSet(PROJECT, PACKAGE, FILE, FILE_IN_OTHER_PROJECT), + componentIds = authorization.keepAuthorizedComponentKeys( + Sets.<String>newHashSet(PROJECT, PACKAGE, FILE, FILE_IN_OTHER_PROJECT), null, "admin"); assertThat(componentIds).isEmpty(); } @Test - public void should_return_root_project_ids_for_user() { - setupData("should_return_root_project_ids_for_user"); + public void should_return_root_project_keys_for_user() { + setupData("should_return_root_project_keys_for_user"); AuthorizationDao authorization = new AuthorizationDao(getMyBatis()); - Collection<Long> rootProjectIds = authorization.selectAuthorizedRootProjectsIds(USER, "user"); + Collection<String> rootProjectIds = authorization.selectAuthorizedRootProjectsKeys(USER, "user"); assertThat(rootProjectIds).containsOnly(PROJECT); // user does not have the role "admin" - rootProjectIds = authorization.selectAuthorizedRootProjectsIds(USER, "admin"); + rootProjectIds = authorization.selectAuthorizedRootProjectsKeys(USER, "admin"); assertThat(rootProjectIds).isEmpty(); } @Test - public void should_return_root_project_ids_for_group() { + public void should_return_root_project_keys_for_group() { // but user is not in an authorized group - setupData("should_return_root_project_ids_for_group"); + setupData("should_return_root_project_keys_for_group"); AuthorizationDao authorization = new AuthorizationDao(getMyBatis()); - Collection<Long> rootProjectIds = authorization.selectAuthorizedRootProjectsIds(USER, "user"); + Collection<String> rootProjectIds = authorization.selectAuthorizedRootProjectsKeys(USER, "user"); assertThat(rootProjectIds).containsOnly(PROJECT); // user does not have the role "admin" - rootProjectIds = authorization.selectAuthorizedRootProjectsIds(USER, "admin"); + rootProjectIds = authorization.selectAuthorizedRootProjectsKeys(USER, "admin"); assertThat(rootProjectIds).isEmpty(); } @Test - public void should_return_root_project_ids_for_anonymous() { - setupData("should_return_root_project_ids_for_anonymous"); + public void should_return_root_project_keys_for_anonymous() { + setupData("should_return_root_project_keys_for_anonymous"); AuthorizationDao authorization = new AuthorizationDao(getMyBatis()); - Collection<Long> rootProjectIds = authorization.selectAuthorizedRootProjectsIds(null, "user"); + Collection<String> rootProjectIds = authorization.selectAuthorizedRootProjectsKeys(null, "user"); assertThat(rootProjectIds).containsOnly(PROJECT); // group does not have the role "admin" - rootProjectIds = authorization.selectAuthorizedRootProjectsIds(null, "admin"); + rootProjectIds = authorization.selectAuthorizedRootProjectsKeys(null, "admin"); assertThat(rootProjectIds).isEmpty(); } diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueStatsDaoTest/should_select_assignees.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueStatsDaoTest/should_select_assignees.xml index 71624f7d596..4cf535d51a2 100644 --- a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueStatsDaoTest/should_select_assignees.xml +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueStatsDaoTest/should_select_assignees.xml @@ -1,7 +1,7 @@ <dataset> <group_roles id="1" group_id="[null]" resource_id="399" role="user"/> - <projects id="399" root_id="[null]" qualifier="TRK" scope="PRJ"/> + <projects id="399" kee="my.project:kee" root_id="[null]" qualifier="TRK" scope="PRJ"/> <issues id="100" diff --git a/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_ids_for_anonymous.xml b/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_ids_for_anonymous.xml deleted file mode 100644 index 78751463f13..00000000000 --- a/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_ids_for_anonymous.xml +++ /dev/null @@ -1,13 +0,0 @@ -<dataset> - - <user_roles id="1" user_id="100" resource_id="999" role="user"/> - <groups_users user_id="100" group_id="200"/> - <group_roles id="1" group_id="[null]" resource_id="300" role="user"/> - - <projects id="300" scope="PRJ" qualifier="TRK" enabled="[true]"/> - <projects id="301" scope="PRJ" qualifier="TRK" enabled="[true]"/> - <projects id="302" scope="PRJ" qualifier="TRK" enabled="[true]"/> - - <projects id="303" scope="PRJ" qualifier="TRK" enabled="[true]"/> - -</dataset> diff --git a/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_ids_for_group.xml b/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_ids_for_group.xml deleted file mode 100644 index 8ed4eaf95e0..00000000000 --- a/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_ids_for_group.xml +++ /dev/null @@ -1,15 +0,0 @@ -<dataset> - - <!-- user 100 has no direct grant access, but is in the group 200 that has the role "user" - on the project 300 --> - <user_roles id="1" user_id="100" resource_id="999" role="user"/> - <groups_users user_id="100" group_id="200"/> - <group_roles id="1" group_id="200" resource_id="300" role="user"/> - - <projects id="300" scope="PRJ" qualifier="TRK" enabled="[true]"/> - <projects id="301" scope="PRJ" qualifier="TRK" enabled="[true]"/> - <projects id="302" scope="PRJ" qualifier="TRK" enabled="[true]"/> - - <projects id="303" scope="PRJ" qualifier="TRK" enabled="[true]"/> - -</dataset> diff --git a/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_ids_for_user.xml b/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_ids_for_user.xml deleted file mode 100644 index b3154f594d2..00000000000 --- a/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_ids_for_user.xml +++ /dev/null @@ -1,14 +0,0 @@ -<dataset> - - <!-- user 100 has the role "user" on the project 300 and in group 200 --> - <user_roles id="1" user_id="100" resource_id="300" role="user"/> - <groups_users user_id="100" group_id="200"/> - <group_roles id="1" group_id="200" resource_id="999" role="user"/> - - <projects id="300" scope="PRJ" qualifier="TRK" enabled="[true]"/> - <projects id="301" scope="PRJ" qualifier="TRK" enabled="[true]"/> - <projects id="302" scope="PRJ" qualifier="TRK" enabled="[true]"/> - - <projects id="303" scope="PRJ" qualifier="TRK" enabled="[true]"/> - -</dataset> diff --git a/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_keys_for_anonymous.xml b/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_keys_for_anonymous.xml new file mode 100644 index 00000000000..14f78bec9ec --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_keys_for_anonymous.xml @@ -0,0 +1,13 @@ +<dataset> + + <user_roles id="1" user_id="100" resource_id="999" role="user"/> + <groups_users user_id="100" group_id="200"/> + <group_roles id="1" group_id="[null]" resource_id="300" role="user"/> + + <projects id="300" kee="pj-w-snapshot" scope="PRJ" qualifier="TRK" enabled="[true]"/> + <projects id="301" kee="pj-w-snapshot1" scope="PRJ" qualifier="TRK" enabled="[true]"/> + <projects id="302" kee="pj-w-snapshot2" scope="PRJ" qualifier="TRK" enabled="[true]"/> + + <projects id="303" kee="pj-w-snapshot3" scope="PRJ" qualifier="TRK" enabled="[true]"/> + +</dataset> diff --git a/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_keys_for_group.xml b/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_keys_for_group.xml new file mode 100644 index 00000000000..9c5f753751d --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_keys_for_group.xml @@ -0,0 +1,15 @@ +<dataset> + + <!-- user 100 has no direct grant access, but is in the group 200 that has the role "user" + on the project 300 --> + <user_roles id="1" user_id="100" resource_id="999" role="user"/> + <groups_users user_id="100" group_id="200"/> + <group_roles id="1" group_id="200" resource_id="300" role="user"/> + + <projects id="300" kee="pj-w-snapshot" scope="PRJ" qualifier="TRK" enabled="[true]"/> + <projects id="301" kee="pj-w-snapshot1" scope="PRJ" qualifier="TRK" enabled="[true]"/> + <projects id="302" kee="pj-w-snapshot2" scope="PRJ" qualifier="TRK" enabled="[true]"/> + + <projects id="303" kee="pj-w-snapshot3" scope="PRJ" qualifier="TRK" enabled="[true]"/> + +</dataset> diff --git a/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_keys_for_user.xml b/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_keys_for_user.xml new file mode 100644 index 00000000000..773dd296f08 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/user/AuthorizationDaoTest/should_return_root_project_keys_for_user.xml @@ -0,0 +1,14 @@ +<dataset> + + <!-- user 100 has the role "user" on the project 300 and in group 200 --> + <user_roles id="1" user_id="100" resource_id="300" role="user"/> + <groups_users user_id="100" group_id="200"/> + <group_roles id="1" group_id="200" resource_id="999" role="user"/> + + <projects id="300" kee="pj-w-snapshot" scope="PRJ" qualifier="TRK" enabled="[true]"/> + <projects id="301" kee="pj-w-snapshot1" scope="PRJ" qualifier="TRK" enabled="[true]"/> + <projects id="302" kee="pj-w-snapshot2" scope="PRJ" qualifier="TRK" enabled="[true]"/> + + <projects id="303" kee="pj-w-snapshot3" scope="PRJ" qualifier="TRK" enabled="[true]"/> + +</dataset> diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssue.java index ea505af1b48..2c9263e2642 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssue.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssue.java @@ -38,7 +38,11 @@ import javax.annotation.CheckForNull; import javax.annotation.Nullable; import java.io.Serializable; -import java.util.*; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; import static com.google.common.collect.Lists.newArrayList; @@ -119,7 +123,7 @@ public class DefaultIssue implements Issue { } /** - * The project key is not always populated, that's why it's not present is the Issue API + * The project key is not always populated, that's why it's not present in the Issue API */ @CheckForNull public String projectKey() { @@ -356,7 +360,7 @@ public class DefaultIssue implements Issue { } public Map<String, String> attributes() { - return attributes == null ? Collections.<String, String> emptyMap() : ImmutableMap.copyOf(attributes); + return attributes == null ? Collections.<String, String>emptyMap() : ImmutableMap.copyOf(attributes); } public DefaultIssue setAttributes(@Nullable Map<String, String> map) { @@ -401,7 +405,6 @@ public class DefaultIssue implements Issue { return this; } - @CheckForNull public FieldDiffs currentChange() { return currentChange; diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/web/UserRole.java b/sonar-plugin-api/src/main/java/org/sonar/api/web/UserRole.java index f4afb868839..8831085b394 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/web/UserRole.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/web/UserRole.java @@ -40,6 +40,7 @@ public @interface UserRole { String USER = "user"; String ADMIN = "admin"; String CODEVIEWER = "codeviewer"; + String ISSUE_ADMIN = "issueadmin"; String[] value() default {}; diff --git a/sonar-server/src/main/java/org/sonar/server/issue/ActionPlanService.java b/sonar-server/src/main/java/org/sonar/server/issue/ActionPlanService.java index 5bac54257a5..37325365b55 100644 --- a/sonar-server/src/main/java/org/sonar/server/issue/ActionPlanService.java +++ b/sonar-server/src/main/java/org/sonar/server/issue/ActionPlanService.java @@ -32,7 +32,13 @@ import org.sonar.core.issue.ActionPlanDeadlineComparator; import org.sonar.core.issue.ActionPlanStats; import org.sonar.core.issue.DefaultActionPlan; import org.sonar.core.issue.IssueUpdater; -import org.sonar.core.issue.db.*; +import org.sonar.core.issue.db.ActionPlanDao; +import org.sonar.core.issue.db.ActionPlanDto; +import org.sonar.core.issue.db.ActionPlanStatsDao; +import org.sonar.core.issue.db.ActionPlanStatsDto; +import org.sonar.core.issue.db.IssueDao; +import org.sonar.core.issue.db.IssueDto; +import org.sonar.core.issue.db.IssueStorage; import org.sonar.core.resource.ResourceDao; import org.sonar.core.resource.ResourceDto; import org.sonar.core.resource.ResourceQuery; @@ -41,7 +47,11 @@ import org.sonar.server.user.UserSession; import javax.annotation.CheckForNull; -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.List; import static com.google.common.collect.Lists.newArrayList; @@ -58,9 +68,8 @@ public class ActionPlanService implements ServerComponent { private final IssueUpdater issueUpdater; private final IssueStorage issueStorage; - public ActionPlanService(ActionPlanDao actionPlanDao, ActionPlanStatsDao actionPlanStatsDao, ResourceDao resourceDao, AuthorizationDao authorizationDao, - IssueDao issueDao, IssueUpdater issueUpdater, IssueStorage issueStorage) { + IssueDao issueDao, IssueUpdater issueUpdater, IssueStorage issueStorage) { this.actionPlanDao = actionPlanDao; this.actionPlanStatsDao = actionPlanStatsDao; this.resourceDao = resourceDao; @@ -197,7 +206,7 @@ public class ActionPlanService implements ServerComponent { } private void checkAuthorization(UserSession userSession, ResourceDto project, String requiredRole) { - if (!authorizationDao.isAuthorizedComponentId(project.getId(), userSession.userId(), requiredRole)) { + if (!authorizationDao.isAuthorizedComponentKey(project.getKey(), userSession.userId(), requiredRole)) { // TODO throw unauthorized throw new IllegalStateException("User does not have the required role on the project: " + project.getKey()); } diff --git a/sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueFinder.java b/sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueFinder.java index 8a57fa291b7..9601bf4f8ea 100644 --- a/sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueFinder.java +++ b/sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueFinder.java @@ -25,7 +25,11 @@ import org.apache.ibatis.session.SqlSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.component.Component; -import org.sonar.api.issue.*; +import org.sonar.api.issue.ActionPlan; +import org.sonar.api.issue.Issue; +import org.sonar.api.issue.IssueFinder; +import org.sonar.api.issue.IssueQuery; +import org.sonar.api.issue.IssueQueryResult; import org.sonar.api.issue.internal.DefaultIssue; import org.sonar.api.issue.internal.DefaultIssueComment; import org.sonar.api.rules.Rule; @@ -39,7 +43,6 @@ import org.sonar.core.issue.db.IssueDto; import org.sonar.core.persistence.MyBatis; import org.sonar.core.resource.ResourceDao; import org.sonar.core.rule.DefaultRuleFinder; -import org.sonar.core.user.AuthorizationDao; import org.sonar.server.user.UserSession; import java.util.Collection; @@ -59,23 +62,20 @@ public class DefaultIssueFinder implements IssueFinder { private final MyBatis myBatis; private final IssueDao issueDao; private final IssueChangeDao issueChangeDao; - private final AuthorizationDao authorizationDao; private final DefaultRuleFinder ruleFinder; private final UserFinder userFinder; private final ResourceDao resourceDao; private final ActionPlanService actionPlanService; public DefaultIssueFinder(MyBatis myBatis, - IssueDao issueDao, IssueChangeDao issueChangeDao, - AuthorizationDao authorizationDao, - DefaultRuleFinder ruleFinder, - UserFinder userFinder, - ResourceDao resourceDao, - ActionPlanService actionPlanService) { + IssueDao issueDao, IssueChangeDao issueChangeDao, + DefaultRuleFinder ruleFinder, + UserFinder userFinder, + ResourceDao resourceDao, + ActionPlanService actionPlanService) { this.myBatis = myBatis; this.issueDao = issueDao; this.issueChangeDao = issueChangeDao; - this.authorizationDao = authorizationDao; this.ruleFinder = ruleFinder; this.userFinder = userFinder; this.resourceDao = resourceDao; @@ -87,7 +87,7 @@ public class DefaultIssueFinder implements IssueFinder { if (dto == null) { throw new IllegalStateException("Unknown issue: " + issueKey); } - if (!authorizationDao.isAuthorizedComponentId(dto.getComponentId(), UserSession.get().userId(), requiredRole)) { + if (!UserSession.get().hasProjectPermission(requiredRole, dto.getRootComponentKey())) { throw new IllegalStateException("User does not have the required role required to change the issue: " + issueKey); } return dto.toDefaultIssue(); diff --git a/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java b/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java index ac571ba5e7d..3c7fd4b6507 100644 --- a/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java +++ b/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java @@ -106,11 +106,11 @@ public class InternalRubyIssueService implements ServerComponent { } public List<Transition> listTransitions(String issueKey) { - return issueService.listTransitions(issueKey); + return issueService.listTransitions(issueKey, UserSession.get()); } public List<Transition> listTransitions(Issue issue) { - return issueService.listTransitions(issue); + return issueService.listTransitions(issue, UserSession.get()); } public List<String> listStatus() { @@ -129,7 +129,7 @@ public class InternalRubyIssueService implements ServerComponent { return changelogService.changelog(issue); } - public List<String> formatChangelog(FieldDiffs diffs){ + public List<String> formatChangelog(FieldDiffs diffs) { return issueChangelogFormatter.format(UserSession.get().locale(), diffs); } @@ -406,7 +406,7 @@ public class InternalRubyIssueService implements ServerComponent { } public IssueQuery emptyIssueQuery() { - return PublicRubyIssueService.toQuery(Maps.<String, Object> newHashMap()); + return PublicRubyIssueService.toQuery(Maps.<String, Object>newHashMap()); } @CheckForNull diff --git a/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java b/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java index 40bd5885e2b..3e02d66e516 100644 --- a/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java +++ b/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java @@ -19,9 +19,8 @@ */ package org.sonar.server.issue; -import org.sonar.core.preview.PreviewCache; - import com.google.common.base.Strings; +import org.apache.commons.lang.StringUtils; import org.sonar.api.ServerComponent; import org.sonar.api.issue.ActionPlan; import org.sonar.api.issue.Issue; @@ -39,6 +38,7 @@ import org.sonar.core.issue.IssueUpdater; import org.sonar.core.issue.db.IssueStorage; import org.sonar.core.issue.workflow.IssueWorkflow; import org.sonar.core.issue.workflow.Transition; +import org.sonar.core.preview.PreviewCache; import org.sonar.core.resource.ResourceDao; import org.sonar.core.resource.ResourceDto; import org.sonar.core.resource.ResourceQuery; @@ -47,6 +47,7 @@ import org.sonar.server.user.UserSession; import javax.annotation.Nullable; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; @@ -98,20 +99,29 @@ public class IssueService implements ServerComponent { * <p/> * Never return null, but return an empty list if the issue does not exist. */ - public List<Transition> listTransitions(String issueKey) { + public List<Transition> listTransitions(String issueKey, UserSession userSession) { Issue issue = loadIssue(issueKey).first(); - return listTransitions(issue); + return listTransitions(issue, userSession); } /** * Never return null, but an empty list if the issue does not exist. * No security check is done since it should already have been done to get the issue */ - public List<Transition> listTransitions(@Nullable Issue issue) { + public List<Transition> listTransitions(@Nullable Issue issue, UserSession userSession) { if (issue == null) { return Collections.emptyList(); } - return workflow.outTransitions(issue); + List<Transition> outTransitions = workflow.outTransitions(issue); + List<Transition> allowedTransitions = new ArrayList<Transition>(); + for (Transition transition : outTransitions) { + DefaultIssue defaultIssue = (DefaultIssue) issue; + if (StringUtils.isBlank(transition.requiredProjectPermission()) || + userSession.hasProjectPermission(UserRole.ISSUE_ADMIN, defaultIssue.projectKey())) { + allowedTransitions.add(transition); + } + } + return allowedTransitions; } public Issue doTransition(String issueKey, String transition, UserSession userSession) { @@ -188,7 +198,7 @@ public class IssueService implements ServerComponent { if (resourceDto == null) { throw new IllegalArgumentException("Unknown component: " + issue.componentKey()); } - if (!authorizationDao.isAuthorizedComponentId(resourceDto.getId(), userSession.userId(), UserRole.USER)) { + if (!authorizationDao.isAuthorizedComponentKey(issue.componentKey(), userSession.userId(), UserRole.USER)) { // TODO throw unauthorized throw new IllegalStateException("User does not have the required role"); } diff --git a/sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionService.java b/sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionService.java index b07f8b2308e..874cfca324d 100644 --- a/sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionService.java +++ b/sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionService.java @@ -39,6 +39,7 @@ import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.user.UserSession; import javax.annotation.Nullable; + import java.util.List; import java.util.Map; @@ -87,7 +88,7 @@ public class InternalPermissionService implements ServerComponent { ResourceDto provisioned = resourceDao.selectProvisionedProject(componentKey); if (provisioned == null) { - checkProjectAdminPermission(component.getId()); + checkProjectAdminPermission(componentKey); } else { UserSession.get().checkGlobalPermission(GlobalPermissions.PROVISIONING); } @@ -101,16 +102,18 @@ public class InternalPermissionService implements ServerComponent { ApplyPermissionTemplateQuery query = ApplyPermissionTemplateQuery.buildFromParams(params); query.validate(); - // If only one project is selected, check user has admin permission on it, otherwise we are in the case of a bulk change and only system admin has permission to do it + // If only one project is selected, check user has admin permission on it, otherwise we are in the case of a bulk change and only system + // admin has permission to do it if (query.getSelectedComponents().size() == 1) { - checkProjectAdminPermission(Long.parseLong(query.getSelectedComponents().get(0))); + checkProjectAdminPermission(query.getSelectedComponents().get(0)); } else { checkProjectAdminPermission(null); UserSession.get().checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN); } - for (String component : query.getSelectedComponents()) { - permissionFacade.applyPermissionTemplate(query.getTemplateKey(), Long.parseLong(component)); + for (String componentKey : query.getSelectedComponents()) { + ComponentDto component = (ComponentDto) resourceDao.findByKey(componentKey); + permissionFacade.applyPermissionTemplate(query.getTemplateKey(), component.getId()); } } @@ -131,30 +134,30 @@ public class InternalPermissionService implements ServerComponent { private void applyGroupPermissionChange(String operation, PermissionChangeQuery permissionChangeQuery) { Long componentId = getComponentId(permissionChangeQuery.component()); - checkProjectAdminPermission(componentId); + checkProjectAdminPermission(permissionChangeQuery.component()); List<String> existingPermissions = permissionFacade.selectGroupPermissions(permissionChangeQuery.group(), componentId); if (shouldSkipPermissionChange(operation, existingPermissions, permissionChangeQuery)) { LOG.info("Skipping permission change '{} {}' for group {} as it matches the current permission scheme", - new String[]{operation, permissionChangeQuery.permission(), permissionChangeQuery.group()}); + new String[] {operation, permissionChangeQuery.permission(), permissionChangeQuery.group()}); } else { Long targetedGroup = getTargetedGroup(permissionChangeQuery.group()); if (ADD.equals(operation)) { - permissionFacade.insertGroupPermission(getComponentId(permissionChangeQuery.component()), targetedGroup, permissionChangeQuery.permission()); + permissionFacade.insertGroupPermission(componentId, targetedGroup, permissionChangeQuery.permission()); } else { - permissionFacade.deleteGroupPermission(getComponentId(permissionChangeQuery.component()), targetedGroup, permissionChangeQuery.permission()); + permissionFacade.deleteGroupPermission(componentId, targetedGroup, permissionChangeQuery.permission()); } } } private void applyUserPermissionChange(String operation, PermissionChangeQuery permissionChangeQuery) { Long componentId = getComponentId(permissionChangeQuery.component()); - checkProjectAdminPermission(componentId); + checkProjectAdminPermission(permissionChangeQuery.component()); List<String> existingPermissions = permissionFacade.selectUserPermissions(permissionChangeQuery.user(), componentId); if (shouldSkipPermissionChange(operation, existingPermissions, permissionChangeQuery)) { LOG.info("Skipping permission change '{} {}' for user {} as it matches the current permission scheme", - new String[]{operation, permissionChangeQuery.permission(), permissionChangeQuery.user()}); + new String[] {operation, permissionChangeQuery.permission(), permissionChangeQuery.user()}); } else { Long targetedUser = getTargetedUser(permissionChangeQuery.user()); if (ADD.equals(operation)) { @@ -204,11 +207,11 @@ public class InternalPermissionService implements ServerComponent { } } - private void checkProjectAdminPermission(@Nullable Long componentId) { - if (componentId == null) { + private void checkProjectAdminPermission(@Nullable String projectKey) { + if (projectKey == null) { UserSession.get().checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN); } else { - if (!UserSession.get().hasGlobalPermission(GlobalPermissions.SYSTEM_ADMIN) && !UserSession.get().hasProjectPermission(UserRole.ADMIN, componentId)) { + if (!UserSession.get().hasGlobalPermission(GlobalPermissions.SYSTEM_ADMIN) && !UserSession.get().hasProjectPermission(UserRole.ADMIN, projectKey)) { throw new ForbiddenException("Insufficient privileges"); } } diff --git a/sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionTemplateService.java b/sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionTemplateService.java index e7835f53809..72e8d89a7a5 100644 --- a/sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionTemplateService.java +++ b/sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionTemplateService.java @@ -28,14 +28,13 @@ import org.sonar.api.ServerComponent; import org.sonar.core.permission.PermissionTemplateDao; import org.sonar.core.permission.PermissionTemplateDto; import org.sonar.core.resource.ResourceDao; -import org.sonar.core.resource.ResourceDto; -import org.sonar.core.resource.ResourceQuery; import org.sonar.core.user.UserDao; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ServerErrorException; import javax.annotation.CheckForNull; import javax.annotation.Nullable; + import java.util.List; /** @@ -67,7 +66,7 @@ public class InternalPermissionTemplateService implements ServerComponent { } public List<PermissionTemplate> selectAllPermissionTemplates(@Nullable String componentKey) { - PermissionTemplateUpdater.checkProjectAdminUser(getComponentId(componentKey)); + PermissionTemplateUpdater.checkProjectAdminUser(componentKey); List<PermissionTemplate> permissionTemplates = Lists.newArrayList(); List<PermissionTemplateDto> permissionTemplateDtos = permissionTemplateDao.selectAllPermissionTemplates(); if (permissionTemplateDtos != null) { @@ -161,16 +160,4 @@ public class InternalPermissionTemplateService implements ServerComponent { } } - @Nullable - private Long getComponentId(String componentKey) { - if (componentKey == null) { - return null; - } else { - ResourceDto resourceDto = resourceDao.getResource(ResourceQuery.create().setKey(componentKey)); - if (resourceDto == null) { - throw new BadRequestException("Project does not exists."); - } - return resourceDto.getId(); - } - } } diff --git a/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplateUpdater.java b/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplateUpdater.java index bdaf6376ff7..bc41d110f63 100644 --- a/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplateUpdater.java +++ b/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplateUpdater.java @@ -34,6 +34,7 @@ import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.user.UserSession; import javax.annotation.Nullable; + import java.util.List; abstract class PermissionTemplateUpdater { @@ -63,18 +64,18 @@ abstract class PermissionTemplateUpdater { Long getUserId() { UserDto userDto = userDao.selectActiveUserByLogin(updatedReference); - if(userDto == null) { + if (userDto == null) { throw new BadRequestException("Unknown user: " + updatedReference); } return userDto.getId(); } Long getGroupId() { - if(DefaultGroups.isAnyone(updatedReference)) { + if (DefaultGroups.isAnyone(updatedReference)) { return null; } GroupDto groupDto = userDao.selectGroupByName(updatedReference); - if(groupDto == null) { + if (groupDto == null) { throw new BadRequestException("Unknown group: " + updatedReference); } return groupDto.getId(); @@ -84,13 +85,13 @@ abstract class PermissionTemplateUpdater { checkProjectAdminUser(null); } - static void checkProjectAdminUser(@Nullable Long projectId) { + static void checkProjectAdminUser(@Nullable String componentKey) { UserSession currentSession = UserSession.get(); currentSession.checkLoggedIn(); - if (projectId == null) { + if (componentKey == null) { currentSession.checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN); } else { - if (!currentSession.hasGlobalPermission(GlobalPermissions.SYSTEM_ADMIN) && !currentSession.hasProjectPermission(UserRole.ADMIN, projectId)) { + if (!currentSession.hasGlobalPermission(GlobalPermissions.SYSTEM_ADMIN) && !currentSession.hasProjectPermission(UserRole.ADMIN, componentKey)) { throw new ForbiddenException("Insufficient privileges"); } } @@ -98,14 +99,14 @@ abstract class PermissionTemplateUpdater { private void validatePermission(String permission) { List<String> supportedPermissions = Lists.newArrayList(UserRole.ADMIN, UserRole.CODEVIEWER, UserRole.USER); - if(permission == null || !supportedPermissions.contains(permission)) { + if (permission == null || !supportedPermissions.contains(permission)) { throw new BadRequestException("Invalid permission: " + permission); } } private Long getTemplateId(String name) { PermissionTemplateDto permissionTemplateDto = permissionTemplateDao.selectTemplateByName(name); - if(permissionTemplateDto == null) { + if (permissionTemplateDto == null) { throw new BadRequestException("Unknown template: " + name); } return permissionTemplateDto.getId(); diff --git a/sonar-server/src/main/java/org/sonar/server/user/UserSession.java b/sonar-server/src/main/java/org/sonar/server/user/UserSession.java index f5fed66a2d4..580ef135362 100644 --- a/sonar-server/src/main/java/org/sonar/server/user/UserSession.java +++ b/sonar-server/src/main/java/org/sonar/server/user/UserSession.java @@ -56,7 +56,7 @@ public class UserSession { private Locale locale = Locale.ENGLISH; List<String> globalPermissions = null; - HashMultimap<String, Long> projectIdByPermission = HashMultimap.create(); + HashMultimap<String, String> projectKeyByPermission = HashMultimap.create(); List<String> projectPermissions = newArrayList(); UserSession() { @@ -137,8 +137,8 @@ public class UserSession { /** * Ensures that user implies the specified project permission. If not a {@link org.sonar.server.exceptions.ForbiddenException} is thrown. */ - public UserSession checkProjectPermission(String projectPermission, Long componentId) { - if (!hasProjectPermission(projectPermission, componentId)) { + public UserSession checkProjectPermission(String projectPermission, String projectKey) { + if (!hasProjectPermission(projectPermission, projectKey)) { throw new ForbiddenException("Insufficient privileges"); } return this; @@ -147,15 +147,15 @@ public class UserSession { /** * Does the user have the given project permission ? */ - public boolean hasProjectPermission(String permission, Long componentId) { + public boolean hasProjectPermission(String permission, String projectKey) { if (!projectPermissions.contains(permission)) { - Collection<Long> projectIds = authorizationDao().selectAuthorizedRootProjectsIds(userId, permission); - for (Long id : projectIds) { - projectIdByPermission.put(permission, id); + Collection<String> projectKeys = authorizationDao().selectAuthorizedRootProjectsKeys(userId, permission); + for (String key : projectKeys) { + projectKeyByPermission.put(permission, key); } projectPermissions.add(permission); } - return projectIdByPermission.get(permission).contains(componentId); + return projectKeyByPermission.get(permission).contains(projectKey); } AuthorizationDao authorizationDao() { diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/roles_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/roles_controller.rb index 0a3d13ebba1..be5d9aba056 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/roles_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/roles_controller.rb @@ -112,7 +112,7 @@ class RolesController < ApplicationController if params['components'].blank? params['pageSize'] = -1 components = Internal.component_api.findWithUncompleteProjects(params).components().to_a - params['components'] = components.collect{|component| component.getId()}.join(',') + params['components'] = components.collect{|component| component.key()}.join(',') end Internal.permissions.applyPermissionTemplate(params) diff --git a/sonar-server/src/test/java/org/sonar/server/issue/ActionPlanServiceTest.java b/sonar-server/src/test/java/org/sonar/server/issue/ActionPlanServiceTest.java index d49ba739016..9bcd00ec644 100644 --- a/sonar-server/src/test/java/org/sonar/server/issue/ActionPlanServiceTest.java +++ b/sonar-server/src/test/java/org/sonar/server/issue/ActionPlanServiceTest.java @@ -32,7 +32,13 @@ import org.sonar.api.web.UserRole; import org.sonar.core.issue.ActionPlanStats; import org.sonar.core.issue.DefaultActionPlan; import org.sonar.core.issue.IssueUpdater; -import org.sonar.core.issue.db.*; +import org.sonar.core.issue.db.ActionPlanDao; +import org.sonar.core.issue.db.ActionPlanDto; +import org.sonar.core.issue.db.ActionPlanStatsDao; +import org.sonar.core.issue.db.ActionPlanStatsDto; +import org.sonar.core.issue.db.IssueDao; +import org.sonar.core.issue.db.IssueDto; +import org.sonar.core.issue.db.IssueStorage; import org.sonar.core.resource.ResourceDao; import org.sonar.core.resource.ResourceDto; import org.sonar.core.resource.ResourceQuery; @@ -45,7 +51,13 @@ import static com.google.common.collect.Lists.newArrayList; import static org.fest.assertions.Assertions.assertThat; import static org.fest.assertions.Fail.fail; import static org.mockito.Matchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; public class ActionPlanServiceTest { @@ -64,7 +76,7 @@ public class ActionPlanServiceTest { public void before() { when(userSession.isLoggedIn()).thenReturn(true); when(userSession.userId()).thenReturn(10); - when(authorizationDao.isAuthorizedComponentId(anyLong(), eq(10), anyString())).thenReturn(true); + when(authorizationDao.isAuthorizedComponentKey(anyString(), eq(10), anyString())).thenReturn(true); actionPlanService = new ActionPlanService(actionPlanDao, actionPlanStatsDao, resourceDao, authorizationDao, issueDao, issueUpdater, issueStorage); } @@ -76,14 +88,14 @@ public class ActionPlanServiceTest { actionPlanService.create(actionPlan, userSession); verify(actionPlanDao).save(any(ActionPlanDto.class)); - verify(authorizationDao).isAuthorizedComponentId(anyLong(), anyInt(), eq(UserRole.ADMIN)); + verify(authorizationDao).isAuthorizedComponentKey(anyString(), anyInt(), eq(UserRole.ADMIN)); } @Test public void should_create_required_admin_role() { when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(new ResourceDto().setKey("org.sonar.Sample").setId(1l)); ActionPlan actionPlan = DefaultActionPlan.create("Long term"); - when(authorizationDao.isAuthorizedComponentId(anyLong(), eq(10), anyString())).thenReturn(false); + when(authorizationDao.isAuthorizedComponentKey(anyString(), eq(10), anyString())).thenReturn(false); try { actionPlanService.create(actionPlan, userSession); @@ -91,7 +103,7 @@ public class ActionPlanServiceTest { } catch (Exception e) { assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("User does not have the required role on the project: org.sonar.Sample"); } - verify(authorizationDao).isAuthorizedComponentId(eq(1l), eq(10), eq(UserRole.ADMIN)); + verify(authorizationDao).isAuthorizedComponentKey(eq("org.sonar.Sample"), eq(10), eq(UserRole.ADMIN)); verifyZeroInteractions(actionPlanDao); } @@ -105,7 +117,7 @@ public class ActionPlanServiceTest { assertThat(result).isNotNull(); assertThat(result.status()).isEqualTo("CLOSED"); - verify(authorizationDao).isAuthorizedComponentId(anyLong(), anyInt(), eq(UserRole.ADMIN)); + verify(authorizationDao).isAuthorizedComponentKey(anyString(), anyInt(), eq(UserRole.ADMIN)); } @Test @@ -115,7 +127,7 @@ public class ActionPlanServiceTest { actionPlanService.update(actionPlan, userSession); verify(actionPlanDao).update(any(ActionPlanDto.class)); - verify(authorizationDao).isAuthorizedComponentId(anyLong(), anyInt(), eq(UserRole.ADMIN)); + verify(authorizationDao).isAuthorizedComponentKey(anyString(), anyInt(), eq(UserRole.ADMIN)); } @Test @@ -124,7 +136,7 @@ public class ActionPlanServiceTest { when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(new ResourceDto().setKey("org.sonar.Sample").setId(1l)); actionPlanService.delete("ABCD", userSession); verify(actionPlanDao).delete("ABCD"); - verify(authorizationDao).isAuthorizedComponentId(anyLong(), anyInt(), eq(UserRole.ADMIN)); + verify(authorizationDao).isAuthorizedComponentKey(anyString(), anyInt(), eq(UserRole.ADMIN)); } @Test @@ -139,7 +151,7 @@ public class ActionPlanServiceTest { ArgumentCaptor<DefaultIssue> captor = ArgumentCaptor.forClass(DefaultIssue.class); actionPlanService.delete("ABCD", userSession); verify(actionPlanDao).delete("ABCD"); - verify(authorizationDao).isAuthorizedComponentId(anyLong(), anyInt(), eq(UserRole.ADMIN)); + verify(authorizationDao).isAuthorizedComponentKey(anyString(), anyInt(), eq(UserRole.ADMIN)); verify(issueUpdater).plan(captor.capture(), eq((ActionPlan) null), any(IssueChangeContext.class)); verify(issueStorage).save(newArrayList(captor.getAllValues())); } @@ -152,7 +164,7 @@ public class ActionPlanServiceTest { ActionPlan result = actionPlanService.findByKey("ABCD", userSession); assertThat(result).isNotNull(); assertThat(result.key()).isEqualTo("ABCD"); - verify(authorizationDao).isAuthorizedComponentId(anyLong(), anyInt(), eq(UserRole.USER)); + verify(authorizationDao).isAuthorizedComponentKey(anyString(), anyInt(), eq(UserRole.USER)); } @Test @@ -176,14 +188,14 @@ public class ActionPlanServiceTest { Collection<ActionPlan> results = actionPlanService.findOpenByProjectKey("org.sonar.Sample", userSession); assertThat(results).hasSize(1); assertThat(results.iterator().next().key()).isEqualTo("ABCD"); - verify(authorizationDao).isAuthorizedComponentId(anyLong(), anyInt(), eq(UserRole.USER)); + verify(authorizationDao).isAuthorizedComponentKey(anyString(), anyInt(), eq(UserRole.USER)); } @Test public void should_find_open_by_project_key_required_user_role() { when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(new ResourceDto().setKey("org.sonar.Sample").setId(1l)); when(actionPlanDao.findOpenByProjectId(1l)).thenReturn(newArrayList(new ActionPlanDto().setKey("ABCD"))); - when(authorizationDao.isAuthorizedComponentId(anyLong(), eq(10), anyString())).thenReturn(false); + when(authorizationDao.isAuthorizedComponentKey(anyString(), eq(10), anyString())).thenReturn(false); try { actionPlanService.findOpenByProjectKey("org.sonar.Sample", userSession); @@ -191,7 +203,7 @@ public class ActionPlanServiceTest { } catch (Exception e) { assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("User does not have the required role on the project: org.sonar.Sample"); } - verify(authorizationDao).isAuthorizedComponentId(eq(1l), eq(10), eq(UserRole.USER)); + verify(authorizationDao).isAuthorizedComponentKey(eq("org.sonar.Sample"), eq(10), eq(UserRole.USER)); verifyZeroInteractions(actionPlanDao); } @@ -208,7 +220,7 @@ public class ActionPlanServiceTest { Collection<ActionPlanStats> results = actionPlanService.findActionPlanStats("org.sonar.Sample", userSession); assertThat(results).hasSize(1); - verify(authorizationDao).isAuthorizedComponentId(anyLong(), anyInt(), eq(UserRole.USER)); + verify(authorizationDao).isAuthorizedComponentKey(anyString(), anyInt(), eq(UserRole.USER)); } @Test(expected = IllegalArgumentException.class) diff --git a/sonar-server/src/test/java/org/sonar/server/issue/DefaultIssueFinderTest.java b/sonar-server/src/test/java/org/sonar/server/issue/DefaultIssueFinderTest.java index 667c9f4bc0a..aecd54dd836 100644 --- a/sonar-server/src/test/java/org/sonar/server/issue/DefaultIssueFinderTest.java +++ b/sonar-server/src/test/java/org/sonar/server/issue/DefaultIssueFinderTest.java @@ -40,7 +40,6 @@ import org.sonar.core.issue.db.IssueDto; import org.sonar.core.persistence.MyBatis; import org.sonar.core.resource.ResourceDao; import org.sonar.core.rule.DefaultRuleFinder; -import org.sonar.core.user.AuthorizationDao; import org.sonar.core.user.DefaultUser; import java.util.Collections; @@ -52,21 +51,22 @@ import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyCollection; import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyListOf; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.anyListOf; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; public class DefaultIssueFinderTest { MyBatis mybatis = mock(MyBatis.class); IssueDao issueDao = mock(IssueDao.class); IssueChangeDao issueChangeDao = mock(IssueChangeDao.class); - AuthorizationDao authorizationDao = mock(AuthorizationDao.class); DefaultRuleFinder ruleFinder = mock(DefaultRuleFinder.class); ResourceDao resourceDao = mock(ResourceDao.class); ActionPlanService actionPlanService = mock(ActionPlanService.class); UserFinder userFinder = mock(UserFinder.class); - DefaultIssueFinder finder = new DefaultIssueFinder(mybatis, issueDao, issueChangeDao, authorizationDao, ruleFinder, userFinder, resourceDao, actionPlanService); + DefaultIssueFinder finder = new DefaultIssueFinder(mybatis, issueDao, issueChangeDao, ruleFinder, userFinder, resourceDao, actionPlanService); @Test public void should_find_issues() { @@ -252,7 +252,7 @@ public class DefaultIssueFinderTest { when(userFinder.findByLogins(anyListOf(String.class))).thenReturn(Lists.<User>newArrayList( new DefaultUser().setLogin("perceval").setName("Perceval"), new DefaultUser().setLogin("arthur").setName("Roi Arthur") - )); + )); IssueQuery query = IssueQuery.builder().build(); @@ -295,8 +295,7 @@ public class DefaultIssueFinderTest { .setRootComponentKey_unit_test_only("struts") .setRuleKey_unit_test_only("squid", "AvoidCycle") .setStatus("OPEN").setResolution("OPEN") - .setTechnicalDebt(10L) - ; + .setTechnicalDebt(10L); List<IssueDto> dtoList = newArrayList(issue); when(issueDao.selectByIds(anyCollection(), any(SqlSession.class))).thenReturn(dtoList); diff --git a/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceTest.java b/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceTest.java index 8ce062f1af2..68091cdea87 100644 --- a/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceTest.java +++ b/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceTest.java @@ -20,8 +20,6 @@ package org.sonar.server.issue; -import org.sonar.core.preview.PreviewCache; - import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -43,6 +41,7 @@ import org.sonar.core.issue.IssueUpdater; import org.sonar.core.issue.db.IssueStorage; import org.sonar.core.issue.workflow.IssueWorkflow; import org.sonar.core.issue.workflow.Transition; +import org.sonar.core.preview.PreviewCache; import org.sonar.core.resource.ResourceDao; import org.sonar.core.resource.ResourceDto; import org.sonar.core.resource.ResourceQuery; @@ -58,7 +57,6 @@ import static org.fest.assertions.Assertions.assertThat; import static org.fest.assertions.Fail.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; @@ -91,7 +89,7 @@ public class IssueServiceTest { when(userSession.userId()).thenReturn(10); when(userSession.login()).thenReturn("arthur"); - when(authorizationDao.isAuthorizedComponentId(anyLong(), eq(10), anyString())).thenReturn(true); + when(authorizationDao.isAuthorizedComponentKey(anyString(), eq(10), anyString())).thenReturn(true); when(finder.find(any(IssueQuery.class))).thenReturn(issueQueryResult); when(issueQueryResult.issues()).thenReturn(newArrayList((Issue) issue)); when(issueQueryResult.first()).thenReturn(issue); @@ -108,7 +106,7 @@ public class IssueServiceTest { @Test public void should_fail_to_load_issue() { - when(issueQueryResult.issues()).thenReturn(Collections.<Issue> emptyList()); + when(issueQueryResult.issues()).thenReturn(Collections.<Issue>emptyList()); when(finder.find(any(IssueQuery.class))).thenReturn(issueQueryResult); try { @@ -130,7 +128,7 @@ public class IssueServiceTest { List<Transition> transitions = newArrayList(transition); when(workflow.outTransitions(issue)).thenReturn(transitions); - List<Transition> result = issueService.listTransitions("ABCD"); + List<Transition> result = issueService.listTransitions("ABCD", userSession); assertThat(result).hasSize(1); assertThat(result.get(0)).isEqualTo(transition); } @@ -140,7 +138,7 @@ public class IssueServiceTest { when(issueQueryResult.first()).thenReturn(null); when(issueQueryResult.issues()).thenReturn(newArrayList((Issue) new DefaultIssue())); - assertThat(issueService.listTransitions("ABCD")).isEmpty(); + assertThat(issueService.listTransitions("ABCD", userSession)).isEmpty(); verifyZeroInteractions(workflow); } @@ -379,7 +377,7 @@ public class IssueServiceTest { assertThat(result.updateDate()).isNotNull(); verify(issueStorage).save(manualIssue); - verify(authorizationDao).isAuthorizedComponentId(anyLong(), anyInt(), eq(UserRole.USER)); + verify(authorizationDao).isAuthorizedComponentKey(anyString(), anyInt(), eq(UserRole.USER)); } @Test @@ -387,7 +385,7 @@ public class IssueServiceTest { RuleKey ruleKey = RuleKey.of("manual", "manualRuleKey"); when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(mock(ResourceDto.class)); when(ruleFinder.findByKey(ruleKey)).thenReturn(Rule.create("manual", "manualRuleKey")); - when(authorizationDao.isAuthorizedComponentId(anyLong(), eq(10), anyString())).thenReturn(false); + when(authorizationDao.isAuthorizedComponentKey(anyString(), eq(10), anyString())).thenReturn(false); DefaultIssue manualIssue = new DefaultIssue().setKey("GHIJ").setRuleKey(ruleKey).setComponentKey("org.sonar.Sample"); try { diff --git a/sonar-server/src/test/java/org/sonar/server/permission/InternalPermissionServiceTest.java b/sonar-server/src/test/java/org/sonar/server/permission/InternalPermissionServiceTest.java index 99f28326c18..49648665887 100644 --- a/sonar-server/src/test/java/org/sonar/server/permission/InternalPermissionServiceTest.java +++ b/sonar-server/src/test/java/org/sonar/server/permission/InternalPermissionServiceTest.java @@ -50,7 +50,10 @@ import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; public class InternalPermissionServiceTest { @@ -78,7 +81,7 @@ public class InternalPermissionServiceTest { } @Test - public void return_global_permissions() { + public void return_global_permissions() { assertThat(service.globalPermissions()).containsOnly( GlobalPermissions.SYSTEM_ADMIN, GlobalPermissions.QUALITY_PROFILE_ADMIN, GlobalPermissions.DASHBOARD_SHARING, GlobalPermissions.DRY_RUN_EXECUTION, GlobalPermissions.SCAN_EXECUTION, GlobalPermissions.PROVISIONING); @@ -101,7 +104,7 @@ public class InternalPermissionServiceTest { params = buildPermissionChangeParams("user", null, "org.sample.Sample", "user"); setUpComponentUserPermissions("user", 10L, "codeviewer"); - MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, 10L); + MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, "org.sample.Sample"); service.addPermission(params); @@ -125,7 +128,7 @@ public class InternalPermissionServiceTest { params = buildPermissionChangeParams("user", null, "org.sample.Sample", "codeviewer"); setUpComponentUserPermissions("user", 10L, "codeviewer"); - MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, 10L); + MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, "org.sample.Sample"); service.removePermission(params); @@ -149,7 +152,7 @@ public class InternalPermissionServiceTest { params = buildPermissionChangeParams(null, "group", "org.sample.Sample", "user"); setUpGlobalGroupPermissions("group", "codeviewer"); - MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, 10L); + MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, "org.sample.Sample"); service.addPermission(params); @@ -171,7 +174,7 @@ public class InternalPermissionServiceTest { new ResourceDto().setId(10L).setKey("org.sample.Sample")); params = buildPermissionChangeParams(null, DefaultGroups.ANYONE, "org.sample.Sample", "user"); - MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, 10L); + MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, "org.sample.Sample"); service.addPermission(params); @@ -195,7 +198,7 @@ public class InternalPermissionServiceTest { params = buildPermissionChangeParams(null, "group", "org.sample.Sample", "codeviewer"); setUpComponentGroupPermissions("group", 10L, "codeviewer"); - MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, 10L); + MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, "org.sample.Sample"); service.removePermission(params); @@ -219,7 +222,7 @@ public class InternalPermissionServiceTest { params = buildPermissionChangeParams(null, DefaultGroups.ANYONE, "org.sample.Sample", "codeviewer"); setUpComponentGroupPermissions(DefaultGroups.ANYONE, 10L, "codeviewer"); - MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, 10L); + MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, "org.sample.Sample"); service.removePermission(params); @@ -242,8 +245,8 @@ public class InternalPermissionServiceTest { new ResourceDto().setId(10L).setKey("org.sample.Sample")); params = buildPermissionChangeParams("user", null, "org.sample.Sample", "codeviewer"); - setUpComponentUserPermissions("user", 10L, "codeviewer"); - MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, 10L); + setUpComponentUserPermissions("user", 10L, "codeviewer"); + MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, "org.sample.Sample"); service.addPermission(params); @@ -267,7 +270,7 @@ public class InternalPermissionServiceTest { params = buildPermissionChangeParams(null, "group", "org.sample.Sample", "codeviewer"); setUpComponentGroupPermissions("group", 10L, "codeviewer"); - MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, 10L); + MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, "org.sample.Sample"); service.addPermission(params); @@ -352,9 +355,18 @@ public class InternalPermissionServiceTest { @Test public void apply_permission_template_on_many_projects() throws Exception { + ComponentDto c1 = mock(ComponentDto.class); + when(c1.getId()).thenReturn(1L); + when(resourceDao.findByKey("org.sample.Sample1")).thenReturn(c1); + ComponentDto c2 = mock(ComponentDto.class); + when(c2.getId()).thenReturn(2L); + when(resourceDao.findByKey("org.sample.Sample2")).thenReturn(c2); + ComponentDto c3 = mock(ComponentDto.class); + when(c3.getId()).thenReturn(3L); + when(resourceDao.findByKey("org.sample.Sample3")).thenReturn(c3); params = Maps.newHashMap(); params.put("template_key", "my_template_key"); - params.put("components", "1,2,3"); + params.put("components", "org.sample.Sample1,org.sample.Sample2,org.sample.Sample3"); service.applyPermissionTemplate(params); @@ -367,9 +379,18 @@ public class InternalPermissionServiceTest { public void apply_permission_template_on_many_projects_without_permission() { MockUserSession.set().setLogin("admin").setGlobalPermissions(); + ComponentDto c1 = mock(ComponentDto.class); + when(c1.getId()).thenReturn(1L); + when(resourceDao.findByKey("org.sample.Sample1")).thenReturn(c1); + ComponentDto c2 = mock(ComponentDto.class); + when(c2.getId()).thenReturn(2L); + when(resourceDao.findByKey("org.sample.Sample2")).thenReturn(c2); + ComponentDto c3 = mock(ComponentDto.class); + when(c3.getId()).thenReturn(3L); + when(resourceDao.findByKey("org.sample.Sample3")).thenReturn(c3); params = Maps.newHashMap(); params.put("template_key", "my_template_key"); - params.put("components", "1,2,3"); + params.put("components", "org.sample.Sample1,org.sample.Sample2,org.sample.Sample3"); service.applyPermissionTemplate(params); @@ -378,11 +399,15 @@ public class InternalPermissionServiceTest { @Test public void apply_permission_template_on_one_project() throws Exception { - MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, 1L); + MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, "org.sample.Sample"); params = Maps.newHashMap(); params.put("template_key", "my_template_key"); - params.put("components", "1"); + params.put("components", "org.sample.Sample"); + + ComponentDto c = mock(ComponentDto.class); + when(c.getId()).thenReturn(1L); + when(resourceDao.findByKey("org.sample.Sample")).thenReturn(c); service.applyPermissionTemplate(params); @@ -411,7 +436,7 @@ public class InternalPermissionServiceTest { ComponentDto mockComponent = mock(ComponentDto.class); when(mockComponent.getId()).thenReturn(componentId); when(mockComponent.qualifier()).thenReturn(qualifier); - MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, 1234L); + MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, componentKey); when(resourceDao.findByKey(componentKey)).thenReturn(mockComponent); service.applyDefaultPermissionTemplate(componentKey); diff --git a/sonar-server/src/test/java/org/sonar/server/permission/InternalPermissionTemplateServiceTest.java b/sonar-server/src/test/java/org/sonar/server/permission/InternalPermissionTemplateServiceTest.java index 1c3a2dea77c..42f5b9971ba 100644 --- a/sonar-server/src/test/java/org/sonar/server/permission/InternalPermissionTemplateServiceTest.java +++ b/sonar-server/src/test/java/org/sonar/server/permission/InternalPermissionTemplateServiceTest.java @@ -26,7 +26,11 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.web.UserRole; -import org.sonar.core.permission.*; +import org.sonar.core.permission.GlobalPermissions; +import org.sonar.core.permission.PermissionTemplateDao; +import org.sonar.core.permission.PermissionTemplateDto; +import org.sonar.core.permission.PermissionTemplateGroupDto; +import org.sonar.core.permission.PermissionTemplateUserDto; import org.sonar.core.resource.ResourceDao; import org.sonar.core.resource.ResourceDto; import org.sonar.core.resource.ResourceQuery; @@ -39,7 +43,12 @@ import org.sonar.server.user.MockUserSession; import java.util.List; import static org.fest.assertions.Assertions.assertThat; -import static org.mockito.Mockito.*; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; public class InternalPermissionTemplateServiceTest { @@ -113,13 +122,13 @@ public class InternalPermissionTemplateServiceTest { buildUserPermission("user_dry_run", GlobalPermissions.DRY_RUN_EXECUTION), buildUserPermission("user_scan_and_dry_run", GlobalPermissions.SCAN_EXECUTION), buildUserPermission("user_scan_and_dry_run", GlobalPermissions.DRY_RUN_EXECUTION) - ); + ); List<PermissionTemplateGroupDto> groupsPermissions = Lists.newArrayList( buildGroupPermission("admin_group", GlobalPermissions.SYSTEM_ADMIN), buildGroupPermission("scan_group", GlobalPermissions.SCAN_EXECUTION), buildGroupPermission(null, GlobalPermissions.DRY_RUN_EXECUTION) - ); + ); PermissionTemplateDto permissionTemplateDto = new PermissionTemplateDto() .setId(1L) @@ -158,7 +167,7 @@ public class InternalPermissionTemplateServiceTest { @Test public void should_retrieve_all_permission_templates_from_project() throws Exception { - MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, 10L); + MockUserSession.set().setLogin("admin").addProjectPermissions(UserRole.ADMIN, "org.sample.Sample"); PermissionTemplateDto template1 = new PermissionTemplateDto().setId(1L).setName("template1").setDescription("template1"); diff --git a/sonar-server/src/test/java/org/sonar/server/user/MockUserSession.java b/sonar-server/src/test/java/org/sonar/server/user/MockUserSession.java index 99dd143f4c3..d5770638049 100644 --- a/sonar-server/src/test/java/org/sonar/server/user/MockUserSession.java +++ b/sonar-server/src/test/java/org/sonar/server/user/MockUserSession.java @@ -22,6 +22,7 @@ package org.sonar.server.user; import com.google.common.collect.HashMultimap; import javax.annotation.Nullable; + import java.util.Arrays; import java.util.Collections; import java.util.Locale; @@ -32,7 +33,7 @@ public class MockUserSession extends UserSession { private MockUserSession() { globalPermissions = Collections.emptyList(); - projectIdByPermission = HashMultimap.create(); + projectKeyByPermission = HashMultimap.create(); } public static MockUserSession set() { @@ -65,9 +66,9 @@ public class MockUserSession extends UserSession { return this; } - public MockUserSession addProjectPermissions(String projectPermission, Long... projectIds) { + public MockUserSession addProjectPermissions(String projectPermission, String... projectKeys) { this.projectPermissions.add(projectPermission); - this.projectIdByPermission.putAll(projectPermission, newArrayList(projectIds)); + this.projectKeyByPermission.putAll(projectPermission, newArrayList(projectKeys)); return this; } } diff --git a/sonar-server/src/test/java/org/sonar/server/user/UserSessionTest.java b/sonar-server/src/test/java/org/sonar/server/user/UserSessionTest.java index 56a033783f5..f791174da30 100644 --- a/sonar-server/src/test/java/org/sonar/server/user/UserSessionTest.java +++ b/sonar-server/src/test/java/org/sonar/server/user/UserSessionTest.java @@ -103,29 +103,29 @@ public class UserSessionTest { public void has_project_permission() throws Exception { AuthorizationDao authorizationDao = mock(AuthorizationDao.class); UserSession session = new SpyUserSession("marius", authorizationDao).setUserId(1); - when(authorizationDao.selectAuthorizedRootProjectsIds(1, UserRole.USER)).thenReturn(newArrayList(10L)); + when(authorizationDao.selectAuthorizedRootProjectsKeys(1, UserRole.USER)).thenReturn(newArrayList("com.foo:Bar")); - assertThat(session.hasProjectPermission(UserRole.USER, 10L)).isTrue(); - assertThat(session.hasProjectPermission(UserRole.CODEVIEWER, 10L)).isFalse(); - assertThat(session.hasProjectPermission(UserRole.ADMIN, 10L)).isFalse(); + assertThat(session.hasProjectPermission(UserRole.USER, "com.foo:Bar")).isTrue(); + assertThat(session.hasProjectPermission(UserRole.CODEVIEWER, "com.foo:Bar")).isFalse(); + assertThat(session.hasProjectPermission(UserRole.ADMIN, "com.foo:Bar")).isFalse(); } @Test public void check_project_permission_ok() throws Exception { AuthorizationDao authorizationDao = mock(AuthorizationDao.class); UserSession session = new SpyUserSession("marius", authorizationDao).setUserId(1); - when(authorizationDao.selectAuthorizedRootProjectsIds(1, UserRole.USER)).thenReturn(newArrayList(10L)); + when(authorizationDao.selectAuthorizedRootProjectsKeys(1, UserRole.USER)).thenReturn(newArrayList("com.foo:Bar")); - session.checkProjectPermission(UserRole.USER, 10L); + session.checkProjectPermission(UserRole.USER, "com.foo:Bar"); } @Test(expected = ForbiddenException.class) public void check_project_permission_ko() throws Exception { AuthorizationDao authorizationDao = mock(AuthorizationDao.class); UserSession session = new SpyUserSession("marius", authorizationDao).setUserId(1); - when(authorizationDao.selectAuthorizedRootProjectsIds(1, UserRole.USER)).thenReturn(newArrayList(11L)); + when(authorizationDao.selectAuthorizedRootProjectsKeys(1, UserRole.USER)).thenReturn(newArrayList("com.foo:Bar2")); - session.checkProjectPermission(UserRole.USER, 10L); + session.checkProjectPermission(UserRole.USER, "com.foo:Bar"); } static class SpyUserSession extends UserSession { |