From dc8c6c7ec08ef010bf944749c48539b49bfd9b26 Mon Sep 17 00:00:00 2001 From: Arnaud Roques Date: Tue, 23 Nov 2021 17:38:29 +0100 Subject: [PATCH] Minor formatting and SURL::create now throws MalformedURLException --- .../sourceforge/plantuml/security/SURL.java | 196 +++++++++--------- .../plantuml/security/SecurityUtils.java | 2 +- 2 files changed, 99 insertions(+), 99 deletions(-) diff --git a/src/net/sourceforge/plantuml/security/SURL.java b/src/net/sourceforge/plantuml/security/SURL.java index 75e02b673..78bbc0fe9 100644 --- a/src/net/sourceforge/plantuml/security/SURL.java +++ b/src/net/sourceforge/plantuml/security/SURL.java @@ -53,6 +53,7 @@ import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; @@ -125,16 +126,23 @@ public class SURL { private final String securityIdentifier; private SURL(URL url, String securityIdentifier) { - assert url != null; - assert securityIdentifier != null; - this.internal = url; - this.securityIdentifier = securityIdentifier; + this.internal = Objects.requireNonNull(url); + this.securityIdentifier = Objects.requireNonNull(securityIdentifier); } + /** + * Create a secure URL from a String. + *

+ * The url must be http or https. + * Return null in case of error or if url is null + * + * @param url plain url starting by http:// or https// + * @return the secure URL or null + */ public static SURL create(String url) { - if (url == null) { + if (url == null) return null; - } + if (url.startsWith("http://") || url.startsWith("https://")) try { return create(new URL(url)); @@ -144,29 +152,30 @@ public class SURL { return null; } - public static SURL create(URL url) { + /** + * Create a secure URL from a java.net.URL object. + *

+ * It takes into account credentials. + * + * @param url + * @return the secure URL + * @throws MalformedURLException if url is null + */ + public static SURL create(URL url) throws MalformedURLException { if (url == null) - return null; + throw new MalformedURLException("URL cannot be null"); - String credentialId = url.getUserInfo(); + final String credentialId = url.getUserInfo(); - final URL internalUrl; - if (credentialId == null || credentialId.indexOf(':') > 0) { + if (credentialId == null || credentialId.indexOf(':') > 0) // No user info at all, or a user with password (This is a legacy BasicAuth // access, and we bypass it): - internalUrl = url; - credentialId = WITHOUT_AUTHENTICATION; - } else { + return new SURL(url, WITHOUT_AUTHENTICATION); + else if (SecurityUtils.existsSecurityCredentials(credentialId)) // Given userInfo, but without a password. We try to find SecurityCredentials - if (SecurityUtils.existsSecurityCredentials(credentialId)) { - internalUrl = removeUserInfo(url); - } else { - internalUrl = url; - credentialId = WITHOUT_AUTHENTICATION; - } - } - - return new SURL(internalUrl, credentialId); + return new SURL(removeUserInfo(url), credentialId); + else + return new SURL(url, WITHOUT_AUTHENTICATION); } /** @@ -174,8 +183,9 @@ public class SURL { * * @param url plain URL * @return SURL without any user credential information. + * @throws MalformedURLException */ - public static SURL createWithoutUser(URL url) { + static SURL createWithoutUser(URL url) throws MalformedURLException { return new SURL(removeUserInfo(url), WITHOUT_AUTHENTICATION); } @@ -188,7 +198,7 @@ public class SURL { * with existing credentials. With a bad host cache the second test will fail, * or we have unpredicted results. */ - public static void resetBadHosts() { + static void resetBadHosts() { BAD_HOSTS.clear(); } @@ -232,11 +242,10 @@ public class SURL { private boolean isInAllowList() { final String full = cleanPath(internal.toString()); - for (String allow : getAllowList()) { - if (full.startsWith(cleanPath(allow))) { + for (String allow : getAllowList()) + if (full.startsWith(cleanPath(allow))) return true; - } - } + return false; } @@ -253,9 +262,9 @@ public class SURL { private List getAllowList() { final String env = SecurityUtils.getenv(SecurityUtils.PATHS_ALLOWED); - if (env == null) { + if (env == null) return Collections.emptyList(); - } + return Arrays.asList(StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(env).split(";")); } @@ -273,28 +282,28 @@ public class SURL { * @return data loaded data from endpoint */ public byte[] getBytes() { - if (!isUrlOk()) { + if (isUrlOk() == false) return null; - } - SecurityCredentials credentials = SecurityUtils.loadSecurityCredentials(securityIdentifier); - SecurityAuthentication authentication = SecurityUtils.getAuthenticationManager(credentials).create(credentials); + + final SecurityCredentials credentials = SecurityUtils.loadSecurityCredentials(securityIdentifier); + final SecurityAuthentication authentication = SecurityUtils.getAuthenticationManager(credentials) + .create(credentials); try { - String host = internal.getHost(); - Long bad = BAD_HOSTS.get(host); + final String host = internal.getHost(); + final Long bad = BAD_HOSTS.get(host); if (bad != null) { - if ((System.currentTimeMillis() - bad) < 1000L * 60) { + if ((System.currentTimeMillis() - bad) < 1000L * 60) return null; - } BAD_HOSTS.remove(host); } try { - Future result = EXE + final Future result = EXE .submit(requestWithGetAndResponse(internal, credentials.getProxy(), authentication, null)); - byte[] data = result.get(SecurityUtils.getSecurityProfile().getTimeout(), TimeUnit.MILLISECONDS); - if (data != null) { + final byte[] data = result.get(SecurityUtils.getSecurityProfile().getTimeout(), TimeUnit.MILLISECONDS); + if (data != null) return data; - } + } catch (Exception e) { System.err.println("issue " + host + " " + e); } @@ -327,18 +336,18 @@ public class SURL { * @param headers additional headers, if needed * @return loaded data from endpoint */ - public byte[] getBytes(Proxy proxy, SecurityAuthentication authentication, Map headers) { - if (!isUrlOk()) { + private byte[] getBytes(Proxy proxy, SecurityAuthentication authentication, Map headers) { + if (isUrlOk() == false) return null; - } + final Future result = EXE.submit(requestWithGetAndResponse(internal, proxy, authentication, headers)); - byte[] data = null; + try { - data = result.get(SecurityUtils.getSecurityProfile().getTimeout(), TimeUnit.MILLISECONDS); + return result.get(SecurityUtils.getSecurityProfile().getTimeout(), TimeUnit.MILLISECONDS); } catch (Exception e) { System.err.println("SURL response issue to " + internal.getHost() + " " + e); + return null; } - return data; } /** @@ -363,18 +372,18 @@ public class SURL { */ public byte[] getBytesOnPost(Proxy proxy, SecurityAuthentication authentication, String data, Map headers) { - if (!isUrlOk()) { + if (isUrlOk() == false) return null; - } + final Future result = EXE .submit(requestWithPostAndResponse(internal, proxy, authentication, data, headers)); - byte[] response = null; + try { - response = result.get(SecurityUtils.getSecurityProfile().getTimeout(), TimeUnit.MILLISECONDS); + return result.get(SecurityUtils.getSecurityProfile().getTimeout(), TimeUnit.MILLISECONDS); } catch (Exception e) { System.err.println("SURL response issue to " + internal.getHost() + " " + e); + return null; } - return response; } /** @@ -392,11 +401,10 @@ public class SURL { public byte[] call() throws IOException { // Add proxy, if passed throw parameters final URLConnection connection = proxy == null ? url.openConnection() : url.openConnection(proxy); - if (connection == null) { + if (connection == null) return null; - } - HttpURLConnection http = (HttpURLConnection) connection; + final HttpURLConnection http = (HttpURLConnection) connection; applyEndpointAccessAuthentication(http, authentication); applyAdditionalHeaders(http, headers); @@ -424,43 +432,41 @@ public class SURL { public byte[] call() throws IOException { // Add proxy, if passed throw parameters final URLConnection connection = proxy == null ? url.openConnection() : url.openConnection(proxy); - if (connection == null) { + if (connection == null) return null; - } - boolean withContent = StringUtils.isNotEmpty(data); + final boolean withContent = StringUtils.isNotEmpty(data); - HttpURLConnection http = (HttpURLConnection) connection; + final HttpURLConnection http = (HttpURLConnection) connection; http.setRequestMethod("POST"); - if (withContent) { + if (withContent) http.setDoOutput(true); - } applyEndpointAccessAuthentication(http, authentication); applyAdditionalHeaders(http, headers); - Charset charSet = extractCharset(http.getRequestProperty("Content-Type")); + final Charset charSet = extractCharset(http.getRequestProperty("Content-Type")); - if (withContent) { + if (withContent) sendRequestAsBytes(http, data.getBytes(charSet != null ? charSet : StandardCharsets.UTF_8)); - } + return retrieveResponseAsBytes(http); } }; } private static Charset extractCharset(String contentType) { - if (StringUtils.isEmpty(contentType)) { + if (StringUtils.isEmpty(contentType)) return null; - } - Matcher matcher = Pattern.compile("(?i)\\bcharset=\\s*\"?([^\\s;\"]*)").matcher(contentType); - if (matcher.find()) { + + final Matcher matcher = Pattern.compile("(?i)\\bcharset=\\s*\"?([^\\s;\"]*)").matcher(contentType); + if (matcher.find()) try { return Charset.forName(matcher.group(1)); } catch (Exception e) { e.printStackTrace(); } - } + return null; } @@ -473,14 +479,14 @@ public class SURL { * download was broken */ private static byte[] retrieveResponseAsBytes(HttpURLConnection connection) throws IOException { - int responseCode = connection.getResponseCode(); + final int responseCode = connection.getResponseCode(); if (responseCode < HttpURLConnection.HTTP_BAD_REQUEST) { try (InputStream input = connection.getInputStream()) { return retrieveData(input); } } else { try (InputStream error = connection.getErrorStream()) { - byte[] bytes = retrieveData(error); + final byte[] bytes = retrieveData(error); throw new IOException( "HTTP error " + responseCode + " with " + new String(bytes, StandardCharsets.UTF_8)); } @@ -522,9 +528,9 @@ public class SURL { public InputStream openStream() { if (isUrlOk()) { final byte[] data = getBytes(); - if (data != null) { + if (data != null) return new ByteArrayInputStream(data); - } + } return null; } @@ -546,7 +552,7 @@ public class SURL { * @return true, if credentials will be used for a connection */ public boolean isAuthorizationConfigured() { - return !WITHOUT_AUTHENTICATION.equals(securityIdentifier); + return WITHOUT_AUTHENTICATION.equals(securityIdentifier) == false; } /** @@ -559,10 +565,10 @@ public class SURL { * @see SecurityUtils#isNonSSLAuthenticationAllowed() */ private static void applyEndpointAccessAuthentication(URLConnection http, SecurityAuthentication authentication) { - if (authentication.isPublic()) { + if (authentication.isPublic()) // Shortcut: No need to apply authentication. return; - } + if (http instanceof HttpsURLConnection || SecurityUtils.isNonSSLAuthenticationAllowed()) { SecurityAccessInterceptor accessInterceptor = SecurityUtils.getAccessInterceptor(authentication); accessInterceptor.apply(authentication, http); @@ -580,20 +586,18 @@ public class SURL { * @param headers map Keys with values (can be String or list of String) */ private static void applyAdditionalHeaders(URLConnection http, Map headers) { - if (headers == null || headers.isEmpty()) { + if (headers == null || headers.isEmpty()) return; - } + for (Map.Entry header : headers.entrySet()) { - Object value = header.getValue(); - if (value instanceof String) { + final Object value = header.getValue(); + if (value instanceof String) http.setRequestProperty(header.getKey(), (String) value); - } else if (value instanceof List) { - for (Object item : (List) value) { - if (item != null) { + else if (value instanceof List) + for (Object item : (List) value) + if (item != null) http.addRequestProperty(header.getKey(), item.toString()); - } - } - } + } } @@ -603,14 +607,10 @@ public class SURL { * * @param url URL with UserInfo part * @return url without UserInfo part + * @throws MalformedURLException */ - private static URL removeUserInfo(URL url) { - try { - return new URL(removeUserInfoFromUrlPath(url.toExternalForm())); - } catch (MalformedURLException e) { - e.printStackTrace(); - return url; - } + private static URL removeUserInfo(URL url) throws MalformedURLException { + return new URL(removeUserInfoFromUrlPath(url.toExternalForm())); } /** @@ -622,10 +622,10 @@ public class SURL { */ private static String removeUserInfoFromUrlPath(String url) { // Simple solution: - Matcher matcher = PATTERN_USERINFO.matcher(url); - if (matcher.find()) { + final Matcher matcher = PATTERN_USERINFO.matcher(url); + if (matcher.find()) return matcher.replaceFirst("$1$3"); - } + return url; } } diff --git a/src/net/sourceforge/plantuml/security/SecurityUtils.java b/src/net/sourceforge/plantuml/security/SecurityUtils.java index a67a5b9a1..22b533e4a 100644 --- a/src/net/sourceforge/plantuml/security/SecurityUtils.java +++ b/src/net/sourceforge/plantuml/security/SecurityUtils.java @@ -351,7 +351,7 @@ public class SecurityUtils { */ public static SecurityCredentials loadSecurityCredentials(String userToken) { if (userToken != null && checkFileSystemSaveCharactersStrict(userToken) && !NO_CREDENTIALS.equals(userToken)) { - SFile securityPath = getSecurityPath(); + final SFile securityPath = getSecurityPath(); if (securityPath != null) { // SFile does not allow access to the security path (to hide the credentials in DSL scripts) File securityFilePath = securityPath.conv();