Repository: incubator-ranger Updated Branches: refs/heads/master 80c289370 -> f8b4d4a9a
RANGER-405 Hbase plugin: Don't skipt auditing access requests by "superusers" Signed-off-by: Madhan Neethiraj <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/incubator-ranger/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ranger/commit/f8b4d4a9 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ranger/tree/f8b4d4a9 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ranger/diff/f8b4d4a9 Branch: refs/heads/master Commit: f8b4d4a9a28e097abe21565a0af9c21ee700c699 Parents: 80c2893 Author: Alok Lal <[email protected]> Authored: Fri Apr 17 01:07:27 2015 -0700 Committer: Madhan Neethiraj <[email protected]> Committed: Fri Apr 17 22:52:19 2015 -0700 ---------------------------------------------------------------------- .../hbase/AuthorizationSession.java | 16 ++++++- .../authorization/hbase/HbaseAuditHandler.java | 5 ++ .../hbase/HbaseAuditHandlerImpl.java | 21 +++++++- .../authorization/hbase/HbaseAuthUtilsImpl.java | 1 - .../authorization/hbase/HbaseFactory.java | 6 +++ .../authorization/hbase/HbaseUserUtils.java | 7 +++ .../authorization/hbase/HbaseUserUtilsImpl.java | 50 ++++++++++++++++++-- .../hbase/RangerAuthorizationCoprocessor.java | 44 ++++------------- .../java/org/apache/ranger/biz/AssetMgr.java | 2 +- 9 files changed, 110 insertions(+), 42 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f8b4d4a9/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/AuthorizationSession.java ---------------------------------------------------------------------- diff --git a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/AuthorizationSession.java b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/AuthorizationSession.java index 1c712a4..46ed758 100644 --- a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/AuthorizationSession.java +++ b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/AuthorizationSession.java @@ -57,6 +57,7 @@ public class AuthorizationSession { Set<String> _groups; // this exits to avoid having to get group for a user repeatedly. It is kept in sync with _user; // Passing a null handler to policy engine would suppress audit logging. HbaseAuditHandler _auditHandler = null; + boolean _superUser = false; // is this session for a super user? // internal state per-authorization RangerAccessRequest _request; @@ -89,10 +90,11 @@ public class AuthorizationSession { AuthorizationSession user(User aUser) { _user = aUser; if (_user == null) { - LOG.debug("AuthorizationSession.user: user is null!"); + LOG.warn("AuthorizationSession.user: user is null!"); _groups = null; } else { _groups = _userUtils.getUserGroups(_user); + _superUser = _userUtils.isSuperUser(_user); } return this; } @@ -185,6 +187,12 @@ public class AuthorizationSession { throw new IllegalStateException(message); } else { // ok to pass potentially null handler to policy engine. Null handler effectively suppresses the audit. + if (_auditHandler != null && _superUser) { + if (LOG.isDebugEnabled()) { + LOG.debug("Setting super-user override on audit handler"); + } + _auditHandler.setSuperUserOverride(_superUser); + } _result = _authorizer.isAccessAllowed(_request, _auditHandler); } if (LOG.isDebugEnabled()) { @@ -255,6 +263,12 @@ public class AuthorizationSession { } else { allowed = _result.getIsAllowed(); } + if (!allowed && _superUser) { + if (LOG.isDebugEnabled()) { + LOG.debug("User [" + _user + "] is a superUser! Overriding policy engine's decision. Request is deemed authorized!"); + } + allowed = true; + } return allowed; } http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f8b4d4a9/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandler.java ---------------------------------------------------------------------- diff --git a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandler.java b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandler.java index 28d41aa..f94cef4 100644 --- a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandler.java +++ b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandler.java @@ -45,4 +45,9 @@ public interface HbaseAuditHandler extends RangerAuditHandler { */ void setMostRecentEvent(AuthzAuditEvent capturedEvents); + /** + * Is audit handler being used in context of a access authorization of a superuser? + * @param override + */ + void setSuperUserOverride(boolean override); } http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f8b4d4a9/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandlerImpl.java ---------------------------------------------------------------------- diff --git a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandlerImpl.java b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandlerImpl.java index fb4f8a0..e383614 100644 --- a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandlerImpl.java +++ b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuditHandlerImpl.java @@ -31,6 +31,7 @@ public class HbaseAuditHandlerImpl extends RangerDefaultAuditHandler implements final List<AuthzAuditEvent> _allEvents = new ArrayList<AuthzAuditEvent>(); // we replace its contents anytime new audit events are generated. AuthzAuditEvent _mostRecentEvent = null; + boolean _superUserOverride = false; @Override public AuthzAuditEvent getAuthzEvents(RangerAccessResult result) { @@ -52,13 +53,14 @@ public class HbaseAuditHandlerImpl extends RangerDefaultAuditHandler implements if (_mostRecentEvent != null) { result.add(_mostRecentEvent); } - + applySuperUserOverride(result); return result; } @Override public AuthzAuditEvent discardMostRecentEvent() { AuthzAuditEvent result = _mostRecentEvent; + applySuperUserOverride(result); _mostRecentEvent = null; return result; } @@ -67,4 +69,21 @@ public class HbaseAuditHandlerImpl extends RangerDefaultAuditHandler implements public void setMostRecentEvent(AuthzAuditEvent event) { _mostRecentEvent = event; } + + @Override + public void setSuperUserOverride(boolean override) { + _superUserOverride = override; + } + + void applySuperUserOverride(List<AuthzAuditEvent> events) { + for (AuthzAuditEvent event : events) { + applySuperUserOverride(event); + } + } + + void applySuperUserOverride(AuthzAuditEvent event) { + if (event != null && _superUserOverride) { + event.setAccessResult((short)1); + } + } } http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f8b4d4a9/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImpl.java ---------------------------------------------------------------------- diff --git a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImpl.java b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImpl.java index a94bf1e..d80a04a 100644 --- a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImpl.java +++ b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImpl.java @@ -21,7 +21,6 @@ package org.apache.ranger.authorization.hbase; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hbase.HRegionInfo; -import org.apache.hadoop.hbase.NamespaceDescriptor; import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment; import org.apache.hadoop.hbase.security.access.Permission.Action; import org.apache.hadoop.hbase.util.Bytes; http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f8b4d4a9/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseFactory.java ---------------------------------------------------------------------- diff --git a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseFactory.java b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseFactory.java index 5b5690f..3488d70 100644 --- a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseFactory.java +++ b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseFactory.java @@ -18,6 +18,8 @@ */ package org.apache.ranger.authorization.hbase; +import org.apache.hadoop.conf.Configuration; + // TODO remove this in favor of Guice DI @@ -48,4 +50,8 @@ public class HbaseFactory { HbaseAuditHandler getAuditHandler() { return new HbaseAuditHandlerImpl(); } + + static void initialize(Configuration conf) { + HbaseUserUtilsImpl.initiailize(conf); + } } http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f8b4d4a9/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtils.java ---------------------------------------------------------------------- diff --git a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtils.java b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtils.java index aa85994..05d67d6 100644 --- a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtils.java +++ b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtils.java @@ -49,4 +49,11 @@ public interface HbaseUserUtils { * @return */ String getUserAsString(); + + /** + * Returns true of specified user is configured to be a super user + * @param user + * @return + */ + boolean isSuperUser(User user); } http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f8b4d4a9/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtilsImpl.java ---------------------------------------------------------------------- diff --git a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtilsImpl.java b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtilsImpl.java index fd15aaa..ddc84d8 100644 --- a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtilsImpl.java +++ b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseUserUtilsImpl.java @@ -20,22 +20,49 @@ package org.apache.ranger.authorization.hbase; import java.io.IOException; import java.util.Arrays; -import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.ipc.RpcServer; import org.apache.hadoop.hbase.security.User; public class HbaseUserUtilsImpl implements HbaseUserUtils { private static final Log LOG = LogFactory.getLog(HbaseUserUtilsImpl.class.getName()); + private static final String SUPERUSER_CONFIG_PROP = "hbase.superuser"; - static Set<String> _SuperUsers = Collections.synchronizedSet(new HashSet<String>()); - static AtomicBoolean initialized = new AtomicBoolean(false); + // only to detect problems with initialization order, not for thread-safety. + static final AtomicBoolean _Initialized = new AtomicBoolean(false); + // should never be null + static final AtomicReference<Set<String>> _SuperUsers = new AtomicReference<Set<String>>(new HashSet<String>()); + + public static void initiailize(Configuration conf) { + + if (_Initialized.get()) { + LOG.warn("HbaseUserUtilsImpl.initialize: Unexpected: initialization called more than once!"); + } else { + if (conf == null) { + LOG.error("HbaseUserUtilsImpl.initialize: Internal error: called with null conf value!"); + } else { + String[] users = conf.getStrings(SUPERUSER_CONFIG_PROP); + if (users != null && users.length > 0) { + Set<String> superUsers = new HashSet<String>(users.length); + for (String user : users) { + user = user.trim(); + LOG.info("HbaseUserUtilsImpl.initialize: Adding Super User(" + user + ")"); + superUsers.add(user); + } + _SuperUsers.set(superUsers); + } + } + _Initialized.set(true); + } + } @Override public String getUserAsString(User user) { @@ -84,4 +111,21 @@ public class HbaseUserUtilsImpl implements HbaseUserUtils { return getUserAsString(user); } } + + /** + * No user can be a superuser till the class is properly initialized. Once class is properly initialized, users specified in + * configuration would be reported as super users. + */ + @Override + public boolean isSuperUser(User user) { + if (!_Initialized.get()) { + LOG.error("HbaseUserUtilsImpl.isSuperUser: Internal error: called before initialization was complete!"); + } + Set<String> superUsers = _SuperUsers.get(); // can never be null + boolean isSuper = superUsers.contains(user.getShortName()); + if (LOG.isDebugEnabled()) { + LOG.debug("IsSuperCheck on [" + user.getShortName() + "] returns [" + isSuper + "]"); + } + return isSuper; + } } http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f8b4d4a9/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java ---------------------------------------------------------------------- diff --git a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java index edc769b..2926bec 100644 --- a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java +++ b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java @@ -72,11 +72,11 @@ import org.apache.hadoop.hbase.protobuf.ResponseConverter; import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos; import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService; import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription; +import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas; import org.apache.hadoop.hbase.protobuf.generated.SecureBulkLoadProtos.CleanupBulkLoadRequest; import org.apache.hadoop.hbase.protobuf.generated.SecureBulkLoadProtos.PrepareBulkLoadRequest; -import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas; -import org.apache.hadoop.hbase.regionserver.Region; import org.apache.hadoop.hbase.regionserver.InternalScanner; +import org.apache.hadoop.hbase.regionserver.Region; import org.apache.hadoop.hbase.regionserver.RegionScanner; import org.apache.hadoop.hbase.regionserver.ScanType; import org.apache.hadoop.hbase.regionserver.Store; @@ -115,7 +115,6 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess private static boolean UpdateRangerPoliciesOnGrantRevoke = RangerHadoopConstants.HBASE_UPDATE_RANGER_POLICIES_ON_GRANT_REVOKE_DEFAULT_VALUE; private static final String GROUP_PREFIX = "@"; - private static final String SUPERUSER_CONFIG_PROP = "hbase.superuser"; private static final String WILDCARD = "*"; private static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT+0"); @@ -123,8 +122,6 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess private RegionCoprocessorEnvironment regionEnv; private Map<InternalScanner, String> scannerOwners = new MapMaker().weakKeys().makeMap(); - private List<String> superUserList = null; - /* * These are package level only for testability and aren't meant to be exposed outside via getters/setters or made available to derived classes. */ @@ -150,21 +147,12 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess if (user == null) { throw new IOException("Unable to obtain the current user, authorization checks for internal operations will not work correctly!"); } - String currentUser = user.getShortName(); - List<String> superusers = Lists.asList(currentUser, conf.getStrings(SUPERUSER_CONFIG_PROP, new String[0])); + String systemUser = user.getShortName(); User activeUser = getActiveUser(); - if (!(superusers.contains(activeUser.getShortName()))) { + if (!Objects.equal(systemUser, activeUser.getShortName()) && !_userUtils.isSuperUser(activeUser)) { throw new AccessDeniedException("User '" + user.getShortName() + "is not system or super user."); } } - private boolean isSuperUser(User user) { - boolean isSuper = false; - isSuper = (superUserList != null && superUserList.contains(user.getShortName())); - if (LOG.isDebugEnabled()) { - LOG.debug("IsSuperCheck on [" + user.getShortName() + "] returns [" + isSuper + "]"); - } - return isSuper; - } protected boolean isSpecialTable(HRegionInfo regionInfo) { return isSpecialTable(regionInfo.getTable().getName()); } @@ -213,7 +201,6 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess throw new AccessDeniedException("User '"+ requestUserName +"' is not the scanner owner!"); } } - /** * @param families * @return empty map if families is null, would never have empty or null keys, would never have null values, values could be empty (non-null) set @@ -344,7 +331,7 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess // if authorized then pass captured events as access allowed set else as access denied set. result = new ColumnFamilyAccessResult(authorized, authorized, authorized ? Collections.singletonList(event) : null, - authorized ? null : event, null, reason); + authorized ? null : event, null, reason); if (LOG.isDebugEnabled()) { String message = String.format(messageTemplate, operation, access, families.toString(), result.toString()); LOG.debug(message); @@ -534,9 +521,6 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess String message = "Unexpeceted: User is null: access denied, not audited!"; LOG.warn("canSkipAccessCheck: exiting" + message); throw new AccessDeniedException("No user associated with request (" + operation + ") for action: " + access + "on table:" + table); - } else if (isSuperUser(user)) { - LOG.debug("canSkipAccessCheck: true: superuser access allowed, not audited"); - result = true; } else if (isAccessForMetadataRead(access, table)) { LOG.debug("canSkipAccessCheck: true: metadata read access always allowed, not audited"); result = true; @@ -913,19 +897,9 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess coprocessorType = REGIONAL_COPROCESSOR_TYPE; appType = "hbaseRegional"; } - - if (superUserList == null) { - superUserList = new ArrayList<String>(); - Configuration conf = env.getConfiguration(); - String[] users = conf.getStrings(SUPERUSER_CONFIG_PROP); - if (users != null) { - for (String user : users) { - user = user.trim(); - LOG.info("Start() - Adding Super User(" + user + ")"); - superUserList.add(user); - } - } - } + + Configuration conf = env.getConfiguration(); + HbaseFactory.initialize(conf); // create and initialize the plugin class RangerHBasePlugin plugin = hbasePlugin; @@ -947,7 +921,7 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess } if (LOG.isDebugEnabled()) { - LOG.debug("Start of Coprocessor: [" + coprocessorType + "] with superUserList [" + superUserList + "]"); + LOG.debug("Start of Coprocessor: [" + coprocessorType + "]"); } } @Override http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f8b4d4a9/security-admin/src/main/java/org/apache/ranger/biz/AssetMgr.java ---------------------------------------------------------------------- diff --git a/security-admin/src/main/java/org/apache/ranger/biz/AssetMgr.java b/security-admin/src/main/java/org/apache/ranger/biz/AssetMgr.java index 1c076c5..a838d8e 100644 --- a/security-admin/src/main/java/org/apache/ranger/biz/AssetMgr.java +++ b/security-admin/src/main/java/org/apache/ranger/biz/AssetMgr.java @@ -1694,7 +1694,7 @@ public class AssetMgr extends AssetMgrBase { .getBooleanProperty( "xa.log.SC_NOT_MODIFIED", false); if (!logNotModified) { - logger.info("Not logging HttpServletResponse." + logger.debug("Not logging HttpServletResponse." + "SC_NOT_MODIFIED, to enable, update " + ": xa.log.SC_NOT_MODIFIED"); return null;
