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 if (user == null) { 112 throw new IllegalArgumentException("user is null."); 113 } 114 115 UserGroupInformation realUser = user.getRealUser(); 116 if (realUser == null) { 117 return; 118 } 119 120 AccessControlList acl = proxyUserAcl.get(configPrefix + 121 realUser.getShortUserName()); 122 if (acl == null || !acl.isUserAllowed(user)) { 123 throw new AuthorizationException("User: " + realUser.getUserName() 124 + " is not allowed to impersonate " + user.getUserName()); 125 } 126 127 MachineList MachineList = proxyHosts.get( 128 getProxySuperuserIpConfKey(realUser.getShortUserName())); 129 130 if(MachineList == null || !MachineList.includes(remoteAddress)) { 131 throw new AuthorizationException("Unauthorized connection for super-user: " 132 + realUser.getUserName() + " from IP " + remoteAddress); 133 } 134 } 135 136 private String getAclKey(String key) { 137 int endIndex = key.lastIndexOf("."); 138 if (endIndex != -1) { 139 return key.substring(0, endIndex); 140 } 141 return key; 142 } 143 144 /** 145 * Returns configuration key for effective usergroups allowed for a superuser 146 * 147 * @param userName name of the superuser 148 * @return configuration key for superuser usergroups 149 */ 150 public String getProxySuperuserUserConfKey(String userName) { 151 return configPrefix + userName + CONF_USERS; 152 } 153 154 /** 155 * Returns configuration key for effective groups allowed for a superuser 156 * 157 * @param userName name of the superuser 158 * @return configuration key for superuser groups 159 */ 160 public String getProxySuperuserGroupConfKey(String userName) { 161 return configPrefix + userName + CONF_GROUPS; 162 } 163 164 /** 165 * Return configuration key for superuser ip addresses 166 * 167 * @param userName name of the superuser 168 * @return configuration key for superuser ip-addresses 169 */ 170 public String getProxySuperuserIpConfKey(String userName) { 171 return configPrefix + userName + CONF_HOSTS; 172 } 173 174 @VisibleForTesting 175 public Map<String, Collection<String>> getProxyGroups() { 176 Map<String,Collection<String>> proxyGroups = new HashMap<String,Collection<String>>(); 177 for(Entry<String, AccessControlList> entry : proxyUserAcl.entrySet()) { 178 proxyGroups.put(entry.getKey() + CONF_GROUPS, entry.getValue().getGroups()); 179 } 180 return proxyGroups; 181 } 182 183 @VisibleForTesting 184 public Map<String, Collection<String>> getProxyHosts() { 185 Map<String, Collection<String>> tmpProxyHosts = 186 new HashMap<String, Collection<String>>(); 187 for (Map.Entry<String, MachineList> proxyHostEntry :proxyHosts.entrySet()) { 188 tmpProxyHosts.put(proxyHostEntry.getKey(), 189 proxyHostEntry.getValue().getCollection()); 190 } 191 return tmpProxyHosts; 192 } 193}