Revision: 6251
          http://sourceforge.net/p/jump-pilot/code/6251
Author:   edso
Date:     2020-04-13 18:05:27 +0000 (Mon, 13 Apr 2020)
Log Message:
-----------
WMS client
* text request fetches encoding from header content-type now
* save trusted url that needs no cert verification only per session
* fix http auth on cert unverified requests
* rework allow cert unverified dialog, properly wraps and resizes now

Modified Paths:
--------------
    core/trunk/ChangeLog
    core/trunk/src/com/vividsolutions/wms/AbstractWMSRequest.java
    core/trunk/src/org/openjump/util/URLConnectionProvider.java

Modified: core/trunk/ChangeLog
===================================================================
--- core/trunk/ChangeLog        2020-04-13 17:59:51 UTC (rev 6250)
+++ core/trunk/ChangeLog        2020-04-13 18:05:27 UTC (rev 6251)
@@ -6,6 +6,11 @@
 
 2020-04-13 ede
   * upgrade apache-commons jars codec, compress, imaging, lang3 to latest 
stable
+  WMS client
+  * text request fetches encoding from header content-type now
+  * save trusted url that needs no cert verification only per session
+  * fix http auth on cert unverified requests
+  * rework allow cert unverified dialog, properly wraps and resizes now
 
 2020-04-13 mmichaud <m.michael.mich...@orange.fr>
   * Fix #492 GetFeatureInfo without certificate + encoding

Modified: core/trunk/src/com/vividsolutions/wms/AbstractWMSRequest.java
===================================================================
--- core/trunk/src/com/vividsolutions/wms/AbstractWMSRequest.java       
2020-04-13 17:59:51 UTC (rev 6250)
+++ core/trunk/src/com/vividsolutions/wms/AbstractWMSRequest.java       
2020-04-13 18:05:27 UTC (rev 6251)
@@ -6,17 +6,20 @@
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.nio.charset.Charset;
 import java.util.List;
 import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import javax.imageio.ImageIO;
 
-import org.apache.commons.codec.Charsets;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.input.BoundedInputStream;
 import org.openjump.util.URLConnectionProvider;
 
 import com.vividsolutions.jump.util.FileUtil;
+import com.vividsolutions.jump.workbench.Logger;
 
 abstract public class AbstractWMSRequest implements WMSRequest {
 
@@ -66,7 +69,7 @@
   protected HttpURLConnection prepareConnection() throws IOException {
     URL requestUrl = getURL();
     // by default we follow redirections
-    con = (HttpURLConnection) 
URLConnectionProvider.getJUMP_URLConnectionProvider().getHttpConnection(requestUrl,
 true);
+    con = (HttpURLConnection) 
URLConnectionProvider.getInstance().getHttpConnection(requestUrl, true);
 
     return con;
   }
@@ -157,19 +160,36 @@
         "\nResponse code: " + con.getResponseCode() + "\nHeaders:\n" + headers 
+ "\nResponse body:\n" + result);
   }
 
+  private static Pattern charsetPattern = null;
+
   protected String readConnection(HttpURLConnection con, long limit) throws 
IOException {
     boolean httpOk = con.getResponseCode() == HttpURLConnection.HTTP_OK;
     // get correct stream
     InputStream in = httpOk ? con.getInputStream() : con.getErrorStream();
 
+    String contentType = con.getContentType();
+    Charset charset = Charset.forName("UTF-8");
+    try {
+      if (contentType != null) {
+        // avoid recompiling regex pattern
+        if ( charsetPattern == null )
+          charsetPattern = 
Pattern.compile("(?i:charset)=[\"']?([\\w-]+)[\\\"']?");
+        Matcher matcher = charsetPattern.matcher(contentType);
+        if (matcher.find()) {
+          String charsetName = matcher.group(1);
+          charset = Charset.forName(charsetName);
+        }
+      }
+    } catch (Exception e) {
+      Logger.error("Content-type charset raised error. "+contentType,e);
+    }
+
     String result = "";
     if (in!=null) {
       // limit max chars
       BoundedInputStream bin = new BoundedInputStream(in, limit > 0 ? limit : 
-1);
-      byte[] bytes = new byte[bin.available()];
-      bin.read(bytes);
-      result = new String(bytes, Charsets.UTF_8);
-      //result = IOUtils.toString(bin);
+      // we use parsed HttpURLConnection.getContentType() charset here
+      result = IOUtils.toString(bin, charset);
       FileUtil.close(bin);
     }
 

Modified: core/trunk/src/org/openjump/util/URLConnectionProvider.java
===================================================================
--- core/trunk/src/org/openjump/util/URLConnectionProvider.java 2020-04-13 
17:59:51 UTC (rev 6250)
+++ core/trunk/src/org/openjump/util/URLConnectionProvider.java 2020-04-13 
18:05:27 UTC (rev 6251)
@@ -2,6 +2,9 @@
 
 import static javax.swing.JOptionPane.YES_NO_OPTION;
 
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.BufferedImage;
 import java.io.IOException;
 import java.net.HttpURLConnection;
 import java.net.URL;
@@ -14,15 +17,11 @@
 import java.util.Set;
 
 import javax.net.ssl.*;
-import javax.swing.JOptionPane;
+import javax.swing.*;
 
 import com.vividsolutions.jump.I18N;
-import com.vividsolutions.jump.util.Blackboard;
-import com.vividsolutions.jump.workbench.JUMPWorkbench;
 import com.vividsolutions.jump.workbench.Logger;
-import com.vividsolutions.jump.workbench.plugin.PlugInContext;
 import com.vividsolutions.jump.workbench.ui.network.ProxySettingsOptionsPanel;
-import com.vividsolutions.jump.workbench.ui.plugin.PersistentBlackboardPlugIn;
 import com.vividsolutions.wms.WMSException;
 
 import net.iharder.Base64;
@@ -30,30 +29,23 @@
 public class URLConnectionProvider {
 
   public static String KEY = URLConnectionProvider.class.getName() + " - 
UNCERTIFIED_AUTHORIZED_URL";
-  private Blackboard blackboard;
-  private Set<String> authorizedURL;
+  // keep list of trusted url per session
+  private static Set<URL> trustedURLs = new HashSet<URL>();
 
-  public static URLConnectionProvider OJ_URL_CONNECTION_PROVIDER;
+  public static URLConnectionProvider instance;
 
-  public URLConnectionProvider(Blackboard blackboard) {
-    this.blackboard = blackboard;
-    this.authorizedURL = (Set<String>)this.blackboard.get(KEY, new 
HashSet<String>());
+  // use getInstance() instead
+  private URLConnectionProvider() {
+    super();
   }
 
-  public static URLConnectionProvider getJUMP_URLConnectionProvider() {
-    if (OJ_URL_CONNECTION_PROVIDER == null) {
-      OJ_URL_CONNECTION_PROVIDER = new URLConnectionProvider(
-              
PersistentBlackboardPlugIn.get(JUMPWorkbench.getInstance().getContext())
-      );
+  public static URLConnectionProvider getInstance() {
+    if (instance == null) {
+      instance = new URLConnectionProvider();
     }
-    return OJ_URL_CONNECTION_PROVIDER;
+    return instance;
   }
 
-  public URLConnectionProvider(PlugInContext plugInContext) {
-    this.blackboard = 
PersistentBlackboardPlugIn.get(plugInContext.getWorkbenchContext());
-    this.authorizedURL = (Set<String>)this.blackboard.get(KEY, new 
HashSet<String>());
-  }
-
   public HttpURLConnection getHttpConnection(URL url, boolean followRedirects) 
throws IOException {
     HttpURLConnection connection = (HttpURLConnection) getHttpConnection(url);
 
@@ -108,33 +100,24 @@
       throw new IOException("Please provide an http(s):// url.");
 
     HttpURLConnection connection = (HttpURLConnection)url.openConnection();
+    // apply auth and timeouts
+    connection = applyParametersAndSettings(connection);
 
-    // add auth info if any
-    String userInfo = url.getUserInfo();
-    if (userInfo != null) {
-      String auth = 
Base64.encodeBytes(UriUtil.urlDecode(userInfo).getBytes(Charset.forName("UTF-8")));
-      connection.setRequestProperty("Authorization", "Basic " + auth);
-      Logger.trace("Added auth header 'Authorization: Basic "+auth+"'");
-    }
-
-    // apply timeouts from settings
-    connection.setConnectTimeout(Integer.parseInt(
-        
ProxySettingsOptionsPanel.getInstance().getSetting(ProxySettingsOptionsPanel.OPEN_TIMEOUT_KEY).toString()));
-    connection.setReadTimeout(Integer.parseInt(
-        
ProxySettingsOptionsPanel.getInstance().getSetting(ProxySettingsOptionsPanel.READ_TIMEOUT_KEY).toString()));
-
+    // use base url, no need to bother user with the full http query
+    URL baseURL = new URL(url.getProtocol(), url.getHost(), url.getPort(), 
url.getPath());
     try {
-      setTrustOption(false, url);
+      setTrustOption(false, baseURL);
       connection.connect(); // try to connect
       return connection;    // can connect
     } catch(GeneralSecurityException|SSLException e) {
-      String baseURL = new URL(url.getProtocol(), url.getHost(), 
url.getPort(), url.getPath()).toString();
-      if (authorizedURL.contains(baseURL) || acceptConnection(url)) {
+      if (isTrusted(baseURL) || askIfUserAllowsInvalidCertificate(baseURL)) {
         try {
-          setTrustOption(true, url);
+          // we are in the list or just allowed by user
+          setTrustOption(true, baseURL);
           connection = (HttpURLConnection) url.openConnection();
-          authorizedURL.add(baseURL);
-          //setTrustOption(false, null);
+          // apply auth and timeouts
+          connection = applyParametersAndSettings(connection);
+
           return connection;
         } catch(GeneralSecurityException ex2) {
           throw new IOException(ex2);
@@ -145,13 +128,70 @@
     }
   }
 
-  private boolean acceptConnection(URL url) {
+  // run this *every time* after url.openConnection() to make sure auth and 
default timeouts are set
+  private HttpURLConnection applyParametersAndSettings( HttpURLConnection 
connection ) {
+    // add auth info if any
+    String userInfo = connection.getURL().getUserInfo();
+    if (userInfo != null) {
+      String auth = 
Base64.encodeBytes(UriUtil.urlDecode(userInfo).getBytes(Charset.forName("UTF-8")));
+      connection.setRequestProperty("Authorization", "Basic " + auth);
+      Logger.trace("Added auth header 'Authorization: Basic "+auth+"'");
+    }
+
+    // apply timeouts from settings
+    connection.setConnectTimeout(Integer.parseInt(
+        
ProxySettingsOptionsPanel.getInstance().getSetting(ProxySettingsOptionsPanel.OPEN_TIMEOUT_KEY).toString()));
+    connection.setReadTimeout(Integer.parseInt(
+        
ProxySettingsOptionsPanel.getInstance().getSetting(ProxySettingsOptionsPanel.READ_TIMEOUT_KEY).toString()));
+
+    return connection;
+  }
+
+  private boolean askIfUserAllowsInvalidCertificate(URL url) {
+    String text = I18N.getMessage(
+        "com.vididsolutions.wms.WMService.UnverifiedCertificate",
+        UriUtil.urlStripPassword(url.toString()));
+
+    // JEditor wraps nicely, allow Scrollbar resizing
+    JEditorPane textPane = new JEditorPane("text/plain", text) {
+      @Override
+      public boolean getScrollableTracksViewportWidth() {
+        return true;
+      }
+    };
+
+    // set a proper initial width
+    textPane.setSize(new Dimension(400, 10));
+    textPane.setPreferredSize(new Dimension(400, 
textPane.getPreferredSize().height));
+
+    // fixup look
+    textPane.setBackground(new JOptionPane().getBackground());
+    textPane.setBorder(null);
+
+    // make it scrollable
+    JScrollPane scrollPane = new JScrollPane(textPane);
+    scrollPane.setBorder(null);
+
+    // make the JOptionPane resizable
+    textPane.addHierarchyListener(new HierarchyListener() {
+      public void hierarchyChanged(HierarchyEvent e) {
+        Window window = SwingUtilities.getWindowAncestor(textPane);
+        if (window instanceof Dialog) {
+          Dialog dialog = (Dialog) window;
+          if (!dialog.isResizable()) {
+            dialog.setResizable(true);
+          }
+          // remove icon
+          Image img = new BufferedImage(1, 1,BufferedImage.TYPE_INT_ARGB_PRE);
+          dialog.setIconImage(img);
+          // pack to fit screen
+          dialog.pack();
+        }
+      }
+    });
+
     int r = JOptionPane.showConfirmDialog(
-            null,
-            I18N.getMessage(
-                    "com.vididsolutions.wms.WMService.UnverifiedCertificate",
-                    UriUtil.urlStripPassword(url.toString())
-            ),
+            null,scrollPane,
             "Confirmation dialog",
             YES_NO_OPTION,
             JOptionPane.WARNING_MESSAGE);
@@ -158,12 +198,12 @@
     return r == JOptionPane.YES_OPTION;
   }
 
+  // a dummy trust manager that actually accepts everything
   private TrustManager trm = new X509TrustManager() {
     public X509Certificate[] getAcceptedIssuers() { return null; }
     public void checkClientTrusted(X509Certificate[] certs, String authType) { 
}
     public void checkServerTrusted(X509Certificate[] certs, String authType) { 
}
   };
-  private Set<URL> trustedURLs = new HashSet<>();
 
   /**
    * setDefaultSSLSocketFactory of HttpsURLConnection to a dummy trust managed
@@ -184,7 +224,13 @@
       Logger.info("Using the system trust manager to verify certificate for 
host '"+host+"'.");
       sc.init(null, null, null);
     }
-    // TODO: we should maybe not set a factory for _all_ connections here
+    // TODO: we should maybe not set a factory for _all_ connections here, 
+    //       or at least reset when we are done, maybe rewriting WMS using 
+    //       a more sophisticated http client is the way to go?
     HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
   }
+
+  private boolean isTrusted(URL url) {
+    return trustedURLs.contains(url);
+  }
 }



_______________________________________________
Jump-pilot-devel mailing list
Jump-pilot-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jump-pilot-devel

Reply via email to