diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/provider/TestCustomSaslAuthenticationProvider.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/provider/CustomSaslAuthenticationProviderTestBase.java similarity index 73% rename from hbase-server/src/test/java/org/apache/hadoop/hbase/security/provider/TestCustomSaslAuthenticationProvider.java rename to hbase-server/src/test/java/org/apache/hadoop/hbase/security/provider/CustomSaslAuthenticationProviderTestBase.java index b8c70729c506..f8ce3030bf0f 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/provider/TestCustomSaslAuthenticationProvider.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/provider/CustomSaslAuthenticationProviderTestBase.java @@ -31,7 +31,6 @@ import java.io.IOException; import java.net.InetAddress; import java.security.PrivilegedExceptionAction; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -53,7 +52,6 @@ import org.apache.hadoop.fs.Path; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.CellUtil; -import org.apache.hadoop.hbase.HBaseClassTestRule; import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.LocalHBaseCluster; @@ -72,10 +70,8 @@ import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; import org.apache.hadoop.hbase.ipc.BlockingRpcClient; import org.apache.hadoop.hbase.ipc.NettyRpcClient; -import org.apache.hadoop.hbase.ipc.NettyRpcServer; import org.apache.hadoop.hbase.ipc.RpcClientFactory; import org.apache.hadoop.hbase.ipc.RpcServerFactory; -import org.apache.hadoop.hbase.ipc.SimpleRpcServer; import org.apache.hadoop.hbase.security.AccessDeniedException; import org.apache.hadoop.hbase.security.HBaseKerberosUtils; import org.apache.hadoop.hbase.security.SaslUtil; @@ -83,8 +79,6 @@ import org.apache.hadoop.hbase.security.User; import org.apache.hadoop.hbase.security.token.SecureTestCluster; import org.apache.hadoop.hbase.security.token.TokenProvider; -import org.apache.hadoop.hbase.testclassification.MediumTests; -import org.apache.hadoop.hbase.testclassification.SecurityTests; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.CommonFSUtils; import org.apache.hadoop.hbase.util.Pair; @@ -100,13 +94,10 @@ import org.junit.After; import org.junit.AfterClass; import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -116,48 +107,30 @@ /** * Tests the pluggable authentication framework with SASL using a contrived authentication system. - * - * This tests holds a "user database" in memory as a hashmap. Clients provide their password - * in the client Hadoop configuration. The servers validate this password via the "user database". + * This tests holds a "user database" in memory as a hashmap. Clients provide their password in the + * client Hadoop configuration. The servers validate this password via the "user database". */ -@RunWith(Parameterized.class) -@Category({MediumTests.class, SecurityTests.class}) -public class TestCustomSaslAuthenticationProvider { - private static final Logger LOG = LoggerFactory.getLogger( - TestCustomSaslAuthenticationProvider.class); +public abstract class CustomSaslAuthenticationProviderTestBase { - @ClassRule - public static final HBaseClassTestRule CLASS_RULE = - HBaseClassTestRule.forClass(TestCustomSaslAuthenticationProvider.class); + private static final Logger LOG = + LoggerFactory.getLogger(CustomSaslAuthenticationProviderTestBase.class); - private static final Map USER_DATABASE = createUserDatabase(); + private static final Map USER_DATABASE = createUserDatabase(); private static final String USER1_PASSWORD = "foobarbaz"; private static final String USER2_PASSWORD = "bazbarfoo"; - @Parameterized.Parameters(name = "{index}: rpcClientImpl={0}, rpcServerImpl={1}") + @Parameters public static Collection parameters() { - List params = new ArrayList<>(); - List rpcClientImpls = Arrays.asList( - BlockingRpcClient.class.getName(), NettyRpcClient.class.getName()); - List rpcServerImpls = Arrays.asList( - SimpleRpcServer.class.getName(), NettyRpcServer.class.getName()); - for (String rpcClientImpl : rpcClientImpls) { - for (String rpcServerImpl : rpcServerImpls) { - params.add(new Object[] { rpcClientImpl, rpcServerImpl }); - } - } - return params; + return Arrays.asList(new Object[] { BlockingRpcClient.class.getName() }, + new Object[] { NettyRpcClient.class.getName() }); } - @Parameterized.Parameter(0) + @Parameter public String rpcClientImpl; - @Parameterized.Parameter(1) - public String rpcServerImpl; - - private static Map createUserDatabase() { - Map db = new ConcurrentHashMap<>(); + private static Map createUserDatabase() { + Map db = new ConcurrentHashMap<>(); db.put("user1", USER1_PASSWORD); db.put("user2", USER2_PASSWORD); return db; @@ -172,14 +145,15 @@ public static String getPassword(String user) { } /** - * A custom token identifier for our custom auth'n method. Unique from the TokenIdentifier - * used for delegation tokens. + * A custom token identifier for our custom auth'n method. Unique from the TokenIdentifier used + * for delegation tokens. */ public static class PasswordAuthTokenIdentifier extends TokenIdentifier { public static final Text PASSWORD_AUTH_TOKEN = new Text("HBASE_PASSWORD_TEST_TOKEN"); private String username; - public PasswordAuthTokenIdentifier() {} + public PasswordAuthTokenIdentifier() { + } public PasswordAuthTokenIdentifier(String username) { this.username = username; @@ -209,29 +183,29 @@ public UserGroupInformation getUser() { } } - public static Token createPasswordToken( - String username, String password, String clusterId) { + public static Token createPasswordToken(String username, + String password, String clusterId) { PasswordAuthTokenIdentifier id = new PasswordAuthTokenIdentifier(username); - Token token = new Token<>(id.getBytes(), Bytes.toBytes(password), - id.getKind(), new Text(clusterId)); + Token token = + new Token<>(id.getBytes(), Bytes.toBytes(password), id.getKind(), new Text(clusterId)); return token; } /** - * Client provider that finds custom Token in the user's UGI and authenticates with the server - * via DIGEST-MD5 using that password. + * Client provider that finds custom Token in the user's UGI and authenticates with the server via + * DIGEST-MD5 using that password. */ public static class InMemoryClientProvider extends AbstractSaslClientAuthenticationProvider { public static final String MECHANISM = "DIGEST-MD5"; - public static final SaslAuthMethod SASL_AUTH_METHOD = new SaslAuthMethod( - "IN_MEMORY", (byte)42, MECHANISM, AuthenticationMethod.TOKEN); + public static final SaslAuthMethod SASL_AUTH_METHOD = + new SaslAuthMethod("IN_MEMORY", (byte) 42, MECHANISM, AuthenticationMethod.TOKEN); @Override public SaslClient createClient(Configuration conf, InetAddress serverAddr, - SecurityInfo securityInfo, Token token, boolean fallbackAllowed, - Map saslProps) throws IOException { + SecurityInfo securityInfo, Token token, boolean fallbackAllowed, + Map saslProps) throws IOException { return Sasl.createSaslClient(new String[] { MECHANISM }, null, null, - SaslUtil.SASL_DEFAULT_REALM, saslProps, new InMemoryClientProviderCallbackHandler(token)); + SaslUtil.SASL_DEFAULT_REALM, saslProps, new InMemoryClientProviderCallbackHandler(token)); } public Optional> findToken(User user) { @@ -253,11 +227,12 @@ public SaslAuthMethod getSaslAuthMethod() { } /** - * Sasl CallbackHandler which extracts information from our custom token and places - * it into the Sasl objects. + * Sasl CallbackHandler which extracts information from our custom token and places it into the + * Sasl objects. */ public class InMemoryClientProviderCallbackHandler implements CallbackHandler { private final Token token; + public InMemoryClientProviderCallbackHandler(Token token) { this.token = token; } @@ -302,21 +277,21 @@ public UserInformation getUserInfo(User user) { * Server provider which validates credentials from an in-memory database. */ public static class InMemoryServerProvider extends InMemoryClientProvider - implements SaslServerAuthenticationProvider { + implements SaslServerAuthenticationProvider { @Override - public AttemptingUserProvidingSaslServer createServer( - SecretManager secretManager, - Map saslProps) throws IOException { + public AttemptingUserProvidingSaslServer + createServer(SecretManager secretManager, Map saslProps) + throws IOException { return new AttemptingUserProvidingSaslServer( - Sasl.createSaslServer(getSaslAuthMethod().getSaslMechanism(), null, - SaslUtil.SASL_DEFAULT_REALM, saslProps, new InMemoryServerProviderCallbackHandler()), + Sasl.createSaslServer(getSaslAuthMethod().getSaslMechanism(), null, + SaslUtil.SASL_DEFAULT_REALM, saslProps, new InMemoryServerProviderCallbackHandler()), () -> null); } /** - * Pulls the correct password for the user who started the SASL handshake so that SASL - * can validate that the user provided the right password. + * Pulls the correct password for the user who started the SASL handshake so that SASL can + * validate that the user provided the right password. */ private class InMemoryServerProviderCallbackHandler implements CallbackHandler { @@ -344,11 +319,11 @@ public void handle(Callback[] callbacks) throws InvalidToken, UnsupportedCallbac try { id.readFields(new DataInputStream(new ByteArrayInputStream(encodedId))); } catch (IOException e) { - throw (InvalidToken) new InvalidToken( - "Can't de-serialize tokenIdentifier").initCause(e); + throw (InvalidToken) new InvalidToken("Can't de-serialize tokenIdentifier") + .initCause(e); } - char[] actualPassword = SaslUtil.encodePassword( - Bytes.toBytes(getPassword(id.getUser().getUserName()))); + char[] actualPassword = + SaslUtil.encodePassword(Bytes.toBytes(getPassword(id.getUser().getUserName()))); pc.setPassword(actualPassword); } if (ac != null) { @@ -373,7 +348,7 @@ public boolean supportsProtocolAuthentication() { @Override public UserGroupInformation getAuthorizedUgi(String authzId, - SecretManager secretManager) throws IOException { + SecretManager secretManager) throws IOException { UserGroupInformation authorizedUgi; byte[] encodedId = SaslUtil.decodeIdentifier(authzId); PasswordAuthTokenIdentifier tokenId = new PasswordAuthTokenIdentifier(); @@ -384,8 +359,7 @@ public UserGroupInformation getAuthorizedUgi(String authzId, } authorizedUgi = tokenId.getUser(); if (authorizedUgi == null) { - throw new AccessDeniedException( - "Can't retrieve username from tokenIdentifier."); + throw new AccessDeniedException("Can't retrieve username from tokenIdentifier."); } authorizedUgi.addTokenIdentifier(tokenId); authorizedUgi.setAuthenticationMethod(getSaslAuthMethod().getAuthMethod()); @@ -394,30 +368,28 @@ public UserGroupInformation getAuthorizedUgi(String authzId, } /** - * Custom provider which can select our custom provider, amongst other tokens which - * may be available. + * Custom provider which can select our custom provider, amongst other tokens which may be + * available. */ public static class InMemoryProviderSelector extends BuiltInProviderSelector { private InMemoryClientProvider inMemoryProvider; @Override public void configure(Configuration conf, - Collection providers) { + Collection providers) { super.configure(conf, providers); - Optional o = providers.stream() - .filter((p) -> p instanceof InMemoryClientProvider) - .findAny(); + Optional o = + providers.stream().filter((p) -> p instanceof InMemoryClientProvider).findAny(); - inMemoryProvider = (InMemoryClientProvider) o.orElseThrow( - () -> new RuntimeException("InMemoryClientProvider not found in available providers: " - + providers)); + inMemoryProvider = (InMemoryClientProvider) o.orElseThrow(() -> new RuntimeException( + "InMemoryClientProvider not found in available providers: " + providers)); } @Override - public Pair> selectProvider( - String clusterId, User user) { + public Pair> + selectProvider(String clusterId, User user) { Pair> superPair = - super.selectProvider(clusterId, user); + super.selectProvider(clusterId, user); Optional> optional = inMemoryProvider.findToken(user); if (optional.isPresent()) { @@ -430,21 +402,21 @@ public Pair> } } - static void createBaseCluster(HBaseTestingUtility util, File keytabFile, - MiniKdc kdc) throws Exception { + private static void createBaseCluster(HBaseTestingUtility util, File keytabFile, MiniKdc kdc) + throws Exception { String servicePrincipal = "hbase/localhost"; String spnegoPrincipal = "HTTP/localhost"; kdc.createPrincipal(keytabFile, servicePrincipal); util.startMiniZKCluster(); HBaseKerberosUtils.setSecuredConfiguration(util.getConfiguration(), - servicePrincipal + "@" + kdc.getRealm(), spnegoPrincipal + "@" + kdc.getRealm()); + servicePrincipal + "@" + kdc.getRealm(), spnegoPrincipal + "@" + kdc.getRealm()); HBaseKerberosUtils.setSSLConfiguration(util, SecureTestCluster.class); util.getConfiguration().setStrings(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, - TokenProvider.class.getName()); + TokenProvider.class.getName()); util.startMiniDFSCluster(1); - Path rootdir = util.getDataTestDirOnTestFS("TestGenerateDelegationToken"); + Path rootdir = util.getDataTestDirOnTestFS("TestCustomSaslAuthenticationProvider"); CommonFSUtils.setRootDir(util.getConfiguration(), rootdir); } @@ -453,76 +425,66 @@ static void createBaseCluster(HBaseTestingUtility util, File keytabFile, private static LocalHBaseCluster CLUSTER; private static File KEYTAB_FILE; - @BeforeClass - public static void setupCluster() throws Exception { - KEYTAB_FILE = new File( - UTIL.getDataTestDir("keytab").toUri().getPath()); + protected static void startCluster(String rpcServerImpl) throws Exception { + KEYTAB_FILE = new File(UTIL.getDataTestDir("keytab").toUri().getPath()); final MiniKdc kdc = UTIL.setupMiniKdc(KEYTAB_FILE); // Adds our test impls instead of creating service loader entries which // might inadvertently get them loaded on a real cluster. CONF.setStrings(SaslClientAuthenticationProviders.EXTRA_PROVIDERS_KEY, - InMemoryClientProvider.class.getName()); + InMemoryClientProvider.class.getName()); CONF.setStrings(SaslServerAuthenticationProviders.EXTRA_PROVIDERS_KEY, - InMemoryServerProvider.class.getName()); + InMemoryServerProvider.class.getName()); CONF.set(SaslClientAuthenticationProviders.SELECTOR_KEY, - InMemoryProviderSelector.class.getName()); + InMemoryProviderSelector.class.getName()); CONF.setLong(HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN, 600); createBaseCluster(UTIL, KEYTAB_FILE, kdc); - } - - @Before - public void setUpBeforeTest() throws Exception { - CONF.unset(HConstants.CLIENT_CONNECTION_REGISTRY_IMPL_CONF_KEY); - CONF.set(RpcClientFactory.CUSTOM_RPC_CLIENT_IMPL_CONF_KEY, rpcClientImpl); CONF.set(RpcServerFactory.CUSTOM_RPC_SERVER_IMPL_CONF_KEY, rpcServerImpl); - if (rpcClientImpl.equals(BlockingRpcClient.class.getName())) { - // Set the connection registry to ZKConnectionRegistry since hedging is not supported on - // blocking rpc clients. - CONF.set(HConstants.CLIENT_CONNECTION_REGISTRY_IMPL_CONF_KEY, - HConstants.ZK_CONNECTION_REGISTRY_CLASS); - } CLUSTER = new LocalHBaseCluster(CONF, 1); CLUSTER.startup(); - createTable(); } @AfterClass - public static void teardownCluster() throws Exception { + public static void shutdownCluster() throws Exception { if (CLUSTER != null) { CLUSTER.shutdown(); CLUSTER = null; } + UTIL.shutdownMiniDFSCluster(); UTIL.shutdownMiniZKCluster(); + UTIL.cleanupTestDir(); + } + + @Before + public void setUp() throws Exception { + createTable(); } @After - public void shutDownCluster() throws IOException { - if (CLUSTER != null) { - UTIL.deleteTable(name.getTableName()); - CLUSTER.shutdown(); - } + public void tearDown() throws IOException { + UTIL.deleteTable(name.getTableName()); } @Rule public TableNameTestRule name = new TableNameTestRule(); - TableName tableName; - String clusterId; - public void createTable() throws Exception { + private TableName tableName; + + private String clusterId; + + private void createTable() throws Exception { tableName = name.getTableName(); // Create a table and write a record as the service user (hbase) - UserGroupInformation serviceUgi = UserGroupInformation.loginUserFromKeytabAndReturnUGI( - "hbase/localhost", KEYTAB_FILE.getAbsolutePath()); + UserGroupInformation serviceUgi = UserGroupInformation + .loginUserFromKeytabAndReturnUGI("hbase/localhost", KEYTAB_FILE.getAbsolutePath()); clusterId = serviceUgi.doAs(new PrivilegedExceptionAction() { - @Override public String run() throws Exception { + @Override + public String run() throws Exception { try (Connection conn = ConnectionFactory.createConnection(CONF); - Admin admin = conn.getAdmin();) { - admin.createTable(TableDescriptorBuilder - .newBuilder(tableName) - .setColumnFamily(ColumnFamilyDescriptorBuilder.of("f1")) - .build()); + Admin admin = conn.getAdmin();) { + admin.createTable(TableDescriptorBuilder.newBuilder(tableName) + .setColumnFamily(ColumnFamilyDescriptorBuilder.of("f1")).build()); UTIL.waitTableAvailable(tableName); @@ -536,21 +498,25 @@ public void createTable() throws Exception { } } }); - assertNotNull(clusterId); } + private Configuration getClientConf() { + Configuration conf = new Configuration(CONF); + conf.set(RpcClientFactory.CUSTOM_RPC_CLIENT_IMPL_CONF_KEY, rpcClientImpl); + return conf; + } + @Test public void testPositiveAuthentication() throws Exception { // Validate that we can read that record back out as the user with our custom auth'n - final Configuration clientConf = new Configuration(CONF); - UserGroupInformation user1 = UserGroupInformation.createUserForTesting( - "user1", new String[0]); + UserGroupInformation user1 = UserGroupInformation.createUserForTesting("user1", new String[0]); user1.addToken(createPasswordToken("user1", USER1_PASSWORD, clusterId)); user1.doAs(new PrivilegedExceptionAction() { - @Override public Void run() throws Exception { - try (Connection conn = ConnectionFactory.createConnection(clientConf); - Table t = conn.getTable(tableName)) { + @Override + public Void run() throws Exception { + try (Connection conn = ConnectionFactory.createConnection(getClientConf()); + Table t = conn.getTable(tableName)) { Result r = t.get(new Get(Bytes.toBytes("r1"))); assertNotNull(r); assertFalse("Should have read a non-empty Result", r.isEmpty()); @@ -563,7 +529,7 @@ public void testPositiveAuthentication() throws Exception { }); } - @org.junit.Ignore @Test // See HBASE-24047 and its sub-issue to reenable. + @Test public void testNegativeAuthentication() throws Exception { // Validate that we can read that record back out as the user with our custom auth'n final Configuration clientConf = new Configuration(CONF); @@ -585,15 +551,15 @@ public void testNegativeAuthentication() throws Exception { // since it makes sense only when master registry is in use (which has RPCs to master). // That is the reason if you see a slight difference in the test between 3.x and 2.x. try (Connection conn = ConnectionFactory.createConnection(clientConf); - Table t = conn.getTable(tableName)) { + Table t = conn.getTable(tableName)) { t.get(new Get(Bytes.toBytes("r1"))); fail("Should not successfully authenticate with HBase"); } catch (RetriesExhaustedException re) { assertTrue(re.getMessage(), re.getMessage().contains("SaslException")); } catch (Exception e) { // Any other exception is unexpected. - fail("Unexpected exception caught, was expecting a authentication error: " - + Throwables.getStackTraceAsString(e)); + fail("Unexpected exception caught, was expecting a authentication error: " + + Throwables.getStackTraceAsString(e)); } return null; } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/provider/TestCustomSaslAuthenticationProviderNettyRpcServer.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/provider/TestCustomSaslAuthenticationProviderNettyRpcServer.java new file mode 100644 index 000000000000..3fd8a5196282 --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/provider/TestCustomSaslAuthenticationProviderNettyRpcServer.java @@ -0,0 +1,43 @@ +/** + * 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.provider; + +import org.apache.hadoop.hbase.HBaseClassTestRule; +import org.apache.hadoop.hbase.ipc.NettyRpcServer; +import org.apache.hadoop.hbase.testclassification.MediumTests; +import org.apache.hadoop.hbase.testclassification.SecurityTests; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +@Category({ MediumTests.class, SecurityTests.class }) +public class TestCustomSaslAuthenticationProviderNettyRpcServer + extends CustomSaslAuthenticationProviderTestBase { + + @ClassRule + public static final HBaseClassTestRule CLASS_RULE = + HBaseClassTestRule.forClass(TestCustomSaslAuthenticationProviderNettyRpcServer.class); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + startCluster(NettyRpcServer.class.getName()); + } +} diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/provider/TestCustomSaslAuthenticationProviderSimpleRpcServer.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/provider/TestCustomSaslAuthenticationProviderSimpleRpcServer.java new file mode 100644 index 000000000000..58bca98db498 --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/provider/TestCustomSaslAuthenticationProviderSimpleRpcServer.java @@ -0,0 +1,43 @@ +/** + * 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.provider; + +import org.apache.hadoop.hbase.HBaseClassTestRule; +import org.apache.hadoop.hbase.ipc.SimpleRpcServer; +import org.apache.hadoop.hbase.testclassification.MediumTests; +import org.apache.hadoop.hbase.testclassification.SecurityTests; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +@Category({ MediumTests.class, SecurityTests.class }) +public class TestCustomSaslAuthenticationProviderSimpleRpcServer + extends CustomSaslAuthenticationProviderTestBase { + + @ClassRule + public static final HBaseClassTestRule CLASS_RULE = + HBaseClassTestRule.forClass(TestCustomSaslAuthenticationProviderSimpleRpcServer.class); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + startCluster(SimpleRpcServer.class.getName()); + } +}