2525import java .security .NoSuchAlgorithmException ;
2626import java .security .cert .CertificateException ;
2727import javax .net .ssl .SSLContext ;
28+
29+ import com .google .common .base .Splitter ;
30+ import com .google .common .collect .Iterables ;
2831import org .apache .hadoop .hive .metastore .api .MetaException ;
2932import org .apache .hadoop .hive .metastore .security .DelegationTokenIdentifier ;
3033import org .apache .hadoop .hive .metastore .security .DelegationTokenSelector ;
6265import javax .security .auth .login .AppConfigurationEntry .LoginModuleControlFlag ;
6366import java .io .IOException ;
6467import java .net .InetSocketAddress ;
65- import java .net .UnknownHostException ;
6668import java .security .KeyStore ;
6769
6870import java .util .ArrayList ;
6971import java .util .Arrays ;
7072import java .util .HashMap ;
7173import java .util .List ;
7274import java .util .Map ;
75+ import java .util .Set ;
76+ import java .util .stream .Collectors ;
7377
7478public class SecurityUtils {
7579 private static final Logger LOG = LoggerFactory .getLogger (SecurityUtils .class );
@@ -278,17 +282,61 @@ public static TServerSocket getServerSocket(String hiveHost, int portNum) throws
278282 return new TServerSocket (serverAddress );
279283 }
280284
285+ public static String [] parseIncludeProtocols (String protocols ) {
286+ return Iterables .toArray (Splitter .on ("," ).trimResults ().omitEmptyStrings ()
287+ .split (protocols ), String .class );
288+ }
289+
290+ public static String [] parseIncludeCipherSuites (String cipherSuites ) {
291+ return Iterables .toArray (Splitter .on (":" ).trimResults ().omitEmptyStrings ()
292+ .split (cipherSuites ), String .class );
293+ }
294+
295+ private static String [] filterEnabledProtocols (String [] enabledProtocols ,
296+ String includeProtocols ) throws TTransportException {
297+ String [] filteredProtocols = enabledProtocols ;
298+ String [] parsedIncludeProtocols = parseIncludeProtocols (includeProtocols );
299+ if (parsedIncludeProtocols .length > 0 ) {
300+ Set <String > protocolsLowerCase = Arrays .stream (parsedIncludeProtocols ).map (String ::toLowerCase )
301+ .collect (Collectors .toSet ());
302+ filteredProtocols = Arrays .stream (enabledProtocols ).filter (protocol ->
303+ protocolsLowerCase .contains (protocol .toLowerCase ())).toArray (String []::new );
304+ }
305+ if (filteredProtocols .length == 0 ) {
306+ throw new TTransportException ("No TLS protocols to enable. "
307+ + "Protocols configured to include: " + Arrays .toString (parsedIncludeProtocols )
308+ + ", Protocols allowed to enable: " + Arrays .toString (enabledProtocols ));
309+ }
310+ return filteredProtocols ;
311+ }
312+
313+ private static TSSLTransportFactory .TSSLTransportParameters getSSLTransportParameters (boolean isKeyStore ,
314+ String storePath , String storePassword , String storeAlgorithm , String storeType , String includeCipherSuites ) {
315+ TSSLTransportFactory .TSSLTransportParameters params ;
316+ String [] parsedCipherSuites = parseIncludeCipherSuites (includeCipherSuites );
317+ if (parsedCipherSuites .length > 0 ) {
318+ params = new TSSLTransportFactory .TSSLTransportParameters ("TLS" , parsedCipherSuites );
319+ } else {
320+ params = new TSSLTransportFactory .TSSLTransportParameters ();
321+ }
322+ if (isKeyStore ) {
323+ params .setKeyStore (storePath , storePassword , storeAlgorithm , storeType );
324+ } else {
325+ params .setTrustStore (storePath , storePassword , storeAlgorithm , storeType );
326+ params .requireClientAuth (true );
327+ }
328+ return params ;
329+ }
330+
281331 public static TServerSocket getServerSSLSocket (String hiveHost , int portNum , String keyStorePath ,
282- String keyStorePassWord , String keyStoreType , String keyStoreAlgorithm , List <String > sslVersionBlacklist )
283- throws TTransportException , UnknownHostException {
284- TSSLTransportFactory .TSSLTransportParameters params =
285- new TSSLTransportFactory .TSSLTransportParameters ();
286- String kStoreType = keyStoreType .isEmpty ()? KeyStore .getDefaultType () : keyStoreType ;
287- String kStoreAlgorithm = keyStoreAlgorithm .isEmpty ()?
288- KeyManagerFactory .getDefaultAlgorithm () : keyStoreAlgorithm ;
289- params .setKeyStore (keyStorePath , keyStorePassWord , kStoreAlgorithm , kStoreType );
332+ String keyStorePassWord , String keyStoreType , String keyStoreAlgorithm , List <String > sslVersionBlacklist ,
333+ String includeProtocols , String includeCipherSuites ) throws TTransportException {
334+ TSSLTransportFactory .TSSLTransportParameters params = getSSLTransportParameters (true ,
335+ keyStorePath , keyStorePassWord ,
336+ keyStoreAlgorithm .isEmpty () ? KeyManagerFactory .getDefaultAlgorithm () : keyStoreAlgorithm ,
337+ keyStoreType .isEmpty () ? KeyStore .getDefaultType () : keyStoreType , includeCipherSuites );
290338 InetSocketAddress serverAddress ;
291- if (hiveHost == null || hiveHost .isEmpty ()) {
339+ if (StringUtils .isEmpty (hiveHost )) {
292340 // Wildcard bind
293341 serverAddress = new InetSocketAddress (portNum );
294342 } else {
@@ -310,7 +358,12 @@ public static TServerSocket getServerSSLSocket(String hiveHost, int portNum, Str
310358 enabledProtocols .add (protocol );
311359 }
312360 }
313- sslServerSocket .setEnabledProtocols (enabledProtocols .toArray (new String [0 ]));
361+ if (enabledProtocols .isEmpty ()) {
362+ throw new TTransportException ("No TLS protocols to enable after discarding configured blacklist protocols. "
363+ + "Protocols allowed to enable: " + Arrays .toString (sslServerSocket .getEnabledProtocols ()));
364+ }
365+ sslServerSocket .setEnabledProtocols (filterEnabledProtocols (enabledProtocols .toArray (String []::new ),
366+ includeProtocols ));
314367 LOG .info ("SSL Server Socket Enabled Protocols: "
315368 + Arrays .toString (sslServerSocket .getEnabledProtocols ()));
316369 }
@@ -319,18 +372,16 @@ public static TServerSocket getServerSSLSocket(String hiveHost, int portNum, Str
319372
320373 public static TTransport getSSLSocket (String host , int port , int socketTimeout , int connectionTimeout ,
321374 String trustStorePath , String trustStorePassWord , String trustStoreType ,
322- String trustStoreAlgorithm ) throws TTransportException {
323- TSSLTransportFactory .TSSLTransportParameters params =
324- new TSSLTransportFactory .TSSLTransportParameters ();
325- String tStoreType = trustStoreType .isEmpty ()? KeyStore .getDefaultType () : trustStoreType ;
326- String tStoreAlgorithm = trustStoreAlgorithm .isEmpty ()?
327- TrustManagerFactory .getDefaultAlgorithm () : trustStoreAlgorithm ;
328- params .setTrustStore (trustStorePath , trustStorePassWord ,
329- tStoreAlgorithm , tStoreType );
330- params .requireClientAuth (true );
375+ String trustStoreAlgorithm , String includeProtocols , String includeCipherSuites ) throws TTransportException {
376+ TSSLTransportFactory .TSSLTransportParameters params = getSSLTransportParameters (false ,
377+ trustStorePath , trustStorePassWord ,
378+ trustStoreAlgorithm .isEmpty () ? TrustManagerFactory .getDefaultAlgorithm () : trustStoreAlgorithm ,
379+ trustStoreType .isEmpty () ? KeyStore .getDefaultType () : trustStoreType , includeCipherSuites );
331380 // The underlying SSLSocket object is bound to host:port with the given SO_TIMEOUT and
332381 // connection timeout and SSLContext created with the given params
333382 TSocket tSSLSocket = TSSLTransportFactory .getClientSocket (host , port , socketTimeout , params );
383+ SSLSocket sslSocket = (SSLSocket ) (tSSLSocket .getSocket ());
384+ sslSocket .setEnabledProtocols (filterEnabledProtocols (sslSocket .getEnabledProtocols (), includeProtocols ));
334385 tSSLSocket .setConnectTimeout (connectionTimeout );
335386 return getSSLSocketWithHttps (tSSLSocket );
336387 }
@@ -341,13 +392,17 @@ public static TTransport getSSLSocket(String host, int port, int socketTimeout,
341392 */
342393 public static THttpClient getThriftHttpsClient (String httpsUrl , String trustStorePath ,
343394 String trustStorePasswd , String trustStoreAlgorithm , String trustStoreType ,
395+ String includeProtocols , String includeCipherSuites ,
344396 HttpClientBuilder underlyingHttpClientBuilder ) throws TTransportException , IOException ,
345397 KeyStoreException , NoSuchAlgorithmException , CertificateException ,
346398 KeyManagementException {
347399 Preconditions .checkNotNull (underlyingHttpClientBuilder , "httpClientBuilder should not be null" );
348400 if (trustStoreType == null || trustStoreType .isEmpty ()) {
349401 trustStoreType = KeyStore .getDefaultType ();
350402 }
403+ if (trustStoreAlgorithm .isEmpty ()) {
404+ trustStoreAlgorithm = TrustManagerFactory .getDefaultAlgorithm ();
405+ }
351406 KeyStore sslTrustStore = KeyStore .getInstance (trustStoreType );
352407 try (FileInputStream fis = new FileInputStream (trustStorePath )) {
353408 sslTrustStore .load (fis , trustStorePasswd .toCharArray ());
@@ -356,8 +411,18 @@ public static THttpClient getThriftHttpsClient(String httpsUrl, String trustStor
356411 SSLContext sslContext =
357412 SSLContexts .custom ().setTrustManagerFactoryAlgorithm (trustStoreAlgorithm ).
358413 loadTrustMaterial (sslTrustStore , null ).build ();
414+ String [] protocols = null ;
415+ String [] parsedProtocols = parseIncludeProtocols (includeProtocols );
416+ if (parsedProtocols .length > 0 ) {
417+ protocols = parsedProtocols ;
418+ }
419+ String [] ciphers = null ;
420+ String [] parsedCipherSuites = parseIncludeCipherSuites (includeCipherSuites );
421+ if (parsedCipherSuites .length > 0 ) {
422+ ciphers = parsedCipherSuites ;
423+ }
359424 SSLConnectionSocketFactory socketFactory =
360- new SSLConnectionSocketFactory (sslContext , new DefaultHostnameVerifier (null ));
425+ new SSLConnectionSocketFactory (sslContext , protocols , ciphers , new DefaultHostnameVerifier (null ));
361426 final Registry <ConnectionSocketFactory > registry =
362427 RegistryBuilder .<ConnectionSocketFactory > create ().register ("https" , socketFactory )
363428 .build ();
0 commit comments