This is an automated email from the ASF dual-hosted git repository.

jmckenzie pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 6bd373f5d2 Add guardrail to disallow TRUNCATE and DROP TABLE commands
6bd373f5d2 is described below

commit 6bd373f5d27754f80384caa31d1b2a4cfc43bc19
Author: Josh McKenzie <jmcken...@apache.org>
AuthorDate: Mon Apr 18 14:53:17 2022 -0400

    Add guardrail to disallow TRUNCATE and DROP TABLE commands
    
    Patch by Josh McKenzie; reviewed by Aleksey Yeschenko for CASSANDRA-17558
---
 CHANGES.txt                                        |  1 +
 conf/cassandra.yaml                                |  2 +
 src/java/org/apache/cassandra/config/Config.java   |  1 +
 .../apache/cassandra/config/GuardrailsOptions.java | 14 ++++
 .../cql3/statements/TruncateStatement.java         |  2 +
 .../cql3/statements/schema/DropTableStatement.java |  3 +
 .../apache/cassandra/db/guardrails/Guardrails.java | 17 ++++
 .../cassandra/db/guardrails/GuardrailsConfig.java  |  7 ++
 .../cassandra/db/guardrails/GuardrailsMBean.java   | 12 +++
 .../db/guardrails/GuardrailTruncateDropTest.java   | 91 ++++++++++++++++++++++
 10 files changed, 150 insertions(+)

diff --git a/CHANGES.txt b/CHANGES.txt
index 7850ca8e5b..8a4e661719 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 4.1
+ * Add guardrail to disallow TRUNCATE and DROP TABLE commands (CASSANDRA-17558)
  * Add plugin support for CQLSH (CASSANDRA-16456)
  * Add guardrail to disallow querying with ALLOW FILTERING (CASSANDRA-17370)
  * Enhance SnakeYAML properties to be reusable outside of YAML parsing, 
support camel case conversion to snake case, and add support to ignore 
properties (CASSANDRA-17166)
diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml
index f6f0a3ccad..c3e183fbd3 100644
--- a/conf/cassandra.yaml
+++ b/conf/cassandra.yaml
@@ -1626,6 +1626,8 @@ drop_compact_storage_enabled: false
 # user_timestamps_enabled: true
 # Guardrail to allow/disallow GROUP BY functionality.
 # group_by_enabled: true
+# Guardrail to allow/disallow TRUNCATE and DROP statements
+# truncate_drop_enabled: true
 # Guardrail to warn or fail when using a page size greater than threshold.
 # The two thresholds default to -1 to disable.
 # page_size_warn_threshold: -1
diff --git a/src/java/org/apache/cassandra/config/Config.java 
b/src/java/org/apache/cassandra/config/Config.java
index a3d6348fa1..1c277cf0c7 100644
--- a/src/java/org/apache/cassandra/config/Config.java
+++ b/src/java/org/apache/cassandra/config/Config.java
@@ -808,6 +808,7 @@ public class Config
     public volatile Set<ConsistencyLevel> write_consistency_levels_disallowed 
= Collections.emptySet();
     public volatile boolean user_timestamps_enabled = true;
     public volatile boolean group_by_enabled = true;
+    public volatile boolean truncate_drop_enabled = true;
     public volatile boolean secondary_indexes_enabled = true;
     public volatile boolean uncompressed_tables_enabled = true;
     public volatile boolean compact_tables_enabled = true;
diff --git a/src/java/org/apache/cassandra/config/GuardrailsOptions.java 
b/src/java/org/apache/cassandra/config/GuardrailsOptions.java
index d32f3b1bc6..6654b4fc74 100644
--- a/src/java/org/apache/cassandra/config/GuardrailsOptions.java
+++ b/src/java/org/apache/cassandra/config/GuardrailsOptions.java
@@ -329,6 +329,20 @@ public class GuardrailsOptions implements GuardrailsConfig
                                   x -> config.group_by_enabled = x);
     }
 
+    @Override
+    public boolean getTruncateDropEnabled()
+    {
+        return config.truncate_drop_enabled;
+    }
+
+    public void setTruncateDropEnabled(boolean enabled)
+    {
+        updatePropertyWithLogging("truncate_drop_enabled",
+                                  enabled,
+                                  () -> config.truncate_drop_enabled,
+                                  x -> config.truncate_drop_enabled = x);
+    }
+
     @Override
     public boolean getSecondaryIndexesEnabled()
     {
diff --git 
a/src/java/org/apache/cassandra/cql3/statements/TruncateStatement.java 
b/src/java/org/apache/cassandra/cql3/statements/TruncateStatement.java
index 2c1c9941ce..bdd4c7b870 100644
--- a/src/java/org/apache/cassandra/cql3/statements/TruncateStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/TruncateStatement.java
@@ -25,6 +25,7 @@ import org.apache.cassandra.auth.Permission;
 import org.apache.cassandra.cql3.*;
 import org.apache.cassandra.db.ColumnFamilyStore;
 import org.apache.cassandra.db.Keyspace;
+import org.apache.cassandra.db.guardrails.Guardrails;
 import org.apache.cassandra.db.virtual.VirtualKeyspaceRegistry;
 import org.apache.cassandra.exceptions.*;
 import org.apache.cassandra.schema.Schema;
@@ -57,6 +58,7 @@ public class TruncateStatement extends QualifiedStatement 
implements CQLStatemen
     public void validate(ClientState state) throws InvalidRequestException
     {
         Schema.instance.validateTable(keyspace(), name());
+        Guardrails.truncateDropEnabled.ensureEnabled(state);
     }
 
     public ResultMessage execute(QueryState state, QueryOptions options, long 
queryStartNanoTime) throws InvalidRequestException, TruncateException
diff --git 
a/src/java/org/apache/cassandra/cql3/statements/schema/DropTableStatement.java 
b/src/java/org/apache/cassandra/cql3/statements/schema/DropTableStatement.java
index 15c2a03a3a..371b957845 100644
--- 
a/src/java/org/apache/cassandra/cql3/statements/schema/DropTableStatement.java
+++ 
b/src/java/org/apache/cassandra/cql3/statements/schema/DropTableStatement.java
@@ -22,6 +22,7 @@ import org.apache.cassandra.audit.AuditLogEntryType;
 import org.apache.cassandra.auth.Permission;
 import org.apache.cassandra.cql3.CQLStatement;
 import org.apache.cassandra.cql3.QualifiedName;
+import org.apache.cassandra.db.guardrails.Guardrails;
 import org.apache.cassandra.schema.*;
 import org.apache.cassandra.schema.Keyspaces.KeyspacesDiff;
 import org.apache.cassandra.service.ClientState;
@@ -48,6 +49,8 @@ public final class DropTableStatement extends 
AlterSchemaStatement
 
     public Keyspaces apply(Keyspaces schema)
     {
+        Guardrails.truncateDropEnabled.ensureEnabled(state);
+
         KeyspaceMetadata keyspace = schema.getNullable(keyspaceName);
 
         TableMetadata table = null == keyspace
diff --git a/src/java/org/apache/cassandra/db/guardrails/Guardrails.java 
b/src/java/org/apache/cassandra/db/guardrails/Guardrails.java
index 8451aff8f3..3578ceb1ec 100644
--- a/src/java/org/apache/cassandra/db/guardrails/Guardrails.java
+++ b/src/java/org/apache/cassandra/db/guardrails/Guardrails.java
@@ -145,6 +145,11 @@ public final class Guardrails implements GuardrailsMBean
                     state -> 
!CONFIG_PROVIDER.getOrCreate(state).getGroupByEnabled(),
                     "GROUP BY functionality");
 
+    public static final DisableFlag truncateDropEnabled =
+    new DisableFlag("truncate_drop",
+                    state -> 
!CONFIG_PROVIDER.getOrCreate(state).getTruncateDropEnabled(),
+                    "TRUNCATE and DROP TABLE functionality");
+
     /**
      * Guardrail disabling user's ability to turn off compression
      */
@@ -569,6 +574,18 @@ public final class Guardrails implements GuardrailsMBean
         DEFAULT_CONFIG.setGroupByEnabled(enabled);
     }
 
+    @Override
+    public boolean getTruncateDropEnabled()
+    {
+        return DEFAULT_CONFIG.getTruncateDropEnabled();
+    }
+
+    @Override
+    public void setTruncateDropEnabled(boolean enabled)
+    {
+        DEFAULT_CONFIG.setTruncateDropEnabled(enabled);
+    }
+
     @Override
     public int getPageSizeWarnThreshold()
     {
diff --git a/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java 
b/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java
index 6dbc0bb91e..cb2bd313b9 100644
--- a/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java
+++ b/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java
@@ -153,6 +153,13 @@ public interface GuardrailsConfig
      */
     boolean getGroupByEnabled();
 
+    /**
+     * Returns whether TRUNCATE or DROP table are allowed
+     *
+     * @return {@code true} if allowed, {@code false} otherwise.
+     */
+    boolean getTruncateDropEnabled();
+
     /**
      * @return The threshold to warn when page size exceeds given size.
      */
diff --git a/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java 
b/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java
index 3d94410f4e..0240f430a4 100644
--- a/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java
+++ b/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java
@@ -264,6 +264,18 @@ public interface GuardrailsMBean
      */
     void setGroupByEnabled(boolean enabled);
 
+    /**
+     * Returns whether users can TRUNCATE or DROP TABLE
+     *
+     * @return {@code true} if allowed, {@code false} otherwise.
+     */
+    boolean getTruncateDropEnabled();
+
+    /**
+     * Sets whether users can TRUNCATE or DROP TABLE
+     */
+    void setTruncateDropEnabled(boolean enabled);
+
     /**
      * @return The threshold to warn when requested page size greater than 
threshold.
      * -1 means disabled.
diff --git 
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailTruncateDropTest.java 
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailTruncateDropTest.java
new file mode 100644
index 0000000000..a3264fa4fe
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailTruncateDropTest.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.db.guardrails;
+
+import org.junit.After;
+import org.junit.Test;
+
+import static java.lang.String.format;
+
+public class GuardrailTruncateDropTest extends GuardrailTester
+{
+    private String tableQuery = "CREATE TABLE %s(pk int, ck int, v int, 
PRIMARY KEY(pk, ck))";
+
+    private void setGuardrail(boolean enabled)
+    {
+        Guardrails.instance.setTruncateDropEnabled(enabled);
+    }
+
+    @After
+    public void afterTest()
+    {
+        setGuardrail(true);
+    }
+
+    @Test
+    public void testCanDropWhileFeatureEnabled() throws Throwable
+    {
+        setGuardrail(true);
+        createTable(tableQuery);
+        assertValid(String.format("DROP TABLE %s", currentTable()));
+    }
+
+    @Test
+    public void testCannotDropWhileFeatureDisabled() throws Throwable
+    {
+        setGuardrail(false);
+        createTable(tableQuery);
+        assertFails("DROP TABLE %s", "TRUNCATE and DROP TABLE functionality is 
not allowed");
+    }
+
+    @Test
+    public void testIfExistsDoesNotBreakGuardrail() throws Throwable
+    {
+        setGuardrail(false);
+        createTable(tableQuery);
+        assertFails("DROP TABLE IF EXISTS %s", "TRUNCATE and DROP TABLE 
functionality is not allowed");
+    }
+
+    @Test
+    public void testCanTruncateWhileFeatureEnabled() throws Throwable
+    {
+        setGuardrail(true);
+        createTable(tableQuery);
+        assertValid(String.format("TRUNCATE TABLE %s", currentTable()));
+    }
+
+    @Test
+    public void testCannotTruncateWhileFeatureDisabled() throws Throwable
+    {
+        setGuardrail(false);
+        createTable(tableQuery);
+        assertFails("TRUNCATE TABLE %s", "TRUNCATE and DROP TABLE 
functionality is not allowed");
+    }
+
+    @Test
+    public void testExcludedUsersCanAlwaysDropAndTruncate() throws Throwable
+    {
+        String table = keyspace() + '.' + createTableName();
+        setGuardrail(false);
+        testExcludedUsers(() -> format("CREATE TABLE %s (k int PRIMARY KEY, v1 
int, v2 int, v3 int, v4 int)", table),
+                          () -> format("TRUNCATE TABLE %s", table),
+                          () -> format("DROP TABLE %s", table));
+
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to