blob: 1df3824113f69f07d6b21c5dc154f1b1762f5b89 [file] [log] [blame]
/*
* 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.plugin.service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.security.SecureClientLogin;
import org.apache.hadoop.security.authentication.util.KerberosName;
import org.apache.ranger.authorization.hadoop.config.RangerAdminConfig;
import org.apache.ranger.authorization.hadoop.config.RangerConfiguration;
import org.apache.ranger.plugin.model.RangerPolicy;
import org.apache.ranger.plugin.model.RangerService;
import org.apache.ranger.plugin.model.RangerServiceDef;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItem;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemAccess;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
import org.apache.ranger.plugin.model.validation.RangerServiceDefHelper;
import org.apache.ranger.plugin.resourcematcher.RangerAbstractResourceMatcher;
import org.apache.ranger.plugin.util.ServiceDefUtil;
public abstract class RangerBaseService {
private static final Log LOG = LogFactory.getLog(RangerBaseService.class);
protected static final String ADMIN_USER_PRINCIPAL = "ranger.admin.kerberos.principal";
protected static final String ADMIN_USER_KEYTAB = "ranger.admin.kerberos.keytab";
protected static final String LOOKUP_PRINCIPAL = "ranger.lookup.kerberos.principal";
protected static final String LOOKUP_KEYTAB = "ranger.lookup.kerberos.keytab";
protected static final String RANGER_AUTH_TYPE = "hadoop.security.authentication";
protected static final String KERBEROS_TYPE = "kerberos";
protected RangerServiceDef serviceDef;
protected RangerService service;
protected Map<String, String> configs;
protected String serviceName;
protected String serviceType;
private final RangerAdminConfig config;
public RangerBaseService() {
this.config = new RangerAdminConfig();
}
public void init(RangerServiceDef serviceDef, RangerService service) {
this.serviceDef = serviceDef;
this.service = service;
this.configs = service.getConfigs();
this.serviceName = service.getName();
this.serviceType = service.getType();
}
/**
* @return the serviceDef
*/
public RangerServiceDef getServiceDef() {
return serviceDef;
}
/**
* @return the service
*/
public RangerService getService() {
return service;
}
public Map<String, String> getConfigs() {
return configs;
}
public void setConfigs(Map<String, String> configs) {
this.configs = configs;
}
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public String getServiceType() {
return serviceType;
}
public void setServiceType(String serviceType) {
this.serviceType = serviceType;
}
public RangerAdminConfig getConfig() { return config; }
public abstract Map<String, Object> validateConfig() throws Exception;
public abstract List<String> lookupResource(ResourceLookupContext context) throws Exception;
public List<RangerPolicy> getDefaultRangerPolicies() throws Exception {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerBaseService.getDefaultRangerPolicies() ");
}
final Boolean additionalDefaultPolicySetup = Boolean.valueOf(configs.get("setup.additional.default.policies"));
List<RangerPolicy> ret = new ArrayList<RangerPolicy>();
try {
// we need to create one policy for each resource hierarchy
RangerServiceDefHelper serviceDefHelper = new RangerServiceDefHelper(serviceDef);
for (List<RangerServiceDef.RangerResourceDef> aHierarchy : serviceDefHelper.filterHierarchies_containsOnlyMandatoryResources(RangerPolicy.POLICY_TYPE_ACCESS)) {
RangerPolicy policy = getDefaultPolicy(aHierarchy);
if (policy != null) {
ret.add(policy);
}
}
} catch (Exception e) {
LOG.error("Error getting default polcies for Service: " + service.getName(), e);
}
if (additionalDefaultPolicySetup) {
final String PROP_POLICY_NAME_PREFIX = "default-policy.";
final String PROP_POLICY_NAME_SUFFIX = ".name";
TreeSet<String> policyIndexes = new TreeSet<>();
for (String configName : configs.keySet()) {
if (configName.startsWith(PROP_POLICY_NAME_PREFIX) && configName.endsWith(PROP_POLICY_NAME_SUFFIX)) {
policyIndexes.add(configName.substring(PROP_POLICY_NAME_PREFIX.length(), configName.length() - PROP_POLICY_NAME_SUFFIX.length()));
}
}
for (String policyIndex : policyIndexes) {
String resourcePropertyPrefix = "default-policy." + policyIndex + ".resource.";
Map<String, RangerPolicyResource> policyResources = getResourcesForPrefix(resourcePropertyPrefix);
if(MapUtils.isNotEmpty(policyResources)){
addCustomRangerDefaultPolicies(ret, policyResources,policyIndex);
}
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerBaseService.getDefaultRangerPolicies(): " + ret);
}
return ret;
}
private Map<String, RangerPolicyResource> getResourcesForPrefix(String resourcePropertyPrefix) {
Map<String, RangerPolicy.RangerPolicyResource> policyResourceMap = new HashMap<String, RangerPolicy.RangerPolicyResource>();
if (configs != null) {
for (Map.Entry<String, String> entry : configs.entrySet()) {
if(entry.getKey().indexOf(resourcePropertyPrefix) > -1 && StringUtils.isNotBlank(entry.getValue())){
RangerPolicyResource rPolRes=new RangerPolicyResource();
String resourceKey = entry.getKey().substring(resourcePropertyPrefix.length());
List<String> resourceList = new ArrayList<String>(Arrays.asList(entry.getValue().split(",")));
rPolRes.setIsExcludes(false);
rPolRes.setIsRecursive(false);
rPolRes.setValues(resourceList);
policyResourceMap.put(resourceKey, rPolRes);
}
}
}
return policyResourceMap;
}
private void addCustomRangerDefaultPolicies(List<RangerPolicy> ret, Map<String, RangerPolicy.RangerPolicyResource> policyResourceMap, String policyIndex) throws Exception {
LOG.info("Setting additional default policies");
String startConfigName = "default-policy.";
RangerPolicy addDefaultPolicy1 = null;
String policyName = configs.get(startConfigName+policyIndex+".name");
if(policyResourceMap!= null && StringUtils.isNotBlank(policyName)){
String polItem1Users = configs.get(startConfigName+policyIndex+".policyItem.1.users");
String polItem2Users = configs.get(startConfigName+policyIndex+".policyItem.2.users");
String polItem1group = configs.get(startConfigName+policyIndex+".policyItem.1.groups");
String polItem2group = configs.get(startConfigName+policyIndex+".policyItem.2.groups");
String polItem1AccessTypes = configs.get(startConfigName+policyIndex+".policyItem.1.accessTypes");
String polItem2AccessTypes = configs.get(startConfigName+policyIndex+".policyItem.2.accessTypes");
if((StringUtils.isNotBlank(polItem1Users) && StringUtils.isNotBlank(polItem1AccessTypes)) || (StringUtils.isNotBlank(polItem2Users) && StringUtils.isNotBlank(polItem2AccessTypes)) ){
addDefaultPolicy1 = getRangerCustomPolicy(policyName,policyResourceMap,polItem1Users,polItem2Users,polItem1group,polItem2group,polItem1AccessTypes,polItem2AccessTypes);
if(addDefaultPolicy1 != null){
ret.add(addDefaultPolicy1);
}
}
}
}
public RangerPolicy getRangerCustomPolicy(String policyName, Map<String, RangerPolicy.RangerPolicyResource> policyResourceMap, String polItem1Users, String polItem2Users, String polItem1Group, String polItem2Group, String polItem1AccessTypes, String polItem2AccessTypes) throws Exception {
if(LOG.isDebugEnabled()){
LOG.debug("==> RangerBaseService.getAtlasTopicPolicy(). resourcenames" + policyResourceMap + "policy users = " + polItem1Users + polItem2Users + "policy groups = " + polItem1Group + polItem2Group + "accessLists ");
}
RangerPolicy rPolicy = new RangerPolicy();
List<RangerPolicyItem> policyItemList =new ArrayList<RangerPolicyItem>();
List<String> policyItem1UserList = new ArrayList<String>();
List<String> policyItem2UserList = new ArrayList<String>();
List<String> pol1Item1AccessTypeList = new ArrayList<String>();
List<String> pol1Item2AccessTypeList = new ArrayList<String>();
List<String> policyItem1GroupList = new ArrayList<String>();
List<String> policyItem2GroupList = new ArrayList<String>();
if(StringUtils.isNotBlank(polItem1Group)){
policyItem1GroupList.addAll(Arrays.asList(polItem1Group.split(",")));
}
if(StringUtils.isNotBlank(polItem2Group)){
policyItem2GroupList.addAll(Arrays.asList(polItem2Group.split(",")));
}
if(StringUtils.isNotBlank(polItem1Users)){
policyItem1UserList.addAll(Arrays.asList(polItem1Users.split(",")));
}
if(StringUtils.isNotBlank(polItem2Users)){
policyItem2UserList.addAll(Arrays.asList(polItem2Users.split(",")));
}
if(StringUtils.isNotBlank(polItem1AccessTypes)){
pol1Item1AccessTypeList.addAll(Arrays.asList(polItem1AccessTypes.split(",")));
}
if(StringUtils.isNotBlank(polItem2AccessTypes)){
pol1Item2AccessTypeList.addAll(Arrays.asList(polItem2AccessTypes.split(",")));
}
if((CollectionUtils.isNotEmpty(policyItem1UserList)||CollectionUtils.isNotEmpty(policyItem1GroupList)) && CollectionUtils.isNotEmpty(pol1Item1AccessTypeList)){
RangerPolicyItem policyItem1 = setCustomPolItem(policyItem1UserList,pol1Item1AccessTypeList,policyItem1GroupList);
policyItemList.add(policyItem1);
}
if((CollectionUtils.isNotEmpty(policyItem2UserList)||CollectionUtils.isNotEmpty(policyItem2GroupList)) && CollectionUtils.isNotEmpty(pol1Item2AccessTypeList)){
RangerPolicy.RangerPolicyItem policyItem2 = setCustomPolItem(policyItem2UserList,pol1Item2AccessTypeList,policyItem2GroupList);
policyItemList.add(policyItem2);
}
rPolicy.setPolicyItems(policyItemList);
rPolicy.setIsEnabled(true);
rPolicy.setVersion(1L);
rPolicy.setIsAuditEnabled(true);
rPolicy.setService(serviceName);
rPolicy.setDescription("Policy for " + policyName);
rPolicy.setName(policyName);
rPolicy.setResources(policyResourceMap);
if(LOG.isDebugEnabled()){
LOG.debug("<== RangerBaseService.getAtlasTopicPolicy() ");
}
return rPolicy;
}
private RangerPolicyItem setCustomPolItem(List<String> userList, List<String> pol1Item1AccessTypeList, List<String> groupList) {
RangerPolicyItem polItem = new RangerPolicyItem();
if(LOG.isDebugEnabled()){
LOG.debug("==> RangerServiceKafka.setCustomPolItem(). userlist = " + userList + " accessType" + pol1Item1AccessTypeList);
}
List<RangerPolicyItemAccess> polAccesslist =new ArrayList<RangerPolicyItemAccess>();
polItem.setDelegateAdmin(false);
for(String pol1Item1AccessType : pol1Item1AccessTypeList){
RangerPolicyItemAccess polAccess = new RangerPolicyItemAccess();
polAccess.setIsAllowed(true);
polAccess.setType(pol1Item1AccessType);
polAccesslist.add(polAccess);
}
polItem.setAccesses(polAccesslist );
polItem.setUsers(userList);
polItem.setGroups(groupList);
if(LOG.isDebugEnabled()){
LOG.debug("<== RangerServiceKafka.setCustomPolItem()");
}
return polItem;
}
private RangerPolicy getDefaultPolicy(List<RangerServiceDef.RangerResourceDef> resourceHierarchy) throws Exception {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerBaseService.getDefaultPolicy()");
}
RangerPolicy policy = new RangerPolicy();
String policyName=buildPolicyName(resourceHierarchy);
policy.setIsEnabled(true);
policy.setVersion(1L);
policy.setName(policyName);
policy.setService(service.getName());
policy.setDescription("Policy for " + policyName);
policy.setIsAuditEnabled(true);
policy.setResources(createDefaultPolicyResource(resourceHierarchy));
List<RangerPolicy.RangerPolicyItem> policyItems = new ArrayList<RangerPolicy.RangerPolicyItem>();
//Create Default policy item for the service user
RangerPolicy.RangerPolicyItem policyItem = createDefaultPolicyItem(policy.getResources());
policyItems.add(policyItem);
policy.setPolicyItems(policyItems);
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerBaseService.getDefaultPolicy()" + policy);
}
return policy;
}
private RangerPolicy.RangerPolicyItem createDefaultPolicyItem(Map<String, RangerPolicy.RangerPolicyResource> policyResources) throws Exception {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerBaseService.createDefaultPolicyItem()");
}
RangerPolicy.RangerPolicyItem policyItem = new RangerPolicy.RangerPolicyItem();
policyItem.setUsers(getUserList());
policyItem.setGroups(getGroupList());
List<RangerPolicy.RangerPolicyItemAccess> accesses = getAllowedAccesses(policyResources);
policyItem.setAccesses(accesses);
policyItem.setDelegateAdmin(true);
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerBaseService.createDefaultPolicyItem(): " + policyItem );
}
return policyItem;
}
protected List<RangerPolicy.RangerPolicyItemAccess> getAllowedAccesses(Map<String, RangerPolicy.RangerPolicyResource> policyResources) {
List<RangerPolicy.RangerPolicyItemAccess> ret = new ArrayList<RangerPolicy.RangerPolicyItemAccess>();
RangerServiceDef.RangerResourceDef leafResourceDef = ServiceDefUtil.getLeafResourceDef(serviceDef, policyResources);
if (leafResourceDef != null) {
Set<String> accessTypeRestrictions = leafResourceDef.getAccessTypeRestrictions();
for (RangerServiceDef.RangerAccessTypeDef accessTypeDef : serviceDef.getAccessTypes()) {
boolean isAccessTypeAllowed = CollectionUtils.isEmpty(accessTypeRestrictions) || accessTypeRestrictions.contains(accessTypeDef.getName());
if (isAccessTypeAllowed) {
RangerPolicy.RangerPolicyItemAccess access = new RangerPolicy.RangerPolicyItemAccess();
access.setType(accessTypeDef.getName());
access.setIsAllowed(true);
ret.add(access);
}
}
}
return ret;
}
protected Map<String, RangerPolicy.RangerPolicyResource> createDefaultPolicyResource(List<RangerServiceDef.RangerResourceDef> resourceHierarchy) throws Exception {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerBaseService.createDefaultPolicyResource()");
}
Map<String, RangerPolicy.RangerPolicyResource> resourceMap = new HashMap<>();
for (RangerServiceDef.RangerResourceDef resourceDef : resourceHierarchy) {
RangerPolicy.RangerPolicyResource polRes = new RangerPolicy.RangerPolicyResource();
polRes.setIsExcludes(false);
polRes.setIsRecursive(resourceDef.getRecursiveSupported());
polRes.setValue(RangerAbstractResourceMatcher.WILDCARD_ASTERISK);
resourceMap.put(resourceDef.getName(), polRes);
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerBaseService.createDefaultPolicyResource():" + resourceMap);
}
return resourceMap;
}
private String buildPolicyName(List<RangerServiceDef.RangerResourceDef> resourceHierarchy) {
StringBuilder sb = new StringBuilder("all");
if (CollectionUtils.isNotEmpty(resourceHierarchy)) {
int resourceDefCount = 0;
for (RangerServiceDef.RangerResourceDef resourceDef : resourceHierarchy) {
if (resourceDefCount > 0) {
sb.append(", ");
} else {
sb.append(" - ");
}
sb.append(resourceDef.getName());
resourceDefCount++;
}
}
return sb.toString().trim();
}
private List<String> getUserList() {
List<String> ret = new ArrayList<>();
HashSet<String> uniqueUsers = new HashSet<String>();
String[] users = config.getStrings("ranger.default.policy.users");
if (users != null) {
for (String user : users) {
uniqueUsers.add(user);
}
}
Map<String, String> serviceConfig = service.getConfigs();
if (serviceConfig != null ) {
String serviceConfigUser = serviceConfig.get("username");
if (StringUtils.isNotBlank(serviceConfigUser)){
uniqueUsers.add(serviceConfig.get("username"));
}
String defaultUsers = serviceConfig.get("default.policy.users");
if (!StringUtils.isEmpty(defaultUsers)) {
List<String> defaultUserList = new ArrayList<>(Arrays.asList(StringUtils.split(defaultUsers,",")));
if (!defaultUserList.isEmpty()) {
uniqueUsers.addAll(defaultUserList);
}
}
}
String authType = config.get(RANGER_AUTH_TYPE,"simple");
String lookupPrincipal = config.get(LOOKUP_PRINCIPAL);
String lookupKeytab = config.get(LOOKUP_KEYTAB);
String lookUpUser = getLookupUser(authType, lookupPrincipal, lookupKeytab);
if (StringUtils.isNotBlank(lookUpUser)) {
uniqueUsers.add(lookUpUser);
}
ret.addAll(uniqueUsers);
return ret;
}
private List<String> getGroupList() {
List<String> ret = new ArrayList<>();
HashSet<String> uniqueGroups = new HashSet<String>();
String[] groups = config.getStrings("ranger.default.policy.groups");
if (groups != null) {
for (String group : groups) {
uniqueGroups.add(group);
}
}
Map<String, String> serviceConfig = service.getConfigs();
if (serviceConfig != null) {
String defaultGroups = serviceConfig.get("default.policy.groups");
if (!StringUtils.isEmpty(defaultGroups)) {
List<String> defaultGroupList = new ArrayList<>(Arrays.asList(StringUtils.split(defaultGroups, ",")));
if (!defaultGroupList.isEmpty()) {
uniqueGroups.addAll(defaultGroupList);
}
}
}
ret.addAll(uniqueGroups);
return ret;
}
protected String getLookupUser(String authType, String lookupPrincipal, String lookupKeytab) {
String lookupUser = null;
if(!StringUtils.isEmpty(authType) && authType.equalsIgnoreCase(KERBEROS_TYPE)){
if(SecureClientLogin.isKerberosCredentialExists(lookupPrincipal, lookupKeytab)){
KerberosName krbName = new KerberosName(lookupPrincipal);
try {
lookupUser = krbName.getShortName();
} catch (IOException e) {
LOG.error("Unknown lookup user", e);
}
}
}
return lookupUser;
}
}