View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
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.apache.hadoop.hbase.security.visibility.VisibilityUtils.SYSTEM_LABEL;
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertTrue;
24  import static org.junit.Assert.assertFalse;
25  import static org.junit.Assert.fail;
26  
27  import java.io.IOException;
28  import java.security.PrivilegedExceptionAction;
29  import java.util.List;
30  import java.util.concurrent.atomic.AtomicBoolean;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.apache.hadoop.hbase.HConstants;
35  import org.apache.hadoop.hbase.TableName;
36  import org.apache.hadoop.hbase.testclassification.MediumTests;
37  import org.apache.hadoop.hbase.client.HTable;
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.ProtobufUtil;
42  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionActionResult;
43  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.NameBytesPair;
44  import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.ListLabelsResponse;
45  import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsResponse;
46  import org.apache.hadoop.hbase.security.User;
47  import org.apache.hadoop.hbase.util.Bytes;
48  import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;
49  import org.apache.hadoop.hbase.util.Threads;
50  import org.junit.Assert;
51  import org.junit.BeforeClass;
52  import org.junit.Test;
53  import org.junit.experimental.categories.Category;
54  
55  import com.google.protobuf.ByteString;
56  
57  @Category(MediumTests.class)
58  public class TestVisibilityLabelsWithDefaultVisLabelService extends TestVisibilityLabels {
59    final Log LOG = LogFactory.getLog(getClass());
60  
61    @BeforeClass
62    public static void setupBeforeClass() throws Exception {
63      // setup configuration
64      conf = TEST_UTIL.getConfiguration();
65      conf.setBoolean(HConstants.DISTRIBUTED_LOG_REPLAY_KEY, false);
66      conf.setBoolean("hbase.online.schema.update.enable", true);
67      VisibilityTestUtil.enableVisiblityLabels(conf);
68      conf.setClass(VisibilityUtils.VISIBILITY_LABEL_GENERATOR_CLASS, SimpleScanLabelGenerator.class,
69          ScanLabelGenerator.class);
70      conf.set("hbase.superuser", "admin");
71      TEST_UTIL.startMiniCluster(2);
72      SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
73      USER1 = User.createUserForTesting(conf, "user1", new String[] {});
74  
75      // Wait for the labels table to become available
76      TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000);
77      addLabels();
78    }
79  
80    @Test
81    public void testAddLabels() throws Throwable {
82      PrivilegedExceptionAction<VisibilityLabelsResponse> action =
83          new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
84        public VisibilityLabelsResponse run() throws Exception {
85          String[] labels = { "L1", SECRET, "L2", "invalid~", "L3" };
86          VisibilityLabelsResponse response = null;
87          try {
88            response = VisibilityClient.addLabels(conf, labels);
89          } catch (Throwable e) {
90            fail("Should not have thrown exception");
91          }
92          List<RegionActionResult> resultList = response.getResultList();
93          assertEquals(5, resultList.size());
94          assertTrue(resultList.get(0).getException().getValue().isEmpty());
95          assertEquals("org.apache.hadoop.hbase.DoNotRetryIOException", resultList.get(1)
96              .getException().getName());
97          assertTrue(Bytes.toString(resultList.get(1).getException().getValue().toByteArray())
98              .contains(
99                  "org.apache.hadoop.hbase.security.visibility.LabelAlreadyExistsException: "
100                     + "Label 'secret' already exists"));
101         assertTrue(resultList.get(2).getException().getValue().isEmpty());
102         assertTrue(resultList.get(3).getException().getValue().isEmpty());
103         assertTrue(resultList.get(4).getException().getValue().isEmpty());
104         return null;
105       }
106     };
107     SUPERUSER.runAs(action);
108   }
109 
110   @Test(timeout = 60 * 1000)
111   public void testAddVisibilityLabelsOnRSRestart() throws Exception {
112     List<RegionServerThread> regionServerThreads = TEST_UTIL.getHBaseCluster()
113         .getRegionServerThreads();
114     for (RegionServerThread rsThread : regionServerThreads) {
115       rsThread.getRegionServer().abort("Aborting ");
116     }
117     // Start one new RS
118     RegionServerThread rs = TEST_UTIL.getHBaseCluster().startRegionServer();
119     waitForLabelsRegionAvailability(rs.getRegionServer());
120     final AtomicBoolean vcInitialized = new AtomicBoolean(true);
121     do {
122       PrivilegedExceptionAction<VisibilityLabelsResponse> action =
123           new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
124         public VisibilityLabelsResponse run() throws Exception {
125           String[] labels = { SECRET, CONFIDENTIAL, PRIVATE, "ABC", "XYZ" };
126           try {
127             VisibilityLabelsResponse resp = VisibilityClient.addLabels(conf, labels);
128             List<RegionActionResult> results = resp.getResultList();
129             if (results.get(0).hasException()) {
130               NameBytesPair pair = results.get(0).getException();
131               Throwable t = ProtobufUtil.toException(pair);
132               LOG.debug("Got exception writing labels", t);
133               if (t instanceof VisibilityControllerNotReadyException) {
134                 vcInitialized.set(false);
135                 LOG.warn("VisibilityController was not yet initialized");
136                 Threads.sleep(10);
137               } else {
138                 vcInitialized.set(true);
139               }
140             } else LOG.debug("new labels added: " + resp);
141           } catch (Throwable t) {
142             throw new IOException(t);
143           }
144           return null;
145         }
146       };
147       SUPERUSER.runAs(action);
148     } while (!vcInitialized.get());
149     // Scan the visibility label
150     Scan s = new Scan();
151     s.setAuthorizations(new Authorizations(VisibilityUtils.SYSTEM_LABEL));
152     HTable ht = new HTable(conf, LABELS_TABLE_NAME.getName());
153     int i = 0;
154     try {
155       ResultScanner scanner = ht.getScanner(s);
156       while (true) {
157         Result next = scanner.next();
158         if (next == null) {
159           break;
160         }
161         i++;
162       }
163     } finally {
164       if (ht != null) {
165         ht.close();
166       }
167     }
168     // One label is the "system" label.
169     Assert.assertEquals("The count should be 13", 13, i);
170   }
171 
172   @Test
173   public void testListLabels() throws Throwable {
174     PrivilegedExceptionAction<ListLabelsResponse> action =
175         new PrivilegedExceptionAction<ListLabelsResponse>() {
176       public ListLabelsResponse run() throws Exception {
177         ListLabelsResponse response = null;
178         try {
179           response = VisibilityClient.listLabels(conf, null);
180         } catch (Throwable e) {
181           fail("Should not have thrown exception");
182         }
183         // The addLabels() in setup added:
184         // { SECRET, TOPSECRET, CONFIDENTIAL, PUBLIC, PRIVATE, COPYRIGHT, ACCENT,
185         //  UNICODE_VIS_TAG, UC1, UC2 };
186         // The previous tests added 2 more labels: ABC, XYZ
187         // The 'system' label is excluded.
188         List<ByteString> labels = response.getLabelList();
189         assertEquals(12, labels.size());
190         assertTrue(labels.contains(ByteString.copyFrom(SECRET.getBytes())));
191         assertTrue(labels.contains(ByteString.copyFrom(TOPSECRET.getBytes())));
192         assertTrue(labels.contains(ByteString.copyFrom(CONFIDENTIAL.getBytes())));
193         assertTrue(labels.contains(ByteString.copyFrom("ABC".getBytes())));
194         assertTrue(labels.contains(ByteString.copyFrom("XYZ".getBytes())));
195         assertFalse(labels.contains(ByteString.copyFrom(SYSTEM_LABEL.getBytes())));
196         return null;
197       }
198     };
199     SUPERUSER.runAs(action);
200   }
201 
202   @Test
203   public void testListLabelsWithRegEx() throws Throwable {
204     PrivilegedExceptionAction<ListLabelsResponse> action =
205         new PrivilegedExceptionAction<ListLabelsResponse>() {
206       public ListLabelsResponse run() throws Exception {
207         ListLabelsResponse response = null;
208         try {
209           response = VisibilityClient.listLabels(conf, ".*secret");
210         } catch (Throwable e) {
211           fail("Should not have thrown exception");
212         }
213         // Only return the labels that end with 'secret'
214         List<ByteString> labels = response.getLabelList();
215         assertEquals(2, labels.size());
216         assertTrue(labels.contains(ByteString.copyFrom(SECRET.getBytes())));
217         assertTrue(labels.contains(ByteString.copyFrom(TOPSECRET.getBytes())));
218         return null;
219       }
220     };
221     SUPERUSER.runAs(action);
222   }
223 
224   @Test(timeout = 60 * 1000)
225   public void testVisibilityLabelsOnWALReplay() throws Exception {
226     final TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
227     HTable table = null;
228     try {
229       table = createTableAndWriteDataWithLabels(tableName,
230         "(" + SECRET + "|" + CONFIDENTIAL + ")", PRIVATE);
231       List<RegionServerThread> regionServerThreads = TEST_UTIL.getHBaseCluster()
232           .getRegionServerThreads();
233       for (RegionServerThread rsThread : regionServerThreads) {
234         rsThread.getRegionServer().abort("Aborting ");
235       }
236       // Start one new RS
237       RegionServerThread rs = TEST_UTIL.getHBaseCluster().startRegionServer();
238       waitForLabelsRegionAvailability(rs.getRegionServer());
239       Scan s = new Scan();
240       s.setAuthorizations(new Authorizations(SECRET));
241       ResultScanner scanner = table.getScanner(s);
242       Result[] next = scanner.next(3);
243       assertTrue(next.length == 1);
244     } finally {
245       table.close();
246     }
247   }
248 }