@@ -158,6 +158,7 @@ public class SaslAuthenticatorTest {
158
158
private static final long CONNECTIONS_MAX_REAUTH_MS_VALUE = 100L ;
159
159
private static final int BUFFER_SIZE = 4 * 1024 ;
160
160
private static Time time = Time .SYSTEM ;
161
+ private static boolean needLargeExpiration = false ;
161
162
162
163
private NioEchoServer server ;
163
164
private Selector selector ;
@@ -181,6 +182,7 @@ public void setup() throws Exception {
181
182
182
183
@ AfterEach
183
184
public void teardown () throws Exception {
185
+ needLargeExpiration = false ;
184
186
if (server != null )
185
187
this .server .close ();
186
188
if (selector != null )
@@ -1610,6 +1612,42 @@ public void testCannotReauthenticateWithDifferentPrincipal() throws Exception {
1610
1612
server .verifyReauthenticationMetrics (0 , 1 );
1611
1613
}
1612
1614
1615
+ @ Test
1616
+ public void testReauthenticateWithLargeReauthValue () throws Exception {
1617
+ // enable it, we'll get a large expiration timestamp token
1618
+ needLargeExpiration = true ;
1619
+ String node = "0" ;
1620
+ SecurityProtocol securityProtocol = SecurityProtocol .SASL_SSL ;
1621
+
1622
+ configureMechanisms (OAuthBearerLoginModule .OAUTHBEARER_MECHANISM ,
1623
+ List .of (OAuthBearerLoginModule .OAUTHBEARER_MECHANISM ));
1624
+ // set a large re-auth timeout in server side
1625
+ saslServerConfigs .put (BrokerSecurityConfigs .CONNECTIONS_MAX_REAUTH_MS_CONFIG , Long .MAX_VALUE );
1626
+ server = createEchoServer (securityProtocol );
1627
+
1628
+ // set to default value for sasl login configs for initialization in ExpiringCredentialRefreshConfig
1629
+ saslClientConfigs .put (SaslConfigs .SASL_LOGIN_REFRESH_WINDOW_FACTOR , SaslConfigs .DEFAULT_LOGIN_REFRESH_WINDOW_FACTOR );
1630
+ saslClientConfigs .put (SaslConfigs .SASL_LOGIN_REFRESH_WINDOW_JITTER , SaslConfigs .DEFAULT_LOGIN_REFRESH_WINDOW_JITTER );
1631
+ saslClientConfigs .put (SaslConfigs .SASL_LOGIN_REFRESH_MIN_PERIOD_SECONDS , SaslConfigs .DEFAULT_LOGIN_REFRESH_MIN_PERIOD_SECONDS );
1632
+ saslClientConfigs .put (SaslConfigs .SASL_LOGIN_REFRESH_BUFFER_SECONDS , SaslConfigs .DEFAULT_LOGIN_REFRESH_BUFFER_SECONDS );
1633
+ saslClientConfigs .put (SaslConfigs .SASL_LOGIN_CALLBACK_HANDLER_CLASS , AlternateLoginCallbackHandler .class );
1634
+
1635
+ createCustomClientConnection (securityProtocol , OAuthBearerLoginModule .OAUTHBEARER_MECHANISM , node , true );
1636
+
1637
+ // channel should be not null before sasl handshake
1638
+ assertNotNull (selector .channel (node ));
1639
+
1640
+ TestUtils .waitForCondition (() -> {
1641
+ selector .poll (1000 );
1642
+ // this channel should be closed due to session timeout calculation overflow
1643
+ return selector .channel (node ) == null ;
1644
+ }, "channel didn't close with large re-authentication value" );
1645
+
1646
+ // ensure metrics are as expected
1647
+ server .verifyAuthenticationMetrics (0 , 0 );
1648
+ server .verifyReauthenticationMetrics (0 , 0 );
1649
+ }
1650
+
1613
1651
@ Test
1614
1652
public void testCorrelationId () {
1615
1653
SaslClientAuthenticator authenticator = new SaslClientAuthenticator (
@@ -2002,7 +2040,7 @@ private void createClientConnection(SecurityProtocol securityProtocol, String sa
2002
2040
if (enableSaslAuthenticateHeader )
2003
2041
createClientConnection (securityProtocol , node );
2004
2042
else
2005
- createClientConnectionWithoutSaslAuthenticateHeader (securityProtocol , saslMechanism , node );
2043
+ createCustomClientConnection (securityProtocol , saslMechanism , node , false );
2006
2044
}
2007
2045
2008
2046
private NioEchoServer startServerApiVersionsUnsupportedByClient (final SecurityProtocol securityProtocol , String saslMechanism ) throws Exception {
@@ -2090,15 +2128,13 @@ protected void enableKafkaSaslAuthenticateHeaders(boolean flag) {
2090
2128
return server ;
2091
2129
}
2092
2130
2093
- private void createClientConnectionWithoutSaslAuthenticateHeader (final SecurityProtocol securityProtocol ,
2094
- final String saslMechanism , String node ) throws Exception {
2095
-
2096
- final ListenerName listenerName = ListenerName .forSecurityProtocol (securityProtocol );
2097
- final Map <String , ?> configs = Collections .emptyMap ();
2098
- final JaasContext jaasContext = JaasContext .loadClientContext (configs );
2099
- final Map <String , JaasContext > jaasContexts = Collections .singletonMap (saslMechanism , jaasContext );
2100
-
2101
- SaslChannelBuilder clientChannelBuilder = new SaslChannelBuilder (ConnectionMode .CLIENT , jaasContexts ,
2131
+ private SaslChannelBuilder saslChannelBuilderWithoutHeader (
2132
+ final SecurityProtocol securityProtocol ,
2133
+ final String saslMechanism ,
2134
+ final Map <String , JaasContext > jaasContexts ,
2135
+ final ListenerName listenerName
2136
+ ) {
2137
+ return new SaslChannelBuilder (ConnectionMode .CLIENT , jaasContexts ,
2102
2138
securityProtocol , listenerName , false , saslMechanism ,
2103
2139
null , null , null , time , new LogContext (), null ) {
2104
2140
@@ -2125,6 +2161,42 @@ protected void setSaslAuthenticateAndHandshakeVersions(ApiVersionsResponse apiVe
2125
2161
};
2126
2162
}
2127
2163
};
2164
+ }
2165
+
2166
+ private void createCustomClientConnection (
2167
+ final SecurityProtocol securityProtocol ,
2168
+ final String saslMechanism ,
2169
+ String node ,
2170
+ boolean withSaslAuthenticateHeader
2171
+ ) throws Exception {
2172
+
2173
+ final ListenerName listenerName = ListenerName .forSecurityProtocol (securityProtocol );
2174
+ final Map <String , ?> configs = Collections .emptyMap ();
2175
+ final JaasContext jaasContext = JaasContext .loadClientContext (configs );
2176
+ final Map <String , JaasContext > jaasContexts = Collections .singletonMap (saslMechanism , jaasContext );
2177
+
2178
+ SaslChannelBuilder clientChannelBuilder ;
2179
+ if (!withSaslAuthenticateHeader ) {
2180
+ clientChannelBuilder = saslChannelBuilderWithoutHeader (securityProtocol , saslMechanism , jaasContexts , listenerName );
2181
+ } else {
2182
+ clientChannelBuilder = new SaslChannelBuilder (ConnectionMode .CLIENT , jaasContexts ,
2183
+ securityProtocol , listenerName , false , saslMechanism ,
2184
+ null , null , null , time , new LogContext (), null ) {
2185
+
2186
+ @ Override
2187
+ protected SaslClientAuthenticator buildClientAuthenticator (Map <String , ?> configs ,
2188
+ AuthenticateCallbackHandler callbackHandler ,
2189
+ String id ,
2190
+ String serverHost ,
2191
+ String servicePrincipal ,
2192
+ TransportLayer transportLayer ,
2193
+ Subject subject ) {
2194
+
2195
+ return new SaslClientAuthenticator (configs , callbackHandler , id , subject ,
2196
+ servicePrincipal , serverHost , saslMechanism , transportLayer , time , new LogContext ());
2197
+ }
2198
+ };
2199
+ }
2128
2200
clientChannelBuilder .configure (saslClientConfigs );
2129
2201
this .selector = NetworkTestUtils .createSelector (clientChannelBuilder , time );
2130
2202
InetSocketAddress addr = new InetSocketAddress ("localhost" , server .port ());
@@ -2581,10 +2653,11 @@ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallback
2581
2653
+ ++numInvocations ;
2582
2654
String headerJson = "{" + claimOrHeaderJsonText ("alg" , "none" ) + "}" ;
2583
2655
/*
2584
- * Use a short lifetime so the background refresh thread replaces it before we
2656
+ * If we're testing large expiration scenario, use a large lifetime.
2657
+ * Otherwise, use a short lifetime so the background refresh thread replaces it before we
2585
2658
* re-authenticate
2586
2659
*/
2587
- String lifetimeSecondsValueToUse = "1" ;
2660
+ String lifetimeSecondsValueToUse = needLargeExpiration ? String . valueOf ( Long . MAX_VALUE ) : "1" ;
2588
2661
String claimsJson ;
2589
2662
try {
2590
2663
claimsJson = String .format ("{%s,%s,%s}" ,
0 commit comments