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  
19  package org.apache.hadoop.hbase.client;
20  
21  import static org.junit.Assert.assertNotSame;
22  
23  import org.apache.hadoop.conf.Configuration;
24  import org.apache.hadoop.hbase.Coprocessor;
25  import org.apache.hadoop.hbase.HBaseTestingUtility;
26  import org.apache.hadoop.hbase.HColumnDescriptor;
27  import org.apache.hadoop.hbase.HTableDescriptor;
28  import org.apache.hadoop.hbase.TableName;
29  import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
30  import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
31  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
32  import org.apache.hadoop.hbase.security.User;
33  import org.apache.hadoop.hbase.security.access.AccessControlConstants;
34  import org.apache.hadoop.hbase.security.access.AccessControlLists;
35  import org.apache.hadoop.hbase.security.access.AccessController;
36  import org.apache.hadoop.hbase.security.access.Permission;
37  import org.apache.hadoop.hbase.security.access.SecureTestUtil;
38  import org.apache.hadoop.hbase.testclassification.MediumTests;
39  import org.apache.hadoop.hbase.util.Bytes;
40  import org.junit.AfterClass;
41  import org.junit.Assert;
42  import org.junit.Before;
43  import org.junit.BeforeClass;
44  import org.junit.Test;
45  import org.junit.experimental.categories.Category;
46  
47  import java.io.IOException;
48  import java.util.List;
49  import java.util.UUID;
50  
51  @Category(MediumTests.class)
52  public class TestSnapshotWithAcl extends SecureTestUtil {
53  
54    public TableName TEST_TABLE = TableName.valueOf(UUID.randomUUID().toString());
55  
56    private static final int ROW_COUNT = 30000;
57  
58    private static byte[] TEST_FAMILY = Bytes.toBytes("f1");
59    private static byte[] TEST_QUALIFIER = Bytes.toBytes("cq");
60    private static byte[] TEST_ROW = Bytes.toBytes(0);
61    private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
62    private static Configuration conf;
63    private static HBaseAdmin admin = null;
64  
65    // user is table owner. will have all permissions on table
66    private static User USER_OWNER;
67    // user with rw permissions on column family.
68    private static User USER_RW;
69    // user with read-only permissions
70    private static User USER_RO;
71    // user with none permissions
72    private static User USER_NONE;
73  
74    static class AccessReadAction implements AccessTestAction {
75  
76      private TableName tableName;
77  
78      public AccessReadAction(TableName tableName) {
79        this.tableName = tableName;
80      }
81  
82      @Override
83      public Object run() throws Exception {
84        Get g = new Get(TEST_ROW);
85        g.addFamily(TEST_FAMILY);
86        HTable t = new HTable(conf, tableName);
87        try {
88          t.get(g);
89        } finally {
90          t.close();
91        }
92        return null;
93      }
94    };
95  
96    static class AccessWriteAction implements AccessTestAction {
97      private TableName tableName;
98  
99      public AccessWriteAction(TableName tableName) {
100       this.tableName = tableName;
101     }
102 
103     @Override
104     public Object run() throws Exception {
105       Put p = new Put(TEST_ROW);
106       p.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(1));
107       HTable t = new HTable(conf, tableName);
108       try {
109         t.put(p);
110       } finally {
111         t.close();
112       }
113       return null;
114     }
115   }
116 
117   @BeforeClass
118   public static void setupBeforeClass() throws Exception {
119     conf = TEST_UTIL.getConfiguration();
120     // Enable security
121     enableSecurity(conf);
122     conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, AccessController.class.getName());
123     // Verify enableSecurity sets up what we require
124     verifyConfiguration(conf);
125     // Enable EXEC permission checking
126     conf.setBoolean(AccessControlConstants.EXEC_PERMISSION_CHECKS_KEY, true);
127     TEST_UTIL.startMiniCluster();
128     TEST_UTIL.waitUntilAllRegionsAssigned(AccessControlLists.ACL_TABLE_NAME);
129     MasterCoprocessorHost cpHost =
130         TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterCoprocessorHost();
131     cpHost.load(AccessController.class, Coprocessor.PRIORITY_HIGHEST, conf);
132 
133     USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]);
134     USER_RW = User.createUserForTesting(conf, "rwuser", new String[0]);
135     USER_RO = User.createUserForTesting(conf, "rouser", new String[0]);
136     USER_NONE = User.createUserForTesting(conf, "usernone", new String[0]);
137   }
138 
139   @Before
140   public void setUp() throws Exception {
141     admin = TEST_UTIL.getHBaseAdmin();
142     HTableDescriptor htd = new HTableDescriptor(TEST_TABLE);
143     HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY);
144     hcd.setMaxVersions(100);
145     htd.addFamily(hcd);
146     htd.setOwner(USER_OWNER);
147     admin.createTable(htd, new byte[][] { Bytes.toBytes("s") });
148     TEST_UTIL.waitTableEnabled(TEST_TABLE);
149 
150     grantOnTable(TEST_UTIL, USER_RW.getShortName(), TEST_TABLE, TEST_FAMILY, null,
151       Permission.Action.READ, Permission.Action.WRITE);
152 
153     grantOnTable(TEST_UTIL, USER_RO.getShortName(), TEST_TABLE, TEST_FAMILY, null,
154       Permission.Action.READ);
155   }
156 
157   private void loadData() throws IOException {
158     HTable hTable = new HTable(conf, TEST_TABLE);
159     try {
160       for (int i = 0; i < ROW_COUNT; i++) {
161         Put put = new Put(Bytes.toBytes(i));
162         put.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(i));
163         hTable.put(put);
164       }
165       hTable.flushCommits();
166     } finally {
167       hTable.close();
168     }
169   }
170 
171   @AfterClass
172   public static void tearDownAfterClass() throws Exception {
173     TEST_UTIL.shutdownMiniCluster();
174   }
175 
176   private void verifyRows(TableName tableName) throws IOException {
177     HTable hTable = new HTable(conf, tableName);
178     try {
179       Scan scan = new Scan();
180       ResultScanner scanner = hTable.getScanner(scan);
181       Result result;
182       int rowCount = 0;
183       while ((result = scanner.next()) != null) {
184         byte[] value = result.getValue(TEST_FAMILY, TEST_QUALIFIER);
185         Assert.assertArrayEquals(value, Bytes.toBytes(rowCount++));
186       }
187       Assert.assertEquals(rowCount, ROW_COUNT);
188     } finally {
189       hTable.close();
190     }
191   }
192 
193   @Test
194   public void testRestoreSnapshot() throws Exception {
195     verifyAllowed(new AccessReadAction(TEST_TABLE), USER_OWNER, USER_RO, USER_RW);
196     verifyDenied(new AccessReadAction(TEST_TABLE), USER_NONE);
197     verifyAllowed(new AccessWriteAction(TEST_TABLE), USER_OWNER, USER_RW);
198     verifyDenied(new AccessWriteAction(TEST_TABLE), USER_RO, USER_NONE);
199 
200     loadData();
201     verifyRows(TEST_TABLE);
202 
203     String snapshotName1 = UUID.randomUUID().toString();
204     admin.snapshot(snapshotName1, TEST_TABLE);
205 
206     // clone snapshot with restoreAcl true.
207     TableName tableName1 = TableName.valueOf(UUID.randomUUID().toString());
208     admin.cloneSnapshot(snapshotName1, tableName1, true);
209     verifyRows(tableName1);
210     verifyAllowed(new AccessReadAction(tableName1), USER_OWNER, USER_RO, USER_RW);
211     verifyDenied(new AccessReadAction(tableName1), USER_NONE);
212     verifyAllowed(new AccessWriteAction(tableName1), USER_OWNER, USER_RW);
213     verifyDenied(new AccessWriteAction(tableName1), USER_RO, USER_NONE);
214 
215     // clone snapshot with restoreAcl false.
216     TableName tableName2 = TableName.valueOf(UUID.randomUUID().toString());
217     admin.cloneSnapshot(snapshotName1, tableName2, false);
218     verifyRows(tableName2);
219     verifyAllowed(new AccessReadAction(tableName2), USER_OWNER);
220     verifyDenied(new AccessReadAction(tableName2), USER_NONE, USER_RO, USER_RW);
221     verifyAllowed(new AccessWriteAction(tableName2), USER_OWNER);
222     verifyDenied(new AccessWriteAction(tableName2), USER_RO, USER_RW, USER_NONE);
223 
224     // remove read permission for USER_RO.
225     revokeFromTable(TEST_UTIL, USER_RO.getShortName(), TEST_TABLE, TEST_FAMILY, null,
226       Permission.Action.READ);
227     verifyAllowed(new AccessReadAction(TEST_TABLE), USER_OWNER, USER_RW);
228     verifyDenied(new AccessReadAction(TEST_TABLE), USER_RO, USER_NONE);
229     verifyAllowed(new AccessWriteAction(TEST_TABLE), USER_OWNER, USER_RW);
230     verifyDenied(new AccessWriteAction(TEST_TABLE), USER_RO, USER_NONE);
231 
232     // restore snapshot with restoreAcl false.
233     admin.disableTable(TEST_TABLE);
234     admin.restoreSnapshot(snapshotName1, false, false);
235     admin.enableTable(TEST_TABLE);
236     verifyAllowed(new AccessReadAction(TEST_TABLE), USER_OWNER, USER_RW);
237     verifyDenied(new AccessReadAction(TEST_TABLE), USER_RO, USER_NONE);
238     verifyAllowed(new AccessWriteAction(TEST_TABLE), USER_OWNER, USER_RW);
239     verifyDenied(new AccessWriteAction(TEST_TABLE), USER_RO, USER_NONE);
240 
241     // restore snapshot with restoreAcl true.
242     admin.disableTable(TEST_TABLE);
243     admin.restoreSnapshot(snapshotName1, false, true);
244     admin.enableTable(TEST_TABLE);
245     verifyAllowed(new AccessReadAction(TEST_TABLE), USER_OWNER, USER_RO, USER_RW);
246     verifyDenied(new AccessReadAction(TEST_TABLE), USER_NONE);
247     verifyAllowed(new AccessWriteAction(TEST_TABLE), USER_OWNER, USER_RW);
248     verifyDenied(new AccessWriteAction(TEST_TABLE), USER_RO, USER_NONE);
249   }
250 
251   @Test
252   public void testListSnapshot() throws Exception {
253     String snapshotName1 = UUID.randomUUID().toString();
254     admin.snapshot(snapshotName1, TEST_TABLE);
255     List<HBaseProtos.SnapshotDescription> snapshotDescriptions = admin.listSnapshots();
256     for (HBaseProtos.SnapshotDescription snapshotDescription:
257       snapshotDescriptions) {
258       assertNotSame(snapshotDescription.getOwner(), "");
259     }
260     admin.deleteSnapshot(snapshotName1);
261   }
262 }