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