JAL-3633 Added Proxy Authentication credentials in Preferences and set via java.net...
authorBen Soares <b.soares@dundee.ac.uk>
Wed, 22 Jul 2020 18:40:59 +0000 (19:40 +0100)
committerBen Soares <b.soares@dundee.ac.uk>
Thu, 12 Nov 2020 20:42:38 +0000 (20:42 +0000)
src/jalview/bin/Cache.java
src/jalview/gui/Preferences.java
src/jalview/jbgui/GPreferences.java

index 621b74b..6648099 100755 (executable)
@@ -29,6 +29,8 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
 import java.net.URL;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
@@ -276,7 +278,19 @@ public class Cache
       System.getProperty("http.proxyHost"),
       System.getProperty("http.proxyPort"),
       System.getProperty("https.proxyHost"),
-      System.getProperty("https.proxyPort") };
+      System.getProperty("https.proxyPort"),
+      System.getProperty("http.proxyUser"),
+      System.getProperty("http.proxyPassword"),
+      System.getProperty("https.proxyUser"),
+      System.getProperty("https.proxyPassword"),
+      System.getProperty("http.nonProxyHosts") };
+
+  public final static String PROXYTYPE_NONE = "none";
+
+  // "false" and "true" for backward compatibility
+  public final static String PROXYTYPE_SYSTEM = "false";
+
+  public final static String PROXYTYPE_CUSTOM = "true";
 
   /** Jalview Properties */
   public static Properties applicationProperties = new Properties()
@@ -412,34 +426,35 @@ public class Cache
 
     // PROXY TYPE settings (now three options "none", "false", "true", but using
     // backward compatible strings)
-    String proxyType = getDefault("USE_PROXY", "false");
+    String proxyType = getDefault("USE_PROXY", PROXYTYPE_SYSTEM);
     // default to upgrading old settings
     switch (proxyType)
     {
-    case "none":
-      setProxyProperties(null, null, null, null);
+    case PROXYTYPE_NONE:
+      setProxyProperties(null, null, null, null, null, null, null, null);
       break;
-    case "false": // use system settings
+    case PROXYTYPE_SYSTEM: // use system settings
       resetProxyProperties();
       break;
-    case "true": // use specified proxy settings
+    case PROXYTYPE_CUSTOM: // use specified proxy settings
       String httpHost = getDefault("PROXY_SERVER", "");
       String httpPort = getDefault("PROXY_PORT", "8080");
       String httpsHost = getDefault("PROXY_SERVER_HTTPS", httpHost);
       String httpsPort = getDefault("PROXY_PORT_HTTPS", httpPort);
-      setProxyProperties(httpHost, httpPort, httpsHost, httpsPort);
+      String httpUser = getDefault("PROXY_AUTH_USER", null);
+      String httpPassword = getDefault("PROXY_AUTH_PASSWORD", null);
+      // https.proxyUser and https.proxyPassword are not able to be
+      // independently set in Preferences yet
+      String httpsUser = getDefault("PROXY_AUTH_USER_HTTPS", httpUser);
+      String httpsPassword = getDefault("PROXY_AUTH_PASSWORD_HTTPS",
+              httpPassword);
+      setProxyProperties(httpHost, httpPort, httpsHost, httpsPort, httpUser,
+              httpPassword, httpsUser, httpsPassword);
       break;
     default:
       String message = "Incorrect PROXY_TYPE - should be 'none' (clear proxy properties), 'false' (system settings), 'true' (custom settings): "
               + proxyType;
-      if (Cache.log == null)
-      {
-        System.out.println(message);
-      }
-      else
-      {
-        Cache.log.warn(message);
-      }
+      Cache.warn(message);
     }
 
     // LOAD THE AUTHORS FROM THE authors.props file
@@ -1256,72 +1271,183 @@ public class Cache
   public static void resetProxyProperties()
   {
     setProxyProperties(startupProxyProperties[0], startupProxyProperties[1],
-            startupProxyProperties[2], startupProxyProperties[3]);
+            startupProxyProperties[2], startupProxyProperties[3],
+            startupProxyProperties[4], startupProxyProperties[5],
+            startupProxyProperties[6], startupProxyProperties[7]);
     StringBuilder sb = new StringBuilder();
     sb.append("Setting proxy properties to: http.proxyHost=")
             .append(startupProxyProperties[0]).append(", http.proxyPort=")
-            .append(startupProxyProperties[1]).append(", https.proxyHost=")
-            .append(startupProxyProperties[2]).append(", https.proxyPort=")
-            .append(startupProxyProperties[3]);
-    if (Cache.log == null)
-    {
-      System.err.println(sb.toString());
-    }
-    else
-    {
-      Cache.log.debug(sb.toString());
-    }
+            .append(startupProxyProperties[1])
+            .append(startupProxyProperties[4] != null
+                    && !startupProxyProperties[4].isEmpty()
+                            ? " [" + startupProxyProperties[4] + "]"
+                            : "")
+            .append(", https.proxyHost=").append(startupProxyProperties[2])
+            .append(", https.proxyPort=").append(startupProxyProperties[3])
+            .append(startupProxyProperties[6] != null
+                    && !startupProxyProperties[6].isEmpty()
+                            ? " [" + startupProxyProperties[6] + "]"
+                            : "");
+
+    Cache.debug(sb.toString());
   }
 
-  public static void setProxyProperties(String host, String port)
+  public static void setProxyProperties(String httpHost, String httpPort,
+          String httpsHost, String httpsPort, String httpUser,
+          String httpPassword)
   {
-    setProxyProperties(host, port, host, port);
+    setProxyProperties(httpHost, httpPort, httpsHost, httpsPort, httpUser,
+            httpPassword, httpUser, httpPassword);
   }
 
   public static void setProxyProperties(String httpHost, String httpPort,
-          String httpsHost, String httpsPort)
+          String httpsHost, String httpsPort, String httpUser,
+          String httpPassword, String httpsUser, String httpsPassword)
   {
-    // cannot set property to null -- use clearProperty instead
-
-    // http.proxyHost
-    if (httpHost == null)
+    setOrClearSystemProperty("http.proxyHost", httpHost);
+    setOrClearSystemProperty("http.proxyPort", httpPort);
+    setOrClearSystemProperty("https.proxyHost", httpsHost);
+    setOrClearSystemProperty("https.proxyPort", httpsPort);
+    setOrClearSystemProperty("http.proxyUser", httpUser);
+    setOrClearSystemProperty("http.proxyPassword", httpPassword);
+    setOrClearSystemProperty("https.proxyUser", httpsUser);
+    setOrClearSystemProperty("https.proxyPassword", httpsPassword);
+    if (httpUser != null || httpsUser != null)
     {
-      System.clearProperty("http.proxyHost");
+      try
+      {
+        Authenticator.setDefault(new Authenticator()
+        {
+          @Override
+          protected PasswordAuthentication getPasswordAuthentication()
+          {
+            if (getRequestorType() == RequestorType.PROXY)
+            {
+              try
+              {
+                if (getRequestingScheme().equalsIgnoreCase("http")
+                        && getRequestingHost().equalsIgnoreCase(httpHost)
+                        && getRequestingPort() == Integer.valueOf(httpPort))
+                {
+                  return new PasswordAuthentication(httpUser,
+                          httpPassword == null ? new char[] {}
+                                  : httpPassword.toCharArray());
+                }
+                if (getRequestingScheme().equalsIgnoreCase("https")
+                        && getRequestingHost().equalsIgnoreCase(httpsHost)
+                        && getRequestingPort() == Integer
+                                .valueOf(httpsPort))
+                {
+                  return new PasswordAuthentication(httpsUser,
+                          httpsPassword == null ? new char[] {}
+                                  : httpsPassword.toCharArray());
+                }
+              } catch (NumberFormatException e)
+              {
+                Cache.error("Problem with proxy port values [http:"
+                        + httpPort + ", https:" + httpsPort + "]");
+              }
+            }
+            // non proxy request
+            return null;
+          }
+        });
+        // required to re-enable basic authentication (should be okay for a
+        // local proxy)
+        System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
+      } catch (SecurityException e)
+      {
+        Cache.error("Could not set default Authenticator");
+        Cache.debug(getStackTraceString(e));
+      }
     }
     else
     {
-      System.setProperty("http.proxyHost", httpHost);
+      // reset the Authenticator to protect http.proxyUser and
+      // http.proxyPassword Just In Case
+      Authenticator.setDefault(new Authenticator()
+      {
+        @Override
+        protected PasswordAuthentication getPasswordAuthentication()
+        {
+          return null;
+        }
+      });
     }
 
-    // http.proxyPort
-    if (httpPort == null)
+    // clear localhost from proxying unless nonProxyHosts already set (not
+    // currently configurable in Preferences)
+    String nonProxyHosts = startupProxyProperties[8];
+    System.setProperty("http.nonProxyHosts",
+            nonProxyHosts == null ? "localhost" : nonProxyHosts);
+  }
+
+  public static void setOrClearSystemProperty(String key, String value)
+  {
+    if (key == null)
+    {
+      return;
+    }
+    if (value == null)
     {
-      System.clearProperty("http.proxyPort");
+      System.clearProperty(key);
     }
     else
     {
-      System.setProperty("http.proxyPort", httpPort);
+      System.setProperty(key, value);
     }
+  }
+
+  public final static int DEBUG = 10;
+
+  public final static int INFO = 20;
+
+  public final static int WARN = 30;
 
-    // https.proxyHost
-    if (httpsHost == null)
+  public final static int ERROR = 40;
+
+  public static boolean println(int level, String message)
+  {
+    if (Cache.log == null)
     {
-      System.clearProperty("https.proxyHost");
+      if (level >= ERROR)
+        System.err.println(message);
+      else
+        System.out.println(message);
+      return false;
     }
-    else
+    if (level >= WARN)
     {
-      System.setProperty("https.proxyHost", httpsHost);
+      Cache.log.warn(message);
     }
-
-    // https.proxyPort
-    if (httpsPort == null)
+    else if (level >= INFO)
     {
-      System.clearProperty("https.proxyPort");
+      Cache.log.info(message);
     }
     else
     {
-      System.setProperty("https.proxyPort", httpsPort);
+      Cache.log.debug(message);
     }
+    return true;
+  }
+
+  public static void debug(String message)
+  {
+    println(DEBUG, message);
+  }
 
+  public static void info(String message)
+  {
+    println(INFO, message);
+  }
+
+  public static void warn(String message)
+  {
+    println(WARN, message);
+  }
+
+  public static void error(String message)
+  {
+    println(ERROR, message);
   }
 }
index f337898..827c9a0 100755 (executable)
@@ -127,6 +127,8 @@ public class Preferences extends GPreferences
 
   private static final int MAX_FONT_SIZE = 30;
 
+  private String previousProxyType;
+
   /**
    * Holds name and link separated with | character. Sequence ID must be
    * $SEQUENCE_ID$ or $SEQUENCE_ID=/.possible | chars ./=$
@@ -537,15 +539,16 @@ public class Preferences extends GPreferences
     }
 
     String proxyTypeString = Cache.getDefault("USE_PROXY", "false");
+    previousProxyType = proxyTypeString;
     switch (proxyTypeString)
     {
-    case "none":
+    case Cache.PROXYTYPE_NONE:
       proxyType.setSelected(noProxy.getModel(), true);
       break;
-    case "false":
+    case Cache.PROXYTYPE_SYSTEM:
       proxyType.setSelected(systemProxy.getModel(), true);
       break;
-    case "true":
+    case Cache.PROXYTYPE_CUSTOM:
       proxyType.setSelected(customProxy.getModel(), true);
       break;
     default:
@@ -557,6 +560,12 @@ public class Preferences extends GPreferences
     proxyPortHttpTB.setText(Cache.getDefault("PROXY_PORT", ""));
     proxyServerHttpsTB.setText(Cache.getDefault("PROXY_SERVER_HTTPS", ""));
     proxyPortHttpsTB.setText(Cache.getDefault("PROXY_PORT_HTTPS", ""));
+    proxyAuth.setSelected(Cache.getDefault("PROXY_AUTH", false));
+    proxyAuthUsernameTB
+            .setText(Cache.getDefault("PROXY_AUTH_USERNAME", ""));
+    proxyAuthPasswordTB
+            .setText(Cache.getDefault("PROXY_AUTH_PASSWORD", ""));
+    setCustomProxyEnabled();
 
     defaultBrowser.setText(Cache.getDefault("DEFAULT_BROWSER", ""));
 
@@ -828,35 +837,20 @@ public class Preferences extends GPreferences
     Cache.applicationProperties.setProperty("DEFAULT_URL",
             sequenceUrlLinks.getPrimaryUrlId());
 
+    // Proxy settings
     Cache.applicationProperties.setProperty("USE_PROXY",
-            customProxy.isSelected() ? "true"
-                    : noProxy.isSelected() ? "none" : "false");
-
+            customProxy.isSelected() ? Cache.PROXYTYPE_CUSTOM
+                    : noProxy.isSelected() ? Cache.PROXYTYPE_NONE
+                            : Cache.PROXYTYPE_SYSTEM);
     Cache.setOrRemove("PROXY_SERVER", proxyServerHttpTB.getText());
-
     Cache.setOrRemove("PROXY_PORT", proxyPortHttpTB.getText());
-
     Cache.setOrRemove("PROXY_SERVER_HTTPS", proxyServerHttpsTB.getText());
-
     Cache.setOrRemove("PROXY_PORT_HTTPS", proxyPortHttpsTB.getText());
-
-    if (noProxy.isSelected())
-    {
-      Cache.log.warn("Setting no proxy settings");
-      Cache.setProxyProperties(null, null, null, null);
-    }
-    else if (customProxy.isSelected())
-    {
-      Cache.log.warn("Setting custom proxy settings");
-      Cache.setProxyProperties(proxyServerHttpTB.getText(),
-              proxyPortHttpTB.getText(), proxyServerHttpsTB.getText(),
-              proxyPortHttpsTB.getText());
-    }
-    else // systemProxy should be selected and is sensible default
-    {
-      Cache.log.warn("Setting system proxy settings");
-      Cache.resetProxyProperties();
-    }
+    Cache.setOrRemove("PROXY_AUTH",
+            Boolean.toString(proxyAuth.isSelected()));
+    Cache.setOrRemove("PROXY_AUTH_USERNAME", proxyAuthUsernameTB.getText());
+    Cache.setOrRemove("PROXY_AUTH_PASSWORD", proxyAuthPasswordTB.getText());
+    setProxyFromSettings();
 
     Cache.setProperty("VERSION_CHECK",
             Boolean.toString(versioncheck.isSelected()));
@@ -954,6 +948,39 @@ public class Preferences extends GPreferences
     }
   }
 
+  public void setProxyFromSettings()
+  {
+    String proxyType = Cache.getDefault("USE_PROXY",
+            Cache.PROXYTYPE_SYSTEM);
+    if (proxyType.equals(Cache.PROXYTYPE_NONE))
+    {
+      if (!previousProxyType.equals(proxyType))
+        Cache.log.info("Setting no proxy settings");
+      Cache.setProxyProperties(null, null, null, null, null, null, null,
+              null);
+    }
+    else if (proxyType.equals(Cache.PROXYTYPE_CUSTOM))
+    {
+      if (!previousProxyType.equals(proxyType))
+        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),
+              Cache.getDefault("PROXY_SERVER_HTTPS", null),
+              Cache.getDefault("PROXY_PORT_HTTPS", null),
+              proxyAuthSet ? Cache.getDefault("PROXY_AUTH_USERNAME", "")
+                      : null,
+              proxyAuthSet ? Cache.getDefault("PROXY_AUTH_PASSWORD", "")
+                      : null);
+    }
+    else // systemProxy should be selected and is sensible default anyway
+    {
+      if (!previousProxyType.equals(proxyType))
+        Cache.log.info("Setting system proxy settings");
+      Cache.resetProxyProperties();
+    }
+  }
+
   /**
    * Do any necessary validation before saving settings. Return focus to the
    * first tab which fails validation.
index ca5b203..67da0f4 100755 (executable)
@@ -961,9 +961,11 @@ public class GPreferences extends JPanel
     systemProxy.setFont(LABEL_FONT);
     systemProxy.setHorizontalAlignment(SwingConstants.LEFT);
     systemProxy.setText(MessageManager.formatMessage("label.system_proxy",
-            displayHostPort(Cache.startupProxyProperties[0],
+            displayUserHostPort(Cache.startupProxyProperties[4],
+                    Cache.startupProxyProperties[0],
                     Cache.startupProxyProperties[1]),
-            displayHostPort(Cache.startupProxyProperties[2],
+            displayUserHostPort(Cache.startupProxyProperties[6],
+                    Cache.startupProxyProperties[2],
                     Cache.startupProxyProperties[3])));
     customProxy.setFont(LABEL_FONT);
     customProxy.setHorizontalAlignment(SwingConstants.LEFT);
@@ -997,7 +999,6 @@ public class GPreferences extends JPanel
     });
 
     setCustomProxyEnabled();
-    setProxyAuthEnabled();
 
     // Make proxy server panel
     JPanel proxyPanel = new JPanel();
@@ -1107,7 +1108,7 @@ public class GPreferences extends JPanel
     return proxyPanel;
   }
 
-  private String displayHostPort(String host, String port)
+  private String displayUserHostPort(String user, String host, String port)
   {
     boolean hostBlank = (host == null || host.isEmpty());
     boolean portBlank = (port == null || port.isEmpty());
@@ -1117,6 +1118,12 @@ public class GPreferences extends JPanel
     }
 
     StringBuilder sb = new StringBuilder();
+    if (user != null)
+    {
+      sb.append(user.isEmpty() || user.indexOf(" ") > -1 ? '"' + user + '"'
+              : user);
+      sb.append("@");
+    }
     sb.append(hostBlank ? "" : host);
     if (!portBlank)
     {