|
@@ -22,6 +22,7 @@ import java.io.IOException;
|
|
|
import java.io.UnsupportedEncodingException;
|
|
|
import java.net.InetSocketAddress;
|
|
|
import java.net.Socket;
|
|
|
+import java.security.PrivilegedExceptionAction;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Collections;
|
|
|
import java.util.Comparator;
|
|
@@ -31,30 +32,39 @@ import java.util.TreeSet;
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
import javax.servlet.jsp.JspWriter;
|
|
|
|
|
|
+import org.apache.commons.logging.Log;
|
|
|
+import org.apache.commons.logging.LogFactory;
|
|
|
import org.apache.hadoop.conf.Configuration;
|
|
|
import org.apache.hadoop.hdfs.DFSClient;
|
|
|
import org.apache.hadoop.hdfs.protocol.DatanodeID;
|
|
|
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
|
|
|
import org.apache.hadoop.hdfs.protocol.LocatedBlock;
|
|
|
import org.apache.hadoop.hdfs.protocol.FSConstants.UpgradeAction;
|
|
|
+import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier;
|
|
|
import org.apache.hadoop.hdfs.server.common.HdfsConstants;
|
|
|
import org.apache.hadoop.hdfs.server.common.UpgradeStatusReport;
|
|
|
import org.apache.hadoop.hdfs.server.datanode.DataNode;
|
|
|
+import org.apache.hadoop.hdfs.server.namenode.DatanodeDescriptor;
|
|
|
+import org.apache.hadoop.hdfs.server.namenode.FSNamesystem;
|
|
|
import org.apache.hadoop.http.HtmlQuoting;
|
|
|
import org.apache.hadoop.fs.Path;
|
|
|
+import org.apache.hadoop.security.AccessControlException;
|
|
|
+import org.apache.hadoop.security.UserGroupInformation;
|
|
|
+import org.apache.hadoop.security.token.Token;
|
|
|
import org.apache.hadoop.util.StringUtils;
|
|
|
import org.apache.hadoop.net.NetUtils;
|
|
|
import org.apache.hadoop.hdfs.security.BlockAccessToken;
|
|
|
|
|
|
public class JspHelper {
|
|
|
final static public String WEB_UGI_PROPERTY_NAME = "dfs.web.ugi";
|
|
|
+ public static final String DELEGATION_PARAMETER_NAME = "delegation";
|
|
|
+ public static final String SET_DELEGATION = "&" + DELEGATION_PARAMETER_NAME +
|
|
|
+ "=";
|
|
|
+ private static final Log LOG = LogFactory.getLog(JspHelper.class);
|
|
|
|
|
|
static FSNamesystem fsn = null;
|
|
|
public static InetSocketAddress nameNodeAddr;
|
|
|
- public static final Configuration conf = new Configuration();
|
|
|
|
|
|
- public static final int defaultChunkSizeToView =
|
|
|
- conf.getInt("dfs.default.chunk.view.size", 32 * 1024);
|
|
|
static Random rand = new Random();
|
|
|
|
|
|
public JspHelper() {
|
|
@@ -111,8 +121,11 @@ public class JspHelper {
|
|
|
return chosenNode;
|
|
|
}
|
|
|
public void streamBlockInAscii(InetSocketAddress addr, long blockId,
|
|
|
- BlockAccessToken accessToken, long genStamp, long blockSize,
|
|
|
- long offsetIntoBlock, long chunkSizeToView, JspWriter out)
|
|
|
+ BlockAccessToken accessToken, long genStamp,
|
|
|
+ long blockSize,
|
|
|
+ long offsetIntoBlock, long chunkSizeToView,
|
|
|
+ JspWriter out,
|
|
|
+ Configuration conf)
|
|
|
throws IOException {
|
|
|
if (chunkSizeToView == 0) return;
|
|
|
Socket s = new Socket();
|
|
@@ -332,7 +345,10 @@ public class JspHelper {
|
|
|
Collections.sort(nodes, new NodeComapare(field, order));
|
|
|
}
|
|
|
|
|
|
- public static void printPathWithLinks(String dir, JspWriter out, int namenodeInfoPort ) throws IOException {
|
|
|
+ public static void printPathWithLinks(String dir, JspWriter out,
|
|
|
+ int namenodeInfoPort,
|
|
|
+ String tokenString
|
|
|
+ ) throws IOException {
|
|
|
try {
|
|
|
String[] parts = dir.split(Path.SEPARATOR);
|
|
|
StringBuilder tempPath = new StringBuilder(dir.length());
|
|
@@ -344,7 +360,8 @@ public class JspHelper {
|
|
|
if (!parts[i].equals("")) {
|
|
|
tempPath.append(parts[i]);
|
|
|
out.print("<a href=\"browseDirectory.jsp" + "?dir="
|
|
|
- + tempPath.toString() + "&namenodeInfoPort=" + namenodeInfoPort);
|
|
|
+ + tempPath.toString() + "&namenodeInfoPort=" + namenodeInfoPort
|
|
|
+ + SET_DELEGATION + tokenString);
|
|
|
out.print("\">" + parts[i] + "</a>" + Path.SEPARATOR);
|
|
|
tempPath.append(Path.SEPARATOR);
|
|
|
}
|
|
@@ -358,22 +375,113 @@ public class JspHelper {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public static void printGotoForm(JspWriter out, int namenodeInfoPort, String file) throws IOException {
|
|
|
+ public static void printGotoForm(JspWriter out,
|
|
|
+ int namenodeInfoPort,
|
|
|
+ String tokenString,
|
|
|
+ String file) throws IOException {
|
|
|
out.print("<form action=\"browseDirectory.jsp\" method=\"get\" name=\"goto\">");
|
|
|
out.print("Goto : ");
|
|
|
out.print("<input name=\"dir\" type=\"text\" width=\"50\" id\"dir\" value=\""+ file+"\">");
|
|
|
out.print("<input name=\"go\" type=\"submit\" value=\"go\">");
|
|
|
out.print("<input name=\"namenodeInfoPort\" type=\"hidden\" "
|
|
|
+ "value=\"" + namenodeInfoPort + "\">");
|
|
|
+ out.print("<input name=\"" + DELEGATION_PARAMETER_NAME +
|
|
|
+ "\" type=\"hidden\" value=\"" + tokenString + "\">");
|
|
|
out.print("</form>");
|
|
|
}
|
|
|
|
|
|
public static void createTitle(JspWriter out,
|
|
|
- HttpServletRequest req, String file) throws IOException{
|
|
|
+ HttpServletRequest req,
|
|
|
+ String file) throws IOException{
|
|
|
if(file == null) file = "";
|
|
|
int start = Math.max(0,file.length() - 100);
|
|
|
if(start != 0)
|
|
|
file = "..." + file.substring(start, file.length());
|
|
|
out.print("<title>HDFS:" + file + "</title>");
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * If security is turned off, what is the default web user?
|
|
|
+ * @param conf the configuration to look in
|
|
|
+ * @return the remote user that was configuration
|
|
|
+ */
|
|
|
+ public static UserGroupInformation getDefaultWebUser(Configuration conf
|
|
|
+ ) throws IOException {
|
|
|
+ String[] strings = conf.getStrings(JspHelper.WEB_UGI_PROPERTY_NAME);
|
|
|
+ if (strings == null || strings.length == 0) {
|
|
|
+ throw new IOException("Cannot determine UGI from request or conf");
|
|
|
+ }
|
|
|
+ return UserGroupInformation.createRemoteUser(strings[0]);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Get {@link UserGroupInformation} and possibly the delegation token out of
|
|
|
+ * the request.
|
|
|
+ * @param request the http request
|
|
|
+ * @return a new user from the request
|
|
|
+ * @throws AccessControlException if the request has no token
|
|
|
+ */
|
|
|
+ public static UserGroupInformation getUGI(HttpServletRequest request,
|
|
|
+ Configuration conf
|
|
|
+ ) throws IOException {
|
|
|
+ UserGroupInformation ugi = null;
|
|
|
+ if(UserGroupInformation.isSecurityEnabled()) {
|
|
|
+ String user = request.getRemoteUser();
|
|
|
+ String tokenString = request.getParameter(DELEGATION_PARAMETER_NAME);
|
|
|
+ if (tokenString != null) {
|
|
|
+ Token<DelegationTokenIdentifier> token =
|
|
|
+ new Token<DelegationTokenIdentifier>();
|
|
|
+ token.decodeFromUrlString(tokenString);
|
|
|
+ ugi = UserGroupInformation.createRemoteUser(user);
|
|
|
+ ugi.addToken(token);
|
|
|
+ } else {
|
|
|
+ if(user == null) {
|
|
|
+ throw new IOException("Security enabled but user not " +
|
|
|
+ "authenticated by filter");
|
|
|
+ }
|
|
|
+ ugi = UserGroupInformation.createRemoteUser(user);
|
|
|
+ }
|
|
|
+ } else { // Security's not on, pull from url
|
|
|
+ String user = request.getParameter("ugi");
|
|
|
+
|
|
|
+ if(user == null) { // not specified in request
|
|
|
+ ugi = getDefaultWebUser(conf);
|
|
|
+ } else {
|
|
|
+ ugi = UserGroupInformation.createRemoteUser(user);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(LOG.isDebugEnabled())
|
|
|
+ LOG.debug("getUGI is returning: " + ugi.getShortUserName());
|
|
|
+ return ugi;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static DFSClient getDFSClient(final UserGroupInformation user,
|
|
|
+ final InetSocketAddress addr,
|
|
|
+ final Configuration conf
|
|
|
+ ) throws IOException,
|
|
|
+ InterruptedException {
|
|
|
+ return
|
|
|
+ user.doAs(new PrivilegedExceptionAction<DFSClient>() {
|
|
|
+ public DFSClient run() throws IOException {
|
|
|
+ return new DFSClient(addr, conf);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /** Convert a String to chunk-size-to-view. */
|
|
|
+ public static int string2ChunkSizeToView(String s, int defaultValue) {
|
|
|
+ int n = s == null? 0: Integer.parseInt(s);
|
|
|
+ return n > 0? n: defaultValue;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Get the default chunk size.
|
|
|
+ * @param conf the configuration
|
|
|
+ * @return the number of bytes to chunk in
|
|
|
+ */
|
|
|
+ public static int getDefaultChunkSize(Configuration conf) {
|
|
|
+ return conf.getInt("dfs.default.chunk.view.size", 32 * 1024);
|
|
|
+ }
|
|
|
}
|