From acce506ab387a7792b44676988b6490febd7a24e Mon Sep 17 00:00:00 2001 From: milanmajchrak Date: Wed, 11 Sep 2024 13:36:07 +0200 Subject: [PATCH 1/5] Encoded the UTF-8 characters from the redirect URL to UTF --- .../clarin/ClarinShibbolethLoginFilter.java | 8 +++++++- .../org/dspace/app/rest/utils/ClarinUtils.java | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/clarin/ClarinShibbolethLoginFilter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/clarin/ClarinShibbolethLoginFilter.java index 02ecaa593a90..f15acdf03bab 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/clarin/ClarinShibbolethLoginFilter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/clarin/ClarinShibbolethLoginFilter.java @@ -22,6 +22,7 @@ import org.dspace.app.rest.security.DSpaceAuthentication; import org.dspace.app.rest.security.RestAuthenticationService; import org.dspace.app.rest.security.StatelessLoginFilter; +import org.dspace.app.rest.utils.ClarinUtils; import org.dspace.authenticate.clarin.ClarinShibAuthentication; import org.dspace.authenticate.clarin.ShibHeaders; import org.dspace.content.clarin.ClarinVerificationToken; @@ -307,7 +308,12 @@ private void redirectAfterSuccess(HttpServletRequest request, HttpServletRespons if (StringUtils.equalsAnyIgnoreCase(redirectHostName, allowedHostNames.toArray(new String[0]))) { log.debug("Shibboleth redirecting to " + redirectUrl); - response.sendRedirect(redirectUrl); + // Encode the UTF-8 characters from redirect URL to UTF-8, to ensure it's properly encoded for the browser + String encodedRedirectUrl = ClarinUtils.encodeNonAsciiCharacters(redirectUrl); + if (StringUtils.isEmpty(encodedRedirectUrl)) { + log.error("Invalid Encoded Shibboleth redirectURL=" + redirectUrl + ". URL is empty!"); + } + response.sendRedirect(encodedRedirectUrl); } else { log.error("Invalid Shibboleth redirectURL=" + redirectUrl + ". URL doesn't match hostname of server or UI!"); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ClarinUtils.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ClarinUtils.java index 2a93f5793205..5c3ee64f4a1f 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ClarinUtils.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ClarinUtils.java @@ -7,6 +7,8 @@ */ package org.dspace.app.rest.utils; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; @@ -15,6 +17,7 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; /** @@ -60,4 +63,19 @@ public void checkServerTrusted(java.security.cert.X509Certificate[] certs, Strin throw new RuntimeException("Error disabling SSL certificate validation", e); } } + + /** + * Function to encode only non-ASCII characters + */ + public static String encodeNonAsciiCharacters(String input) { + StringBuilder result = new StringBuilder(); + for (char ch : input.toCharArray()) { + if (!StringUtils.isAsciiPrintable(String.valueOf(ch))) { // Use Apache Commons method + result.append(URLEncoder.encode(String.valueOf(ch), StandardCharsets.UTF_8)); + } else { + result.append(ch); // Leave ASCII characters intact + } + } + return result.toString(); + } } From e6e26733d51dd9c91ca87662148f5e7c3f8c03cf Mon Sep 17 00:00:00 2001 From: milanmajchrak Date: Tue, 17 Sep 2024 10:08:27 +0200 Subject: [PATCH 2/5] Moved ClarinUtils into Utils class --- .../app/rest/ClarinDiscoJuiceFeedsDownloadService.java | 4 ++-- .../app/rest/{utils/ClarinUtils.java => dq/Utils.java} | 6 +++--- .../rest/security/clarin/ClarinShibbolethLoginFilter.java | 3 +-- .../dspace/app/rest/ClarinDiscoJuiceFeedsControllerIT.java | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) rename dspace-server-webapp/src/main/java/org/dspace/app/rest/{utils/ClarinUtils.java => dq/Utils.java} (96%) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/ClarinDiscoJuiceFeedsDownloadService.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/ClarinDiscoJuiceFeedsDownloadService.java index 7fdd9a9ade54..6451e4d281f6 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/ClarinDiscoJuiceFeedsDownloadService.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/ClarinDiscoJuiceFeedsDownloadService.java @@ -34,7 +34,7 @@ import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.Logger; -import org.dspace.app.rest.utils.ClarinUtils; +import org.dspace.app.rest.dq.Utils; import org.dspace.services.ConfigurationService; import org.dspace.utils.DSpace; import org.json.simple.JSONArray; @@ -237,7 +237,7 @@ private static JSONArray downloadJSON(String url) { conn.setReadTimeout(10000); // Disable SSL certificate validation if (disableSSL && conn instanceof HttpsURLConnection) { - ClarinUtils.disableCertificateValidation((HttpsURLConnection) conn); + Utils.disableCertificateValidation((HttpsURLConnection) conn); } //Caution does not follow redirects, and even if you set it to http->https is not possible Object obj = parser.parse(new InputStreamReader(conn.getInputStream())); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ClarinUtils.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/dq/Utils.java similarity index 96% rename from dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ClarinUtils.java rename to dspace-server-webapp/src/main/java/org/dspace/app/rest/dq/Utils.java index 5c3ee64f4a1f..7c8d33b45baf 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ClarinUtils.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/dq/Utils.java @@ -5,7 +5,7 @@ * * http://www.dspace.org/license/ */ -package org.dspace.app.rest.utils; +package org.dspace.app.rest.dq; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -26,9 +26,9 @@ * @author Milan Majchrak (dspace at dataquest.sk) */ @Component -public class ClarinUtils { +public class Utils { - private ClarinUtils() { + private Utils() { } /** diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/clarin/ClarinShibbolethLoginFilter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/clarin/ClarinShibbolethLoginFilter.java index f15acdf03bab..4e400c5f9f9f 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/clarin/ClarinShibbolethLoginFilter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/clarin/ClarinShibbolethLoginFilter.java @@ -22,7 +22,6 @@ import org.dspace.app.rest.security.DSpaceAuthentication; import org.dspace.app.rest.security.RestAuthenticationService; import org.dspace.app.rest.security.StatelessLoginFilter; -import org.dspace.app.rest.utils.ClarinUtils; import org.dspace.authenticate.clarin.ClarinShibAuthentication; import org.dspace.authenticate.clarin.ShibHeaders; import org.dspace.content.clarin.ClarinVerificationToken; @@ -309,7 +308,7 @@ private void redirectAfterSuccess(HttpServletRequest request, HttpServletRespons if (StringUtils.equalsAnyIgnoreCase(redirectHostName, allowedHostNames.toArray(new String[0]))) { log.debug("Shibboleth redirecting to " + redirectUrl); // Encode the UTF-8 characters from redirect URL to UTF-8, to ensure it's properly encoded for the browser - String encodedRedirectUrl = ClarinUtils.encodeNonAsciiCharacters(redirectUrl); + String encodedRedirectUrl = org.dspace.app.rest.dq.Utils.encodeNonAsciiCharacters(redirectUrl); if (StringUtils.isEmpty(encodedRedirectUrl)) { log.error("Invalid Encoded Shibboleth redirectURL=" + redirectUrl + ". URL is empty!"); } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinDiscoJuiceFeedsControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinDiscoJuiceFeedsControllerIT.java index 0075011fd0bf..2503cf741052 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinDiscoJuiceFeedsControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinDiscoJuiceFeedsControllerIT.java @@ -21,8 +21,8 @@ import javax.net.ssl.HttpsURLConnection; import org.apache.commons.lang3.StringUtils; +import org.dspace.app.rest.dq.Utils; import org.dspace.app.rest.test.AbstractControllerIntegrationTest; -import org.dspace.app.rest.utils.ClarinUtils; import org.dspace.services.ConfigurationService; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; @@ -64,7 +64,7 @@ public void testDiscoFeedURL() throws Exception { // Disable SSL certificate validation if (disableSSL && conn instanceof HttpsURLConnection) { - ClarinUtils.disableCertificateValidation((HttpsURLConnection) conn); + Utils.disableCertificateValidation((HttpsURLConnection) conn); } Object obj = parser.parse(new InputStreamReader(conn.getInputStream())); From e301bc79f27db87ba8e86d343653346a2e2f85ec Mon Sep 17 00:00:00 2001 From: milanmajchrak Date: Tue, 17 Sep 2024 10:38:27 +0200 Subject: [PATCH 3/5] Added a new `dq` package into ComponentScan --- .../main/java/org/dspace/app/rest/utils/ApplicationConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ApplicationConfig.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ApplicationConfig.java index 48538deb13d4..2c26608d12ad 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ApplicationConfig.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ApplicationConfig.java @@ -30,6 +30,7 @@ // trouble. Be careful what you add here. @ComponentScan( { "org.dspace.app.rest.converter", + "org.dspace.app.rest.dq", "org.dspace.app.rest.repository", "org.dspace.app.rest.utils", "org.dspace.app.configuration", From 37212bc60f5946f864e9a11caaa941de21ca1a09 Mon Sep 17 00:00:00 2001 From: milanmajchrak Date: Tue, 17 Sep 2024 11:15:58 +0200 Subject: [PATCH 4/5] Moved dq.Utils into DSpace utils.Utils because the components with the same name causes conflicts. --- .../ClarinDiscoJuiceFeedsDownloadService.java | 2 +- .../java/org/dspace/app/rest/dq/Utils.java | 81 ------------------- .../clarin/ClarinShibbolethLoginFilter.java | 2 +- .../java/org/dspace/app/rest/utils/Utils.java | 57 +++++++++++++ .../ClarinDiscoJuiceFeedsControllerIT.java | 2 +- 5 files changed, 60 insertions(+), 84 deletions(-) delete mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/dq/Utils.java diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/ClarinDiscoJuiceFeedsDownloadService.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/ClarinDiscoJuiceFeedsDownloadService.java index 6451e4d281f6..73b5d2b3dfef 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/ClarinDiscoJuiceFeedsDownloadService.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/ClarinDiscoJuiceFeedsDownloadService.java @@ -34,7 +34,7 @@ import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.Logger; -import org.dspace.app.rest.dq.Utils; +import org.dspace.app.rest.utils.Utils; import org.dspace.services.ConfigurationService; import org.dspace.utils.DSpace; import org.json.simple.JSONArray; diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/dq/Utils.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/dq/Utils.java deleted file mode 100644 index 7c8d33b45baf..000000000000 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/dq/Utils.java +++ /dev/null @@ -1,81 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ -package org.dspace.app.rest.dq; - -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Component; - -/** - * Collection of utility methods for clarin customized operations - * - * @author Milan Majchrak (dspace at dataquest.sk) - */ -@Component -public class Utils { - - private Utils() { - } - - /** - * Disables SSL certificate validation for the given connection - * - * @param connection - */ - public static void disableCertificateValidation(HttpsURLConnection connection) { - try { - // Create a TrustManager that trusts all certificates - TrustManager[] trustAllCerts = { new X509TrustManager() { - public java.security.cert.X509Certificate[] getAcceptedIssuers() { - return null; - } - - public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { - } - - public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { - } } - }; - - // Install the TrustManager - SSLContext sslContext = SSLContext.getInstance("SSL"); - sslContext.init(null, trustAllCerts, new SecureRandom()); - connection.setSSLSocketFactory(sslContext.getSocketFactory()); - - // Set a HostnameVerifier that accepts all hostnames - connection.setHostnameVerifier((hostname, session) -> true); - - } catch (NoSuchAlgorithmException | KeyManagementException e) { - throw new RuntimeException("Error disabling SSL certificate validation", e); - } - } - - /** - * Function to encode only non-ASCII characters - */ - public static String encodeNonAsciiCharacters(String input) { - StringBuilder result = new StringBuilder(); - for (char ch : input.toCharArray()) { - if (!StringUtils.isAsciiPrintable(String.valueOf(ch))) { // Use Apache Commons method - result.append(URLEncoder.encode(String.valueOf(ch), StandardCharsets.UTF_8)); - } else { - result.append(ch); // Leave ASCII characters intact - } - } - return result.toString(); - } -} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/clarin/ClarinShibbolethLoginFilter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/clarin/ClarinShibbolethLoginFilter.java index 4e400c5f9f9f..78887d5f5e58 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/clarin/ClarinShibbolethLoginFilter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/clarin/ClarinShibbolethLoginFilter.java @@ -308,7 +308,7 @@ private void redirectAfterSuccess(HttpServletRequest request, HttpServletRespons if (StringUtils.equalsAnyIgnoreCase(redirectHostName, allowedHostNames.toArray(new String[0]))) { log.debug("Shibboleth redirecting to " + redirectUrl); // Encode the UTF-8 characters from redirect URL to UTF-8, to ensure it's properly encoded for the browser - String encodedRedirectUrl = org.dspace.app.rest.dq.Utils.encodeNonAsciiCharacters(redirectUrl); + String encodedRedirectUrl = org.dspace.app.rest.utils.Utils.encodeNonAsciiCharacters(redirectUrl); if (StringUtils.isEmpty(encodedRedirectUrl)) { log.error("Invalid Encoded Shibboleth redirectURL=" + redirectUrl + ". URL is empty!"); } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/Utils.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/Utils.java index ed6e26ed0fb7..347a23b86de5 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/Utils.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/Utils.java @@ -29,6 +29,11 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; @@ -44,6 +49,10 @@ import java.util.TreeSet; import java.util.UUID; import javax.annotation.Nullable; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; @@ -1076,4 +1085,52 @@ private BaseObjectRest findBaseObjectRest(Context context, String apiCategory, S context.restoreAuthSystemState(); } } + + /** + * Disables SSL certificate validation for the given connection + * + * @param connection + */ + public static void disableCertificateValidation(HttpsURLConnection connection) { + try { + // Create a TrustManager that trusts all certificates + TrustManager[] trustAllCerts = { new X509TrustManager() { + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + + public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { + } + + public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { + } } + }; + + // Install the TrustManager + SSLContext sslContext = SSLContext.getInstance("SSL"); + sslContext.init(null, trustAllCerts, new SecureRandom()); + connection.setSSLSocketFactory(sslContext.getSocketFactory()); + + // Set a HostnameVerifier that accepts all hostnames + connection.setHostnameVerifier((hostname, session) -> true); + + } catch (NoSuchAlgorithmException | KeyManagementException e) { + throw new RuntimeException("Error disabling SSL certificate validation", e); + } + } + + /** + * Function to encode only non-ASCII characters + */ + public static String encodeNonAsciiCharacters(String input) { + StringBuilder result = new StringBuilder(); + for (char ch : input.toCharArray()) { + if (!StringUtils.isAsciiPrintable(String.valueOf(ch))) { // Use Apache Commons method + result.append(URLEncoder.encode(String.valueOf(ch), StandardCharsets.UTF_8)); + } else { + result.append(ch); // Leave ASCII characters intact + } + } + return result.toString(); + } } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinDiscoJuiceFeedsControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinDiscoJuiceFeedsControllerIT.java index 2503cf741052..d20298ac9116 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinDiscoJuiceFeedsControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinDiscoJuiceFeedsControllerIT.java @@ -21,8 +21,8 @@ import javax.net.ssl.HttpsURLConnection; import org.apache.commons.lang3.StringUtils; -import org.dspace.app.rest.dq.Utils; import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.app.rest.utils.Utils; import org.dspace.services.ConfigurationService; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; From 95d443066ef46086229bd623834c3b215e29711c Mon Sep 17 00:00:00 2001 From: milanmajchrak Date: Tue, 17 Sep 2024 11:53:14 +0200 Subject: [PATCH 5/5] Removed *.dq component scan from the App --- .../main/java/org/dspace/app/rest/utils/ApplicationConfig.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ApplicationConfig.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ApplicationConfig.java index 2c26608d12ad..48538deb13d4 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ApplicationConfig.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ApplicationConfig.java @@ -30,7 +30,6 @@ // trouble. Be careful what you add here. @ComponentScan( { "org.dspace.app.rest.converter", - "org.dspace.app.rest.dq", "org.dspace.app.rest.repository", "org.dspace.app.rest.utils", "org.dspace.app.configuration",