You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ga...@apache.org on 2011/11/19 01:25:38 UTC
svn commit: r1203915 [3/3] - in /hbase/branches/0.92: ./
security/src/main/java/org/apache/hadoop/hbase/security/access/
security/src/test/java/org/apache/hadoop/hbase/security/access/
src/main/java/org/apache/hadoop/hbase/ src/main/java/org/apache/had...
Added: hbase/branches/0.92/security/src/test/java/org/apache/hadoop/hbase/security/access/TestTablePermissions.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/security/src/test/java/org/apache/hadoop/hbase/security/access/TestTablePermissions.java?rev=1203915&view=auto
==============================================================================
--- hbase/branches/0.92/security/src/test/java/org/apache/hadoop/hbase/security/access/TestTablePermissions.java (added)
+++ hbase/branches/0.92/security/src/test/java/org/apache/hadoop/hbase/security/access/TestTablePermissions.java Sat Nov 19 00:25:37 2011
@@ -0,0 +1,305 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hbase.security.access;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ListMultimap;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.Abortable;
+import org.apache.hadoop.hbase.HBaseTestingUtility;
+import org.apache.hadoop.hbase.client.HBaseAdmin;
+import org.apache.hadoop.hbase.client.HTable;
+import org.apache.hadoop.hbase.client.Put;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.*;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.junit.Assert.*;
+
+/**
+ * Test the reading and writing of access permissions on {@code _acl_} table.
+ */
+public class TestTablePermissions {
+ private static final Log LOG = LogFactory.getLog(TestTablePermissions.class);
+ private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
+ private static ZooKeeperWatcher ZKW;
+ private final static Abortable ABORTABLE = new Abortable() {
+ private final AtomicBoolean abort = new AtomicBoolean(false);
+
+ @Override
+ public void abort(String why, Throwable e) {
+ LOG.info(why, e);
+ abort.set(true);
+ }
+
+ @Override
+ public boolean isAborted() {
+ return abort.get();
+ }
+ };
+
+ private static byte[] TEST_TABLE = Bytes.toBytes("perms_test");
+ private static byte[] TEST_TABLE2 = Bytes.toBytes("perms_test2");
+ private static byte[] TEST_FAMILY = Bytes.toBytes("f1");
+ private static byte[] TEST_QUALIFIER = Bytes.toBytes("col1");
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ // setup configuration
+ Configuration conf = UTIL.getConfiguration();
+ SecureTestUtil.enableSecurity(conf);
+
+ UTIL.startMiniCluster();
+ ZKW = new ZooKeeperWatcher(UTIL.getConfiguration(),
+ "TestTablePermissions", ABORTABLE);
+
+ UTIL.createTable(TEST_TABLE, TEST_FAMILY);
+ UTIL.createTable(TEST_TABLE2, TEST_FAMILY);
+ }
+
+ @AfterClass
+ public static void afterClass() throws Exception {
+ UTIL.shutdownMiniCluster();
+ }
+
+ @Test
+ public void testBasicWrite() throws Exception {
+ Configuration conf = UTIL.getConfiguration();
+ // add some permissions
+ AccessControlLists.addTablePermission(conf, TEST_TABLE,
+ "george", new TablePermission(TEST_TABLE, null,
+ TablePermission.Action.READ, TablePermission.Action.WRITE));
+ AccessControlLists.addTablePermission(conf, TEST_TABLE,
+ "hubert", new TablePermission(TEST_TABLE, null,
+ TablePermission.Action.READ));
+ AccessControlLists.addTablePermission(conf, TEST_TABLE,
+ "humphrey", new TablePermission(TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER,
+ TablePermission.Action.READ));
+
+ // retrieve the same
+ ListMultimap<String,TablePermission> perms =
+ AccessControlLists.getTablePermissions(conf, TEST_TABLE);
+ List<TablePermission> userPerms = perms.get("george");
+ assertNotNull("Should have permissions for george", userPerms);
+ assertEquals("Should have 1 permission for george", 1, userPerms.size());
+ TablePermission permission = userPerms.get(0);
+ assertTrue("Permission should be for " + TEST_TABLE,
+ Bytes.equals(TEST_TABLE, permission.getTable()));
+ assertNull("Column family should be empty", permission.getFamily());
+
+ // check actions
+ assertNotNull(permission.getActions());
+ assertEquals(2, permission.getActions().length);
+ List<TablePermission.Action> actions = Arrays.asList(permission.getActions());
+ assertTrue(actions.contains(TablePermission.Action.READ));
+ assertTrue(actions.contains(TablePermission.Action.WRITE));
+
+ userPerms = perms.get("hubert");
+ assertNotNull("Should have permissions for hubert", userPerms);
+ assertEquals("Should have 1 permission for hubert", 1, userPerms.size());
+ permission = userPerms.get(0);
+ assertTrue("Permission should be for " + TEST_TABLE,
+ Bytes.equals(TEST_TABLE, permission.getTable()));
+ assertNull("Column family should be empty", permission.getFamily());
+
+ // check actions
+ assertNotNull(permission.getActions());
+ assertEquals(1, permission.getActions().length);
+ actions = Arrays.asList(permission.getActions());
+ assertTrue(actions.contains(TablePermission.Action.READ));
+ assertFalse(actions.contains(TablePermission.Action.WRITE));
+
+ userPerms = perms.get("humphrey");
+ assertNotNull("Should have permissions for humphrey", userPerms);
+ assertEquals("Should have 1 permission for humphrey", 1, userPerms.size());
+ permission = userPerms.get(0);
+ assertTrue("Permission should be for " + TEST_TABLE,
+ Bytes.equals(TEST_TABLE, permission.getTable()));
+ assertTrue("Permission should be for family " + TEST_FAMILY,
+ Bytes.equals(TEST_FAMILY, permission.getFamily()));
+ assertTrue("Permission should be for qualifier " + TEST_QUALIFIER,
+ Bytes.equals(TEST_QUALIFIER, permission.getQualifier()));
+
+ // check actions
+ assertNotNull(permission.getActions());
+ assertEquals(1, permission.getActions().length);
+ actions = Arrays.asList(permission.getActions());
+ assertTrue(actions.contains(TablePermission.Action.READ));
+ assertFalse(actions.contains(TablePermission.Action.WRITE));
+
+ // table 2 permissions
+ AccessControlLists.addTablePermission(conf, TEST_TABLE2, "hubert",
+ new TablePermission(TEST_TABLE2, null,
+ TablePermission.Action.READ, TablePermission.Action.WRITE));
+
+ // check full load
+ Map<byte[],ListMultimap<String,TablePermission>> allPerms =
+ AccessControlLists.loadAll(conf);
+ assertEquals("Full permission map should have entries for both test tables",
+ 2, allPerms.size());
+
+ userPerms = allPerms.get(TEST_TABLE).get("hubert");
+ assertNotNull(userPerms);
+ assertEquals(1, userPerms.size());
+ permission = userPerms.get(0);
+ assertTrue(Bytes.equals(TEST_TABLE, permission.getTable()));
+ assertEquals(1, permission.getActions().length);
+ assertEquals(TablePermission.Action.READ, permission.getActions()[0]);
+
+ userPerms = allPerms.get(TEST_TABLE2).get("hubert");
+ assertNotNull(userPerms);
+ assertEquals(1, userPerms.size());
+ permission = userPerms.get(0);
+ assertTrue(Bytes.equals(TEST_TABLE2, permission.getTable()));
+ assertEquals(2, permission.getActions().length);
+ actions = Arrays.asList(permission.getActions());
+ assertTrue(actions.contains(TablePermission.Action.READ));
+ assertTrue(actions.contains(TablePermission.Action.WRITE));
+ }
+
+ @Test
+ public void testPersistence() throws Exception {
+ Configuration conf = UTIL.getConfiguration();
+ AccessControlLists.addTablePermission(conf, TEST_TABLE, "albert",
+ new TablePermission(TEST_TABLE, null, TablePermission.Action.READ));
+ AccessControlLists.addTablePermission(conf, TEST_TABLE, "betty",
+ new TablePermission(TEST_TABLE, null, TablePermission.Action.READ,
+ TablePermission.Action.WRITE));
+ AccessControlLists.addTablePermission(conf, TEST_TABLE, "clark",
+ new TablePermission(TEST_TABLE, TEST_FAMILY, TablePermission.Action.READ));
+ AccessControlLists.addTablePermission(conf, TEST_TABLE, "dwight",
+ new TablePermission(TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER,
+ TablePermission.Action.WRITE));
+
+ // verify permissions survive changes in table metadata
+ ListMultimap<String,TablePermission> preperms =
+ AccessControlLists.getTablePermissions(conf, TEST_TABLE);
+
+ HTable table = new HTable(conf, TEST_TABLE);
+ table.put(new Put(Bytes.toBytes("row1"))
+ .add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes("v1")));
+ table.put(new Put(Bytes.toBytes("row2"))
+ .add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes("v2")));
+ HBaseAdmin admin = UTIL.getHBaseAdmin();
+ admin.split(TEST_TABLE);
+
+ // wait for split
+ Thread.sleep(10000);
+
+ ListMultimap<String,TablePermission> postperms =
+ AccessControlLists.getTablePermissions(conf, TEST_TABLE);
+
+ checkMultimapEqual(preperms, postperms);
+ }
+
+ @Test
+ public void testSerialization() throws Exception {
+ Configuration conf = UTIL.getConfiguration();
+ ListMultimap<String,TablePermission> permissions = ArrayListMultimap.create();
+ permissions.put("george", new TablePermission(TEST_TABLE, null,
+ TablePermission.Action.READ));
+ permissions.put("george", new TablePermission(TEST_TABLE, TEST_FAMILY,
+ TablePermission.Action.WRITE));
+ permissions.put("george", new TablePermission(TEST_TABLE2, null,
+ TablePermission.Action.READ));
+ permissions.put("hubert", new TablePermission(TEST_TABLE2, null,
+ TablePermission.Action.READ, TablePermission.Action.WRITE));
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ AccessControlLists.writePermissions(new DataOutputStream(bos),
+ permissions, conf);
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+ ListMultimap<String,TablePermission> copy =
+ AccessControlLists.readPermissions(new DataInputStream(bis), conf);
+
+ checkMultimapEqual(permissions, copy);
+ }
+
+ public void checkMultimapEqual(ListMultimap<String,TablePermission> first,
+ ListMultimap<String,TablePermission> second) {
+ assertEquals(first.size(), second.size());
+ for (String key : first.keySet()) {
+ List<TablePermission> firstPerms = first.get(key);
+ List<TablePermission> secondPerms = second.get(key);
+ assertNotNull(secondPerms);
+ assertEquals(firstPerms.size(), secondPerms.size());
+ LOG.info("First permissions: "+firstPerms.toString());
+ LOG.info("Second permissions: "+secondPerms.toString());
+ for (TablePermission p : firstPerms) {
+ assertTrue("Permission "+p.toString()+" not found", secondPerms.contains(p));
+ }
+ }
+ }
+
+ @Test
+ public void testEquals() throws Exception {
+ TablePermission p1 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ);
+ TablePermission p2 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ);
+ assertTrue(p1.equals(p2));
+ assertTrue(p2.equals(p1));
+
+ p1 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ, TablePermission.Action.WRITE);
+ p2 = new TablePermission(TEST_TABLE, null, TablePermission.Action.WRITE, TablePermission.Action.READ);
+ assertTrue(p1.equals(p2));
+ assertTrue(p2.equals(p1));
+
+ p1 = new TablePermission(TEST_TABLE, TEST_FAMILY, TablePermission.Action.READ, TablePermission.Action.WRITE);
+ p2 = new TablePermission(TEST_TABLE, TEST_FAMILY, TablePermission.Action.WRITE, TablePermission.Action.READ);
+ assertTrue(p1.equals(p2));
+ assertTrue(p2.equals(p1));
+
+ p1 = new TablePermission(TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER, TablePermission.Action.READ, TablePermission.Action.WRITE);
+ p2 = new TablePermission(TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER, TablePermission.Action.WRITE, TablePermission.Action.READ);
+ assertTrue(p1.equals(p2));
+ assertTrue(p2.equals(p1));
+
+ p1 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ);
+ p2 = new TablePermission(TEST_TABLE, TEST_FAMILY, TablePermission.Action.READ);
+ assertFalse(p1.equals(p2));
+ assertFalse(p2.equals(p1));
+
+ p1 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ);
+ p2 = new TablePermission(TEST_TABLE, null, TablePermission.Action.WRITE);
+ assertFalse(p1.equals(p2));
+ assertFalse(p2.equals(p1));
+ p2 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ, TablePermission.Action.WRITE);
+ assertFalse(p1.equals(p2));
+ assertFalse(p2.equals(p1));
+
+ p1 = new TablePermission(TEST_TABLE, null, TablePermission.Action.READ);
+ p2 = new TablePermission(TEST_TABLE2, null, TablePermission.Action.READ);
+ assertFalse(p1.equals(p2));
+ assertFalse(p2.equals(p1));
+
+ p2 = new TablePermission(TEST_TABLE, null);
+ assertFalse(p1.equals(p2));
+ assertFalse(p2.equals(p1));
+ }
+}
Added: hbase/branches/0.92/security/src/test/java/org/apache/hadoop/hbase/security/access/TestZKPermissionsWatcher.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/security/src/test/java/org/apache/hadoop/hbase/security/access/TestZKPermissionsWatcher.java?rev=1203915&view=auto
==============================================================================
--- hbase/branches/0.92/security/src/test/java/org/apache/hadoop/hbase/security/access/TestZKPermissionsWatcher.java (added)
+++ hbase/branches/0.92/security/src/test/java/org/apache/hadoop/hbase/security/access/TestZKPermissionsWatcher.java Sat Nov 19 00:25:37 2011
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hbase.security.access;
+
+import static org.junit.Assert.*;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.Abortable;
+import org.apache.hadoop.hbase.HBaseTestingUtility;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Test the reading and writing of access permissions to and from zookeeper.
+ */
+public class TestZKPermissionsWatcher {
+ private static final Log LOG = LogFactory.getLog(TestZKPermissionsWatcher.class);
+ private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
+ private static TableAuthManager AUTH_A;
+ private static TableAuthManager AUTH_B;
+ private final static Abortable ABORTABLE = new Abortable() {
+ private final AtomicBoolean abort = new AtomicBoolean(false);
+
+ @Override
+ public void abort(String why, Throwable e) {
+ LOG.info(why, e);
+ abort.set(true);
+ }
+
+ @Override
+ public boolean isAborted() {
+ return abort.get();
+ }
+ };
+
+ private static byte[] TEST_TABLE = Bytes.toBytes("perms_test");
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ // setup configuration
+ Configuration conf = UTIL.getConfiguration();
+ SecureTestUtil.enableSecurity(conf);
+
+ // start minicluster
+ UTIL.startMiniCluster();
+ AUTH_A = TableAuthManager.get(new ZooKeeperWatcher(conf,
+ "TestZKPermissionsWatcher_1", ABORTABLE), conf);
+ AUTH_B = TableAuthManager.get(new ZooKeeperWatcher(conf,
+ "TestZKPermissionsWatcher_2", ABORTABLE), conf);
+ }
+
+ @AfterClass
+ public static void afterClass() throws Exception {
+ UTIL.shutdownMiniCluster();
+ }
+
+ @Test
+ public void testPermissionsWatcher() throws Exception {
+ assertFalse(AUTH_A.authorizeUser("george", TEST_TABLE, null,
+ TablePermission.Action.READ));
+ assertFalse(AUTH_A.authorizeUser("george", TEST_TABLE, null,
+ TablePermission.Action.WRITE));
+ assertFalse(AUTH_A.authorizeUser("hubert", TEST_TABLE, null,
+ TablePermission.Action.READ));
+ assertFalse(AUTH_A.authorizeUser("hubert", TEST_TABLE, null,
+ TablePermission.Action.WRITE));
+
+ assertFalse(AUTH_B.authorizeUser("george", TEST_TABLE, null,
+ TablePermission.Action.READ));
+ assertFalse(AUTH_B.authorizeUser("george", TEST_TABLE, null,
+ TablePermission.Action.WRITE));
+ assertFalse(AUTH_B.authorizeUser("hubert", TEST_TABLE, null,
+ TablePermission.Action.READ));
+ assertFalse(AUTH_B.authorizeUser("hubert", TEST_TABLE, null,
+ TablePermission.Action.WRITE));
+
+ // update ACL: george RW
+ List<TablePermission> acl = new ArrayList<TablePermission>();
+ acl.add(new TablePermission(TEST_TABLE, null, TablePermission.Action.READ,
+ TablePermission.Action.WRITE));
+ AUTH_A.setUserPermissions("george", TEST_TABLE, acl);
+ Thread.sleep(100);
+
+ // check it
+ assertTrue(AUTH_A.authorizeUser("george", TEST_TABLE, null,
+ TablePermission.Action.READ));
+ assertTrue(AUTH_A.authorizeUser("george", TEST_TABLE, null,
+ TablePermission.Action.WRITE));
+ assertTrue(AUTH_B.authorizeUser("george", TEST_TABLE, null,
+ TablePermission.Action.READ));
+ assertTrue(AUTH_B.authorizeUser("george", TEST_TABLE, null,
+ TablePermission.Action.WRITE));
+ assertFalse(AUTH_A.authorizeUser("hubert", TEST_TABLE, null,
+ TablePermission.Action.READ));
+ assertFalse(AUTH_A.authorizeUser("hubert", TEST_TABLE, null,
+ TablePermission.Action.WRITE));
+ assertFalse(AUTH_B.authorizeUser("hubert", TEST_TABLE, null,
+ TablePermission.Action.READ));
+ assertFalse(AUTH_B.authorizeUser("hubert", TEST_TABLE, null,
+ TablePermission.Action.WRITE));
+
+ // update ACL: hubert R
+ acl = new ArrayList<TablePermission>();
+ acl.add(new TablePermission(TEST_TABLE, null, TablePermission.Action.READ));
+ AUTH_B.setUserPermissions("hubert", TEST_TABLE, acl);
+ Thread.sleep(100);
+
+ // check it
+ assertTrue(AUTH_A.authorizeUser("george", TEST_TABLE, null,
+ TablePermission.Action.READ));
+ assertTrue(AUTH_A.authorizeUser("george", TEST_TABLE, null,
+ TablePermission.Action.WRITE));
+ assertTrue(AUTH_B.authorizeUser("george", TEST_TABLE, null,
+ TablePermission.Action.READ));
+ assertTrue(AUTH_B.authorizeUser("george", TEST_TABLE, null,
+ TablePermission.Action.WRITE));
+ assertTrue(AUTH_A.authorizeUser("hubert", TEST_TABLE, null,
+ TablePermission.Action.READ));
+ assertFalse(AUTH_A.authorizeUser("hubert", TEST_TABLE, null,
+ TablePermission.Action.WRITE));
+ assertTrue(AUTH_B.authorizeUser("hubert", TEST_TABLE, null,
+ TablePermission.Action.READ));
+ assertFalse(AUTH_B.authorizeUser("hubert", TEST_TABLE, null,
+ TablePermission.Action.WRITE));
+ }
+}
Modified: hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java?rev=1203915&r1=1203914&r2=1203915&view=diff
==============================================================================
--- hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java (original)
+++ hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java Sat Nov 19 00:25:37 2011
@@ -35,6 +35,7 @@ import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.io.hfile.Compression;
import org.apache.hadoop.hbase.regionserver.StoreFile;
+import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.io.WritableComparable;
@@ -80,7 +81,11 @@ public class HTableDescriptor implements
public static final String MAX_FILESIZE = "MAX_FILESIZE";
private static final ImmutableBytesWritable MAX_FILESIZE_KEY =
new ImmutableBytesWritable(Bytes.toBytes(MAX_FILESIZE));
-
+
+ public static final String OWNER = "OWNER";
+ public static final ImmutableBytesWritable OWNER_KEY =
+ new ImmutableBytesWritable(Bytes.toBytes(OWNER));
+
/**
* <em>INTERNAL</em> Used by rest interface to access this metadata
* attribute which denotes if the table is Read Only
@@ -90,7 +95,7 @@ public class HTableDescriptor implements
public static final String READONLY = "READONLY";
private static final ImmutableBytesWritable READONLY_KEY =
new ImmutableBytesWritable(Bytes.toBytes(READONLY));
-
+
/**
* <em>INTERNAL</em> Used by HBase Shell interface to access this metadata
* attribute which represents the maximum size of the memstore after which
@@ -101,7 +106,7 @@ public class HTableDescriptor implements
public static final String MEMSTORE_FLUSHSIZE = "MEMSTORE_FLUSHSIZE";
private static final ImmutableBytesWritable MEMSTORE_FLUSHSIZE_KEY =
new ImmutableBytesWritable(Bytes.toBytes(MEMSTORE_FLUSHSIZE));
-
+
/**
* <em>INTERNAL</em> Used by rest interface to access this metadata
* attribute which denotes if the table is a -ROOT- region or not
@@ -111,7 +116,7 @@ public class HTableDescriptor implements
public static final String IS_ROOT = "IS_ROOT";
private static final ImmutableBytesWritable IS_ROOT_KEY =
new ImmutableBytesWritable(Bytes.toBytes(IS_ROOT));
-
+
/**
* <em>INTERNAL</em> Used by rest interface to access this metadata
* attribute which denotes if it is a catalog table, either
@@ -1064,7 +1069,7 @@ public class HTableDescriptor implements
public static final HTableDescriptor ROOT_TABLEDESC = new HTableDescriptor(
HConstants.ROOT_TABLE_NAME,
new HColumnDescriptor[] { new HColumnDescriptor(HConstants.CATALOG_FAMILY,
- 10, // Ten is arbitrary number. Keep versions to help debuggging.
+ 10, // Ten is arbitrary number. Keep versions to help debugging.
Compression.Algorithm.NONE.getName(), true, true, 8 * 1024,
HConstants.FOREVER, StoreFile.BloomType.NONE.toString(),
HConstants.REPLICATION_SCOPE_LOCAL) });
@@ -1073,8 +1078,31 @@ public class HTableDescriptor implements
public static final HTableDescriptor META_TABLEDESC = new HTableDescriptor(
HConstants.META_TABLE_NAME, new HColumnDescriptor[] {
new HColumnDescriptor(HConstants.CATALOG_FAMILY,
- 10, // Ten is arbitrary number. Keep versions to help debuggging.
+ 10, // Ten is arbitrary number. Keep versions to help debugging.
Compression.Algorithm.NONE.getName(), true, true, 8 * 1024,
HConstants.FOREVER, StoreFile.BloomType.NONE.toString(),
HConstants.REPLICATION_SCOPE_LOCAL)});
+
+
+ public void setOwner(User owner) {
+ setOwnerString(owner != null ? owner.getShortName() : null);
+ }
+
+ // used by admin.rb:alter(table_name,*args) to update owner.
+ public void setOwnerString(String ownerString) {
+ if (ownerString != null) {
+ setValue(OWNER_KEY, Bytes.toBytes(ownerString));
+ } else {
+ values.remove(OWNER_KEY);
+ }
+ }
+
+ public String getOwnerString() {
+ if (getValue(OWNER_KEY) != null) {
+ return Bytes.toString(getValue(OWNER_KEY));
+ }
+ // Note that every table should have an owner (i.e. should have OWNER_KEY set).
+ // .META. and -ROOT- should return system user as owner, not null (see MasterFileSystem.java:bootstrap()).
+ return null;
+ }
}
Modified: hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseRegionObserver.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseRegionObserver.java?rev=1203915&r1=1203914&r2=1203915&view=diff
==============================================================================
--- hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseRegionObserver.java (original)
+++ hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseRegionObserver.java Sat Nov 19 00:25:37 2011
@@ -48,10 +48,10 @@ import java.io.IOException;
*/
public abstract class BaseRegionObserver implements RegionObserver {
@Override
- public void start(CoprocessorEnvironment e) { }
+ public void start(CoprocessorEnvironment e) throws IOException { }
@Override
- public void stop(CoprocessorEnvironment e) { }
+ public void stop(CoprocessorEnvironment e) throws IOException { }
@Override
public void preOpen(ObserverContext<RegionCoprocessorEnvironment> e) { }
Modified: hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java?rev=1203915&r1=1203914&r2=1203915&view=diff
==============================================================================
--- hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java (original)
+++ hbase/branches/0.92/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java Sat Nov 19 00:25:37 2011
@@ -381,6 +381,9 @@ public class ZKUtil {
public String toString() {
return node + " (" + RegionTransitionData.fromBytes(data) + ")";
}
+ public boolean isEmpty() {
+ return (data.length == 0);
+ }
}
/**
Modified: hbase/branches/0.92/src/main/resources/hbase-default.xml
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/src/main/resources/hbase-default.xml?rev=1203915&r1=1203914&r2=1203915&view=diff
==============================================================================
--- hbase/branches/0.92/src/main/resources/hbase-default.xml (original)
+++ hbase/branches/0.92/src/main/resources/hbase-default.xml Sat Nov 19 00:25:37 2011
@@ -622,6 +622,12 @@
</property>
<property>
+ <name>zookeeper.znode.acl.parent</name>
+ <value>acl</value>
+ <description>Root ZNode for access control lists.</description>
+ </property>
+
+ <property>
<name>hbase.coprocessor.region.classes</name>
<value></value>
<description>A comma-separated list of Coprocessors that are loaded by
Modified: hbase/branches/0.92/src/main/ruby/hbase.rb
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/src/main/ruby/hbase.rb?rev=1203915&r1=1203914&r2=1203915&view=diff
==============================================================================
--- hbase/branches/0.92/src/main/ruby/hbase.rb (original)
+++ hbase/branches/0.92/src/main/ruby/hbase.rb Sat Nov 19 00:25:37 2011
@@ -73,3 +73,4 @@ require 'hbase/hbase'
require 'hbase/admin'
require 'hbase/table'
require 'hbase/replication_admin'
+require 'hbase/security'
Modified: hbase/branches/0.92/src/main/ruby/hbase/admin.rb
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/src/main/ruby/hbase/admin.rb?rev=1203915&r1=1203914&r2=1203915&view=diff
==============================================================================
--- hbase/branches/0.92/src/main/ruby/hbase/admin.rb (original)
+++ hbase/branches/0.92/src/main/ruby/hbase/admin.rb Sat Nov 19 00:25:37 2011
@@ -281,7 +281,6 @@ module Hbase
@admin.createTable(table_description)
end
- #----------------------------------------------------------------------------------------------
# Check the status of alter command (number of regions reopened)
def alter_status(table_name)
# Table name should be a string
@@ -328,7 +327,17 @@ module Hbase
# No method parameter, try to use the args as a column definition
unless method = arg.delete(METHOD)
+ # Note that we handle owner here, and also below (see (2)) as part of the "METHOD => 'table_att'" table attributes.
+ # In other words, if OWNER is specified, then METHOD is set to table_att.
+ # alter 'tablename', {OWNER => 'username'} (that is, METHOD => 'table_att' is not specified).
+ if arg[OWNER]
+ htd.setOwnerString(arg[OWNER])
+ @admin.modifyTable(table_name.to_java_bytes, htd)
+ return
+ end
+
descriptor = hcd(arg, htd)
+
if arg[COMPRESSION_COMPACT]
descriptor.setValue(COMPRESSION_COMPACT, arg[COMPRESSION_COMPACT])
end
@@ -368,6 +377,8 @@ module Hbase
htd.setReadOnly(JBoolean.valueOf(arg[READONLY])) if arg[READONLY]
htd.setMemStoreFlushSize(JLong.valueOf(arg[MEMSTORE_FLUSHSIZE])) if arg[MEMSTORE_FLUSHSIZE]
htd.setDeferredLogFlush(JBoolean.valueOf(arg[DEFERRED_LOG_FLUSH])) if arg[DEFERRED_LOG_FLUSH]
+ # (2) Here, we handle the alternate syntax of ownership setting, where method => 'table_att' is specified.
+ htd.setOwnerString(arg[OWNER]) if arg[OWNER]
# set a coprocessor attribute
if arg.kind_of?(Hash)
Modified: hbase/branches/0.92/src/main/ruby/hbase/hbase.rb
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/src/main/ruby/hbase/hbase.rb?rev=1203915&r1=1203914&r2=1203915&view=diff
==============================================================================
--- hbase/branches/0.92/src/main/ruby/hbase/hbase.rb (original)
+++ hbase/branches/0.92/src/main/ruby/hbase/hbase.rb Sat Nov 19 00:25:37 2011
@@ -22,6 +22,7 @@ include Java
require 'hbase/admin'
require 'hbase/table'
+require 'hbase/security'
module Hbase
class Hbase
@@ -52,5 +53,8 @@ module Hbase
::Hbase::RepAdmin.new(configuration, formatter)
end
+ def security_admin(formatter)
+ ::Hbase::SecurityAdmin.new(configuration, formatter)
+ end
end
end
Added: hbase/branches/0.92/src/main/ruby/hbase/security.rb
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/src/main/ruby/hbase/security.rb?rev=1203915&view=auto
==============================================================================
--- hbase/branches/0.92/src/main/ruby/hbase/security.rb (added)
+++ hbase/branches/0.92/src/main/ruby/hbase/security.rb Sat Nov 19 00:25:37 2011
@@ -0,0 +1,128 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include Java
+
+# Wrapper for org.apache.hadoop.hbase.client.HBaseAdmin
+
+module Hbase
+ class SecurityAdmin
+ include HBaseConstants
+
+ def initialize(configuration, formatter)
+ @config = configuration
+ @admin = org.apache.hadoop.hbase.client.HBaseAdmin.new(configuration)
+ @formatter = formatter
+ end
+
+ #----------------------------------------------------------------------------------------------
+ def grant(user, permissions, table_name, family=nil, qualifier=nil)
+ security_available?
+
+ # Table should exist
+ raise(ArgumentError, "Can't find a table: #{table_name}") unless exists?(table_name)
+
+ htd = @admin.getTableDescriptor(table_name.to_java_bytes)
+
+ if (family != nil)
+ raise(ArgumentError, "Can't find a family: #{family}") unless htd.hasFamily(family.to_java_bytes)
+ end
+
+ #TODO: need to validate user name
+
+ # invoke cp endpoint to perform access control
+ fambytes = family.to_java_bytes if (family != nil)
+ qualbytes = qualifier.to_java_bytes if (qualifier != nil)
+ tp = org.apache.hadoop.hbase.security.access.TablePermission.new(table_name.to_java_bytes, fambytes, qualbytes, permissions.to_java_bytes)
+ meta_table = org.apache.hadoop.hbase.client.HTable.new(@config, org.apache.hadoop.hbase.security.access.AccessControlLists::ACL_TABLE_NAME)
+ protocol = meta_table.coprocessorProxy(org.apache.hadoop.hbase.security.access.AccessControllerProtocol.java_class,
+ org.apache.hadoop.hbase.HConstants::EMPTY_START_ROW)
+ protocol.grant(user.to_java_bytes, tp)
+ end
+
+ #----------------------------------------------------------------------------------------------
+ def revoke(user, table_name, family=nil, qualifier=nil)
+ security_available?
+
+ # Table should exist
+ raise(ArgumentError, "Can't find table: #{table_name}") unless exists?(table_name)
+
+ htd = @admin.getTableDescriptor(table_name.to_java_bytes)
+
+ if (family != nil)
+ raise(ArgumentError, "Can't find a family: #{family}") unless htd.hasFamily(family.to_java_bytes)
+ end
+
+ fambytes = family.to_java_bytes if (family != nil)
+ qualbytes = qualifier.to_java_bytes if (qualifier != nil)
+ tp = org.apache.hadoop.hbase.security.access.TablePermission.new(table_name.to_java_bytes, fambytes, qualbytes, "".to_java_bytes)
+ meta_table = org.apache.hadoop.hbase.client.HTable.new(@config, org.apache.hadoop.hbase.security.access.AccessControlLists::ACL_TABLE_NAME)
+ protocol = meta_table.coprocessorProxy(org.apache.hadoop.hbase.security.access.AccessControllerProtocol.java_class,
+ org.apache.hadoop.hbase.HConstants::EMPTY_START_ROW)
+ protocol.revoke(user.to_java_bytes, tp)
+ end
+
+ #----------------------------------------------------------------------------------------------
+ def user_permission(table_name)
+ security_available?
+
+ raise(ArgumentError, "Can't find table: #{table_name}") unless exists?(table_name)
+
+ meta_table = org.apache.hadoop.hbase.client.HTable.new(@config, org.apache.hadoop.hbase.security.access.AccessControlLists::ACL_TABLE_NAME)
+ protocol = meta_table.coprocessorProxy(org.apache.hadoop.hbase.security.access.AccessControllerProtocol.java_class,
+ org.apache.hadoop.hbase.HConstants::EMPTY_START_ROW)
+ perms = protocol.getUserPermissions(table_name.to_java_bytes)
+
+ res = {}
+ count = 0
+ perms.each do |value|
+ user_name = String.from_java_bytes(value.getUser)
+ table = (value.getTable != nil) ? org.apache.hadoop.hbase.util.Bytes::toStringBinary(value.getTable) : ''
+ family = (value.getFamily != nil) ? org.apache.hadoop.hbase.util.Bytes::toStringBinary(value.getFamily) : ''
+ qualifier = (value.getQualifier != nil) ? org.apache.hadoop.hbase.util.Bytes::toStringBinary(value.getQualifier) : ''
+
+ action = org.apache.hadoop.hbase.security.access.Permission.new value.getActions
+
+ if block_given?
+ yield(user_name, "#{table},#{family},#{qualifier}: #{action.to_s}")
+ else
+ res[user_name] ||= {}
+ res[user_name][family + ":" +qualifier] = action
+ end
+ count += 1
+ end
+
+ return ((block_given?) ? count : res)
+ end
+
+ # Does table exist?
+ def exists?(table_name)
+ @admin.tableExists(table_name)
+ end
+
+ # Make sure that security classes are available
+ def security_available?()
+ begin
+ org.apache.hadoop.hbase.security.access.AccessControllerProtocol
+ rescue NameError
+ raise(ArgumentError, "DISABLED: Security features are not available in this build of HBase")
+ end
+ end
+
+ end
+end
Modified: hbase/branches/0.92/src/main/ruby/shell.rb
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/src/main/ruby/shell.rb?rev=1203915&r1=1203914&r2=1203915&view=diff
==============================================================================
--- hbase/branches/0.92/src/main/ruby/shell.rb (original)
+++ hbase/branches/0.92/src/main/ruby/shell.rb Sat Nov 19 00:25:37 2011
@@ -87,6 +87,10 @@ module Shell
@hbase_replication_admin ||= hbase.replication_admin(formatter)
end
+ def hbase_security_admin
+ @hbase_security_admin ||= hbase.security_admin(formatter)
+ end
+
def export_commands(where)
::Shell.commands.keys.each do |cmd|
where.send :instance_eval, <<-EOF
@@ -284,3 +288,14 @@ Shell.load_command_group(
]
)
+Shell.load_command_group(
+ 'security',
+ :full_name => 'SECURITY TOOLS',
+ :comment => "NOTE: Above commands are only applicable if running with the AccessController coprocessor",
+ :commands => %w[
+ grant
+ revoke
+ user_permission
+ ]
+)
+
Modified: hbase/branches/0.92/src/main/ruby/shell/commands.rb
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/src/main/ruby/shell/commands.rb?rev=1203915&r1=1203914&r2=1203915&view=diff
==============================================================================
--- hbase/branches/0.92/src/main/ruby/shell/commands.rb (original)
+++ hbase/branches/0.92/src/main/ruby/shell/commands.rb Sat Nov 19 00:25:37 2011
@@ -53,6 +53,10 @@ module Shell
shell.hbase_replication_admin
end
+ def security_admin
+ shell.hbase_security_admin
+ end
+
#----------------------------------------------------------------------
def formatter
Added: hbase/branches/0.92/src/main/ruby/shell/commands/grant.rb
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/src/main/ruby/shell/commands/grant.rb?rev=1203915&view=auto
==============================================================================
--- hbase/branches/0.92/src/main/ruby/shell/commands/grant.rb (added)
+++ hbase/branches/0.92/src/main/ruby/shell/commands/grant.rb Sat Nov 19 00:25:37 2011
@@ -0,0 +1,43 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+module Shell
+ module Commands
+ class Grant < Command
+ def help
+ return <<-EOF
+Grant users specific rights to tables.
+Syntax : grant <user> <permissions> <table> <column family> <column qualifier>
+
+permissions is either zero or more letters from the set "RWXCA".
+READ('R'), WRITE('W'), EXEC('X'), CREATE('C'), ADMIN('A')
+
+For example:
+
+ hbase> grant 'bobsmith', 'RW', 't1', 'f1', 'col1'
+EOF
+ end
+
+ def command(user, rights, table_name, family=nil, qualifier=nil)
+ format_simple_command do
+ security_admin.grant(user, rights, table_name, family, qualifier)
+ end
+ end
+ end
+ end
+end
Added: hbase/branches/0.92/src/main/ruby/shell/commands/revoke.rb
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/src/main/ruby/shell/commands/revoke.rb?rev=1203915&view=auto
==============================================================================
--- hbase/branches/0.92/src/main/ruby/shell/commands/revoke.rb (added)
+++ hbase/branches/0.92/src/main/ruby/shell/commands/revoke.rb Sat Nov 19 00:25:37 2011
@@ -0,0 +1,39 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+module Shell
+ module Commands
+ class Revoke < Command
+ def help
+ return <<-EOF
+Revoke a user's access rights to tables.
+Syntax : revoke <user> <table> <column family>
+For example:
+
+ hbase> revoke 'bobsmith', 't1', 'f1'
+EOF
+ end
+
+ def command(user, table_name, family=nil, qualifier=nil)
+ format_simple_command do
+ security_admin.revoke(user, table_name, family, qualifier)
+ end
+ end
+ end
+ end
+end
Added: hbase/branches/0.92/src/main/ruby/shell/commands/user_permission.rb
URL: http://svn.apache.org/viewvc/hbase/branches/0.92/src/main/ruby/shell/commands/user_permission.rb?rev=1203915&view=auto
==============================================================================
--- hbase/branches/0.92/src/main/ruby/shell/commands/user_permission.rb (added)
+++ hbase/branches/0.92/src/main/ruby/shell/commands/user_permission.rb Sat Nov 19 00:25:37 2011
@@ -0,0 +1,46 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+module Shell
+ module Commands
+ class UserPermission < Command
+ def help
+ return <<-EOF
+Show all table access permissions for the particular user.
+Syntax : user_permission <table>
+For example:
+
+ hbase> user_permission 'table1'
+EOF
+ end
+
+ def command(table)
+ #format_simple_command do
+ #admin.user_permission(table)
+ now = Time.now
+ formatter.header(["User", "Table,Family,Qualifier:Permission"])
+
+ count = security_admin.user_permission(table) do |user, permission|
+ formatter.row([ user, permission])
+ end
+
+ formatter.footer(now, count)
+ end
+ end
+ end
+end