001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019package org.apache.hadoop.security.authorize; 020 021import java.util.Collection; 022import java.util.HashMap; 023import java.util.Map; 024import java.util.Map.Entry; 025import java.util.regex.Pattern; 026 027import org.apache.hadoop.classification.InterfaceAudience; 028import org.apache.hadoop.classification.InterfaceStability; 029import org.apache.hadoop.conf.Configuration; 030import org.apache.hadoop.security.UserGroupInformation; 031import org.apache.hadoop.util.MachineList; 032 033import com.google.common.annotations.VisibleForTesting; 034 035@InterfaceStability.Unstable 036@InterfaceAudience.Public 037public class DefaultImpersonationProvider implements ImpersonationProvider { 038 private static final String CONF_HOSTS = ".hosts"; 039 private static final String CONF_USERS = ".users"; 040 private static final String CONF_GROUPS = ".groups"; 041 // acl and list of hosts per proxyuser 042 private Map<String, AccessControlList> proxyUserAcl = 043 new HashMap<String, AccessControlList>(); 044 private Map<String, MachineList> proxyHosts = 045 new HashMap<String, MachineList>(); 046 private Configuration conf; 047 048 049 private static DefaultImpersonationProvider testProvider; 050 051 public static synchronized DefaultImpersonationProvider getTestProvider() { 052 if (testProvider == null) { 053 testProvider = new DefaultImpersonationProvider(); 054 testProvider.setConf(new Configuration()); 055 testProvider.init(ProxyUsers.CONF_HADOOP_PROXYUSER); 056 } 057 return testProvider; 058 } 059 060 @Override 061 public void setConf(Configuration conf) { 062 this.conf = conf; 063 } 064 065 private String configPrefix; 066 067 @Override 068 public void init(String configurationPrefix) { 069 configPrefix = configurationPrefix + 070 (configurationPrefix.endsWith(".") ? "" : "."); 071 072 // constructing regex to match the following patterns: 073 // $configPrefix.[ANY].users 074 // $configPrefix.[ANY].groups 075 // $configPrefix.[ANY].hosts 076 // 077 String prefixRegEx = configPrefix.replace(".", "\\."); 078 String usersGroupsRegEx = prefixRegEx + "[^.]*(" + 079 Pattern.quote(CONF_USERS) + "|" + Pattern.quote(CONF_GROUPS) + ")"; 080 String hostsRegEx = prefixRegEx + "[^.]*" + Pattern.quote(CONF_HOSTS); 081 082 // get list of users and groups per proxyuser 083 Map<String,String> allMatchKeys = 084 conf.getValByRegex(usersGroupsRegEx); 085 for(Entry<String, String> entry : allMatchKeys.entrySet()) { 086 String aclKey = getAclKey(entry.getKey()); 087 if (!proxyUserAcl.containsKey(aclKey)) { 088 proxyUserAcl.put(aclKey, new AccessControlList( 089 allMatchKeys.get(aclKey + CONF_USERS) , 090 allMatchKeys.get(aclKey + CONF_GROUPS))); 091 } 092 } 093 094 // get hosts per proxyuser 095 allMatchKeys = conf.getValByRegex(hostsRegEx); 096 for(Entry<String, String> entry : allMatchKeys.entrySet()) { 097 proxyHosts.put(entry.getKey(), 098 new MachineList(entry.getValue())); 099 } 100 } 101 102 @Override 103 public Configuration getConf() { 104 return conf; 105 } 106 107 @Override 108 public void authorize(UserGroupInformation user, 109 String remoteAddress) throws AuthorizationException { 110 111 UserGroupInformation realUser = user.getRealUser(); 112 if (realUser == null) { 113 return; 114 } 115 116 AccessControlList acl = proxyUserAcl.get(configPrefix + 117 realUser.getShortUserName()); 118 if (acl == null || !acl.isUserAllowed(user)) { 119 throw new AuthorizationException("User: " + realUser.getUserName() 120 + " is not allowed to impersonate " + user.getUserName()); 121 } 122 123 MachineList MachineList = proxyHosts.get( 124 getProxySuperuserIpConfKey(realUser.getShortUserName())); 125 126 if(MachineList == null || !MachineList.includes(remoteAddress)) { 127 throw new AuthorizationException("Unauthorized connection for super-user: " 128 + realUser.getUserName() + " from IP " + remoteAddress); 129 } 130 } 131 132 private String getAclKey(String key) { 133 int endIndex = key.lastIndexOf("."); 134 if (endIndex != -1) { 135 return key.substring(0, endIndex); 136 } 137 return key; 138 } 139 140 /** 141 * Returns configuration key for effective usergroups allowed for a superuser 142 * 143 * @param userName name of the superuser 144 * @return configuration key for superuser usergroups 145 */ 146 public String getProxySuperuserUserConfKey(String userName) { 147 return configPrefix + userName + CONF_USERS; 148 } 149 150 /** 151 * Returns configuration key for effective groups allowed for a superuser 152 * 153 * @param userName name of the superuser 154 * @return configuration key for superuser groups 155 */ 156 public String getProxySuperuserGroupConfKey(String userName) { 157 return configPrefix + userName + CONF_GROUPS; 158 } 159 160 /** 161 * Return configuration key for superuser ip addresses 162 * 163 * @param userName name of the superuser 164 * @return configuration key for superuser ip-addresses 165 */ 166 public String getProxySuperuserIpConfKey(String userName) { 167 return configPrefix + userName + CONF_HOSTS; 168 } 169 170 @VisibleForTesting 171 public Map<String, Collection<String>> getProxyGroups() { 172 Map<String,Collection<String>> proxyGroups = new HashMap<String,Collection<String>>(); 173 for(Entry<String, AccessControlList> entry : proxyUserAcl.entrySet()) { 174 proxyGroups.put(entry.getKey() + CONF_GROUPS, entry.getValue().getGroups()); 175 } 176 return proxyGroups; 177 } 178 179 @VisibleForTesting 180 public Map<String, Collection<String>> getProxyHosts() { 181 Map<String, Collection<String>> tmpProxyHosts = 182 new HashMap<String, Collection<String>>(); 183 for (Map.Entry<String, MachineList> proxyHostEntry :proxyHosts.entrySet()) { 184 tmpProxyHosts.put(proxyHostEntry.getKey(), 185 proxyHostEntry.getValue().getCollection()); 186 } 187 return tmpProxyHosts; 188 } 189}