From e916d491bc40a67fcf069df20f4deb70da1a42bf Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Fri, 18 Mar 2016 17:53:30 +0100 Subject: [PATCH] SONAR-6732 ensure properties in DB are never altered from CE --- .../container/ComputeEngineContainerImpl.java | 11 +- .../main/java/org/sonar/ce/db/CeDbClient.java | 45 +++++ .../sonar/ce/db/ReadOnlyPropertiesDao.java | 117 +++++++++++++ .../java/org/sonar/ce/db/package-info.java | 23 +++ .../ComputeEngineContainerImplTest.java | 2 +- .../java/org/sonar/ce/db/CeDbClientTest.java | 42 +++++ .../ce/db/ReadOnlyPropertiesDaoTest.java | 158 ++++++++++++++++++ 7 files changed, 394 insertions(+), 4 deletions(-) create mode 100644 server/sonar-ce/src/main/java/org/sonar/ce/db/CeDbClient.java create mode 100644 server/sonar-ce/src/main/java/org/sonar/ce/db/ReadOnlyPropertiesDao.java create mode 100644 server/sonar-ce/src/main/java/org/sonar/ce/db/package-info.java create mode 100644 server/sonar-ce/src/test/java/org/sonar/ce/db/CeDbClientTest.java create mode 100644 server/sonar-ce/src/test/java/org/sonar/ce/db/ReadOnlyPropertiesDaoTest.java diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java index ef74282206f..7354d63978c 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java @@ -35,6 +35,8 @@ import org.sonar.api.server.rule.RulesDefinitionXmlLoader; import org.sonar.api.utils.Durations; import org.sonar.api.utils.System2; import org.sonar.api.utils.UriReader; +import org.sonar.ce.db.CeDbClient; +import org.sonar.ce.db.ReadOnlyPropertiesDao; import org.sonar.ce.es.EsIndexerEnabler; import org.sonar.ce.property.CePropertyDefinitions; import org.sonar.ce.settings.ComputeEngineSettings; @@ -54,7 +56,6 @@ import org.sonar.core.user.DeprecatedUserFinder; import org.sonar.core.util.UuidFactoryImpl; import org.sonar.db.DaoModule; import org.sonar.db.DatabaseChecker; -import org.sonar.db.DbClient; import org.sonar.db.DefaultDatabase; import org.sonar.db.permission.PermissionRepository; import org.sonar.db.purge.PurgeProfiler; @@ -159,8 +160,10 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer { CeUserSession.class, // DB - DbClient.class, DaoModule.class, + // DbClient.class, replaced by CeDbClient to use ReadOnlyPropertiesDao instead of PropertiesDao + ReadOnlyPropertiesDao.class, + CeDbClient.class, // MigrationStepModule.class, DB maintenance, responsibility of Web Server // Elasticsearch @@ -174,9 +177,11 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer { IssueIndex.class, // Classes kept for backward compatibility of plugins/libs (like sonar-license) that are directly calling classes from the core - org.sonar.core.properties.PropertiesDao.class + // org.sonar.core.properties.PropertiesDao.class, replaced by ReadOnlyPropertiesDao (declared above) which is a ReadOnly implementation }; private static final Object[] LEVEL_2_COMPONENTS = new Object[] { + // add ReadOnlyPropertiesDao at level2 again so that it shadows PropertiesDao + ReadOnlyPropertiesDao.class, DefaultServerUpgradeStatus.class, // no DatabaseMigrator.class, responsibility of Web Server diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/db/CeDbClient.java b/server/sonar-ce/src/main/java/org/sonar/ce/db/CeDbClient.java new file mode 100644 index 00000000000..6cf67f8f009 --- /dev/null +++ b/server/sonar-ce/src/main/java/org/sonar/ce/db/CeDbClient.java @@ -0,0 +1,45 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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.ce.db; + +import java.util.Map; +import org.sonar.db.Dao; +import org.sonar.db.Database; +import org.sonar.db.DbClient; +import org.sonar.db.MyBatis; +import org.sonar.db.property.PropertiesDao; + +public class CeDbClient extends DbClient { + private ReadOnlyPropertiesDao readOnlyPropertiesDao; + + public CeDbClient(Database database, MyBatis myBatis, Dao... daos) { + super(database, myBatis, daos); + } + + @Override + protected void doOnLoad(Map daoByClass) { + this.readOnlyPropertiesDao = getDao(daoByClass, ReadOnlyPropertiesDao.class); + } + + @Override + public PropertiesDao propertiesDao() { + return this.readOnlyPropertiesDao; + } +} diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/db/ReadOnlyPropertiesDao.java b/server/sonar-ce/src/main/java/org/sonar/ce/db/ReadOnlyPropertiesDao.java new file mode 100644 index 00000000000..373ae90e168 --- /dev/null +++ b/server/sonar-ce/src/main/java/org/sonar/ce/db/ReadOnlyPropertiesDao.java @@ -0,0 +1,117 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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.ce.db; + +import java.util.Map; +import org.sonar.core.properties.PropertiesDao; +import org.sonar.db.DbSession; +import org.sonar.db.MyBatis; +import org.sonar.db.property.PropertyDto; + +/** + * Compute Engine specific override of {@link PropertiesDao} and {@link org.sonar.db.property.PropertiesDao} which + * implements no write method (ie. insert/update/delete) because updating the Properties is the Web Server responsibility + * alone. + *

+ * This ugly trick is required because licensed plugin bundle {@link com.sonarsource.license.api.internal.ServerLicenseVerifierImpl} + * which update license properties by calling {@link PropertiesDao} directly and this can not be disabled. + *

+ */ +public class ReadOnlyPropertiesDao extends PropertiesDao { + public ReadOnlyPropertiesDao(MyBatis mybatis) { + super(mybatis); + } + + @Override + public void insertProperty(DbSession session, PropertyDto property) { + // do nothing + } + + @Override + public void insertProperty(PropertyDto property) { + // do nothing + } + + @Override + public void deleteProjectProperty(String key, Long projectId) { + // do nothing + } + + @Override + public void deleteProjectProperty(String key, Long projectId, DbSession session) { + // do nothing + } + + @Override + public void deleteProjectProperties(String key, String value, DbSession session) { + // do nothing + } + + @Override + public void deleteProjectProperties(String key, String value) { + // do nothing + } + + @Override + public void deleteGlobalProperties() { + // do nothing + } + + @Override + public void deleteGlobalProperty(String key, DbSession session) { + // do nothing + } + + @Override + public void deleteGlobalProperty(String key) { + // do nothing + } + + @Override + public void deleteAllProperties(String key) { + // do nothing + } + + @Override + public void insertGlobalProperties(Map properties) { + // do nothing + } + + @Override + public void renamePropertyKey(String oldKey, String newKey) { + // do nothing + } + + @Override + public void updateProperties(String key, String oldValue, String newValue) { + // do nothing + } + + @Override + public void updateProperties(String key, String oldValue, String newValue, DbSession session) { + // do nothing + } + + @Override + public void setProperty(org.sonar.core.properties.PropertyDto property) { + // do nothing + } + +} diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/db/package-info.java b/server/sonar-ce/src/main/java/org/sonar/ce/db/package-info.java new file mode 100644 index 00000000000..74cebb0c907 --- /dev/null +++ b/server/sonar-ce/src/main/java/org/sonar/ce/db/package-info.java @@ -0,0 +1,23 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.ce.db; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java index b0075cd6677..6e9e5dbc679 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java @@ -89,7 +89,7 @@ public class ComputeEngineContainerImplTest { ); assertThat(picoContainer.getParent().getParent().getComponentAdapters()).hasSize( CONTAINER_ITSELF - + 10 // level 2 + + 11 // level 2 ); assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize( COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/db/CeDbClientTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/db/CeDbClientTest.java new file mode 100644 index 00000000000..883247ab312 --- /dev/null +++ b/server/sonar-ce/src/test/java/org/sonar/ce/db/CeDbClientTest.java @@ -0,0 +1,42 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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.ce.db; + +import org.junit.Test; +import org.sonar.db.Dao; +import org.sonar.db.Database; +import org.sonar.db.DbClient; +import org.sonar.db.MyBatis; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class CeDbClientTest { + private Database database = mock(Database.class); + private MyBatis myBatis = mock(MyBatis.class); + private ReadOnlyPropertiesDao readOnlyPropertiesDao = new ReadOnlyPropertiesDao(myBatis); + + private DbClient underTest = new CeDbClient(database, myBatis, (Dao) readOnlyPropertiesDao); + + @Test + public void getPropertiesDao_returns_ReadOnlyPropertiesDao() { + assertThat(underTest.propertiesDao()).isSameAs(readOnlyPropertiesDao); + } +} diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/db/ReadOnlyPropertiesDaoTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/db/ReadOnlyPropertiesDaoTest.java new file mode 100644 index 00000000000..bcb0549bc18 --- /dev/null +++ b/server/sonar-ce/src/test/java/org/sonar/ce/db/ReadOnlyPropertiesDaoTest.java @@ -0,0 +1,158 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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.ce.db; + +import org.junit.Test; +import org.sonar.db.DbSession; +import org.sonar.db.MyBatis; +import org.sonar.db.property.PropertyDto; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +public class ReadOnlyPropertiesDaoTest { + private MyBatis myBatis = mock(MyBatis.class); + private DbSession dbSession = mock(DbSession.class); + private PropertyDto propertyDto = mock(PropertyDto.class); + private org.sonar.core.properties.PropertyDto oldPropertyDto = mock(org.sonar.core.properties.PropertyDto.class); + private ReadOnlyPropertiesDao underTest = new ReadOnlyPropertiesDao(myBatis); + + @Test + public void insertProperty() { + underTest.insertProperty(dbSession, propertyDto); + + assertNoInteraction(); + } + + @Test + public void insertProperty1() { + underTest.insertProperty(propertyDto); + + assertNoInteraction(); + } + + @Test + public void deleteProjectProperty() { + underTest.deleteProjectProperty(null, null); + + assertNoInteraction(); + + } + + @Test + public void deleteProjectProperty1() { + underTest.deleteProjectProperty(null, null, dbSession); + + assertNoInteraction(); + + } + + @Test + public void deleteProjectProperties() { + underTest.deleteProjectProperties(null, null); + + assertNoInteraction(); + + } + + @Test + public void deleteProjectProperties1() { + underTest.deleteProjectProperties(null, null, dbSession); + + assertNoInteraction(); + + } + + @Test + public void deleteGlobalProperties() { + underTest.deleteGlobalProperties(); + + assertNoInteraction(); + + } + + @Test + public void deleteGlobalProperty() { + underTest.deleteGlobalProperty(null); + + assertNoInteraction(); + + } + + @Test + public void deleteGlobalProperty1() { + underTest.deleteGlobalProperty(null, dbSession); + + assertNoInteraction(); + + } + + @Test + public void deleteAllProperties() { + underTest.deleteAllProperties(null); + + assertNoInteraction(); + + } + + @Test + public void insertGlobalProperties() { + underTest.insertGlobalProperties(null); + + assertNoInteraction(); + + } + + @Test + public void renamePropertyKey() { + underTest.renamePropertyKey(null, null); + + assertNoInteraction(); + + } + + @Test + public void updateProperties() { + underTest.updateProperties(null, null, null); + + assertNoInteraction(); + + } + + @Test + public void updateProperties1() { + underTest.updateProperties(null, null, null, dbSession); + + assertNoInteraction(); + + } + + @Test + public void setProperty() { + underTest.setProperty(oldPropertyDto); + + assertNoInteraction(); + + } + + private void assertNoInteraction() { + verifyNoMoreInteractions(myBatis, dbSession, propertyDto); + } +} -- 2.39.5