X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fbin%2FCache.java;h=4a83b35c81d95e0b2443caebabe91f514f7da569;hb=5d501d5230ad1c42f1e17a485cb86a04ba8b538a;hp=6648099eac8e8195fceb7df691cd9a8e7c5c84ff;hpb=245686954f67953e2dda80efc8c7a5c6d6b965e1;p=jalview.git diff --git a/src/jalview/bin/Cache.java b/src/jalview/bin/Cache.java index 6648099..4a83b35 100755 --- a/src/jalview/bin/Cache.java +++ b/src/jalview/bin/Cache.java @@ -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; @@ -52,13 +53,16 @@ import org.apache.log4j.Logger; import org.apache.log4j.SimpleLayout; import jalview.datamodel.PDBEntry; +import jalview.gui.Preferences; import jalview.gui.UserDefinedColours; import jalview.schemes.ColourSchemeLoader; import jalview.schemes.ColourSchemes; import jalview.schemes.UserColourScheme; import jalview.structure.StructureImportSettings; import jalview.urls.IdOrgSettings; +import jalview.util.ChannelProperties; import jalview.util.ColorUtils; +import jalview.util.MessageManager; import jalview.util.Platform; import jalview.ws.sifts.SiftsSettings; @@ -292,6 +296,9 @@ public class Cache public final static String PROXYTYPE_CUSTOM = "true"; + // in-memory only storage of proxy password, safer to use char array + public static char[] proxyAuthPassword = null; + /** Jalview Properties */ public static Properties applicationProperties = new Properties() { @@ -303,6 +310,9 @@ public class Cache } }; + /* build Properties (not all saved to .jalview_properties) */ + public static Properties buildProperties = new Properties(); + /** Default file is ~/.jalview_properties */ static String propertiesFile; @@ -350,7 +360,8 @@ public class Cache // lcastor.addAppender(ap); // jalview.bin.Cache.log.addAppender(ap); // Tell the user that debug is enabled - jalview.bin.Cache.log.debug("Jalview Debugging Output Follows."); + jalview.bin.Cache.log.debug(ChannelProperties.getProperty("app_name") + + " Debugging Output Follows."); } catch (Exception ex) { System.err.println("Problems initializing the log4j system\n"); @@ -431,7 +442,7 @@ public class Cache switch (proxyType) { case PROXYTYPE_NONE: - setProxyProperties(null, null, null, null, null, null, null, null); + clearProxyProperties(); break; case PROXYTYPE_SYSTEM: // use system settings resetProxyProperties(); @@ -442,14 +453,11 @@ public class Cache String httpsHost = getDefault("PROXY_SERVER_HTTPS", httpHost); String httpsPort = getDefault("PROXY_PORT_HTTPS", httpPort); 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 + // independently set in Preferences yet (or http.nonProxyHosts) 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); + proxyAuthPassword, httpsUser, proxyAuthPassword, "localhost"); break; default: String message = "Incorrect PROXY_TYPE - should be 'none' (clear proxy properties), 'false' (system settings), 'true' (custom settings): " @@ -522,9 +530,13 @@ public class Cache class VersionChecker extends Thread { + @Override public void run() { + String remoteBuildPropertiesUrl = Cache + .getAppbaseBuildProperties(); + String orgtimeout = System .getProperty("sun.net.client.defaultConnectTimeout"); if (orgtimeout == null) @@ -538,28 +550,19 @@ public class Cache { System.setProperty("sun.net.client.defaultConnectTimeout", "5000"); - java.net.URL url = new java.net.URL(Cache - .getDefault("www.jalview.org", "http://www.jalview.org") - + "/webstart/jalview.jnlp"); + java.net.URL url = new java.net.URL(remoteBuildPropertiesUrl); + BufferedReader in = new BufferedReader( new InputStreamReader(url.openStream())); - String line = null; - while ((line = in.readLine()) != null) - { - if (line.indexOf("jalview.version") == -1) - { - continue; - } - line = line.substring(line.indexOf("value=") + 7); - line = line.substring(0, line.lastIndexOf("\"")); - remoteVersion = line; - break; - } + Properties remoteBuildProperties = new Properties(); + remoteBuildProperties.load(in); + remoteVersion = remoteBuildProperties.getProperty("VERSION"); } catch (Exception ex) { - System.out.println( - "Non-fatal exception when checking version at www.jalview.org :"); + System.out + .println("Non-fatal exception when checking version at " + + remoteBuildPropertiesUrl + ":"); System.out.println(ex); remoteVersion = getProperty("VERSION"); } @@ -634,8 +637,23 @@ public class Cache String buildDetails = resolveResourceURLFor("/.build_properties"); URL localJarFileURL = new URL(buildDetails); InputStream in = localJarFileURL.openStream(); - applicationProperties.load(in); + buildProperties.load(in); in.close(); + if (buildProperties.getProperty("BUILD_DATE", null) != null) + { + applicationProperties.put("BUILD_DATE", + buildProperties.getProperty("BUILD_DATE")); + } + if (buildProperties.getProperty("INSTALLATION", null) != null) + { + applicationProperties.put("INSTALLATION", + buildProperties.getProperty("INSTALLATION")); + } + if (buildProperties.getProperty("VERSION", null) != null) + { + applicationProperties.put("VERSION", + buildProperties.getProperty("VERSION")); + } } catch (Exception ex) { System.out.println("Error reading build details: " + ex); @@ -658,8 +676,8 @@ public class Cache new BuildDetails(codeVersion, null, codeInstallation); if (printVersion && reportVersion) { - System.out.println( - "Jalview Version: " + codeVersion + codeInstallation); + System.out.println(ChannelProperties.getProperty("app_name") + + " Version: " + codeVersion + codeInstallation); } } @@ -826,7 +844,8 @@ public class Cache lvclient.addAppender(log.getAppender("JalviewLogger")); // Tell the user that debug is enabled - lvclient.debug("Jalview Vamsas Client Debugging Output Follows."); + lvclient.debug(ChannelProperties.getProperty("app_name") + + " Vamsas Client Debugging Output Follows."); } } catch (Exception e) { @@ -865,7 +884,8 @@ public class Cache lgclient.addAppender(log.getAppender("JalviewLogger")); // Tell the user that debug is enabled - lgclient.debug("Jalview Groovy Client Debugging Output Follows."); + lgclient.debug(ChannelProperties.getProperty("app_name") + + " Groovy Client Debugging Output Follows."); } } catch (Error e) { @@ -927,7 +947,7 @@ public class Cache .getConstructor(new Class[] { String.class, String.class, String.class }) .newInstance(new Object[] - { "Jalview Desktop", + { ChannelProperties.getProperty("app_name") + " Desktop", (vrs = jalview.bin.Cache.getProperty("VERSION") + "_" + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")), @@ -1203,10 +1223,12 @@ public class Cache public static String getVersionDetailsForConsole() { StringBuilder sb = new StringBuilder(); - sb.append("Jalview Version: "); + sb.append(ChannelProperties.getProperty("app_name")) + .append(" Version: "); sb.append(jalview.bin.Cache.getDefault("VERSION", "TEST")); sb.append("\n"); - sb.append("Jalview Installation: "); + sb.append(ChannelProperties.getProperty("app_name")) + .append(" Installation: "); sb.append(jalview.bin.Cache.getDefault("INSTALLATION", "unknown")); sb.append("\n"); sb.append("Build Date: "); @@ -1242,6 +1264,8 @@ public class Cache { appendIfNotNull(sb, "Getdown appdir: ", System.getProperty("getdownappdir"), "\n", null); + appendIfNotNull(sb, "Getdown appbase: ", + System.getProperty("getdownappbase"), "\n", null); appendIfNotNull(sb, "Java home: ", System.getProperty("java.home"), "\n", "unknown"); } @@ -1268,12 +1292,23 @@ public class Cache } // proxy properties methods + public static void clearProxyProperties() + { + setProxyProperties(null, null, null, null, null, null, null, null, + null); + } + public static void resetProxyProperties() { setProxyProperties(startupProxyProperties[0], startupProxyProperties[1], startupProxyProperties[2], startupProxyProperties[3], - startupProxyProperties[4], startupProxyProperties[5], - startupProxyProperties[6], startupProxyProperties[7]); + startupProxyProperties[4], + startupProxyProperties[5] == null ? null + : startupProxyProperties[5].toCharArray(), + startupProxyProperties[6], + startupProxyProperties[7] == null ? null + : startupProxyProperties[7].toCharArray(), + startupProxyProperties[8]); StringBuilder sb = new StringBuilder(); sb.append("Setting proxy properties to: http.proxyHost=") .append(startupProxyProperties[0]).append(", http.proxyPort=") @@ -1292,68 +1327,195 @@ public class Cache Cache.debug(sb.toString()); } - public static void setProxyProperties(String httpHost, String httpPort, - String httpsHost, String httpsPort, String httpUser, - String httpPassword) + public static void setProxyPropertiesFromPreferences() + { + setProxyPropertiesFromPreferences(Cache.PROXYTYPE_SYSTEM); + } + + public static void setProxyPropertiesFromPreferences( + String previousProxyType) { - setProxyProperties(httpHost, httpPort, httpsHost, httpsPort, httpUser, - httpPassword, httpUser, httpPassword); + String proxyType = Cache.getDefault("USE_PROXY", + Cache.PROXYTYPE_SYSTEM); + if (previousProxyType != null + && !proxyType.equals(Cache.PROXYTYPE_CUSTOM) // always apply + // customProxy + && proxyType.equals(previousProxyType)) + { + // no change + return; + } + switch (proxyType) + { + case Cache.PROXYTYPE_NONE: + if (!previousProxyType.equals(proxyType)) + { + 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), + Cache.getDefault("PROXY_SERVER_HTTPS", null), + Cache.getDefault("PROXY_PORT_HTTPS", null), + proxyAuthSet ? Cache.getDefault("PROXY_AUTH_USERNAME", "") + : null, + proxyAuthSet ? Cache.proxyAuthPassword : null, + proxyAuthSet ? Cache.getDefault("PROXY_AUTH_USERNAME", "") + : null, + proxyAuthSet ? Cache.proxyAuthPassword : null, "localhost"); + break; + default: // system proxy settings by default + Cache.log.info("Setting system proxy settings"); + Cache.resetProxyProperties(); + } } public static void setProxyProperties(String httpHost, String httpPort, String httpsHost, String httpsPort, String httpUser, - String httpPassword, String httpsUser, String httpsPassword) + char[] httpPassword, String httpsUser, char[] httpsPassword, + String nonProxyHosts) { 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); + // 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 { - Authenticator.setDefault(new Authenticator() + char[] displayHttpPw = new char[httpPassword == null ? 0 + : httpPassword.length]; + Arrays.fill(displayHttpPw, '*'); + Cache.debug("CACHE Proxy: setting new Authenticator with httpUser='" + + httpUser + "' httpPassword='" + displayHttpPw + "'"); + if (!Platform.isJS()) + /* * + * java.net.Authenticator not implemented in SwingJS yet + * + * @j2sIgnore + * + */ { - @Override - protected PasswordAuthentication getPasswordAuthentication() + Authenticator.setDefault(new Authenticator() { - if (getRequestorType() == RequestorType.PROXY) + @Override + protected PasswordAuthentication getPasswordAuthentication() { - try + if (getRequestorType() == RequestorType.PROXY) { - if (getRequestingScheme().equalsIgnoreCase("http") - && getRequestingHost().equalsIgnoreCase(httpHost) - && getRequestingPort() == Integer.valueOf(httpPort)) + String protocol = getRequestingProtocol(); + boolean needProxyPasswordSet = false; + if (customProxySet && + // we have a username but no password for the scheme being + // requested + (protocol.equalsIgnoreCase("http") + && (httpUser != null && httpUser.length() > 0 + && (httpPassword == null + || httpPassword.length == 0))) + || (protocol.equalsIgnoreCase("https") + && (httpsUser != null + && httpsUser.length() > 0 + && (httpsPassword == null + || httpsPassword.length == 0)))) { - return new PasswordAuthentication(httpUser, - httpPassword == null ? new char[] {} - : httpPassword.toCharArray()); + // open Preferences -> Connections + String message = MessageManager + .getString("label.proxy_password_required"); + Preferences.openPreferences(Preferences.CONNECTIONS_TAB, + message); + Preferences.getInstance() + .proxyAuthPasswordCheckHighlight(true, true); } - if (getRequestingScheme().equalsIgnoreCase("https") - && getRequestingHost().equalsIgnoreCase(httpsHost) - && getRequestingPort() == Integer - .valueOf(httpsPort)) + else { - return new PasswordAuthentication(httpsUser, - httpsPassword == null ? new char[] {} - : httpsPassword.toCharArray()); + try + { + if (protocol.equalsIgnoreCase("http") + && getRequestingHost() + .equalsIgnoreCase(httpHost) + && getRequestingPort() == Integer + .valueOf(httpPort)) + { + Cache.debug( + "AUTHENTICATOR returning PasswordAuthentication(\"" + + httpUser + "\", '" + + new String(displayHttpPw) + "')"); + return new PasswordAuthentication(httpUser, + httpPassword); + } + if (protocol.equalsIgnoreCase("https") + && getRequestingHost() + .equalsIgnoreCase(httpsHost) + && getRequestingPort() == Integer + .valueOf(httpsPort)) + { + char[] displayHttpsPw = new char[httpPassword.length]; + Arrays.fill(displayHttpsPw, '*'); + Cache.debug( + "AUTHENTICATOR returning PasswordAuthentication(\"" + + httpsUser + "\", '" + displayHttpsPw + + "'"); + return new PasswordAuthentication(httpsUser, + httpsPassword); + } + } catch (NumberFormatException e) + { + Cache.error("Problem with proxy port values [http:" + + httpPort + ", https:" + httpsPort + "]"); + } + Cache.debug( + "AUTHENTICATOR after trying to get PasswordAuthentication"); } - } catch (NumberFormatException e) - { - Cache.error("Problem with proxy port values [http:" - + httpPort + ", https:" + httpsPort + "]"); } + // non proxy request + Cache.debug("AUTHENTICATOR returning null"); + return null; } - // non proxy request - return null; - } - }); + }); + } // end of j2sIgnore for java.net.Authenticator + // required to re-enable basic authentication (should be okay for a // local proxy) + Cache.debug( + "AUTHENTICATOR setting property 'jdk.http.auth.tunneling.disabledSchemes' to \"\""); System.setProperty("jdk.http.auth.tunneling.disabledSchemes", ""); } catch (SecurityException e) { @@ -1365,21 +1527,32 @@ public class Cache { // reset the Authenticator to protect http.proxyUser and // http.proxyPassword Just In Case - Authenticator.setDefault(new Authenticator() + /* as noted above, due to bug in java this doesn't work if the sun.net.www.protocol.http.AuthCache + * has working credentials. No workaround for Java 11. + */ + if (!Platform.isJS()) + /* * + * java.net.Authenticator not implemented in SwingJS yet + * + * @j2sIgnore + * + */ { - @Override - protected PasswordAuthentication getPasswordAuthentication() - { - return null; - } - }); + Cache.debug("AUTHENTICATOR setting default Authenticator to null"); + Authenticator.setDefault(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); + // nonProxyHosts not currently configurable in Preferences + Cache.debug("AUTHENTICATOR setting property 'http.nonProxyHosts' to \"" + + nonProxyHosts + "\""); + setOrClearSystemProperty("http.nonProxyHosts", nonProxyHosts); + } + + public static void setOrClearSystemProperty(String key, char[] value) + { + setOrClearSystemProperty(key, + (value == null) ? null : new String(value)); } public static void setOrClearSystemProperty(String key, String value) @@ -1398,25 +1571,32 @@ public class Cache } } - public final static int DEBUG = 10; + public final static int TRACE = 10; + + public final static int DEBUG = 20; - public final static int INFO = 20; + public final static int INFO = 30; - public final static int WARN = 30; + public final static int WARN = 40; - public final static int ERROR = 40; + public final static int ERROR = 50; public static boolean println(int level, String message) { if (Cache.log == null) { - if (level >= ERROR) + if (level >= WARN) System.err.println(message); - else + else if (level >= INFO) System.out.println(message); + // not printing debug or trace messages return false; } - if (level >= WARN) + if (level >= ERROR) + { + Cache.log.error(message); + } + else if (level >= WARN) { Cache.log.warn(message); } @@ -1424,13 +1604,22 @@ public class Cache { Cache.log.info(message); } - else + else if (level >= DEBUG) { Cache.log.debug(message); } + else + { + Cache.log.trace(message); + } return true; } + public static void trace(String message) + { + println(TRACE, message); + } + public static void debug(String message) { println(DEBUG, message); @@ -1450,4 +1639,77 @@ public class Cache { println(ERROR, message); } + + /** + * Getdown appbase methods + */ + + private static final String releaseAppbase; + + private static String getdownAppbase; + + private static String getdownDistDir; + + static + { + if (!Platform.isJS()) + { + Float specversion = Float + .parseFloat(System.getProperty("java.specification.version")); + releaseAppbase = (specversion < 9) + ? "https://www.jalview.org/getdown/release/1.8" + : "https://www.jalview.org/getdown/release/11"; + } + else + { + // this value currenly made up, can be changed to URL that will be + // "https://www.jalview.org/jalview-js/swingjs/j2s/build_properties" + releaseAppbase = "https://www.jalview.org/jalview-js"; + getdownAppbase = releaseAppbase; + getdownDistDir = "/swingjs/j2s"; + } + } + + // look for properties (passed in by getdown) otherwise default to release + private static void setGetdownAppbase() + { + if (getdownAppbase != null) + { + return; + } + String appbase = System.getProperty("getdownappbase"); + String distDir = System.getProperty("getdowndistdir"); + if (appbase == null) + { + appbase = buildProperties.getProperty("GETDOWNAPPBASE"); + distDir = buildProperties.getProperty("GETDOWNAPPDISTDIR"); + } + if (appbase == null) + { + appbase = releaseAppbase; + distDir = "release"; + } + if (appbase.endsWith("/")) + { + appbase = appbase.substring(0, appbase.length() - 1); + } + if (distDir == null) + { + distDir = appbase.equals(releaseAppbase) ? "release" : "alt"; + } + getdownAppbase = appbase; + getdownDistDir = distDir; + } + + public static String getGetdownAppbase() + { + setGetdownAppbase(); + return getdownAppbase; + } + + public static String getAppbaseBuildProperties() + { + String appbase = getGetdownAppbase(); + return appbase + "/" + getdownDistDir + "/build_properties"; + } }