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