blob: 81606ff6b5cf00e59097e1451424219701a08982 [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 org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.CQLTester;
import org.awaitility.core.ThrowingRunnable;
import static java.lang.String.format;
/**
* Tests the {@link org.apache.cassandra.auth.Permission#SELECT_MASKED} permission.
*/
public class SelectMaskedPermissionTest extends CQLTester
{
private static final Object[] CLEAR_ROW = row(7, 7, 7, 7);
private static final String USER = "ddm_user"; // user that will have their permissions changed
private static final String PASSWORD = "ddm_password";
@BeforeClass
public static void beforeClass()
{
DatabaseDescriptor.setDynamicDataMaskingEnabled(true);
DatabaseDescriptor.setPermissionsValidity(0);
DatabaseDescriptor.setRolesValidity(0);
CQLTester.setUpClass();
requireAuthentication();
requireNetwork();
}
@Before
public void before() throws Throwable
{
useSuperUser();
createTable("CREATE TABLE %s (k int, c int, s int static, v int, PRIMARY KEY (k, c))");
executeNet("INSERT INTO %s(k, c, s, v) VALUES (?, ?, ?, ?)", CLEAR_ROW);
executeNet(format("CREATE USER IF NOT EXISTS %s WITH PASSWORD '%s'", USER, PASSWORD));
executeNet(format("GRANT SELECT ON ALL KEYSPACES TO %s", USER));
}
@After
public void after() throws Throwable
{
useSuperUser();
executeNet("DROP USER IF EXISTS " + USER);
alterTable("ALTER TABLE %s ALTER k DROP MASKED");
alterTable("ALTER TABLE %s ALTER c DROP MASKED");
alterTable("ALTER TABLE %s ALTER s DROP MASKED");
alterTable("ALTER TABLE %s ALTER v DROP MASKED");
}
@Test
public void testPartitionKeyColumn() throws Throwable
{
alterTable("ALTER TABLE %s ALTER k MASKED WITH DEFAULT");
Object[] maskedRow = row(0, 7, 7, 7);
// test queries with default permissions (no UNMASK nor SELECT_MASKED)
testPartitionKeyColumnWithDefaultPermissions(maskedRow);
// test queries with only SELECT_MASKED permission
executeNet(format("GRANT SELECT_MASKED ON ALL KEYSPACES TO %s", USER));
testPartitionKeyColumnWithOnlySelectMasked(maskedRow);
// test queries with only UNMASK permission (which includes SELECT_MASKED)
executeNet(format("REVOKE SELECT_MASKED ON ALL KEYSPACES FROM %s", USER));
executeNet(format("GRANT UNMASK ON ALL KEYSPACES TO %s", USER));
testPartitionKeyColumnWithUnmask();
// test queries with both UNMASK and SELECT_MASKED permissions
executeNet(format("GRANT UNMASK, SELECT_MASKED ON ALL KEYSPACES TO %s", USER));
testPartitionKeyColumnWithUnmask();
// test queries again without both UNMASK and SELECT_MASKED permissions
executeNet(format("REVOKE UNMASK, SELECT_MASKED ON ALL KEYSPACES FROM %s", USER));
testPartitionKeyColumnWithDefaultPermissions(maskedRow);
}
private void testPartitionKeyColumnWithDefaultPermissions(Object[] maskedRow) throws Throwable
{
assertWithUser(() -> {
assertAuthorizedQuery("SELECT * FROM %s", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE c = 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE v = 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE s = 7 ALLOW FILTERING", maskedRow);
assertUnauthorizedQuery("SELECT * FROM %s WHERE k = 7", "[k]");
assertUnauthorizedQuery("SELECT * FROM %s WHERE k >= 7 ALLOW FILTERING", "[k]");
assertUnauthorizedQuery("SELECT * FROM %s WHERE k = 7 AND c = 7", "[k]");
assertUnauthorizedQuery("SELECT * FROM %s WHERE k = 7 AND v = 7 ALLOW FILTERING", "[k]");
assertUnauthorizedQuery("SELECT * FROM %s WHERE token(k) = token(7)", "[k]");
assertUnauthorizedQuery("SELECT * FROM %s WHERE token(k) >= token(7)", "[k]");
});
}
private void testPartitionKeyColumnWithOnlySelectMasked(Object[] maskedRow) throws Throwable
{
assertWithUser(() -> {
assertAuthorizedQuery("SELECT * FROM %s", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE c = 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE v = 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE s = 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE k >= 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7 AND c = 7", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7 AND v = 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE token(k) = token(7)", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE token(k) >= token(7)", maskedRow);
});
}
private void testPartitionKeyColumnWithUnmask() throws Throwable
{
assertWithUser(() -> {
assertAuthorizedQuery("SELECT * FROM %s", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE c = 7 ALLOW FILTERING", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE v = 7 ALLOW FILTERING", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE s = 7 ALLOW FILTERING", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE k >= 7 ALLOW FILTERING", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7 AND c = 7", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7 AND v = 7 ALLOW FILTERING", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE token(k) = token(7)", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE token(k) >= token(7)", CLEAR_ROW);
});
}
@Test
public void testClusteringKeyColumn() throws Throwable
{
alterTable("ALTER TABLE %s ALTER c MASKED WITH DEFAULT");
Object[] maskedRow = row(7, 0, 7, 7);
// test queries with default permissions (no UNMASK nor SELECT_MASKED)
testClusteringKeyColumnWithDefaultPermissions(maskedRow);
// test queries with only SELECT_MASKED permission
executeNet(format("GRANT SELECT_MASKED ON ALL KEYSPACES TO %s", USER));
testClusteringKeyColumnWithOnlySelectMasked(maskedRow);
// test queries with only UNMASK permission (which includes SELECT_MASKED)
executeNet(format("REVOKE SELECT_MASKED ON ALL KEYSPACES FROM %s", USER));
executeNet(format("GRANT UNMASK ON ALL KEYSPACES TO %s", USER));
testClusteringKeyColumnWithUnmask();
// test queries with both UNMASK and SELECT_MASKED permissions
executeNet(format("GRANT UNMASK, SELECT_MASKED ON ALL KEYSPACES TO %s", USER));
testClusteringKeyColumnWithUnmask();
// test queries again without both UNMASK and SELECT_MASKED permissions
executeNet(format("REVOKE UNMASK, SELECT_MASKED ON ALL KEYSPACES FROM %s", USER));
testClusteringKeyColumnWithDefaultPermissions(maskedRow);
}
private void testClusteringKeyColumnWithDefaultPermissions(Object[] maskedRow) throws Throwable
{
assertWithUser(() -> {
assertAuthorizedQuery("SELECT * FROM %s", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE v = 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE s = 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE token(k) = token(7)", maskedRow);
assertUnauthorizedQuery("SELECT * FROM %s WHERE c = 7 ALLOW FILTERING", "[c]");
assertUnauthorizedQuery("SELECT * FROM %s WHERE k = 7 AND c = 7", "[c]");
});
}
private void testClusteringKeyColumnWithOnlySelectMasked(Object[] maskedRow) throws Throwable
{
assertWithUser(() -> {
assertAuthorizedQuery("SELECT * FROM %s", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE v = 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE s = 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE token(k) = token(7)", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE c = 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7 AND c = 7", maskedRow);
});
}
private void testClusteringKeyColumnWithUnmask() throws Throwable
{
assertWithUser(() -> {
assertAuthorizedQuery("SELECT * FROM %s", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE v = 7 ALLOW FILTERING", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE s = 7 ALLOW FILTERING", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE token(k) = token(7)", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE c = 7 ALLOW FILTERING", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7 AND c = 7", CLEAR_ROW);
});
}
@Test
public void testStaticColumn() throws Throwable
{
alterTable("ALTER TABLE %s ALTER s MASKED WITH DEFAULT");
Object[] maskedRow = row(7, 7, 0, 7);
// test queries with default permissions (no UNMASK nor SELECT_MASKED)
testStaticColumnWithDefaultPermissions(maskedRow);
// test queries with only SELECT_MASKED permission
executeNet(format("GRANT SELECT_MASKED ON ALL KEYSPACES TO %s", USER));
testStaticColumnWithOnlySelectMasked(maskedRow);
// test queries with only UNMASK permission (which includes SELECT_MASKED)
executeNet(format("REVOKE SELECT_MASKED ON ALL KEYSPACES FROM %s", USER));
executeNet(format("GRANT UNMASK ON ALL KEYSPACES TO %s", USER));
testStaticColumnWithUnmask();
// test queries with both UNMASK and SELECT_MASKED permissions
executeNet(format("GRANT UNMASK, SELECT_MASKED ON ALL KEYSPACES TO %s", USER));
testStaticColumnWithUnmask();
// test queries again without both UNMASK and SELECT_MASKED permissions
executeNet(format("REVOKE UNMASK, SELECT_MASKED ON ALL KEYSPACES FROM %s", USER));
testStaticColumnWithDefaultPermissions(maskedRow);
}
private void testStaticColumnWithDefaultPermissions(Object[] maskedRow) throws Throwable
{
assertWithUser(() -> {
assertAuthorizedQuery("SELECT * FROM %s", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE token(k) = token(7)", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7 AND c = 7", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE c = 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE v = 7 ALLOW FILTERING", maskedRow);
assertUnauthorizedQuery("SELECT * FROM %s WHERE s = 7 ALLOW FILTERING", "[s]");
});
}
private void testStaticColumnWithOnlySelectMasked(Object[] maskedRow) throws Throwable
{
assertWithUser(() -> {
assertAuthorizedQuery("SELECT * FROM %s", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE token(k) = token(7)", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7 AND c = 7", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE c = 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE s = 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE v = 7 ALLOW FILTERING", maskedRow);
});
}
private void testStaticColumnWithUnmask() throws Throwable
{
assertWithUser(() -> {
assertAuthorizedQuery("SELECT * FROM %s", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE token(k) = token(7)", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7 AND c = 7", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE c = 7 ALLOW FILTERING", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE s = 7 ALLOW FILTERING", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE v = 7 ALLOW FILTERING", CLEAR_ROW);
});
}
@Test
public void testCollections() throws Throwable
{
alterTable("ALTER TABLE %s ALTER v MASKED WITH DEFAULT");
Object[] maskedRow = row(7, 7, 7, 0);
// test queries with default permissions (no UNMASK nor SELECT_MASKED)
testCollectionsWithDefaultPermissions(maskedRow);
// test queries with only SELECT_MASKED permission
executeNet(format("GRANT SELECT_MASKED ON ALL KEYSPACES TO %s", USER));
testCollectionsWithOnlySelectMasked(maskedRow);
// test queries with only UNMASK permission (which includes SELECT_MASKED)
executeNet(format("REVOKE SELECT_MASKED ON ALL KEYSPACES FROM %s", USER));
executeNet(format("GRANT UNMASK ON ALL KEYSPACES TO %s", USER));
testCollectionsWithUnmask();
// test queries with both UNMASK and SELECT_MASKED permissions
executeNet(format("GRANT UNMASK, SELECT_MASKED ON ALL KEYSPACES TO %s", USER));
testCollectionsWithUnmask();
// test queries again without both UNMASK and SELECT_MASKED permissions
executeNet(format("REVOKE UNMASK, SELECT_MASKED ON ALL KEYSPACES FROM %s", USER));
testCollectionsWithDefaultPermissions(maskedRow);
}
private void testCollectionsWithDefaultPermissions(Object[] maskedRow) throws Throwable
{
assertWithUser(() -> {
assertAuthorizedQuery("SELECT * FROM %s", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE token(k) = token(7)", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7 AND c = 7", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE c = 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE s = 7 ALLOW FILTERING", maskedRow);
assertUnauthorizedQuery("SELECT * FROM %s WHERE v = 7 ALLOW FILTERING", "[v]");
});
}
private void testCollectionsWithOnlySelectMasked(Object[] maskedRow) throws Throwable
{
assertWithUser(() -> {
assertAuthorizedQuery("SELECT * FROM %s", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE token(k) = token(7)", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7 AND c = 7", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE c = 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE s = 7 ALLOW FILTERING", maskedRow);
assertAuthorizedQuery("SELECT * FROM %s WHERE v = 7 ALLOW FILTERING", maskedRow);
});
}
private void testCollectionsWithUnmask() throws Throwable
{
assertWithUser(() -> {
assertAuthorizedQuery("SELECT * FROM %s", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE token(k) = token(7)", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE k = 7 AND c = 7", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE c = 7 ALLOW FILTERING", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE s = 7 ALLOW FILTERING", CLEAR_ROW);
assertAuthorizedQuery("SELECT * FROM %s WHERE v = 7 ALLOW FILTERING", CLEAR_ROW);
});
}
private void assertAuthorizedQuery(String query, Object[]... rows) throws Throwable
{
assertRowsNet(executeNet(query), rows);
}
private void assertUnauthorizedQuery(String query, String unauthorizedColumns) throws Throwable
{
assertInvalidMessageNet(format("User %s has no UNMASK nor SELECT_MASKED permission on table %s.%s, " +
"cannot query masked columns %s",
USER, KEYSPACE, currentTable(), unauthorizedColumns), query);
}
private void assertWithUser(ThrowingRunnable assertion) throws Throwable
{
useUser(USER, PASSWORD);
assertion.run();
useSuperUser();
}
}