Merge -r 1370044:1370045 from trunk to branch. FIXES: HADOOP-8644

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1370050 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Alejandro Abdelnur 2012-08-06 22:39:15 +00:00
parent 7f92566e21
commit 80f8a6f8a3
10 changed files with 170 additions and 2 deletions

View File

@ -171,6 +171,7 @@ public class AuthenticatedURL {
}
private Authenticator authenticator;
private ConnectionConfigurator connConfigurator;
/**
* Creates an {@link AuthenticatedURL}.
@ -186,11 +187,25 @@ public class AuthenticatedURL {
* KerberosAuthenticator} is used.
*/
public AuthenticatedURL(Authenticator authenticator) {
this(authenticator, null);
}
/**
* Creates an <code>AuthenticatedURL</code>.
*
* @param authenticator the {@link Authenticator} instance to use, if <code>null</code> a {@link
* KerberosAuthenticator} is used.
* @param connConfigurator a connection configurator.
*/
public AuthenticatedURL(Authenticator authenticator,
ConnectionConfigurator connConfigurator) {
try {
this.authenticator = (authenticator != null) ? authenticator : DEFAULT_AUTHENTICATOR.newInstance();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
this.connConfigurator = connConfigurator;
this.authenticator.setConnectionConfigurator(connConfigurator);
}
/**
@ -216,6 +231,9 @@ public class AuthenticatedURL {
}
authenticator.authenticate(url, token);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
if (connConfigurator != null) {
conn = connConfigurator.configure(conn);
}
injectToken(conn, token);
return conn;
}

View File

@ -24,6 +24,14 @@ import java.net.URL;
*/
public interface Authenticator {
/**
* Sets a {@link ConnectionConfigurator} instance to use for
* configuring connections.
*
* @param configurator the {@link ConnectionConfigurator} instance.
*/
public void setConnectionConfigurator(ConnectionConfigurator configurator);
/**
* Authenticates against a URL and returns a {@link AuthenticatedURL.Token} to be
* used by subsequent requests.

View File

@ -0,0 +1,36 @@
/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License. See accompanying LICENSE file.
*/
package org.apache.hadoop.security.authentication.client;
import java.io.IOException;
import java.net.HttpURLConnection;
/**
* Interface to configure {@link HttpURLConnection} created by
* {@link AuthenticatedURL} instances.
*/
public interface ConnectionConfigurator {
/**
* Configures the given {@link HttpURLConnection} instance.
*
* @param conn the {@link HttpURLConnection} instance to configure.
* @return the configured {@link HttpURLConnection} instance.
*
* @throws IOException if an IO error occurred.
*/
public HttpURLConnection configure(HttpURLConnection conn) throws IOException;
}

View File

@ -113,6 +113,18 @@ public class KerberosAuthenticator implements Authenticator {
private URL url;
private HttpURLConnection conn;
private Base64 base64;
private ConnectionConfigurator connConfigurator;
/**
* Sets a {@link ConnectionConfigurator} instance to use for
* configuring connections.
*
* @param configurator the {@link ConnectionConfigurator} instance.
*/
@Override
public void setConnectionConfigurator(ConnectionConfigurator configurator) {
connConfigurator = configurator;
}
/**
* Performs SPNEGO authentication against the specified URL.
@ -135,6 +147,9 @@ public class KerberosAuthenticator implements Authenticator {
this.url = url;
base64 = new Base64(0);
conn = (HttpURLConnection) url.openConnection();
if (connConfigurator != null) {
conn = connConfigurator.configure(conn);
}
conn.setRequestMethod(AUTH_HTTP_METHOD);
conn.connect();
if (isNegotiate()) {
@ -244,6 +259,9 @@ public class KerberosAuthenticator implements Authenticator {
private void sendToken(byte[] outToken) throws IOException, AuthenticationException {
String token = base64.encodeToString(outToken);
conn = (HttpURLConnection) url.openConnection();
if (connConfigurator != null) {
conn = connConfigurator.configure(conn);
}
conn.setRequestMethod(AUTH_HTTP_METHOD);
conn.setRequestProperty(AUTHORIZATION, NEGOTIATE + " " + token);
conn.connect();

View File

@ -32,6 +32,19 @@ public class PseudoAuthenticator implements Authenticator {
private static final String USER_NAME_EQ = USER_NAME + "=";
private ConnectionConfigurator connConfigurator;
/**
* Sets a {@link ConnectionConfigurator} instance to use for
* configuring connections.
*
* @param configurator the {@link ConnectionConfigurator} instance.
*/
@Override
public void setConnectionConfigurator(ConnectionConfigurator configurator) {
connConfigurator = configurator;
}
/**
* Performs simple authentication against the specified URL.
* <p/>
@ -56,6 +69,9 @@ public class PseudoAuthenticator implements Authenticator {
strUrl += paramSeparator + USER_NAME_EQ + getUserName();
url = new URL(strUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
if (connConfigurator != null) {
conn = connConfigurator.configure(conn);
}
conn.setRequestMethod("OPTIONS");
conn.connect();
AuthenticatedURL.extractToken(conn, token);

View File

@ -15,6 +15,7 @@ package org.apache.hadoop.security.authentication.client;
import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
import junit.framework.TestCase;
import org.mockito.Mockito;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.FilterHolder;
@ -120,8 +121,11 @@ public abstract class AuthenticatorTestCase extends TestCase {
try {
URL url = new URL(getBaseURL());
AuthenticatedURL.Token token = new AuthenticatedURL.Token();
AuthenticatedURL aUrl = new AuthenticatedURL(authenticator);
ConnectionConfigurator connConf =
Mockito.mock(ConnectionConfigurator.class);
AuthenticatedURL aUrl = new AuthenticatedURL(authenticator, connConf);
HttpURLConnection conn = aUrl.openConnection(url, token);
Mockito.verify(connConf).configure(Mockito.<HttpURLConnection>any());
String tokenStr = token.toString();
if (doPost) {
conn.setRequestMethod("POST");

View File

@ -18,6 +18,7 @@ import junit.framework.TestCase;
import org.mockito.Mockito;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -114,4 +115,21 @@ public class TestAuthenticatedURL extends TestCase {
}
}
public void testConnectionConfigurator() throws Exception {
HttpURLConnection conn = Mockito.mock(HttpURLConnection.class);
Mockito.when(conn.getResponseCode()).
thenReturn(HttpURLConnection.HTTP_UNAUTHORIZED);
ConnectionConfigurator connConf =
Mockito.mock(ConnectionConfigurator.class);
Mockito.when(connConf.configure(Mockito.<HttpURLConnection>any())).
thenReturn(conn);
Authenticator authenticator = Mockito.mock(Authenticator.class);
AuthenticatedURL aURL = new AuthenticatedURL(authenticator, connConf);
aURL.openConnection(new URL("http://foo"), new AuthenticatedURL.Token());
Mockito.verify(connConf).configure(Mockito.<HttpURLConnection>any());
}
}

View File

@ -20,6 +20,8 @@ Release 2.0.1-alpha - UNRELEASED
HADOOP-8465. hadoop-auth should support ephemeral authentication (tucu)
HADOOP-8644. AuthenticatedURL should be able to use SSLFactory. (tucu)
IMPROVEMENTS
HADOOP-8340. SNAPSHOT build versions should compare as less than their eventual

View File

@ -20,14 +20,17 @@ package org.apache.hadoop.security.ssl;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.security.authentication.client.ConnectionConfigurator;
import org.apache.hadoop.util.ReflectionUtils;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocketFactory;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.security.GeneralSecurityException;
/**
@ -42,7 +45,7 @@ import java.security.GeneralSecurityException;
*/
@InterfaceAudience.Private
@InterfaceStability.Evolving
public class SSLFactory {
public class SSLFactory implements ConnectionConfigurator {
@InterfaceAudience.Private
public static enum Mode { CLIENT, SERVER }
@ -234,4 +237,29 @@ public class SSLFactory {
return requireClientCert;
}
/**
* If the given {@link HttpURLConnection} is an {@link HttpsURLConnection}
* configures the connection with the {@link SSLSocketFactory} and
* {@link HostnameVerifier} of this SSLFactory, otherwise does nothing.
*
* @param conn the {@link HttpURLConnection} instance to configure.
* @return the configured {@link HttpURLConnection} instance.
*
* @throws IOException if an IO error occurred.
*/
@Override
public HttpURLConnection configure(HttpURLConnection conn)
throws IOException {
if (conn instanceof HttpsURLConnection) {
HttpsURLConnection sslConn = (HttpsURLConnection) conn;
try {
sslConn.setSSLSocketFactory(createSSLSocketFactory());
} catch (GeneralSecurityException ex) {
throw new IOException(ex);
}
sslConn.setHostnameVerifier(getHostnameVerifier());
conn = sslConn;
}
return conn;
}
}

View File

@ -25,6 +25,7 @@ import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import javax.net.ssl.HttpsURLConnection;
import java.io.File;
import java.net.URL;
import java.security.GeneralSecurityException;
@ -161,4 +162,23 @@ public class TestSSLFactory {
}
}
@Test
public void testConnectionConfigurator() throws Exception {
Configuration conf = createConfiguration(false);
conf.set(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY, "STRICT_IE6");
SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf);
try {
sslFactory.init();
HttpsURLConnection sslConn =
(HttpsURLConnection) new URL("https://foo").openConnection();
Assert.assertNotSame("STRICT_IE6",
sslConn.getHostnameVerifier().toString());
sslFactory.configure(sslConn);
Assert.assertEquals("STRICT_IE6",
sslConn.getHostnameVerifier().toString());
} finally {
sslFactory.destroy();
}
}
}