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 SecureTestUtil.enableSecurity(conf);
84 conf.set("hbase.coprocessor.master.classes", AccessController.class.getName() + ","
85 + VisibilityController.class.getName());
86 conf.set("hbase.coprocessor.region.classes", AccessController.class.getName() + ","
87 + VisibilityController.class.getName());
88 TEST_UTIL.startMiniCluster(2);
89
90 TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME.getName(), 50000);
91
92 TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000);
93 addLabels();
94
95
96 SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
97 NORMAL_USER1 = User.createUserForTesting(conf, "user1", new String[] {});
98 NORMAL_USER2 = User.createUserForTesting(conf, "user2", new String[] {});
99
100
101
102 SecureTestUtil.grantOnTable(TEST_UTIL, NORMAL_USER1.getShortName(), LABELS_TABLE_NAME,
103 null, null, Permission.Action.EXEC);
104 SecureTestUtil.grantOnTable(TEST_UTIL, NORMAL_USER2.getShortName(), LABELS_TABLE_NAME,
105 null, null, Permission.Action.EXEC);
106 }
107
108 @AfterClass
109 public static void tearDownAfterClass() throws Exception {
110 TEST_UTIL.shutdownMiniCluster();
111 }
112
113 @Test
114 public void testScanForUserWithFewerLabelAuthsThanLabelsInScanAuthorizations() throws Throwable {
115 String[] auths = { SECRET };
116 String user = "user2";
117 VisibilityClient.setAuths(conf, auths, user);
118 TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
119 final Table table = createTableAndWriteDataWithLabels(tableName, SECRET + "&" + CONFIDENTIAL
120 + "&!" + PRIVATE, SECRET + "&!" + PRIVATE);
121 SecureTestUtil.grantOnTable(TEST_UTIL, NORMAL_USER2.getShortName(), tableName,
122 null, null, Permission.Action.READ);
123 PrivilegedExceptionAction<Void> scanAction = new PrivilegedExceptionAction<Void>() {
124 public Void run() throws Exception {
125 Scan s = new Scan();
126 s.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL));
127 try (Connection connection = ConnectionFactory.createConnection(conf);
128 Table t = connection.getTable(table.getName())) {
129 ResultScanner scanner = t.getScanner(s);
130 Result result = scanner.next();
131 assertTrue(!result.isEmpty());
132 assertTrue(Bytes.equals(Bytes.toBytes("row2"), result.getRow()));
133 result = scanner.next();
134 assertNull(result);
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 Table 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 try (Connection connection = ConnectionFactory.createConnection(conf);
155 Table t = connection.getTable(table.getName())) {
156 ResultScanner scanner = t.getScanner(s);
157 Result[] result = scanner.next(5);
158 assertTrue(result.length == 2);
159 }
160 return null;
161 }
162 };
163 SUPERUSER.runAs(scanAction);
164 }
165
166 @Test
167 public void testGetForSuperUserWithFewerLabelAuths() throws Throwable {
168 String[] auths = { SECRET };
169 String user = "admin";
170 VisibilityClient.setAuths(conf, auths, user);
171 TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
172 final Table table = createTableAndWriteDataWithLabels(tableName, SECRET + "&" + CONFIDENTIAL
173 + "&!" + PRIVATE, SECRET + "&!" + PRIVATE);
174 PrivilegedExceptionAction<Void> scanAction = new PrivilegedExceptionAction<Void>() {
175 public Void run() throws Exception {
176 Get g = new Get(row1);
177 g.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL));
178 try (Connection connection = ConnectionFactory.createConnection(conf);
179 Table t = connection.getTable(table.getName())) {
180 Result result = t.get(g);
181 assertTrue(!result.isEmpty());
182 }
183 return null;
184 }
185 };
186 SUPERUSER.runAs(scanAction);
187 }
188
189 @Test
190 public void testVisibilityLabelsForUserWithNoAuths() throws Throwable {
191 String user = "admin";
192 String[] auths = { SECRET };
193 VisibilityClient.clearAuths(conf, auths, user);
194 VisibilityClient.setAuths(conf, auths, "user1");
195 TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
196 final Table table = createTableAndWriteDataWithLabels(tableName, SECRET);
197 SecureTestUtil.grantOnTable(TEST_UTIL, NORMAL_USER1.getShortName(), tableName,
198 null, null, Permission.Action.READ);
199 SecureTestUtil.grantOnTable(TEST_UTIL, NORMAL_USER2.getShortName(), tableName,
200 null, null, Permission.Action.READ);
201 PrivilegedExceptionAction<Void> getAction = new PrivilegedExceptionAction<Void>() {
202 public Void run() throws Exception {
203 Get g = new Get(row1);
204 g.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL));
205 try (Connection connection = ConnectionFactory.createConnection(conf);
206 Table t = connection.getTable(table.getName())) {
207 Result result = t.get(g);
208 assertTrue(result.isEmpty());
209 }
210 return null;
211 }
212 };
213 NORMAL_USER2.runAs(getAction);
214 }
215
216 @Test
217 public void testLabelsTableOpsWithDifferentUsers() throws Throwable {
218 PrivilegedExceptionAction<VisibilityLabelsResponse> action =
219 new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
220 public VisibilityLabelsResponse run() throws Exception {
221 try {
222 return VisibilityClient.addLabels(conf, new String[] { "l1", "l2" });
223 } catch (Throwable e) {
224 }
225 return null;
226 }
227 };
228 VisibilityLabelsResponse response = NORMAL_USER1.runAs(action);
229 assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response
230 .getResult(0).getException().getName());
231 assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response
232 .getResult(1).getException().getName());
233
234 action = new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
235 public VisibilityLabelsResponse run() throws Exception {
236 try {
237 return VisibilityClient.setAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user1");
238 } catch (Throwable e) {
239 }
240 return null;
241 }
242 };
243 response = NORMAL_USER1.runAs(action);
244 assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response
245 .getResult(0).getException().getName());
246 assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response
247 .getResult(1).getException().getName());
248
249 action = new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
250 public VisibilityLabelsResponse run() throws Exception {
251 try {
252 return VisibilityClient.setAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user1");
253 } catch (Throwable e) {
254 }
255 return null;
256 }
257 };
258 response = SUPERUSER.runAs(action);
259 assertTrue(response.getResult(0).getException().getValue().isEmpty());
260 assertTrue(response.getResult(1).getException().getValue().isEmpty());
261
262 action = new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
263 public VisibilityLabelsResponse run() throws Exception {
264 try {
265 return VisibilityClient.clearAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user1");
266 } catch (Throwable e) {
267 }
268 return null;
269 }
270 };
271 response = NORMAL_USER1.runAs(action);
272 assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response.getResult(0)
273 .getException().getName());
274 assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response.getResult(1)
275 .getException().getName());
276
277 response = VisibilityClient.clearAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user1");
278 assertTrue(response.getResult(0).getException().getValue().isEmpty());
279 assertTrue(response.getResult(1).getException().getValue().isEmpty());
280
281 VisibilityClient.setAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user3");
282 PrivilegedExceptionAction<GetAuthsResponse> action1 =
283 new PrivilegedExceptionAction<GetAuthsResponse>() {
284 public GetAuthsResponse run() throws Exception {
285 try {
286 return VisibilityClient.getAuths(conf, "user3");
287 } catch (Throwable e) {
288 }
289 return null;
290 }
291 };
292 GetAuthsResponse authsResponse = NORMAL_USER1.runAs(action1);
293 assertNull(authsResponse);
294 authsResponse = SUPERUSER.runAs(action1);
295 List<String> authsList = new ArrayList<String>();
296 for (ByteString authBS : authsResponse.getAuthList()) {
297 authsList.add(Bytes.toString(authBS.toByteArray()));
298 }
299 assertEquals(2, authsList.size());
300 assertTrue(authsList.contains(CONFIDENTIAL));
301 assertTrue(authsList.contains(PRIVATE));
302 }
303
304 private static Table createTableAndWriteDataWithLabels(TableName tableName, String... labelExps)
305 throws Exception {
306 Table table = null;
307 try {
308 table = TEST_UTIL.createTable(tableName, fam);
309 int i = 1;
310 List<Put> puts = new ArrayList<Put>();
311 for (String labelExp : labelExps) {
312 Put put = new Put(Bytes.toBytes("row" + i));
313 put.add(fam, qual, HConstants.LATEST_TIMESTAMP, value);
314 put.setCellVisibility(new CellVisibility(labelExp));
315 puts.add(put);
316 i++;
317 }
318 table.put(puts);
319 } finally {
320 if (table != null) {
321 table.close();
322 }
323 }
324 return table;
325 }
326
327 private static void addLabels() throws IOException {
328 String[] labels = { SECRET, CONFIDENTIAL, PRIVATE };
329 try {
330 VisibilityClient.addLabels(conf, labels);
331 } catch (Throwable t) {
332 throw new IOException(t);
333 }
334 }
335 }