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.Result;
38  import org.apache.hadoop.hbase.client.ResultScanner;
39  import org.apache.hadoop.hbase.client.Scan;
40  import org.apache.hadoop.hbase.client.Table;
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  import com.google.protobuf.ByteString;
55  
56  @Category(MediumTests.class)
57  public class TestVisibilityLabelsWithDefaultVisLabelService extends TestVisibilityLabels {
58    final Log LOG = LogFactory.getLog(getClass());
59  
60    @BeforeClass
61    public static void setupBeforeClass() throws Exception {
62      // setup configuration
63      conf = TEST_UTIL.getConfiguration();
64      conf.setBoolean(HConstants.DISTRIBUTED_LOG_REPLAY_KEY, false);
65      conf.setBoolean("hbase.online.schema.update.enable", true);
66      VisibilityTestUtil.enableVisiblityLabels(conf);
67      conf.setClass(VisibilityUtils.VISIBILITY_LABEL_GENERATOR_CLASS, SimpleScanLabelGenerator.class,
68          ScanLabelGenerator.class);
69      conf.set("hbase.superuser", "admin");
70      TEST_UTIL.startMiniCluster(2);
71      SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
72      USER1 = User.createUserForTesting(conf, "user1", new String[] {});
73  
74      // Wait for the labels table to become available
75      TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000);
76      addLabels();
77    }
78  
79    @Test
80    public void testAddLabels() throws Throwable {
81      PrivilegedExceptionAction<VisibilityLabelsResponse> action =
82          new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
83        public VisibilityLabelsResponse run() throws Exception {
84          String[] labels = { "L1", SECRET, "L2", "invalid~", "L3" };
85          VisibilityLabelsResponse response = null;
86          try {
87            response = VisibilityClient.addLabels(conf, labels);
88          } catch (Throwable e) {
89            fail("Should not have thrown exception");
90          }
91          List<RegionActionResult> resultList = response.getResultList();
92          assertEquals(5, resultList.size());
93          assertTrue(resultList.get(0).getException().getValue().isEmpty());
94          assertEquals("org.apache.hadoop.hbase.DoNotRetryIOException", resultList.get(1)
95              .getException().getName());
96          assertTrue(Bytes.toString(resultList.get(1).getException().getValue().toByteArray())
97              .contains(
98                  "org.apache.hadoop.hbase.security.visibility.LabelAlreadyExistsException: "
99                      + "Label 'secret' already exists"));
100         assertTrue(resultList.get(2).getException().getValue().isEmpty());
101         assertTrue(resultList.get(3).getException().getValue().isEmpty());
102         assertTrue(resultList.get(4).getException().getValue().isEmpty());
103         return null;
104       }
105     };
106     SUPERUSER.runAs(action);
107   }
108 
109   @Test(timeout = 60 * 1000)
110   public void testAddVisibilityLabelsOnRSRestart() throws Exception {
111     List<RegionServerThread> regionServerThreads = TEST_UTIL.getHBaseCluster()
112         .getRegionServerThreads();
113     for (RegionServerThread rsThread : regionServerThreads) {
114       rsThread.getRegionServer().abort("Aborting ");
115     }
116     // Start one new RS
117     RegionServerThread rs = TEST_UTIL.getHBaseCluster().startRegionServer();
118     waitForLabelsRegionAvailability(rs.getRegionServer());
119     final AtomicBoolean vcInitialized = new AtomicBoolean(true);
120     do {
121       PrivilegedExceptionAction<VisibilityLabelsResponse> action =
122           new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
123         public VisibilityLabelsResponse run() throws Exception {
124           String[] labels = { SECRET, CONFIDENTIAL, PRIVATE, "ABC", "XYZ" };
125           try {
126             VisibilityLabelsResponse resp = VisibilityClient.addLabels(conf, labels);
127             List<RegionActionResult> results = resp.getResultList();
128             if (results.get(0).hasException()) {
129               NameBytesPair pair = results.get(0).getException();
130               Throwable t = ProtobufUtil.toException(pair);
131               LOG.debug("Got exception writing labels", t);
132               if (t instanceof VisibilityControllerNotReadyException) {
133                 vcInitialized.set(false);
134                 LOG.warn("VisibilityController was not yet initialized");
135                 Threads.sleep(10);
136               } else {
137                 vcInitialized.set(true);
138               }
139             } else LOG.debug("new labels added: " + resp);
140           } catch (Throwable t) {
141             throw new IOException(t);
142           }
143           return null;
144         }
145       };
146       SUPERUSER.runAs(action);
147     } while (!vcInitialized.get());
148     // Scan the visibility label
149     Scan s = new Scan();
150     s.setAuthorizations(new Authorizations(VisibilityUtils.SYSTEM_LABEL));
151 
152     int i = 0;
153     try (Table ht = TEST_UTIL.getConnection().getTable(LABELS_TABLE_NAME);
154          ResultScanner scanner = ht.getScanner(s)) {
155       while (true) {
156         Result next = scanner.next();
157         if (next == null) {
158           break;
159         }
160         i++;
161       }
162     }
163     // One label is the "system" label.
164     Assert.assertEquals("The count should be 13", 13, i);
165   }
166 
167   @Test
168   public void testListLabels() throws Throwable {
169     PrivilegedExceptionAction<ListLabelsResponse> action =
170         new PrivilegedExceptionAction<ListLabelsResponse>() {
171       public ListLabelsResponse run() throws Exception {
172         ListLabelsResponse response = null;
173         try {
174           response = VisibilityClient.listLabels(conf, null);
175         } catch (Throwable e) {
176           fail("Should not have thrown exception");
177         }
178         // The addLabels() in setup added:
179         // { SECRET, TOPSECRET, CONFIDENTIAL, PUBLIC, PRIVATE, COPYRIGHT, ACCENT,
180         //  UNICODE_VIS_TAG, UC1, UC2 };
181         // The previous tests added 2 more labels: ABC, XYZ
182         // The 'system' label is excluded.
183         List<ByteString> labels = response.getLabelList();
184         assertEquals(12, labels.size());
185         assertTrue(labels.contains(ByteString.copyFrom(SECRET.getBytes())));
186         assertTrue(labels.contains(ByteString.copyFrom(TOPSECRET.getBytes())));
187         assertTrue(labels.contains(ByteString.copyFrom(CONFIDENTIAL.getBytes())));
188         assertTrue(labels.contains(ByteString.copyFrom("ABC".getBytes())));
189         assertTrue(labels.contains(ByteString.copyFrom("XYZ".getBytes())));
190         assertFalse(labels.contains(ByteString.copyFrom(SYSTEM_LABEL.getBytes())));
191         return null;
192       }
193     };
194     SUPERUSER.runAs(action);
195   }
196 
197   @Test
198   public void testListLabelsWithRegEx() throws Throwable {
199     PrivilegedExceptionAction<ListLabelsResponse> action =
200         new PrivilegedExceptionAction<ListLabelsResponse>() {
201       public ListLabelsResponse run() throws Exception {
202         ListLabelsResponse response = null;
203         try {
204           response = VisibilityClient.listLabels(conf, ".*secret");
205         } catch (Throwable e) {
206           fail("Should not have thrown exception");
207         }
208         // Only return the labels that end with 'secret'
209         List<ByteString> labels = response.getLabelList();
210         assertEquals(2, labels.size());
211         assertTrue(labels.contains(ByteString.copyFrom(SECRET.getBytes())));
212         assertTrue(labels.contains(ByteString.copyFrom(TOPSECRET.getBytes())));
213         return null;
214       }
215     };
216     SUPERUSER.runAs(action);
217   }
218 
219   @Test(timeout = 60 * 1000)
220   public void testVisibilityLabelsOnWALReplay() throws Exception {
221     final TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
222     try (Table table = createTableAndWriteDataWithLabels(tableName,
223         "(" + SECRET + "|" + CONFIDENTIAL + ")", PRIVATE);) {
224       List<RegionServerThread> regionServerThreads = TEST_UTIL.getHBaseCluster()
225           .getRegionServerThreads();
226       for (RegionServerThread rsThread : regionServerThreads) {
227         rsThread.getRegionServer().abort("Aborting ");
228       }
229       // Start one new RS
230       RegionServerThread rs = TEST_UTIL.getHBaseCluster().startRegionServer();
231       waitForLabelsRegionAvailability(rs.getRegionServer());
232       Scan s = new Scan();
233       s.setAuthorizations(new Authorizations(SECRET));
234       ResultScanner scanner = table.getScanner(s);
235       Result[] next = scanner.next(3);
236       assertTrue(next.length == 1);
237     }
238   }
239 }