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

adelapena 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 f444c40286 Add guardrail to disallow querying with ALLOW FILTERING
f444c40286 is described below

commit f444c4028680c78b6167161833d6564c3557618f
Author: Savni  Nagarkar <[email protected]>
AuthorDate: Thu Feb 17 13:29:58 2022 -0600

    Add guardrail to disallow querying with ALLOW FILTERING
    
    patch by Savni Nagarkar; reviewed by Andres de la Peña, David Capwell and 
Josh McKenzie for CASSANDRA-17370
---
 CHANGES.txt                                        |  1 +
 NEWS.txt                                           |  1 +
 conf/cassandra.yaml                                |  2 +
 src/java/org/apache/cassandra/config/Config.java   |  1 +
 .../apache/cassandra/config/GuardrailsOptions.java | 14 ++++
 .../cassandra/cql3/statements/SelectStatement.java |  4 +-
 .../apache/cassandra/db/guardrails/Guardrails.java | 20 +++++
 .../cassandra/db/guardrails/GuardrailsConfig.java  |  7 ++
 .../cassandra/db/guardrails/GuardrailsMBean.java   | 14 ++++
 .../db/guardrails/GuardrailAllowFilteringTest.java | 94 ++++++++++++++++++++++
 10 files changed, 157 insertions(+), 1 deletion(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 9410f075bc..4ae12a7c97 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 4.1
+ * 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)
  * nodetool compact should support using a key string to find the range to 
avoid operators having to manually do this (CASSANDRA-17537)
  * Add guardrail for data disk usage (CASSANDRA-17150)
diff --git a/NEWS.txt b/NEWS.txt
index 72c95e00c4..97bfd331c4 100644
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -84,6 +84,7 @@ New features
         - Whether GROUP BY queries are allowed.
         - Whether the creation of secondary indexes is allowed.
         - Whether the creation of uncompressed tables is allowed.
+        - Whether querying with ALLOW FILTERING is allowed.
     - Add support for the use of pure monotonic functions on the last 
attribute of the GROUP BY clause.
     - Add floor functions that can be use to group by time range.
     - Support for native transport rate limiting via 
native_transport_rate_limiting_enabled and 
diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml
index b28f4388f5..f6f0a3ccad 100644
--- a/conf/cassandra.yaml
+++ b/conf/cassandra.yaml
@@ -1664,6 +1664,8 @@ drop_compact_storage_enabled: false
 # The two thresholds default to -1 to disable.
 # items_per_collection_warn_threshold: -1
 # items_per_collection_fail_threshold: -1
+# Guardrail to allow/disallow querying with ALLOW FILTERING. Defaults to true.
+# allow_filtering_enabled: true
 # Guardrail to warn or fail when creating a user-defined-type with more fields 
in than threshold.
 # Default -1 to disable.
 # fields_per_udt_warn_threshold: -1
diff --git a/src/java/org/apache/cassandra/config/Config.java 
b/src/java/org/apache/cassandra/config/Config.java
index 2f339418b1..a3d6348fa1 100644
--- a/src/java/org/apache/cassandra/config/Config.java
+++ b/src/java/org/apache/cassandra/config/Config.java
@@ -812,6 +812,7 @@ public class Config
     public volatile boolean uncompressed_tables_enabled = true;
     public volatile boolean compact_tables_enabled = true;
     public volatile boolean read_before_write_list_operations_enabled = true;
+    public volatile boolean allow_filtering_enabled = true;
     public volatile DataStorageSpec collection_size_warn_threshold = null;
     public volatile DataStorageSpec collection_size_fail_threshold = null;
     public volatile int items_per_collection_warn_threshold = -1;
diff --git a/src/java/org/apache/cassandra/config/GuardrailsOptions.java 
b/src/java/org/apache/cassandra/config/GuardrailsOptions.java
index 160906353e..d32f3b1bc6 100644
--- a/src/java/org/apache/cassandra/config/GuardrailsOptions.java
+++ b/src/java/org/apache/cassandra/config/GuardrailsOptions.java
@@ -385,6 +385,20 @@ public class GuardrailsOptions implements GuardrailsConfig
                                   x -> 
config.read_before_write_list_operations_enabled = x);
     }
 
+    @Override
+    public boolean getAllowFilteringEnabled()
+    {
+        return config.allow_filtering_enabled;
+    }
+
+    public void setAllowFilteringEnabled(boolean enabled)
+    {
+        updatePropertyWithLogging("allow_filtering_enabled",
+                                  enabled,
+                                  () -> config.allow_filtering_enabled,
+                                  x -> config.allow_filtering_enabled = x);
+    }
+
     @Override
     public int getInSelectCartesianProductWarnThreshold()
     {
diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java 
b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
index b27266ce7e..030b4cd785 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@ -35,6 +35,7 @@ import org.apache.cassandra.auth.Permission;
 import org.apache.cassandra.db.guardrails.Guardrails;
 import org.apache.cassandra.schema.ColumnMetadata;
 import org.apache.cassandra.schema.Schema;
+import org.apache.cassandra.schema.SchemaConstants;
 import org.apache.cassandra.schema.TableMetadata;
 import org.apache.cassandra.schema.TableMetadataRef;
 import org.apache.cassandra.cql3.*;
@@ -238,7 +239,8 @@ public class SelectStatement implements 
CQLStatement.SingleKeyspaceCqlStatement
 
     public void validate(ClientState state) throws InvalidRequestException
     {
-        // Nothing to do, all validation has been done by 
RawStatement.prepare()
+        if (parameters.allowFiltering && 
!SchemaConstants.isSystemKeyspace(table.keyspace))
+            Guardrails.allowFilteringEnabled.ensureEnabled(state);
     }
 
     public ResultMessage.Rows execute(QueryState state, QueryOptions options, 
long queryStartNanoTime)
diff --git a/src/java/org/apache/cassandra/db/guardrails/Guardrails.java 
b/src/java/org/apache/cassandra/db/guardrails/Guardrails.java
index d7ec81e83b..8451aff8f3 100644
--- a/src/java/org/apache/cassandra/db/guardrails/Guardrails.java
+++ b/src/java/org/apache/cassandra/db/guardrails/Guardrails.java
@@ -197,6 +197,14 @@ public final class Guardrails implements GuardrailsMBean
                     state -> 
!CONFIG_PROVIDER.getOrCreate(state).getReadBeforeWriteListOperationsEnabled(),
                     "List operation requiring read before write");
 
+    /**
+     * Guardrail disabling ALLOW FILTERING statement within a query
+     */
+    public static final DisableFlag allowFilteringEnabled =
+    new DisableFlag("allow_filtering",
+                    state -> 
!CONFIG_PROVIDER.getOrCreate(state).getAllowFilteringEnabled(),
+                    "Querying with ALLOW FILTERING");
+
     /**
      * Guardrail on the number of restrictions created by a cartesian product 
of a CQL's {@code IN} query.
      */
@@ -513,6 +521,18 @@ public final class Guardrails implements GuardrailsMBean
         DEFAULT_CONFIG.setUserTimestampsEnabled(enabled);
     }
 
+    @Override
+    public boolean getAllowFilteringEnabled()
+    {
+        return DEFAULT_CONFIG.getAllowFilteringEnabled();
+    }
+
+    @Override
+    public void setAllowFilteringEnabled(boolean enabled)
+    {
+        DEFAULT_CONFIG.setAllowFilteringEnabled(enabled);
+    }
+
     @Override
     public boolean getUncompressedTablesEnabled()
     {
diff --git a/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java 
b/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java
index 562509b7dd..6dbc0bb91e 100644
--- a/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java
+++ b/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java
@@ -170,6 +170,13 @@ public interface GuardrailsConfig
      */
     boolean getReadBeforeWriteListOperationsEnabled();
 
+    /**
+     * Returns whether ALLOW FILTERING property is allowed.
+     *
+     * @return {@code true} if ALLOW FILTERING is allowed, {@code false} 
otherwise.
+     */
+    boolean getAllowFilteringEnabled();
+
     /**
      * @return The threshold to warn when an IN query creates a cartesian 
product with a size exceeding threshold.
      * -1 means disabled.
diff --git a/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java 
b/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java
index 215b953b89..3d94410f4e 100644
--- a/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java
+++ b/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java
@@ -208,6 +208,20 @@ public interface GuardrailsMBean
      */
     void setUserTimestampsEnabled(boolean enabled);
 
+    /**
+     * Returns whether ALLOW FILTERING property is allowed.
+     *
+     * @return {@code true} if ALLOW FILTERING is allowed, {@code false} 
otherwise.
+     */
+    boolean getAllowFilteringEnabled();
+
+    /**
+     * Sets whether ALLOW FILTERING is allowed.
+     *
+     * @param enabled {@code true} if ALLOW FILTERING is allowed, {@code 
false} otherwise.
+     */
+    void setAllowFilteringEnabled(boolean enabled);
+
     /**
      * Returns whether users can disable compression on tables
      *
diff --git 
a/test/unit/org/apache/cassandra/db/guardrails/GuardrailAllowFilteringTest.java 
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailAllowFilteringTest.java
new file mode 100644
index 0000000000..c46498c01f
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/db/guardrails/GuardrailAllowFilteringTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.Before;
+import org.junit.Test;
+
+import org.apache.cassandra.schema.SchemaConstants;
+import org.apache.cassandra.schema.SchemaKeyspaceTables;
+
+public class GuardrailAllowFilteringTest extends GuardrailTester
+{
+    private boolean enableState;
+
+    @Before
+    public void setupTest()
+    {
+        createTable("CREATE TABLE %s (k int PRIMARY KEY, a int, b int)");
+        enableState = getGuardrial();
+    }
+
+    @After
+    public void teardownTest()
+    {
+        setGuardrail(enableState);
+    }
+
+    private void setGuardrail(boolean allowFilteringEnabled)
+    {
+        guardrails().setAllowFilteringEnabled(allowFilteringEnabled);
+    }
+
+    private boolean getGuardrial()
+    {
+        return guardrails().getAllowFilteringEnabled();
+    }
+
+    @Test
+    public void testAllowFilteringDisabled() throws Throwable
+    {
+        setGuardrail(false);
+        assertFails("SELECT * FROM %s WHERE a = 5 ALLOW FILTERING", "Querying 
with ALLOW FILTERING is not allowed");
+    }
+
+    @Test
+    public void testAllowFilteringDisabedNotUsed() throws Throwable
+    {
+        setGuardrail(false);
+        execute("INSERT INTO %s (k, a, b) VALUES (1, 1, 1)");
+        assertValid("SELECT * FROM %s");
+    }
+
+    @Test
+    public void testAllowFilteringEnabled() throws Throwable
+    {
+        setGuardrail(true);
+        execute("INSERT INTO %s (k, a, b) VALUES (1, 1, 1)");
+        assertValid("SELECT * FROM %s WHERE a = 5 ALLOW FILTERING");
+    }
+
+    @Test
+    public void testExcludedUsers() throws Throwable
+    {
+        setGuardrail(false);
+        testExcludedUsers(() -> "SELECT * FROM %s WHERE a = 5 ALLOW 
FILTERING");
+    }
+
+    @Test
+    public void testSystemTable() throws Throwable
+    {
+        setGuardrail(false);
+        assertValid(String.format("SELECT * FROM %s.%s WHERE table_name = '%s' 
ALLOW FILTERING",
+                                  SchemaConstants.SCHEMA_KEYSPACE_NAME,
+                                  SchemaKeyspaceTables.TABLES,
+                                  currentTable()));
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to