blob: 06bec755d1294216adf175a263f4fde4f930374b [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.drill.exec.coord.zk;
import com.typesafe.config.ConfigValueFactory;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.ACLProvider;
import org.apache.curator.retry.RetryNTimes;
import org.apache.curator.test.TestingServer;
import org.apache.drill.categories.SecurityTest;
import org.apache.drill.common.config.DrillConfig;
import org.apache.drill.common.scanner.ClassPathScanner;
import org.apache.drill.common.scanner.persistence.ScanResult;
import org.apache.drill.exec.ExecConstants;
import org.apache.drill.exec.server.BootStrapContext;
import org.apache.drill.exec.server.options.SystemOptionManager;
import org.apache.drill.test.BaseTest;
import org.apache.zookeeper.data.ACL;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import java.nio.charset.StandardCharsets;
import java.util.List;
@Ignore("See DRILL-6823")
@Category(SecurityTest.class)
public class TestZKACL extends BaseTest {
private TestingServer server;
private final static String cluster_config_znode = "test-cluster_config_znode";
private final static byte[] cluster_config_data = "drill-node-1".getBytes(StandardCharsets.UTF_8);
private final static String drill_zk_root = "drill-test-drill_zk_root";
private final static String drill_cluster_name = "test-drillbits";
private static final String drillClusterPath = "/" + drill_zk_root + "/" + drill_cluster_name;
private static final RetryPolicy retryPolicy = new RetryNTimes(1, 1000);
private static final String drillUDFName = "test-udfs";
private final static byte[] udf_data = "test-udf-1".getBytes(StandardCharsets.UTF_8);
private static final String drillUDFPath = "/" + drill_zk_root + "/" + drillUDFName;
private static ACLProvider aclProviderDelegate;
private static CuratorFramework client;
@Before
public void setUp() throws Exception {
System.setProperty("zookeeper.authProvider.1", "org.apache.zookeeper.server.auth.SASLAuthenticationProvider");
String configPath = (ClassLoader.getSystemResource("zkacltest.conf")).getPath();
System.setProperty("java.security.auth.login.config", configPath);
server = new TestingServer();
final DrillConfig config = new DrillConfig(DrillConfig.create().withValue(ExecConstants.ZK_ACL_PROVIDER,
ConfigValueFactory.fromAnyRef("creator-all")
).withValue(ExecConstants.ZK_APPLY_SECURE_ACL, ConfigValueFactory.fromAnyRef(true)));
final ScanResult result = ClassPathScanner.fromPrescan(config);
final BootStrapContext bootStrapContext =
new BootStrapContext(config, SystemOptionManager.createDefaultOptionDefinitions(), result);
aclProviderDelegate = ZKACLProviderFactory.getACLProvider(config, drillClusterPath, bootStrapContext);
server.start();
client = CuratorFrameworkFactory.builder().
retryPolicy(retryPolicy).
connectString(server.getConnectString()).
aclProvider(aclProviderDelegate).
build();
client.start();
}
/**
* Test ACLs on znodes required to discover the cluster
*
* ZK libraries only supports one client instance per-machine per-server and it is cached.
* This test will fail when run after other ZK tests that setup the client in a way that will cause this test to fail
*/
@Test
public void testClusterDiscoveryPaths() {
try {
String path = PathUtils.join(drillClusterPath, cluster_config_znode);
client.create().creatingParentsIfNeeded().forPath(path, cluster_config_data);
List<ACL> remoteACLs = client.getACL().forPath(path);
List<ACL> desiredACLs = ((ZKACLProviderDelegate) aclProviderDelegate).aclProvider.getDrillAclForPath(drillClusterPath);
// Check the ACLs
for (ACL remote : remoteACLs) {
boolean found = false;
for (ACL desired : desiredACLs) {
// desiredACL list is READ_ACL_UNSAFE (READ, WORLD_ANYONE) + CREATOR_ALL_ACL(ALL, AUTH)
// AUTH in CREATOR_ALL would translate to SASL, username. Hence the replacement
// Note: The username("testuser1") should match the username in java.security.auth.login.config
found = desired.toString().equals(remote.toString().replace("sasl", "auth").replace("testuser1", ""));
if (found) { break; }
}
Assert.assertTrue(found);
}
// check if the data can be read
byte[] actual = client.getData().forPath(path);
Assert.assertArrayEquals("testClusterDiscoveryPaths data mismatch", cluster_config_data, actual);
} catch (Exception e) {
throw new IllegalStateException("testClusterDiscoveryPaths failed");
}
}
/**
* Test ACLs on znodes other than ones required to discover the cluster
*
* ZK libraries only supports one client instance per-machine per-server and it is cached.
* This test will fail when run after other ZK tests that setup the client in a way that will cause this test to fail
*/
@Test
public void testNonClusterDiscoveryPaths() {
try {
client.create().creatingParentsIfNeeded().forPath(drillUDFPath, udf_data);
List<ACL> remoteACLs = client.getACL().forPath(drillUDFPath);
List<ACL> desiredACLs = ((ZKACLProviderDelegate) aclProviderDelegate).aclProvider.getDrillAclForPath(drillUDFPath);
Assert.assertEquals(remoteACLs.size(), desiredACLs.size());
for (ACL remote : remoteACLs) {
boolean found = false;
for (ACL desired : desiredACLs) {
// desiredACL list is READ_ACL_UNSAFE (READ, WORLD_ANYONE) + CREATOR_ALL_ACL(ALL, AUTH)
// AUTH in CREATOR_ALL would translate to SASL, username. Hence the replacement
// Note: The username("testuser1") should match the username in java.security.auth.login.config
found = desired.toString().equals(remote.toString().replace("sasl", "auth").replace("testuser1", ""));
if (found) { break; }
}
Assert.assertTrue(found);
}
// check if the data can be read
byte[] actual = client.getData().forPath(drillUDFPath);
Assert.assertArrayEquals("testNonClusterDiscoveryPaths data mismatch", udf_data, actual);
} catch (Exception e) {
throw new IllegalStateException("testNonClusterDiscoveryPaths failed");
}
}
@After
public void tearDown() throws Exception {
client.close();
server.close();
}
}