mirror of https://github.com/apache/cassandra
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
This commit is contained in:
parent
545809616c
commit
f444c40286
|
|
@ -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)
|
||||
|
|
|
|||
1
NEWS.txt
1
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue