From a9e18620b92b2f6ea5d2e4fa1d338c6a912ef934 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Tue, 16 Oct 2012 19:17:06 +0000
Subject: [PATCH]   - Convert HTTP and CONNECT proxies to MD5 authentication  
 - Allow multiple users   - Migrate passwords on first save

---
 .../i2p/i2ptunnel/I2PTunnelConnectClient.java |   7 +-
 .../i2p/i2ptunnel/I2PTunnelHTTPClient.java    |   7 +-
 .../i2ptunnel/I2PTunnelHTTPClientBase.java    | 114 +++++++++---------
 .../src/net/i2p/i2ptunnel/web/EditBean.java   |  21 ++--
 .../src/net/i2p/i2ptunnel/web/IndexBean.java  |  92 +++++++++++---
 apps/i2ptunnel/jsp/editClient.jsp             |   4 +-
 6 files changed, 153 insertions(+), 92 deletions(-)

diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java
index fde47077fc..142aaf49bb 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java
@@ -58,7 +58,7 @@ import net.i2p.util.PortMapper;
  */
 public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements Runnable {
 
-    private static final String AUTH_REALM = "I2P SSL Proxy";
+    public static final String AUTH_REALM = "I2P SSL Proxy";
 
     private final static byte[] ERR_DESTINATION_UNKNOWN =
         ("HTTP/1.1 503 Service Unavailable\r\n"+
@@ -277,14 +277,15 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
             }
             
             // Authorization
-            if (!authorize(s, requestId, method, authorization)) {
+            AuthResult result = authorize(s, requestId, method, authorization);
+            if (result != AuthResult.AUTH_GOOD) {
                 if (_log.shouldLog(Log.WARN)) {
                     if (authorization != null)
                         _log.warn(getPrefix(requestId) + "Auth failed, sending 407 again");
                     else
                         _log.warn(getPrefix(requestId) + "Auth required, sending 407");
                 }
-                out.write(getAuthError(false).getBytes());
+                out.write(getAuthError(result == AuthResult.AUTH_STALE).getBytes());
                 s.close();
                 return;
             }
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
index 594e64c3a5..518e7dcdcb 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
@@ -77,7 +77,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
      */
     private final String _proxyNonce;
 
-    private static final String AUTH_REALM = "I2P HTTP Proxy";
+    public static final String AUTH_REALM = "I2P HTTP Proxy";
 
     /**
      *  These are backups if the xxx.ht error page is missing.
@@ -846,7 +846,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
             }
 
             // Authorization
-            if(!authorize(s, requestId, method, authorization)) {
+            AuthResult result = authorize(s, requestId, method, authorization);
+            if (result != AuthResult.AUTH_GOOD) {
                 if(_log.shouldLog(Log.WARN)) {
                     if(authorization != null) {
                         _log.warn(getPrefix(requestId) + "Auth failed, sending 407 again");
@@ -854,7 +855,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
                         _log.warn(getPrefix(requestId) + "Auth required, sending 407");
                     }
                 }
-                out.write(getAuthError(false).getBytes());
+                out.write(getAuthError(result == AuthResult.AUTH_STALE).getBytes());
                 writeFooter(out);
                 s.close();
                 return;
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java
index 4b53e03996..1a88969141 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java
@@ -122,9 +122,16 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
     /** passwords for specific outproxies may be added with outproxyUsername.fooproxy.i2p=user and outproxyPassword.fooproxy.i2p=pw */
     public static final String PROP_OUTPROXY_USER_PREFIX = PROP_OUTPROXY_USER + '.';
     public static final String PROP_OUTPROXY_PW_PREFIX = PROP_OUTPROXY_PW + '.';
+    /** new style MD5 auth */
+    public static final String PROP_PROXY_DIGEST_PREFIX = "proxy.auth.";
+    public static final String PROP_PROXY_DIGEST_SUFFIX = ".md5";
+    public static final String BASIC_AUTH = "basic";
+    public static final String DIGEST_AUTH = "digest";
 
     protected abstract String getRealm();
 
+    protected enum AuthResult {AUTH_BAD_REQ, AUTH_BAD, AUTH_STALE, AUTH_GOOD}
+
     /**
      *  @since 0.9.4
      */
@@ -144,81 +151,77 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
      *  @param authorization may be null, the full auth line e.g. "Basic lskjlksjf"
      *  @return success
      */
-    protected boolean authorize(Socket s, long requestId, String method, String authorization) {
+    protected AuthResult authorize(Socket s, long requestId, String method, String authorization) {
         String authRequired = getTunnel().getClientOptions().getProperty(PROP_AUTH);
         if (authRequired == null)
-            return true;
+            return AuthResult.AUTH_GOOD;
         authRequired = authRequired.toLowerCase(Locale.US);
         if (authRequired.equals("false"))
-            return true;
+            return AuthResult.AUTH_GOOD;
         if (s instanceof InternalSocket) {
             if (_log.shouldLog(Log.INFO))
                 _log.info(getPrefix(requestId) + "Internal access, no auth required");
-            return true;
+            return AuthResult.AUTH_GOOD;
         }
         if (authorization == null)
-            return false;
+            return AuthResult.AUTH_BAD;
         if (_log.shouldLog(Log.INFO))
             _log.info(getPrefix(requestId) + "Auth: " + authorization);
         String authLC = authorization.toLowerCase(Locale.US);
-        if (authRequired.equals("true") || authRequired.equals("basic")) {
+        if (authRequired.equals("true") || authRequired.equals(BASIC_AUTH)) {
             if (!authLC.startsWith("basic "))
-                return false;
+                return AuthResult.AUTH_BAD;
             authorization = authorization.substring(6);
 
-                // hmm safeDecode(foo, true) to use standard alphabet is private in Base64
-                byte[] decoded = Base64.decode(authorization.replace("/", "~").replace("+", "="));
-                if (decoded != null) {
-                    // We send Accept-Charset: UTF-8 in the 407 so hopefully it comes back that way inside the B64 ?
-                    try {
-                        String dec = new String(decoded, "UTF-8");
-                        String[] parts = dec.split(":");
-                        String user = parts[0];
-                        String pw = parts[1];
-                        // first try pw for that user
-                        String configPW = getTunnel().getClientOptions().getProperty(PROP_PW_PREFIX + user);
-                        if (configPW == null) {
-                            // if not, look at default user and pw
-                            String configUser = getTunnel().getClientOptions().getProperty(PROP_USER);
-                            if (user.equals(configUser))
-                                configPW = getTunnel().getClientOptions().getProperty(PROP_PW);
-                        }
-                        if (configPW != null) {
-                            if (pw.equals(configPW)) {
-                                if (_log.shouldLog(Log.INFO))
-                                    _log.info(getPrefix(requestId) + "Good auth - user: " + user + " pw: " + pw);
-                                return true;
-                            } else {
-                                if (_log.shouldLog(Log.WARN))
-                                    _log.warn(getPrefix(requestId) + "Bad auth, pw mismatch - user: " + user + " pw: " + pw + " expected: " + configPW);
-                            }
-                        } else {
-                            if (_log.shouldLog(Log.WARN))
-                                _log.warn(getPrefix(requestId) + "Bad auth, no stored pw for user: " + user + " pw: " + pw);
+            // hmm safeDecode(foo, true) to use standard alphabet is private in Base64
+            byte[] decoded = Base64.decode(authorization.replace("/", "~").replace("+", "="));
+            if (decoded != null) {
+                // We send Accept-Charset: UTF-8 in the 407 so hopefully it comes back that way inside the B64 ?
+                try {
+                    String dec = new String(decoded, "UTF-8");
+                    String[] parts = dec.split(":");
+                    String user = parts[0];
+                    String pw = parts[1];
+                    // first try pw for that user
+                    String configPW = getTunnel().getClientOptions().getProperty(PROP_PW_PREFIX + user);
+                    if (configPW == null) {
+                        // if not, look at default user and pw
+                        String configUser = getTunnel().getClientOptions().getProperty(PROP_USER);
+                        if (user.equals(configUser))
+                            configPW = getTunnel().getClientOptions().getProperty(PROP_PW);
+                    }
+                    if (configPW != null) {
+                        if (pw.equals(configPW)) {
+                            if (_log.shouldLog(Log.INFO))
+                                _log.info(getPrefix(requestId) + "Good auth - user: " + user + " pw: " + pw);
+                            return AuthResult.AUTH_GOOD;
                         }
-                    } catch (UnsupportedEncodingException uee) {
-                        _log.error(getPrefix(requestId) + "No UTF-8 support? B64: " + authorization, uee);
-                    } catch (ArrayIndexOutOfBoundsException aioobe) {
-                        // no ':' in response
-                        if (_log.shouldLog(Log.WARN))
-                            _log.warn(getPrefix(requestId) + "Bad auth B64: " + authorization, aioobe);
                     }
-                } else {
+                    _log.logAlways(Log.WARN, "PROXY AUTH FAILURE: user " + user);
+                } catch (UnsupportedEncodingException uee) {
+                    _log.error(getPrefix(requestId) + "No UTF-8 support? B64: " + authorization, uee);
+                } catch (ArrayIndexOutOfBoundsException aioobe) {
+                    // no ':' in response
                     if (_log.shouldLog(Log.WARN))
-                        _log.warn(getPrefix(requestId) + "Bad auth B64: " + authorization);
+                        _log.warn(getPrefix(requestId) + "Bad auth B64: " + authorization, aioobe);
+                    return AuthResult.AUTH_BAD_REQ;
                 }
-
-            return false;
-        } else if (authRequired.equals("digest")) {
+                return AuthResult.AUTH_BAD;
+            } else {
+                if (_log.shouldLog(Log.WARN))
+                    _log.warn(getPrefix(requestId) + "Bad auth B64: " + authorization);
+                return AuthResult.AUTH_BAD_REQ;
+            }
+        } else if (authRequired.equals(DIGEST_AUTH)) {
             if (!authLC.startsWith("digest "))
-                return false;
+                return AuthResult.AUTH_BAD;
             authorization = authorization.substring(7);
             Map<String, String> args = parseArgs(authorization);
             AuthResult rv = validateDigest(method, args);
-            return rv == AuthResult.AUTH_GOOD;
+            return rv;
         } else {
             _log.error("Unknown proxy authorization type configured: " + authRequired);
-            return true;
+            return AuthResult.AUTH_BAD_REQ;
         }
     }
 
@@ -250,10 +253,10 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
             return check;
         }
         // get H(A1) == stored password
-        String ha1 = getTunnel().getClientOptions().getProperty(PROP_PW_PREFIX + user);
+        String ha1 = getTunnel().getClientOptions().getProperty(PROP_PROXY_DIGEST_PREFIX + user +
+                                                                PROP_PROXY_DIGEST_SUFFIX);
         if (ha1 == null) {
-            if (_log.shouldLog(Log.INFO))
-                _log.info("Bad digest auth - no stored pw for user: " + user);
+            _log.logAlways(Log.WARN, "PROXY AUTH FAILURE: user " + user);
             return AuthResult.AUTH_BAD;
         }
         // get H(A2)
@@ -263,8 +266,9 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
         String kd = ha1 + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2;
         String hkd = PasswordManager.md5Hex(kd);
         if (!response.equals(hkd)) {
+            _log.logAlways(Log.WARN, "PROXY AUTH FAILURE: user " + user);
             if (_log.shouldLog(Log.INFO))
-                _log.info("Bad digest auth - user: " + user);
+                _log.info("Bad digest auth: " + DataHelper.toString(args));
             return AuthResult.AUTH_BAD;
         }
         if (_log.shouldLog(Log.INFO))
@@ -288,8 +292,6 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
         return Base64.encode(n);
     }
 
-    protected enum AuthResult {AUTH_BAD_REQ, AUTH_BAD, AUTH_STALE, AUTH_GOOD}
-
     /**
      *  Verify the Base 64 of 24 bytes: (now, md5 of (now, proxy nonce))
      *  @since 0.9.4
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java
index a0c38616e8..33e4f3fffd 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java
@@ -221,19 +221,7 @@ public class EditBean extends IndexBean {
     
     /** all proxy auth @since 0.8.2 */
     public boolean getProxyAuth(int tunnel) {
-        return getBooleanProperty(tunnel, I2PTunnelHTTPClientBase.PROP_AUTH) &&
-               getProxyUsername(tunnel).length() > 0 &&
-               getProxyPassword(tunnel).length() > 0;
-    }
-    
-    public String getProxyUsername(int tunnel) {
-        return getProperty(tunnel, I2PTunnelHTTPClientBase.PROP_USER, "");
-    }
-    
-    public String getProxyPassword(int tunnel) {
-        if (getProxyUsername(tunnel).length() <= 0)
-            return "";
-        return getProperty(tunnel, I2PTunnelHTTPClientBase.PROP_PW, "");
+        return getProperty(tunnel, I2PTunnelHTTPClientBase.PROP_AUTH, "false") != "false";
     }
     
     public boolean getOutproxyAuth(int tunnel) {
@@ -354,10 +342,17 @@ public class EditBean extends IndexBean {
             if (opts == null) return "";
             StringBuilder buf = new StringBuilder(64);
             int i = 0;
+            boolean isMD5Proxy = "httpclient".equals(tun.getType()) ||
+                                 "connectclient".equals(tun.getType());
             for (Iterator iter = opts.keySet().iterator(); iter.hasNext(); ) {
                 String key = (String)iter.next();
                 if (_noShowSet.contains(key))
                     continue;
+                // leave in for HTTP and Connect so it can get migrated to MD5
+                // hide for SOCKS until migrated to MD5
+                if ((!isMD5Proxy) &&
+                    _nonProxyNoShowSet.contains(key))
+                    continue;
                 String val = opts.getProperty(key);
                 if (i != 0) buf.append(' ');
                 buf.append(key).append('=').append(val);
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
index 363c9a60b1..0ef169a421 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
@@ -27,6 +27,7 @@ import net.i2p.data.Certificate;
 import net.i2p.data.Destination;
 import net.i2p.data.PrivateKeyFile;
 import net.i2p.data.SessionKey;
+import net.i2p.i2ptunnel.I2PTunnelConnectClient;
 import net.i2p.i2ptunnel.I2PTunnelHTTPClient;
 import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase;
 import net.i2p.i2ptunnel.I2PTunnelIRCClient;
@@ -36,6 +37,7 @@ import net.i2p.util.Addresses;
 import net.i2p.util.ConcurrentHashSet;
 import net.i2p.util.FileUtil;
 import net.i2p.util.Log;
+import net.i2p.util.PasswordManager;
 
 /**
  * Simple accessor for exposing tunnel info, but also an ugly form handler
@@ -83,6 +85,8 @@ public class IndexBean {
     private int _hashCashValue;
     private int _certType;
     private String _certSigner;
+    private String _newProxyUser;
+    private String _newProxyPW;
     
     public static final int RUNNING = 1;
     public static final int STARTING = 2;
@@ -224,9 +228,9 @@ public class IndexBean {
     private String start() {
         if (_tunnel < 0) return "Invalid tunnel";
         
-        List controllers = _group.getControllers();
+        List<TunnelController> controllers = _group.getControllers();
         if (_tunnel >= controllers.size()) return "Invalid tunnel";
-        TunnelController controller = (TunnelController)controllers.get(_tunnel);
+        TunnelController controller = controllers.get(_tunnel);
         controller.startTunnelBackground();
         // give the messages a chance to make it to the window
         try { Thread.sleep(1000); } catch (InterruptedException ie) {}
@@ -237,9 +241,9 @@ public class IndexBean {
     private String stop() {
         if (_tunnel < 0) return "Invalid tunnel";
         
-        List controllers = _group.getControllers();
+        List<TunnelController> controllers = _group.getControllers();
         if (_tunnel >= controllers.size()) return "Invalid tunnel";
-        TunnelController controller = (TunnelController)controllers.get(_tunnel);
+        TunnelController controller = controllers.get(_tunnel);
         controller.stopTunnel();
         // give the messages a chance to make it to the window
         try { Thread.sleep(1000); } catch (InterruptedException ie) {}
@@ -268,10 +272,10 @@ public class IndexBean {
         // if the current tunnel is shared, and of supported type
         if (Boolean.parseBoolean(cur.getSharedClient()) && isClient(cur.getType())) {
             // all clients use the same I2CP session, and as such, use the same I2CP options
-            List controllers = _group.getControllers();
+            List<TunnelController> controllers = _group.getControllers();
 
             for (int i = 0; i < controllers.size(); i++) {
-                TunnelController c = (TunnelController)controllers.get(i);
+                TunnelController c = controllers.get(i);
 
                 // Current tunnel modified by user, skip
                 if (c == cur) continue;
@@ -804,21 +808,22 @@ public class IndexBean {
 
     /** all proxy auth @since 0.8.2 */
     public void setProxyAuth(String s) {
-        _booleanOptions.add(I2PTunnelHTTPClientBase.PROP_AUTH);
+        if (s != null)
+            _otherOptions.put(I2PTunnelHTTPClientBase.PROP_AUTH, I2PTunnelHTTPClientBase.DIGEST_AUTH);
     }
     
     public void setProxyUsername(String s) {
         if (s != null)
-            _otherOptions.put(I2PTunnelHTTPClientBase.PROP_USER, s.trim());
+            _newProxyUser = s.trim();
     }
     
     public void setProxyPassword(String s) {
         if (s != null)
-            _otherOptions.put(I2PTunnelHTTPClientBase.PROP_PW, s.trim());
+            _newProxyPW = s.trim();
     }
     
     public void setOutproxyAuth(String s) {
-        _booleanOptions.add(I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH);
+        _otherOptions.put(I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH, I2PTunnelHTTPClientBase.DIGEST_AUTH);
     }
     
     public void setOutproxyUsername(String s) {
@@ -1040,6 +1045,45 @@ public class IndexBean {
                 config.setProperty("proxyList", _proxyList);
         }
 
+        // Proxy auth including migration to MD5
+        if ("httpclient".equals(_type) || "connectclient".equals(_type)) {
+            // Migrate even if auth is disabled
+            // go get the old from custom options that updateConfigGeneric() put in there
+            String puser = "option." + I2PTunnelHTTPClientBase.PROP_USER;
+            String user = config.getProperty(puser);
+            String ppw = "option." + I2PTunnelHTTPClientBase.PROP_PW;
+            String pw = config.getProperty(ppw);
+            if (user != null && pw != null && user.length() > 0 && pw.length() > 0) {
+                String pmd5 = "option." + I2PTunnelHTTPClientBase.PROP_PROXY_DIGEST_PREFIX +
+                              user + I2PTunnelHTTPClientBase.PROP_PROXY_DIGEST_SUFFIX;
+                if (config.getProperty(pmd5) == null) {
+                    // not in there, migrate
+                    String realm = _type.equals("httpclient") ? I2PTunnelHTTPClient.AUTH_REALM
+                                                              : I2PTunnelConnectClient.AUTH_REALM;
+                    String hex = PasswordManager.md5Hex(realm, user, pw);
+                    if (hex != null) {
+                        config.setProperty(pmd5, hex);
+                        config.remove(puser);
+                        config.remove(ppw);
+                    }
+                }
+            }
+            // New user/password
+            String auth = _otherOptions.get(I2PTunnelHTTPClientBase.PROP_AUTH);
+            if (auth != null && !auth.equals("false")) {
+                if (_newProxyUser != null && _newProxyPW != null &&
+                    _newProxyUser.length() > 0 && _newProxyPW.length() > 0) {
+                    String pmd5 = "option." + I2PTunnelHTTPClientBase.PROP_PROXY_DIGEST_PREFIX +
+                                  _newProxyUser + I2PTunnelHTTPClientBase.PROP_PROXY_DIGEST_SUFFIX;
+                    String realm = _type.equals("httpclient") ? I2PTunnelHTTPClient.AUTH_REALM
+                                                              : I2PTunnelConnectClient.AUTH_REALM;
+                    String hex = PasswordManager.md5Hex(realm, _newProxyUser, _newProxyPW);
+                    if (hex != null)
+                        config.setProperty(pmd5, hex);
+                }
+            }
+        }
+
         if ("ircclient".equals(_type) || "client".equals(_type) || "streamrclient".equals(_type)) {
             if (_targetDestination != null)
                 config.setProperty("targetDestination", _targetDestination);
@@ -1084,15 +1128,16 @@ public class IndexBean {
         "i2cp.reduceOnIdle", "i2cp.closeOnIdle", "i2cp.newDestOnResume", "persistentClientKey", "i2cp.delayOpen"
         };
     private static final String _booleanProxyOpts[] = {
-        I2PTunnelHTTPClientBase.PROP_AUTH, I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH
+        I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH
         };
     private static final String _booleanServerOpts[] = {
         "i2cp.reduceOnIdle", "i2cp.encryptLeaseSet", PROP_ENABLE_ACCESS_LIST, PROP_ENABLE_BLACKLIST
         };
     private static final String _otherClientOpts[] = {
         "i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.closeIdleTime",
-        "proxyUsername", "proxyPassword", "outproxyUsername", "outproxyPassword",
-        I2PTunnelHTTPClient.PROP_JUMP_SERVERS
+        "outproxyUsername", "outproxyPassword",
+        I2PTunnelHTTPClient.PROP_JUMP_SERVERS,
+        I2PTunnelHTTPClientBase.PROP_AUTH
         };
     private static final String _otherServerOpts[] = {
         "i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.leaseSetKey", "i2cp.accessList",
@@ -1101,7 +1146,17 @@ public class IndexBean {
          PROP_MAX_STREAMS
         };
 
+    /**
+     *  do NOT add these to noShoOpts, we must leave them in for HTTPClient and ConnectCLient
+     *  so they will get migrated to MD5
+     *  TODO migrate socks to MD5
+     */
+    private static final String _otherProxyOpts[] = {
+        "proxyUsername", "proxyPassword"
+        };
+
     protected static final Set _noShowSet = new HashSet(64);
+    protected static final Set _nonProxyNoShowSet = new HashSet(4);
     static {
         _noShowSet.addAll(Arrays.asList(_noShowOpts));
         _noShowSet.addAll(Arrays.asList(_booleanClientOpts));
@@ -1109,6 +1164,7 @@ public class IndexBean {
         _noShowSet.addAll(Arrays.asList(_booleanServerOpts));
         _noShowSet.addAll(Arrays.asList(_otherClientOpts));
         _noShowSet.addAll(Arrays.asList(_otherServerOpts));
+        _nonProxyNoShowSet.addAll(Arrays.asList(_otherProxyOpts));
     }
 
     private void updateConfigGeneric(Properties config) {
@@ -1139,6 +1195,12 @@ public class IndexBean {
                 String key = pair.substring(0, eq);
                 if (_noShowSet.contains(key))
                     continue;
+                // leave in for HTTP and Connect so it can get migrated to MD5
+                // hide for SOCKS until migrated to MD5
+                if ((!"httpclient".equals(_type)) &&
+                    (! "connectclient".equals(_type)) &&
+                    _nonProxyNoShowSet.contains(key))
+                    continue;
                 String val = pair.substring(eq+1);
                 config.setProperty("option." + key, val);
             }
@@ -1190,9 +1252,9 @@ public class IndexBean {
     protected TunnelController getController(int tunnel) {
         if (tunnel < 0) return null;
         if (_group == null) return null;
-        List controllers = _group.getControllers();
+        List<TunnelController> controllers = _group.getControllers();
         if (controllers.size() > tunnel)
-            return (TunnelController)controllers.get(tunnel); 
+            return controllers.get(tunnel); 
         else
             return null;
     }
diff --git a/apps/i2ptunnel/jsp/editClient.jsp b/apps/i2ptunnel/jsp/editClient.jsp
index d2ca8f7ad3..bd147880be 100644
--- a/apps/i2ptunnel/jsp/editClient.jsp
+++ b/apps/i2ptunnel/jsp/editClient.jsp
@@ -435,13 +435,13 @@
                 <label>
                     <%=intl._("Username")%>:
                 </label>
-                <input type="text" id="clientPort" name="proxyUsername" title="Set username for this service" value="<%=editBean.getProxyUsername(curTunnel)%>" class="freetext" />                
+                <input type="text" id="clientPort" name="proxyUsername" title="Set username for this service" value="" class="freetext" />                
             </div>
             <div id="portField" class="rowItem">
                 <label>
                     <%=intl._("Password")%>:
                 </label>
-                <input type="password" id="clientPort" name="proxyPassword" title="Set password for this service" value="<%=editBean.getProxyPassword(curTunnel)%>" class="freetext" />                
+                <input type="password" id="clientPort" name="proxyPassword" title="Set password for this service" value="" class="freetext" />                
             </div>
             <div class="subdivider">
                 <hr />
-- 
GitLab