1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.test;
20
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertTrue;
23 import static org.junit.Assert.fail;
24
25 import java.io.IOException;
26 import java.util.List;
27
28 import org.apache.commons.cli.CommandLine;
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.hadoop.conf.Configuration;
32 import org.apache.hadoop.fs.FileSystem;
33 import org.apache.hadoop.fs.Path;
34 import org.apache.hadoop.fs.permission.FsPermission;
35 import org.apache.hadoop.hbase.HBaseConfiguration;
36 import org.apache.hadoop.hbase.IntegrationTestingUtility;
37 import org.apache.hadoop.hbase.testclassification.IntegrationTests;
38 import org.apache.hadoop.hbase.util.AbstractHBaseTool;
39 import org.apache.hadoop.hbase.util.FSUtils;
40 import org.apache.hadoop.hbase.zookeeper.RecoverableZooKeeper;
41 import org.apache.hadoop.hbase.zookeeper.ZKUtil;
42 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
43 import org.apache.hadoop.util.ToolRunner;
44 import org.apache.zookeeper.KeeperException;
45 import org.apache.zookeeper.KeeperException.Code;
46 import org.apache.zookeeper.KeeperException.NoNodeException;
47 import org.apache.zookeeper.ZooDefs.Ids;
48 import org.apache.zookeeper.ZooDefs.Perms;
49 import org.apache.zookeeper.data.ACL;
50 import org.apache.zookeeper.data.Id;
51 import org.apache.zookeeper.data.Stat;
52 import org.junit.experimental.categories.Category;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 @Category(IntegrationTests.class)
69 public class IntegrationTestZKAndFSPermissions extends AbstractHBaseTool {
70
71 private static final Log LOG = LogFactory.getLog(IntegrationTestZKAndFSPermissions.class);
72 private String superUser;
73 private String masterPrincipal;
74 private boolean isForce;
75 private String fsPerms;
76 private boolean skipFSCheck;
77 private boolean skipZKCheck;
78
79 public static final String FORCE_CHECK_ARG = "f";
80 public static final String PRINCIPAL_ARG = "p";
81 public static final String SUPERUSER_ARG = "s";
82 public static final String FS_PERMS = "fs_perms";
83 public static final String SKIP_CHECK_FS = "skip_fs_check";
84 public static final String SKIP_CHECK_ZK = "skip_zk_check";
85
86 @Override
87 public void setConf(Configuration conf) {
88 super.setConf(conf);
89 }
90
91 @Override
92 protected void addOptions() {
93 addOptNoArg(FORCE_CHECK_ARG, "Whether to skip configuration lookup and assume a secure setup");
94 addOptWithArg(PRINCIPAL_ARG, "The principal for zk authorization");
95 addOptWithArg(SUPERUSER_ARG, "The principal for super user");
96 addOptWithArg(FS_PERMS, "FS permissions, ex. 700, 750, etc. Defaults to 700");
97 addOptNoArg(SKIP_CHECK_FS, "Whether to skip checking FS permissions");
98 addOptNoArg(SKIP_CHECK_ZK, "Whether to skip checking ZK permissions");
99 }
100
101 @Override
102 protected void processOptions(CommandLine cmd) {
103 isForce = cmd.hasOption(FORCE_CHECK_ARG);
104 masterPrincipal = getShortUserName(conf.get("hbase.master.kerberos.principal"));
105 superUser = cmd.getOptionValue(SUPERUSER_ARG, conf.get("hbase.superuser"));
106 masterPrincipal = cmd.getOptionValue(PRINCIPAL_ARG, masterPrincipal);
107 fsPerms = cmd.getOptionValue(FS_PERMS, "700");
108 skipFSCheck = cmd.hasOption(SKIP_CHECK_FS);
109 skipZKCheck = cmd.hasOption(SKIP_CHECK_ZK);
110 }
111
112 private String getShortUserName(String principal) {
113 for (int i = 0; i < principal.length(); i++) {
114 if (principal.charAt(i) == '/' || principal.charAt(i) == '@') {
115 return principal.substring(0, i);
116 }
117 }
118 return principal;
119 }
120
121 @Override
122 protected int doWork() throws Exception {
123 if (!isForce) {
124 if (!"kerberos".equalsIgnoreCase(conf.get("hbase.security.authentication"))) {
125 LOG.warn("hbase.security.authentication is not kerberos, and -f is not supplied. Skip "
126 + "running the test");
127 return 0;
128 }
129 }
130
131 if (!skipZKCheck) {
132 testZNodeACLs();
133 } if (!skipFSCheck) {
134 testFSPerms();
135 }
136 return 0;
137 }
138
139 private void testZNodeACLs() throws IOException, KeeperException, InterruptedException {
140
141 ZooKeeperWatcher watcher = new ZooKeeperWatcher(conf, "IntegrationTestZnodeACLs", null);
142 RecoverableZooKeeper zk = ZKUtil.connect(this.conf, watcher);
143
144 String baseZNode = watcher.baseZNode;
145
146 LOG.info("");
147 LOG.info("***********************************************************************************");
148 LOG.info("Checking ZK permissions, root znode: " + baseZNode);
149 LOG.info("***********************************************************************************");
150 LOG.info("");
151
152 checkZnodePermsRecursive(watcher, zk, baseZNode);
153
154 LOG.info("Checking ZK permissions: SUCCESS");
155 }
156
157 private void checkZnodePermsRecursive(ZooKeeperWatcher watcher,
158 RecoverableZooKeeper zk, String znode) throws KeeperException, InterruptedException {
159
160 boolean expectedWorldReadable = watcher.isClientReadable(znode);
161
162 assertZnodePerms(zk, znode, expectedWorldReadable);
163
164 try {
165 List<String> children = zk.getChildren(znode, false);
166
167 for (String child : children) {
168 checkZnodePermsRecursive(watcher, zk, ZKUtil.joinZNode(znode, child));
169 }
170 } catch (KeeperException ke) {
171
172 if (ke.code() != Code.NOAUTH && ke.code() != Code.NONODE) {
173 throw ke;
174 }
175 }
176 }
177
178 private void assertZnodePerms(RecoverableZooKeeper zk, String znode,
179 boolean expectedWorldReadable) throws KeeperException, InterruptedException {
180 Stat stat = new Stat();
181 List<ACL> acls;
182 try {
183 acls = zk.getZooKeeper().getACL(znode, stat);
184 } catch (NoNodeException ex) {
185 LOG.debug("Caught exception for missing znode", ex);
186
187 return;
188 }
189 String[] superUsers = superUser == null ? null : superUser.split(",");
190
191 LOG.info("Checking ACLs for znode znode:" + znode + " acls:" + acls);
192
193 for (ACL acl : acls) {
194 int perms = acl.getPerms();
195 Id id = acl.getId();
196
197
198 if (Ids.ANYONE_ID_UNSAFE.equals(id)) {
199
200 assertTrue(expectedWorldReadable);
201
202 assertEquals(perms, Perms.READ);
203 } else if (superUsers != null && ZooKeeperWatcher.isSuperUserId(superUsers, id)) {
204
205 assertEquals(perms, Perms.ALL);
206 } else if (new Id("sasl", masterPrincipal).equals(id)) {
207
208 assertEquals(perms, Perms.ALL);
209 } else {
210 fail("An ACL is found which is not expected for the znode:" + znode + " , ACL:" + acl);
211 }
212 }
213 }
214
215 private void testFSPerms() throws IOException {
216 Path rootDir = FSUtils.getRootDir(conf);
217
218 LOG.info("");
219 LOG.info("***********************************************************************************");
220 LOG.info("Checking FS permissions for root dir:" + rootDir);
221 LOG.info("***********************************************************************************");
222 LOG.info("");
223 FileSystem fs = rootDir.getFileSystem(conf);
224
225 short expectedPerms = Short.valueOf(fsPerms, 8);
226
227 assertEquals(
228 FsPermission.createImmutable(expectedPerms),
229 fs.getFileStatus(rootDir).getPermission());
230
231 LOG.info("Checking FS permissions: SUCCESS");
232 }
233
234 public static void main(String[] args) throws Exception {
235 Configuration configuration = HBaseConfiguration.create();
236 IntegrationTestingUtility.setUseDistributedCluster(configuration);
237 IntegrationTestZKAndFSPermissions tool = new IntegrationTestZKAndFSPermissions();
238 int ret = ToolRunner.run(configuration, tool, args);
239 System.exit(ret);
240 }
241 }