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