HADOOP-12897. KerberosAuthenticator.authenticate to include URL on IO failures. Contributed by Ajay Kumar.
This commit is contained in:
parent
324e5a7cf2
commit
b0d3c877e3
@ -13,6 +13,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.hadoop.security.authentication.client;
|
package org.apache.hadoop.security.authentication.client;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.apache.hadoop.security.authentication.server.HttpConstants;
|
import org.apache.hadoop.security.authentication.server.HttpConstants;
|
||||||
import org.apache.hadoop.security.authentication.util.AuthToken;
|
import org.apache.hadoop.security.authentication.util.AuthToken;
|
||||||
@ -177,41 +179,65 @@ public void setConnectionConfigurator(ConnectionConfigurator configurator) {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void authenticate(URL url, AuthenticatedURL.Token token)
|
public void authenticate(URL url, AuthenticatedURL.Token token)
|
||||||
throws IOException, AuthenticationException {
|
throws IOException, AuthenticationException {
|
||||||
if (!token.isSet()) {
|
if (!token.isSet()) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
base64 = new Base64(0);
|
base64 = new Base64(0);
|
||||||
HttpURLConnection conn = token.openConnection(url, connConfigurator);
|
try {
|
||||||
conn.setRequestMethod(AUTH_HTTP_METHOD);
|
HttpURLConnection conn = token.openConnection(url, connConfigurator);
|
||||||
conn.connect();
|
conn.setRequestMethod(AUTH_HTTP_METHOD);
|
||||||
|
conn.connect();
|
||||||
boolean needFallback = false;
|
|
||||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
boolean needFallback = false;
|
||||||
LOG.debug("JDK performed authentication on our behalf.");
|
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||||
// If the JDK already did the SPNEGO back-and-forth for
|
LOG.debug("JDK performed authentication on our behalf.");
|
||||||
// us, just pull out the token.
|
// If the JDK already did the SPNEGO back-and-forth for
|
||||||
AuthenticatedURL.extractToken(conn, token);
|
// us, just pull out the token.
|
||||||
if (isTokenKerberos(token)) {
|
AuthenticatedURL.extractToken(conn, token);
|
||||||
return;
|
if (isTokenKerberos(token)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
needFallback = true;
|
||||||
}
|
}
|
||||||
needFallback = true;
|
if (!needFallback && isNegotiate(conn)) {
|
||||||
}
|
LOG.debug("Performing our own SPNEGO sequence.");
|
||||||
if (!needFallback && isNegotiate(conn)) {
|
doSpnegoSequence(token);
|
||||||
LOG.debug("Performing our own SPNEGO sequence.");
|
} else {
|
||||||
doSpnegoSequence(token);
|
LOG.debug("Using fallback authenticator sequence.");
|
||||||
} else {
|
Authenticator auth = getFallBackAuthenticator();
|
||||||
LOG.debug("Using fallback authenticator sequence.");
|
// Make sure that the fall back authenticator have the same
|
||||||
Authenticator auth = getFallBackAuthenticator();
|
// ConnectionConfigurator, since the method might be overridden.
|
||||||
// Make sure that the fall back authenticator have the same
|
// Otherwise the fall back authenticator might not have the
|
||||||
// ConnectionConfigurator, since the method might be overridden.
|
// information to make the connection (e.g., SSL certificates)
|
||||||
// Otherwise the fall back authenticator might not have the information
|
auth.setConnectionConfigurator(connConfigurator);
|
||||||
// to make the connection (e.g., SSL certificates)
|
auth.authenticate(url, token);
|
||||||
auth.setConnectionConfigurator(connConfigurator);
|
}
|
||||||
auth.authenticate(url, token);
|
} catch (IOException ex){
|
||||||
|
throw wrapExceptionWithMessage(ex,
|
||||||
|
"Error while authenticating with endpoint: " + url);
|
||||||
|
} catch (AuthenticationException ex){
|
||||||
|
throw wrapExceptionWithMessage(ex,
|
||||||
|
"Error while authenticating with endpoint: " + url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static <T extends Exception> T wrapExceptionWithMessage(
|
||||||
|
T exception, String msg) {
|
||||||
|
Class<? extends Throwable> exceptionClass = exception.getClass();
|
||||||
|
try {
|
||||||
|
Constructor<? extends Throwable> ctor = exceptionClass
|
||||||
|
.getConstructor(String.class);
|
||||||
|
Throwable t = ctor.newInstance(msg);
|
||||||
|
return (T) (t.initCause(exception));
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LOG.debug("Unable to wrap exception of type {}, it has "
|
||||||
|
+ "no (String) constructor.", exceptionClass, e);
|
||||||
|
return exception;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the specified URL does not support SPNEGO authentication, a fallback {@link Authenticator} will be used.
|
* If the specified URL does not support SPNEGO authentication, a fallback {@link Authenticator} will be used.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
import static org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler.KEYTAB;
|
import static org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler.KEYTAB;
|
||||||
import static org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler.NAME_RULES;
|
import static org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler.NAME_RULES;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.CharacterCodingException;
|
||||||
|
import javax.security.sasl.AuthenticationException;
|
||||||
import org.apache.hadoop.minikdc.KerberosSecurityTestcase;
|
import org.apache.hadoop.minikdc.KerberosSecurityTestcase;
|
||||||
import org.apache.hadoop.security.authentication.KerberosTestUtils;
|
import org.apache.hadoop.security.authentication.KerberosTestUtils;
|
||||||
import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
|
import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
|
||||||
@ -218,4 +221,30 @@ public Void call() throws Exception {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 60000)
|
||||||
|
public void testWrapExceptionWithMessage() {
|
||||||
|
IOException ex;
|
||||||
|
ex = new IOException("Induced exception");
|
||||||
|
ex = KerberosAuthenticator.wrapExceptionWithMessage(ex, "Error while "
|
||||||
|
+ "authenticating with endpoint: localhost");
|
||||||
|
Assert.assertEquals("Induced exception", ex.getCause().getMessage());
|
||||||
|
Assert.assertEquals("Error while authenticating with endpoint: localhost",
|
||||||
|
ex.getMessage());
|
||||||
|
|
||||||
|
ex = new AuthenticationException("Auth exception");
|
||||||
|
ex = KerberosAuthenticator.wrapExceptionWithMessage(ex, "Error while "
|
||||||
|
+ "authenticating with endpoint: localhost");
|
||||||
|
Assert.assertEquals("Auth exception", ex.getCause().getMessage());
|
||||||
|
Assert.assertEquals("Error while authenticating with endpoint: localhost",
|
||||||
|
ex.getMessage());
|
||||||
|
|
||||||
|
// Test for Exception with no (String) constructor
|
||||||
|
// redirect the LOG to and check log message
|
||||||
|
ex = new CharacterCodingException();
|
||||||
|
Exception ex2 = KerberosAuthenticator.wrapExceptionWithMessage(ex,
|
||||||
|
"Error while authenticating with endpoint: localhost");
|
||||||
|
Assert.assertTrue(ex instanceof CharacterCodingException);
|
||||||
|
Assert.assertTrue(ex.equals(ex2));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -383,8 +383,9 @@ public Void run() throws Exception {
|
|||||||
Assert.fail("should fail with no credentials");
|
Assert.fail("should fail with no credentials");
|
||||||
} catch (AuthenticationException ae) {
|
} catch (AuthenticationException ae) {
|
||||||
Assert.assertNotNull(ae.getCause());
|
Assert.assertNotNull(ae.getCause());
|
||||||
Assert.assertEquals(GSSException.class, ae.getCause().getClass());
|
Assert.assertEquals(GSSException.class,
|
||||||
GSSException gsse = (GSSException)ae.getCause();
|
ae.getCause().getCause().getClass());
|
||||||
|
GSSException gsse = (GSSException)ae.getCause().getCause();
|
||||||
Assert.assertEquals(GSSException.NO_CRED, gsse.getMajor());
|
Assert.assertEquals(GSSException.NO_CRED, gsse.getMajor());
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
Assert.fail("Unexpected exception" + t);
|
Assert.fail("Unexpected exception" + t);
|
||||||
|
@ -356,7 +356,10 @@ public void testLogLevelByHttp() throws Exception {
|
|||||||
fail("A HTTPS Client should not have succeeded in connecting to a " +
|
fail("A HTTPS Client should not have succeeded in connecting to a " +
|
||||||
"HTTP server");
|
"HTTP server");
|
||||||
} catch (SSLException e) {
|
} catch (SSLException e) {
|
||||||
GenericTestUtils.assertExceptionContains("Unrecognized SSL message", e);
|
GenericTestUtils.assertExceptionContains("Error while authenticating "
|
||||||
|
+ "with endpoint", e);
|
||||||
|
GenericTestUtils.assertExceptionContains("Unrecognized SSL message", e
|
||||||
|
.getCause());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,7 +377,10 @@ public void testLogLevelByHttpWithSpnego() throws Exception {
|
|||||||
fail("A HTTPS Client should not have succeeded in connecting to a " +
|
fail("A HTTPS Client should not have succeeded in connecting to a " +
|
||||||
"HTTP server");
|
"HTTP server");
|
||||||
} catch (SSLException e) {
|
} catch (SSLException e) {
|
||||||
GenericTestUtils.assertExceptionContains("Unrecognized SSL message", e);
|
GenericTestUtils.assertExceptionContains("Error while authenticating "
|
||||||
|
+ "with endpoint", e);
|
||||||
|
GenericTestUtils.assertExceptionContains("Unrecognized SSL message", e
|
||||||
|
.getCause());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,8 +399,10 @@ public void testLogLevelByHttps() throws Exception {
|
|||||||
fail("A HTTP Client should not have succeeded in connecting to a " +
|
fail("A HTTP Client should not have succeeded in connecting to a " +
|
||||||
"HTTPS server");
|
"HTTPS server");
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
|
GenericTestUtils.assertExceptionContains("Error while authenticating "
|
||||||
|
+ "with endpoint", e);
|
||||||
GenericTestUtils.assertExceptionContains(
|
GenericTestUtils.assertExceptionContains(
|
||||||
"Unexpected end of file from server", e);
|
"Unexpected end of file from server", e.getCause());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,8 +421,10 @@ public void testLogLevelByHttpsWithSpnego() throws Exception {
|
|||||||
fail("A HTTP Client should not have succeeded in connecting to a " +
|
fail("A HTTP Client should not have succeeded in connecting to a " +
|
||||||
"HTTPS server");
|
"HTTPS server");
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
|
GenericTestUtils.assertExceptionContains("Error while authenticating "
|
||||||
|
+ "with endpoint", e);
|
||||||
GenericTestUtils.assertExceptionContains(
|
GenericTestUtils.assertExceptionContains(
|
||||||
"Unexpected end of file from server", e);
|
"Unexpected end of file from server", e.getCause());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -364,7 +364,7 @@ private void testDelegationTokenAuthenticatorCalls(final boolean useQS)
|
|||||||
aUrl.getDelegationToken(nonAuthURL, token, FOO_USER);
|
aUrl.getDelegationToken(nonAuthURL, token, FOO_USER);
|
||||||
Assert.fail();
|
Assert.fail();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Assert.assertTrue(ex.getMessage().contains("401"));
|
Assert.assertTrue(ex.getCause().getMessage().contains("401"));
|
||||||
}
|
}
|
||||||
|
|
||||||
aUrl.getDelegationToken(authURL, token, FOO_USER);
|
aUrl.getDelegationToken(authURL, token, FOO_USER);
|
||||||
@ -776,7 +776,7 @@ private void testKerberosDelegationTokenAuthenticator(
|
|||||||
aUrl.getDelegationToken(url, token, FOO_USER, doAsUser);
|
aUrl.getDelegationToken(url, token, FOO_USER, doAsUser);
|
||||||
Assert.fail();
|
Assert.fail();
|
||||||
} catch (AuthenticationException ex) {
|
} catch (AuthenticationException ex) {
|
||||||
Assert.assertTrue(ex.getMessage().contains("GSSException"));
|
Assert.assertTrue(ex.getCause().getMessage().contains("GSSException"));
|
||||||
}
|
}
|
||||||
|
|
||||||
doAsKerberosUser("client", keytabFile.getAbsolutePath(),
|
doAsKerberosUser("client", keytabFile.getAbsolutePath(),
|
||||||
|
Loading…
Reference in New Issue
Block a user