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