001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.security.access;
019
020import org.apache.hadoop.conf.Configuration;
021import org.apache.hadoop.fs.Path;
022import org.apache.hadoop.hbase.HBaseTestingUtility;
023import org.apache.hadoop.hbase.NamespaceDescriptor;
024import org.apache.hadoop.hbase.TableName;
025import org.apache.hadoop.hbase.client.*;
026import org.apache.hadoop.hbase.security.User;
027import org.apache.hadoop.hbase.util.Bytes;
028import org.slf4j.Logger;
029import org.slf4j.LoggerFactory;
030
031import java.io.IOException;
032import java.security.PrivilegedExceptionAction;
033import java.util.ArrayList;
034import java.util.Arrays;
035import java.util.List;
036
037import static org.junit.Assert.assertEquals;
038
039final class TestHDFSAclHelper {
040  private static final Logger LOG = LoggerFactory.getLogger(TestHDFSAclHelper.class);
041
042  private TestHDFSAclHelper() {
043  }
044
045  static void grantOnTable(HBaseTestingUtility util, String user, TableName tableName,
046                           Permission.Action... actions) throws Exception {
047    SecureTestUtil.grantOnTable(util, user, tableName, null, null, actions);
048  }
049
050  static void createNamespace(HBaseTestingUtility util, String namespace) throws IOException {
051    if (Arrays.stream(util.getAdmin().listNamespaceDescriptors())
052        .noneMatch(ns -> ns.getName().equals(namespace))) {
053      NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create(namespace).build();
054      util.getAdmin().createNamespace(namespaceDescriptor);
055    }
056  }
057
058  static Table createTable(HBaseTestingUtility util, TableName tableName) throws IOException {
059    createNamespace(util, tableName.getNamespaceAsString());
060    TableDescriptor td = getTableDescriptorBuilder(util, tableName)
061        .setValue(SnapshotScannerHDFSAclHelper.ACL_SYNC_TO_HDFS_ENABLE, "true").build();
062    byte[][] splits = new byte[][] { Bytes.toBytes("2"), Bytes.toBytes("4") };
063    return util.createTable(td, splits);
064  }
065
066  static Table createMobTable(HBaseTestingUtility util, TableName tableName) throws IOException {
067    createNamespace(util, tableName.getNamespaceAsString());
068    TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName)
069        .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(COLUMN1).setMobEnabled(true)
070            .setMobThreshold(0).build())
071        .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(COLUMN2).setMobEnabled(true)
072            .setMobThreshold(0).build())
073        .setOwner(User.createUserForTesting(util.getConfiguration(), "owner", new String[] {}))
074        .setValue(SnapshotScannerHDFSAclHelper.ACL_SYNC_TO_HDFS_ENABLE, "true").build();
075    byte[][] splits = new byte[][] { Bytes.toBytes("2"), Bytes.toBytes("4") };
076    return util.createTable(td, splits);
077  }
078
079  static TableDescriptor createUserScanSnapshotDisabledTable(HBaseTestingUtility util,
080      TableName tableName) throws IOException {
081    createNamespace(util, tableName.getNamespaceAsString());
082    TableDescriptor td = getTableDescriptorBuilder(util, tableName).build();
083    byte[][] splits = new byte[][] { Bytes.toBytes("2"), Bytes.toBytes("4") };
084    try (Table t = util.createTable(td, splits)) {
085      put(t);
086    }
087    return td;
088  }
089
090  static TableDescriptorBuilder getTableDescriptorBuilder(HBaseTestingUtility util,
091      TableName tableName) {
092    return TableDescriptorBuilder.newBuilder(tableName)
093        .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(COLUMN1).build())
094        .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(COLUMN2).build())
095        .setOwner(User.createUserForTesting(util.getConfiguration(), "owner", new String[] {}));
096  }
097
098  static void createTableAndPut(HBaseTestingUtility util, TableName tableNam) throws IOException {
099    try (Table t = createTable(util, tableNam)) {
100      put(t);
101    }
102  }
103
104  static final byte[] COLUMN1 = Bytes.toBytes("A");
105  static final byte[] COLUMN2 = Bytes.toBytes("B");
106
107  static void put(Table hTable) throws IOException {
108    List<Put> puts = new ArrayList<>();
109    for (int i = 0; i < 6; i++) {
110      Put put = new Put(Bytes.toBytes(i));
111      put.addColumn(COLUMN1, null, Bytes.toBytes(i));
112      put.addColumn(COLUMN2, null, Bytes.toBytes(i + 1));
113      puts.add(put);
114    }
115    hTable.put(puts);
116  }
117
118  static void put2(Table hTable) throws IOException {
119    List<Put> puts = new ArrayList<>();
120    for (int i = 0; i < 10; i++) {
121      if (i == 5) {
122        continue;
123      }
124      Put put = new Put(Bytes.toBytes(i));
125      put.addColumn(COLUMN1, null, Bytes.toBytes(i + 2));
126      put.addColumn(COLUMN2, null, Bytes.toBytes(i + 3));
127      puts.add(put);
128    }
129    hTable.put(puts);
130  }
131
132  /**
133   * Check if user is able to read expected rows from the specific snapshot
134   * @param user the specific user
135   * @param snapshot the snapshot to be scanned
136   * @param expectedRowCount expected row count read from snapshot, -1 if expects
137   *          AccessControlException
138   * @throws IOException user scan snapshot error
139   * @throws InterruptedException user scan snapshot error
140   */
141  static void canUserScanSnapshot(HBaseTestingUtility util, User user, String snapshot,
142      int expectedRowCount) throws IOException, InterruptedException {
143    PrivilegedExceptionAction<Void> action =
144        getScanSnapshotAction(util.getConfiguration(), snapshot, expectedRowCount);
145    user.runAs(action);
146  }
147
148  static PrivilegedExceptionAction<Void> getScanSnapshotAction(Configuration conf,
149                                                               String snapshotName, long expectedRowCount) {
150    return () -> {
151      try {
152        Path restoreDir = new Path(SnapshotScannerHDFSAclHelper.SNAPSHOT_RESTORE_TMP_DIR_DEFAULT);
153        Scan scan = new Scan();
154        TableSnapshotScanner scanner =
155            new TableSnapshotScanner(conf, restoreDir, snapshotName, scan);
156        int rowCount = 0;
157        while (true) {
158          Result result = scanner.next();
159          if (result == null) {
160            break;
161          }
162          rowCount++;
163        }
164        scanner.close();
165        assertEquals(expectedRowCount, rowCount);
166      } catch (Exception e) {
167        LOG.debug("Scan snapshot error, snapshot {}", snapshotName, e);
168        assertEquals(expectedRowCount, -1);
169      }
170      return null;
171    };
172  }
173}