Skip to content

Commit 745b86f

Browse files
committed
HBASE-29144 Client request fails for KERBEROS with RpcConnectionRegistry (#7588)
Signed-off-by: Junegunn Choi <[email protected]> (cherry picked from commit 19c9d33)
1 parent 8841deb commit 745b86f

File tree

19 files changed

+498
-513
lines changed

19 files changed

+498
-513
lines changed

hbase-client/src/main/java/org/apache/hadoop/hbase/ipc/AbstractRpcClient.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.apache.hadoop.hbase.net.Address;
4444
import org.apache.hadoop.hbase.security.User;
4545
import org.apache.hadoop.hbase.security.UserProvider;
46+
import org.apache.hadoop.hbase.security.provider.SaslClientAuthenticationProviders;
4647
import org.apache.hadoop.hbase.trace.TraceUtil;
4748
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
4849
import org.apache.hadoop.hbase.util.PoolMap;
@@ -116,6 +117,8 @@ public abstract class AbstractRpcClient<T extends RpcConnection> implements RpcC
116117
protected final UserProvider userProvider;
117118
protected final CellBlockBuilder cellBlockBuilder;
118119

120+
protected final SaslClientAuthenticationProviders providers;
121+
119122
protected final int minIdleTimeBeforeClose; // if the connection is idle for more than this
120123
// time (in ms), it will be closed at any moment.
121124
protected final int maxRetries; // the max. no. of retries for socket connections
@@ -184,6 +187,8 @@ public AbstractRpcClient(Configuration conf, String clusterId, SocketAddress loc
184187
conf.getInt(HConstants.HBASE_CLIENT_PERSERVER_REQUESTS_THRESHOLD,
185188
HConstants.DEFAULT_HBASE_CLIENT_PERSERVER_REQUESTS_THRESHOLD);
186189

190+
this.providers = new SaslClientAuthenticationProviders(conf);
191+
187192
this.connections = new PoolMap<>(getPoolType(conf), getPoolSize(conf));
188193

189194
this.cleanupIdleConnectionTask = IDLE_CONN_SWEEPER.scheduleAtFixedRate(new Runnable() {

hbase-client/src/main/java/org/apache/hadoop/hbase/ipc/BlockingRpcConnection.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,9 @@ public void cleanup(IOException e) {
220220

221221
BlockingRpcConnection(BlockingRpcClient rpcClient, ConnectionId remoteId) throws IOException {
222222
super(rpcClient.conf, AbstractRpcClient.WHEEL_TIMER, remoteId, rpcClient.clusterId,
223-
rpcClient.userProvider.isHBaseSecurityEnabled(), rpcClient.codec, rpcClient.compressor,
224-
rpcClient.cellBlockBuilder, rpcClient.metrics, rpcClient.connectionAttributes);
223+
rpcClient.userProvider.isHBaseSecurityEnabled(), rpcClient.providers, rpcClient.codec,
224+
rpcClient.compressor, rpcClient.cellBlockBuilder, rpcClient.metrics,
225+
rpcClient.connectionAttributes);
225226
this.rpcClient = rpcClient;
226227
this.connectionHeaderPreamble = getConnectionHeaderPreamble();
227228
ConnectionHeader header = getConnectionHeader();

hbase-client/src/main/java/org/apache/hadoop/hbase/ipc/NettyRpcConnection.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,9 @@ class NettyRpcConnection extends RpcConnection {
106106

107107
NettyRpcConnection(NettyRpcClient rpcClient, ConnectionId remoteId) throws IOException {
108108
super(rpcClient.conf, AbstractRpcClient.WHEEL_TIMER, remoteId, rpcClient.clusterId,
109-
rpcClient.userProvider.isHBaseSecurityEnabled(), rpcClient.codec, rpcClient.compressor,
110-
rpcClient.cellBlockBuilder, rpcClient.metrics, rpcClient.connectionAttributes);
109+
rpcClient.userProvider.isHBaseSecurityEnabled(), rpcClient.providers, rpcClient.codec,
110+
rpcClient.compressor, rpcClient.cellBlockBuilder, rpcClient.metrics,
111+
rpcClient.connectionAttributes);
111112
this.rpcClient = rpcClient;
112113
this.eventLoop = rpcClient.group.next();
113114
byte[] connectionHeaderPreamble = getConnectionHeaderPreamble();

hbase-client/src/main/java/org/apache/hadoop/hbase/ipc/RpcConnection.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ abstract class RpcConnection {
119119
private String lastSucceededServerPrincipal;
120120

121121
protected RpcConnection(Configuration conf, HashedWheelTimer timeoutTimer, ConnectionId remoteId,
122-
String clusterId, boolean isSecurityEnabled, Codec codec, CompressionCodec compressor,
123-
CellBlockBuilder cellBlockBuilder, MetricsConnection metrics,
124-
Map<String, byte[]> connectionAttributes) throws IOException {
122+
String clusterId, boolean isSecurityEnabled, SaslClientAuthenticationProviders providers,
123+
Codec codec, CompressionCodec compressor, CellBlockBuilder cellBlockBuilder,
124+
MetricsConnection metrics, Map<String, byte[]> connectionAttributes) throws IOException {
125125
this.timeoutTimer = timeoutTimer;
126126
this.codec = codec;
127127
this.compressor = compressor;
@@ -134,8 +134,6 @@ protected RpcConnection(Configuration conf, HashedWheelTimer timeoutTimer, Conne
134134
this.useSasl = isSecurityEnabled;
135135

136136
// Choose the correct Token and AuthenticationProvider for this client to use
137-
SaslClientAuthenticationProviders providers =
138-
SaslClientAuthenticationProviders.getInstance(conf);
139137
Pair<SaslClientAuthenticationProvider, Token<? extends TokenIdentifier>> pair;
140138
if (useSasl && securityInfo != null) {
141139
pair = providers.selectProvider(clusterId, ticket);

hbase-client/src/main/java/org/apache/hadoop/hbase/security/provider/AuthenticationProviderSelector.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@
3232
public interface AuthenticationProviderSelector {
3333

3434
/**
35-
* Initializes the implementation with configuration and a set of providers available. This method
36-
* should be called exactly once per implementation prior to calling
37-
* {@link #selectProvider(String, User)}.
35+
* Initializes the implementation with configuration and a set of providers available.
36+
* <p>
37+
* This method is called once upon construction, before {@link #selectProvider(String, User)} is
38+
* invoked.
3839
*/
3940
void configure(Configuration conf,
4041
Collection<SaslClientAuthenticationProvider> availableProviders);

hbase-client/src/main/java/org/apache/hadoop/hbase/security/provider/SaslClientAuthenticationProviders.java

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,36 @@ public final class SaslClientAuthenticationProviders {
4848
public static final String SELECTOR_KEY = "hbase.client.sasl.provider.class";
4949
public static final String EXTRA_PROVIDERS_KEY = "hbase.client.sasl.provider.extras";
5050

51-
private static final AtomicReference<SaslClientAuthenticationProviders> providersRef =
51+
private static final AtomicReference<SaslClientAuthenticationProviders> PROVIDER_REF =
5252
new AtomicReference<>();
5353

5454
private final Collection<SaslClientAuthenticationProvider> providers;
5555
private final AuthenticationProviderSelector selector;
5656

57-
private SaslClientAuthenticationProviders(Collection<SaslClientAuthenticationProvider> providers,
58-
AuthenticationProviderSelector selector) {
59-
this.providers = providers;
60-
this.selector = selector;
57+
/**
58+
* Creates a new instance of SaslClientAuthenticationProviders.
59+
* @param conf the configuration to use for loading providers and selector
60+
*/
61+
public SaslClientAuthenticationProviders(Configuration conf) {
62+
ServiceLoader<SaslClientAuthenticationProvider> loader =
63+
ServiceLoader.load(SaslClientAuthenticationProvider.class,
64+
SaslClientAuthenticationProviders.class.getClassLoader());
65+
HashMap<Byte, SaslClientAuthenticationProvider> providerMap = new HashMap<>();
66+
for (SaslClientAuthenticationProvider provider : loader) {
67+
addProviderIfNotExists(provider, providerMap);
68+
}
69+
70+
addExplicitProviders(conf, providerMap);
71+
72+
providers = Collections.unmodifiableCollection(providerMap.values());
73+
74+
if (LOG.isTraceEnabled()) {
75+
String loadedProviders = providers.stream().map((provider) -> provider.getClass().getName())
76+
.collect(Collectors.joining(", "));
77+
LOG.trace("Found SaslClientAuthenticationProviders {}", loadedProviders);
78+
}
79+
80+
selector = instantiateSelector(conf, providers);
6181
}
6282

6383
/**
@@ -69,22 +89,30 @@ public int getNumRegisteredProviders() {
6989

7090
/**
7191
* Returns a singleton instance of {@link SaslClientAuthenticationProviders}.
92+
* @deprecated Since 2.5.14 and 2.6.4, will be removed in newer minor release lines. This class
93+
* should not be singleton, please do not use it any more. see HBASE-29144 for more
94+
* details.
7295
*/
96+
@Deprecated
7397
public static synchronized SaslClientAuthenticationProviders getInstance(Configuration conf) {
74-
SaslClientAuthenticationProviders providers = providersRef.get();
98+
SaslClientAuthenticationProviders providers = PROVIDER_REF.get();
7599
if (providers == null) {
76-
providers = instantiate(conf);
77-
providersRef.set(providers);
100+
providers = new SaslClientAuthenticationProviders(conf);
101+
PROVIDER_REF.set(providers);
78102
}
79103

80104
return providers;
81105
}
82106

83107
/**
84108
* Removes the cached singleton instance of {@link SaslClientAuthenticationProviders}.
109+
* @deprecated Since 2.5.14 and 2.6.4, will be removed in newer minor release lines. This class
110+
* should not be singleton, please do not use it any more. see HBASE-29144 for more
111+
* details.
85112
*/
113+
@Deprecated
86114
public static synchronized void reset() {
87-
providersRef.set(null);
115+
PROVIDER_REF.set(null);
88116
}
89117

90118
/**
@@ -93,7 +121,7 @@ public static synchronized void reset() {
93121
*/
94122
static void addProviderIfNotExists(SaslClientAuthenticationProvider provider,
95123
HashMap<Byte, SaslClientAuthenticationProvider> providers) {
96-
Byte code = provider.getSaslAuthMethod().getCode();
124+
byte code = provider.getSaslAuthMethod().getCode();
97125
SaslClientAuthenticationProvider existingProvider = providers.get(code);
98126
if (existingProvider != null) {
99127
throw new RuntimeException("Already registered authentication provider with " + code + " "
@@ -105,7 +133,7 @@ static void addProviderIfNotExists(SaslClientAuthenticationProvider provider,
105133
/**
106134
* Instantiates the ProviderSelector implementation from the provided configuration.
107135
*/
108-
static AuthenticationProviderSelector instantiateSelector(Configuration conf,
136+
private static AuthenticationProviderSelector instantiateSelector(Configuration conf,
109137
Collection<SaslClientAuthenticationProvider> providers) {
110138
Class<? extends AuthenticationProviderSelector> clz = conf.getClass(SELECTOR_KEY,
111139
BuiltInProviderSelector.class, AuthenticationProviderSelector.class);
@@ -161,34 +189,6 @@ static void addExplicitProviders(Configuration conf,
161189
}
162190
}
163191

164-
/**
165-
* Instantiates all client authentication providers and returns an instance of
166-
* {@link SaslClientAuthenticationProviders}.
167-
*/
168-
static SaslClientAuthenticationProviders instantiate(Configuration conf) {
169-
ServiceLoader<SaslClientAuthenticationProvider> loader =
170-
ServiceLoader.load(SaslClientAuthenticationProvider.class,
171-
SaslClientAuthenticationProviders.class.getClassLoader());
172-
HashMap<Byte, SaslClientAuthenticationProvider> providerMap = new HashMap<>();
173-
for (SaslClientAuthenticationProvider provider : loader) {
174-
addProviderIfNotExists(provider, providerMap);
175-
}
176-
177-
addExplicitProviders(conf, providerMap);
178-
179-
Collection<SaslClientAuthenticationProvider> providers =
180-
Collections.unmodifiableCollection(providerMap.values());
181-
182-
if (LOG.isTraceEnabled()) {
183-
String loadedProviders = providers.stream().map((provider) -> provider.getClass().getName())
184-
.collect(Collectors.joining(", "));
185-
LOG.trace("Found SaslClientAuthenticationProviders {}", loadedProviders);
186-
}
187-
188-
AuthenticationProviderSelector selector = instantiateSelector(conf, providers);
189-
return new SaslClientAuthenticationProviders(providers, selector);
190-
}
191-
192192
/**
193193
* Returns the provider and token pair for SIMPLE authentication. This method is a "hack" while
194194
* SIMPLE authentication for HBase does not flow through the SASL codepath.

hbase-client/src/test/java/org/apache/hadoop/hbase/security/provider/TestSaslClientAuthenticationProviders.java

Lines changed: 12 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,16 @@
1717
*/
1818
package org.apache.hadoop.hbase.security.provider;
1919

20-
import static org.junit.Assert.assertEquals;
21-
import static org.junit.Assert.assertNotSame;
22-
import static org.junit.Assert.assertSame;
20+
import static org.junit.jupiter.api.Assertions.assertEquals;
21+
import static org.junit.jupiter.api.Assertions.assertSame;
22+
import static org.junit.jupiter.api.Assertions.assertThrows;
2323

2424
import java.io.IOException;
2525
import java.net.InetAddress;
2626
import java.util.HashMap;
2727
import java.util.Map;
2828
import javax.security.sasl.SaslClient;
2929
import org.apache.hadoop.conf.Configuration;
30-
import org.apache.hadoop.hbase.HBaseClassTestRule;
3130
import org.apache.hadoop.hbase.HBaseConfiguration;
3231
import org.apache.hadoop.hbase.security.SecurityInfo;
3332
import org.apache.hadoop.hbase.security.User;
@@ -36,19 +35,15 @@
3635
import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
3736
import org.apache.hadoop.security.token.Token;
3837
import org.apache.hadoop.security.token.TokenIdentifier;
39-
import org.junit.ClassRule;
40-
import org.junit.Test;
41-
import org.junit.experimental.categories.Category;
38+
import org.junit.jupiter.api.Tag;
39+
import org.junit.jupiter.api.Test;
4240

4341
import org.apache.hadoop.hbase.shaded.protobuf.generated.RPCProtos.UserInformation;
4442

45-
@Category({ SmallTests.class, SecurityTests.class })
43+
@Tag(SmallTests.TAG)
44+
@Tag(SecurityTests.TAG)
4645
public class TestSaslClientAuthenticationProviders {
4746

48-
@ClassRule
49-
public static final HBaseClassTestRule CLASS_RULE =
50-
HBaseClassTestRule.forClass(TestSaslClientAuthenticationProviders.class);
51-
5247
@Test
5348
public void testCannotAddTheSameProviderTwice() {
5449
HashMap<Byte, SaslClientAuthenticationProvider> registeredProviders = new HashMap<>();
@@ -58,38 +53,19 @@ public void testCannotAddTheSameProviderTwice() {
5853
SaslClientAuthenticationProviders.addProviderIfNotExists(p1, registeredProviders);
5954
assertEquals(1, registeredProviders.size());
6055

61-
try {
62-
SaslClientAuthenticationProviders.addProviderIfNotExists(p2, registeredProviders);
63-
} catch (RuntimeException e) {
64-
}
56+
assertThrows(RuntimeException.class,
57+
() -> SaslClientAuthenticationProviders.addProviderIfNotExists(p2, registeredProviders));
6558

66-
assertSame("Expected the original provider to be present", p1,
67-
registeredProviders.entrySet().iterator().next().getValue());
59+
assertSame(p1, registeredProviders.entrySet().iterator().next().getValue(),
60+
"Expected the original provider to be present");
6861
}
6962

7063
@Test
71-
public void testInstanceIsCached() {
72-
Configuration conf = HBaseConfiguration.create();
73-
SaslClientAuthenticationProviders providers1 =
74-
SaslClientAuthenticationProviders.getInstance(conf);
75-
SaslClientAuthenticationProviders providers2 =
76-
SaslClientAuthenticationProviders.getInstance(conf);
77-
assertSame(providers1, providers2);
78-
79-
SaslClientAuthenticationProviders.reset();
80-
81-
SaslClientAuthenticationProviders providers3 =
82-
SaslClientAuthenticationProviders.getInstance(conf);
83-
assertNotSame(providers1, providers3);
84-
assertEquals(providers1.getNumRegisteredProviders(), providers3.getNumRegisteredProviders());
85-
}
86-
87-
@Test(expected = RuntimeException.class)
8864
public void testDifferentConflictingImplementationsFail() {
8965
Configuration conf = HBaseConfiguration.create();
9066
conf.setStrings(SaslClientAuthenticationProviders.EXTRA_PROVIDERS_KEY,
9167
ConflictingProvider1.class.getName(), ConflictingProvider2.class.getName());
92-
SaslClientAuthenticationProviders.getInstance(conf);
68+
assertThrows(RuntimeException.class, () -> new SaslClientAuthenticationProviders(conf));
9369
}
9470

9571
static class ConflictingProvider1 implements SaslClientAuthenticationProvider {

hbase-common/src/test/java/org/apache/hadoop/hbase/HBaseParameterizedParameterResolver.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import org.junit.jupiter.api.extension.ParameterResolver;
2424
import org.junit.jupiter.params.provider.Arguments;
2525

26+
import org.apache.hbase.thirdparty.com.google.common.primitives.Primitives;
27+
2628
/**
2729
* @see HBaseParameterizedTestTemplate
2830
*/
@@ -38,8 +40,20 @@ public class HBaseParameterizedParameterResolver implements ParameterResolver {
3840
public boolean supportsParameter(ParameterContext pc, ExtensionContext ec)
3941
throws ParameterResolutionException {
4042
int index = pc.getIndex();
41-
return index < values.length
42-
&& pc.getParameter().getType().isAssignableFrom(values[index].getClass());
43+
if (index >= values.length) {
44+
return false;
45+
}
46+
Object value = values[index];
47+
Class<?> expectedType = pc.getParameter().getType();
48+
if (expectedType.isPrimitive()) {
49+
// primitive type can not accept null value
50+
if (value == null) {
51+
return false;
52+
}
53+
// test with wrapper type, otherwise it will always return false
54+
return Primitives.wrap(expectedType).isAssignableFrom(value.getClass());
55+
}
56+
return expectedType.isAssignableFrom(value.getClass());
4357
}
4458

4559
@Override

hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/mapreduce/TestTableMapReduceUtil.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import org.apache.hadoop.hbase.HBaseClassTestRule;
3030
import org.apache.hadoop.hbase.HBaseTestingUtility;
3131
import org.apache.hadoop.hbase.client.Scan;
32-
import org.apache.hadoop.hbase.security.provider.SaslClientAuthenticationProviders;
3332
import org.apache.hadoop.hbase.security.token.AuthenticationTokenIdentifier;
3433
import org.apache.hadoop.hbase.testclassification.MapReduceTests;
3534
import org.apache.hadoop.hbase.testclassification.MediumTests;
@@ -43,7 +42,6 @@
4342
import org.apache.hadoop.security.UserGroupInformation;
4443
import org.apache.hadoop.security.token.Token;
4544
import org.apache.hadoop.security.token.TokenIdentifier;
46-
import org.junit.After;
4745
import org.junit.ClassRule;
4846
import org.junit.Test;
4947
import org.junit.experimental.categories.Category;
@@ -59,11 +57,6 @@ public class TestTableMapReduceUtil {
5957
public static final HBaseClassTestRule CLASS_RULE =
6058
HBaseClassTestRule.forClass(TestTableMapReduceUtil.class);
6159

62-
@After
63-
public void after() {
64-
SaslClientAuthenticationProviders.reset();
65-
}
66-
6760
/*
6861
* initTableSnapshotMapperJob is tested in {@link TestTableSnapshotInputFormat} because the method
6962
* depends on an online cluster.

hbase-server/src/main/java/org/apache/hadoop/hbase/ipc/RpcServer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import org.apache.hadoop.hbase.security.SaslUtil.QualityOfProtection;
5454
import org.apache.hadoop.hbase.security.User;
5555
import org.apache.hadoop.hbase.security.UserProvider;
56+
import org.apache.hadoop.hbase.security.provider.SaslServerAuthenticationProviders;
5657
import org.apache.hadoop.hbase.security.token.AuthenticationTokenSecretManager;
5758
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
5859
import org.apache.hadoop.hbase.util.GsonUtil;
@@ -97,6 +98,7 @@ public abstract class RpcServer implements RpcServerInterface, ConfigurationObse
9798
private final boolean authorize;
9899
private volatile boolean isOnlineLogProviderEnabled;
99100
protected boolean isSecurityEnabled;
101+
protected final SaslServerAuthenticationProviders saslProviders;
100102

101103
public static final byte CURRENT_VERSION = 0;
102104

@@ -309,6 +311,7 @@ public RpcServer(final Server server, final String name,
309311
saslProps = Collections.emptyMap();
310312
serverPrincipal = HConstants.EMPTY_STRING;
311313
}
314+
this.saslProviders = new SaslServerAuthenticationProviders(conf);
312315

313316
this.isOnlineLogProviderEnabled = getIsOnlineLogProviderEnabled(conf);
314317
this.scheduler = scheduler;

0 commit comments

Comments
 (0)