blob: 252aac5002f3e787bd81db46e762b307d602bb92 [file] [log] [blame]
/*
* 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.cql3.functions.masking;
import java.nio.ByteBuffer;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.apache.cassandra.db.marshal.AbstractType;
import static java.lang.String.format;
/**
* {@link ColumnMaskTester} verifying that masks can be applied to columns in any position (partition key columns,
* clustering key columns, static columns and regular columns). The columns of any depending materialized views should
* be udpated accordingly.
*/
@RunWith(Parameterized.class)
public abstract class ColumnMaskInAnyPositionTester extends ColumnMaskTester
{
/** The column mask as expressed in CQL statements right after the {@code MASKED WITH} keywords. */
@Parameterized.Parameter
public String mask;
/** The type of the masked column */
@Parameterized.Parameter(1)
public String type;
/** The types of the tested masking function partial arguments. */
@Parameterized.Parameter(2)
public List<AbstractType<?>> argumentTypes;
/** The serialized values of the tested masking function partial arguments. */
@Parameterized.Parameter(3)
public List<ByteBuffer> argumentValues;
@Test
public void testCreateTableWithMaskedColumns() throws Throwable
{
// Nothing is masked
createTable("CREATE TABLE %s (k int, c int, r int, s int static, PRIMARY KEY(k, c))");
assertTableColumnsAreNotMasked("k", "c", "r", "s");
// Masked partition key
createTable(format("CREATE TABLE %%s (k %s MASKED WITH %s PRIMARY KEY, r int)", type, mask));
assertTableColumnsAreMasked("k");
assertTableColumnsAreNotMasked("r");
// Masked partition key component
createTable(format("CREATE TABLE %%s (k1 int, k2 %s MASKED WITH %s, r int, PRIMARY KEY(k1, k2))", type, mask));
assertTableColumnsAreMasked("k2");
assertTableColumnsAreNotMasked("k1", "r");
// Masked clustering key
createTable(format("CREATE TABLE %%s (k int, c %s MASKED WITH %s, r int, PRIMARY KEY (k, c))", type, mask));
assertTableColumnsAreMasked("c");
assertTableColumnsAreNotMasked("k", "r");
// Masked clustering key with reverse order
createTable(format("CREATE TABLE %%s (k int, c %s MASKED WITH %s, r int, PRIMARY KEY (k, c)) " +
"WITH CLUSTERING ORDER BY (c DESC)", type, mask));
assertTableColumnsAreMasked("c");
assertTableColumnsAreNotMasked("k", "r");
// Masked clustering key component
createTable(format("CREATE TABLE %%s (k int, c1 int, c2 %s MASKED WITH %s, r int, PRIMARY KEY (k, c1, c2))", type, mask));
assertTableColumnsAreMasked("c2");
assertTableColumnsAreNotMasked("k", "c1", "r");
// Masked regular column
createTable(format("CREATE TABLE %%s (k int PRIMARY KEY, r1 %s MASKED WITH %s, r2 int)", type, mask));
assertTableColumnsAreMasked("r1");
assertTableColumnsAreNotMasked("k", "r2");
// Masked static column
createTable(format("CREATE TABLE %%s (k int, c int, r int, s %s STATIC MASKED WITH %s, PRIMARY KEY (k, c))", type, mask));
assertTableColumnsAreMasked("s");
assertTableColumnsAreNotMasked("k", "c", "r");
// Multiple masked columns
createTable(format("CREATE TABLE %%s (" +
"k1 int, k2 %s MASKED WITH %s, " +
"c1 int, c2 %s MASKED WITH %s, " +
"r1 int, r2 %s MASKED WITH %s, " +
"s1 int static, s2 %s static MASKED WITH %s, " +
"PRIMARY KEY((k1, k2), c1, c2))",
type, mask, type, mask, type, mask, type, mask));
assertTableColumnsAreMasked("k2", "c2", "r2", "s2");
assertTableColumnsAreNotMasked("k1", "c1", "r1", "s1");
}
@Test
public void testCreateTableWithMaskedColumnsAndMaterializedView() throws Throwable
{
createTable(format("CREATE TABLE %%s (" +
"k1 int, k2 %s MASKED WITH %s, " +
"c1 int, c2 %s MASKED WITH %s, " +
"r1 int, r2 %s MASKED WITH %s, " +
"s1 int static, s2 %s static MASKED WITH %s, " +
"PRIMARY KEY((k1, k2), c1, c2))",
type, mask, type, mask, type, mask, type, mask));
createView("CREATE MATERIALIZED VIEW %s AS SELECT k1, k2, c1, c2, r1, r2 FROM %s " +
"WHERE k1 IS NOT NULL AND k2 IS NOT NULL " +
"AND c1 IS NOT NULL AND c2 IS NOT NULL " +
"AND r1 IS NOT NULL AND r2 IS NOT NULL " +
"PRIMARY KEY (r2, c2, c1, k2, k1)");
assertTableColumnsAreMasked("k2", "c2", "r2", "s2");
assertTableColumnsAreNotMasked("k1", "c1", "r1", "s1");
assertViewColumnsAreMasked("k2", "c2", "r2");
assertViewColumnsAreNotMasked("k1", "c1", "r1");
}
@Test
public void testAlterTableWithMaskedColumns() throws Throwable
{
// Create the table to be altered
createTable(format("CREATE TABLE %%s (k %s, c %<s, r1 %<s, r2 %<s MASKED WITH %s, r3 %s, s %<s static, " +
"PRIMARY KEY (k, c))", type, mask, type));
assertTableColumnsAreMasked("r2");
assertTableColumnsAreNotMasked("k", "c", "r1", "r3", "s");
// Add new masked column
alterTable(format("ALTER TABLE %%s ADD r4 %s MASKED WITH %s", type, mask));
assertTableColumnsAreMasked("r2", "r4");
assertTableColumnsAreNotMasked("k", "c", "r1", "r3", "s");
// Set mask for an existing but unmasked column
alterTable(format("ALTER TABLE %%s ALTER r1 MASKED WITH %s", mask));
assertTableColumnsAreMasked("r1", "r2", "r4");
// Unmask a masked column
alterTable("ALTER TABLE %s ALTER r1 DROP MASKED");
alterTable("ALTER TABLE %s ALTER r2 DROP MASKED");
assertTableColumnsAreMasked("r4");
assertTableColumnsAreNotMasked("r1", "r2", "r3");
// Mask and disable mask for primary key
alterTable(format("ALTER TABLE %%s ALTER k MASKED WITH %s", mask));
assertTableColumnsAreMasked("k");
alterTable("ALTER TABLE %s ALTER k DROP MASKED");
assertTableColumnsAreNotMasked("k");
// Mask and disable mask for clustering key
alterTable(format("ALTER TABLE %%s ALTER c MASKED WITH %s", mask));
assertTableColumnsAreMasked("c");
alterTable("ALTER TABLE %s ALTER c DROP MASKED");
assertTableColumnsAreNotMasked("c");
// Mask and disable mask for static column
alterTable(format("ALTER TABLE %%s ALTER s MASKED WITH %s", mask));
assertTableColumnsAreMasked("s");
alterTable("ALTER TABLE %s ALTER s DROP MASKED");
assertTableColumnsAreNotMasked("s");
// Add multiple masked columns within the same query
alterTable(format("ALTER TABLE %%s ADD (" +
"r5 %s MASKED WITH %s, " +
"r6 %s, " +
"r7 %s MASKED WITH %s, " +
"r8 %s)",
type, mask, type, type, mask, type));
assertTableColumnsAreMasked("r5", "r7");
assertTableColumnsAreNotMasked("r6", "r8");
}
@Test
public void testAlterTableWithMaskedColumnsAndMaterializedView() throws Throwable
{
createTable(format("CREATE TABLE %%s (" +
"k %s, c %<s, r1 %<s, r2 %<s, s1 %<s static, s2 %<s static, " +
"PRIMARY KEY(k, c))", type));
createView("CREATE MATERIALIZED VIEW %s AS SELECT k, c, r2 FROM %s " +
"WHERE k IS NOT NULL AND c IS NOT NULL " +
"AND r1 IS NOT NULL AND r2 IS NOT NULL " +
"PRIMARY KEY (r2, c, k)");
// Adding a column to the table doesn't have an effect on the view
alterTable(format("ALTER TABLE %%s ADD r3 %s MASKED WITH %s", type, mask));
assertTableColumnsAreMasked("r3");
assertTableColumnsAreNotMasked("k", "c", "r1", "r2", "s1", "s2");
assertViewColumnsAreNotMasked("k", "c", "r2");
// Masking a column that is not part of the view doesn't have an effect on the view
alterTable(format("ALTER TABLE %%s ALTER r1 MASKED WITH %s", mask));
alterTable(format("ALTER TABLE %%s ALTER s1 MASKED WITH %s", mask));
assertTableColumnsAreMasked("r1", "r3", "s1");
assertTableColumnsAreNotMasked("k", "c", "r2", "s2");
assertViewColumnsAreNotMasked("k", "c", "r2");
// Masking a column that is part of the view should have an effect on the view
alterTable(format("ALTER TABLE %%s ALTER r2 MASKED WITH %s", mask));
assertTableColumnsAreMasked("r1", "r2", "r3", "s1");
assertTableColumnsAreNotMasked("k", "c", "s2");
assertViewColumnsAreMasked("r2");
assertViewColumnsAreNotMasked("k", "c");
// Mask the rest of the columns
alterTable(format("ALTER TABLE %%s ALTER k MASKED WITH %s", mask));
alterTable(format("ALTER TABLE %%s ALTER c MASKED WITH %s", mask));
alterTable(format("ALTER TABLE %%s ALTER s2 MASKED WITH %s", mask));
assertTableColumnsAreMasked("k", "c", "r1", "r2", "r3", "s1", "s2");
assertViewColumnsAreMasked("k", "c", "r2");
// Unmask a column that is part of the view
alterTable("ALTER TABLE %s ALTER r2 DROP MASKED");
assertTableColumnsAreMasked("k", "c", "r1", "r3", "s1", "s2");
assertTableColumnsAreNotMasked("r2");
assertViewColumnsAreMasked("k", "c");
assertViewColumnsAreNotMasked("r2");
// Unmask the rest of the columns
alterTable("ALTER TABLE %s ALTER k DROP MASKED");
alterTable("ALTER TABLE %s ALTER c DROP MASKED");
alterTable("ALTER TABLE %s ALTER r1 DROP MASKED");
alterTable("ALTER TABLE %s ALTER r3 DROP MASKED");
alterTable("ALTER TABLE %s ALTER s1 DROP MASKED");
alterTable("ALTER TABLE %s ALTER s2 DROP MASKED");
assertTableColumnsAreNotMasked("k", "c", "r1", "r2", "r3", "s1", "s2");
assertViewColumnsAreNotMasked("k", "c", "r2");
}
private String functionName()
{
if (mask.equals("DEFAULT"))
return "mask_default";
return StringUtils.remove(StringUtils.substringBefore(mask, "("), KEYSPACE + ".");
}
private void assertTableColumnsAreMasked(String... columns) throws Throwable
{
for (String column : columns)
{
assertColumnIsMasked(currentTable(), column, functionName(), argumentTypes, argumentValues);
}
}
private void assertViewColumnsAreMasked(String... columns) throws Throwable
{
for (String column : columns)
{
assertColumnIsMasked(currentView(), column, functionName(), argumentTypes, argumentValues);
}
}
}