Ensure only safe redirects are followed and simplify connection handling

NetBeans did follow redirects even if a protocol change happened. In
this case the user is not aware, that a download potentially drops from
https to http. Instead protocol changes are only allowed, if the
originating URL is insecure (http).

Instead of trying to handle the SSL/TLS trust internally, the default
JDK mechanisms for handling SSL/TLS connections are now used and the
connection configuration code was centralized.
diff --git a/platform/autoupdate.services/src/org/netbeans/modules/autoupdate/services/InstallSupportImpl.java b/platform/autoupdate.services/src/org/netbeans/modules/autoupdate/services/InstallSupportImpl.java
index 5098c28..1644392 100644
--- a/platform/autoupdate.services/src/org/netbeans/modules/autoupdate/services/InstallSupportImpl.java
+++ b/platform/autoupdate.services/src/org/netbeans/modules/autoupdate/services/InstallSupportImpl.java
@@ -924,9 +924,10 @@
             String label) throws MalformedURLException, IOException {
         
         OpenConnectionListener listener = new OpenConnectionListener(source);
-        final Task task = NetworkAccess.createNetworkAcessTask(source,
+        final Task task = NetworkAccess.createNetworkAccessTask(source,
                 AutoupdateSettings.getOpenConnectionTimeout(),
-                listener);
+                listener,
+                false);
         new Thread(new Runnable() {
             @SuppressWarnings("SleepWhileInLoop")
             @Override
diff --git a/platform/autoupdate.services/src/org/netbeans/modules/autoupdate/updateprovider/AutoupdateCatalogCache.java b/platform/autoupdate.services/src/org/netbeans/modules/autoupdate/updateprovider/AutoupdateCatalogCache.java
index ab94735..ba81ccd 100644
--- a/platform/autoupdate.services/src/org/netbeans/modules/autoupdate/updateprovider/AutoupdateCatalogCache.java
+++ b/platform/autoupdate.services/src/org/netbeans/modules/autoupdate/updateprovider/AutoupdateCatalogCache.java
@@ -216,7 +216,7 @@
 
         DownloadListener nwl = new DownloadListener(sourceUrl, temp, allowZeroSize);
         
-        NetworkAccess.Task task = NetworkAccess.createNetworkAcessTask (sourceUrl, AutoupdateSettings.getOpenConnectionTimeout (), nwl);
+        NetworkAccess.Task task = NetworkAccess.createNetworkAccessTask (sourceUrl, AutoupdateSettings.getOpenConnectionTimeout (), nwl, true);
         task.waitFinished ();
         nwl.notifyException ();
         synchronized(getLock(cache)) {
diff --git a/platform/autoupdate.services/src/org/netbeans/modules/autoupdate/updateprovider/NetworkAccess.java b/platform/autoupdate.services/src/org/netbeans/modules/autoupdate/updateprovider/NetworkAccess.java
index c79154a..1560eda 100644
--- a/platform/autoupdate.services/src/org/netbeans/modules/autoupdate/updateprovider/NetworkAccess.java
+++ b/platform/autoupdate.services/src/org/netbeans/modules/autoupdate/updateprovider/NetworkAccess.java
@@ -24,10 +24,6 @@
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.net.URLConnection;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.security.cert.X509Certificate;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
@@ -40,12 +36,6 @@
 import java.util.concurrent.TimeoutException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
 import org.openide.util.Cancellable;
 import org.openide.util.NbBundle;
 import org.openide.util.RequestProcessor;
@@ -63,19 +53,20 @@
 
     private NetworkAccess () {}
     
-    public static Task createNetworkAcessTask (URL url, int timeout, NetworkListener networkAcesssListener) {
-        return new Task (url, timeout, networkAcesssListener);
+    public static Task createNetworkAccessTask (URL url, int timeout, NetworkListener networkAccessListener, boolean disableInsecureRedirects) {
+        return new Task (url, timeout, networkAccessListener, disableInsecureRedirects);
     }
     
     public static class Task implements Cancellable {
+        private final ExecutorService es = Executors.newSingleThreadExecutor();
+        private final boolean disableInsecureRedirects;
         private URL url;
         private int timeout;
         private NetworkListener listener;
-        private final ExecutorService es = Executors.newSingleThreadExecutor ();
         private Future<InputStream> connect = null;
         private RequestProcessor.Task rpTask = null;
         
-        private Task (URL url, int timeout, NetworkListener listener) {
+        private Task (URL url, int timeout, NetworkListener listener, boolean disableInsecureRedirects) {
             if (url == null) {
                 throw new IllegalArgumentException ("URL cannot be null.");
             }
@@ -85,6 +76,7 @@
             this.url = url;
             this.timeout = timeout;
             this.listener = listener;
+            this.disableInsecureRedirects = disableInsecureRedirects;
             postTask ();
         }
         
@@ -146,11 +138,7 @@
                 @Override
                 public InputStream call () throws Exception {
                     URLConnection conn = url.openConnection ();
-                    conn.setConnectTimeout (timeout);
-                    conn.setReadTimeout(timeout);
-                    if(conn instanceof HttpsURLConnection){
-                        NetworkAccess.initSSL((HttpsURLConnection) conn);
-                    }
+                    configureConnection(conn, timeout);
 
                     // handle redirection here
                     int redirCount = 0;
@@ -181,13 +169,52 @@
                 }
             };
         }
-        
+
         @Override
         public boolean cancel () {
-            return connect.cancel (true);
+            return connect.cancel(true);
         }
-        
+
+        private URLConnection checkRedirect(URLConnection conn, int timeout) throws IOException {
+            if (conn instanceof HttpURLConnection) {
+                conn.connect();
+                int code = ((HttpURLConnection) conn).getResponseCode();
+                boolean isInsecure = "http".equalsIgnoreCase(conn.getURL().getProtocol());
+                if (code == HttpURLConnection.HTTP_MOVED_TEMP
+                    || code == HttpURLConnection.HTTP_MOVED_PERM) {
+                    // in case of redirection, try to obtain new URL
+                    String redirUrl = conn.getHeaderField("Location"); //NOI18N
+                    if (null != redirUrl && !redirUrl.isEmpty()) {
+                        //create connection to redirected url and substitute original connection
+                        URL redirectedUrl = new URL(redirUrl);
+                        if (disableInsecureRedirects && (!isInsecure) && (!redirectedUrl.getProtocol().equalsIgnoreCase(conn.getURL().getProtocol()))) {
+                            throw new IOException(String.format(
+                                "Redirect from secure URL '%s' to '%s' blocked.",
+                                conn.getURL().toExternalForm(),
+                                redirectedUrl.toExternalForm()
+                            ));
+                        }
+                        URLConnection connRedir = redirectedUrl.openConnection();
+                        connRedir.setRequestProperty("User-Agent", "NetBeans"); // NOI18N
+                        connRedir.setConnectTimeout(timeout);
+                        connRedir.setReadTimeout(timeout);
+                        return connRedir;
+                    }
+                }
+            }
+            return conn;
+        }
+
+        private static void configureConnection(URLConnection conn, int timeout) {
+            if (conn instanceof HttpURLConnection) {
+                ((HttpURLConnection) conn).setInstanceFollowRedirects(false);
+            }
+            conn.setRequestProperty("User-Agent", "NetBeans");
+            conn.setConnectTimeout(timeout);
+            conn.setReadTimeout(timeout);
+        }
     }
+
     private interface SizedConnection extends Callable<InputStream> {
         public int getContentLength();
     }
@@ -197,67 +224,4 @@
         public void accessTimeOut ();
         public void notifyException (Exception x);
     }
-    
-    public static void initSSL(HttpURLConnection httpCon) throws IOException {
-        if (httpCon instanceof HttpsURLConnection) {
-            HttpsURLConnection https = (HttpsURLConnection) httpCon;
-
-            try {
-                TrustManager[] trustAllCerts = new TrustManager[]{
-                    new X509TrustManager() {
-                        @Override
-                        public X509Certificate[] getAcceptedIssuers() {
-                            return new X509Certificate[0];
-                        }
-
-                        @Override
-                        public void checkClientTrusted(X509Certificate[] certs, String authType) {
-                        }
-
-                        @Override
-                        public void checkServerTrusted(X509Certificate[] certs, String authType) {
-                        }
-                    }};
-                SSLContext sslContext = SSLContext.getInstance("SSL"); // NOI18N
-                sslContext.init(null, trustAllCerts, new SecureRandom());
-                https.setHostnameVerifier(new HostnameVerifier() {
-                    @Override
-                    public boolean verify(String hostname, SSLSession session) {
-                        return true;
-                    }
-                });
-                https.setSSLSocketFactory(sslContext.getSocketFactory());
-            } catch (KeyManagementException ex) {
-                throw new IOException(ex);
-            } catch (NoSuchAlgorithmException ex) {
-                throw new IOException(ex);
-            }
-        }
-    }
-
-    private static URLConnection checkRedirect(URLConnection conn, int timeout) throws IOException {
-        if (conn instanceof HttpURLConnection) {
-            conn.connect();
-            int code = ((HttpURLConnection) conn).getResponseCode();
-            if (code == HttpURLConnection.HTTP_MOVED_TEMP
-                    || code == HttpURLConnection.HTTP_MOVED_PERM) {
-                // in case of redirection, try to obtain new URL
-                String redirUrl = conn.getHeaderField("Location"); //NOI18N
-                if (null != redirUrl && !redirUrl.isEmpty()) {
-                    //create connection to redirected url and substitute original conn
-                    URL redirectedUrl = new URL(redirUrl);
-                    URLConnection connRedir = redirectedUrl.openConnection();
-                    // XXX is this neede
-                    connRedir.setRequestProperty("User-Agent", "NetBeans"); // NOI18N
-                    connRedir.setConnectTimeout(timeout);
-                    connRedir.setReadTimeout(timeout);
-                    if (connRedir instanceof HttpsURLConnection) {
-                        NetworkAccess.initSSL((HttpsURLConnection) connRedir);
-                    }
-                    return connRedir;
-                }
-            }
-        }
-        return conn;
-    }
 }