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