Well, this works, but it's ugly.
In your project's dependencies, add:
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.squareup.okhttp3:okhttp:3.6.0'
compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.0.2'
(you may already have the picasso
line — I am just making sure that you are on the latest version)
Next, add this class to your project (based on this answer):
public static class TLSSocketFactory extends SSLSocketFactory {
private SSLSocketFactory internalSSLSocketFactory;
public TLSSocketFactory(SSLSocketFactory delegate) throws
KeyManagementException, NoSuchAlgorithmException {
internalSSLSocketFactory = delegate;
}
@Override
public String[] getDefaultCipherSuites() {
return internalSSLSocketFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return internalSSLSocketFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose)
throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
}
@Override
public Socket createSocket(String host, int port) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
}
/*
* Utility methods
*/
private static Socket enableTLSOnSocket(Socket socket) {
if (socket != null && (socket instanceof SSLSocket)
&& isTLSServerEnabled((SSLSocket) socket)) { // skip the fix if server doesn't provide there TLS version
((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1.1", "TLSv1.2"});
}
return socket;
}
private static boolean isTLSServerEnabled(SSLSocket sslSocket) {
System.out.println("__prova__ :: " + sslSocket.getSupportedProtocols().toString());
for (String protocol : sslSocket.getSupportedProtocols()) {
if (protocol.equals("TLSv1.1") || protocol.equals("TLSv1.2")) {
return true;
}
}
return false;
}
}
(that class is public static
, and so is designed to be a nested class inside something else — just get rid of the static
if you want it to be a standalone class)
Then, in your class that is using Picasso, add this method, based on this issue comment:
public X509TrustManager provideX509TrustManager() {
try {
TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
factory.init((KeyStore) null);
TrustManager[] trustManagers = factory.getTrustManagers();
return (X509TrustManager) trustManagers[0];
}
catch (NoSuchAlgorithmException exception) {
Log.e(getClass().getSimpleName(), "not trust manager available", exception);
}
catch (KeyStoreException exception) {
Log.e(getClass().getSimpleName(), "not trust manager available", exception);
}
return null;
}
Finally, this code should successfully download your image:
SSLContext sslContext=SSLContext.getInstance("TLS");
sslContext.init(null, null, null);
SSLSocketFactory noSSLv3Factory;
if (Build.VERSION.SDK_INT<=Build.VERSION_CODES.KITKAT) {
noSSLv3Factory=new TLSSocketFactory(sslContext.getSocketFactory());
}
else {
noSSLv3Factory=sslContext.getSocketFactory();
}
OkHttpClient.Builder okb=new OkHttpClient.Builder()
.sslSocketFactory(noSSLv3Factory, provideX509TrustManager());
OkHttpClient ok=okb.build();
Picasso p=new Picasso.Builder(getActivity())
.downloader(new OkHttp3Downloader(ok))
.build();
p.load(
"https://sdo.gsfc.nasa.gov/assets/img/latest/latest_2048_HMIIC.jpg")
.fit().centerCrop()
.placeholder(R.drawable.owner_placeholder)
.error(R.drawable.owner_error).into(icon);
(where you would replace my fit()
and subsequent calls with the right ones for your project)
If you happen to know the people maintaining that NASA server... they really ought to upgrade their SSL support. Just sayin'.