HDFS-4564. Ensure webhdfs returns correct HTTP response codes for denied operations. Contributed by Daryn Sharp.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1583241 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Arun Murthy 2014-03-31 07:25:53 +00:00
parent 3532d96ff6
commit 004d0854b7
5 changed files with 27 additions and 34 deletions

View File

@ -349,7 +349,7 @@ public void testDelegationTokenOperations() throws Exception {
url = new URL(TestJettyHelper.getJettyURL(), url = new URL(TestJettyHelper.getJettyURL(),
"/webhdfs/v1/?op=GETHOMEDIRECTORY&delegation=" + tokenStr); "/webhdfs/v1/?op=GETHOMEDIRECTORY&delegation=" + tokenStr);
conn = (HttpURLConnection) url.openConnection(); conn = (HttpURLConnection) url.openConnection();
Assert.assertEquals(HttpURLConnection.HTTP_UNAUTHORIZED, Assert.assertEquals(HttpURLConnection.HTTP_FORBIDDEN,
conn.getResponseCode()); conn.getResponseCode());
} }

View File

@ -1050,6 +1050,9 @@ BREAKDOWN OF HDFS-5535 ROLLING UPGRADE SUBTASKS AND RELATED JIRAS
HDFS-6038. Allow JournalNode to handle editlog produced by new release with HDFS-6038. Allow JournalNode to handle editlog produced by new release with
future layoutversion. (jing9) future layoutversion. (jing9)
HDFS-4564. Ensure webhdfs returns correct HTTP response codes for denied
operations. (daryn via acmurthy)
Release 2.3.1 - UNRELEASED Release 2.3.1 - UNRELEASED
INCOMPATIBLE CHANGES INCOMPATIBLE CHANGES

View File

@ -304,6 +304,11 @@ private Path makeAbsolute(Path f) {
private static Map<?, ?> validateResponse(final HttpOpParam.Op op, private static Map<?, ?> validateResponse(final HttpOpParam.Op op,
final HttpURLConnection conn, boolean unwrapException) throws IOException { final HttpURLConnection conn, boolean unwrapException) throws IOException {
final int code = conn.getResponseCode(); final int code = conn.getResponseCode();
// server is demanding an authentication we don't support
if (code == HttpURLConnection.HTTP_UNAUTHORIZED) {
throw new IOException(
new AuthenticationException(conn.getResponseMessage()));
}
if (code != op.getExpectedHttpResponseCode()) { if (code != op.getExpectedHttpResponseCode()) {
final Map<?, ?> m; final Map<?, ?> m;
try { try {
@ -450,52 +455,33 @@ protected AbstractRunner(final HttpOpParam.Op op, boolean redirected) {
this.redirected = redirected; this.redirected = redirected;
} }
private HttpURLConnection getHttpUrlConnection(final URL url) AbstractRunner run() throws IOException {
throws IOException, AuthenticationException {
UserGroupInformation connectUgi = ugi.getRealUser(); UserGroupInformation connectUgi = ugi.getRealUser();
if (connectUgi == null) { if (connectUgi == null) {
connectUgi = ugi; connectUgi = ugi;
} }
if (op.getRequireAuth()) {
connectUgi.checkTGTAndReloginFromKeytab();
}
try { try {
// the entire lifecycle of the connection must be run inside the
// doAs to ensure authentication is performed correctly
return connectUgi.doAs( return connectUgi.doAs(
new PrivilegedExceptionAction<HttpURLConnection>() { new PrivilegedExceptionAction<AbstractRunner>() {
@Override @Override
public HttpURLConnection run() throws IOException { public AbstractRunner run() throws IOException {
return openHttpUrlConnection(url); return runWithRetry();
} }
}); });
} catch (IOException ioe) {
Throwable cause = ioe.getCause();
if (cause != null && cause instanceof AuthenticationException) {
throw (AuthenticationException)cause;
}
throw ioe;
} catch (InterruptedException e) { } catch (InterruptedException e) {
throw new IOException(e); throw new IOException(e);
} }
} }
private HttpURLConnection openHttpUrlConnection(final URL url)
throws IOException {
final HttpURLConnection conn;
try {
conn = (HttpURLConnection) connectionFactory.openConnection(url,
op.getRequireAuth());
} catch (AuthenticationException e) {
throw new IOException(e);
}
return conn;
}
private void init() throws IOException { private void init() throws IOException {
checkRetry = !redirected; checkRetry = !redirected;
URL url = getUrl(); URL url = getUrl();
try { conn = (HttpURLConnection) connectionFactory.openConnection(url);
conn = getHttpUrlConnection(url);
} catch(AuthenticationException ae) {
checkRetry = false;
throw new IOException("Authentication failed, url=" + url, ae);
}
} }
private void connect() throws IOException { private void connect() throws IOException {
@ -516,7 +502,7 @@ private void disconnect() {
} }
} }
AbstractRunner run() throws IOException { private AbstractRunner runWithRetry() throws IOException {
/** /**
* Do the real work. * Do the real work.
* *
@ -543,6 +529,10 @@ AbstractRunner run() throws IOException {
} }
return this; return this;
} catch(IOException ioe) { } catch(IOException ioe) {
Throwable cause = ioe.getCause();
if (cause != null && cause instanceof AuthenticationException) {
throw ioe; // no retries for auth failures
}
shouldRetry(ioe, retry); shouldRetry(ioe, retry);
} }
} }

View File

@ -77,9 +77,9 @@ public Response toResponse(Exception e) {
//Map response status //Map response status
final Response.Status s; final Response.Status s;
if (e instanceof SecurityException) { if (e instanceof SecurityException) {
s = Response.Status.UNAUTHORIZED; s = Response.Status.FORBIDDEN;
} else if (e instanceof AuthorizationException) { } else if (e instanceof AuthorizationException) {
s = Response.Status.UNAUTHORIZED; s = Response.Status.FORBIDDEN;
} else if (e instanceof FileNotFoundException) { } else if (e instanceof FileNotFoundException) {
s = Response.Status.NOT_FOUND; s = Response.Status.NOT_FOUND;
} else if (e instanceof IOException) { } else if (e instanceof IOException) {

View File

@ -410,7 +410,7 @@ public void testResponseCode() throws IOException {
new DoAsParam(ugi.getShortUserName() + "proxy")); new DoAsParam(ugi.getShortUserName() + "proxy"));
final HttpURLConnection conn = (HttpURLConnection) url.openConnection(); final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.connect(); conn.connect();
assertEquals(HttpServletResponse.SC_UNAUTHORIZED, conn.getResponseCode()); assertEquals(HttpServletResponse.SC_FORBIDDEN, conn.getResponseCode());
conn.disconnect(); conn.disconnect();
} }