]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6502 WS permissions/add_group_to_template add a group to a permission template
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Mon, 24 Aug 2015 06:23:42 +0000 (08:23 +0200)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Mon, 24 Aug 2015 08:38:51 +0000 (10:38 +0200)
20 files changed:
server/sonar-server/src/main/java/org/sonar/server/permission/PermissionRequestValidator.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplateUpdater.java
server/sonar-server/src/main/java/org/sonar/server/permission/PermissionUpdater.java
server/sonar-server/src/main/java/org/sonar/server/permission/PermissionValueValidator.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/permission/ws/AddGroupToTemplateAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/permission/ws/AddUserToTemplateAction.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionDependenciesFinder.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionRequest.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionsWsModule.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/RemoveUserFromTemplateAction.java
server/sonar-server/src/main/java/org/sonar/server/ws/WsUtils.java
server/sonar-server/src/test/java/org/sonar/server/permission/ws/AddGroupToTemplateActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/permission/ws/AddUserToTemplateActionTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/ws/PermissionsWsModuleTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/ws/RemoveGroupActionTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/ws/RemoveUserFromTemplateActionTest.java
sonar-db/src/main/java/org/sonar/core/permission/ProjectPermissions.java
sonar-db/src/main/java/org/sonar/db/permission/PermissionTemplateDao.java
sonar-db/src/main/resources/org/sonar/db/permission/PermissionTemplateMapper.xml
sonar-plugin-api/src/main/java/org/sonar/api/security/DefaultGroups.java

diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionRequestValidator.java b/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionRequestValidator.java
new file mode 100644 (file)
index 0000000..9ce5d35
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.permission;
+
+import javax.annotation.Nullable;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.permission.ProjectPermissions;
+
+import static java.lang.String.format;
+import static org.sonar.api.security.DefaultGroups.isAnyone;
+import static org.sonar.server.ws.WsUtils.checkRequest;
+
+public class PermissionRequestValidator {
+  private PermissionRequestValidator() {
+    // static methods only
+  }
+
+  public static void validateProjectPermission(String permission) {
+    checkRequest(ProjectPermissions.ALL.contains(permission),
+      format("The 'permission' parameter for project permissions must be one of %s. '%s' was passed.", ProjectPermissions.ALL_ON_ONE_LINE, permission));
+  }
+
+  public static void validateGlobalPermission(String permission) {
+    checkRequest(GlobalPermissions.ALL.contains(permission),
+      format("The 'permission' parameter for global permissions must be one of %s. '%s' was passed.", GlobalPermissions.ALL_ON_ONE_LINE, permission));
+  }
+
+  public static void validateNotAnyoneAndAdminPermission(String permission, @Nullable String groupName) {
+    checkRequest(!GlobalPermissions.SYSTEM_ADMIN.equals(permission) || !isAnyone(groupName),
+      String.format("It is not possible to add the '%s' permission to the '%s' group.", permission, groupName));
+  }
+}
index 4f3970f642b8e81aea11f25cfbf54ca4892ecbd2..28063e8bdafa3299e8ff4af880e3c51a74be4c40 100644 (file)
@@ -30,7 +30,7 @@ import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.user.UserSession;
 
 import static org.sonar.server.permission.PermissionPrivilegeChecker.checkGlobalAdminUser;
-import static org.sonar.server.permission.PermissionValueValidator.validateProjectPermission;
+import static org.sonar.server.permission.PermissionRequestValidator.validateProjectPermission;
 
 /**
  * @deprecated since 5.2 can be removed when Ruby doesn't rely on PermissionTemplateService
index d1f3262503464a2e6a30924e6f55a580f2938a83..27be8f1c8aeb6d3f3db1e4542c8b6399e1955703 100644 (file)
@@ -23,7 +23,6 @@ package org.sonar.server.permission;
 import java.util.List;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
-import org.sonar.api.security.DefaultGroups;
 import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
@@ -36,7 +35,9 @@ import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.issue.index.IssueAuthorizationIndexer;
 import org.sonar.server.user.UserSession;
 
+import static org.sonar.api.security.DefaultGroups.isAnyone;
 import static org.sonar.server.permission.PermissionPrivilegeChecker.checkProjectAdminUserByComponentKey;
+import static org.sonar.server.permission.PermissionRequestValidator.validateNotAnyoneAndAdminPermission;
 
 public class PermissionUpdater {
 
@@ -114,7 +115,7 @@ public class PermissionUpdater {
     Long targetedGroup = getTargetedGroup(session, permissionChange.groupName());
     String permission = permissionChange.permission();
     if (Operation.ADD == operation) {
-      checkNotAnyoneAndAdmin(permission, permissionChange.groupName());
+      validateNotAnyoneAndAdminPermission(permission, permissionChange.groupName());
       permissionRepository.insertGroupPermission(componentId, targetedGroup, permission, session);
     } else {
       checkAdminUsersExistOutsideTheRemovedGroup(session, permissionChange, targetedGroup);
@@ -123,13 +124,6 @@ public class PermissionUpdater {
     return true;
   }
 
-  private static void checkNotAnyoneAndAdmin(String permission, String group) {
-    if (GlobalPermissions.SYSTEM_ADMIN.equals(permission)
-      && DefaultGroups.isAnyone(group)) {
-      throw new BadRequestException(String.format("It is not possible to add the '%s' permission to the '%s' group.", permission, group));
-    }
-  }
-
   private boolean applyChangeOnUser(DbSession session, Operation operation, PermissionChange permissionChange) {
     Long componentId = getComponentId(session, permissionChange.componentKey());
     checkProjectAdminUserByComponentKey(userSession, permissionChange.componentKey());
@@ -173,7 +167,7 @@ public class PermissionUpdater {
 
   @Nullable
   private Long getTargetedGroup(DbSession session, String group) {
-    if (DefaultGroups.isAnyone(group)) {
+    if (isAnyone(group)) {
       return null;
     } else {
       GroupDto groupDto = dbClient.groupDao().selectByName(session, group);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionValueValidator.java b/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionValueValidator.java
deleted file mode 100644 (file)
index e8a4a2d..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.server.permission;
-
-import org.sonar.core.permission.ProjectPermissions;
-import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.server.exceptions.BadRequestException;
-
-public class PermissionValueValidator {
-  private PermissionValueValidator() {
-    // static methods only
-  }
-
-  public static void validateProjectPermission(String permission) {
-    if (!ProjectPermissions.ALL.contains(permission)) {
-      throw new BadRequestException(String.format("The 'permission' parameter for project permissions must be one of %s. '%s' was passed.", ProjectPermissions.ALL_ON_ONE_LINE,
-        permission));
-    }
-  }
-
-  public static void validateGlobalPermission(String permission) {
-    if (!GlobalPermissions.ALL.contains(permission)) {
-      throw new BadRequestException(String.format("The 'permission' parameter for global permissions must be one of %s. '%s' was passed.", GlobalPermissions.ALL_ON_ONE_LINE,
-        permission));
-    }
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/ws/AddGroupToTemplateAction.java b/server/sonar-server/src/main/java/org/sonar/server/permission/ws/AddGroupToTemplateAction.java
new file mode 100644 (file)
index 0000000..6e35f17
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.permission.ws;
+
+import javax.annotation.Nullable;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.permission.PermissionQuery;
+import org.sonar.db.permission.PermissionTemplateDto;
+import org.sonar.db.user.GroupDto;
+import org.sonar.server.user.UserSession;
+
+import static org.sonar.api.security.DefaultGroups.ANYONE;
+import static org.sonar.db.user.GroupMembershipQuery.IN;
+import static org.sonar.server.permission.PermissionPrivilegeChecker.checkGlobalAdminUser;
+import static org.sonar.server.permission.PermissionRequestValidator.validateNotAnyoneAndAdminPermission;
+import static org.sonar.server.permission.PermissionRequestValidator.validateProjectPermission;
+import static org.sonar.server.permission.ws.Parameters.PARAM_GROUP_ID;
+import static org.sonar.server.permission.ws.Parameters.PARAM_GROUP_NAME;
+import static org.sonar.server.permission.ws.Parameters.PARAM_PERMISSION;
+import static org.sonar.server.permission.ws.Parameters.PARAM_TEMPLATE_KEY;
+import static org.sonar.server.permission.ws.Parameters.createGroupIdParameter;
+import static org.sonar.server.permission.ws.Parameters.createGroupNameParameter;
+import static org.sonar.server.permission.ws.Parameters.createPermissionParameter;
+import static org.sonar.server.permission.ws.Parameters.createTemplateKeyParameter;
+
+public class AddGroupToTemplateAction implements PermissionsWsAction {
+  private final DbClient dbClient;
+  private final PermissionDependenciesFinder dependenciesFinder;
+  private final UserSession userSession;
+
+  public AddGroupToTemplateAction(DbClient dbClient, PermissionDependenciesFinder dependenciesFinder, UserSession userSession) {
+    this.dbClient = dbClient;
+    this.dependenciesFinder = dependenciesFinder;
+    this.userSession = userSession;
+  }
+
+  @Override
+  public void define(WebService.NewController context) {
+    WebService.NewAction action = context
+      .createAction("add_group_to_template")
+      .setPost(true)
+      .setSince("5.2")
+      .setDescription("Add a group to a permission template.<br /> " +
+        "The group id or group name must be provided. <br />" +
+        "It requires administration permissions to access.")
+      .setHandler(this);
+
+    createTemplateKeyParameter(action);
+    createPermissionParameter(action);
+    createGroupIdParameter(action);
+    createGroupNameParameter(action);
+  }
+
+  @Override
+  public void handle(Request wsRequest, Response wsResponse) throws Exception {
+    checkGlobalAdminUser(userSession);
+
+    String templateKey = wsRequest.mandatoryParam(PARAM_TEMPLATE_KEY);
+    String permission = wsRequest.mandatoryParam(PARAM_PERMISSION);
+    Long groupIdParam = wsRequest.paramAsLong(PARAM_GROUP_ID);
+    String groupName = wsRequest.param(PARAM_GROUP_NAME);
+
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      validateProjectPermission(permission);
+      validateNotAnyoneAndAdminPermission(permission, groupName);
+
+      PermissionTemplateDto template = dependenciesFinder.getTemplate(templateKey);
+      GroupDto group = dependenciesFinder.getGroup(dbSession, groupIdParam, groupName);
+
+      if (!groupAlreadyAdded(dbSession, template.getId(), group, permission)) {
+        Long groupId = group == null ? null : group.getId();
+        dbClient.permissionTemplateDao().insertGroupPermission(dbSession, template.getId(), groupId, permission);
+      }
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+
+    wsResponse.noContent();
+  }
+
+  private boolean groupAlreadyAdded(DbSession dbSession, long templateId, @Nullable GroupDto group, String permission) {
+    String groupName = group == null ? ANYONE : group.getName();
+    PermissionQuery permissionQuery = PermissionQuery.builder().membership(IN).permission(permission).build();
+    return dbClient.permissionTemplateDao().hasGroup(dbSession, permissionQuery, templateId, groupName);
+  }
+}
index 78b5e7ec988a98c4734fff21f631db5c4df3a4c6..01ae1255d4c6afa6519240693be8f7c4b1b5c1de 100644 (file)
@@ -36,7 +36,7 @@ import org.sonar.server.user.UserSession;
 import static com.google.common.collect.FluentIterable.from;
 import static org.sonar.db.user.GroupMembershipQuery.IN;
 import static org.sonar.server.permission.PermissionPrivilegeChecker.checkGlobalAdminUser;
-import static org.sonar.server.permission.PermissionValueValidator.validateProjectPermission;
+import static org.sonar.server.permission.PermissionRequestValidator.validateProjectPermission;
 import static org.sonar.server.permission.ws.Parameters.PARAM_PERMISSION;
 import static org.sonar.server.permission.ws.Parameters.PARAM_TEMPLATE_KEY;
 import static org.sonar.server.permission.ws.Parameters.PARAM_USER_LOGIN;
index 80db297ef989882637bff1f3490250d0c376dabe..32d73c48a081edb826bf714e6547dcdb5bf14547 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.server.permission.ws;
 
 import com.google.common.base.Optional;
 import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.ComponentDto;
@@ -29,11 +30,12 @@ import org.sonar.db.permission.PermissionTemplateDto;
 import org.sonar.db.user.GroupDto;
 import org.sonar.db.user.UserDto;
 import org.sonar.server.component.ComponentFinder;
-import org.sonar.server.exceptions.BadRequestException;
 
-import static com.google.common.base.Preconditions.checkNotNull;
+import static java.lang.String.format;
 import static org.sonar.api.security.DefaultGroups.ANYONE;
 import static org.sonar.api.security.DefaultGroups.isAnyone;
+import static org.sonar.server.ws.WsUtils.checkFound;
+import static org.sonar.server.ws.WsUtils.checkRequest;
 
 public class PermissionDependenciesFinder {
   private final DbClient dbClient;
@@ -56,57 +58,44 @@ public class PermissionDependenciesFinder {
   }
 
   String getGroupName(DbSession dbSession, PermissionRequest request) {
-    if (isAnyone(request.groupName())) {
-      return ANYONE;
+    GroupDto group = getGroup(dbSession, request.groupId(), request.groupName());
+
+    return group == null ? ANYONE : group.getName();
+  }
+
+  /**
+   * 
+   * @return null if it's the anyone group
+   */
+  @CheckForNull
+  GroupDto getGroup(DbSession dbSession, @Nullable Long groupId, @Nullable String groupName) {
+    checkRequest(groupId != null ^ groupName != null, "Group name or group id must be provided, not both.");
+    if (isAnyone(groupName)) {
+      return null;
     }
 
     GroupDto group = null;
 
-    Long groupId = request.groupId();
     if (groupId != null) {
-      group = dbClient.groupDao().selectById(dbSession, groupId);
-      if (group == null) {
-        throw new BadRequestException(String.format("Group with id '%d' is not found", groupId));
-      }
+      group = checkFound(dbClient.groupDao().selectById(dbSession, groupId),
+        format("Group with id '%d' is not found", groupId));
     }
 
-    String groupName = request.groupName();
     if (groupName != null) {
-      group = dbClient.groupDao().selectByName(dbSession, groupName);
-      if (group == null) {
-        throw new BadRequestException(String.format("Group with name '%s' is not found", groupName));
-      }
-    }
-
-    return checkNotNull(group).getName();
-  }
-
-  @CheckForNull
-  Long getGroupId(DbSession dbSession, String groupName) {
-    if (isAnyone(groupName)) {
-      return null;
+      group = checkFound(dbClient.groupDao().selectByName(dbSession, groupName),
+        format("Group with name '%s' is not found", groupName));
     }
 
-    GroupDto group = dbClient.groupDao().selectByName(dbSession, groupName);
-    if (group == null) {
-      throw new BadRequestException(String.format("Group with name '%s' is not found", groupName));
-    }
-    return group.getId();
+    return group;
   }
 
   UserDto getUser(DbSession dbSession, String userLogin) {
-    UserDto user = dbClient.userDao().selectActiveUserByLogin(dbSession, userLogin);
-    if (user == null) {
-      throw new BadRequestException(String.format("User with login '%s' is not found'", userLogin));
-    }
-    return user;
+    return checkFound(dbClient.userDao().selectActiveUserByLogin(dbSession, userLogin),
+      format("User with login '%s' is not found'", userLogin));
   }
 
   PermissionTemplateDto getTemplate(String templateKey) {
-    PermissionTemplateDto permissionTemplate = dbClient.permissionTemplateDao().selectTemplateByKey(templateKey);
-    if (permissionTemplate == null) {
-      throw new BadRequestException(String.format("Permission template with key '%s' is not found", templateKey));
-    }
-    return permissionTemplate;
+    return checkFound(dbClient.permissionTemplateDao().selectTemplateByKey(templateKey),
+      format("Permission template with key '%s' is not found", templateKey));
   }
 }
index d043ea3a9427715dc9ecd1097486eff58c88d5ea..a6a87a7106dfbf7cf64b11511891897235de169d 100644 (file)
@@ -34,8 +34,8 @@ import static org.sonar.server.permission.ws.Parameters.PARAM_PERMISSION;
 import static org.sonar.server.permission.ws.Parameters.PARAM_PROJECT_KEY;
 import static org.sonar.server.permission.ws.Parameters.PARAM_PROJECT_UUID;
 import static org.sonar.server.permission.ws.Parameters.PARAM_USER_LOGIN;
-import static org.sonar.server.permission.PermissionValueValidator.validateGlobalPermission;
-import static org.sonar.server.permission.PermissionValueValidator.validateProjectPermission;
+import static org.sonar.server.permission.PermissionRequestValidator.validateGlobalPermission;
+import static org.sonar.server.permission.PermissionRequestValidator.validateProjectPermission;
 import static org.sonar.server.ws.WsUtils.checkRequest;
 
 class PermissionRequest {
index 18bf09ceddf59d604b56f04ea648228e55c9a941..f7434324cbdc2839cc6ab5ff92b7fbdea1ad55c4 100644 (file)
@@ -39,6 +39,7 @@ public class PermissionsWsModule extends Module {
       SearchProjectPermissionsDataLoader.class,
       PermissionDependenciesFinder.class,
       AddUserToTemplateAction.class,
-      RemoveUserFromTemplateAction.class);
+      RemoveUserFromTemplateAction.class,
+      AddGroupToTemplateAction.class);
   }
 }
index cdd5afe077233bf8424092be4479903b5451f1bb..7b2857e21ef5421d0cbda9ee8e918423f7fb6a17 100644 (file)
@@ -30,7 +30,7 @@ import org.sonar.db.user.UserDto;
 import org.sonar.server.user.UserSession;
 
 import static org.sonar.server.permission.PermissionPrivilegeChecker.checkGlobalAdminUser;
-import static org.sonar.server.permission.PermissionValueValidator.validateProjectPermission;
+import static org.sonar.server.permission.PermissionRequestValidator.validateProjectPermission;
 import static org.sonar.server.permission.ws.Parameters.PARAM_PERMISSION;
 import static org.sonar.server.permission.ws.Parameters.PARAM_TEMPLATE_KEY;
 import static org.sonar.server.permission.ws.Parameters.PARAM_USER_LOGIN;
index 707cbbde6c583445f2c41c4f92950477e39ba1af..b96a67b7235cb298e191a4d4fad401e3293aaf2a 100644 (file)
@@ -28,6 +28,7 @@ import org.sonar.api.server.ws.Response;
 import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.core.util.ProtobufJsonFormat;
 import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.plugins.MimeTypes;
 
 public class WsUtils {
@@ -56,9 +57,21 @@ public class WsUtils {
   /**
    * @throws BadRequestException
    */
-  public static void checkRequest(boolean expression, String errorMessage) {
+  public static void checkRequest(boolean expression, String message) {
     if (!expression) {
-      throw new BadRequestException(errorMessage);
+      throw new BadRequestException(message);
     }
   }
+
+  /**
+   * @throws NotFoundException if the value if null
+   * @return the value
+   */
+  public static <T> T checkFound(T value, String message) {
+    if (value == null) {
+      throw new NotFoundException(message);
+    }
+
+    return value;
+  }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/ws/AddGroupToTemplateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/ws/AddGroupToTemplateActionTest.java
new file mode 100644 (file)
index 0000000..221fbfc
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.permission.ws;
+
+import com.google.common.base.Function;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.permission.GroupWithPermissionDto;
+import org.sonar.db.permission.PermissionQuery;
+import org.sonar.db.permission.PermissionTemplateDto;
+import org.sonar.db.user.GroupDto;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
+import org.sonar.server.ws.WsActionTester;
+import org.sonar.test.DbTests;
+
+import static com.google.common.collect.FluentIterable.from;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.security.DefaultGroups.ANYONE;
+import static org.sonar.api.web.UserRole.ADMIN;
+import static org.sonar.api.web.UserRole.CODEVIEWER;
+import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
+import static org.sonar.db.permission.PermissionTemplateTesting.newPermissionTemplateDto;
+import static org.sonar.db.user.GroupMembershipQuery.IN;
+import static org.sonar.db.user.GroupTesting.newGroupDto;
+import static org.sonar.server.permission.ws.Parameters.PARAM_GROUP_ID;
+import static org.sonar.server.permission.ws.Parameters.PARAM_PERMISSION;
+import static org.sonar.server.permission.ws.Parameters.PARAM_TEMPLATE_KEY;
+
+@Category(DbTests.class)
+public class AddGroupToTemplateActionTest {
+
+  private static final String GROUP_NAME = "group-name";
+  @Rule
+  public DbTester db = DbTester.create(System2.INSTANCE);
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  WsActionTester ws;
+  DbClient dbClient;
+  DbSession dbSession;
+  GroupDto group;
+  PermissionTemplateDto permissionTemplate;
+
+  @Before
+  public void setUp() {
+    dbClient = db.getDbClient();
+    dbSession = db.getSession();
+    userSession.login().setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+
+    PermissionDependenciesFinder dependenciesFinder = new PermissionDependenciesFinder(dbClient, new ComponentFinder(dbClient));
+    ws = new WsActionTester(new AddGroupToTemplateAction(dbClient, dependenciesFinder, userSession));
+
+    group = insertGroup(newGroupDto().setName(GROUP_NAME));
+    permissionTemplate = insertPermissionTemplate(newPermissionTemplateDto());
+    commit();
+  }
+
+  @Test
+  public void add_group_to_template() {
+    newRequest(GROUP_NAME, permissionTemplate.getKee(), CODEVIEWER);
+
+    assertThat(getGroupNamesInTemplateAndPermission(permissionTemplate.getId(), CODEVIEWER)).containsExactly(GROUP_NAME);
+  }
+
+  @Test
+  public void add_with_group_id() {
+    ws.newRequest()
+      .setParam(PARAM_TEMPLATE_KEY, permissionTemplate.getKee())
+      .setParam(PARAM_PERMISSION, CODEVIEWER)
+      .setParam(PARAM_GROUP_ID, String.valueOf(group.getId()))
+      .execute();
+
+    assertThat(getGroupNamesInTemplateAndPermission(permissionTemplate.getId(), CODEVIEWER)).containsExactly(GROUP_NAME);
+  }
+
+  @Test
+  public void does_not_add_a_group_twice() {
+    newRequest(GROUP_NAME, permissionTemplate.getKee(), ISSUE_ADMIN);
+    newRequest(GROUP_NAME, permissionTemplate.getKee(), ISSUE_ADMIN);
+
+    assertThat(getGroupNamesInTemplateAndPermission(permissionTemplate.getId(), ISSUE_ADMIN)).containsExactly(GROUP_NAME);
+  }
+
+  @Test
+  public void add_anyone_group_to_template() {
+    newRequest(ANYONE, permissionTemplate.getKee(), CODEVIEWER);
+
+    assertThat(getGroupNamesInTemplateAndPermission(permissionTemplate.getId(), CODEVIEWER)).containsExactly(ANYONE);
+  }
+
+  @Test
+  public void fail_if_add_anyone_group_to_admin_permission() {
+    expectedException.expect(BadRequestException.class);
+    expectedException.expectMessage(String.format("It is not possible to add the '%s' permission to the '%s' group.", UserRole.ADMIN, ANYONE));
+
+    newRequest(ANYONE, permissionTemplate.getKee(), ADMIN);
+  }
+
+  @Test
+  public void fail_if_not_a_project_permission() {
+    expectedException.expect(BadRequestException.class);
+
+    newRequest(GROUP_NAME, permissionTemplate.getKee(), GlobalPermissions.PREVIEW_EXECUTION);
+  }
+
+  @Test
+  public void fail_if_insufficient_privileges() {
+    expectedException.expect(ForbiddenException.class);
+    userSession.setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+
+    newRequest(GROUP_NAME, permissionTemplate.getKee(), CODEVIEWER);
+  }
+
+  @Test
+  public void fail_if_not_logged_in() {
+    expectedException.expect(UnauthorizedException.class);
+    userSession.anonymous();
+
+    newRequest(GROUP_NAME, permissionTemplate.getKee(), CODEVIEWER);
+  }
+
+  @Test
+  public void fail_if_group_params_missing() {
+    expectedException.expect(BadRequestException.class);
+
+    newRequest(null, permissionTemplate.getKee(), CODEVIEWER);
+  }
+
+  @Test
+  public void fail_if_permission_missing() {
+    expectedException.expect(IllegalArgumentException.class);
+
+    newRequest(GROUP_NAME, permissionTemplate.getKee(), null);
+  }
+
+  @Test
+  public void fail_if_template_key_missing() {
+    expectedException.expect(IllegalArgumentException.class);
+
+    newRequest(GROUP_NAME, null, CODEVIEWER);
+  }
+
+  @Test
+  public void fail_if_group_does_not_exist() {
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage("Group with name 'unknown-group-name' is not found");
+
+    newRequest("unknown-group-name", permissionTemplate.getKee(), CODEVIEWER);
+  }
+
+  @Test
+  public void fail_if_template_key_does_not_exist() {
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage("Permission template with key 'unknown-key' is not found");
+
+    newRequest(GROUP_NAME, "unknown-key", CODEVIEWER);
+  }
+
+  private void newRequest(@Nullable String groupName, @Nullable String templateKey, @Nullable String permission) {
+    TestRequest request = ws.newRequest();
+    if (groupName != null) {
+      request.setParam(Parameters.PARAM_GROUP_NAME, groupName);
+    }
+    if (templateKey != null) {
+      request.setParam(PARAM_TEMPLATE_KEY, templateKey);
+    }
+    if (permission != null) {
+      request.setParam(Parameters.PARAM_PERMISSION, permission);
+    }
+
+    request.execute();
+  }
+
+  private void commit() {
+    dbSession.commit();
+  }
+
+  private GroupDto insertGroup(GroupDto groupDto) {
+    return dbClient.groupDao().insert(dbSession, groupDto);
+  }
+
+  private PermissionTemplateDto insertPermissionTemplate(PermissionTemplateDto permissionTemplate) {
+    return dbClient.permissionTemplateDao().insertPermissionTemplate(permissionTemplate.getName(), permissionTemplate.getDescription(), permissionTemplate.getKeyPattern());
+  }
+
+  private List<String> getGroupNamesInTemplateAndPermission(long templateId, String permission) {
+    PermissionQuery permissionQuery = PermissionQuery.builder().permission(permission).membership(IN).build();
+    return from(dbClient.permissionTemplateDao()
+      .selectGroups(dbSession, permissionQuery, templateId))
+      .transform(GroupWithPermissionToGroupName.INSTANCE)
+      .toList();
+  }
+
+  private enum GroupWithPermissionToGroupName implements Function<GroupWithPermissionDto, String> {
+    INSTANCE;
+
+    @Override
+    public String apply(@Nonnull GroupWithPermissionDto groupWithPermission) {
+      return groupWithPermission.getName();
+    }
+
+  }
+}
index 957fdcf2691cea1f4cff1ea32239f8cdc03f2b9d..a4fdf5f09cc175d00e2f76aea08244246b0205b2 100644 (file)
@@ -41,6 +41,7 @@ import org.sonar.db.user.UserDto;
 import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.exceptions.UnauthorizedException;
 import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.TestRequest;
@@ -147,7 +148,7 @@ public class AddUserToTemplateActionTest {
 
   @Test
   public void fail_if_user_does_not_exist() {
-    expectedException.expect(BadRequestException.class);
+    expectedException.expect(NotFoundException.class);
     expectedException.expectMessage("User with login 'unknown-login' is not found");
 
     newRequest("unknown-login", permissionTemplate.getKee(), CODEVIEWER);
@@ -155,7 +156,7 @@ public class AddUserToTemplateActionTest {
 
   @Test
   public void fail_if_template_key_does_not_exist() {
-    expectedException.expect(BadRequestException.class);
+    expectedException.expect(NotFoundException.class);
     expectedException.expectMessage("Permission template with key 'unknown-key' is not found");
 
     newRequest(USER_LOGIN, "unknown-key", CODEVIEWER);
index b609653ed9d007ab95afb21e77d5a20dac76c9a4..cabe737a9075e7301ad730fdad483f19b1fc4140 100644 (file)
@@ -30,6 +30,6 @@ public class PermissionsWsModuleTest {
   public void verify_count_of_added_components() {
     ComponentContainer container = new ComponentContainer();
     new PermissionsWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(16);
+    assertThat(container.size()).isEqualTo(17);
   }
 }
index 016cf0aab0d06b03aa537f7fb70098ed7f3aa4cd..4e85fdb1efe636e867466b481eef22e27986b510 100644 (file)
@@ -35,6 +35,7 @@ import org.sonar.db.component.ComponentDto;
 import org.sonar.db.user.GroupDto;
 import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.exceptions.ServerException;
 import org.sonar.server.permission.PermissionChange;
 import org.sonar.server.permission.PermissionUpdater;
@@ -144,7 +145,7 @@ public class RemoveGroupActionTest {
 
   @Test
   public void fail_when_project_does_not_exist() throws Exception {
-    expectedException.expect(BadRequestException.class);
+    expectedException.expect(NotFoundException.class);
 
     newRequest()
       .setParam(PARAM_GROUP_NAME, "sonar-administrators")
@@ -207,7 +208,7 @@ public class RemoveGroupActionTest {
 
   @Test
   public void fail_when_group_id_does_not_exist() throws Exception {
-    expectedException.expect(BadRequestException.class);
+    expectedException.expect(NotFoundException.class);
     expectedException.expectMessage("Group with id '42' is not found");
 
     newRequest()
index 080a7b1e0f3b1169c95887ee035733d294a31354..93bb60e77af293e8536edb4914e936c54d3cf99e 100644 (file)
@@ -41,6 +41,7 @@ import org.sonar.db.user.UserDto;
 import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.exceptions.UnauthorizedException;
 import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.TestRequest;
@@ -171,7 +172,7 @@ public class RemoveUserFromTemplateActionTest {
 
   @Test
   public void fail_if_user_does_not_exist() {
-    expectedException.expect(BadRequestException.class);
+    expectedException.expect(NotFoundException.class);
     expectedException.expectMessage("User with login 'unknown-login' is not found");
 
     newRequest("unknown-login", permissionTemplate.getKee(), DEFAULT_PERMISSION);
@@ -179,7 +180,7 @@ public class RemoveUserFromTemplateActionTest {
 
   @Test
   public void fail_if_template_key_does_not_exist() {
-    expectedException.expect(BadRequestException.class);
+    expectedException.expect(NotFoundException.class);
     expectedException.expectMessage("Permission template with key 'unknown-key' is not found");
 
     newRequest(USER_LOGIN, "unknown-key", DEFAULT_PERMISSION);
index e7365f8232b9f25cdff3a731cdef63af0989f1f4..26e86f41ff337b83021fe4c8a023a72445dff2ed 100644 (file)
@@ -31,6 +31,10 @@ import org.sonar.api.web.UserRole;
  */
 public final class ProjectPermissions {
 
+  private ProjectPermissions() {
+    // static constants only
+  }
+
   /**
    * All the component permissions values, ordered from {@link UserRole#USER} to {@link UserRole#CODEVIEWER}.
    */
index b5c58686816e05743878941c2c37a7b8c4ba72dd..1170be201d10c8ecebffe972002bfcb8c1a461d7 100644 (file)
@@ -103,11 +103,22 @@ public class PermissionTemplateDao implements Dao {
     }
   }
 
-  public int countGroups(DbSession session, PermissionQuery query, Long templateId) {
+  public int countGroups(DbSession session, PermissionQuery query, long templateId) {
+    return countGroups(session, query, templateId, null);
+  }
+
+  private int countGroups(DbSession session, PermissionQuery query, long templateId, @Nullable String groupName) {
     Map<String, Object> parameters = groupsParamaters(query, templateId);
+    if (groupName != null) {
+      parameters.put("groupName", groupName.toUpperCase());
+    }
     return mapper(session).countGroups(parameters);
   }
 
+  public boolean hasGroup(DbSession session, PermissionQuery query, long templateId, String groupName) {
+    return countGroups(session, query, templateId, groupName) > 0;
+  }
+
   private static Map<String, Object> groupsParamaters(PermissionQuery query, Long templateId) {
     Map<String, Object> params = newHashMap();
     params.put(QUERY_PARAMETER, query);
@@ -266,19 +277,23 @@ public class PermissionTemplateDao implements Dao {
   }
 
   public void insertGroupPermission(Long templateId, @Nullable Long groupId, String permission) {
+    DbSession session = myBatis.openSession(false);
+    try {
+      insertGroupPermission(session, templateId, groupId, permission);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public void insertGroupPermission(DbSession session, Long templateId, @Nullable Long groupId, String permission) {
     PermissionTemplateGroupDto permissionTemplateGroup = new PermissionTemplateGroupDto()
       .setTemplateId(templateId)
       .setPermission(permission)
       .setGroupId(groupId)
       .setCreatedAt(now())
       .setUpdatedAt(now());
-    SqlSession session = myBatis.openSession(false);
-    try {
-      mapper(session).insertGroupPermission(permissionTemplateGroup);
-      session.commit();
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
+    mapper(session).insertGroupPermission(permissionTemplateGroup);
+    session.commit();
   }
 
   public void deleteGroupPermission(Long templateId, @Nullable Long groupId, String permission) {
index 260baeb1d9052d3d90ed336bb22d2a95b3f0162d..ce3496d303f80f4e274cc65d01d074d0d0e18c5d 100644 (file)
       <if test="query.search() != null">
         AND (UPPER(groups.name) LIKE #{query.searchSql} ESCAPE '/')
       </if>
+      <choose>
+        <when test="query.membership() == 'IN'">
+          AND groups.permission IS NOT NULL
+        </when>
+        <when test="query.membership() == 'OUT'">
+          AND groups.permission IS NULL
+        </when>
+      </choose>
     </where>
     ORDER BY groups.name
   </select>
     </where>
     ) groups
     <where>
+      <if test="groupName!=null">
+        AND (UPPER(groups.name) LIKE #{groupName} ESCAPE '/')
+      </if>
       <if test="query.search() != null">
         AND (UPPER(groups.name) LIKE #{query.searchSql} ESCAPE '/')
       </if>
+      <choose>
+        <when test="query.membership() == 'IN'">
+          AND groups.permission IS NOT NULL
+        </when>
+        <when test="query.membership() == 'OUT'">
+          AND groups.permission IS NULL
+        </when>
+      </choose>
     </where>
   </select>
 
index 2d9a4f1154c4e48e1d998a63b6a8f45c429ebcc4..8f07391bf7b27f42407061e700c1ae08eb5105c6 100644 (file)
@@ -19,6 +19,8 @@
  */
 package org.sonar.api.security;
 
+import javax.annotation.Nullable;
+
 /**
  * Name of the default user groups
  *
@@ -32,7 +34,7 @@ public final class DefaultGroups {
   public static final String ADMINISTRATORS = "sonar-administrators";
   public static final String USERS = "sonar-users";
 
-  public static boolean isAnyone(String groupName) {
+  public static boolean isAnyone(@Nullable String groupName) {
     return ANYONE.equalsIgnoreCase(groupName);
   }
 }