1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.security.visibility;
19
20 import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABELS_TABLE_NAME;
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertNull;
23 import static org.junit.Assert.assertTrue;
24
25 import java.io.IOException;
26 import java.security.PrivilegedExceptionAction;
27 import java.util.ArrayList;
28 import java.util.List;
29
30 import org.apache.hadoop.conf.Configuration;
31 import org.apache.hadoop.hbase.HBaseTestingUtility;
32 import org.apache.hadoop.hbase.HConstants;
33 import org.apache.hadoop.hbase.testclassification.MediumTests;
34 import org.apache.hadoop.hbase.TableName;
35 import org.apache.hadoop.hbase.client.Get;
36 import org.apache.hadoop.hbase.client.HTable;
37 import org.apache.hadoop.hbase.client.Put;
38 import org.apache.hadoop.hbase.client.Result;
39 import org.apache.hadoop.hbase.client.ResultScanner;
40 import org.apache.hadoop.hbase.client.Scan;
41 import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.GetAuthsResponse;
42 import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsResponse;
43 import org.apache.hadoop.hbase.security.User;
44 import org.apache.hadoop.hbase.security.access.AccessControlLists;
45 import org.apache.hadoop.hbase.security.access.AccessController;
46 import org.apache.hadoop.hbase.security.access.Permission;
47 import org.apache.hadoop.hbase.security.access.SecureTestUtil;
48 import org.apache.hadoop.hbase.util.Bytes;
49 import org.junit.AfterClass;
50 import org.junit.BeforeClass;
51 import org.junit.Rule;
52 import org.junit.Test;
53 import org.junit.experimental.categories.Category;
54 import org.junit.rules.TestName;
55
56 import com.google.protobuf.ByteString;
57
58 @Category(MediumTests.class)
59 public class TestVisibilityLabelsWithACL {
60
61 private static final String PRIVATE = "private";
62 private static final String CONFIDENTIAL = "confidential";
63 private static final String SECRET = "secret";
64 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
65 private static final byte[] row1 = Bytes.toBytes("row1");
66 private final static byte[] fam = Bytes.toBytes("info");
67 private final static byte[] qual = Bytes.toBytes("qual");
68 private final static byte[] value = Bytes.toBytes("value");
69 private static Configuration conf;
70
71 @Rule
72 public final TestName TEST_NAME = new TestName();
73 private static User SUPERUSER;
74 private static User NORMAL_USER1;
75 private static User NORMAL_USER2;
76
77 @BeforeClass
78 public static void setupBeforeClass() throws Exception {
79
80 conf = TEST_UTIL.getConfiguration();
81 SecureTestUtil.enableSecurity(conf);
82 conf.set("hbase.coprocessor.master.classes", AccessController.class.getName() + ","
83 + VisibilityController.class.getName());
84 conf.set("hbase.coprocessor.region.classes", AccessController.class.getName() + ","
85 + VisibilityController.class.getName());
86 TEST_UTIL.startMiniCluster(2);
87
88 TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME.getName(), 50000);
89
90 TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000);
91 addLabels();
92
93
94 SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
95 NORMAL_USER1 = User.createUserForTesting(conf, "user1", new String[] {});
96 NORMAL_USER2 = User.createUserForTesting(conf, "user2", new String[] {});
97
98
99
100 SecureTestUtil.grantOnTable(TEST_UTIL, NORMAL_USER1.getShortName(), LABELS_TABLE_NAME,
101 null, null, Permission.Action.EXEC);
102 SecureTestUtil.grantOnTable(TEST_UTIL, NORMAL_USER2.getShortName(), LABELS_TABLE_NAME,
103 null, null, Permission.Action.EXEC);
104 }
105
106 @AfterClass
107 public static void tearDownAfterClass() throws Exception {
108 TEST_UTIL.shutdownMiniCluster();
109 }
110
111 @Test
112 public void testScanForUserWithFewerLabelAuthsThanLabelsInScanAuthorizations() throws Throwable {
113 String[] auths = { SECRET };
114 String user = "user2";
115 VisibilityClient.setAuths(conf, auths, user);
116 TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
117 final HTable table = createTableAndWriteDataWithLabels(tableName, SECRET + "&" + CONFIDENTIAL
118 + "&!" + PRIVATE, SECRET + "&!" + PRIVATE);
119 SecureTestUtil.grantOnTable(TEST_UTIL, NORMAL_USER2.getShortName(), tableName,
120 null, null, Permission.Action.READ);
121 PrivilegedExceptionAction<Void> scanAction = new PrivilegedExceptionAction<Void>() {
122 public Void run() throws Exception {
123 Scan s = new Scan();
124 s.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL));
125 HTable t = new HTable(conf, table.getTableName());
126 try {
127 ResultScanner scanner = t.getScanner(s);
128 Result result = scanner.next();
129 assertTrue(!result.isEmpty());
130 assertTrue(Bytes.equals(Bytes.toBytes("row2"), result.getRow()));
131 result = scanner.next();
132 assertNull(result);
133 } finally {
134 t.close();
135 }
136 return null;
137 }
138 };
139 NORMAL_USER2.runAs(scanAction);
140 }
141
142 @Test
143 public void testScanForSuperUserWithFewerLabelAuths() throws Throwable {
144 String[] auths = { SECRET };
145 String user = "admin";
146 VisibilityClient.setAuths(conf, auths, user);
147 TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
148 final HTable table = createTableAndWriteDataWithLabels(tableName, SECRET + "&" + CONFIDENTIAL
149 + "&!" + PRIVATE, SECRET + "&!" + PRIVATE);
150 PrivilegedExceptionAction<Void> scanAction = new PrivilegedExceptionAction<Void>() {
151 public Void run() throws Exception {
152 Scan s = new Scan();
153 s.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL));
154 HTable t = new HTable(conf, table.getTableName());
155 try {
156 ResultScanner scanner = t.getScanner(s);
157 Result[] result = scanner.next(5);
158 assertTrue(result.length == 2);
159 } finally {
160 t.close();
161 }
162 return null;
163 }
164 };
165 SUPERUSER.runAs(scanAction);
166 }
167
168 @Test
169 public void testGetForSuperUserWithFewerLabelAuths() throws Throwable {
170 String[] auths = { SECRET };
171 String user = "admin";
172 VisibilityClient.setAuths(conf, auths, user);
173 TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
174 final HTable table = createTableAndWriteDataWithLabels(tableName, SECRET + "&" + CONFIDENTIAL
175 + "&!" + PRIVATE, SECRET + "&!" + PRIVATE);
176 PrivilegedExceptionAction<Void> scanAction = new PrivilegedExceptionAction<Void>() {
177 public Void run() throws Exception {
178 Get g = new Get(row1);
179 g.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL));
180 HTable t = new HTable(conf, table.getTableName());
181 try {
182 Result result = t.get(g);
183 assertTrue(!result.isEmpty());
184 } finally {
185 t.close();
186 }
187 return null;
188 }
189 };
190 SUPERUSER.runAs(scanAction);
191 }
192
193 @Test
194 public void testVisibilityLabelsForUserWithNoAuths() throws Throwable {
195 String user = "admin";
196 String[] auths = { SECRET };
197 VisibilityClient.clearAuths(conf, auths, user);
198 VisibilityClient.setAuths(conf, auths, "user1");
199 TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
200 final HTable table = createTableAndWriteDataWithLabels(tableName, SECRET);
201 SecureTestUtil.grantOnTable(TEST_UTIL, NORMAL_USER1.getShortName(), tableName,
202 null, null, Permission.Action.READ);
203 SecureTestUtil.grantOnTable(TEST_UTIL, NORMAL_USER2.getShortName(), tableName,
204 null, null, Permission.Action.READ);
205 PrivilegedExceptionAction<Void> getAction = new PrivilegedExceptionAction<Void>() {
206 public Void run() throws Exception {
207 Get g = new Get(row1);
208 g.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL));
209 HTable t = new HTable(conf, table.getTableName());
210 try {
211 Result result = t.get(g);
212 assertTrue(result.isEmpty());
213 } finally {
214 t.close();
215 }
216 return null;
217 }
218 };
219 NORMAL_USER2.runAs(getAction);
220 }
221
222 @Test
223 public void testLabelsTableOpsWithDifferentUsers() throws Throwable {
224 PrivilegedExceptionAction<VisibilityLabelsResponse> action =
225 new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
226 public VisibilityLabelsResponse run() throws Exception {
227 try {
228 return VisibilityClient.addLabels(conf, new String[] { "l1", "l2" });
229 } catch (Throwable e) {
230 }
231 return null;
232 }
233 };
234 VisibilityLabelsResponse response = NORMAL_USER1.runAs(action);
235 assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response
236 .getResult(0).getException().getName());
237 assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response
238 .getResult(1).getException().getName());
239
240 action = new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
241 public VisibilityLabelsResponse run() throws Exception {
242 try {
243 return VisibilityClient.setAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user1");
244 } catch (Throwable e) {
245 }
246 return null;
247 }
248 };
249 response = NORMAL_USER1.runAs(action);
250 assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response
251 .getResult(0).getException().getName());
252 assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response
253 .getResult(1).getException().getName());
254
255 action = new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
256 public VisibilityLabelsResponse run() throws Exception {
257 try {
258 return VisibilityClient.setAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user1");
259 } catch (Throwable e) {
260 }
261 return null;
262 }
263 };
264 response = SUPERUSER.runAs(action);
265 assertTrue(response.getResult(0).getException().getValue().isEmpty());
266 assertTrue(response.getResult(1).getException().getValue().isEmpty());
267
268 action = new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
269 public VisibilityLabelsResponse run() throws Exception {
270 try {
271 return VisibilityClient.clearAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user1");
272 } catch (Throwable e) {
273 }
274 return null;
275 }
276 };
277 response = NORMAL_USER1.runAs(action);
278 assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response.getResult(0)
279 .getException().getName());
280 assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response.getResult(1)
281 .getException().getName());
282
283 response = VisibilityClient.clearAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user1");
284 assertTrue(response.getResult(0).getException().getValue().isEmpty());
285 assertTrue(response.getResult(1).getException().getValue().isEmpty());
286
287 VisibilityClient.setAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user3");
288 PrivilegedExceptionAction<GetAuthsResponse> action1 =
289 new PrivilegedExceptionAction<GetAuthsResponse>() {
290 public GetAuthsResponse run() throws Exception {
291 try {
292 return VisibilityClient.getAuths(conf, "user3");
293 } catch (Throwable e) {
294 }
295 return null;
296 }
297 };
298 GetAuthsResponse authsResponse = NORMAL_USER1.runAs(action1);
299 assertNull(authsResponse);
300 authsResponse = SUPERUSER.runAs(action1);
301 List<String> authsList = new ArrayList<String>();
302 for (ByteString authBS : authsResponse.getAuthList()) {
303 authsList.add(Bytes.toString(authBS.toByteArray()));
304 }
305 assertEquals(2, authsList.size());
306 assertTrue(authsList.contains(CONFIDENTIAL));
307 assertTrue(authsList.contains(PRIVATE));
308 }
309
310 private static HTable createTableAndWriteDataWithLabels(TableName tableName, String... labelExps)
311 throws Exception {
312 HTable table = null;
313 try {
314 table = TEST_UTIL.createTable(tableName, fam);
315 int i = 1;
316 List<Put> puts = new ArrayList<Put>();
317 for (String labelExp : labelExps) {
318 Put put = new Put(Bytes.toBytes("row" + i));
319 put.add(fam, qual, HConstants.LATEST_TIMESTAMP, value);
320 put.setCellVisibility(new CellVisibility(labelExp));
321 puts.add(put);
322 i++;
323 }
324 table.put(puts);
325 } finally {
326 if (table != null) {
327 table.close();
328 }
329 }
330 return table;
331 }
332
333 private static void addLabels() throws IOException {
334 String[] labels = { SECRET, CONFIDENTIAL, PRIVATE };
335 try {
336 VisibilityClient.addLabels(conf, labels);
337 } catch (Throwable t) {
338 throw new IOException(t);
339 }
340 }
341 }