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 static org.junit.Assert.assertEquals;
021
022import java.io.IOException;
023import java.security.PrivilegedExceptionAction;
024import java.util.ArrayList;
025import java.util.Arrays;
026import java.util.List;
027import org.apache.hadoop.conf.Configuration;
028import org.apache.hadoop.fs.Path;
029import org.apache.hadoop.hbase.HBaseTestingUtility;
030import org.apache.hadoop.hbase.NamespaceDescriptor;
031import org.apache.hadoop.hbase.TableName;
032import org.apache.hadoop.hbase.client.*;
033import org.apache.hadoop.hbase.security.User;
034import org.apache.hadoop.hbase.util.Bytes;
035import org.slf4j.Logger;
036import org.slf4j.LoggerFactory;
037
038final class TestHDFSAclHelper {
039  private static final Logger LOG = LoggerFactory.getLogger(TestHDFSAclHelper.class);
040
041  private TestHDFSAclHelper() {
042  }
043
044  static void grantOnTable(HBaseTestingUtility util, String user, TableName tableName,
045    Permission.Action... actions) throws Exception {
046    SecureTestUtil.grantOnTable(util, user, tableName, null, null, actions);
047  }
048
049  static void createNamespace(HBaseTestingUtility util, String namespace) throws IOException {
050    if (
051      Arrays.stream(util.getAdmin().listNamespaceDescriptors())
052        .noneMatch(ns -> ns.getName().equals(namespace))
053    ) {
054      NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create(namespace).build();
055      util.getAdmin().createNamespace(namespaceDescriptor);
056    }
057  }
058
059  static Table createTable(HBaseTestingUtility util, TableName tableName) throws IOException {
060    createNamespace(util, tableName.getNamespaceAsString());
061    TableDescriptor td = getTableDescriptorBuilder(util, tableName)
062      .setValue(SnapshotScannerHDFSAclHelper.ACL_SYNC_TO_HDFS_ENABLE, "true").build();
063    byte[][] splits = new byte[][] { Bytes.toBytes("2"), Bytes.toBytes("4") };
064    return util.createTable(td, splits);
065  }
066
067  static Table createMobTable(HBaseTestingUtility util, TableName tableName) throws IOException {
068    createNamespace(util, tableName.getNamespaceAsString());
069    TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName)
070      .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(COLUMN1).setMobEnabled(true)
071        .setMobThreshold(0).build())
072      .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(COLUMN2).setMobEnabled(true)
073        .setMobThreshold(0).build())
074      .setOwner(User.createUserForTesting(util.getConfiguration(), "owner", new String[] {}))
075      .setValue(SnapshotScannerHDFSAclHelper.ACL_SYNC_TO_HDFS_ENABLE, "true").build();
076    byte[][] splits = new byte[][] { Bytes.toBytes("2"), Bytes.toBytes("4") };
077    return util.createTable(td, splits);
078  }
079
080  static TableDescriptor createUserScanSnapshotDisabledTable(HBaseTestingUtility util,
081    TableName tableName) throws IOException {
082    createNamespace(util, tableName.getNamespaceAsString());
083    TableDescriptor td = getTableDescriptorBuilder(util, tableName).build();
084    byte[][] splits = new byte[][] { Bytes.toBytes("2"), Bytes.toBytes("4") };
085    try (Table t = util.createTable(td, splits)) {
086      put(t);
087    }
088    return td;
089  }
090
091  static TableDescriptorBuilder getTableDescriptorBuilder(HBaseTestingUtility util,
092    TableName tableName) {
093    return TableDescriptorBuilder.newBuilder(tableName)
094      .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(COLUMN1).build())
095      .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(COLUMN2).build())
096      .setOwner(User.createUserForTesting(util.getConfiguration(), "owner", new String[] {}));
097  }
098
099  static void createTableAndPut(HBaseTestingUtility util, TableName tableNam) throws IOException {
100    try (Table t = createTable(util, tableNam)) {
101      put(t);
102    }
103  }
104
105  static final byte[] COLUMN1 = Bytes.toBytes("A");
106  static final byte[] COLUMN2 = Bytes.toBytes("B");
107
108  static void put(Table hTable) throws IOException {
109    List<Put> puts = new ArrayList<>();
110    for (int i = 0; i < 6; i++) {
111      Put put = new Put(Bytes.toBytes(i));
112      put.addColumn(COLUMN1, null, Bytes.toBytes(i));
113      put.addColumn(COLUMN2, null, Bytes.toBytes(i + 1));
114      puts.add(put);
115    }
116    hTable.put(puts);
117  }
118
119  static void put2(Table hTable) throws IOException {
120    List<Put> puts = new ArrayList<>();
121    for (int i = 0; i < 10; i++) {
122      if (i == 5) {
123        continue;
124      }
125      Put put = new Put(Bytes.toBytes(i));
126      put.addColumn(COLUMN1, null, Bytes.toBytes(i + 2));
127      put.addColumn(COLUMN2, null, Bytes.toBytes(i + 3));
128      puts.add(put);
129    }
130    hTable.put(puts);
131  }
132
133  /**
134   * Check if user is able to read expected rows from the specific snapshot
135   * @param user             the specific user
136   * @param snapshot         the snapshot to be scanned
137   * @param expectedRowCount expected row count read from snapshot, -1 if expects
138   *                         AccessControlException
139   * @throws IOException          user scan snapshot error
140   * @throws InterruptedException user scan snapshot error
141   */
142  static void canUserScanSnapshot(HBaseTestingUtility util, User user, String snapshot,
143    int expectedRowCount) throws IOException, InterruptedException {
144    PrivilegedExceptionAction<Void> action =
145      getScanSnapshotAction(util.getConfiguration(), snapshot, expectedRowCount);
146    user.runAs(action);
147  }
148
149  static PrivilegedExceptionAction<Void> getScanSnapshotAction(Configuration conf,
150    String snapshotName, long expectedRowCount) {
151    return () -> {
152      try {
153        Path restoreDir = new Path(SnapshotScannerHDFSAclHelper.SNAPSHOT_RESTORE_TMP_DIR_DEFAULT);
154        Scan scan = new Scan();
155        TableSnapshotScanner scanner =
156          new TableSnapshotScanner(conf, restoreDir, snapshotName, scan);
157        int rowCount = 0;
158        while (true) {
159          Result result = scanner.next();
160          if (result == null) {
161            break;
162          }
163          rowCount++;
164        }
165        scanner.close();
166        assertEquals(expectedRowCount, rowCount);
167      } catch (Exception e) {
168        LOG.debug("Scan snapshot error, snapshot {}", snapshotName, e);
169        assertEquals(expectedRowCount, -1);
170      }
171      return null;
172    };
173  }
174}