2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org
.apache
.hadoop
.hbase
.zookeeper
;
20 import static org
.junit
.Assert
.assertEquals
;
21 import static org
.junit
.Assert
.assertTrue
;
24 import java
.io
.FileWriter
;
25 import java
.io
.IOException
;
26 import java
.util
.ArrayList
;
27 import java
.util
.List
;
29 import javax
.security
.auth
.login
.AppConfigurationEntry
;
31 import org
.apache
.hadoop
.conf
.Configuration
;
32 import org
.apache
.hadoop
.hbase
.HBaseConfiguration
;
33 import org
.apache
.hadoop
.hbase
.HBaseTestingUtility
;
34 import org
.apache
.hadoop
.hbase
.HConstants
;
35 import org
.apache
.hadoop
.hbase
.ServerName
;
36 import org
.apache
.hadoop
.hbase
.TestZooKeeper
;
37 import org
.apache
.hadoop
.hbase
.testclassification
.MediumTests
;
38 import org
.apache
.hadoop
.hbase
.testclassification
.ZKTests
;
39 import org
.apache
.zookeeper
.ZooDefs
;
40 import org
.apache
.zookeeper
.data
.ACL
;
41 import org
.apache
.zookeeper
.data
.Stat
;
42 import org
.junit
.AfterClass
;
43 import org
.junit
.Before
;
44 import org
.junit
.BeforeClass
;
45 import org
.junit
.Test
;
46 import org
.junit
.experimental
.categories
.Category
;
47 import org
.slf4j
.Logger
;
48 import org
.slf4j
.LoggerFactory
;
50 @Category({ ZKTests
.class, MediumTests
.class })
51 public class TestZooKeeperACL
{
52 private final static Logger LOG
= LoggerFactory
.getLogger(TestZooKeeperACL
.class);
53 private final static HBaseTestingUtility TEST_UTIL
=
54 new HBaseTestingUtility();
56 private static ZKWatcher zkw
;
57 private static boolean secureZKAvailable
;
60 public static void setUpBeforeClass() throws Exception
{
61 File saslConfFile
= File
.createTempFile("tmp", "jaas.conf");
62 FileWriter fwriter
= new FileWriter(saslConfFile
);
66 "org.apache.zookeeper.server.auth.DigestLoginModule required\n" +
67 "user_hbase=\"secret\";\n" +
70 "org.apache.zookeeper.server.auth.DigestLoginModule required\n" +
71 "username=\"hbase\"\n" +
72 "password=\"secret\";\n" +
75 System
.setProperty("java.security.auth.login.config",
76 saslConfFile
.getAbsolutePath());
77 System
.setProperty("zookeeper.authProvider.1",
78 "org.apache.zookeeper.server.auth.SASLAuthenticationProvider");
80 TEST_UTIL
.getConfiguration().setInt("hbase.zookeeper.property.maxClientCnxns", 1000);
82 // If Hadoop is missing HADOOP-7070 the cluster will fail to start due to
83 // the JAAS configuration required by ZK being clobbered by Hadoop
85 TEST_UTIL
.startMiniCluster();
86 } catch (IOException e
) {
87 LOG
.warn("Hadoop is missing HADOOP-7070", e
);
88 secureZKAvailable
= false;
92 new Configuration(TEST_UTIL
.getConfiguration()),
93 TestZooKeeper
.class.getName(), null);
97 public static void tearDownAfterClass() throws Exception
{
98 if (!secureZKAvailable
) {
101 TEST_UTIL
.shutdownMiniCluster();
105 public void setUp() throws Exception
{
106 if (!secureZKAvailable
) {
109 TEST_UTIL
.ensureSomeRegionServersAvailable(2);
113 * Create a node and check its ACL. When authentication is enabled on
114 * ZooKeeper, all nodes (except /hbase/root-region-server, /hbase/master
115 * and /hbase/hbaseid) should be created so that only the hbase server user
116 * (master or region server user) that created them can access them, and
117 * this user should have all permissions on this node. For
118 * /hbase/root-region-server, /hbase/master, and /hbase/hbaseid the
119 * permissions should be as above, but should also be world-readable. First
120 * we check the general case of /hbase nodes in the following test, and
121 * then check the subset of world-readable nodes in the three tests after
124 @Test (timeout
=30000)
125 public void testHBaseRootZNodeACL() throws Exception
{
126 if (!secureZKAvailable
) {
130 List
<ACL
> acls
= zkw
.getRecoverableZooKeeper().getZooKeeper()
131 .getACL("/hbase", new Stat());
132 assertEquals(1, acls
.size());
133 assertEquals("sasl", acls
.get(0).getId().getScheme());
134 assertEquals("hbase", acls
.get(0).getId().getId());
135 assertEquals(ZooDefs
.Perms
.ALL
, acls
.get(0).getPerms());
139 * When authentication is enabled on ZooKeeper, /hbase/root-region-server
140 * should be created with 2 ACLs: one specifies that the hbase user has
141 * full access to the node; the other, that it is world-readable.
143 @Test (timeout
=30000)
144 public void testHBaseRootRegionServerZNodeACL() throws Exception
{
145 if (!secureZKAvailable
) {
149 List
<ACL
> acls
= zkw
.getRecoverableZooKeeper().getZooKeeper()
150 .getACL("/hbase/root-region-server", new Stat());
151 assertEquals(2, acls
.size());
153 boolean foundWorldReadableAcl
= false;
154 boolean foundHBaseOwnerAcl
= false;
155 for(int i
= 0; i
< 2; i
++) {
156 if (acls
.get(i
).getId().getScheme().equals("world") == true) {
157 assertEquals("anyone", acls
.get(0).getId().getId());
158 assertEquals(ZooDefs
.Perms
.READ
, acls
.get(0).getPerms());
159 foundWorldReadableAcl
= true;
162 if (acls
.get(i
).getId().getScheme().equals("sasl") == true) {
163 assertEquals("hbase", acls
.get(1).getId().getId());
164 assertEquals("sasl", acls
.get(1).getId().getScheme());
165 foundHBaseOwnerAcl
= true;
166 } else { // error: should not get here: test fails.
171 assertTrue(foundWorldReadableAcl
);
172 assertTrue(foundHBaseOwnerAcl
);
176 * When authentication is enabled on ZooKeeper, /hbase/master should be
177 * created with 2 ACLs: one specifies that the hbase user has full access
178 * to the node; the other, that it is world-readable.
180 @Test (timeout
=30000)
181 public void testHBaseMasterServerZNodeACL() throws Exception
{
182 if (!secureZKAvailable
) {
186 List
<ACL
> acls
= zkw
.getRecoverableZooKeeper().getZooKeeper()
187 .getACL("/hbase/master", new Stat());
188 assertEquals(2, acls
.size());
190 boolean foundWorldReadableAcl
= false;
191 boolean foundHBaseOwnerAcl
= false;
192 for(int i
= 0; i
< 2; i
++) {
193 if (acls
.get(i
).getId().getScheme().equals("world") == true) {
194 assertEquals("anyone", acls
.get(0).getId().getId());
195 assertEquals(ZooDefs
.Perms
.READ
, acls
.get(0).getPerms());
196 foundWorldReadableAcl
= true;
198 if (acls
.get(i
).getId().getScheme().equals("sasl") == true) {
199 assertEquals("hbase", acls
.get(1).getId().getId());
200 assertEquals("sasl", acls
.get(1).getId().getScheme());
201 foundHBaseOwnerAcl
= true;
202 } else { // error: should not get here: test fails.
207 assertTrue(foundWorldReadableAcl
);
208 assertTrue(foundHBaseOwnerAcl
);
212 * When authentication is enabled on ZooKeeper, /hbase/hbaseid should be
213 * created with 2 ACLs: one specifies that the hbase user has full access
214 * to the node; the other, that it is world-readable.
216 @Test (timeout
=30000)
217 public void testHBaseIDZNodeACL() throws Exception
{
218 if (!secureZKAvailable
) {
222 List
<ACL
> acls
= zkw
.getRecoverableZooKeeper().getZooKeeper()
223 .getACL("/hbase/hbaseid", new Stat());
224 assertEquals(2, acls
.size());
226 boolean foundWorldReadableAcl
= false;
227 boolean foundHBaseOwnerAcl
= false;
228 for(int i
= 0; i
< 2; i
++) {
229 if (acls
.get(i
).getId().getScheme().equals("world") == true) {
230 assertEquals("anyone", acls
.get(0).getId().getId());
231 assertEquals(ZooDefs
.Perms
.READ
, acls
.get(0).getPerms());
232 foundWorldReadableAcl
= true;
234 if (acls
.get(i
).getId().getScheme().equals("sasl") == true) {
235 assertEquals("hbase", acls
.get(1).getId().getId());
236 assertEquals("sasl", acls
.get(1).getId().getScheme());
237 foundHBaseOwnerAcl
= true;
238 } else { // error: should not get here: test fails.
243 assertTrue(foundWorldReadableAcl
);
244 assertTrue(foundHBaseOwnerAcl
);
248 * Finally, we check the ACLs of a node outside of the /hbase hierarchy and
249 * verify that its ACL is simply 'hbase:Perms.ALL'.
252 public void testOutsideHBaseNodeACL() throws Exception
{
253 if (!secureZKAvailable
) {
257 ZKUtil
.createWithParents(zkw
, "/testACLNode");
258 List
<ACL
> acls
= zkw
.getRecoverableZooKeeper().getZooKeeper()
259 .getACL("/testACLNode", new Stat());
260 assertEquals(1, acls
.size());
261 assertEquals("sasl", acls
.get(0).getId().getScheme());
262 assertEquals("hbase", acls
.get(0).getId().getId());
263 assertEquals(ZooDefs
.Perms
.ALL
, acls
.get(0).getPerms());
267 * Check if ZooKeeper JaasConfiguration is valid.
270 public void testIsZooKeeperSecure() throws Exception
{
271 boolean testJaasConfig
=
272 ZKUtil
.isSecureZooKeeper(new Configuration(TEST_UTIL
.getConfiguration()));
273 assertEquals(testJaasConfig
, secureZKAvailable
);
274 // Define Jaas configuration without ZooKeeper Jaas config
275 File saslConfFile
= File
.createTempFile("tmp", "fakeJaas.conf");
276 FileWriter fwriter
= new FileWriter(saslConfFile
);
280 System
.setProperty("java.security.auth.login.config",
281 saslConfFile
.getAbsolutePath());
283 testJaasConfig
= ZKUtil
.isSecureZooKeeper(new Configuration(TEST_UTIL
.getConfiguration()));
284 assertEquals(false, testJaasConfig
);
285 saslConfFile
.delete();
289 * Check if Programmatic way of setting zookeeper security settings is valid.
292 public void testIsZooKeeperSecureWithProgrammaticConfig() throws Exception
{
294 javax
.security
.auth
.login
.Configuration
.setConfiguration(new DummySecurityConfiguration());
296 Configuration config
= new Configuration(HBaseConfiguration
.create());
297 boolean testJaasConfig
= ZKUtil
.isSecureZooKeeper(config
);
298 assertEquals(false, testJaasConfig
);
300 // Now set authentication scheme to Kerberos still it should return false
301 // because no configuration set
302 config
.set("hbase.security.authentication", "kerberos");
303 testJaasConfig
= ZKUtil
.isSecureZooKeeper(config
);
304 assertEquals(false, testJaasConfig
);
306 // Now set programmatic options related to security
307 config
.set(HConstants
.ZK_CLIENT_KEYTAB_FILE
, "/dummy/file");
308 config
.set(HConstants
.ZK_CLIENT_KERBEROS_PRINCIPAL
, "dummy");
309 config
.set(HConstants
.ZK_SERVER_KEYTAB_FILE
, "/dummy/file");
310 config
.set(HConstants
.ZK_SERVER_KERBEROS_PRINCIPAL
, "dummy");
311 testJaasConfig
= ZKUtil
.isSecureZooKeeper(config
);
312 assertEquals(true, testJaasConfig
);
315 private static class DummySecurityConfiguration
extends javax
.security
.auth
.login
.Configuration
{
317 public AppConfigurationEntry
[] getAppConfigurationEntry(String name
) {
322 @Test(timeout
= 10000)
323 public void testAdminDrainAllowedOnSecureZK() throws Exception
{
324 if (!secureZKAvailable
) {
327 List
<ServerName
> decommissionedServers
= new ArrayList
<>(1);
328 decommissionedServers
.add(ServerName
.parseServerName("ZZZ,123,123"));
330 // If unable to connect to secure ZK cluster then this operation would fail.
331 TEST_UTIL
.getAdmin().decommissionRegionServers(decommissionedServers
, false);
333 decommissionedServers
= TEST_UTIL
.getAdmin().listDecommissionedRegionServers();
334 assertEquals(1, decommissionedServers
.size());
335 assertEquals(ServerName
.parseServerName("ZZZ,123,123"), decommissionedServers
.get(0));
337 TEST_UTIL
.getAdmin().recommissionRegionServer(decommissionedServers
.get(0), null);
338 decommissionedServers
= TEST_UTIL
.getAdmin().listDecommissionedRegionServers();
339 assertEquals(0, decommissionedServers
.size());