Return-Path: X-Original-To: apmail-hbase-commits-archive@www.apache.org Delivered-To: apmail-hbase-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 458E618C4C for ; Fri, 15 Jan 2016 15:26:50 +0000 (UTC) Received: (qmail 5636 invoked by uid 500); 15 Jan 2016 15:26:49 -0000 Delivered-To: apmail-hbase-commits-archive@hbase.apache.org Received: (qmail 5373 invoked by uid 500); 15 Jan 2016 15:26:49 -0000 Mailing-List: contact commits-help@hbase.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@hbase.apache.org Delivered-To: mailing list commits@hbase.apache.org Received: (qmail 4188 invoked by uid 99); 15 Jan 2016 15:26:49 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 15 Jan 2016 15:26:49 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 0B3C4E08E9; Fri, 15 Jan 2016 15:26:49 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: syuanjiang@apache.org To: commits@hbase.apache.org Date: Fri, 15 Jan 2016 15:26:54 -0000 Message-Id: In-Reply-To: <07d22d7e080f4961913c9e759a03854d@git.apache.org> References: <07d22d7e080f4961913c9e759a03854d@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [7/9] hbase git commit: HBASE-14865 Support passing multiple QOPs to SaslClient/Server via hbase.rpc.protection (Appy) HBASE-14865 Support passing multiple QOPs to SaslClient/Server via hbase.rpc.protection (Appy) Project: http://git-wip-us.apache.org/repos/asf/hbase/repo Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/4ac8d4ce Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/4ac8d4ce Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/4ac8d4ce Branch: refs/heads/hbase-12439 Commit: 4ac8d4ce610a107112acb6aa070157691c022e90 Parents: ae7cc0c Author: tedyu Authored: Thu Jan 14 16:39:52 2016 -0800 Committer: tedyu Committed: Thu Jan 14 16:39:52 2016 -0800 ---------------------------------------------------------------------- .../hadoop/hbase/ipc/AsyncRpcChannel.java | 33 +- .../hbase/security/HBaseSaslRpcClient.java | 8 +- .../hbase/security/SaslClientHandler.java | 30 +- .../apache/hadoop/hbase/security/SaslUtil.java | 74 +++-- .../hbase/security/TestHBaseSaslRpcClient.java | 309 ++++++++++++++++++ .../hadoop/hbase/security/TestSaslUtil.java | 59 ++++ .../org/apache/hadoop/hbase/ipc/RpcServer.java | 4 +- .../hbase/security/HBaseSaslRpcServer.java | 9 +- .../hbase/security/AbstractTestSecureIPC.java | 245 ++++++++++++++ .../hbase/security/TestAsyncSecureIPC.java | 33 ++ .../hbase/security/TestHBaseSaslRpcClient.java | 325 ------------------- .../hadoop/hbase/security/TestSecureIPC.java | 33 ++ .../hadoop/hbase/security/TestSecureRPC.java | 216 ------------ 13 files changed, 751 insertions(+), 627 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hbase/blob/4ac8d4ce/hbase-client/src/main/java/org/apache/hadoop/hbase/ipc/AsyncRpcChannel.java ---------------------------------------------------------------------- diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/ipc/AsyncRpcChannel.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/ipc/AsyncRpcChannel.java index 44e8322..69978fc 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/ipc/AsyncRpcChannel.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/ipc/AsyncRpcChannel.java @@ -32,7 +32,6 @@ import io.netty.util.concurrent.Promise; import java.io.IOException; import java.net.ConnectException; import java.net.InetSocketAddress; -import java.net.SocketException; import java.nio.ByteBuffer; import java.security.PrivilegedExceptionAction; import java.util.ArrayList; @@ -104,8 +103,7 @@ public class AsyncRpcChannel { final String serviceName; final InetSocketAddress address; - private int ioFailureCounter = 0; - private int connectFailureCounter = 0; + private int failureCounter = 0; boolean useSasl; AuthMethod authMethod; @@ -134,7 +132,7 @@ public class AsyncRpcChannel { * @param bootstrap to construct channel on * @param client to connect with * @param ticket of user which uses connection - * @param serviceName name of service to connect to + * @param serviceName name of service to connect to * @param address to connect to */ public AsyncRpcChannel(Bootstrap bootstrap, final AsyncRpcClient client, User ticket, String @@ -166,11 +164,7 @@ public class AsyncRpcChannel { @Override public void operationComplete(final ChannelFuture f) throws Exception { if (!f.isSuccess()) { - if (f.cause() instanceof SocketException) { - retryOrClose(bootstrap, connectFailureCounter++, f.cause()); - } else { - retryOrClose(bootstrap, ioFailureCounter++, f.cause()); - } + retryOrClose(bootstrap, failureCounter++, client.failureSleep, f.cause()); return; } channel = f.channel(); @@ -263,13 +257,8 @@ public class AsyncRpcChannel { // Handle Sasl failure. Try to potentially get new credentials handleSaslConnectionFailure(retryCount, cause, realTicket); - // Try to reconnect - client.newTimeout(new TimerTask() { - @Override - public void run(Timeout timeout) throws Exception { - connect(bootstrap); - } - }, random.nextInt(reloginMaxBackoff) + 1, TimeUnit.MILLISECONDS); + retryOrClose(bootstrap, failureCounter++, random.nextInt(reloginMaxBackoff) + 1, + cause); } catch (IOException | InterruptedException e) { close(e); } @@ -286,16 +275,18 @@ public class AsyncRpcChannel { * Retry to connect or close * * @param bootstrap to connect with - * @param connectCounter amount of tries + * @param failureCount failure count * @param e exception of fail */ - private void retryOrClose(final Bootstrap bootstrap, int connectCounter, Throwable e) { - if (connectCounter < client.maxRetries) { + private void retryOrClose(final Bootstrap bootstrap, int failureCount, + long timeout, Throwable e) { + if (failureCount < client.maxRetries) { client.newTimeout(new TimerTask() { - @Override public void run(Timeout timeout) throws Exception { + @Override + public void run(Timeout timeout) throws Exception { connect(bootstrap); } - }, client.failureSleep, TimeUnit.MILLISECONDS); + }, timeout, TimeUnit.MILLISECONDS); } else { client.failedServers.addToFailedServers(address); close(e); http://git-wip-us.apache.org/repos/asf/hbase/blob/4ac8d4ce/hbase-client/src/main/java/org/apache/hadoop/hbase/security/HBaseSaslRpcClient.java ---------------------------------------------------------------------- diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/HBaseSaslRpcClient.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/HBaseSaslRpcClient.java index ab3ee0e..ce32ed9 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/HBaseSaslRpcClient.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/HBaseSaslRpcClient.java @@ -25,6 +25,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Map; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; @@ -59,6 +60,7 @@ public class HBaseSaslRpcClient { private final SaslClient saslClient; private final boolean fallbackAllowed; + protected final Map saslProps; /** * Create a HBaseSaslRpcClient for an authentication method * @@ -96,7 +98,7 @@ public class HBaseSaslRpcClient { Token token, String serverPrincipal, boolean fallbackAllowed, String rpcProtection) throws IOException { this.fallbackAllowed = fallbackAllowed; - SaslUtil.initSaslProperties(rpcProtection); + saslProps = SaslUtil.initSaslProperties(rpcProtection); switch (method) { case DIGEST: if (LOG.isDebugEnabled()) @@ -138,13 +140,13 @@ public class HBaseSaslRpcClient { String saslDefaultRealm, CallbackHandler saslClientCallbackHandler) throws IOException { return Sasl.createSaslClient(mechanismNames, null, null, saslDefaultRealm, - SaslUtil.SASL_PROPS, saslClientCallbackHandler); + saslProps, saslClientCallbackHandler); } protected SaslClient createKerberosSaslClient(String[] mechanismNames, String userFirstPart, String userSecondPart) throws IOException { return Sasl.createSaslClient(mechanismNames, null, userFirstPart, - userSecondPart, SaslUtil.SASL_PROPS, null); + userSecondPart, saslProps, null); } private static void readStatus(DataInputStream inStream) throws IOException { http://git-wip-us.apache.org/repos/asf/hbase/blob/4ac8d4ce/hbase-client/src/main/java/org/apache/hadoop/hbase/security/SaslClientHandler.java ---------------------------------------------------------------------- diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/SaslClientHandler.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/SaslClientHandler.java index f52987b..bfb625b 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/SaslClientHandler.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/SaslClientHandler.java @@ -41,6 +41,7 @@ import javax.security.sasl.SaslException; import java.io.IOException; import java.nio.charset.Charset; import java.security.PrivilegedExceptionAction; +import java.util.Map; import java.util.Random; /** @@ -58,6 +59,7 @@ public class SaslClientHandler extends ChannelDuplexHandler { * Used for client or server's token to send or receive from each other. */ private final SaslClient saslClient; + private final Map saslProps; private final SaslExceptionHandler exceptionHandler; private final SaslSuccessfulConnectHandler successfulConnectHandler; private byte[] saslToken; @@ -67,8 +69,6 @@ public class SaslClientHandler extends ChannelDuplexHandler { private Random random; /** - * Constructor - * * @param ticket the ugi * @param method auth method * @param token for Sasl @@ -76,8 +76,6 @@ public class SaslClientHandler extends ChannelDuplexHandler { * @param fallbackAllowed True if server may also fall back to less secure connection * @param rpcProtection Quality of protection. Can be 'authentication', 'integrity' or * 'privacy'. - * @param exceptionHandler handler for exceptions - * @param successfulConnectHandler handler for succesful connects * @throws java.io.IOException if handler could not be created */ public SaslClientHandler(UserGroupInformation ticket, AuthMethod method, @@ -90,7 +88,7 @@ public class SaslClientHandler extends ChannelDuplexHandler { this.exceptionHandler = exceptionHandler; this.successfulConnectHandler = successfulConnectHandler; - SaslUtil.initSaslProperties(rpcProtection); + saslProps = SaslUtil.initSaslProperties(rpcProtection); switch (method) { case DIGEST: if (LOG.isDebugEnabled()) @@ -125,32 +123,23 @@ public class SaslClientHandler extends ChannelDuplexHandler { /** * Create a Digest Sasl client - * - * @param mechanismNames names of mechanisms - * @param saslDefaultRealm default realm for sasl - * @param saslClientCallbackHandler handler for the client - * @return new SaslClient - * @throws java.io.IOException if creation went wrong */ protected SaslClient createDigestSaslClient(String[] mechanismNames, String saslDefaultRealm, CallbackHandler saslClientCallbackHandler) throws IOException { - return Sasl.createSaslClient(mechanismNames, null, null, saslDefaultRealm, SaslUtil.SASL_PROPS, + return Sasl.createSaslClient(mechanismNames, null, null, saslDefaultRealm, saslProps, saslClientCallbackHandler); } /** * Create Kerberos client * - * @param mechanismNames names of mechanisms * @param userFirstPart first part of username * @param userSecondPart second part of username - * @return new SaslClient - * @throws java.io.IOException if fails */ protected SaslClient createKerberosSaslClient(String[] mechanismNames, String userFirstPart, String userSecondPart) throws IOException { return Sasl - .createSaslClient(mechanismNames, null, userFirstPart, userSecondPart, SaslUtil.SASL_PROPS, + .createSaslClient(mechanismNames, null, userFirstPart, userSecondPart, saslProps, null); } @@ -269,11 +258,6 @@ public class SaslClientHandler extends ChannelDuplexHandler { } } - /** - * Write SASL token - * @param ctx to write to - * @param saslToken to write - */ private void writeSaslToken(final ChannelHandlerContext ctx, byte[] saslToken) { ByteBuf b = ctx.alloc().buffer(4 + saslToken.length); b.writeInt(saslToken.length); @@ -290,9 +274,6 @@ public class SaslClientHandler extends ChannelDuplexHandler { /** * Get the read status - * - * @param inStream to read - * @throws org.apache.hadoop.ipc.RemoteException if status was not success */ private static void readStatus(ByteBuf inStream) throws RemoteException { int status = inStream.readInt(); // read status @@ -360,7 +341,6 @@ public class SaslClientHandler extends ChannelDuplexHandler { * * @param retryCount current retry count * @param random to create new backoff with - * @param cause of fail */ public void handle(int retryCount, Random random, Throwable cause); } http://git-wip-us.apache.org/repos/asf/hbase/blob/4ac8d4ce/hbase-client/src/main/java/org/apache/hadoop/hbase/security/SaslUtil.java ---------------------------------------------------------------------- diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/SaslUtil.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/SaslUtil.java index f2f3393..b505fc0 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/SaslUtil.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/SaslUtil.java @@ -32,24 +32,31 @@ import org.apache.hadoop.hbase.classification.InterfaceAudience; public class SaslUtil { private static final Log log = LogFactory.getLog(SaslUtil.class); public static final String SASL_DEFAULT_REALM = "default"; - public static final Map SASL_PROPS = - new TreeMap(); public static final int SWITCH_TO_SIMPLE_AUTH = -88; - public static enum QualityOfProtection { + public enum QualityOfProtection { AUTHENTICATION("auth"), INTEGRITY("auth-int"), PRIVACY("auth-conf"); - public final String saslQop; + private final String saslQop; - private QualityOfProtection(String saslQop) { + QualityOfProtection(String saslQop) { this.saslQop = saslQop; } public String getSaslQop() { return saslQop; } + + public boolean matches(String stringQop) { + if (saslQop.equals(stringQop)) { + log.warn("Use authentication/integrity/privacy as value for rpc protection " + + "configurations instead of auth/auth-int/auth-conf."); + return true; + } + return name().equalsIgnoreCase(stringQop); + } } /** Splitting fully qualified Kerberos name into parts */ @@ -71,40 +78,39 @@ public class SaslUtil { /** * Returns {@link org.apache.hadoop.hbase.security.SaslUtil.QualityOfProtection} - * corresponding to the given {@code stringQop} value. Returns null if value is - * invalid. + * corresponding to the given {@code stringQop} value. + * @throws IllegalArgumentException If stringQop doesn't match any QOP. */ public static QualityOfProtection getQop(String stringQop) { - QualityOfProtection qop = null; - if (QualityOfProtection.AUTHENTICATION.name().toLowerCase().equals(stringQop) - || QualityOfProtection.AUTHENTICATION.saslQop.equals(stringQop)) { - qop = QualityOfProtection.AUTHENTICATION; - } else if (QualityOfProtection.INTEGRITY.name().toLowerCase().equals(stringQop) - || QualityOfProtection.INTEGRITY.saslQop.equals(stringQop)) { - qop = QualityOfProtection.INTEGRITY; - } else if (QualityOfProtection.PRIVACY.name().toLowerCase().equals(stringQop) - || QualityOfProtection.PRIVACY.saslQop.equals(stringQop)) { - qop = QualityOfProtection.PRIVACY; - } - if (qop == null) { - throw new IllegalArgumentException("Invalid qop: " + stringQop - + ". It must be one of 'authentication', 'integrity', 'privacy'."); + for (QualityOfProtection qop : QualityOfProtection.values()) { + if (qop.matches(stringQop)) { + return qop; + } } - if (QualityOfProtection.AUTHENTICATION.saslQop.equals(stringQop) - || QualityOfProtection.INTEGRITY.saslQop.equals(stringQop) - || QualityOfProtection.PRIVACY.saslQop.equals(stringQop)) { - log.warn("Use authentication/integrity/privacy as value for rpc protection " - + "configurations instead of auth/auth-int/auth-conf."); - } - return qop; + throw new IllegalArgumentException("Invalid qop: " + stringQop + + ". It must be one of 'authentication', 'integrity', 'privacy'."); } - static void initSaslProperties(String rpcProtection) { - QualityOfProtection saslQOP = getQop(rpcProtection); - if (saslQOP == null) { - saslQOP = QualityOfProtection.AUTHENTICATION; + /** + * @param rpcProtection Value of 'hbase.rpc.protection' configuration. + * @return Map with values for SASL properties. + */ + static Map initSaslProperties(String rpcProtection) { + String saslQop; + if (rpcProtection.isEmpty()) { + saslQop = QualityOfProtection.AUTHENTICATION.getSaslQop(); + } else { + String[] qops = rpcProtection.split(","); + StringBuilder saslQopBuilder = new StringBuilder(); + for (int i = 0; i < qops.length; ++i) { + QualityOfProtection qop = getQop(qops[i]); + saslQopBuilder.append(",").append(qop.getSaslQop()); + } + saslQop = saslQopBuilder.substring(1); // remove first ',' } - SaslUtil.SASL_PROPS.put(Sasl.QOP, saslQOP.getSaslQop()); - SaslUtil.SASL_PROPS.put(Sasl.SERVER_AUTH, "true"); + Map saslProps = new TreeMap<>(); + saslProps.put(Sasl.QOP, saslQop); + saslProps.put(Sasl.SERVER_AUTH, "true"); + return saslProps; } } http://git-wip-us.apache.org/repos/asf/hbase/blob/4ac8d4ce/hbase-client/src/test/java/org/apache/hadoop/hbase/security/TestHBaseSaslRpcClient.java ---------------------------------------------------------------------- diff --git a/hbase-client/src/test/java/org/apache/hadoop/hbase/security/TestHBaseSaslRpcClient.java b/hbase-client/src/test/java/org/apache/hadoop/hbase/security/TestHBaseSaslRpcClient.java new file mode 100644 index 0000000..0e3aeab --- /dev/null +++ b/hbase-client/src/test/java/org/apache/hadoop/hbase/security/TestHBaseSaslRpcClient.java @@ -0,0 +1,309 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.hadoop.hbase.security; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.TextOutputCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.Sasl; +import javax.security.sasl.RealmCallback; +import javax.security.sasl.RealmChoiceCallback; +import javax.security.sasl.SaslClient; + +import org.apache.hadoop.hbase.testclassification.SecurityTests; +import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.apache.hadoop.hbase.security.HBaseSaslRpcClient.SaslClientCallbackHandler; +import org.apache.hadoop.io.DataInputBuffer; +import org.apache.hadoop.io.DataOutputBuffer; +import org.apache.hadoop.security.token.Token; +import org.apache.hadoop.security.token.TokenIdentifier; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; + +import com.google.common.base.Strings; + +@Category({SecurityTests.class, SmallTests.class}) +public class TestHBaseSaslRpcClient { + + static { + System.setProperty("java.security.krb5.realm", "DOMAIN.COM"); + System.setProperty("java.security.krb5.kdc", "DOMAIN.COM"); + } + + static final String DEFAULT_USER_NAME = "principal"; + static final String DEFAULT_USER_PASSWORD = "password"; + + private static final Logger LOG = Logger.getLogger(TestHBaseSaslRpcClient.class); + + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @BeforeClass + public static void before() { + Logger.getRootLogger().setLevel(Level.DEBUG); + } + + @Test + public void testSaslClientUsesGivenRpcProtection() throws Exception { + Token token = createTokenMockWithCredentials(DEFAULT_USER_NAME, + DEFAULT_USER_PASSWORD); + for (SaslUtil.QualityOfProtection qop : SaslUtil.QualityOfProtection.values()) { + String negotiatedQop = new HBaseSaslRpcClient(AuthMethod.DIGEST, token, + "principal/host@DOMAIN.COM", false, qop.name()) { + public String getQop() { + return saslProps.get(Sasl.QOP); + } + }.getQop(); + assertEquals(negotiatedQop, qop.getSaslQop()); + } + } + + @Test + public void testSaslClientCallbackHandler() throws UnsupportedCallbackException { + final Token token = createTokenMock(); + when(token.getIdentifier()).thenReturn(DEFAULT_USER_NAME.getBytes()); + when(token.getPassword()).thenReturn(DEFAULT_USER_PASSWORD.getBytes()); + + final NameCallback nameCallback = mock(NameCallback.class); + final PasswordCallback passwordCallback = mock(PasswordCallback.class); + final RealmCallback realmCallback = mock(RealmCallback.class); + final RealmChoiceCallback realmChoiceCallback = mock(RealmChoiceCallback.class); + + Callback[] callbackArray = {nameCallback, passwordCallback, + realmCallback, realmChoiceCallback}; + final SaslClientCallbackHandler saslClCallbackHandler = new SaslClientCallbackHandler(token); + saslClCallbackHandler.handle(callbackArray); + verify(nameCallback).setName(anyString()); + verify(realmCallback).setText(anyString()); + verify(passwordCallback).setPassword(any(char[].class)); + } + + @Test + public void testSaslClientCallbackHandlerWithException() { + final Token token = createTokenMock(); + when(token.getIdentifier()).thenReturn(DEFAULT_USER_NAME.getBytes()); + when(token.getPassword()).thenReturn(DEFAULT_USER_PASSWORD.getBytes()); + final SaslClientCallbackHandler saslClCallbackHandler = new SaslClientCallbackHandler(token); + try { + saslClCallbackHandler.handle(new Callback[] { mock(TextOutputCallback.class) }); + } catch (UnsupportedCallbackException expEx) { + //expected + } catch (Exception ex) { + fail("testSaslClientCallbackHandlerWithException error : " + ex.getMessage()); + } + } + + @Test + public void testHBaseSaslRpcClientCreation() throws Exception { + //creation kerberos principal check section + assertFalse(assertSuccessCreationKerberosPrincipal(null)); + assertFalse(assertSuccessCreationKerberosPrincipal("DOMAIN.COM")); + assertFalse(assertSuccessCreationKerberosPrincipal("principal/DOMAIN.COM")); + if (!assertSuccessCreationKerberosPrincipal("principal/localhost@DOMAIN.COM")) { + // XXX: This can fail if kerberos support in the OS is not sane, see HBASE-10107. + // For now, don't assert, just warn + LOG.warn("Could not create a SASL client with valid Kerberos credential"); + } + + //creation digest principal check section + assertFalse(assertSuccessCreationDigestPrincipal(null, null)); + assertFalse(assertSuccessCreationDigestPrincipal("", "")); + assertFalse(assertSuccessCreationDigestPrincipal("", null)); + assertFalse(assertSuccessCreationDigestPrincipal(null, "")); + assertTrue(assertSuccessCreationDigestPrincipal(DEFAULT_USER_NAME, DEFAULT_USER_PASSWORD)); + + //creation simple principal check section + assertFalse(assertSuccessCreationSimplePrincipal("", "")); + assertFalse(assertSuccessCreationSimplePrincipal(null, null)); + assertFalse(assertSuccessCreationSimplePrincipal(DEFAULT_USER_NAME, DEFAULT_USER_PASSWORD)); + + //exceptions check section + assertTrue(assertIOExceptionThenSaslClientIsNull(DEFAULT_USER_NAME, DEFAULT_USER_PASSWORD)); + assertTrue(assertIOExceptionWhenGetStreamsBeforeConnectCall( + DEFAULT_USER_NAME, DEFAULT_USER_PASSWORD)); + } + + @Test + public void testAuthMethodReadWrite() throws IOException { + DataInputBuffer in = new DataInputBuffer(); + DataOutputBuffer out = new DataOutputBuffer(); + + assertAuthMethodRead(in, AuthMethod.SIMPLE); + assertAuthMethodRead(in, AuthMethod.KERBEROS); + assertAuthMethodRead(in, AuthMethod.DIGEST); + + assertAuthMethodWrite(out, AuthMethod.SIMPLE); + assertAuthMethodWrite(out, AuthMethod.KERBEROS); + assertAuthMethodWrite(out, AuthMethod.DIGEST); + } + + private void assertAuthMethodRead(DataInputBuffer in, AuthMethod authMethod) + throws IOException { + in.reset(new byte[] {authMethod.code}, 1); + assertEquals(authMethod, AuthMethod.read(in)); + } + + private void assertAuthMethodWrite(DataOutputBuffer out, AuthMethod authMethod) + throws IOException { + authMethod.write(out); + assertEquals(authMethod.code, out.getData()[0]); + out.reset(); + } + + private boolean assertIOExceptionWhenGetStreamsBeforeConnectCall(String principal, + String password) throws IOException { + boolean inState = false; + boolean outState = false; + + HBaseSaslRpcClient rpcClient = new HBaseSaslRpcClient(AuthMethod.DIGEST, + createTokenMockWithCredentials(principal, password), principal, false) { + @Override + public SaslClient createDigestSaslClient(String[] mechanismNames, + String saslDefaultRealm, CallbackHandler saslClientCallbackHandler) + throws IOException { + return Mockito.mock(SaslClient.class); + } + + @Override + public SaslClient createKerberosSaslClient(String[] mechanismNames, + String userFirstPart, String userSecondPart) throws IOException { + return Mockito.mock(SaslClient.class); + } + }; + + try { + rpcClient.getInputStream(Mockito.mock(InputStream.class)); + } catch(IOException ex) { + //Sasl authentication exchange hasn't completed yet + inState = true; + } + + try { + rpcClient.getOutputStream(Mockito.mock(OutputStream.class)); + } catch(IOException ex) { + //Sasl authentication exchange hasn't completed yet + outState = true; + } + + return inState && outState; + } + + private boolean assertIOExceptionThenSaslClientIsNull(String principal, String password) { + try { + new HBaseSaslRpcClient(AuthMethod.DIGEST, + createTokenMockWithCredentials(principal, password), principal, false) { + @Override + public SaslClient createDigestSaslClient(String[] mechanismNames, + String saslDefaultRealm, CallbackHandler saslClientCallbackHandler) + throws IOException { + return null; + } + + @Override + public SaslClient createKerberosSaslClient(String[] mechanismNames, + String userFirstPart, String userSecondPart) throws IOException { + return null; + } + }; + return false; + } catch (IOException ex) { + return true; + } + } + + private boolean assertSuccessCreationKerberosPrincipal(String principal) { + HBaseSaslRpcClient rpcClient = null; + try { + rpcClient = createSaslRpcClientForKerberos(principal); + } catch(Exception ex) { + LOG.error(ex.getMessage(), ex); + } + return rpcClient != null; + } + + private boolean assertSuccessCreationDigestPrincipal(String principal, String password) { + HBaseSaslRpcClient rpcClient = null; + try { + rpcClient = new HBaseSaslRpcClient(AuthMethod.DIGEST, + createTokenMockWithCredentials(principal, password), principal, false); + } catch(Exception ex) { + LOG.error(ex.getMessage(), ex); + } + return rpcClient != null; + } + + private boolean assertSuccessCreationSimplePrincipal(String principal, String password) { + HBaseSaslRpcClient rpcClient = null; + try { + rpcClient = createSaslRpcClientSimple(principal, password); + } catch(Exception ex) { + LOG.error(ex.getMessage(), ex); + } + return rpcClient != null; + } + + private HBaseSaslRpcClient createSaslRpcClientForKerberos(String principal) + throws IOException { + return new HBaseSaslRpcClient(AuthMethod.KERBEROS, createTokenMock(), principal, false); + } + + private Token createTokenMockWithCredentials( + String principal, String password) + throws IOException { + Token token = createTokenMock(); + if (!Strings.isNullOrEmpty(principal) && !Strings.isNullOrEmpty(password)) { + when(token.getIdentifier()).thenReturn(DEFAULT_USER_NAME.getBytes()); + when(token.getPassword()).thenReturn(DEFAULT_USER_PASSWORD.getBytes()); + } + return token; + } + + private HBaseSaslRpcClient createSaslRpcClientSimple(String principal, String password) + throws IOException { + return new HBaseSaslRpcClient(AuthMethod.SIMPLE, createTokenMock(), principal, false); + } + + @SuppressWarnings("unchecked") + private Token createTokenMock() { + return mock(Token.class); + } +} http://git-wip-us.apache.org/repos/asf/hbase/blob/4ac8d4ce/hbase-client/src/test/java/org/apache/hadoop/hbase/security/TestSaslUtil.java ---------------------------------------------------------------------- diff --git a/hbase-client/src/test/java/org/apache/hadoop/hbase/security/TestSaslUtil.java b/hbase-client/src/test/java/org/apache/hadoop/hbase/security/TestSaslUtil.java new file mode 100644 index 0000000..6c99739 --- /dev/null +++ b/hbase-client/src/test/java/org/apache/hadoop/hbase/security/TestSaslUtil.java @@ -0,0 +1,59 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.hadoop.hbase.security; + +import static org.junit.Assert.assertEquals; + +import org.apache.hadoop.hbase.testclassification.SecurityTests; +import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.ExpectedException; + +import javax.security.sasl.Sasl; +import java.util.Map; + +@Category({SecurityTests.class, SmallTests.class}) +public class TestSaslUtil { + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @Test + public void testInitSaslProperties() { + Map props; + + props = SaslUtil.initSaslProperties("integrity"); + assertEquals(props.get(Sasl.QOP), "auth-int"); + + props = SaslUtil.initSaslProperties("privacy,authentication"); + assertEquals(props.get(Sasl.QOP), "auth-conf,auth"); + + props = SaslUtil.initSaslProperties("integrity,authentication,privacy"); + assertEquals(props.get(Sasl.QOP), "auth-int,auth,auth-conf"); + + exception.expect(IllegalArgumentException.class); + props = SaslUtil.initSaslProperties("xyz"); + assertEquals(props.get(Sasl.QOP), "auth"); + + exception.expect(IllegalArgumentException.class); + props = SaslUtil.initSaslProperties(""); + assertEquals(props.get(Sasl.QOP), "auth"); + } +} http://git-wip-us.apache.org/repos/asf/hbase/blob/4ac8d4ce/hbase-server/src/main/java/org/apache/hadoop/hbase/ipc/RpcServer.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/ipc/RpcServer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/ipc/RpcServer.java index ed8d37d..d32fca7 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/ipc/RpcServer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/ipc/RpcServer.java @@ -1413,7 +1413,7 @@ public class RpcServer implements RpcServerInterface, ConfigurationObserver { } saslServer = Sasl.createSaslServer(AuthMethod.DIGEST .getMechanismName(), null, SaslUtil.SASL_DEFAULT_REALM, - SaslUtil.SASL_PROPS, new SaslDigestCallbackHandler( + HBaseSaslRpcServer.getSaslProps(), new SaslDigestCallbackHandler( secretManager, this)); break; default: @@ -1433,7 +1433,7 @@ public class RpcServer implements RpcServerInterface, ConfigurationObserver { public Object run() throws SaslException { saslServer = Sasl.createSaslServer(AuthMethod.KERBEROS .getMechanismName(), names[0], names[1], - SaslUtil.SASL_PROPS, new SaslGssCallbackHandler()); + HBaseSaslRpcServer.getSaslProps(), new SaslGssCallbackHandler()); return null; } }); http://git-wip-us.apache.org/repos/asf/hbase/blob/4ac8d4ce/hbase-server/src/main/java/org/apache/hadoop/hbase/security/HBaseSaslRpcServer.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/HBaseSaslRpcServer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/HBaseSaslRpcServer.java index b9e56d9..450db64 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/HBaseSaslRpcServer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/HBaseSaslRpcServer.java @@ -21,6 +21,7 @@ package org.apache.hadoop.hbase.security; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; +import java.util.Map; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; @@ -48,11 +49,17 @@ import org.apache.hadoop.security.token.SecretManager.InvalidToken; public class HBaseSaslRpcServer { private static final Log LOG = LogFactory.getLog(HBaseSaslRpcServer.class); + private static Map saslProps = null; + public static void init(Configuration conf) { - SaslUtil.initSaslProperties(conf.get("hbase.rpc.protection", + saslProps = SaslUtil.initSaslProperties(conf.get("hbase.rpc.protection", QualityOfProtection.AUTHENTICATION.name().toLowerCase())); } + public static Map getSaslProps() { + return saslProps; + } + public static T getIdentifier(String id, SecretManager secretManager) throws InvalidToken { byte[] tokenId = SaslUtil.decodeIdentifier(id); http://git-wip-us.apache.org/repos/asf/hbase/blob/4ac8d4ce/hbase-server/src/test/java/org/apache/hadoop/hbase/security/AbstractTestSecureIPC.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/AbstractTestSecureIPC.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/AbstractTestSecureIPC.java new file mode 100644 index 0000000..6145838 --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/AbstractTestSecureIPC.java @@ -0,0 +1,245 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.hadoop.hbase.security; + +import static org.apache.hadoop.hbase.security.HBaseKerberosUtils.getKeytabFileForTesting; +import static org.apache.hadoop.hbase.security.HBaseKerberosUtils.getPrincipalForTesting; +import static org.apache.hadoop.hbase.security.HBaseKerberosUtils.getSecuredConfiguration; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; + +import java.io.File; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Properties; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.CommonConfigurationKeys; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.ServerName; +import org.apache.hadoop.hbase.ipc.FifoRpcScheduler; +import org.apache.hadoop.hbase.ipc.RpcClient; +import org.apache.hadoop.hbase.ipc.RpcClientFactory; +import org.apache.hadoop.hbase.ipc.RpcServer; +import org.apache.hadoop.hbase.ipc.RpcServerInterface; +import org.apache.hadoop.hbase.ipc.TestDelayedRpc.TestDelayedImplementation; +import org.apache.hadoop.hbase.ipc.TestDelayedRpc.TestThread; +import org.apache.hadoop.hbase.ipc.protobuf.generated.TestDelayedRpcProtos; +import org.apache.hadoop.minikdc.MiniKdc; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; + +import com.google.common.collect.Lists; +import com.google.protobuf.BlockingRpcChannel; +import com.google.protobuf.BlockingService; + +import javax.security.sasl.SaslException; + +public abstract class AbstractTestSecureIPC { + + private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); + + private static final File KEYTAB_FILE = new File(TEST_UTIL.getDataTestDir("keytab").toUri() + .getPath()); + + private static MiniKdc KDC; + private static String HOST = "localhost"; + private static String PRINCIPAL; + + String krbKeytab; + String krbPrincipal; + UserGroupInformation ugi; + Configuration clientConf; + Configuration serverConf; + + abstract Class getRpcClientClass(); + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @BeforeClass + public static void setUp() throws Exception { + Properties conf = MiniKdc.createConf(); + conf.put(MiniKdc.DEBUG, true); + KDC = new MiniKdc(conf, new File(TEST_UTIL.getDataTestDir("kdc").toUri().getPath())); + KDC.start(); + PRINCIPAL = "hbase/" + HOST; + KDC.createPrincipal(KEYTAB_FILE, PRINCIPAL); + HBaseKerberosUtils.setKeytabFileForTesting(KEYTAB_FILE.getAbsolutePath()); + HBaseKerberosUtils.setPrincipalForTesting(PRINCIPAL + "@" + KDC.getRealm()); + } + + @AfterClass + public static void tearDown() throws IOException { + if (KDC != null) { + KDC.stop(); + } + TEST_UTIL.cleanupTestDir(); + } + + @Before + public void setUpTest() throws Exception { + krbKeytab = getKeytabFileForTesting(); + krbPrincipal = getPrincipalForTesting(); + ugi = loginKerberosPrincipal(krbKeytab, krbPrincipal); + clientConf = getSecuredConfiguration(); + clientConf.set(RpcClientFactory.CUSTOM_RPC_CLIENT_IMPL_CONF_KEY, getRpcClientClass().getName()); + serverConf = getSecuredConfiguration(); + } + + @Test + public void testRpcCallWithEnabledKerberosSaslAuth() throws Exception { + UserGroupInformation ugi2 = UserGroupInformation.getCurrentUser(); + + // check that the login user is okay: + assertSame(ugi, ugi2); + assertEquals(AuthenticationMethod.KERBEROS, ugi.getAuthenticationMethod()); + assertEquals(krbPrincipal, ugi.getUserName()); + + callRpcService(User.create(ugi2)); + } + + @Test + public void testRpcFallbackToSimpleAuth() throws Exception { + String clientUsername = "testuser"; + UserGroupInformation clientUgi = UserGroupInformation.createUserForTesting(clientUsername, + new String[]{clientUsername}); + + // check that the client user is insecure + assertNotSame(ugi, clientUgi); + assertEquals(AuthenticationMethod.SIMPLE, clientUgi.getAuthenticationMethod()); + assertEquals(clientUsername, clientUgi.getUserName()); + + clientConf.set(User.HBASE_SECURITY_CONF_KEY, "simple"); + serverConf.setBoolean(RpcServer.FALLBACK_TO_INSECURE_CLIENT_AUTH, true); + callRpcService(User.create(clientUgi)); + } + + void setRpcProtection(String clientProtection, String serverProtection) { + clientConf.set("hbase.rpc.protection", clientProtection); + serverConf.set("hbase.rpc.protection", serverProtection); + } + + /** + * Test various combinations of Server and Client qops. + * @throws Exception + */ + @Test + public void testSaslWithCommonQop() throws Exception { + setRpcProtection("privacy,authentication", "authentication"); + callRpcService(User.create(ugi)); + + setRpcProtection("authentication", "privacy,authentication"); + callRpcService(User.create(ugi)); + + setRpcProtection("integrity,authentication", "privacy,authentication"); + callRpcService(User.create(ugi)); + } + + @Test + public void testSaslNoCommonQop() throws Exception { + exception.expect(SaslException.class); + exception.expectMessage("No common protection layer between client and server"); + setRpcProtection("integrity", "privacy"); + callRpcService(User.create(ugi)); + } + + private UserGroupInformation loginKerberosPrincipal(String krbKeytab, String krbPrincipal) + throws Exception { + Configuration cnf = new Configuration(); + cnf.set(CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION, "kerberos"); + UserGroupInformation.setConfiguration(cnf); + UserGroupInformation.loginUserFromKeytab(krbPrincipal, krbKeytab); + return UserGroupInformation.getLoginUser(); + } + + /** + * Sets up a RPC Server and a Client. Does a RPC checks the result. If an exception is thrown + * from the stub, this function will throw root cause of that exception. + */ + private void callRpcService(User clientUser) throws Exception { + SecurityInfo securityInfoMock = Mockito.mock(SecurityInfo.class); + Mockito.when(securityInfoMock.getServerPrincipal()) + .thenReturn(HBaseKerberosUtils.KRB_PRINCIPAL); + SecurityInfo.addInfo("TestDelayedService", securityInfoMock); + + boolean delayReturnValue = false; + InetSocketAddress isa = new InetSocketAddress(HOST, 0); + TestDelayedImplementation instance = new TestDelayedImplementation(delayReturnValue); + BlockingService service = + TestDelayedRpcProtos.TestDelayedService.newReflectiveBlockingService(instance); + + RpcServerInterface rpcServer = + new RpcServer(null, "testSecuredDelayedRpc", + Lists.newArrayList(new RpcServer.BlockingServiceAndInterface(service, null)), isa, + serverConf, new FifoRpcScheduler(serverConf, 1)); + rpcServer.start(); + RpcClient rpcClient = + RpcClientFactory.createClient(clientConf, HConstants.DEFAULT_CLUSTER_ID.toString()); + try { + InetSocketAddress address = rpcServer.getListenerAddress(); + if (address == null) { + throw new IOException("Listener channel is closed"); + } + BlockingRpcChannel channel = + rpcClient.createBlockingRpcChannel( + ServerName.valueOf(address.getHostName(), address.getPort(), + System.currentTimeMillis()), clientUser, 0); + TestDelayedRpcProtos.TestDelayedService.BlockingInterface stub = + TestDelayedRpcProtos.TestDelayedService.newBlockingStub(channel); + List results = new ArrayList<>(); + TestThread th1 = new TestThread(stub, true, results); + final Throwable exception[] = new Throwable[1]; + Collections.synchronizedList(new ArrayList()); + Thread.UncaughtExceptionHandler exceptionHandler = + new Thread.UncaughtExceptionHandler() { + public void uncaughtException(Thread th, Throwable ex) { + exception[0] = ex; + } + }; + th1.setUncaughtExceptionHandler(exceptionHandler); + th1.start(); + th1.join(); + if (exception[0] != null) { + // throw root cause. + while (exception[0].getCause() != null) { + exception[0] = exception[0].getCause(); + } + throw (Exception) exception[0]; + } + + assertEquals(0xDEADBEEF, results.get(0).intValue()); + } finally { + rpcClient.close(); + rpcServer.stop(); + } + } +} http://git-wip-us.apache.org/repos/asf/hbase/blob/4ac8d4ce/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestAsyncSecureIPC.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestAsyncSecureIPC.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestAsyncSecureIPC.java new file mode 100644 index 0000000..ea37915 --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestAsyncSecureIPC.java @@ -0,0 +1,33 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.hadoop.hbase.security; + +import org.apache.hadoop.hbase.ipc.AsyncRpcClient; +import org.apache.hadoop.hbase.ipc.RpcClient; +import org.apache.hadoop.hbase.testclassification.SecurityTests; +import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.junit.experimental.categories.Category; + +@Category({ SecurityTests.class, SmallTests.class }) +public class TestAsyncSecureIPC extends AbstractTestSecureIPC { + + Class getRpcClientClass() { + return AsyncRpcClient.class; + } +} http://git-wip-us.apache.org/repos/asf/hbase/blob/4ac8d4ce/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestHBaseSaslRpcClient.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestHBaseSaslRpcClient.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestHBaseSaslRpcClient.java deleted file mode 100644 index 96ed986..0000000 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestHBaseSaslRpcClient.java +++ /dev/null @@ -1,325 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ -package org.apache.hadoop.hbase.security; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.TextOutputCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.sasl.Sasl; -import javax.security.sasl.RealmCallback; -import javax.security.sasl.RealmChoiceCallback; -import javax.security.sasl.SaslClient; - -import org.apache.hadoop.hbase.testclassification.SecurityTests; -import org.apache.hadoop.hbase.testclassification.SmallTests; -import org.apache.hadoop.hbase.security.HBaseSaslRpcClient.SaslClientCallbackHandler; -import org.apache.hadoop.io.DataInputBuffer; -import org.apache.hadoop.io.DataOutputBuffer; -import org.apache.hadoop.security.token.Token; -import org.apache.hadoop.security.token.TokenIdentifier; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; -import org.mockito.Mockito; - -import com.google.common.base.Strings; - -@Category({SecurityTests.class, SmallTests.class}) -public class TestHBaseSaslRpcClient { - - static { - System.setProperty("java.security.krb5.realm", "DOMAIN.COM"); - System.setProperty("java.security.krb5.kdc", "DOMAIN.COM"); - } - - static final String DEFAULT_USER_NAME = "principal"; - static final String DEFAULT_USER_PASSWORD = "password"; - - private static final Logger LOG = Logger.getLogger(TestHBaseSaslRpcClient.class); - - - @Rule - public ExpectedException exception = ExpectedException.none(); - - @BeforeClass - public static void before() { - Logger.getRootLogger().setLevel(Level.DEBUG); - } - - @Test - public void testSaslQOPNotEmpty() throws Exception { - Token token = createTokenMockWithCredentials(DEFAULT_USER_NAME, - DEFAULT_USER_PASSWORD); - // default QOP is authentication - new HBaseSaslRpcClient(AuthMethod.DIGEST, token, "principal/host@DOMAIN.COM", false); - assertTrue(SaslUtil.SASL_PROPS.get(Sasl.QOP).equals(SaslUtil.QualityOfProtection. - AUTHENTICATION.getSaslQop())); - - // check with specific QOPs - new HBaseSaslRpcClient(AuthMethod.DIGEST, token, "principal/host@DOMAIN.COM", false, - "authentication"); - assertTrue(SaslUtil.SASL_PROPS.get(Sasl.QOP).equals(SaslUtil.QualityOfProtection. - AUTHENTICATION.getSaslQop())); - - new HBaseSaslRpcClient(AuthMethod.DIGEST, token, "principal/host@DOMAIN.COM", false, - "privacy"); - assertTrue(SaslUtil.SASL_PROPS.get(Sasl.QOP).equals(SaslUtil.QualityOfProtection. - PRIVACY.getSaslQop())); - - new HBaseSaslRpcClient(AuthMethod.DIGEST, token, "principal/host@DOMAIN.COM", false, - "integrity"); - assertTrue(SaslUtil.SASL_PROPS.get(Sasl.QOP).equals(SaslUtil.QualityOfProtection. - INTEGRITY.getSaslQop())); - - exception.expect(IllegalArgumentException.class); - new HBaseSaslRpcClient(AuthMethod.DIGEST, token, "principal/host@DOMAIN.COM", false, - "wrongvalue"); - } - - @Test - public void testSaslClientCallbackHandler() throws UnsupportedCallbackException { - final Token token = createTokenMock(); - when(token.getIdentifier()).thenReturn(DEFAULT_USER_NAME.getBytes()); - when(token.getPassword()).thenReturn(DEFAULT_USER_PASSWORD.getBytes()); - - final NameCallback nameCallback = mock(NameCallback.class); - final PasswordCallback passwordCallback = mock(PasswordCallback.class); - final RealmCallback realmCallback = mock(RealmCallback.class); - final RealmChoiceCallback realmChoiceCallback = mock(RealmChoiceCallback.class); - - Callback[] callbackArray = {nameCallback, passwordCallback, - realmCallback, realmChoiceCallback}; - final SaslClientCallbackHandler saslClCallbackHandler = new SaslClientCallbackHandler(token); - saslClCallbackHandler.handle(callbackArray); - verify(nameCallback).setName(anyString()); - verify(realmCallback).setText(anyString()); - verify(passwordCallback).setPassword(any(char[].class)); - } - - @Test - public void testSaslClientCallbackHandlerWithException() { - final Token token = createTokenMock(); - when(token.getIdentifier()).thenReturn(DEFAULT_USER_NAME.getBytes()); - when(token.getPassword()).thenReturn(DEFAULT_USER_PASSWORD.getBytes()); - final SaslClientCallbackHandler saslClCallbackHandler = new SaslClientCallbackHandler(token); - try { - saslClCallbackHandler.handle(new Callback[] { mock(TextOutputCallback.class) }); - } catch (UnsupportedCallbackException expEx) { - //expected - } catch (Exception ex) { - fail("testSaslClientCallbackHandlerWithException error : " + ex.getMessage()); - } - } - - @Test - public void testHBaseSaslRpcClientCreation() throws Exception { - //creation kerberos principal check section - assertFalse(assertSuccessCreationKerberosPrincipal(null)); - assertFalse(assertSuccessCreationKerberosPrincipal("DOMAIN.COM")); - assertFalse(assertSuccessCreationKerberosPrincipal("principal/DOMAIN.COM")); - if (!assertSuccessCreationKerberosPrincipal("principal/localhost@DOMAIN.COM")) { - // XXX: This can fail if kerberos support in the OS is not sane, see HBASE-10107. - // For now, don't assert, just warn - LOG.warn("Could not create a SASL client with valid Kerberos credential"); - } - - //creation digest principal check section - assertFalse(assertSuccessCreationDigestPrincipal(null, null)); - assertFalse(assertSuccessCreationDigestPrincipal("", "")); - assertFalse(assertSuccessCreationDigestPrincipal("", null)); - assertFalse(assertSuccessCreationDigestPrincipal(null, "")); - assertTrue(assertSuccessCreationDigestPrincipal(DEFAULT_USER_NAME, DEFAULT_USER_PASSWORD)); - - //creation simple principal check section - assertFalse(assertSuccessCreationSimplePrincipal("", "")); - assertFalse(assertSuccessCreationSimplePrincipal(null, null)); - assertFalse(assertSuccessCreationSimplePrincipal(DEFAULT_USER_NAME, DEFAULT_USER_PASSWORD)); - - //exceptions check section - assertTrue(assertIOExceptionThenSaslClientIsNull(DEFAULT_USER_NAME, DEFAULT_USER_PASSWORD)); - assertTrue(assertIOExceptionWhenGetStreamsBeforeConnectCall( - DEFAULT_USER_NAME, DEFAULT_USER_PASSWORD)); - } - - @Test - public void testAuthMethodReadWrite() throws IOException { - DataInputBuffer in = new DataInputBuffer(); - DataOutputBuffer out = new DataOutputBuffer(); - - assertAuthMethodRead(in, AuthMethod.SIMPLE); - assertAuthMethodRead(in, AuthMethod.KERBEROS); - assertAuthMethodRead(in, AuthMethod.DIGEST); - - assertAuthMethodWrite(out, AuthMethod.SIMPLE); - assertAuthMethodWrite(out, AuthMethod.KERBEROS); - assertAuthMethodWrite(out, AuthMethod.DIGEST); - } - - private void assertAuthMethodRead(DataInputBuffer in, AuthMethod authMethod) - throws IOException { - in.reset(new byte[] {authMethod.code}, 1); - assertEquals(authMethod, AuthMethod.read(in)); - } - - private void assertAuthMethodWrite(DataOutputBuffer out, AuthMethod authMethod) - throws IOException { - authMethod.write(out); - assertEquals(authMethod.code, out.getData()[0]); - out.reset(); - } - - private boolean assertIOExceptionWhenGetStreamsBeforeConnectCall(String principal, - String password) throws IOException { - boolean inState = false; - boolean outState = false; - - HBaseSaslRpcClient rpcClient = new HBaseSaslRpcClient(AuthMethod.DIGEST, - createTokenMockWithCredentials(principal, password), principal, false) { - @Override - public SaslClient createDigestSaslClient(String[] mechanismNames, - String saslDefaultRealm, CallbackHandler saslClientCallbackHandler) - throws IOException { - return Mockito.mock(SaslClient.class); - } - - @Override - public SaslClient createKerberosSaslClient(String[] mechanismNames, - String userFirstPart, String userSecondPart) throws IOException { - return Mockito.mock(SaslClient.class); - } - }; - - try { - rpcClient.getInputStream(Mockito.mock(InputStream.class)); - } catch(IOException ex) { - //Sasl authentication exchange hasn't completed yet - inState = true; - } - - try { - rpcClient.getOutputStream(Mockito.mock(OutputStream.class)); - } catch(IOException ex) { - //Sasl authentication exchange hasn't completed yet - outState = true; - } - - return inState && outState; - } - - private boolean assertIOExceptionThenSaslClientIsNull(String principal, String password) { - try { - new HBaseSaslRpcClient(AuthMethod.DIGEST, - createTokenMockWithCredentials(principal, password), principal, false) { - @Override - public SaslClient createDigestSaslClient(String[] mechanismNames, - String saslDefaultRealm, CallbackHandler saslClientCallbackHandler) - throws IOException { - return null; - } - - @Override - public SaslClient createKerberosSaslClient(String[] mechanismNames, - String userFirstPart, String userSecondPart) throws IOException { - return null; - } - }; - return false; - } catch (IOException ex) { - return true; - } - } - - private boolean assertSuccessCreationKerberosPrincipal(String principal) { - HBaseSaslRpcClient rpcClient = null; - try { - rpcClient = createSaslRpcClientForKerberos(principal); - } catch(Exception ex) { - LOG.error(ex.getMessage(), ex); - } - return rpcClient != null; - } - - private boolean assertSuccessCreationDigestPrincipal(String principal, String password) { - HBaseSaslRpcClient rpcClient = null; - try { - rpcClient = new HBaseSaslRpcClient(AuthMethod.DIGEST, - createTokenMockWithCredentials(principal, password), principal, false); - } catch(Exception ex) { - LOG.error(ex.getMessage(), ex); - } - return rpcClient != null; - } - - private boolean assertSuccessCreationSimplePrincipal(String principal, String password) { - HBaseSaslRpcClient rpcClient = null; - try { - rpcClient = createSaslRpcClientSimple(principal, password); - } catch(Exception ex) { - LOG.error(ex.getMessage(), ex); - } - return rpcClient != null; - } - - private HBaseSaslRpcClient createSaslRpcClientForKerberos(String principal) - throws IOException { - return new HBaseSaslRpcClient(AuthMethod.KERBEROS, createTokenMock(), principal, false); - } - - private Token createTokenMockWithCredentials( - String principal, String password) - throws IOException { - Token token = createTokenMock(); - if (!Strings.isNullOrEmpty(principal) && !Strings.isNullOrEmpty(password)) { - when(token.getIdentifier()).thenReturn(DEFAULT_USER_NAME.getBytes()); - when(token.getPassword()).thenReturn(DEFAULT_USER_PASSWORD.getBytes()); - } - return token; - } - - private HBaseSaslRpcClient createSaslRpcClientSimple(String principal, String password) - throws IOException { - return new HBaseSaslRpcClient(AuthMethod.SIMPLE, createTokenMock(), principal, false); - } - - @SuppressWarnings("unchecked") - private Token createTokenMock() { - return mock(Token.class); - } -} http://git-wip-us.apache.org/repos/asf/hbase/blob/4ac8d4ce/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestSecureIPC.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestSecureIPC.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestSecureIPC.java new file mode 100644 index 0000000..98ea221 --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestSecureIPC.java @@ -0,0 +1,33 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.hadoop.hbase.security; + +import org.apache.hadoop.hbase.ipc.RpcClient; +import org.apache.hadoop.hbase.ipc.RpcClientImpl; +import org.apache.hadoop.hbase.testclassification.SecurityTests; +import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.junit.experimental.categories.Category; + +@Category({ SecurityTests.class, SmallTests.class }) +public class TestSecureIPC extends AbstractTestSecureIPC { + + Class getRpcClientClass() { + return RpcClientImpl.class; + } +} http://git-wip-us.apache.org/repos/asf/hbase/blob/4ac8d4ce/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestSecureRPC.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestSecureRPC.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestSecureRPC.java deleted file mode 100644 index 769e014..0000000 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/TestSecureRPC.java +++ /dev/null @@ -1,216 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ -package org.apache.hadoop.hbase.security; - -import static org.apache.hadoop.hbase.security.HBaseKerberosUtils.getKeytabFileForTesting; -import static org.apache.hadoop.hbase.security.HBaseKerberosUtils.getPrincipalForTesting; -import static org.apache.hadoop.hbase.security.HBaseKerberosUtils.getSecuredConfiguration; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertSame; - -import java.io.File; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; - -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.fs.CommonConfigurationKeys; -import org.apache.hadoop.hbase.HBaseTestingUtility; -import org.apache.hadoop.hbase.HConstants; -import org.apache.hadoop.hbase.ServerName; -import org.apache.hadoop.hbase.ipc.AsyncRpcClient; -import org.apache.hadoop.hbase.ipc.FifoRpcScheduler; -import org.apache.hadoop.hbase.ipc.RpcClient; -import org.apache.hadoop.hbase.ipc.RpcClientFactory; -import org.apache.hadoop.hbase.ipc.RpcClientImpl; -import org.apache.hadoop.hbase.ipc.RpcServer; -import org.apache.hadoop.hbase.ipc.RpcServerInterface; -import org.apache.hadoop.hbase.ipc.TestDelayedRpc.TestDelayedImplementation; -import org.apache.hadoop.hbase.ipc.TestDelayedRpc.TestThread; -import org.apache.hadoop.hbase.ipc.protobuf.generated.TestDelayedRpcProtos; -import org.apache.hadoop.hbase.testclassification.SecurityTests; -import org.apache.hadoop.hbase.testclassification.SmallTests; -import org.apache.hadoop.minikdc.MiniKdc; -import org.apache.hadoop.security.UserGroupInformation; -import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.mockito.Mockito; - -import com.google.common.collect.Lists; -import com.google.protobuf.BlockingRpcChannel; -import com.google.protobuf.BlockingService; - -@Category({ SecurityTests.class, SmallTests.class }) -public class TestSecureRPC { - - private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); - - private static final File KEYTAB_FILE = new File(TEST_UTIL.getDataTestDir("keytab").toUri() - .getPath()); - - private static MiniKdc KDC; - - private static String HOST = "localhost"; - - private static String PRINCIPAL; - - @BeforeClass - public static void setUp() throws Exception { - Properties conf = MiniKdc.createConf(); - conf.put(MiniKdc.DEBUG, true); - KDC = new MiniKdc(conf, new File(TEST_UTIL.getDataTestDir("kdc").toUri().getPath())); - KDC.start(); - PRINCIPAL = "hbase/" + HOST; - KDC.createPrincipal(KEYTAB_FILE, PRINCIPAL); - HBaseKerberosUtils.setKeytabFileForTesting(KEYTAB_FILE.getAbsolutePath()); - HBaseKerberosUtils.setPrincipalForTesting(PRINCIPAL + "@" + KDC.getRealm()); - } - - @AfterClass - public static void tearDown() throws IOException { - if (KDC != null) { - KDC.stop(); - } - TEST_UTIL.cleanupTestDir(); - } - - @Test - public void testRpc() throws Exception { - testRpcCallWithEnabledKerberosSaslAuth(RpcClientImpl.class); - } - - @Test - public void testRpcWithInsecureFallback() throws Exception { - testRpcFallbackToSimpleAuth(RpcClientImpl.class); - } - - @Test - public void testAsyncRpc() throws Exception { - testRpcCallWithEnabledKerberosSaslAuth(AsyncRpcClient.class); - } - - @Test - public void testAsyncRpcWithInsecureFallback() throws Exception { - testRpcFallbackToSimpleAuth(AsyncRpcClient.class); - } - - private void testRpcCallWithEnabledKerberosSaslAuth(Class rpcImplClass) - throws Exception { - String krbKeytab = getKeytabFileForTesting(); - String krbPrincipal = getPrincipalForTesting(); - - UserGroupInformation ugi = loginKerberosPrincipal(krbKeytab, krbPrincipal); - UserGroupInformation ugi2 = UserGroupInformation.getCurrentUser(); - - // check that the login user is okay: - assertSame(ugi, ugi2); - assertEquals(AuthenticationMethod.KERBEROS, ugi.getAuthenticationMethod()); - assertEquals(krbPrincipal, ugi.getUserName()); - - Configuration clientConf = getSecuredConfiguration(); - callRpcService(rpcImplClass, User.create(ugi2), clientConf, false); - } - - private UserGroupInformation loginKerberosPrincipal(String krbKeytab, String krbPrincipal) - throws Exception { - Configuration cnf = new Configuration(); - cnf.set(CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION, "kerberos"); - UserGroupInformation.setConfiguration(cnf); - UserGroupInformation.loginUserFromKeytab(krbPrincipal, krbKeytab); - return UserGroupInformation.getLoginUser(); - } - - private void callRpcService(Class rpcImplClass, User clientUser, - Configuration clientConf, boolean allowInsecureFallback) - throws Exception { - Configuration clientConfCopy = new Configuration(clientConf); - clientConfCopy.set(RpcClientFactory.CUSTOM_RPC_CLIENT_IMPL_CONF_KEY, rpcImplClass.getName()); - - Configuration conf = getSecuredConfiguration(); - conf.setBoolean(RpcServer.FALLBACK_TO_INSECURE_CLIENT_AUTH, allowInsecureFallback); - - SecurityInfo securityInfoMock = Mockito.mock(SecurityInfo.class); - Mockito.when(securityInfoMock.getServerPrincipal()) - .thenReturn(HBaseKerberosUtils.KRB_PRINCIPAL); - SecurityInfo.addInfo("TestDelayedService", securityInfoMock); - - boolean delayReturnValue = false; - InetSocketAddress isa = new InetSocketAddress(HOST, 0); - TestDelayedImplementation instance = new TestDelayedImplementation(delayReturnValue); - BlockingService service = - TestDelayedRpcProtos.TestDelayedService.newReflectiveBlockingService(instance); - - RpcServerInterface rpcServer = - new RpcServer(null, "testSecuredDelayedRpc", - Lists.newArrayList(new RpcServer.BlockingServiceAndInterface(service, null)), isa, - conf, new FifoRpcScheduler(conf, 1)); - rpcServer.start(); - RpcClient rpcClient = - RpcClientFactory.createClient(clientConfCopy, HConstants.DEFAULT_CLUSTER_ID.toString()); - try { - InetSocketAddress address = rpcServer.getListenerAddress(); - if (address == null) { - throw new IOException("Listener channel is closed"); - } - BlockingRpcChannel channel = - rpcClient.createBlockingRpcChannel( - ServerName.valueOf(address.getHostName(), address.getPort(), - System.currentTimeMillis()), clientUser, 5000); - TestDelayedRpcProtos.TestDelayedService.BlockingInterface stub = - TestDelayedRpcProtos.TestDelayedService.newBlockingStub(channel); - List results = new ArrayList(); - TestThread th1 = new TestThread(stub, true, results); - th1.start(); - th1.join(); - - assertEquals(0xDEADBEEF, results.get(0).intValue()); - } finally { - rpcClient.close(); - rpcServer.stop(); - } - } - - public void testRpcFallbackToSimpleAuth(Class rpcImplClass) throws Exception { - String krbKeytab = getKeytabFileForTesting(); - String krbPrincipal = getPrincipalForTesting(); - - UserGroupInformation ugi = loginKerberosPrincipal(krbKeytab, krbPrincipal); - assertEquals(AuthenticationMethod.KERBEROS, ugi.getAuthenticationMethod()); - assertEquals(krbPrincipal, ugi.getUserName()); - - String clientUsername = "testuser"; - UserGroupInformation clientUgi = UserGroupInformation.createUserForTesting(clientUsername, - new String[]{clientUsername}); - - // check that the client user is insecure - assertNotSame(ugi, clientUgi); - assertEquals(AuthenticationMethod.SIMPLE, clientUgi.getAuthenticationMethod()); - assertEquals(clientUsername, clientUgi.getUserName()); - - Configuration clientConf = new Configuration(); - clientConf.set(User.HBASE_SECURITY_CONF_KEY, "simple"); - callRpcService(rpcImplClass, User.create(clientUgi), clientConf, true); - } -} \ No newline at end of file