You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by mb...@apache.org on 2013/01/09 06:45:33 UTC
svn commit: r1430691 - in
/hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access:
AccessController.java AuthResult.java
Author: mbertozzi
Date: Wed Jan 9 05:45:33 2013
New Revision: 1430691
URL: http://svn.apache.org/viewvc?rev=1430691&view=rev
Log:
HBASE-6386 Audit log messages do not include column family / qualifier information consistently (Marcelo Vanzin)
Modified:
hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AuthResult.java
Modified: hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java?rev=1430691&r1=1430690&r2=1430691&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java (original)
+++ hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java Wed Jan 9 05:45:33 2013
@@ -64,6 +64,7 @@ import org.apache.hadoop.hbase.security.
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker;
@@ -198,12 +199,14 @@ public class AccessController extends Ba
// this is a very common operation, so deal with it quickly.
if (hri.isRootRegion() || hri.isMetaRegion()) {
if (permRequest == Permission.Action.READ) {
- return AuthResult.allow(request, "All users allowed", user, permRequest, tableName);
+ return AuthResult.allow(request, "All users allowed", user,
+ permRequest, tableName, families);
}
}
if (user == null) {
- return AuthResult.deny(request, "No user associated with request!", null, permRequest, tableName);
+ return AuthResult.deny(request, "No user associated with request!", null,
+ permRequest, tableName, families);
}
// Users with CREATE/ADMIN rights need to modify .META. and _acl_ table
@@ -217,12 +220,14 @@ public class AccessController extends Ba
(authManager.authorize(user, Permission.Action.CREATE) ||
authManager.authorize(user, Permission.Action.ADMIN)))
{
- return AuthResult.allow(request, "Table permission granted", user, permRequest, tableName);
+ return AuthResult.allow(request, "Table permission granted", user,
+ permRequest, tableName, families);
}
// 2. check for the table-level, if successful we can short-circuit
if (authManager.authorize(user, tableName, (byte[])null, permRequest)) {
- return AuthResult.allow(request, "Table permission granted", user, permRequest, tableName);
+ return AuthResult.allow(request, "Table permission granted", user,
+ permRequest, tableName, families);
}
// 3. check permissions against the requested families
@@ -244,7 +249,7 @@ public class AccessController extends Ba
if (!authManager.authorize(user, tableName, family.getKey(),
qualifier, permRequest)) {
return AuthResult.deny(request, "Failed qualifier check", user,
- permRequest, tableName, family.getKey(), qualifier);
+ permRequest, tableName, makeFamilyMap(family.getKey(), qualifier));
}
}
} else if (family.getValue() instanceof List) { // List<KeyValue>
@@ -253,25 +258,25 @@ public class AccessController extends Ba
if (!authManager.authorize(user, tableName, family.getKey(),
kv.getQualifier(), permRequest)) {
return AuthResult.deny(request, "Failed qualifier check", user,
- permRequest, tableName, family.getKey(), kv.getQualifier());
+ permRequest, tableName, makeFamilyMap(family.getKey(), kv.getQualifier()));
}
}
}
} else {
// no qualifiers and family-level check already failed
return AuthResult.deny(request, "Failed family check", user, permRequest,
- tableName, family.getKey(), null);
+ tableName, makeFamilyMap(family.getKey(), null));
}
}
// all family checks passed
return AuthResult.allow(request, "All family checks passed", user, permRequest,
- tableName);
+ tableName, families);
}
// 4. no families to check and table level access failed
return AuthResult.deny(request, "No families to check and table permission failed",
- user, permRequest, tableName);
+ user, permRequest, tableName, families);
}
private void logResult(AuthResult result) {
@@ -344,9 +349,9 @@ public class AccessController extends Ba
private void requirePermission(String request, Permission.Action perm) throws IOException {
User user = getActiveUser();
if (authManager.authorize(user, perm)) {
- logResult(AuthResult.allow(request, "Global check allowed", user, perm, null));
+ logResult(AuthResult.allow(request, "Global check allowed", user, perm, null, null));
} else {
- logResult(AuthResult.deny(request, "Global check failed", user, perm, null));
+ logResult(AuthResult.deny(request, "Global check failed", user, perm, null, null));
throw new AccessDeniedException("Insufficient permissions for user '" +
(user != null ? user.getShortName() : "null") +"' (global, action=" +
perm.toString() + ")");
@@ -358,25 +363,6 @@ public class AccessController extends Ba
* action on the set of table column families.
* @param perm Action that is required
* @param env The current coprocessor environment
- * @param families The set of column families present/required in the request
- * @throws AccessDeniedException if the authorization check failed
- */
- private void requirePermission(String request, Permission.Action perm,
- RegionCoprocessorEnvironment env, Collection<byte[]> families)
- throws IOException {
- // create a map of family-qualifier
- HashMap<byte[], Set<byte[]>> familyMap = new HashMap<byte[], Set<byte[]>>();
- for (byte[] family : families) {
- familyMap.put(family, null);
- }
- requirePermission(request, perm, env, familyMap);
- }
-
- /**
- * Authorizes that the current user has permission to perform the given
- * action on the set of table column families.
- * @param perm Action that is required
- * @param env The current coprocessor environment
* @param families The map of column families-qualifiers.
* @throws AccessDeniedException if the authorization check failed
*/
@@ -389,24 +375,36 @@ public class AccessController extends Ba
logResult(result);
if (!result.isAllowed()) {
- StringBuilder sb = new StringBuilder("");
- if ((families != null && families.size() > 0)) {
- for (byte[] familyName : families.keySet()) {
- if (sb.length() != 0) {
- sb.append(", ");
- }
- sb.append(Bytes.toString(familyName));
- }
- }
throw new AccessDeniedException("Insufficient permissions (table=" +
env.getRegion().getTableDesc().getNameAsString()+
((families != null && families.size() > 0) ? ", family: " +
- sb.toString() : "") + ", action=" +
+ result.toFamilyString() : "") + ", action=" +
perm.toString() + ")");
}
}
/**
+ * Checks that the user has the given global permission. The generated
+ * audit log message will contain context information for the operation
+ * being authorized, based on the given parameters.
+ * @param perm Action being requested
+ * @param tableName Affected table name.
+ * @param familiMap Affected column families.
+ */
+ private void requireGlobalPermission(String request, Permission.Action perm, byte[] tableName,
+ Map<byte[], ? extends Collection<byte[]>> familyMap) throws IOException {
+ User user = getActiveUser();
+ if (authManager.authorize(user, perm)) {
+ logResult(AuthResult.allow(request, "Global check allowed", user, perm, tableName, familyMap));
+ } else {
+ logResult(AuthResult.deny(request, "Global check failed", user, perm, tableName, familyMap));
+ throw new AccessDeniedException("Insufficient permissions for user '" +
+ (user != null ? user.getShortName() : "null") +"' (global, action=" +
+ perm.toString() + ")");
+ }
+ }
+
+ /**
* Returns <code>true</code> if the current user is allowed the given action
* over at least one of the column qualifiers in the given column families.
*/
@@ -785,7 +783,7 @@ public class AccessController extends Ba
assert family != null;
//noinspection PrimitiveArrayArgumentToVariableArgMethod
requirePermission("getClosestRowBefore", Permission.Action.READ, c.getEnvironment(),
- Lists.newArrayList(family));
+ makeFamilyMap(family, null));
}
@Override
@@ -815,7 +813,7 @@ public class AccessController extends Ba
get.setFilter(filter);
}
logResult(AuthResult.allow("get", "Access allowed with filter", requestUser,
- Permission.Action.READ, authResult.getTable()));
+ Permission.Action.READ, authResult.getTable(), get.getFamilyMap()));
} else {
logResult(authResult);
throw new AccessDeniedException("Insufficient permissions (table=" +
@@ -831,7 +829,7 @@ public class AccessController extends Ba
public boolean preExists(final ObserverContext<RegionCoprocessorEnvironment> c,
final Get get, final boolean exists) throws IOException {
requirePermission("exists", Permission.Action.READ, c.getEnvironment(),
- get.familySet());
+ get.getFamilyMap());
return exists;
}
@@ -874,7 +872,7 @@ public class AccessController extends Ba
final CompareFilter.CompareOp compareOp,
final ByteArrayComparable comparator, final Put put,
final boolean result) throws IOException {
- Collection<byte[]> familyMap = Arrays.asList(new byte[][]{family});
+ Map<byte[], ? extends Collection<byte[]>> familyMap = makeFamilyMap(family, qualifier);
requirePermission("checkAndPut", Permission.Action.READ, c.getEnvironment(), familyMap);
requirePermission("checkAndPut", Permission.Action.WRITE, c.getEnvironment(), familyMap);
return result;
@@ -886,7 +884,7 @@ public class AccessController extends Ba
final CompareFilter.CompareOp compareOp,
final ByteArrayComparable comparator, final Delete delete,
final boolean result) throws IOException {
- Collection<byte[]> familyMap = Arrays.asList(new byte[][]{family});
+ Map<byte[], ? extends Collection<byte[]>> familyMap = makeFamilyMap(family, qualifier);
requirePermission("checkAndDelete", Permission.Action.READ, c.getEnvironment(), familyMap);
requirePermission("checkAndDelete", Permission.Action.WRITE, c.getEnvironment(), familyMap);
return result;
@@ -897,8 +895,8 @@ public class AccessController extends Ba
final byte [] row, final byte [] family, final byte [] qualifier,
final long amount, final boolean writeToWAL)
throws IOException {
- requirePermission("incrementColumnValue", Permission.Action.WRITE, c.getEnvironment(),
- Arrays.asList(new byte[][]{family}));
+ Map<byte[], ? extends Collection<byte[]>> familyMap = makeFamilyMap(family, qualifier);
+ requirePermission("incrementColumnValue", Permission.Action.WRITE, c.getEnvironment(), familyMap);
return -1;
}
@@ -913,8 +911,11 @@ public class AccessController extends Ba
public Result preIncrement(final ObserverContext<RegionCoprocessorEnvironment> c,
final Increment increment)
throws IOException {
- requirePermission("increment", Permission.Action.WRITE, c.getEnvironment(),
- increment.getFamilyMap().keySet());
+ Map<byte[], Set<byte[]>> familyMap = Maps.newHashMap();
+ for (Map.Entry<byte[], ? extends Map<byte[], Long>> entry : increment.getFamilyMap().entrySet()) {
+ familyMap.put(entry.getKey(), entry.getValue().keySet());
+ }
+ requirePermission("increment", Permission.Action.WRITE, c.getEnvironment(), familyMap);
return null;
}
@@ -945,7 +946,7 @@ public class AccessController extends Ba
scan.setFilter(filter);
}
logResult(AuthResult.allow("scannerOpen", "Access allowed with filter", user,
- Permission.Action.READ, authResult.getTable()));
+ Permission.Action.READ, authResult.getTable(), scan.getFamilyMap()));
} else {
// no table/family level perms and no qualifier level perms, reject
logResult(authResult);
@@ -1204,4 +1205,15 @@ public class AccessController extends Ba
throws IOException {
requirePermission("preStopRegionServer", Permission.Action.ADMIN);
}
+
+ private Map<byte[], ? extends Collection<byte[]>> makeFamilyMap(byte[] family,
+ byte[] qualifier) {
+ if (family == null) {
+ return null;
+ }
+
+ Map<byte[], Collection<byte[]>> familyMap = Maps.newHashMapWithExpectedSize(1);
+ familyMap.put(family, qualifier != null ? ImmutableSet.of(qualifier) : null);
+ return familyMap;
+ }
}
Modified: hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AuthResult.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AuthResult.java?rev=1430691&r1=1430690&r2=1430691&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AuthResult.java (original)
+++ hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AuthResult.java Wed Jan 9 05:45:33 2013
@@ -18,8 +18,12 @@
package org.apache.hadoop.hbase.security.access;
+import java.util.Collection;
+import java.util.Map;
+
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.util.Bytes;
@@ -32,14 +36,17 @@ import org.apache.hadoop.hbase.util.Byte
public class AuthResult {
private final boolean allowed;
private final byte[] table;
- private final byte[] family;
- private final byte[] qualifier;
private final Permission.Action action;
private final String request;
private final String reason;
private final User user;
- public AuthResult(boolean allowed, String request, String reason, User user,
+ // "family" and "qualifier" should only be used if "families" is null.
+ private final byte[] family;
+ private final byte[] qualifier;
+ private final Map<byte[], ? extends Collection<?>> families;
+
+ public AuthResult(boolean allowed, String request, String reason, User user,
Permission.Action action, byte[] table, byte[] family, byte[] qualifier) {
this.allowed = allowed;
this.request = request;
@@ -49,6 +56,21 @@ public class AuthResult {
this.family = family;
this.qualifier = qualifier;
this.action = action;
+ this.families = null;
+ }
+
+ public AuthResult(boolean allowed, String request, String reason, User user,
+ Permission.Action action, byte[] table,
+ Map<byte[], ? extends Collection<?>> families) {
+ this.allowed = allowed;
+ this.request = request;
+ this.reason = reason;
+ this.user = user;
+ this.table = table;
+ this.family = null;
+ this.qualifier = null;
+ this.action = action;
+ this.families = families;
}
public boolean isAllowed() {
@@ -83,34 +105,87 @@ public class AuthResult {
return request;
}
+ String toFamilyString() {
+ StringBuilder sb = new StringBuilder();
+ if (families != null) {
+ boolean first = true;
+ for (Map.Entry<byte[], ? extends Collection<?>> entry : families.entrySet()) {
+ String familyName = Bytes.toString(entry.getKey());
+ if (entry.getValue() != null && !entry.getValue().isEmpty()) {
+ for (Object o : entry.getValue()) {
+ String qualifier;
+ if (o instanceof byte[]) {
+ qualifier = Bytes.toString((byte[])o);
+ } else if (o instanceof KeyValue) {
+ byte[] rawQualifier = ((KeyValue)o).getQualifier();
+ qualifier = Bytes.toString(rawQualifier);
+ } else {
+ // Shouldn't really reach this?
+ qualifier = o.toString();
+ }
+ if (!first) {
+ sb.append("|");
+ }
+ first = false;
+ sb.append(familyName).append(":").append(qualifier);
+ }
+ } else {
+ if (!first) {
+ sb.append("|");
+ }
+ first = false;
+ sb.append(familyName);
+ }
+ }
+ } else if (family != null) {
+ sb.append(Bytes.toString(family));
+ if (qualifier != null) {
+ sb.append(":").append(Bytes.toString(qualifier));
+ }
+ }
+ return sb.toString();
+ }
+
public String toContextString() {
- return "(user=" + (user != null ? user.getName() : "UNKNOWN") + ", " +
- "scope=" + (table == null ? "GLOBAL" : Bytes.toString(table)) + ", " +
- "family=" + (family != null ? Bytes.toString(family) : "") + ", " +
- "qualifer=" + (qualifier != null ? Bytes.toString(qualifier) : "") + ", " +
- "action=" + (action != null ? action.toString() : "") + ")";
+ StringBuilder sb = new StringBuilder();
+ sb.append("(user=")
+ .append(user != null ? user.getName() : "UNKNOWN")
+ .append(", ");
+ sb.append("scope=")
+ .append(table == null ? "GLOBAL" : Bytes.toString(table))
+ .append(", ");
+ sb.append("family=")
+ .append(toFamilyString())
+ .append(", ");
+ sb.append("action=")
+ .append(action != null ? action.toString() : "")
+ .append(")");
+ return sb.toString();
}
public String toString() {
return "AuthResult" + toContextString();
}
- public static AuthResult allow(String request, String reason, User user, Permission.Action action,
- byte[] table, byte[] family, byte[] qualifier) {
+ public static AuthResult allow(String request, String reason, User user,
+ Permission.Action action, byte[] table, byte[] family, byte[] qualifier) {
return new AuthResult(true, request, reason, user, action, table, family, qualifier);
}
- public static AuthResult allow(String request, String reason, User user, Permission.Action action, byte[] table) {
- return new AuthResult(true, request, reason, user, action, table, null, null);
+ public static AuthResult allow(String request, String reason, User user,
+ Permission.Action action, byte[] table,
+ Map<byte[], ? extends Collection<?>> families) {
+ return new AuthResult(true, request, reason, user, action, table, families);
}
public static AuthResult deny(String request, String reason, User user,
- Permission.Action action, byte[] table) {
- return new AuthResult(false, request, reason, user, action, table, null, null);
+ Permission.Action action, byte[] table, byte[] family, byte[] qualifier) {
+ return new AuthResult(false, request, reason, user, action, table, family, qualifier);
}
public static AuthResult deny(String request, String reason, User user,
- Permission.Action action, byte[] table, byte[] family, byte[] qualifier) {
- return new AuthResult(false, request, reason, user, action, table, family, qualifier);
+ Permission.Action action, byte[] table,
+ Map<byte[], ? extends Collection<?>> families) {
+ return new AuthResult(false, request, reason, user, action, table, families);
}
}
\ No newline at end of file