001/** 002 * Licensed under the Apache License, Version 2.0 (the "License"); 003 * you may not use this file except in compliance with the License. 004 * You may obtain a copy of the License at 005 * 006 * http://www.apache.org/licenses/LICENSE-2.0 007 * 008 * Unless required by applicable law or agreed to in writing, software 009 * distributed under the License is distributed on an "AS IS" BASIS, 010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 011 * See the License for the specific language governing permissions and 012 * limitations under the License. See accompanying LICENSE file. 013 */ 014package org.apache.hadoop.hdfs.server.datanode.web.webhdfs; 015 016import org.apache.commons.logging.Log; 017import org.apache.commons.logging.LogFactory; 018import org.apache.hadoop.conf.Configuration; 019import org.apache.hadoop.hdfs.DFSConfigKeys; 020import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier; 021import org.apache.hadoop.hdfs.server.common.JspHelper; 022import org.apache.hadoop.ipc.Client; 023import org.apache.hadoop.security.UserGroupInformation; 024import org.apache.hadoop.security.token.Token; 025 026import com.google.common.annotations.VisibleForTesting; 027import com.google.common.cache.Cache; 028import com.google.common.cache.CacheBuilder; 029 030import java.io.ByteArrayInputStream; 031import java.io.DataInputStream; 032import java.io.IOException; 033import java.util.concurrent.Callable; 034import java.util.concurrent.ExecutionException; 035import java.util.concurrent.TimeUnit; 036 037/** 038 * Create UGI from the request for the WebHDFS requests for the DNs. Note that 039 * the DN does not authenticate the UGI -- the NN will authenticate them in 040 * subsequent operations. 041 */ 042public class DataNodeUGIProvider { 043 private final ParameterParser params; 044 @VisibleForTesting 045 static Cache<String, UserGroupInformation> ugiCache; 046 public static final Log LOG = LogFactory.getLog(Client.class); 047 048 DataNodeUGIProvider(ParameterParser params) { 049 this.params = params; 050 } 051 052 public static synchronized void init(Configuration conf) { 053 if (ugiCache == null) { 054 ugiCache = CacheBuilder 055 .newBuilder() 056 .expireAfterAccess( 057 conf.getInt( 058 DFSConfigKeys.DFS_WEBHDFS_UGI_EXPIRE_AFTER_ACCESS_KEY, 059 DFSConfigKeys.DFS_WEBHDFS_UGI_EXPIRE_AFTER_ACCESS_DEFAULT), 060 TimeUnit.MILLISECONDS).build(); 061 } 062 } 063 064 @VisibleForTesting 065 void clearCache() throws IOException { 066 if (UserGroupInformation.isSecurityEnabled()) { 067 params.delegationToken().decodeIdentifier().clearCache(); 068 } 069 } 070 071 UserGroupInformation ugi() throws IOException { 072 UserGroupInformation ugi; 073 074 try { 075 if (UserGroupInformation.isSecurityEnabled()) { 076 final Token<DelegationTokenIdentifier> token = params.delegationToken(); 077 078 ugi = ugiCache.get(buildTokenCacheKey(token), 079 new Callable<UserGroupInformation>() { 080 @Override 081 public UserGroupInformation call() throws Exception { 082 return tokenUGI(token); 083 } 084 }); 085 } else { 086 final String usernameFromQuery = params.userName(); 087 final String doAsUserFromQuery = params.doAsUser(); 088 final String remoteUser = usernameFromQuery == null ? JspHelper 089 .getDefaultWebUserName(params.conf()) // not specified in request 090 : usernameFromQuery; 091 092 ugi = ugiCache.get( 093 buildNonTokenCacheKey(doAsUserFromQuery, remoteUser), 094 new Callable<UserGroupInformation>() { 095 @Override 096 public UserGroupInformation call() throws Exception { 097 return nonTokenUGI(usernameFromQuery, doAsUserFromQuery, 098 remoteUser); 099 } 100 }); 101 } 102 } catch (ExecutionException e) { 103 Throwable cause = e.getCause(); 104 if (cause instanceof IOException) { 105 throw (IOException) cause; 106 } else { 107 throw new IOException(cause); 108 } 109 } 110 111 return ugi; 112 } 113 114 private String buildTokenCacheKey(Token<DelegationTokenIdentifier> token) { 115 return token.buildCacheKey(); 116 } 117 118 private UserGroupInformation tokenUGI(Token<DelegationTokenIdentifier> token) 119 throws IOException { 120 ByteArrayInputStream buf = 121 new ByteArrayInputStream(token.getIdentifier()); 122 DataInputStream in = new DataInputStream(buf); 123 DelegationTokenIdentifier id = new DelegationTokenIdentifier(); 124 id.readFields(in); 125 UserGroupInformation ugi = id.getUser(); 126 ugi.addToken(token); 127 return ugi; 128 } 129 130 private String buildNonTokenCacheKey(String doAsUserFromQuery, 131 String remoteUser) throws IOException { 132 String key = doAsUserFromQuery == null ? String.format("{%s}", remoteUser) 133 : String.format("{%s}:{%s}", remoteUser, doAsUserFromQuery); 134 return key; 135 } 136 137 private UserGroupInformation nonTokenUGI(String usernameFromQuery, 138 String doAsUserFromQuery, String remoteUser) throws IOException { 139 140 UserGroupInformation ugi = UserGroupInformation 141 .createRemoteUser(remoteUser); 142 JspHelper.checkUsername(ugi.getShortUserName(), usernameFromQuery); 143 if (doAsUserFromQuery != null) { 144 // create and attempt to authorize a proxy user 145 ugi = UserGroupInformation.createProxyUser(doAsUserFromQuery, ugi); 146 } 147 return ugi; 148 } 149}