From 660dace43c5f5077fe877bdcfab5e725bf1c96a2 Mon Sep 17 00:00:00 2001 From: Aleksei Zotov Date: Fri, 23 Jul 2021 19:45:46 +0400 Subject: [PATCH] Add tests for Resource fromName/getName patch by Aleksei Zotov; reviewed by Berenguer Blasi, Sam Tunnicliffe for CASSANDRA-16995 --- CHANGES.txt | 1 + .../cassandra/auth/FunctionResource.java | 5 +- .../cassandra/auth/FunctionResourceTest.java | 115 ++++++++++++++++++ .../apache/cassandra/auth/ResourcesTest.java | 79 ++++++++++++ 4 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 test/unit/org/apache/cassandra/auth/FunctionResourceTest.java create mode 100644 test/unit/org/apache/cassandra/auth/ResourcesTest.java diff --git a/CHANGES.txt b/CHANGES.txt index b1ab34a7e8..cac42fb4ef 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.0.26: + * ArrayIndexOutOfBoundsException in FunctionResource#fromName (CASSANDRA-16977, CASSANDRA-16995) * CVE-2015-0886 Security vulnerability in jbcrypt is addressed (CASSANDRA-9384) * Avoid useless SSTable reads during single partition queries (CASSANDRA-16944) * Debian init respects CASSANDRA_HEAPDUMP_DIR (CASSANDRA-13843) diff --git a/src/java/org/apache/cassandra/auth/FunctionResource.java b/src/java/org/apache/cassandra/auth/FunctionResource.java index 01a4de5b08..9a6c6ab877 100644 --- a/src/java/org/apache/cassandra/auth/FunctionResource.java +++ b/src/java/org/apache/cassandra/auth/FunctionResource.java @@ -18,6 +18,7 @@ package org.apache.cassandra.auth; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; @@ -176,8 +177,10 @@ public class FunctionResource implements IResource if (parts.length == 2) return keyspace(parts[1]); + if (!name.matches("^.+\\[.*\\]$")) + throw new IllegalArgumentException(String.format("%s is not a valid function resource name. It must end with \"[]\"", name)); String[] nameAndArgs = StringUtils.split(parts[2], "[|]"); - return function(parts[1], nameAndArgs[0], argsListFromString(nameAndArgs[1])); + return function(parts[1], nameAndArgs[0], nameAndArgs.length > 1 ? argsListFromString(nameAndArgs[1]) : Collections.emptyList()); } /** diff --git a/test/unit/org/apache/cassandra/auth/FunctionResourceTest.java b/test/unit/org/apache/cassandra/auth/FunctionResourceTest.java new file mode 100644 index 0000000000..54da393edc --- /dev/null +++ b/test/unit/org/apache/cassandra/auth/FunctionResourceTest.java @@ -0,0 +1,115 @@ +/* + * 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.auth; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import org.apache.cassandra.db.marshal.AbstractType; +import org.apache.cassandra.db.marshal.TypeParser; + +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.Assert.assertEquals; + +public class FunctionResourceTest +{ + private static final String ks = "fr_ks"; + private static final String func = "functions"; + private static final String name = "concat"; + private static final String varType = "org.apache.cassandra.db.marshal.UTF8Type"; + + @Test + public void testFunction() throws Exception + { + FunctionResource expected = FunctionResource.root(); + FunctionResource actual = FunctionResource.fromName(func); + assertEquals(expected, actual); + assertEquals(expected.getName(), actual.getName()); + } + + @Test + public void testFunctionKeyspace() throws Exception + { + FunctionResource expected = FunctionResource.keyspace(ks); + FunctionResource actual = FunctionResource.fromName(String.format("%s/%s", func, ks)); + assertEquals(expected, actual); + assertEquals(expected.getKeyspace(), actual.getKeyspace()); + } + + @Test + public void testFunctionWithSingleInputParameter() throws Exception + { + List> argTypes = new ArrayList<>(); + argTypes.add(TypeParser.parse(varType)); + FunctionResource expected = FunctionResource.function(ks, name, argTypes); + FunctionResource actual = FunctionResource.fromName(String.format("%s/%s/%s[%s]", func, ks, name, varType)); + assertEquals(expected, actual); + assertEquals(expected.getKeyspace(), actual.getKeyspace()); + } + + @Test + public void testFunctionWithMultipleInputParameters() throws Exception + { + List> argTypes = new ArrayList<>(); + argTypes.add(TypeParser.parse(varType)); + argTypes.add(TypeParser.parse(varType)); + FunctionResource expected = FunctionResource.function(ks, name, argTypes); + FunctionResource actual = FunctionResource.fromName(String.format("%s/%s/%s[%s^%s]", func, ks, name, varType, varType)); + assertEquals(expected, actual); + assertEquals(expected.getKeyspace(), actual.getKeyspace()); + } + + @Test + public void testFunctionWithoutInputParameters() throws Exception + { + List> argTypes = new ArrayList<>(); + FunctionResource expected = FunctionResource.function(ks, name, argTypes); + FunctionResource actual = FunctionResource.fromName(String.format("%s/%s/%s[]", func, ks, name)); + assertEquals(expected, actual); + assertEquals(expected.getKeyspace(), actual.getKeyspace()); + + String error = "functions/fr_ks/concat is not a valid function resource name. It must end with \"[]\""; + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> FunctionResource.fromName(String.format("%s/%s/%s", + func, + ks, + name))) + .withMessage(error); + } + + @Test + public void testInvalidFunctionName() + { + String expected = "functions_test is not a valid function resource name"; + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> FunctionResource.fromName("functions_test")) + .withMessage(expected); + } + + @Test + public void testFunctionWithInvalidInput() + { + String expected = String.format("%s/%s/%s[%s]/test is not a valid function resource name", func, ks, name, varType); + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> FunctionResource.fromName(String.format("%s/%s/%s[%s]/test", + func, + ks, + name, + varType))) + .withMessage(expected); + } +} diff --git a/test/unit/org/apache/cassandra/auth/ResourcesTest.java b/test/unit/org/apache/cassandra/auth/ResourcesTest.java new file mode 100644 index 0000000000..b3d85cbede --- /dev/null +++ b/test/unit/org/apache/cassandra/auth/ResourcesTest.java @@ -0,0 +1,79 @@ +/* + * 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.auth; + +import java.util.Arrays; +import java.util.Collections; + +import org.junit.Test; + +import org.apache.cassandra.db.marshal.DoubleType; +import org.apache.cassandra.db.marshal.Int32Type; + +import static org.junit.Assert.assertEquals; + +public class ResourcesTest +{ + + @Test + public void testRoleResourceNameConversion() + { + assertEquals(RoleResource.root(), Resources.fromName("roles")); + assertEquals("roles", RoleResource.root().getName()); + + assertEquals(RoleResource.role("role1"), Resources.fromName("roles/role1")); + assertEquals("roles/role1", RoleResource.role("role1").getName()); + } + + @Test + public void testDataResourceNameConversion() + { + assertEquals(DataResource.root(), Resources.fromName("data")); + assertEquals("data", DataResource.root().getName()); + + assertEquals(DataResource.keyspace("ks1"), Resources.fromName("data/ks1")); + assertEquals("data/ks1", DataResource.keyspace("ks1").getName()); + + assertEquals(DataResource.table("ks1", "t1"), Resources.fromName("data/ks1/t1")); + assertEquals("data/ks1/t1", DataResource.table("ks1", "t1").getName()); + } + + @Test + public void testFunctionResourceNameConversion() + { + assertEquals(FunctionResource.root(), Resources.fromName("functions")); + assertEquals("functions", FunctionResource.root().getName()); + + assertEquals(FunctionResource.keyspace("ks1"), Resources.fromName("functions/ks1")); + assertEquals("functions/ks1", FunctionResource.keyspace("ks1").getName()); + + assertEquals(FunctionResource.function("ks1", "f1", Collections.emptyList()), + Resources.fromName("functions/ks1/f1[]")); + // this is actually supported by an explicit check in TypeParser + assertEquals(FunctionResource.function("ks1", "f1", Arrays.asList(Int32Type.instance, DoubleType.instance)), + Resources.fromName("functions/ks1/f1[Int32Type^DoubleType]")); + assertEquals("functions/ks1/f1[]", + FunctionResource.function("ks1", "f1", Collections.emptyList()).getName()); + + assertEquals(FunctionResource.function("ks1", "f1", Arrays.asList(Int32Type.instance, DoubleType.instance)), + Resources.fromName("functions/ks1/f1[org.apache.cassandra.db.marshal.Int32Type^org.apache.cassandra.db.marshal.DoubleType]")); + assertEquals("functions/ks1/f1[org.apache.cassandra.db.marshal.Int32Type^org.apache.cassandra.db.marshal.DoubleType]", + FunctionResource.function("ks1", "f1", Arrays.asList(Int32Type.instance, DoubleType.instance)).getName()); + } +}