Skip to content

Commit

Permalink
SONAR-11271 Add application and portfolio creator to sonar-administra…
Browse files Browse the repository at this point in the history
…tors group
  • Loading branch information
ehartmann authored and SonarTech committed Oct 10, 2018
1 parent d989b18 commit 924ce60
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ INSERT INTO GROUP_ROLES(ID, ORGANIZATION_UUID, GROUP_ID, RESOURCE_ID, ROLE) VALU
INSERT INTO GROUP_ROLES(ID, ORGANIZATION_UUID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (4, 'AVdqnciQUUs7Zd3KPvFD', null, null, 'scan');
INSERT INTO GROUP_ROLES(ID, ORGANIZATION_UUID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (5, 'AVdqnciQUUs7Zd3KPvFD', null, null, 'provisioning');
INSERT INTO GROUP_ROLES(ID, ORGANIZATION_UUID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (6, 'AVdqnciQUUs7Zd3KPvFD', 1, null, 'provisioning');
ALTER TABLE GROUP_ROLES ALTER COLUMN ID RESTART WITH 7;
INSERT INTO GROUP_ROLES(ID, ORGANIZATION_UUID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (7, 'AVdqnciQUUs7Zd3KPvFD', 1, null, 'applicationcreator');
INSERT INTO GROUP_ROLES(ID, ORGANIZATION_UUID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (8, 'AVdqnciQUUs7Zd3KPvFD', 1, null, 'portfoliocreator');
ALTER TABLE GROUP_ROLES ALTER COLUMN ID RESTART WITH 9;

INSERT INTO GROUPS_USERS(USER_ID, GROUP_ID) VALUES (1, 1);
INSERT INTO GROUPS_USERS(USER_ID, GROUP_ID) VALUES (1, 2);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* SonarQube
* Copyright (C) 2009-2018 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.platform.db.migration.version.v74;

import java.sql.SQLException;
import org.sonar.api.config.Configuration;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.SupportsBlueGreen;
import org.sonar.server.platform.db.migration.step.DataChange;
import org.sonar.server.platform.db.migration.version.v63.DefaultOrganizationUuidProvider;

@SupportsBlueGreen
public class AddApplicationCreatorAndPortfolioCreatorToSonarAdministrator extends DataChange {

private final Configuration configuration;
private final DefaultOrganizationUuidProvider defaultOrganizationUuidProvider;

public AddApplicationCreatorAndPortfolioCreatorToSonarAdministrator(Database db, Configuration configuration,
DefaultOrganizationUuidProvider defaultOrganizationUuidProvider) {
super(db);
this.configuration = configuration;
this.defaultOrganizationUuidProvider = defaultOrganizationUuidProvider;
}

@Override
protected void execute(Context context) throws SQLException {
if (configuration.getBoolean("sonar.sonarcloud.enabled").orElse(false)) {
// Nothing to do on SonarCloud
return;
}

Integer sonarAdmGroupId = context.prepareSelect("select ID from GROUPS where name=?")
.setString(1, "sonar-administrators")
.get(r -> r.getInt(1));

if (sonarAdmGroupId == null) {
// We cannot find the default sonar-administrators groups
return;
}

insertPermissionIfMissing(context, sonarAdmGroupId, "applicationcreator");
insertPermissionIfMissing(context, sonarAdmGroupId, "portfoliocreator");
}

private void insertPermissionIfMissing(Context context, Integer sonarAdmGroupId, String role) throws SQLException {
if (isPermissionMissing(context, sonarAdmGroupId, role)) {
context.prepareUpsert("insert into GROUP_ROLES(ORGANIZATION_UUID, GROUP_ID, ROLE) values(?, ?, ?)")
.setString(1, defaultOrganizationUuidProvider.get(context))
.setInt(2, sonarAdmGroupId)
.setString(3, role)
.execute()
.commit();
}
}

private static boolean isPermissionMissing(Context context, Integer sonarAdmGroupId, String role) throws SQLException {
Integer count = context.prepareSelect("select count(ID) from GROUP_ROLES where GROUP_ID=? and ROLE=?")
.setInt(1, sonarAdmGroupId)
.setString(2, role)
.get(r -> r.getInt(1));

return count == null || count == 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ public void addSteps(MigrationStepRegistry registry) {
.add(2324, "Create new creator permissions for applications and portfolios", CreateApplicationsAndPortfoliosCreatorPermissions.class)
.add(2325, "Add default templates for applications and portfolios", AddDefaultPermTemplateColumnsToOrganizations.class)
.add(2326, "Create new creator permissions for applications and portfolios", CreateApplicationsAndPortfoliosCreatorPermissions.class)
.add(2327, "Add default templates for applications and portfolios", AddDefaultPermTemplateColumnsToOrganizations.class)
.add(2328, "Populate default template permissions on organizations", PopulateDefaultPermTemplateOnOrganizations.class)
.add(2327, "Populate default template permissions on organizations", PopulateDefaultPermTemplateOnOrganizations.class)
.add(2328, "Add portfolio and application creator permissions on sonar-administrators group", AddApplicationCreatorAndPortfolioCreatorToSonarAdministrator.class)
;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* SonarQube
* Copyright (C) 2009-2018 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.platform.db.migration.version.v74;

import java.sql.SQLException;
import java.util.Date;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.assertj.core.groups.Tuple;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.core.util.UuidFactoryFast;
import org.sonar.db.CoreDbTester;
import org.sonar.server.platform.db.migration.version.v63.DefaultOrganizationUuidProvider;
import org.sonar.server.platform.db.migration.version.v63.DefaultOrganizationUuidProviderImpl;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;

public class AddApplicationCreatorAndPortfolioCreatorToSonarAdministratorTest {

@Rule
public CoreDbTester db = CoreDbTester.createForSchema(AddApplicationCreatorAndPortfolioCreatorToSonarAdministratorTest.class,
"group_roles_and_internal_properties.sql");

private UuidFactoryFast uuidFactoryFast = UuidFactoryFast.getInstance();
private MapSettings settings = new MapSettings();
private DefaultOrganizationUuidProvider defaultOrganizationUuidProvider = new DefaultOrganizationUuidProviderImpl();
private AddApplicationCreatorAndPortfolioCreatorToSonarAdministrator underTest = new AddApplicationCreatorAndPortfolioCreatorToSonarAdministrator(db.database(), settings.asConfig(),
defaultOrganizationUuidProvider);

@Test
public void is_reentrant() throws SQLException {
String orgUuid = uuidFactoryFast.create();
insertDefaultOrganizationUuid(orgUuid);
insertGroup(orgUuid, "sonar-administrators");
Long adminGroupId = getGroupId("sonar-administrators");

underTest.execute();
underTest.execute();

assertGroupRoles(
tuple(orgUuid, adminGroupId, null, "applicationcreator"),
tuple(orgUuid, adminGroupId, null, "portfoliocreator"));
}

@Test
public void create_missing_permissions() throws SQLException {
String orgUuid = uuidFactoryFast.create();
insertDefaultOrganizationUuid(orgUuid);
insertGroup(orgUuid, "sonar-administrators");
Long adminGroupId = getGroupId("sonar-administrators");

underTest.execute();

assertGroupRoles(
tuple(orgUuid, adminGroupId, null, "applicationcreator"),
tuple(orgUuid, adminGroupId, null, "portfoliocreator"));
}

@Test
public void has_no_effect_if_group_does_not_exist() throws SQLException {
String orgUuid = uuidFactoryFast.create();
insertDefaultOrganizationUuid(orgUuid);
insertGroup(orgUuid, "sonar");

underTest.execute();

assertGroupRoles();
}

@Test
public void has_no_effect_if_roles_are_already_present() throws SQLException {
String orgUuid = uuidFactoryFast.create();
insertDefaultOrganizationUuid(orgUuid);
insertGroup(orgUuid, "sonar-administrators");
Long adminGroupId = getGroupId("sonar-administrators");
insertGroupRole(orgUuid, adminGroupId, null, "applicationcreator");
insertGroupRole(orgUuid, adminGroupId, null, "portfoliocreator");

underTest.execute();

assertGroupRoles(
tuple(orgUuid, adminGroupId, null, "applicationcreator"),
tuple(orgUuid, adminGroupId, null, "portfoliocreator"));
}

@Test
public void has_no_effect_on_SonarCloud() throws SQLException {
settings.setProperty("sonar.sonarcloud.enabled", true);
underTest.execute();
assertGroupRoles();
}

private void insertDefaultOrganizationUuid(String uuid) {
db.executeInsert("INTERNAL_PROPERTIES",
"KEE", "organization.default",
"IS_EMPTY", false,
"TEXT_VALUE", uuid,
"CREATED_AT", System.currentTimeMillis());
}

private void insertGroup(String organizationUuid, String name) {
db.executeInsert("GROUPS",
"ORGANIZATION_UUID", organizationUuid,
"NAME", name,
"CREATED_AT", new Date(),
"UPDATED_AT", new Date());
}

private void insertGroupRole(String organizationUuid, @Nullable Long groupId, @Nullable Integer resourceId, String role) {
db.executeInsert("GROUP_ROLES",
"ORGANIZATION_UUID", organizationUuid,
"GROUP_ID", groupId,
"RESOURCE_ID", resourceId,
"ROLE", role);
}

private Long getGroupId(String groupName) {
return (Long) db.selectFirst("SELECT id FROM groups WHERE name = '" + groupName + "'").get("ID");
}

private void assertGroupRoles(Tuple... expectedTuples) {
assertThat(db.select("SELECT organization_uuid, group_id, resource_id, role FROM group_roles")
.stream()
.map(row -> new Tuple(row.get("ORGANIZATION_UUID"), row.get("GROUP_ID"), row.get("RESOURCE_ID"), row.get("ROLE")))
.collect(Collectors.toList()))
.containsExactlyInAnyOrder(expectedTuples);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
CREATE TABLE "PROPERTIES" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
"PROP_KEY" VARCHAR(512),
"RESOURCE_ID" INTEGER,
"TEXT_VALUE" CLOB(2147483647),
"USER_ID" INTEGER
);

CREATE TABLE "INTERNAL_PROPERTIES" (
"KEE" VARCHAR(50) NOT NULL PRIMARY KEY,
"IS_EMPTY" BOOLEAN NOT NULL,
"TEXT_VALUE" VARCHAR(4000),
"CLOB_VALUE" CLOB,
"CREATED_AT" BIGINT
);

CREATE UNIQUE INDEX "UNIQ_INTERNAL_PROPERTIES" ON "INTERNAL_PROPERTIES" ("KEE");

CREATE TABLE "GROUPS" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
"ORGANIZATION_UUID" VARCHAR(40) NOT NULL,
"NAME" VARCHAR(500),
"DESCRIPTION" VARCHAR(200),
"CREATED_AT" TIMESTAMP,
"UPDATED_AT" TIMESTAMP
);

CREATE TABLE "GROUP_ROLES" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
"ORGANIZATION_UUID" VARCHAR(40) NOT NULL,
"GROUP_ID" INTEGER,
"RESOURCE_ID" INTEGER,
"ROLE" VARCHAR(64) NOT NULL
);
CREATE INDEX "GROUP_ROLES_RESOURCE" ON "GROUP_ROLES" ("RESOURCE_ID");
CREATE UNIQUE INDEX "UNIQ_GROUP_ROLES" ON "GROUP_ROLES" ("ORGANIZATION_UUID", "GROUP_ID", "RESOURCE_ID", "ROLE");

0 comments on commit 924ce60

Please sign in to comment.