1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.security.access;
20
21 import static org.apache.hadoop.hbase.AuthUtil.toGroupEntry;
22 import static org.junit.Assert.assertTrue;
23 import static org.junit.Assert.fail;
24 import static org.mockito.Mockito.mock;
25
26 import com.google.protobuf.Service;
27 import com.google.protobuf.ServiceException;
28 import java.io.IOException;
29 import java.security.PrivilegedExceptionAction;
30 import java.util.HashMap;
31 import org.apache.hadoop.conf.Configuration;
32 import org.apache.hadoop.hbase.Coprocessor;
33 import org.apache.hadoop.hbase.CoprocessorEnvironment;
34 import org.apache.hadoop.hbase.HBaseTestingUtility;
35 import org.apache.hadoop.hbase.ServerName;
36 import org.apache.hadoop.hbase.TableName;
37 import org.apache.hadoop.hbase.client.Admin;
38 import org.apache.hadoop.hbase.client.Connection;
39 import org.apache.hadoop.hbase.client.ConnectionFactory;
40 import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
41 import org.apache.hadoop.hbase.coprocessor.CoprocessorService;
42 import org.apache.hadoop.hbase.coprocessor.SingletonCoprocessorService;
43 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos;
44 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestRpcServiceProtos;
45 import org.apache.hadoop.hbase.security.AccessDeniedException;
46 import org.apache.hadoop.hbase.security.User;
47 import org.apache.hadoop.hbase.testclassification.MediumTests;
48 import org.apache.hadoop.hbase.testclassification.SecurityTests;
49 import org.junit.BeforeClass;
50 import org.junit.Test;
51 import org.junit.experimental.categories.Category;
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 @Category({SecurityTests.class, MediumTests.class})
76 public class TestAdminOnlyOperations {
77
78 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
79 private static Configuration conf;
80
81
82 private static User USER_ADMIN;
83
84 private static User USER_NON_ADMIN;
85
86 private static final String GROUP_ADMIN = "admin_group";
87 private static User USER_GROUP_ADMIN;
88
89
90 public static class DummyCpService implements Coprocessor, CoprocessorService,
91 SingletonCoprocessorService {
92 public DummyCpService() {}
93 public void start(CoprocessorEnvironment env) {}
94 public void stop(CoprocessorEnvironment env) {}
95
96 @Override
97 public Service getService() {
98 return mock(TestRpcServiceProtos.TestProtobufRpcProto.class);
99 }
100 }
101
102 private static void enableSecurity(Configuration conf) throws IOException {
103 conf.set("hadoop.security.authorization", "false");
104 conf.set("hadoop.security.authentication", "simple");
105 conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, AccessController.class.getName() +
106 "," + DummyCpService.class.getName());
107 conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, AccessController.class.getName());
108 conf.set(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY, AccessController.class.getName() +
109 "," + DummyCpService.class.getName());
110 conf.set(User.HBASE_SECURITY_AUTHORIZATION_CONF_KEY, "true");
111 SecureTestUtil.configureSuperuser(conf);
112 }
113
114 @BeforeClass
115 public static void setup() throws Exception {
116 conf = TEST_UTIL.getConfiguration();
117
118
119 enableSecurity(conf);
120 TEST_UTIL.startMiniCluster();
121
122
123 TEST_UTIL.waitUntilAllRegionsAssigned(AccessControlLists.ACL_TABLE_NAME);
124
125
126 USER_ADMIN = User.createUserForTesting(conf, "admin", new String[0]);
127 USER_NON_ADMIN = User.createUserForTesting(conf, "non_admin", new String[0]);
128 USER_GROUP_ADMIN =
129 User.createUserForTesting(conf, "user_group_admin", new String[] { GROUP_ADMIN });
130
131
132 SecureTestUtil.grantGlobal(TEST_UTIL, USER_ADMIN.getShortName(), Permission.Action.ADMIN);
133 SecureTestUtil.grantGlobal(TEST_UTIL, toGroupEntry(GROUP_ADMIN), Permission.Action.ADMIN);
134
135 }
136
137 interface Action {
138 void run(Admin admin) throws Exception;
139 }
140
141 private void verifyAllowed(User user, final Action action) throws Exception {
142 user.runAs(new PrivilegedExceptionAction<Object>() {
143 @Override
144 public Object run() throws Exception {
145 try (Connection conn = ConnectionFactory.createConnection(conf);
146 Admin admin = conn.getAdmin()) {
147 action.run(admin);
148 } catch (IOException e) {
149 fail(e.toString());
150 }
151 return null;
152 }
153 });
154 }
155
156 private void verifyDenied(User user, final Action action) throws Exception {
157 user.runAs(new PrivilegedExceptionAction<Object>() {
158 @Override
159 public Object run() throws Exception {
160 boolean accessDenied = false;
161 try (Connection conn = ConnectionFactory.createConnection(conf);
162 Admin admin = conn.getAdmin()) {
163 action.run(admin);
164 } catch (AccessDeniedException e) {
165 accessDenied = true;
166 }
167 assertTrue("Expected access to be denied", accessDenied);
168 return null;
169 }
170 });
171 }
172
173 private void verifiedDeniedServiceException(User user, final Action action) throws Exception {
174 user.runAs(new PrivilegedExceptionAction<Object>() {
175 @Override public Object run() throws Exception {
176 boolean accessDenied = false;
177 try (Connection conn = ConnectionFactory.createConnection(conf);
178 Admin admin = conn.getAdmin()) {
179 action.run(admin);
180 } catch (ServiceException e) {
181
182 if (e.getCause() instanceof AccessDeniedException) {
183 accessDenied = true;
184 }
185 }
186 assertTrue("Expected access to be denied", accessDenied);
187 return null;
188 }
189 });
190 }
191
192 private void verifyAdminCheckForAction(Action action) throws Exception {
193 verifyAllowed(USER_ADMIN, action);
194 verifyAllowed(USER_GROUP_ADMIN, action);
195 verifyDenied(USER_NON_ADMIN, action);
196 }
197
198 @Test
199 public void testEnableCatalogJanitor() throws Exception {
200 verifyAdminCheckForAction(new Action() {
201 @Override
202 public void run(Admin admin) throws Exception {
203 admin.enableCatalogJanitor(true);
204 }
205 });
206 }
207
208 @Test
209 public void testRunCatalogScan() throws Exception {
210 verifyAdminCheckForAction(new Action() {
211 @Override
212 public void run(Admin admin) throws Exception {
213 admin.runCatalogScan();
214 }
215 });
216 }
217
218 @Test
219 public void testRunCleanerChore() throws Exception {
220 verifyAdminCheckForAction(new Action() {
221 @Override public void run(Admin admin) throws Exception {
222 admin.runCleanerChore();
223 }
224 });
225 }
226
227 @Test
228 public void testSetCleanerChoreRunning() throws Exception {
229 verifyAdminCheckForAction(new Action() {
230 @Override public void run(Admin admin) throws Exception {
231 admin.setCleanerChoreRunning(true);
232 }
233 });
234 }
235
236 @Test
237 public void testExecProcedure() throws Exception {
238 verifyAdminCheckForAction(new Action() {
239 @Override public void run(Admin admin) throws Exception {
240
241 admin.execProcedure("flush-table-proc", TableName.META_TABLE_NAME.getNameAsString(),
242 new HashMap<String, String>());
243 }
244 });
245 }
246
247 @Test
248 public void testExecService() throws Exception {
249 final Action action = new Action() {
250 @Override public void run(Admin admin) throws Exception {
251 TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface service =
252 TestRpcServiceProtos.TestProtobufRpcProto.newBlockingStub(admin.coprocessorService());
253 service.ping(null, TestProtos.EmptyRequestProto.getDefaultInstance());
254 }
255 };
256
257 verifyAllowed(USER_ADMIN, action);
258 verifyAllowed(USER_GROUP_ADMIN, action);
259
260 verifiedDeniedServiceException(USER_NON_ADMIN, action);
261 }
262
263 @Test
264 public void testExecProcedureWithRet() throws Exception {
265 verifyAdminCheckForAction(new Action() {
266 @Override public void run(Admin admin) throws Exception {
267
268 admin.execProcedureWithRet("flush-table-proc", TableName.META_TABLE_NAME.getNameAsString(),
269 new HashMap<String, String>());
270 }
271 });
272 }
273
274 @Test
275 public void testNormalize() throws Exception {
276 verifyAdminCheckForAction(new Action() {
277 @Override
278 public void run(Admin admin) throws Exception {
279 admin.normalize();
280 }
281 });
282 }
283
284 @Test
285 public void testSetNormalizerRunning() throws Exception {
286 verifyAdminCheckForAction(new Action() {
287 @Override public void run(Admin admin) throws Exception {
288 admin.setNormalizerRunning(true);
289 }
290 });
291 }
292
293 @Test
294 public void testExecRegionServerService() throws Exception {
295 Action action = new Action() {
296 @Override
297 public void run(Admin admin) throws Exception {
298 ServerName serverName = TEST_UTIL.getHBaseCluster().getRegionServer(0).getServerName();
299 TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface service =
300 TestRpcServiceProtos.TestProtobufRpcProto.newBlockingStub(
301 admin.coprocessorService(serverName));
302 service.ping(null, TestProtos.EmptyRequestProto.getDefaultInstance());
303 }
304 };
305
306 verifyAllowed(USER_ADMIN, action);
307 verifyAllowed(USER_GROUP_ADMIN, action);
308 verifiedDeniedServiceException(USER_NON_ADMIN, action);
309 }
310 }
311