2121import java .io .IOException ;
2222import java .net .InetAddress ;
2323import java .net .Socket ;
24- import java .net .SocketException ;
2524import java .security .KeyManagementException ;
2625import java .security .NoSuchAlgorithmException ;
2726import java .util .ArrayList ;
3130import javax .net .ssl .SSLSocket ;
3231import javax .net .ssl .SSLSocketFactory ;
3332
33+ import com .google .common .annotations .VisibleForTesting ;
3434import org .slf4j .Logger ;
3535import org .slf4j .LoggerFactory ;
36- import org .wildfly .openssl .OpenSSLProvider ;
37- import org .wildfly .openssl .SSL ;
38-
3936
4037/**
4138 * A {@link SSLSocketFactory} that can delegate to various SSL implementations.
6057 * </p>
6158 *
6259 * In order to load OpenSSL, applications must ensure the wildfly-openssl
63- * artifact is on the classpath. Currently, only ABFS and S3A provide
64- * wildfly-openssl as a runtime dependency.
60+ * artifact is on the classpath. Currently, only ABFS declares
61+ * wildfly-openssl as an explicit dependency.
6562 */
6663public final class DelegatingSSLSocketFactory extends SSLSocketFactory {
6764
@@ -110,7 +107,16 @@ public static synchronized void initializeDefaultFactory(
110107 }
111108
112109 /**
113- * Singletone instance of the SSLSocketFactory.
110+ * For testing only: reset the socket factory.
111+ */
112+ @ VisibleForTesting
113+ public static synchronized void resetDefaultFactory () {
114+ LOG .info ("Resetting default SSL Socket Factory" );
115+ instance = null ;
116+ }
117+
118+ /**
119+ * Singleton instance of the SSLSocketFactory.
114120 *
115121 * SSLSocketFactory must be initialized with appropriate SSLChannelMode
116122 * using initializeDefaultFactory method.
@@ -126,9 +132,7 @@ private DelegatingSSLSocketFactory(SSLChannelMode preferredChannelMode)
126132 throws IOException {
127133 try {
128134 initializeSSLContext (preferredChannelMode );
129- } catch (NoSuchAlgorithmException e ) {
130- throw new IOException (e );
131- } catch (KeyManagementException e ) {
135+ } catch (NoSuchAlgorithmException | KeyManagementException e ) {
132136 throw new IOException (e );
133137 }
134138
@@ -146,42 +150,23 @@ private DelegatingSSLSocketFactory(SSLChannelMode preferredChannelMode)
146150 }
147151
148152 private void initializeSSLContext (SSLChannelMode preferredChannelMode )
149- throws NoSuchAlgorithmException , KeyManagementException {
153+ throws NoSuchAlgorithmException , KeyManagementException , IOException {
154+ LOG .debug ("Initializing SSL Context to channel mode {}" ,
155+ preferredChannelMode );
150156 switch (preferredChannelMode ) {
151157 case Default :
152- if (!openSSLProviderRegistered ) {
153- OpenSSLProvider .register ();
154- openSSLProviderRegistered = true ;
155- }
156158 try {
157- java .util .logging .Logger logger = java .util .logging .Logger .getLogger (
158- SSL .class .getName ());
159- logger .setLevel (Level .WARNING );
160- ctx = SSLContext .getInstance ("openssl.TLS" );
161- ctx .init (null , null , null );
162- // Strong reference needs to be kept to logger until initialization of
163- // SSLContext finished (see HADOOP-16174):
164- logger .setLevel (Level .INFO );
159+ bindToOpenSSLProvider ();
165160 channelMode = SSLChannelMode .OpenSSL ;
166- } catch (NoSuchAlgorithmException e ) {
167- LOG .debug ("Failed to load OpenSSL. Falling back to the JSSE default." );
161+ } catch (LinkageError | NoSuchAlgorithmException | RuntimeException e ) {
162+ LOG .debug ("Failed to load OpenSSL. Falling back to the JSSE default." ,
163+ e );
168164 ctx = SSLContext .getDefault ();
169165 channelMode = SSLChannelMode .Default_JSSE ;
170166 }
171167 break ;
172168 case OpenSSL :
173- if (!openSSLProviderRegistered ) {
174- OpenSSLProvider .register ();
175- openSSLProviderRegistered = true ;
176- }
177- java .util .logging .Logger logger = java .util .logging .Logger .getLogger (
178- SSL .class .getName ());
179- logger .setLevel (Level .WARNING );
180- ctx = SSLContext .getInstance ("openssl.TLS" );
181- ctx .init (null , null , null );
182- // Strong reference needs to be kept to logger until initialization of
183- // SSLContext finished (see HADOOP-16174):
184- logger .setLevel (Level .INFO );
169+ bindToOpenSSLProvider ();
185170 channelMode = SSLChannelMode .OpenSSL ;
186171 break ;
187172 case Default_JSSE :
@@ -193,11 +178,38 @@ private void initializeSSLContext(SSLChannelMode preferredChannelMode)
193178 channelMode = SSLChannelMode .Default_JSSE_with_GCM ;
194179 break ;
195180 default :
196- throw new NoSuchAlgorithmException ("Unknown channel mode: "
181+ throw new IOException ("Unknown channel mode: "
197182 + preferredChannelMode );
198183 }
199184 }
200185
186+ /**
187+ * Bind to the OpenSSL provider via wildfly.
188+ * This MUST be the only place where wildfly classes are referenced,
189+ * so ensuring that any linkage problems only surface here where they may
190+ * be caught by the initialization code.
191+ */
192+ private void bindToOpenSSLProvider ()
193+ throws NoSuchAlgorithmException , KeyManagementException {
194+ if (!openSSLProviderRegistered ) {
195+ LOG .debug ("Attempting to register OpenSSL provider" );
196+ org .wildfly .openssl .OpenSSLProvider .register ();
197+ openSSLProviderRegistered = true ;
198+ }
199+ // Strong reference needs to be kept to logger until initialization of
200+ // SSLContext finished (see HADOOP-16174):
201+ java .util .logging .Logger logger = java .util .logging .Logger .getLogger (
202+ "org.wildfly.openssl.SSL" );
203+ Level originalLevel = logger .getLevel ();
204+ try {
205+ logger .setLevel (Level .WARNING );
206+ ctx = SSLContext .getInstance ("openssl.TLS" );
207+ ctx .init (null , null , null );
208+ } finally {
209+ logger .setLevel (originalLevel );
210+ }
211+ }
212+
201213 public String getProviderName () {
202214 return providerName ;
203215 }
@@ -212,86 +224,80 @@ public String[] getSupportedCipherSuites() {
212224 return ciphers .clone ();
213225 }
214226
227+ /**
228+ * Get the channel mode of this instance.
229+ * @return a channel mode.
230+ */
231+ public SSLChannelMode getChannelMode () {
232+ return channelMode ;
233+ }
234+
215235 public Socket createSocket () throws IOException {
216236 SSLSocketFactory factory = ctx .getSocketFactory ();
217- SSLSocket ss = (SSLSocket ) factory .createSocket ();
218- configureSocket (ss );
219- return ss ;
237+ return configureSocket (factory .createSocket ());
220238 }
221239
222240 @ Override
223241 public Socket createSocket (Socket s , String host , int port ,
224242 boolean autoClose ) throws IOException {
225243 SSLSocketFactory factory = ctx .getSocketFactory ();
226- SSLSocket ss = (SSLSocket ) factory .createSocket (s , host , port , autoClose );
227244
228- configureSocket (ss );
229- return ss ;
245+ return configureSocket (
246+ factory . createSocket ( s , host , port , autoClose )) ;
230247 }
231248
232249 @ Override
233250 public Socket createSocket (InetAddress address , int port ,
234251 InetAddress localAddress , int localPort )
235252 throws IOException {
236253 SSLSocketFactory factory = ctx .getSocketFactory ();
237- SSLSocket ss = (SSLSocket ) factory
238- .createSocket (address , port , localAddress , localPort );
239-
240- configureSocket (ss );
241- return ss ;
254+ return configureSocket (factory
255+ .createSocket (address , port , localAddress , localPort ));
242256 }
243257
244258 @ Override
245259 public Socket createSocket (String host , int port , InetAddress localHost ,
246260 int localPort ) throws IOException {
247261 SSLSocketFactory factory = ctx .getSocketFactory ();
248- SSLSocket ss = (SSLSocket ) factory
249- .createSocket (host , port , localHost , localPort );
250262
251- configureSocket (ss );
252-
253- return ss ;
263+ return configureSocket (factory
264+ .createSocket (host , port , localHost , localPort ));
254265 }
255266
256267 @ Override
257268 public Socket createSocket (InetAddress host , int port ) throws IOException {
258269 SSLSocketFactory factory = ctx .getSocketFactory ();
259- SSLSocket ss = (SSLSocket ) factory .createSocket (host , port );
260-
261- configureSocket (ss );
262270
263- return ss ;
271+ return configureSocket ( factory . createSocket ( host , port )) ;
264272 }
265273
266274 @ Override
267275 public Socket createSocket (String host , int port ) throws IOException {
268276 SSLSocketFactory factory = ctx .getSocketFactory ();
269- SSLSocket ss = (SSLSocket ) factory .createSocket (host , port );
270-
271- configureSocket (ss );
272277
273- return ss ;
278+ return configureSocket ( factory . createSocket ( host , port )) ;
274279 }
275280
276- private void configureSocket (SSLSocket ss ) throws SocketException {
277- ss .setEnabledCipherSuites (ciphers );
281+ private Socket configureSocket (Socket socket ) {
282+ ((SSLSocket ) socket ).setEnabledCipherSuites (ciphers );
283+ return socket ;
278284 }
279285
280286 private String [] alterCipherList (String [] defaultCiphers ) {
281287
282- ArrayList <String > preferredSuits = new ArrayList <>();
288+ ArrayList <String > preferredSuites = new ArrayList <>();
283289
284290 // Remove GCM mode based ciphers from the supported list.
285291 for (int i = 0 ; i < defaultCiphers .length ; i ++) {
286292 if (defaultCiphers [i ].contains ("_GCM_" )) {
287293 LOG .debug ("Removed Cipher - {} from list of enabled SSLSocket ciphers" ,
288294 defaultCiphers [i ]);
289295 } else {
290- preferredSuits .add (defaultCiphers [i ]);
296+ preferredSuites .add (defaultCiphers [i ]);
291297 }
292298 }
293299
294- ciphers = preferredSuits .toArray (new String [0 ]);
300+ ciphers = preferredSuites .toArray (new String [0 ]);
295301 return ciphers ;
296302 }
297- }
303+ }
0 commit comments