http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ebe83454/hdfs-agent/src/main/java/org/apache/ranger/authorization/hadoop/RangerHdfsAuthorizerImpl.java ---------------------------------------------------------------------- diff --git a/hdfs-agent/src/main/java/org/apache/ranger/authorization/hadoop/RangerHdfsAuthorizerImpl.java b/hdfs-agent/src/main/java/org/apache/ranger/authorization/hadoop/RangerHdfsAuthorizerImpl.java new file mode 100644 index 0000000..9389875 --- /dev/null +++ b/hdfs-agent/src/main/java/org/apache/ranger/authorization/hadoop/RangerHdfsAuthorizerImpl.java @@ -0,0 +1,538 @@ +/* + * 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.ranger.authorization.hadoop; + +import static org.apache.ranger.authorization.hadoop.constants.RangerHadoopConstants.EXECUTE_ACCCESS_TYPE; +import static org.apache.ranger.authorization.hadoop.constants.RangerHadoopConstants.READ_ACCCESS_TYPE; +import static org.apache.ranger.authorization.hadoop.constants.RangerHadoopConstants.WRITE_ACCCESS_TYPE; + +import java.net.InetAddress; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.Stack; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.fs.permission.FsAction; +import org.apache.hadoop.hdfs.server.namenode.INode; +import org.apache.hadoop.hdfs.server.namenode.INodeAttributeProvider; +import org.apache.hadoop.hdfs.server.namenode.INodeAttributes; +import org.apache.hadoop.hdfs.server.namenode.INodeDirectory; +import org.apache.hadoop.hdfs.util.ReadOnlyList; +import org.apache.hadoop.ipc.Server; +import org.apache.hadoop.security.AccessControlException; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.ranger.audit.model.AuthzAuditEvent; +import org.apache.ranger.authorization.hadoop.config.RangerConfiguration; +import org.apache.ranger.authorization.hadoop.constants.RangerHadoopConstants; +import org.apache.ranger.authorization.hadoop.exceptions.RangerAccessControlException; +import org.apache.ranger.authorization.utils.StringUtil; +import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl; +import org.apache.ranger.plugin.policyengine.RangerAccessResource; +import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.service.RangerBasePlugin; + +import com.google.common.collect.Sets; + +public class RangerHdfsAuthorizerImpl extends INodeAttributeProvider { + private static final Log LOG = LogFactory.getLog(RangerHdfsAuthorizerImpl.class); + + private RangerHdfsPlugin rangerPlugin = null; + private Map<FsAction, Set<String>> access2ActionListMapper = new HashMap<FsAction, Set<String>>(); + + public RangerHdfsAuthorizerImpl() { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerHdfsAuthorizer.RangerHdfsAuthorizer()"); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerHdfsAuthorizer.RangerHdfsAuthorizer()"); + } + } + + public void start() { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerHdfsAuthorizer.start()"); + } + + RangerHdfsPlugin plugin = new RangerHdfsPlugin(); + plugin.init(); + + access2ActionListMapper.put(FsAction.NONE, new HashSet<String>()); + access2ActionListMapper.put(FsAction.ALL, Sets.newHashSet(READ_ACCCESS_TYPE, WRITE_ACCCESS_TYPE, EXECUTE_ACCCESS_TYPE)); + access2ActionListMapper.put(FsAction.READ, Sets.newHashSet(READ_ACCCESS_TYPE)); + access2ActionListMapper.put(FsAction.READ_WRITE, Sets.newHashSet(READ_ACCCESS_TYPE, WRITE_ACCCESS_TYPE)); + access2ActionListMapper.put(FsAction.READ_EXECUTE, Sets.newHashSet(READ_ACCCESS_TYPE, EXECUTE_ACCCESS_TYPE)); + access2ActionListMapper.put(FsAction.WRITE, Sets.newHashSet(WRITE_ACCCESS_TYPE)); + access2ActionListMapper.put(FsAction.WRITE_EXECUTE, Sets.newHashSet(WRITE_ACCCESS_TYPE, EXECUTE_ACCCESS_TYPE)); + access2ActionListMapper.put(FsAction.EXECUTE, Sets.newHashSet(EXECUTE_ACCCESS_TYPE)); + + rangerPlugin = plugin; + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerHdfsAuthorizer.start()"); + } + } + + public void stop() { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerHdfsAuthorizer.stop()"); + } + + RangerHdfsPlugin plugin = rangerPlugin; + rangerPlugin = null; + + if(plugin != null) { + plugin.cleanup(); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerHdfsAuthorizer.stop()"); + } + } + + @Override + public INodeAttributes getAttributes(String fullPath, INodeAttributes inode) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerHdfsAuthorizer.getAttributes(" + fullPath + ")"); + } + + INodeAttributes ret = inode; // return default attributes + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerHdfsAuthorizer.getAttributes(" + fullPath + "): " + ret); + } + + return ret; + } + + @Override + public INodeAttributes getAttributes(String[] pathElements, INodeAttributes inode) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerHdfsAuthorizer.getAttributes(pathElementsCount=" + (pathElements == null ? 0 : pathElements.length) + ")"); + } + + INodeAttributes ret = inode; // return default attributes + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerHdfsAuthorizer.getAttributes(pathElementsCount=" + (pathElements == null ? 0 : pathElements.length) + "): " + ret); + } + + return ret; + } + + @Override + public AccessControlEnforcer getExternalAccessControlEnforcer(AccessControlEnforcer defaultEnforcer) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerHdfsAuthorizer.getExternalAccessControlEnforcer()"); + } + + RangerAccessControlEnforcer rangerAce = new RangerAccessControlEnforcer(defaultEnforcer); + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerHdfsAuthorizer.getExternalAccessControlEnforcer()"); + } + + return rangerAce; + } + + + class RangerAccessControlEnforcer implements AccessControlEnforcer { + private INodeAttributeProvider.AccessControlEnforcer defaultEnforcer = null; + + public RangerAccessControlEnforcer(AccessControlEnforcer defaultEnforcer) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerAccessControlEnforcer.RangerAccessControlEnforcer()"); + } + + this.defaultEnforcer = defaultEnforcer; + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerAccessControlEnforcer.RangerAccessControlEnforcer()"); + } + } + + @Override + public void checkPermission(String fsOwner, String superGroup, UserGroupInformation ugi, + INodeAttributes[] inodeAttrs, INode[] inodes, byte[][] pathByNameArr, + int snapshotId, String path, int ancestorIndex, boolean doCheckOwner, + FsAction ancestorAccess, FsAction parentAccess, FsAction access, + FsAction subAccess, boolean ignoreEmptyDir) throws AccessControlException { + boolean accessGranted = false; + RangerHdfsPlugin plugin = rangerPlugin; + RangerHdfsAuditHandler auditHandler = null; + String user = ugi != null ? ugi.getShortUserName() : null; + Set<String> groups = ugi != null ? Sets.newHashSet(ugi.getGroupNames()) : null; + + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerAccessControlEnforcer.checkPermission(" + + "fsOwner=" + fsOwner + "; superGroup=" + superGroup + ", inodesCount=" + (inodes != null ? inodes.length : 0) + + ", snapshotId=" + snapshotId + ", user=" + user + ", path=" + path + ", ancestorIndex=" + ancestorIndex + + ", doCheckOwner="+ doCheckOwner + ", ancestorAccess=" + ancestorAccess + ", parentAccess=" + parentAccess + + ", access=" + access + ", subAccess=" + subAccess + ", ignoreEmptyDir=" + ignoreEmptyDir + ")"); + } + + try { + if(plugin != null && !ArrayUtils.isEmpty(inodes)) { + auditHandler = new RangerHdfsAuditHandler(path); + + if(ancestorIndex >= inodes.length) { + ancestorIndex = inodes.length - 1; + } + + for(; ancestorIndex >= 0 && inodes[ancestorIndex] == null; ancestorIndex--); + + accessGranted = true; + + INode ancestor = inodes.length > ancestorIndex && ancestorIndex >= 0 ? inodes[ancestorIndex] : null; + INode parent = inodes.length > 1 ? inodes[inodes.length - 2] : null; + INode inode = inodes[inodes.length - 1]; + + boolean noAccessToCheck = access == null && parentAccess == null && ancestorAccess == null && subAccess == null; + + if(noAccessToCheck) { // check for traverse (EXECUTE) access on the path (if path is a directory) or its parent (if path is a file) + INode node = null; + INodeAttributes nodeAttribs = null; + + if(inode != null && inode.isDirectory()) { + node = inode; + nodeAttribs = inodeAttrs.length > 0 ? inodeAttrs[inodeAttrs.length - 1] : null; + } else if(parent != null) { + node = parent; + nodeAttribs = inodeAttrs.length > 1 ? inodeAttrs[inodeAttrs.length - 2] : null; + } + + if(node != null) { + accessGranted = isAccessAllowed(node, nodeAttribs, FsAction.EXECUTE, user, groups, fsOwner, superGroup, plugin, null); + } + } + + // checkStickyBit + if (accessGranted && parentAccess != null && parentAccess.implies(FsAction.WRITE) && parent != null && inode != null) { + if (parent.getFsPermission() != null && parent.getFsPermission().getStickyBit()) { + // user should be owner of the parent or the inode + accessGranted = StringUtils.equals(parent.getUserName(), user) || StringUtils.equals(inode.getUserName(), user); + } + } + + // checkAncestorAccess + if(accessGranted && ancestorAccess != null && ancestor != null) { + INodeAttributes ancestorAttribs = inodeAttrs.length > ancestorIndex ? inodeAttrs[ancestorIndex] : null; + + accessGranted = isAccessAllowed(ancestor, ancestorAttribs, ancestorAccess, user, groups, fsOwner, superGroup, plugin, auditHandler); + } + + // checkParentAccess + if(accessGranted && parentAccess != null && parent != null) { + INodeAttributes parentAttribs = inodeAttrs.length > 1 ? inodeAttrs[inodeAttrs.length - 2] : null; + + accessGranted = isAccessAllowed(parent, parentAttribs, parentAccess, user, groups, fsOwner, superGroup, plugin, auditHandler); + } + + // checkINodeAccess + if(accessGranted && access != null && inode != null) { + INodeAttributes inodeAttribs = inodeAttrs.length > 0 ? inodeAttrs[inodeAttrs.length - 1] : null; + + accessGranted = isAccessAllowed(inode, inodeAttribs, access, user, groups, fsOwner, superGroup, plugin, auditHandler); + } + + // checkSubAccess + if(accessGranted && subAccess != null && inode != null && inode.isDirectory()) { + Stack<INodeDirectory> directories = new Stack<INodeDirectory>(); + + for(directories.push(inode.asDirectory()); !directories.isEmpty(); ) { + INodeDirectory dir = directories.pop(); + ReadOnlyList<INode> cList = dir.getChildrenList(snapshotId); + + if (!(cList.isEmpty() && ignoreEmptyDir)) { + INodeAttributes dirAttribs = dir.getSnapshotINode(snapshotId); + + accessGranted = isAccessAllowed(dir, dirAttribs, subAccess, user, groups, fsOwner, superGroup, plugin, auditHandler); + + if(! accessGranted) { + break; + } + } + + for(INode child : cList) { + if (child.isDirectory()) { + directories.push(child.asDirectory()); + } + } + } + } + + // checkOwnerAccess + if(accessGranted && doCheckOwner) { + INodeAttributes inodeAttribs = inodeAttrs.length > 0 ? inodeAttrs[inodeAttrs.length - 1] : null; + String owner = inodeAttribs != null ? inodeAttribs.getUserName() : null; + + accessGranted = StringUtils.equals(user, owner); + } + } + + if(! accessGranted && RangerHdfsPlugin.isHadoopAuthEnabled() && defaultEnforcer != null) { + try { + defaultEnforcer.checkPermission(fsOwner, superGroup, ugi, inodeAttrs, inodes, + pathByNameArr, snapshotId, path, ancestorIndex, doCheckOwner, + ancestorAccess, parentAccess, access, subAccess, ignoreEmptyDir); + + accessGranted = true; + } finally { + if(auditHandler != null) { + FsAction action = access; + + if(action == null) { + if(parentAccess != null) { + action = parentAccess; + } else if(ancestorAccess != null) { + action = ancestorAccess; + } else if(subAccess != null) { + action = subAccess; + } else { + action = FsAction.NONE; + } + } + + auditHandler.logHadoopEvent(path, action, accessGranted); + } + } + } + + if(! accessGranted) { + throw new RangerAccessControlException("Permission denied: principal{user=" + user + ",groups: " + groups + "}, access=" + access + ", " + path) ; + } + } finally { + if(auditHandler != null) { + auditHandler.flushAudit(); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerAccessControlEnforcer.checkPermission(" + path + ", " + access + ", user=" + user + ") : " + accessGranted); + } + } + } + + private boolean isAccessAllowed(INode inode, INodeAttributes inodeAttribs, FsAction access, String user, Set<String> groups, String fsOwner, String superGroup, RangerHdfsPlugin plugin, RangerHdfsAuditHandler auditHandler) { + boolean ret = false; + String path = inode != null ? inode.getFullPathName() : null; + String pathOwner = inodeAttribs != null ? inodeAttribs.getUserName() : null; + + if(pathOwner == null && inode != null) { + pathOwner = inode.getUserName(); + } + + if (RangerHadoopConstants.HDFS_ROOT_FOLDER_PATH_ALT.equals(path)) { + path = RangerHadoopConstants.HDFS_ROOT_FOLDER_PATH; + } + + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerAccessControlEnforcer.isAccessAllowed(" + path + ", " + access + ", " + user + ")"); + } + + Set<String> accessTypes = access2ActionListMapper.get(access); + + if(accessTypes == null) { + LOG.warn("RangerAccessControlEnforcer.isAccessAllowed(" + path + ", " + access + ", " + user + "): no Ranger accessType found for " + access); + + accessTypes = access2ActionListMapper.get(FsAction.NONE); + } + + for(String accessType : accessTypes) { + RangerHdfsAccessRequest request = new RangerHdfsAccessRequest(path, pathOwner, access, accessType, user, groups); + + RangerAccessResult result = plugin.isAccessAllowed(request, auditHandler); + + if (result == null) { + LOG.error("RangerAccessControlEnforcer: Internal error: null RangerAccessResult object received back from isAccessAllowed()!"); + } else { + ret = result.getIsAllowed(); + + if (!ret) { + break; + } + } + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerAccessControlEnforcer.isAccessAllowed(" + path + ", " + access + ", " + user + "): " + ret); + } + + return ret; + } + } +} + + +class RangerHdfsPlugin extends RangerBasePlugin { + private static boolean hadoopAuthEnabled = RangerHadoopConstants.RANGER_ADD_HDFS_PERMISSION_DEFAULT; + + public RangerHdfsPlugin() { + super("hdfs", "hdfs"); + } + + public void init() { + super.init(); + + RangerHdfsPlugin.hadoopAuthEnabled = RangerConfiguration.getInstance().getBoolean(RangerHadoopConstants.RANGER_ADD_HDFS_PERMISSION_PROP, RangerHadoopConstants.RANGER_ADD_HDFS_PERMISSION_DEFAULT); + } + + public static boolean isHadoopAuthEnabled() { + return RangerHdfsPlugin.hadoopAuthEnabled; + } +} + +class RangerHdfsResource extends RangerAccessResourceImpl { + private static final String KEY_PATH = "path"; + + + public RangerHdfsResource(String path, String owner) { + super.setValue(KEY_PATH, path); + super.setOwnerUser(owner); + } +} + +class RangerHdfsAccessRequest extends RangerAccessRequestImpl { + public RangerHdfsAccessRequest(String path, String pathOwner, FsAction access, String accessType, String user, Set<String> groups) { + super.setResource(new RangerHdfsResource(path, pathOwner)); + super.setAccessType(accessType); + super.setUser(user); + super.setUserGroups(groups); + super.setAccessTime(StringUtil.getUTCDate()); + super.setClientIPAddress(getRemoteIp()); + super.setAction(access.toString()); + } + + private static String getRemoteIp() { + String ret = null ; + InetAddress ip = Server.getRemoteIp() ; + if (ip != null) { + ret = ip.getHostAddress(); + } + return ret ; + } +} + +class RangerHdfsAuditHandler extends RangerDefaultAuditHandler { + private static final Log LOG = LogFactory.getLog(RangerHdfsAuditHandler.class); + + private boolean isAuditEnabled = false; + private AuthzAuditEvent auditEvent = null; + + private static final String RangerModuleName = RangerConfiguration.getInstance().get(RangerHadoopConstants.AUDITLOG_RANGER_MODULE_ACL_NAME_PROP , RangerHadoopConstants.DEFAULT_RANGER_MODULE_ACL_NAME) ; + private static final String HadoopModuleName = RangerConfiguration.getInstance().get(RangerHadoopConstants.AUDITLOG_HADOOP_MODULE_ACL_NAME_PROP , RangerHadoopConstants.DEFAULT_HADOOP_MODULE_ACL_NAME) ; + private static final String excludeUserList = RangerConfiguration.getInstance().get(RangerHadoopConstants.AUDITLOG_HDFS_EXCLUDE_LIST_PROP, RangerHadoopConstants.AUDITLOG_EMPTY_STRING) ; + private static HashSet<String> excludeUsers = null ; + + static { + if (excludeUserList != null && excludeUserList.trim().length() > 0) { + excludeUsers = new HashSet<String>() ; + for(String excludeUser : excludeUserList.trim().split(",")) { + excludeUser = excludeUser.trim() ; + if (LOG.isDebugEnabled()) { + LOG.debug("Adding exclude user [" + excludeUser + "]"); + } + excludeUsers.add(excludeUser) ; + } + } + } + + public RangerHdfsAuditHandler(String pathToBeValidated) { + auditEvent = new AuthzAuditEvent(); + auditEvent.setResourcePath(pathToBeValidated); + } + + @Override + public void processResult(RangerAccessResult result) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerHdfsAuditHandler.logAudit(" + result + ")"); + } + + if(! isAuditEnabled && result.getIsAudited()) { + isAuditEnabled = true; + } + + RangerAccessRequest request = result.getAccessRequest(); +// RangerServiceDef serviceDef = result.getServiceDef(); + RangerAccessResource resource = request.getResource(); + String resourceType = resource != null ? resource.getLeafName() : null; + String resourcePath = resource != null ? resource.getAsString() : null; + + auditEvent.setUser(request.getUser()); + auditEvent.setResourceType(resourceType) ; + auditEvent.setAccessType(request.getAction()); + auditEvent.setAccessResult((short)(result.getIsAllowed() ? 1 : 0)); + auditEvent.setClientIP(request.getClientIPAddress()); + auditEvent.setEventTime(request.getAccessTime()); + auditEvent.setAclEnforcer(RangerModuleName); + auditEvent.setPolicyId(result.getPolicyId()); + auditEvent.setRepositoryType(result.getServiceType()); + auditEvent.setRepositoryName(result.getServiceName()); + auditEvent.setResultReason(resourcePath); + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerHdfsAuditHandler.logAudit(" + result + "): " + auditEvent); + } + } + + public void logHadoopEvent(String path, FsAction action, boolean accessGranted) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerHdfsAuditHandler.logHadoopEvent(" + path + ", " + action + ", " + accessGranted + ")"); + } + + auditEvent.setResultReason(path); + auditEvent.setAccessResult((short) (accessGranted ? 1 : 0)); + auditEvent.setAccessType(action == null ? null : action.toString()); + auditEvent.setAclEnforcer(HadoopModuleName); + auditEvent.setPolicyId(-1); + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerHdfsAuditHandler.logHadoopEvent(" + path + ", " + action + ", " + accessGranted + "): " + auditEvent); + } + } + + public void flushAudit() { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerHdfsAuditHandler.flushAudit(" + isAuditEnabled + ", " + auditEvent + ")"); + } + + if(isAuditEnabled && !StringUtils.isEmpty(auditEvent.getAccessType())) { + String username = auditEvent.getUser(); + + boolean skipLog = (username != null && excludeUsers != null && excludeUsers.contains(username)) ; + + if (! skipLog) { + super.logAuthzAudit(auditEvent); + } + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerHdfsAuditHandler.flushAudit(" + isAuditEnabled + ", " + auditEvent + ")"); + } + } +} +
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ebe83454/hive-agent/conf/ranger-hive-security.xml ---------------------------------------------------------------------- diff --git a/hive-agent/conf/ranger-hive-security.xml b/hive-agent/conf/ranger-hive-security.xml index 3a5fc54..515b1fd 100644 --- a/hive-agent/conf/ranger-hive-security.xml +++ b/hive-agent/conf/ranger-hive-security.xml @@ -65,6 +65,22 @@ </description> </property> + <property> + <name>ranger.policy.rest.client.connection.timeoutMs</name> + <value>120000</value> + <description> + RangerRestClient Connection Timeout in Milli Seconds + </description> + </property> + + <property> + <name>ranger.policy.rest.client.read.timeoutMs</name> + <value>30000</value> + <description> + RangerRestClient read Timeout in Milli Seconds + </description> + </property> + <property> <name>xasecure.hive.update.xapolicies.on.grant.revoke</name> <value>true</value> http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ebe83454/hive-agent/src/main/java/com/xasecure/authorization/hive/authorizer/XaSecureHiveAuthorizerFactory.java ---------------------------------------------------------------------- diff --git a/hive-agent/src/main/java/com/xasecure/authorization/hive/authorizer/XaSecureHiveAuthorizerFactory.java b/hive-agent/src/main/java/com/xasecure/authorization/hive/authorizer/XaSecureHiveAuthorizerFactory.java index e941704..079616c 100644 --- a/hive-agent/src/main/java/com/xasecure/authorization/hive/authorizer/XaSecureHiveAuthorizerFactory.java +++ b/hive-agent/src/main/java/com/xasecure/authorization/hive/authorizer/XaSecureHiveAuthorizerFactory.java @@ -18,7 +18,7 @@ */ package com.xasecure.authorization.hive.authorizer; -import org.apache.ranger.authorization.hive.authorizer.RangerHiveAuthorizerFactory; +import org.apache.ranger.authorization.hive.authorizer.RangerHiveAuthorizerFactoryImpl; /** * This class exists only to provide for seamless upgrade/downgrade capabilities. Coprocessor name is in hbase config files in /etc/.../conf which @@ -28,6 +28,6 @@ import org.apache.ranger.authorization.hive.authorizer.RangerHiveAuthorizerFacto * This class is final because if one needs to customize coprocessor it is expected that RangerAuthorizationCoprocessor would be modified/extended as that is * the "real" coprocessor! This class, hence, should NEVER be more than an EMPTY shell! */ -public final class XaSecureHiveAuthorizerFactory extends RangerHiveAuthorizerFactory { +public final class XaSecureHiveAuthorizerFactory extends RangerHiveAuthorizerFactoryImpl { } http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ebe83454/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizerFactory.java ---------------------------------------------------------------------- diff --git a/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizerFactory.java b/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizerFactory.java deleted file mode 100644 index bd410b7..0000000 --- a/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizerFactory.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.ranger.authorization.hive.authorizer; - -import org.apache.hadoop.hive.conf.HiveConf; -import org.apache.hadoop.hive.ql.security.HiveAuthenticationProvider; -import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAuthorizer; -import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAuthorizerFactory; -import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAuthzPluginException; -import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveMetastoreClientFactory; -import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAuthzSessionContext; - -public class RangerHiveAuthorizerFactory implements HiveAuthorizerFactory { - @Override - public HiveAuthorizer createHiveAuthorizer(HiveMetastoreClientFactory metastoreClientFactory, - HiveConf conf, - HiveAuthenticationProvider hiveAuthenticator, - HiveAuthzSessionContext sessionContext) - throws HiveAuthzPluginException { - return new RangerHiveAuthorizer(metastoreClientFactory, conf, hiveAuthenticator, sessionContext); - } -} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ebe83454/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizerFactoryImpl.java ---------------------------------------------------------------------- diff --git a/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizerFactoryImpl.java b/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizerFactoryImpl.java new file mode 100644 index 0000000..937aaed --- /dev/null +++ b/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizerFactoryImpl.java @@ -0,0 +1,40 @@ +/* + * 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.ranger.authorization.hive.authorizer; + +import org.apache.hadoop.hive.conf.HiveConf; +import org.apache.hadoop.hive.ql.security.HiveAuthenticationProvider; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAuthorizer; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAuthorizerFactory; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAuthzPluginException; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveMetastoreClientFactory; +import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAuthzSessionContext; + +public class RangerHiveAuthorizerFactoryImpl implements HiveAuthorizerFactory { + + @Override + public HiveAuthorizer createHiveAuthorizer(HiveMetastoreClientFactory metastoreClientFactory, + HiveConf conf, + HiveAuthenticationProvider hiveAuthenticator, + HiveAuthzSessionContext sessionContext) + throws HiveAuthzPluginException { + return new RangerHiveAuthorizer(metastoreClientFactory, conf, hiveAuthenticator, sessionContext); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ebe83454/knox-agent/src/main/java/com/xasecure/pdp/knox/filter/XASecurePDPKnoxFilter.java ---------------------------------------------------------------------- diff --git a/knox-agent/src/main/java/com/xasecure/pdp/knox/filter/XASecurePDPKnoxFilter.java b/knox-agent/src/main/java/com/xasecure/pdp/knox/filter/XASecurePDPKnoxFilter.java deleted file mode 100644 index 6b9d6fd..0000000 --- a/knox-agent/src/main/java/com/xasecure/pdp/knox/filter/XASecurePDPKnoxFilter.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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 com.xasecure.pdp.knox.filter; - -import org.apache.ranger.authorization.knox.RangerPDPKnoxFilter; - -public class XASecurePDPKnoxFilter extends RangerPDPKnoxFilter { -} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ebe83454/plugin-kafka/conf/ranger-kafka-security.xml ---------------------------------------------------------------------- diff --git a/plugin-kafka/conf/ranger-kafka-security.xml b/plugin-kafka/conf/ranger-kafka-security.xml index 2c06f5c..f9c8d5f 100644 --- a/plugin-kafka/conf/ranger-kafka-security.xml +++ b/plugin-kafka/conf/ranger-kafka-security.xml @@ -80,4 +80,5 @@ RangerRestClient read Timeout in Milli Seconds </description> </property> + </configuration> http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ebe83454/plugin-kafka/pom.xml ---------------------------------------------------------------------- diff --git a/plugin-kafka/pom.xml b/plugin-kafka/pom.xml index afee47d..e14e48c 100644 --- a/plugin-kafka/pom.xml +++ b/plugin-kafka/pom.xml @@ -47,5 +47,10 @@ <artifactId>kafka_2.10</artifactId> <version>${kafka.version}</version> </dependency> + <dependency> + <groupId>org.apache.hadoop</groupId> + <artifactId>hadoop-hdfs</artifactId> + <version>${hadoop.version}</version> + </dependency> </dependencies> </project> http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ebe83454/plugin-kafka/src/main/java/org/apache/ranger/authorization/kafka/authorizer/RangerKafkaAuthorizer.java ---------------------------------------------------------------------- diff --git a/plugin-kafka/src/main/java/org/apache/ranger/authorization/kafka/authorizer/RangerKafkaAuthorizer.java b/plugin-kafka/src/main/java/org/apache/ranger/authorization/kafka/authorizer/RangerKafkaAuthorizer.java deleted file mode 100644 index dbb2723..0000000 --- a/plugin-kafka/src/main/java/org/apache/ranger/authorization/kafka/authorizer/RangerKafkaAuthorizer.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * 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.ranger.authorization.kafka.authorizer; - -import java.io.IOException; -import java.security.Principal; -import java.util.Date; - -import javax.security.auth.Subject; - -import kafka.security.auth.Acl; -import kafka.security.auth.Authorizer; -import kafka.security.auth.KafkaPrincipal; -import kafka.security.auth.Operation; -import kafka.security.auth.Resource; -import kafka.security.auth.ResourceType; -import kafka.server.KafkaConfig; -import kafka.common.security.LoginManager; -import kafka.network.RequestChannel.Session; - -import org.apache.commons.lang.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.hadoop.security.UserGroupInformation; -import org.apache.ranger.audit.provider.MiscUtil; -import org.apache.ranger.authorization.utils.StringUtil; -import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler; -import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl; -import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl; -import org.apache.ranger.plugin.policyengine.RangerAccessResult; -import org.apache.ranger.plugin.service.RangerBasePlugin; - -import scala.collection.immutable.HashSet; -import scala.collection.immutable.Set; - -public class RangerKafkaAuthorizer implements Authorizer { - private static final Log logger = LogFactory - .getLog(RangerKafkaAuthorizer.class); - - public static final String KEY_TOPIC = "topic"; - public static final String KEY_CLUSTER = "cluster"; - public static final String KEY_CONSUMER_GROUP = "consumer_group"; - - public static final String ACCESS_TYPE_READ = "consume"; - public static final String ACCESS_TYPE_WRITE = "publish"; - public static final String ACCESS_TYPE_CREATE = "create"; - public static final String ACCESS_TYPE_DELETE = "delete"; - public static final String ACCESS_TYPE_CONFIGURE = "configure"; - public static final String ACCESS_TYPE_DESCRIBE = "describe"; - public static final String ACCESS_TYPE_KAFKA_ADMIN = "kafka_admin"; - - private static volatile RangerBasePlugin rangerPlugin = null; - long lastLogTime = 0; - int errorLogFreq = 30000; // Log after every 30 seconds - - public RangerKafkaAuthorizer() { - } - - /* - * (non-Javadoc) - * - * @see kafka.security.auth.Authorizer#initialize(kafka.server.KafkaConfig) - */ - @Override - public void initialize(KafkaConfig kafkaConfig) { - - if (rangerPlugin == null) { - try { - Subject subject = LoginManager.subject(); - UserGroupInformation ugi = MiscUtil - .createUGIFromSubject(subject); - if (ugi != null) { - MiscUtil.setUGILoginUser(ugi, subject); - } - logger.info("LoginUser=" + MiscUtil.getUGILoginUser()); - } catch (Throwable t) { - logger.error("Error getting principal.", t); - } - - rangerPlugin = new RangerBasePlugin("kafka", "kafka"); - logger.info("Calling plugin.init()"); - rangerPlugin.init(); - - RangerDefaultAuditHandler auditHandler = new RangerDefaultAuditHandler(); - rangerPlugin.setResultProcessor(auditHandler); - } - } - - @Override - public boolean authorize(Session session, Operation operation, - Resource resource) { - - if (rangerPlugin == null) { - MiscUtil.logErrorMessageByInterval(logger, - "Authorizer is still not initialized"); - return false; - } - - // TODO: If resource type if consumer group, then allow it by default - if (resource.resourceType().equals(ResourceType.CONSUMER_GROUP)) { - return true; - } - - String userName = null; - if (session.principal() != null) { - userName = session.principal().getName(); - userName = StringUtils.substringBefore(userName, "/"); - userName = StringUtils.substringBefore(userName, "@"); - } - java.util.Set<String> userGroups = MiscUtil - .getGroupsForRequestUser(userName); - String ip = session.host(); - - Date eventTime = StringUtil.getUTCDate(); - String accessType = mapToRangerAccessType(operation); - boolean validationFailed = false; - String validationStr = ""; - - if (accessType == null) { - if (MiscUtil.logErrorMessageByInterval(logger, - "Unsupported access type. operation=" + operation)) { - logger.fatal("Unsupported access type. session=" + session - + ", operation=" + operation + ", resource=" + resource); - } - validationFailed = true; - validationStr += "Unsupported access type. operation=" + operation; - } - String action = accessType; - - RangerAccessRequestImpl rangerRequest = new RangerAccessRequestImpl(); - rangerRequest.setUser(userName); - rangerRequest.setUserGroups(userGroups); - rangerRequest.setClientIPAddress(ip); - rangerRequest.setAccessTime(eventTime); - - RangerAccessResourceImpl rangerResource = new RangerAccessResourceImpl(); - rangerRequest.setResource(rangerResource); - rangerRequest.setAccessType(accessType); - rangerRequest.setAction(action); - rangerRequest.setRequestData(resource.name()); - - if (resource.resourceType().equals(ResourceType.TOPIC)) { - rangerResource.setValue(KEY_TOPIC, resource.name()); - } else if (resource.resourceType().equals(ResourceType.CLUSTER)) { - // CLUSTER should go as null - // rangerResource.setValue(KEY_CLUSTER, resource.name()); - } else if (resource.resourceType().equals(ResourceType.CONSUMER_GROUP)) { - rangerResource.setValue(KEY_CONSUMER_GROUP, resource.name()); - } else { - logger.fatal("Unsupported resourceType=" + resource.resourceType()); - validationFailed = true; - } - - boolean returnValue = true; - if (validationFailed) { - MiscUtil.logErrorMessageByInterval(logger, validationStr - + ", request=" + rangerRequest); - returnValue = false; - } else { - - try { - RangerAccessResult result = rangerPlugin - .isAccessAllowed(rangerRequest); - if (result == null) { - logger.error("Ranger Plugin returned null. Returning false"); - returnValue = false; - } else { - returnValue = result.getIsAllowed(); - } - } catch (Throwable t) { - logger.error("Error while calling isAccessAllowed(). request=" - + rangerRequest, t); - } - } - if (logger.isDebugEnabled()) { - logger.debug("rangerRequest=" + rangerRequest + ", return=" - + returnValue); - } - return returnValue; - } - - /* - * (non-Javadoc) - * - * @see - * kafka.security.auth.Authorizer#addAcls(scala.collection.immutable.Set, - * kafka.security.auth.Resource) - */ - @Override - public void addAcls(Set<Acl> acls, Resource resource) { - logger.error("addAcls() is not supported by Ranger for Kafka"); - } - - /* - * (non-Javadoc) - * - * @see - * kafka.security.auth.Authorizer#removeAcls(scala.collection.immutable.Set, - * kafka.security.auth.Resource) - */ - @Override - public boolean removeAcls(Set<Acl> acls, Resource resource) { - logger.error("removeAcls() is not supported by Ranger for Kafka"); - return false; - } - - /* - * (non-Javadoc) - * - * @see - * kafka.security.auth.Authorizer#removeAcls(kafka.security.auth.Resource) - */ - @Override - public boolean removeAcls(Resource resource) { - logger.error("removeAcls() is not supported by Ranger for Kafka"); - return false; - } - - /* - * (non-Javadoc) - * - * @see kafka.security.auth.Authorizer#getAcls(kafka.security.auth.Resource) - */ - @Override - public Set<Acl> getAcls(Resource resource) { - Set<Acl> aclList = new HashSet<Acl>(); - logger.error("getAcls() is not supported by Ranger for Kafka"); - - return aclList; - } - - /* - * (non-Javadoc) - * - * @see - * kafka.security.auth.Authorizer#getAcls(kafka.security.auth.KafkaPrincipal - * ) - */ - @Override - public Set<Acl> getAcls(KafkaPrincipal principal) { - Set<Acl> aclList = new HashSet<Acl>(); - logger.error("getAcls() is not supported by Ranger for Kafka"); - return aclList; - } - - /** - * @param operation - * @return - */ - private String mapToRangerAccessType(Operation operation) { - if (operation.equals(Operation.READ)) { - return ACCESS_TYPE_READ; - } else if (operation.equals(Operation.WRITE)) { - return ACCESS_TYPE_WRITE; - } else if (operation.equals(Operation.ALTER)) { - return ACCESS_TYPE_CONFIGURE; - } else if (operation.equals(Operation.DESCRIBE)) { - return ACCESS_TYPE_DESCRIBE; - } else if (operation.equals(Operation.CLUSTER_ACTION)) { - return ACCESS_TYPE_KAFKA_ADMIN; - } - return null; - } -} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ebe83454/plugin-kafka/src/main/java/org/apache/ranger/authorization/kafka/authorizer/RangerKafkaAuthorizerImpl.java ---------------------------------------------------------------------- diff --git a/plugin-kafka/src/main/java/org/apache/ranger/authorization/kafka/authorizer/RangerKafkaAuthorizerImpl.java b/plugin-kafka/src/main/java/org/apache/ranger/authorization/kafka/authorizer/RangerKafkaAuthorizerImpl.java new file mode 100644 index 0000000..608371a --- /dev/null +++ b/plugin-kafka/src/main/java/org/apache/ranger/authorization/kafka/authorizer/RangerKafkaAuthorizerImpl.java @@ -0,0 +1,277 @@ +/* + * 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.ranger.authorization.kafka.authorizer; + +import java.util.Date; +import javax.security.auth.Subject; + +import kafka.security.auth.Acl; +import kafka.security.auth.Authorizer; +import kafka.security.auth.KafkaPrincipal; +import kafka.security.auth.Operation; +import kafka.security.auth.Resource; +import kafka.security.auth.ResourceType; +import kafka.server.KafkaConfig; +import kafka.common.security.LoginManager; +import kafka.network.RequestChannel.Session; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.ranger.audit.provider.MiscUtil; +import org.apache.ranger.authorization.utils.StringUtil; +import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler; +import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl; +import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.service.RangerBasePlugin; + +import scala.collection.immutable.HashSet; +import scala.collection.immutable.Set; + +public class RangerKafkaAuthorizerImpl implements Authorizer { + private static final Log logger = LogFactory + .getLog(RangerKafkaAuthorizerImpl.class); + + public static final String KEY_TOPIC = "topic"; + public static final String KEY_CLUSTER = "cluster"; + public static final String KEY_CONSUMER_GROUP = "consumer_group"; + + public static final String ACCESS_TYPE_READ = "consume"; + public static final String ACCESS_TYPE_WRITE = "publish"; + public static final String ACCESS_TYPE_CREATE = "create"; + public static final String ACCESS_TYPE_DELETE = "delete"; + public static final String ACCESS_TYPE_CONFIGURE = "configure"; + public static final String ACCESS_TYPE_DESCRIBE = "describe"; + public static final String ACCESS_TYPE_KAFKA_ADMIN = "kafka_admin"; + + private static volatile RangerBasePlugin rangerPlugin = null; + long lastLogTime = 0; + int errorLogFreq = 30000; // Log after every 30 seconds + + public RangerKafkaAuthorizerImpl() { + } + + /* + * (non-Javadoc) + * + * @see kafka.security.auth.Authorizer#initialize(kafka.server.KafkaConfig) + */ + @Override + public void initialize(KafkaConfig kafkaConfig) { + + if (rangerPlugin == null) { + try { + Subject subject = LoginManager.subject(); + UserGroupInformation ugi = MiscUtil + .createUGIFromSubject(subject); + if (ugi != null) { + MiscUtil.setUGILoginUser(ugi, subject); + } + logger.info("LoginUser=" + MiscUtil.getUGILoginUser()); + } catch (Throwable t) { + logger.error("Error getting principal.", t); + } + + rangerPlugin = new RangerBasePlugin("kafka", "kafka"); + logger.info("Calling plugin.init()"); + rangerPlugin.init(); + + RangerDefaultAuditHandler auditHandler = new RangerDefaultAuditHandler(); + rangerPlugin.setResultProcessor(auditHandler); + } + } + + @Override + public boolean authorize(Session session, Operation operation, Resource resource) { + + if (rangerPlugin == null) { + MiscUtil.logErrorMessageByInterval(logger, + "Authorizer is still not initialized"); + return false; + } + + // TODO: If resource type if consumer group, then allow it by default + if (resource.resourceType().equals(ResourceType.CONSUMER_GROUP)) { + return true; + } + + String userName = null; + if (session.principal() != null) { + userName = session.principal().getName(); + userName = StringUtils.substringBefore(userName, "/"); + userName = StringUtils.substringBefore(userName, "@"); + } + java.util.Set<String> userGroups = MiscUtil + .getGroupsForRequestUser(userName); + String ip = session.host(); + + Date eventTime = StringUtil.getUTCDate(); + String accessType = mapToRangerAccessType(operation); + boolean validationFailed = false; + String validationStr = ""; + + if (accessType == null) { + if (MiscUtil.logErrorMessageByInterval(logger, + "Unsupported access type. operation=" + operation)) { + logger.fatal("Unsupported access type. session=" + session + + ", operation=" + operation + ", resource=" + resource); + } + validationFailed = true; + validationStr += "Unsupported access type. operation=" + operation; + } + String action = accessType; + + RangerAccessRequestImpl rangerRequest = new RangerAccessRequestImpl(); + rangerRequest.setUser(userName); + rangerRequest.setUserGroups(userGroups); + rangerRequest.setClientIPAddress(ip); + rangerRequest.setAccessTime(eventTime); + + RangerAccessResourceImpl rangerResource = new RangerAccessResourceImpl(); + rangerRequest.setResource(rangerResource); + rangerRequest.setAccessType(accessType); + rangerRequest.setAction(action); + rangerRequest.setRequestData(resource.name()); + + if (resource.resourceType().equals(ResourceType.TOPIC)) { + rangerResource.setValue(KEY_TOPIC, resource.name()); + } else if (resource.resourceType().equals(ResourceType.CLUSTER)) { + // CLUSTER should go as null + // rangerResource.setValue(KEY_CLUSTER, resource.name()); + } else if (resource.resourceType().equals(ResourceType.CONSUMER_GROUP)) { + rangerResource.setValue(KEY_CONSUMER_GROUP, resource.name()); + } else { + logger.fatal("Unsupported resourceType=" + resource.resourceType()); + validationFailed = true; + } + + boolean returnValue = true; + if (validationFailed) { + MiscUtil.logErrorMessageByInterval(logger, validationStr + + ", request=" + rangerRequest); + returnValue = false; + } else { + + try { + RangerAccessResult result = rangerPlugin + .isAccessAllowed(rangerRequest); + if (result == null) { + logger.error("Ranger Plugin returned null. Returning false"); + returnValue = false; + } else { + returnValue = result.getIsAllowed(); + } + } catch (Throwable t) { + logger.error("Error while calling isAccessAllowed(). request=" + + rangerRequest, t); + } + } + if (logger.isDebugEnabled()) { + logger.debug("rangerRequest=" + rangerRequest + ", return=" + + returnValue); + } + return returnValue; + } + + /* + * (non-Javadoc) + * + * @see + * kafka.security.auth.Authorizer#addAcls(scala.collection.immutable.Set, + * kafka.security.auth.Resource) + */ + @Override + public void addAcls(Set<Acl> acls, Resource resource) { + logger.error("addAcls() is not supported by Ranger for Kafka"); + } + + /* + * (non-Javadoc) + * + * @see + * kafka.security.auth.Authorizer#removeAcls(scala.collection.immutable.Set, + * kafka.security.auth.Resource) + */ + @Override + public boolean removeAcls(Set<Acl> acls, Resource resource) { + logger.error("removeAcls() is not supported by Ranger for Kafka"); + return false; + } + + /* + * (non-Javadoc) + * + * @see + * kafka.security.auth.Authorizer#removeAcls(kafka.security.auth.Resource) + */ + @Override + public boolean removeAcls(Resource resource) { + logger.error("removeAcls() is not supported by Ranger for Kafka"); + return false; + } + + /* + * (non-Javadoc) + * + * @see kafka.security.auth.Authorizer#getAcls(kafka.security.auth.Resource) + */ + @Override + public Set<Acl> getAcls(Resource resource) { + Set<Acl> aclList = new HashSet<Acl>(); + logger.error("getAcls() is not supported by Ranger for Kafka"); + + return aclList; + } + + /* + * (non-Javadoc) + * + * @see + * kafka.security.auth.Authorizer#getAcls(kafka.security.auth.KafkaPrincipal + * ) + */ + @Override + public Set<Acl> getAcls(KafkaPrincipal principal) { + Set<Acl> aclList = new HashSet<Acl>(); + logger.error("getAcls() is not supported by Ranger for Kafka"); + return aclList; + } + + /** + * @param operation + * @return + */ + private String mapToRangerAccessType(Operation operation) { + if (operation.equals(Operation.READ)) { + return ACCESS_TYPE_READ; + } else if (operation.equals(Operation.WRITE)) { + return ACCESS_TYPE_WRITE; + } else if (operation.equals(Operation.ALTER)) { + return ACCESS_TYPE_CONFIGURE; + } else if (operation.equals(Operation.DESCRIBE)) { + return ACCESS_TYPE_DESCRIBE; + } else if (operation.equals(Operation.CLUSTER_ACTION)) { + return ACCESS_TYPE_KAFKA_ADMIN; + } + return null; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ebe83454/plugin-kms/conf/ranger-kms-security.xml ---------------------------------------------------------------------- diff --git a/plugin-kms/conf/ranger-kms-security.xml b/plugin-kms/conf/ranger-kms-security.xml index a22e6cb..58f7076 100755 --- a/plugin-kms/conf/ranger-kms-security.xml +++ b/plugin-kms/conf/ranger-kms-security.xml @@ -72,12 +72,13 @@ RangerRestClient Connection Timeout in Milli Seconds </description> </property> - + <property> <name>ranger.plugin.kms.policy.rest.client.read.timeoutMs</name> <value>30000</value> <description> RangerRestClient read Timeout in Milli Seconds </description> - </property> + </property> + </configuration> http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ebe83454/plugin-yarn/src/main/java/org/apache/ranger/authorization/yarn/authorizer/RangerYarnAuthorizer.java ---------------------------------------------------------------------- diff --git a/plugin-yarn/src/main/java/org/apache/ranger/authorization/yarn/authorizer/RangerYarnAuthorizer.java b/plugin-yarn/src/main/java/org/apache/ranger/authorization/yarn/authorizer/RangerYarnAuthorizer.java deleted file mode 100644 index ab9b7a9..0000000 --- a/plugin-yarn/src/main/java/org/apache/ranger/authorization/yarn/authorizer/RangerYarnAuthorizer.java +++ /dev/null @@ -1,354 +0,0 @@ - -/* - * 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.ranger.authorization.yarn.authorizer; - -import java.net.InetAddress; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.ipc.Server; -import org.apache.hadoop.security.UserGroupInformation; -import org.apache.hadoop.security.authorize.AccessControlList; -import org.apache.hadoop.yarn.security.*; -import org.apache.hadoop.yarn.security.PrivilegedEntity.EntityType; -import org.apache.ranger.audit.model.AuthzAuditEvent; -import org.apache.ranger.authorization.hadoop.config.RangerConfiguration; -import org.apache.ranger.authorization.hadoop.constants.RangerHadoopConstants; -import org.apache.ranger.authorization.utils.StringUtil; -import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler; -import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl; -import org.apache.ranger.plugin.policyengine.RangerAccessResult; -import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl; -import org.apache.ranger.plugin.service.RangerBasePlugin; - -import com.google.common.collect.Sets; - -public class RangerYarnAuthorizer extends YarnAuthorizationProvider { - public static final String ACCESS_TYPE_ADMIN_QUEUE = "admin-queue"; - public static final String ACCESS_TYPE_SUBMIT_APP = "submit-app"; - public static final String ACCESS_TYPE_ADMIN = "admin"; - - private static boolean yarnAuthEnabled = RangerHadoopConstants.RANGER_ADD_YARN_PERMISSION_DEFAULT; - - private static final Log LOG = LogFactory.getLog(RangerYarnAuthorizer.class); - - private static volatile RangerYarnPlugin yarnPlugin = null; - - private AccessControlList admins = null; - private Map<PrivilegedEntity, Map<AccessType, AccessControlList>> yarnAcl = new HashMap<PrivilegedEntity, Map<AccessType, AccessControlList>>(); - - @Override - public void init(Configuration conf) { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerYarnAuthorizer.init()"); - } - - RangerYarnPlugin plugin = yarnPlugin; - - if(plugin == null) { - synchronized(RangerYarnAuthorizer.class) { - plugin = yarnPlugin; - - if(plugin == null) { - plugin = new RangerYarnPlugin(); - plugin.init(); - - yarnPlugin = plugin; - } - } - } - - RangerYarnAuthorizer.yarnAuthEnabled = RangerConfiguration.getInstance().getBoolean(RangerHadoopConstants.RANGER_ADD_YARN_PERMISSION_PROP, RangerHadoopConstants.RANGER_ADD_YARN_PERMISSION_DEFAULT); - - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerYarnAuthorizer.init()"); - } - } - - @Override - public boolean checkPermission(AccessType accessType, PrivilegedEntity entity, UserGroupInformation ugi) { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerYarnAuthorizer.checkPermission(" + accessType + ", " + toString(entity) + ", " + ugi + ")"); - } - - boolean ret = false; - RangerYarnPlugin plugin = yarnPlugin; - RangerYarnAuditHandler auditHandler = null; - RangerAccessResult result = null; - - if(plugin != null) { - RangerYarnAccessRequest request = new RangerYarnAccessRequest(entity, getRangerAccessType(accessType), accessType.name(), ugi); - - auditHandler = new RangerYarnAuditHandler(); - - result = plugin.isAccessAllowed(request, auditHandler); - } - - if(RangerYarnAuthorizer.yarnAuthEnabled && (result == null || !result.getIsAccessDetermined())) { - ret = isAllowedByYarnAcl(accessType, entity, ugi, auditHandler); - } else { - ret = result == null ? false : result.getIsAllowed(); - } - - if(auditHandler != null) { - auditHandler.flushAudit(); - } - - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerYarnAuthorizer.checkPermission(" + accessType + ", " + toString(entity) + ", " + ugi + "): " + ret); - } - - return ret; - } - - @Override - public boolean isAdmin(UserGroupInformation ugi) { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerYarnAuthorizer.isAdmin(" + ugi + ")"); - } - - boolean ret = false; - - AccessControlList admins = this.admins; - - if(admins != null) { - ret = admins.isUserAllowed(ugi); - } - - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerYarnAuthorizer.isAdmin(" + ugi + "): " + ret); - } - - return ret; - } - - @Override - public void setAdmins(AccessControlList acl, UserGroupInformation ugi) { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerYarnAuthorizer.setAdmins(" + acl + ", " + ugi + ")"); - } - - admins = acl; - - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerYarnAuthorizer.setAdmins(" + acl + ", " + ugi + ")"); - } - } - - @Override - public void setPermission(PrivilegedEntity entity, Map<AccessType, AccessControlList> permission, UserGroupInformation ugi) { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerYarnAuthorizer.setPermission(" + toString(entity) + ", " + permission + ", " + ugi + ")"); - } - - yarnAcl.put(entity, permission); - - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerYarnAuthorizer.setPermission(" + toString(entity) + ", " + permission + ", " + ugi + ")"); - } - } - - public boolean isAllowedByYarnAcl(AccessType accessType, PrivilegedEntity entity, UserGroupInformation ugi, RangerYarnAuditHandler auditHandler) { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerYarnAuthorizer.isAllowedByYarnAcl(" + accessType + ", " + toString(entity) + ", " + ugi + ")"); - } - - boolean ret = false; - - for(Map.Entry<PrivilegedEntity, Map<AccessType, AccessControlList>> e : yarnAcl.entrySet()) { - PrivilegedEntity aclEntity = e.getKey(); - Map<AccessType, AccessControlList> entityPermissions = e.getValue(); - - AccessControlList acl = entityPermissions == null ? null : entityPermissions.get(accessType); - - if(acl == null || !acl.isUserAllowed(ugi)) { - continue; - } - - if(! isSelfOrChildOf(entity, aclEntity)) { - continue; - } - - ret = true; - - break; - } - - if(auditHandler != null) { - auditHandler.logYarnAclEvent(ret); - } - - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerYarnAuthorizer.isAllowedByYarnAcl(" + accessType + ", " + toString(entity) + ", " + ugi + "): " + ret); - } - - return ret; - } - - private static String getRangerAccessType(AccessType accessType) { - String ret = null; - - switch(accessType) { - case ADMINISTER_QUEUE: - ret = RangerYarnAuthorizer.ACCESS_TYPE_ADMIN_QUEUE; - break; - - case SUBMIT_APP: - ret = RangerYarnAuthorizer.ACCESS_TYPE_SUBMIT_APP; - break; - } - - return ret; - } - - private boolean isSelfOrChildOf(PrivilegedEntity queue, PrivilegedEntity parentQueue) { - boolean ret = queue.equals(parentQueue); - - if(!ret && queue.getType() == EntityType.QUEUE) { - String queueName = queue.getName(); - String parentQueueName = parentQueue.getName(); - - if(queueName.contains(".") && !StringUtil.isEmpty(parentQueueName)) { - if(parentQueueName.charAt(parentQueueName.length() - 1) != '.') { - parentQueueName += "."; - } - - ret = queueName.startsWith(parentQueueName); - } - } - - return ret; - } - - private String toString(PrivilegedEntity entity) { - if(entity != null) { - return "{name=" + entity.getName() + "; type=" + entity.getType() + "}"; - } - - return "null"; - } -} - -class RangerYarnPlugin extends RangerBasePlugin { - public RangerYarnPlugin() { - super("yarn", "yarn"); - } - - @Override - public void init() { - super.init(); - - RangerDefaultAuditHandler auditHandler = new RangerDefaultAuditHandler(); - - super.setResultProcessor(auditHandler); - } -} - -class RangerYarnResource extends RangerAccessResourceImpl { - private static final String KEY_QUEUE = "queue"; - - public RangerYarnResource(PrivilegedEntity entity) { - setValue(KEY_QUEUE, entity != null ? entity.getName() : null); - } -} - -class RangerYarnAccessRequest extends RangerAccessRequestImpl { - public RangerYarnAccessRequest(PrivilegedEntity entity, String accessType, String action, UserGroupInformation ugi) { - super.setResource(new RangerYarnResource(entity)); - super.setAccessType(accessType); - super.setUser(ugi.getShortUserName()); - super.setUserGroups(Sets.newHashSet(ugi.getGroupNames())); - super.setAccessTime(StringUtil.getUTCDate()); - super.setClientIPAddress(getRemoteIp()); - super.setAction(accessType); - } - - private static String getRemoteIp() { - String ret = null ; - InetAddress ip = Server.getRemoteIp() ; - if (ip != null) { - ret = ip.getHostAddress(); - } - return ret ; - } -} - -class RangerYarnAuditHandler extends RangerDefaultAuditHandler { - private static final Log LOG = LogFactory.getLog(RangerYarnAuditHandler.class); - - private static final String YarnModuleName = RangerConfiguration.getInstance().get(RangerHadoopConstants.AUDITLOG_YARN_MODULE_ACL_NAME_PROP , RangerHadoopConstants.DEFAULT_YARN_MODULE_ACL_NAME) ; - - private boolean isAuditEnabled = false; - private AuthzAuditEvent auditEvent = null; - - public RangerYarnAuditHandler() { - } - - @Override - public void processResult(RangerAccessResult result) { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerYarnAuditHandler.logAudit(" + result + ")"); - } - - if(! isAuditEnabled && result.getIsAudited()) { - isAuditEnabled = true; - } - - auditEvent = super.getAuthzEvents(result); - - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerYarnAuditHandler.logAudit(" + result + "): " + auditEvent); - } - } - - public void logYarnAclEvent(boolean accessGranted) { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerYarnAuditHandler.logYarnAclEvent(" + accessGranted + ")"); - } - - if(auditEvent != null) { - auditEvent.setAccessResult((short) (accessGranted ? 1 : 0)); - auditEvent.setAclEnforcer(YarnModuleName); - auditEvent.setPolicyId(-1); - } - - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerYarnAuditHandler.logYarnAclEvent(" + accessGranted + "): " + auditEvent); - } - } - - public void flushAudit() { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerYarnAuditHandler.flushAudit(" + isAuditEnabled + ", " + auditEvent + ")"); - } - - if(isAuditEnabled) { - super.logAuthzAudit(auditEvent); - } - - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerYarnAuditHandler.flushAudit(" + isAuditEnabled + ", " + auditEvent + ")"); - } - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ebe83454/plugin-yarn/src/main/java/org/apache/ranger/authorization/yarn/authorizer/RangerYarnAuthorizerImpl.java ---------------------------------------------------------------------- diff --git a/plugin-yarn/src/main/java/org/apache/ranger/authorization/yarn/authorizer/RangerYarnAuthorizerImpl.java b/plugin-yarn/src/main/java/org/apache/ranger/authorization/yarn/authorizer/RangerYarnAuthorizerImpl.java new file mode 100644 index 0000000..d154539 --- /dev/null +++ b/plugin-yarn/src/main/java/org/apache/ranger/authorization/yarn/authorizer/RangerYarnAuthorizerImpl.java @@ -0,0 +1,354 @@ + +/* + * 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.ranger.authorization.yarn.authorizer; + +import java.net.InetAddress; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.ipc.Server; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.security.authorize.AccessControlList; +import org.apache.hadoop.yarn.security.*; +import org.apache.hadoop.yarn.security.PrivilegedEntity.EntityType; +import org.apache.ranger.audit.model.AuthzAuditEvent; +import org.apache.ranger.authorization.hadoop.config.RangerConfiguration; +import org.apache.ranger.authorization.hadoop.constants.RangerHadoopConstants; +import org.apache.ranger.authorization.utils.StringUtil; +import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler; +import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl; +import org.apache.ranger.plugin.service.RangerBasePlugin; + +import com.google.common.collect.Sets; + +public class RangerYarnAuthorizerImpl extends YarnAuthorizationProvider { + public static final String ACCESS_TYPE_ADMIN_QUEUE = "admin-queue"; + public static final String ACCESS_TYPE_SUBMIT_APP = "submit-app"; + public static final String ACCESS_TYPE_ADMIN = "admin"; + + private static boolean yarnAuthEnabled = RangerHadoopConstants.RANGER_ADD_YARN_PERMISSION_DEFAULT; + + private static final Log LOG = LogFactory.getLog(RangerYarnAuthorizerImpl.class); + + private static volatile RangerYarnPlugin yarnPlugin = null; + + private AccessControlList admins = null; + private Map<PrivilegedEntity, Map<AccessType, AccessControlList>> yarnAcl = new HashMap<PrivilegedEntity, Map<AccessType, AccessControlList>>(); + + @Override + public void init(Configuration conf) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerYarnAuthorizer.init()"); + } + + RangerYarnPlugin plugin = yarnPlugin; + + if(plugin == null) { + synchronized(RangerYarnAuthorizerImpl.class) { + plugin = yarnPlugin; + + if(plugin == null) { + plugin = new RangerYarnPlugin(); + plugin.init(); + + yarnPlugin = plugin; + } + } + } + + RangerYarnAuthorizerImpl.yarnAuthEnabled = RangerConfiguration.getInstance().getBoolean(RangerHadoopConstants.RANGER_ADD_YARN_PERMISSION_PROP, RangerHadoopConstants.RANGER_ADD_YARN_PERMISSION_DEFAULT); + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerYarnAuthorizer.init()"); + } + } + + @Override + public boolean checkPermission(AccessType accessType, PrivilegedEntity entity, UserGroupInformation ugi) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerYarnAuthorizer.checkPermission(" + accessType + ", " + toString(entity) + ", " + ugi + ")"); + } + + boolean ret = false; + RangerYarnPlugin plugin = yarnPlugin; + RangerYarnAuditHandler auditHandler = null; + RangerAccessResult result = null; + + if(plugin != null) { + RangerYarnAccessRequest request = new RangerYarnAccessRequest(entity, getRangerAccessType(accessType), accessType.name(), ugi); + + auditHandler = new RangerYarnAuditHandler(); + + result = plugin.isAccessAllowed(request, auditHandler); + } + + if(RangerYarnAuthorizerImpl.yarnAuthEnabled && (result == null || !result.getIsAccessDetermined())) { + ret = isAllowedByYarnAcl(accessType, entity, ugi, auditHandler); + } else { + ret = result == null ? false : result.getIsAllowed(); + } + + if(auditHandler != null) { + auditHandler.flushAudit(); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerYarnAuthorizer.checkPermission(" + accessType + ", " + toString(entity) + ", " + ugi + "): " + ret); + } + + return ret; + } + + @Override + public boolean isAdmin(UserGroupInformation ugi) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerYarnAuthorizer.isAdmin(" + ugi + ")"); + } + + boolean ret = false; + + AccessControlList admins = this.admins; + + if(admins != null) { + ret = admins.isUserAllowed(ugi); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerYarnAuthorizer.isAdmin(" + ugi + "): " + ret); + } + + return ret; + } + + @Override + public void setAdmins(AccessControlList acl, UserGroupInformation ugi) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerYarnAuthorizer.setAdmins(" + acl + ", " + ugi + ")"); + } + + admins = acl; + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerYarnAuthorizer.setAdmins(" + acl + ", " + ugi + ")"); + } + } + + @Override + public void setPermission(PrivilegedEntity entity, Map<AccessType, AccessControlList> permission, UserGroupInformation ugi) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerYarnAuthorizer.setPermission(" + toString(entity) + ", " + permission + ", " + ugi + ")"); + } + + yarnAcl.put(entity, permission); + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerYarnAuthorizer.setPermission(" + toString(entity) + ", " + permission + ", " + ugi + ")"); + } + } + + public boolean isAllowedByYarnAcl(AccessType accessType, PrivilegedEntity entity, UserGroupInformation ugi, RangerYarnAuditHandler auditHandler) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerYarnAuthorizer.isAllowedByYarnAcl(" + accessType + ", " + toString(entity) + ", " + ugi + ")"); + } + + boolean ret = false; + + for(Map.Entry<PrivilegedEntity, Map<AccessType, AccessControlList>> e : yarnAcl.entrySet()) { + PrivilegedEntity aclEntity = e.getKey(); + Map<AccessType, AccessControlList> entityPermissions = e.getValue(); + + AccessControlList acl = entityPermissions == null ? null : entityPermissions.get(accessType); + + if(acl == null || !acl.isUserAllowed(ugi)) { + continue; + } + + if(! isSelfOrChildOf(entity, aclEntity)) { + continue; + } + + ret = true; + + break; + } + + if(auditHandler != null) { + auditHandler.logYarnAclEvent(ret); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerYarnAuthorizer.isAllowedByYarnAcl(" + accessType + ", " + toString(entity) + ", " + ugi + "): " + ret); + } + + return ret; + } + + private static String getRangerAccessType(AccessType accessType) { + String ret = null; + + switch(accessType) { + case ADMINISTER_QUEUE: + ret = RangerYarnAuthorizerImpl.ACCESS_TYPE_ADMIN_QUEUE; + break; + + case SUBMIT_APP: + ret = RangerYarnAuthorizerImpl.ACCESS_TYPE_SUBMIT_APP; + break; + } + + return ret; + } + + private boolean isSelfOrChildOf(PrivilegedEntity queue, PrivilegedEntity parentQueue) { + boolean ret = queue.equals(parentQueue); + + if(!ret && queue.getType() == EntityType.QUEUE) { + String queueName = queue.getName(); + String parentQueueName = parentQueue.getName(); + + if(queueName.contains(".") && !StringUtil.isEmpty(parentQueueName)) { + if(parentQueueName.charAt(parentQueueName.length() - 1) != '.') { + parentQueueName += "."; + } + + ret = queueName.startsWith(parentQueueName); + } + } + + return ret; + } + + private String toString(PrivilegedEntity entity) { + if(entity != null) { + return "{name=" + entity.getName() + "; type=" + entity.getType() + "}"; + } + + return "null"; + } +} + +class RangerYarnPlugin extends RangerBasePlugin { + public RangerYarnPlugin() { + super("yarn", "yarn"); + } + + @Override + public void init() { + super.init(); + + RangerDefaultAuditHandler auditHandler = new RangerDefaultAuditHandler(); + + super.setResultProcessor(auditHandler); + } +} + +class RangerYarnResource extends RangerAccessResourceImpl { + private static final String KEY_QUEUE = "queue"; + + public RangerYarnResource(PrivilegedEntity entity) { + setValue(KEY_QUEUE, entity != null ? entity.getName() : null); + } +} + +class RangerYarnAccessRequest extends RangerAccessRequestImpl { + public RangerYarnAccessRequest(PrivilegedEntity entity, String accessType, String action, UserGroupInformation ugi) { + super.setResource(new RangerYarnResource(entity)); + super.setAccessType(accessType); + super.setUser(ugi.getShortUserName()); + super.setUserGroups(Sets.newHashSet(ugi.getGroupNames())); + super.setAccessTime(StringUtil.getUTCDate()); + super.setClientIPAddress(getRemoteIp()); + super.setAction(accessType); + } + + private static String getRemoteIp() { + String ret = null ; + InetAddress ip = Server.getRemoteIp() ; + if (ip != null) { + ret = ip.getHostAddress(); + } + return ret ; + } +} + +class RangerYarnAuditHandler extends RangerDefaultAuditHandler { + private static final Log LOG = LogFactory.getLog(RangerYarnAuditHandler.class); + + private static final String YarnModuleName = RangerConfiguration.getInstance().get(RangerHadoopConstants.AUDITLOG_YARN_MODULE_ACL_NAME_PROP , RangerHadoopConstants.DEFAULT_YARN_MODULE_ACL_NAME) ; + + private boolean isAuditEnabled = false; + private AuthzAuditEvent auditEvent = null; + + public RangerYarnAuditHandler() { + } + + @Override + public void processResult(RangerAccessResult result) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerYarnAuditHandler.logAudit(" + result + ")"); + } + + if(! isAuditEnabled && result.getIsAudited()) { + isAuditEnabled = true; + } + + auditEvent = super.getAuthzEvents(result); + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerYarnAuditHandler.logAudit(" + result + "): " + auditEvent); + } + } + + public void logYarnAclEvent(boolean accessGranted) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerYarnAuditHandler.logYarnAclEvent(" + accessGranted + ")"); + } + + if(auditEvent != null) { + auditEvent.setAccessResult((short) (accessGranted ? 1 : 0)); + auditEvent.setAclEnforcer(YarnModuleName); + auditEvent.setPolicyId(-1); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerYarnAuditHandler.logYarnAclEvent(" + accessGranted + "): " + auditEvent); + } + } + + public void flushAudit() { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerYarnAuditHandler.flushAudit(" + isAuditEnabled + ", " + auditEvent + ")"); + } + + if(isAuditEnabled) { + super.logAuthzAudit(auditEvent); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerYarnAuditHandler.flushAudit(" + isAuditEnabled + ", " + auditEvent + ")"); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ebe83454/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 0ccf12e..2452785 100644 --- a/pom.xml +++ b/pom.xml @@ -14,8 +14,7 @@ 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. ---> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.apache</groupId> @@ -97,6 +96,15 @@ <module>unixauthservice</module> <module>ranger-util</module> <module>plugin-kms</module> + <module>plugin-kafka</module> + <module>ranger-hdfs-plugin-shim</module> + <module>ranger-plugin-classloader</module> + <module>ranger-hive-plugin-shim</module> + <module>ranger-hbase-plugin-shim</module> + <module>ranger-knox-plugin-shim</module> + <module>ranger-yarn-plugin-shim</module> + <module>ranger-storm-plugin-shim</module> + <module>ranger-kafka-plugin-shim</module> </modules> <properties> <javac.source.version>1.7</javac.source.version> @@ -150,8 +158,9 @@ <jersey-bundle.version>1.17.1</jersey-bundle.version> <jersey-client.version>2.6</jersey-client.version> <junit.version>4.11</junit.version> - <kafka.version>0.8.2.0</kafka.version> - <!-- <kafka.version>0.8.2.2.3.0.0-2208</kafka.version> --> + <!-- <kafka.version>0.8.2.0</kafka.version> --> + <!-- <kafka.version>0.8.2.2.3.0.0-2320</kafka.version> --> + <kafka.version>0.8.2.2.3.2.0-2950</kafka.version> <mockito.version>1.8.4</mockito.version> <hamcrest-version>1.3</hamcrest-version> <knox.gateway.version>0.6.0</knox.gateway.version> @@ -505,7 +514,7 @@ <phase>process-resources</phase> <configuration> <target> - <echo message="${project.version}" file="${project.build.directory}/version" /> + <echo message="${project.version}" file="${project.build.directory}/version"/> </target> </configuration> <goals> @@ -524,4 +533,4 @@ </plugin> </plugins> </build> -</project> +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ebe83454/ranger-hbase-plugin-shim/pom.xml ---------------------------------------------------------------------- diff --git a/ranger-hbase-plugin-shim/pom.xml b/ranger-hbase-plugin-shim/pom.xml new file mode 100644 index 0000000..c95075b --- /dev/null +++ b/ranger-hbase-plugin-shim/pom.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>security_plugins.ranger-hbase-plugin-shim</groupId> + <artifactId>ranger-hbase-plugin-shim</artifactId> + <name>HBase Security Plugin Shim</name> + <description>HBase Security Plugins Shim</description> + <packaging>jar</packaging> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <parent> + <groupId>org.apache.ranger</groupId> + <artifactId>ranger</artifactId> + <version>0.5.0</version> + <relativePath>..</relativePath> + </parent> + <dependencies> + <dependency> + <groupId>org.apache.hbase</groupId> + <artifactId>hbase-server</artifactId> + <version>${hbase.version}</version> + </dependency> + <dependency> + <groupId>org.apache.hadoop</groupId> + <artifactId>hadoop-hdfs</artifactId> + <version>${hadoop.version}</version> + </dependency> + <dependency> + <groupId>security_plugins.ranger-plugins-common</groupId> + <artifactId>ranger-plugins-common</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>security_plugins.ranger-plugins-audit</groupId> + <artifactId>ranger-plugins-audit</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>security_plugins.ranger-plugin-classloader</groupId> + <artifactId>ranger-plugin-classloader</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>security_plugins.ranger-hbase-plugin</groupId> + <artifactId>ranger-hbase-plugin</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-integration</artifactId> + </dependency> + </dependencies> +</project> http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ebe83454/ranger-hbase-plugin-shim/src/main/java/com/xasecure/authorization/hbase/XaSecureAuthorizationCoprocessor.java ---------------------------------------------------------------------- diff --git a/ranger-hbase-plugin-shim/src/main/java/com/xasecure/authorization/hbase/XaSecureAuthorizationCoprocessor.java b/ranger-hbase-plugin-shim/src/main/java/com/xasecure/authorization/hbase/XaSecureAuthorizationCoprocessor.java new file mode 100644 index 0000000..bc01e51 --- /dev/null +++ b/ranger-hbase-plugin-shim/src/main/java/com/xasecure/authorization/hbase/XaSecureAuthorizationCoprocessor.java @@ -0,0 +1,33 @@ +/** + * + * 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 com.xasecure.authorization.hbase; + +import org.apache.hadoop.hbase.coprocessor.CoprocessorService; +import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService; +import org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor; +/** + * This class exists only to provide for seamless upgrade/downgrade capabilities. Coprocessor name is in hbase config files in /etc/.../conf which + * is not only out of bounds for any upgrade script but also must be of a form to allow for downgrad! Thus when class names were changed XaSecure* -> Ranger* + * this shell class serves to allow for seamles upgrade as well as downgrade. + * + * This class is final because if one needs to customize coprocessor it is expected that RangerAuthorizationCoprocessor would be modified/extended as that is + * the "real" coprocessor! This class, hence, should NEVER be more than an EMPTY shell! + */ +public final class XaSecureAuthorizationCoprocessor extends RangerAuthorizationCoprocessor implements AccessControlService.Interface, CoprocessorService { +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/ebe83454/ranger-hbase-plugin-shim/src/main/java/org/apache/hadoop/hbase/security/access/RangerAccessControlLists.java ---------------------------------------------------------------------- diff --git a/ranger-hbase-plugin-shim/src/main/java/org/apache/hadoop/hbase/security/access/RangerAccessControlLists.java b/ranger-hbase-plugin-shim/src/main/java/org/apache/hadoop/hbase/security/access/RangerAccessControlLists.java new file mode 100644 index 0000000..7f33b15 --- /dev/null +++ b/ranger-hbase-plugin-shim/src/main/java/org/apache/hadoop/hbase/security/access/RangerAccessControlLists.java @@ -0,0 +1,104 @@ +/** + * + * 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 java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.apache.hadoop.hbase.TableExistsException; +import org.apache.hadoop.hbase.master.MasterServices; +import org.apache.log4j.Logger; + + +public class RangerAccessControlLists { + + private static final Logger LOG = Logger.getLogger(RangerAccessControlLists.class) ; + + public static void init(MasterServices master) throws IOException { + + Class<AccessControlLists> accessControlListsClass = AccessControlLists.class ; + String cName = accessControlListsClass.getName() ; + + Class<?>[] params = new Class[1] ; + params[0] = MasterServices.class ; + + for (String mname : new String[] { "init", "createACLTable" } ) { + try { + try { + Method m = accessControlListsClass.getDeclaredMethod(mname, params) ; + if (m != null) { + try { + + try { + m.invoke(null, master) ; + logInfo("Execute method name [" + mname + "] in Class [" + cName + "] is successful."); + } catch (InvocationTargetException e) { + Throwable cause = e ; + boolean tableExistsExceptionFound = false ; + if (e != null) { + Throwable ecause = e.getTargetException() ; + if (ecause != null) { + cause = ecause ; + if (ecause instanceof TableExistsException) { + tableExistsExceptionFound = true ; + } + } + } + if (! tableExistsExceptionFound) { + logError("Unable to execute the method [" + mname + "] on [" + cName + "] due to exception", cause) ; + throw new IOException(cause) ; + } + } + return ; + } catch (IllegalArgumentException e) { + logError("Unable to execute method name [" + mname + "] in Class [" + cName + "].", e); + throw new IOException(e) ; + } catch (IllegalAccessException e) { + logError("Unable to execute method name [" + mname + "] in Class [" + cName + "].", e); + throw new IOException(e) ; + } + } + } + catch(NoSuchMethodException nsme) { + logInfo("Unable to get method name [" + mname + "] in Class [" + cName + "]. Ignoring the exception"); + } + } catch (SecurityException e) { + logError("Unable to get method name [" + mname + "] in Class [" + cName + "].", e); + throw new IOException(e) ; + } + } + throw new IOException("Unable to initialize() [" + cName + "]") ; + } + + + private static void logInfo(String msg) { + // System.out.println(msg) ; + LOG.info(msg) ; + } + + private static void logError(String msg, Throwable t) { +// System.err.println(msg) ; +// if (t != null) { +// t.printStackTrace(System.err); +// } + LOG.error(msg, t); + } + +}
