From 76f302cc06533e740d8f1e4112b3d7110ae8eb9e Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Wed, 19 Apr 2017 16:59:49 +0200 Subject: [PATCH] SONAR-9139 Check 'Administer Quality Profiles' permission when creating custom rule --- .../sonar/server/rule/ws/CreateAction.java | 8 +++- .../sonar/server/rule/ws/DeleteAction.java | 3 +- .../sonar/server/rule/ws/UpdateAction.java | 3 +- .../server/rule/ws/CreateActionTest.java | 45 ++++++++++++++++--- .../server/rule/ws/UpdateActionTest.java | 18 ++++++++ 5 files changed, 68 insertions(+), 9 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/CreateAction.java b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/CreateAction.java index 046c6c4d7df1..a1b6c0661cf9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/CreateAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/CreateAction.java @@ -65,19 +65,22 @@ public class CreateAction implements RulesWsAction { private final RuleCreator ruleCreator; private final RuleMapper ruleMapper; private final OrganizationFlags organizationFlags; + private final RuleWsSupport ruleWsSupport; - public CreateAction(DbClient dbClient, RuleCreator ruleCreator, RuleMapper ruleMapper, OrganizationFlags organizationFlags) { + public CreateAction(DbClient dbClient, RuleCreator ruleCreator, RuleMapper ruleMapper, OrganizationFlags organizationFlags, RuleWsSupport ruleWsSupport) { this.dbClient = dbClient; this.ruleCreator = ruleCreator; this.ruleMapper = ruleMapper; this.organizationFlags = organizationFlags; + this.ruleWsSupport = ruleWsSupport; } @Override public void define(WebService.NewController controller) { WebService.NewAction action = controller .createAction("create") - .setDescription("Create a custom rule") + .setDescription("Create a custom rule.
" + + "Requires the 'Administer Quality Profiles' permission") .setSince("4.4") .setChangelog( new Change("5.5", "Creating manual rule is not more possible"), @@ -137,6 +140,7 @@ public void define(WebService.NewController controller) { @Override public void handle(Request request, Response response) throws Exception { + ruleWsSupport.checkQProfileAdminPermission(); String customKey = request.mandatoryParam(PARAM_CUSTOM_KEY); try (DbSession dbSession = dbClient.openSession(false)) { organizationFlags.checkDisabled(dbSession); diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/DeleteAction.java b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/DeleteAction.java index 0f12108d6ea5..25dd5a3490ff 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/DeleteAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/DeleteAction.java @@ -41,7 +41,8 @@ public DeleteAction(RuleDeleter ruleDeleter, RuleWsSupport ruleWsSupport) { public void define(WebService.NewController controller) { WebService.NewAction action = controller .createAction("delete") - .setDescription("Delete custom rule") + .setDescription("Delete custom rule.
" + + "Requires the 'Administer Quality Profiles' permission") .setSince("4.4") .setPost(true) .setHandler(this); diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/UpdateAction.java b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/UpdateAction.java index 8e3cc9bc5851..955823d80d92 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/UpdateAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/UpdateAction.java @@ -93,7 +93,8 @@ public void define(WebService.NewController controller) { WebService.NewAction action = controller .createAction("update") .setPost(true) - .setDescription("Update an existing rule") + .setDescription("Update an existing rule.
" + + "Requires the 'Administer Quality Profiles' permission") .setSince("4.4") .setHandler(this); diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/CreateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/CreateActionTest.java index bd45de586ea1..11731c7dc1c8 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/CreateActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/CreateActionTest.java @@ -32,11 +32,15 @@ import org.sonar.db.rule.RuleDefinitionDto; import org.sonar.db.rule.RuleDto; import org.sonar.server.es.EsTester; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.exceptions.UnauthorizedException; +import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.organization.TestDefaultOrganizationProvider; import org.sonar.server.organization.TestOrganizationFlags; import org.sonar.server.rule.RuleCreator; import org.sonar.server.rule.index.RuleIndexDefinition; import org.sonar.server.rule.index.RuleIndexer; +import org.sonar.server.tester.UserSessionRule; import org.sonar.server.text.MacroInterpreter; import org.sonar.server.ws.TestResponse; import org.sonar.server.ws.WsActionTester; @@ -46,6 +50,7 @@ import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES; import static org.sonar.db.rule.RuleTesting.newCustomRule; import static org.sonar.db.rule.RuleTesting.newTemplateRule; import static org.sonar.server.util.TypeValidationsTesting.newFullTypeValidations; @@ -58,6 +63,9 @@ public class CreateActionTest { @Rule public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule public DbTester db = DbTester.create(system2); @@ -65,14 +73,17 @@ public class CreateActionTest { public EsTester es = new EsTester(new RuleIndexDefinition(new MapSettings())); private TestOrganizationFlags organizationFlags = TestOrganizationFlags.standalone(); + private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); - private WsActionTester wsTester = new WsActionTester(new CreateAction(db.getDbClient(), + private WsActionTester ws = new WsActionTester(new CreateAction(db.getDbClient(), new RuleCreator(system2, new RuleIndexer(es.client(), db.getDbClient()), db.getDbClient(), newFullTypeValidations(), TestDefaultOrganizationProvider.from(db)), - new RuleMapper(new Languages(), createMacroInterpreter()), organizationFlags)); + new RuleMapper(new Languages(), createMacroInterpreter()), organizationFlags, + new RuleWsSupport(db.getDbClient(), userSession, defaultOrganizationProvider))); @Test public void create_custom_rule() { + logInAsQProfileAdministrator(); organizationFlags.setEnabled(false); // Template rule RuleDto templateRule = newTemplateRule(RuleKey.of("java", "S001"), db.getDefaultOrganization()); @@ -80,7 +91,7 @@ public void create_custom_rule() { db.rules().insertOrUpdateMetadata(templateRule.getMetadata().setRuleId(templateRule.getId())); db.rules().insertRuleParam(templateRule.getDefinition(), param -> param.setName("regex").setType("STRING").setDescription("Reg ex").setDefaultValue(".*")); - String result = wsTester.newRequest() + String result = ws.newRequest() .setParam("custom_key", "MY_CUSTOM") .setParam("template_key", templateRule.getKey().toString()) .setParam("name", "My custom rule") @@ -117,6 +128,7 @@ public void create_custom_rule() { @Test public void create_custom_rule_with_prevent_reactivation_param_to_true() { + logInAsQProfileAdministrator(); organizationFlags.setEnabled(false); RuleDefinitionDto templateRule = newTemplateRule(RuleKey.of("java", "S001")).getDefinition(); db.rules().insert(templateRule); @@ -130,7 +142,7 @@ public void create_custom_rule_with_prevent_reactivation_param_to_true() { .setSeverity(Severity.MAJOR); db.rules().insert(customRule); - TestResponse response = wsTester.newRequest() + TestResponse response = ws.newRequest() .setParam("custom_key", "MY_CUSTOM") .setParam("template_key", templateRule.getKey().toString()) .setParam("name", "My custom rule") @@ -155,12 +167,13 @@ public void create_custom_rule_with_prevent_reactivation_param_to_true() { @Test public void fail_to_create_rule_when_organizations_are_enabled() throws Exception { + logInAsQProfileAdministrator(); organizationFlags.setEnabled(true); expectedException.expect(IllegalStateException.class); expectedException.expectMessage("Organization support is enabled"); - wsTester.newRequest() + ws.newRequest() .setParam("custom_key", "MY_CUSTOM") .setParam("template_key", "java:S001") .setParam("name", "My custom rule") @@ -169,10 +182,32 @@ public void fail_to_create_rule_when_organizations_are_enabled() throws Exceptio .execute(); } + @Test + public void throw_ForbiddenException_if_not_profile_administrator() throws Exception { + userSession.logIn(); + + expectedException.expect(ForbiddenException.class); + + ws.newRequest().execute(); + } + + @Test + public void throw_UnauthorizedException_if_not_logged_in() throws Exception { + expectedException.expect(UnauthorizedException.class); + + ws.newRequest().execute(); + } + private static MacroInterpreter createMacroInterpreter() { MacroInterpreter macroInterpreter = mock(MacroInterpreter.class); doAnswer(returnsFirstArg()).when(macroInterpreter).interpret(anyString()); return macroInterpreter; } + private void logInAsQProfileAdministrator() { + userSession + .logIn() + .addPermission(ADMINISTER_QUALITY_PROFILES, defaultOrganizationProvider.get().getUuid()); + } + } diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/UpdateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/UpdateActionTest.java index 90c54900b0cb..9533ae1cfdd9 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/UpdateActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/UpdateActionTest.java @@ -38,6 +38,8 @@ import org.sonar.db.rule.RuleTesting; import org.sonar.server.es.EsClient; import org.sonar.server.es.EsTester; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.organization.TestDefaultOrganizationProvider; import org.sonar.server.rule.RuleUpdater; @@ -309,6 +311,22 @@ public void fail_to_update_custom_when_description_is_empty() { .execute(); } + @Test + public void throw_ForbiddenException_if_not_profile_administrator() throws Exception { + userSession.logIn(); + + expectedException.expect(ForbiddenException.class); + + ws.newRequest().setMethod("POST").execute(); + } + + @Test + public void throw_UnauthorizedException_if_not_logged_in() throws Exception { + expectedException.expect(UnauthorizedException.class); + + ws.newRequest().setMethod("POST").execute(); + } + private void logInAsQProfileAdministrator() { userSession .logIn()