| /* |
| * 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.hadoop.registry.secure; |
| |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.service.ServiceOperations; |
| import org.apache.hadoop.registry.client.impl.zk.ZKPathDumper; |
| import org.apache.hadoop.registry.client.impl.zk.CuratorService; |
| import org.apache.hadoop.registry.client.impl.zk.RegistrySecurity; |
| import org.apache.zookeeper.CreateMode; |
| import org.apache.zookeeper.Login; |
| import org.apache.zookeeper.server.ZooKeeperSaslServer; |
| import org.apache.zookeeper.server.auth.SaslServerCallbackHandler; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import javax.security.auth.login.AppConfigurationEntry; |
| import javax.security.auth.login.LoginContext; |
| |
| import static org.apache.hadoop.registry.client.api.RegistryConstants.*; |
| import static org.apache.hadoop.registry.client.impl.zk.ZookeeperConfigOptions.PROP_ZK_SASL_CLIENT_CONTEXT; |
| import static org.apache.hadoop.registry.client.impl.zk.ZookeeperConfigOptions.PROP_ZK_SASL_CLIENT_USERNAME; |
| |
| /** |
| * Verify that the Mini ZK service can be started up securely |
| */ |
| public class TestSecureRegistry extends AbstractSecureRegistryTest { |
| private static final Logger LOG = |
| LoggerFactory.getLogger(TestSecureRegistry.class); |
| |
| @Before |
| public void beforeTestSecureZKService() throws Throwable { |
| enableKerberosDebugging(); |
| } |
| |
| @After |
| public void afterTestSecureZKService() throws Throwable { |
| disableKerberosDebugging(); |
| RegistrySecurity.clearZKSaslClientProperties(); |
| } |
| |
| /** |
| * this is a cut and paste of some of the ZK internal code that was |
| * failing on windows and swallowing its exceptions |
| */ |
| @Test |
| public void testLowlevelZKSaslLogin() throws Throwable { |
| RegistrySecurity.bindZKToServerJAASContext(ZOOKEEPER_SERVER_CONTEXT); |
| String serverSection = |
| System.getProperty(ZooKeeperSaslServer.LOGIN_CONTEXT_NAME_KEY, |
| ZooKeeperSaslServer.DEFAULT_LOGIN_CONTEXT_NAME); |
| assertEquals(ZOOKEEPER_SERVER_CONTEXT, serverSection); |
| |
| AppConfigurationEntry entries[]; |
| entries = javax.security.auth.login.Configuration.getConfiguration() |
| .getAppConfigurationEntry( |
| serverSection); |
| |
| assertNotNull("null entries", entries); |
| |
| SaslServerCallbackHandler saslServerCallbackHandler = |
| new SaslServerCallbackHandler( |
| javax.security.auth.login.Configuration.getConfiguration()); |
| Login login = new Login(serverSection, saslServerCallbackHandler); |
| try { |
| login.startThreadIfNeeded(); |
| } finally { |
| login.shutdown(); |
| } |
| } |
| |
| @Test |
| public void testCreateSecureZK() throws Throwable { |
| startSecureZK(); |
| secureZK.stop(); |
| } |
| |
| @Test |
| public void testInsecureClientToZK() throws Throwable { |
| startSecureZK(); |
| userZookeeperToCreateRoot(); |
| RegistrySecurity.clearZKSaslClientProperties(); |
| |
| CuratorService curatorService = |
| startCuratorServiceInstance("insecure client", false); |
| |
| curatorService.zkList("/"); |
| curatorService.zkMkPath("", CreateMode.PERSISTENT, false, |
| RegistrySecurity.WorldReadWriteACL); |
| } |
| |
| /** |
| * test that ZK can write as itself |
| * @throws Throwable |
| */ |
| @Test |
| public void testZookeeperCanWrite() throws Throwable { |
| |
| System.setProperty("curator-log-events", "true"); |
| startSecureZK(); |
| CuratorService curator = null; |
| LoginContext login = login(ZOOKEEPER_LOCALHOST, |
| ZOOKEEPER_CLIENT_CONTEXT, |
| keytab_zk); |
| try { |
| logLoginDetails(ZOOKEEPER, login); |
| RegistrySecurity.setZKSaslClientProperties(ZOOKEEPER, |
| ZOOKEEPER_CLIENT_CONTEXT); |
| curator = startCuratorServiceInstance("ZK", true); |
| LOG.info(curator.toString()); |
| |
| addToTeardown(curator); |
| curator.zkMkPath("/", CreateMode.PERSISTENT, false, |
| RegistrySecurity.WorldReadWriteACL); |
| curator.zkList("/"); |
| curator.zkMkPath("/zookeeper", CreateMode.PERSISTENT, false, |
| RegistrySecurity.WorldReadWriteACL); |
| } finally { |
| logout(login); |
| ServiceOperations.stop(curator); |
| } |
| } |
| |
| @Test |
| public void testSystemPropertyOverwrite() { |
| System.setProperty(PROP_ZK_SASL_CLIENT_USERNAME, ""); |
| System.setProperty(PROP_ZK_SASL_CLIENT_CONTEXT, ""); |
| RegistrySecurity.setZKSaslClientProperties(ZOOKEEPER, |
| ZOOKEEPER_CLIENT_CONTEXT); |
| assertEquals(ZOOKEEPER, System.getProperty(PROP_ZK_SASL_CLIENT_USERNAME)); |
| assertEquals(ZOOKEEPER_CLIENT_CONTEXT, |
| System.getProperty(PROP_ZK_SASL_CLIENT_CONTEXT)); |
| |
| String userName = "user1"; |
| String context = "context1"; |
| System.setProperty(PROP_ZK_SASL_CLIENT_USERNAME, userName); |
| System.setProperty(PROP_ZK_SASL_CLIENT_CONTEXT, context); |
| RegistrySecurity.setZKSaslClientProperties(ZOOKEEPER, |
| ZOOKEEPER_CLIENT_CONTEXT); |
| assertEquals(userName, System.getProperty(PROP_ZK_SASL_CLIENT_USERNAME)); |
| assertEquals(context, System.getProperty(PROP_ZK_SASL_CLIENT_CONTEXT)); |
| } |
| |
| /** |
| * Start a curator service instance |
| * @param name name |
| * @param secure flag to indicate the cluster is secure |
| * @return an inited and started curator service |
| */ |
| protected CuratorService startCuratorServiceInstance(String name, |
| boolean secure) { |
| Configuration clientConf = new Configuration(); |
| clientConf.set(KEY_REGISTRY_ZK_ROOT, "/"); |
| clientConf.setBoolean(KEY_REGISTRY_SECURE, secure); |
| describe(LOG, "Starting Curator service"); |
| CuratorService curatorService = new CuratorService(name, secureZK); |
| curatorService.init(clientConf); |
| curatorService.start(); |
| LOG.info("Curator Binding {}", |
| curatorService.bindingDiagnosticDetails()); |
| return curatorService; |
| } |
| |
| /** |
| * have the ZK user create the root dir. |
| * This logs out the ZK user after and stops its curator instance, |
| * to avoid contamination |
| * @throws Throwable |
| */ |
| public void userZookeeperToCreateRoot() throws Throwable { |
| |
| System.setProperty("curator-log-events", "true"); |
| CuratorService curator = null; |
| LoginContext login = login(ZOOKEEPER_LOCALHOST, |
| ZOOKEEPER_CLIENT_CONTEXT, |
| keytab_zk); |
| try { |
| logLoginDetails(ZOOKEEPER, login); |
| RegistrySecurity.setZKSaslClientProperties(ZOOKEEPER, |
| ZOOKEEPER_CLIENT_CONTEXT); |
| curator = startCuratorServiceInstance("ZK", true); |
| LOG.info(curator.toString()); |
| |
| addToTeardown(curator); |
| curator.zkMkPath("/", CreateMode.PERSISTENT, false, |
| RegistrySecurity.WorldReadWriteACL); |
| ZKPathDumper pathDumper = curator.dumpPath(true); |
| LOG.info(pathDumper.toString()); |
| } finally { |
| logout(login); |
| ServiceOperations.stop(curator); |
| } |
| } |
| } |