Skip to content

Commit df18982

Browse files
committed
HDFS-991. Allow authentication to the web ui via a delegation token.
(omalley) git-svn-id: https://svn.apache.org/repos/asf/hadoop/hdfs/trunk@916873 13f79535-47bb-0310-9956-ffa450edef68
1 parent 12bbab7 commit df18982

File tree

20 files changed

+309
-113
lines changed

20 files changed

+309
-113
lines changed

CHANGES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ Trunk (unreleased changes)
7777

7878
HADOOP-6579. Upgrade the commons-codec library to 1.4. (omalley)
7979

80+
HDFS-991. Allow authentication to the web ui via a delegation token.
81+
(omalley)
82+
8083
OPTIMIZATIONS
8184

8285
HDFS-946. NameNode should not return full path name when lisitng a

src/contrib/hdfsproxy/src/java/org/apache/hadoop/hdfsproxy/ProxyFileDataServlet.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import javax.servlet.ServletException;
2626
import javax.servlet.http.HttpServletRequest;
2727

28+
import org.apache.hadoop.conf.Configuration;
2829
import org.apache.hadoop.hdfs.protocol.ClientProtocol;
2930
import org.apache.hadoop.hdfs.protocol.HdfsFileStatus;
3031
import org.apache.hadoop.hdfs.server.namenode.FileDataServlet;
@@ -58,7 +59,8 @@ protected URI createUri(String parent, HdfsFileStatus i, UserGroupInformation ug
5859

5960
/** {@inheritDoc} */
6061
@Override
61-
protected UserGroupInformation getUGI(HttpServletRequest request) {
62+
protected UserGroupInformation getUGI(HttpServletRequest request,
63+
Configuration conf) {
6264
String userID = (String) request
6365
.getAttribute("org.apache.hadoop.hdfsproxy.authorized.userID");
6466
return UserGroupInformation.createRemoteUser(userID);

src/contrib/hdfsproxy/src/java/org/apache/hadoop/hdfsproxy/ProxyListPathsServlet.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ public void init() throws ServletException {
4242

4343
/** {@inheritDoc} */
4444
@Override
45-
protected UserGroupInformation getUGI(HttpServletRequest request) {
45+
protected UserGroupInformation getUGI(HttpServletRequest request,
46+
Configuration conf) {
4647
String userID = (String) request
4748
.getAttribute("org.apache.hadoop.hdfsproxy.authorized.userID");
4849
return UserGroupInformation.createRemoteUser(userID);

src/contrib/hdfsproxy/src/java/org/apache/hadoop/hdfsproxy/ProxyStreamFile.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ public void init() throws ServletException {
5050
protected DFSClient getDFSClient(HttpServletRequest request)
5151
throws IOException, InterruptedException {
5252
ServletContext context = getServletContext();
53-
final Configuration conf = new HdfsConfiguration((Configuration) context
54-
.getAttribute("name.conf"));
53+
final Configuration conf =
54+
(Configuration) context.getAttribute("name.conf");
5555
final InetSocketAddress nameNodeAddr = (InetSocketAddress) context
5656
.getAttribute("name.node.address");
5757

58-
DFSClient client =
59-
getUGI(request).doAs(new PrivilegedExceptionAction<DFSClient>() {
58+
DFSClient client = getUGI(request, conf).doAs
59+
( new PrivilegedExceptionAction<DFSClient>() {
6060
@Override
6161
public DFSClient run() throws IOException {
6262
return new DFSClient(nameNodeAddr, conf);
@@ -68,7 +68,8 @@ public DFSClient run() throws IOException {
6868

6969
/** {@inheritDoc} */
7070
@Override
71-
protected UserGroupInformation getUGI(HttpServletRequest request) {
71+
protected UserGroupInformation getUGI(HttpServletRequest request,
72+
Configuration conf) {
7273
String userID = (String) request
7374
.getAttribute("org.apache.hadoop.hdfsproxy.authorized.userID");
7475

src/java/org/apache/hadoop/hdfs/server/common/JspHelper.java

Lines changed: 93 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,24 +33,33 @@
3333
import javax.servlet.http.HttpServletRequest;
3434
import javax.servlet.jsp.JspWriter;
3535

36+
import org.apache.commons.logging.Log;
37+
import org.apache.commons.logging.LogFactory;
38+
import org.apache.hadoop.classification.InterfaceAudience;
3639
import org.apache.hadoop.conf.Configuration;
3740
import org.apache.hadoop.fs.Path;
3841
import org.apache.hadoop.hdfs.BlockReader;
39-
import org.apache.hadoop.hdfs.HdfsConfiguration;
4042
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
4143
import org.apache.hadoop.hdfs.protocol.LocatedBlock;
4244
import org.apache.hadoop.hdfs.security.BlockAccessToken;
45+
import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier;
46+
import org.apache.hadoop.hdfs.server.datanode.DatanodeJspHelper;
4347
import org.apache.hadoop.hdfs.server.namenode.DatanodeDescriptor;
48+
import org.apache.hadoop.io.WritableUtils;
4449
import org.apache.hadoop.net.NetUtils;
50+
import org.apache.hadoop.security.AccessControlException;
51+
import org.apache.hadoop.security.UserGroupInformation;
52+
import org.apache.hadoop.security.token.Token;
4553
import org.apache.hadoop.util.VersionInfo;
4654

55+
@InterfaceAudience.Private
4756
public class JspHelper {
4857
final static public String WEB_UGI_PROPERTY_NAME = "dfs.web.ugi";
58+
public static final String DELEGATION_PARAMETER_NAME = "delegation";
59+
public static final String SET_DELEGATION = "&" + DELEGATION_PARAMETER_NAME +
60+
"=";
61+
private static final Log LOG = LogFactory.getLog(JspHelper.class);
4962

50-
public static final Configuration conf = new HdfsConfiguration();
51-
52-
private static final int defaultChunkSizeToView =
53-
conf.getInt("dfs.default.chunk.view.size", 32 * 1024);
5463
static final Random rand = new Random();
5564

5665
/** Private constructor for preventing creating JspHelper object. */
@@ -97,8 +106,11 @@ public static DatanodeInfo bestNode(LocatedBlock blk) throws IOException {
97106
}
98107

99108
public static void streamBlockInAscii(InetSocketAddress addr, long blockId,
100-
BlockAccessToken accessToken, long genStamp, long blockSize,
101-
long offsetIntoBlock, long chunkSizeToView, JspWriter out)
109+
BlockAccessToken accessToken, long genStamp,
110+
long blockSize,
111+
long offsetIntoBlock, long chunkSizeToView,
112+
JspWriter out,
113+
Configuration conf)
102114
throws IOException {
103115
if (chunkSizeToView == 0) return;
104116
Socket s = new Socket();
@@ -261,7 +273,10 @@ public int compare(DatanodeDescriptor d1,
261273
Collections.sort(nodes, new NodeComapare(field, order));
262274
}
263275

264-
public static void printPathWithLinks(String dir, JspWriter out, int namenodeInfoPort ) throws IOException {
276+
public static void printPathWithLinks(String dir, JspWriter out,
277+
int namenodeInfoPort,
278+
String tokenString
279+
) throws IOException {
265280
try {
266281
String[] parts = dir.split(Path.SEPARATOR);
267282
StringBuilder tempPath = new StringBuilder(dir.length());
@@ -273,7 +288,8 @@ public static void printPathWithLinks(String dir, JspWriter out, int namenodeInf
273288
if (!parts[i].equals("")) {
274289
tempPath.append(parts[i]);
275290
out.print("<a href=\"browseDirectory.jsp" + "?dir="
276-
+ tempPath.toString() + "&namenodeInfoPort=" + namenodeInfoPort);
291+
+ tempPath.toString() + "&namenodeInfoPort=" + namenodeInfoPort
292+
+ SET_DELEGATION + tokenString);
277293
out.print("\">" + parts[i] + "</a>" + Path.SEPARATOR);
278294
tempPath.append(Path.SEPARATOR);
279295
}
@@ -287,18 +303,24 @@ public static void printPathWithLinks(String dir, JspWriter out, int namenodeInf
287303
}
288304
}
289305

290-
public static void printGotoForm(JspWriter out, int namenodeInfoPort, String file) throws IOException {
306+
public static void printGotoForm(JspWriter out,
307+
int namenodeInfoPort,
308+
String tokenString,
309+
String file) throws IOException {
291310
out.print("<form action=\"browseDirectory.jsp\" method=\"get\" name=\"goto\">");
292311
out.print("Goto : ");
293312
out.print("<input name=\"dir\" type=\"text\" width=\"50\" id\"dir\" value=\""+ file+"\">");
294313
out.print("<input name=\"go\" type=\"submit\" value=\"go\">");
295314
out.print("<input name=\"namenodeInfoPort\" type=\"hidden\" "
296315
+ "value=\"" + namenodeInfoPort + "\">");
316+
out.print("<input name=\"" + DELEGATION_PARAMETER_NAME +
317+
"\" type=\"hidden\" value=\"" + tokenString + "\">");
297318
out.print("</form>");
298319
}
299320

300321
public static void createTitle(JspWriter out,
301-
HttpServletRequest req, String file) throws IOException{
322+
HttpServletRequest req,
323+
String file) throws IOException{
302324
if(file == null) file = "";
303325
int start = Math.max(0,file.length() - 100);
304326
if(start != 0)
@@ -307,9 +329,9 @@ public static void createTitle(JspWriter out,
307329
}
308330

309331
/** Convert a String to chunk-size-to-view. */
310-
public static int string2ChunkSizeToView(String s) {
332+
public static int string2ChunkSizeToView(String s, int defaultValue) {
311333
int n = s == null? 0: Integer.parseInt(s);
312-
return n > 0? n: defaultChunkSizeToView;
334+
return n > 0? n: defaultValue;
313335
}
314336

315337
/** Return a table containing version information. */
@@ -351,4 +373,62 @@ public static String validateURL(String value) {
351373
return null;
352374
}
353375
}
376+
377+
/**
378+
* If security is turned off, what is the default web user?
379+
* @param conf the configuration to look in
380+
* @return the remote user that was configuration
381+
*/
382+
public static UserGroupInformation getDefaultWebUser(Configuration conf
383+
) throws IOException {
384+
String[] strings = conf.getStrings(JspHelper.WEB_UGI_PROPERTY_NAME);
385+
if (strings == null || strings.length == 0) {
386+
throw new IOException("Cannot determine UGI from request or conf");
387+
}
388+
return UserGroupInformation.createRemoteUser(strings[0]);
389+
}
390+
391+
/**
392+
* Get {@link UserGroupInformation} and possibly the delegation token out of
393+
* the request.
394+
* @param request the http request
395+
* @return a new user from the request
396+
* @throws AccessControlException if the request has no token
397+
*/
398+
public static UserGroupInformation getUGI(HttpServletRequest request,
399+
Configuration conf
400+
) throws IOException {
401+
UserGroupInformation ugi = null;
402+
if(UserGroupInformation.isSecurityEnabled()) {
403+
String user = request.getRemoteUser();
404+
String tokenString = request.getParameter(DELEGATION_PARAMETER_NAME);
405+
if (tokenString != null) {
406+
Token<DelegationTokenIdentifier> token =
407+
new Token<DelegationTokenIdentifier>();
408+
token.decodeFromUrlString(tokenString);
409+
ugi = UserGroupInformation.createRemoteUser(user);
410+
ugi.addToken(token);
411+
} else {
412+
if(user == null) {
413+
throw new IOException("Security enabled but user not " +
414+
"authenticated by filter");
415+
}
416+
ugi = UserGroupInformation.createRemoteUser(user);
417+
}
418+
} else { // Security's not on, pull from url
419+
String user = request.getParameter("ugi");
420+
421+
if(user == null) { // not specified in request
422+
ugi = getDefaultWebUser(conf);
423+
} else {
424+
ugi = UserGroupInformation.createRemoteUser(user);
425+
}
426+
}
427+
428+
if(LOG.isDebugEnabled())
429+
LOG.debug("getUGI is returning: " + ugi.getShortUserName());
430+
return ugi;
431+
}
432+
433+
354434
}

src/java/org/apache/hadoop/hdfs/server/datanode/DataNode.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,7 @@ void startDataNode(Configuration conf,
387387
this.infoServer.addInternalServlet(null, "/getFileChecksum/*",
388388
FileChecksumServlets.GetServlet.class);
389389
this.infoServer.setAttribute("datanode.blockScanner", blockScanner);
390+
this.infoServer.setAttribute("datanode.conf", conf);
390391
this.infoServer.addServlet(null, "/blockScannerReport",
391392
DataBlockScanner.Servlet.class);
392393
this.infoServer.start();

0 commit comments

Comments
 (0)