JAL-3275 JAL-3633: JAL-3275 Turned Preferences into a Singleton that checks renews...
[jalview.git] / src / jalview / bin / Cache.java
index 8269f32..e96fef1 100755 (executable)
@@ -34,6 +34,7 @@ import java.net.PasswordAuthentication;
 import java.net.URL;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
 import java.util.Enumeration;
@@ -54,7 +55,6 @@ import org.apache.log4j.SimpleLayout;
 import jalview.datamodel.PDBEntry;
 import jalview.gui.Preferences;
 import jalview.gui.UserDefinedColours;
-import jalview.jbgui.GPreferences;
 import jalview.schemes.ColourSchemeLoader;
 import jalview.schemes.ColourSchemes;
 import jalview.schemes.UserColourScheme;
@@ -1316,17 +1316,28 @@ public class Cache
   {
     String proxyType = Cache.getDefault("USE_PROXY",
             Cache.PROXYTYPE_SYSTEM);
-    if (proxyType.equals(Cache.PROXYTYPE_NONE))
+    if (previousProxyType != null
+            && !proxyType.equals(Cache.PROXYTYPE_CUSTOM) // always apply
+                                                         // customProxy
+            && proxyType.equals(previousProxyType))
     {
-      if (!previousProxyType.equals(proxyType))
-        Cache.log.info("Setting no proxy settings");
-      Cache.setProxyProperties(null, null, null, null, null, null, null,
-              null, null);
+      // no change
+      return;
     }
-    else if (proxyType.equals(Cache.PROXYTYPE_CUSTOM))
+    switch (proxyType)
     {
+    case Cache.PROXYTYPE_NONE:
       if (!previousProxyType.equals(proxyType))
-        Cache.log.info("Setting custom proxy settings");
+      {
+        Cache.log.info("Setting no proxy settings");
+        Cache.setProxyProperties(null, null, null, null, null, null, null,
+                null, null);
+      }
+      break;
+    case Cache.PROXYTYPE_CUSTOM:
+      // always re-set a custom proxy -- it might have changed, particularly
+      // password
+      Cache.log.info("Setting custom proxy settings");
       boolean proxyAuthSet = Cache.getDefault("PROXY_AUTH", false);
       Cache.setProxyProperties(Cache.getDefault("PROXY_SERVER", null),
               Cache.getDefault("PROXY_PORT", null),
@@ -1338,11 +1349,9 @@ public class Cache
               proxyAuthSet ? Cache.getDefault("PROXY_AUTH_USERNAME", "")
                       : null,
               proxyAuthSet ? Cache.proxyAuthPassword : null, "localhost");
-    }
-    else // systemProxy should be selected and is sensible default anyway
-    {
-      if (!previousProxyType.equals(proxyType))
-        Cache.log.info("Setting system proxy settings");
+      break;
+    default: // system proxy settings by default
+      Cache.log.info("Setting system proxy settings");
       Cache.resetProxyProperties();
     }
   }
@@ -1357,39 +1366,54 @@ public class Cache
     setOrClearSystemProperty("https.proxyHost", httpsHost);
     setOrClearSystemProperty("https.proxyPort", httpsPort);
     setOrClearSystemProperty("http.proxyUser", httpUser);
-    setOrClearSystemProperty("http.proxyPassword", httpPassword);
     setOrClearSystemProperty("https.proxyUser", httpsUser);
-    setOrClearSystemProperty("https.proxyPassword", httpsPassword);
+    // note: passwords for http.proxyPassword and https.proxyPassword are sent
+    // via the Authenticator, properties do not need to be set
+
     // are we using a custom proxy (password prompt might be required)?
     boolean customProxySet = getDefault("USE_PROXY", PROXYTYPE_SYSTEM)
             .equals(PROXYTYPE_CUSTOM);
+
+    /*
+     * A bug in Java means the AuthCache does not get reset, so once it has working credentials,
+     * it never asks for more, so changing the Authenticator has no effect (as getPasswordAuthentication()
+     * is not re-called).
+     * This could lead to password leak to a hostile proxy server, so I'm putting in a hack to clear
+     * the AuthCache.
+     * see https://www.generacodice.com/en/articolo/154918/Reset-the-Authenticator-credentials
+     * ...
+     * Turns out this is only accessible in Java 8, and not in Java 9 onwards, so commenting out
+     */
+    /*
+    try
+    {
+      sun.net.www.protocol.http.AuthCacheValue
+              .setAuthCache(new sun.net.www.protocol.http.AuthCacheImpl());
+    } catch (Throwable t)
+    {
+      Cache.error(t.getMessage());
+      Cache.debug(getStackTraceString(t));
+    }
+    */
+
     if (httpUser != null || httpsUser != null)
     {
       try
       {
+        Cache.debug("CACHE Proxy: setting new Authenticator with httpUser='"
+                + httpUser + "' httpPassword='"
+                + (proxyAuthPassword == null ? "null"
+                        : new String(proxyAuthPassword))
+                + "'"); // DELETE THIS LINE (password in logs)
         Authenticator.setDefault(new Authenticator()
         {
           @Override
           protected PasswordAuthentication getPasswordAuthentication()
           {
-            Cache.debug(
-                    "*** START PasswordAuthentication.getPasswordAuthentication()");
-            Cache.debug("*** getRequestorType()=" + getRequestorType());
             if (getRequestorType() == RequestorType.PROXY)
             {
               String protocol = getRequestingProtocol();
               boolean needProxyPasswordSet = false;
-              Cache.debug("*** customProxySet = " + customProxySet);
-              Cache.debug("*** protocol = " + protocol);
-              Cache.debug("*** httpUser = " + httpUser);
-              Cache.debug(
-                      "*** httpPassword = \"" + (httpPassword == null ? null
-                              : new String(httpPassword)) + "\"");
-              Cache.debug("*** httpsUser = " + httpsUser);
-              Cache.debug("*** httpsPassword = \""
-                      + (httpsPassword == null ? null
-                              : new String(httpsPassword))
-                      + "\"");
               if (customProxySet &&
               // we have a username but no password for the scheme being
               // requested
@@ -1406,13 +1430,12 @@ public class Cache
                 // open Preferences -> Connections
                 String message = MessageManager
                         .getString("label.proxy_password_required");
-                Cache.debug("***+ TRYING TO OPEN PREFERENCES");
-                openPreferencesConnectionsForProxyPassword(message);
-                Cache.debug("***+ AFTER TRYING TO OPEN PREFERENCES");
+                Preferences.openPreferences(Preferences.CONNECTIONS_TAB,
+                        message);
+                Preferences.getPreferences().proxyAuthPasswordFocus();
               }
               else
               {
-                Cache.debug("***+ TRYING TO GET PASSWORDAUTHENTICATION");
                 try
                 {
                   if (protocol.equalsIgnoreCase("http")
@@ -1420,9 +1443,12 @@ public class Cache
                           && getRequestingPort() == Integer
                                   .valueOf(httpPort))
                   {
-                    Cache.debug("***+ RETURNING PasswordAuthentication(\""
-                            + httpUser + "\", \"" + new String(httpPassword)
-                            + "\"");
+                    char[] displayHttpPw = new char[httpPassword.length];
+                    Arrays.fill(displayHttpPw, '*');
+                    Cache.debug(
+                            "AUTHENTICATOR returning PasswordAuthentication(\""
+                                    + httpUser + "\", '"
+                                    + new String(displayHttpPw) + "')");
                     return new PasswordAuthentication(httpUser,
                             httpPassword);
                   }
@@ -1431,8 +1457,12 @@ public class Cache
                           && getRequestingPort() == Integer
                                   .valueOf(httpsPort))
                   {
-                    Cache.debug("***+ RETURNING PasswordAuthentication(\""
-                            + httpsUser + "\", \"" + httpsPassword + "\"");
+                    char[] displayHttpsPw = new char[httpPassword.length];
+                    Arrays.fill(displayHttpsPw, '*');
+                    Cache.debug(
+                            "AUTHENTICATOR returning PasswordAuthentication(\""
+                                    + httpsUser + "\", '" + displayHttpsPw
+                                    + "'");
                     return new PasswordAuthentication(httpsUser,
                             httpsPassword);
                   }
@@ -1442,18 +1472,18 @@ public class Cache
                           + httpPort + ", https:" + httpsPort + "]");
                 }
                 Cache.debug(
-                        "***+ AFTER TRYING TO GET PASSWORDAUTHENTICATION");
+                        "AUTHENTICATOR after trying to get PasswordAuthentication");
               }
             }
             // non proxy request
-            Cache.debug("***+ Returning null");
+            Cache.debug("AUTHENTICATOR returning null");
             return null;
           }
         });
         // required to re-enable basic authentication (should be okay for a
         // local proxy)
         Cache.debug(
-                "***+ Setting jdk.http.auth.tunneling.disabledSchemes to ''");
+                "AUTHENTICATOR setting property 'jdk.http.auth.tunneling.disabledSchemes' to \"\"");
         System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
       } catch (SecurityException e)
       {
@@ -1465,27 +1495,16 @@ public class Cache
     {
       // reset the Authenticator to protect http.proxyUser and
       // http.proxyPassword Just In Case
-      Cache.debug("***+ Setting default Authenticator to null");
+      Cache.debug("AUTHENTICATOR setting default Authenticator to null");
       Authenticator.setDefault(null);
     }
 
     // nonProxyHosts not currently configurable in Preferences
-    Cache.debug("***+ Setting http.nonProxyHosts property to \""
+    Cache.debug("AUTHENTICATOR setting property 'http.nonProxyHosts' to \""
             + nonProxyHosts + "\"");
     setOrClearSystemProperty("http.nonProxyHosts", nonProxyHosts);
   }
 
-  private static void openPreferencesConnectionsForProxyPassword(
-          String message)
-  {
-    //
-    Cache.info("Opening Preferences for proxy password");
-    // Desktop.instance.preferences_actionPerformed(null);
-    Cache.debug("***+########## TRYING TO OPEN PREFERENCES: " + message);
-    Preferences p = new Preferences(GPreferences.CONNECTIONS_TAB, message);
-    p.grabFocus();
-  }
-
   public static void setOrClearSystemProperty(String key, char[] value)
   {
     setOrClearSystemProperty(key,