This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/main by this push:
new 7a33e07c457 Tighten up where we can download resources for Jose from
(#3108)
7a33e07c457 is described below
commit 7a33e07c45782d959aded4bca6a9d637e75b95e9
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Tue May 12 16:15:53 2026 +0100
Tighten up where we can download resources for Jose from (#3108)
---
.../httpsignature/utils/KeyManagementUtils.java | 22 +++++++++++++++++++++-
.../cxf/rs/security/jose/common/JoseUtils.java | 21 ++++++++++++++++++++-
.../cxf/rs/security/jose/jwk/JwkUtilsTest.java | 14 ++++++++++++++
.../filters/JwsJwksJwtAccessTokenValidator.java | 18 +++++++++++++++++-
.../oauth2/services/AuthorizationMetadata.java | 11 +++++++++--
.../JwsJwksJwtAccessTokenValidatorTest.java | 5 +++++
6 files changed, 86 insertions(+), 5 deletions(-)
diff --git
a/rt/rs/security/http-signature/src/main/java/org/apache/cxf/rs/security/httpsignature/utils/KeyManagementUtils.java
b/rt/rs/security/http-signature/src/main/java/org/apache/cxf/rs/security/httpsignature/utils/KeyManagementUtils.java
index 766ae28df7d..e4a4a77be6e 100644
---
a/rt/rs/security/http-signature/src/main/java/org/apache/cxf/rs/security/httpsignature/utils/KeyManagementUtils.java
+++
b/rt/rs/security/http-signature/src/main/java/org/apache/cxf/rs/security/httpsignature/utils/KeyManagementUtils.java
@@ -20,6 +20,7 @@ package org.apache.cxf.rs.security.httpsignature.utils;
import java.io.File;
import java.io.InputStream;
+import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyStore;
import java.security.PrivateKey;
@@ -203,7 +204,7 @@ public final class KeyManagementUtils {
} else {
try {
url = new URL(loc);
- } catch (Exception ex) {
+ } catch (MalformedURLException ex) {
// it can be either a classpath or file resource without a
scheme
url = getClasspathResourceURL(loc, KeyManagementUtils.class,
bus);
if (url == null) {
@@ -213,6 +214,9 @@ public final class KeyManagementUtils {
}
}
}
+ if (url != null) {
+ checkSupportedResourceUrlScheme(url, loc);
+ }
}
if (url == null) {
LOG.warning("No resource " + loc + " is available");
@@ -220,6 +224,22 @@ public final class KeyManagementUtils {
return url;
}
+ private static void checkSupportedResourceUrlScheme(URL url, String loc) {
+ String scheme = url.getProtocol();
+ if ("https".equalsIgnoreCase(scheme)
+ || "file".equalsIgnoreCase(scheme)
+ || "jar".equalsIgnoreCase(scheme)
+ || "zip".equalsIgnoreCase(scheme)
+ || "wsjar".equalsIgnoreCase(scheme)) {
+ return;
+ }
+ if ("http".equalsIgnoreCase(scheme)) {
+ throw new SignatureException("URL resource must use HTTPS: " +
loc);
+ }
+ throw new SignatureException("URL scheme '" + scheme
+ + "' is not supported for HTTP signature
resource loading: " + loc);
+ }
+
private static URL getClasspathResourceURL(String path, Class<?>
callingClass, Bus bus) {
URL url = ClassLoaderUtils.getResource(path, callingClass);
return url == null ? getResource(path, URL.class, bus) : url;
diff --git
a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseUtils.java
b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseUtils.java
index 0b52a35ef95..2bfdfaa554a 100644
---
a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseUtils.java
+++
b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseUtils.java
@@ -21,6 +21,7 @@ package org.apache.cxf.rs.security.jose.common;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.spec.AlgorithmParameterSpec;
@@ -176,7 +177,7 @@ public final class JoseUtils {
} else {
try {
url = new URL(loc);
- } catch (Exception ex) {
+ } catch (MalformedURLException ex) {
// it can be either a classpath or file resource without a
scheme
url = JoseUtils.getClasspathResourceURL(loc, JoseUtils.class,
bus);
if (url == null) {
@@ -186,6 +187,9 @@ public final class JoseUtils {
}
}
}
+ if (url != null) {
+ checkSupportedResourceUrlScheme(url, loc);
+ }
}
if (url == null) {
LOG.warning("No resource " + loc + " is available");
@@ -193,6 +197,21 @@ public final class JoseUtils {
return url;
}
+ private static void checkSupportedResourceUrlScheme(URL url, String loc)
throws IOException {
+ String scheme = url.getProtocol();
+ if ("https".equalsIgnoreCase(scheme)
+ || "file".equalsIgnoreCase(scheme)
+ || "jar".equalsIgnoreCase(scheme)
+ || "zip".equalsIgnoreCase(scheme)
+ || "wsjar".equalsIgnoreCase(scheme)) {
+ return;
+ }
+ if ("http".equalsIgnoreCase(scheme)) {
+ throw new IOException("URL resource must use HTTPS: " + loc);
+ }
+ throw new IOException("URL scheme '" + scheme + "' is not supported
for JOSE resource loading: " + loc);
+ }
+
public static URL getClasspathResourceURL(String path, Class<?>
callingClass, Bus bus) {
URL url = ClassLoaderUtils.getResource(path, callingClass);
return url == null ? getResource(path, URL.class, bus) : url;
diff --git
a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java
b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java
index f7f30daccbb..68818d71501 100644
---
a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java
+++
b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java
@@ -39,6 +39,7 @@ import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class JwkUtilsTest {
@@ -208,6 +209,19 @@ public class JwkUtilsTest {
}
}
+ @Test
+ public void testLoadPublicJwkSetRejectsHttpUrl() throws Exception {
+ final Properties props = new Properties();
+ props.setProperty(JoseConstants.RSSEC_KEY_STORE_FILE,
"http://example.com/keys.jwks");
+ try {
+ JwkUtils.loadPublicJwkSet(null, props);
+ fail();
+ } catch (JwkException e) {
+ assertNotNull(e.getCause());
+ assertTrue(e.getCause().getMessage().contains("must use HTTPS"));
+ }
+ }
+
@Test
public void testEcLeadingZeros() throws Exception {
try (InputStream inputStream =
this.getClass().getResourceAsStream("cert.pem")) {
diff --git
a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/JwsJwksJwtAccessTokenValidator.java
b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/JwsJwksJwtAccessTokenValidator.java
index b9e22be589d..563d80aeb50 100644
---
a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/JwsJwksJwtAccessTokenValidator.java
+++
b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/JwsJwksJwtAccessTokenValidator.java
@@ -18,6 +18,8 @@
*/
package org.apache.cxf.rs.security.oauth2.filters;
+import java.net.MalformedURLException;
+import java.net.URL;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
@@ -55,7 +57,7 @@ public class JwsJwksJwtAccessTokenValidator extends
JwtAccessTokenValidator {
}
public void setJwksURL(String jwksURL) {
- this.jwksURL = jwksURL;
+ this.jwksURL = validateJwksURL(jwksURL);
}
@Override
@@ -88,6 +90,20 @@ public class JwsJwksJwtAccessTokenValidator extends
JwtAccessTokenValidator {
.accept(MediaType.APPLICATION_JSON).get(JsonWebKeys.class);
}
+ private static String validateJwksURL(String theJwksURL) {
+ Objects.requireNonNull(theJwksURL, "JWK Set URL must be specified");
+ final URL url;
+ try {
+ url = new URL(theJwksURL);
+ } catch (MalformedURLException ex) {
+ throw new IllegalArgumentException("Invalid JWK Set URL: " +
theJwksURL, ex);
+ }
+ if (!"https".equalsIgnoreCase(url.getProtocol())) {
+ throw new IllegalArgumentException("JWK Set URL must use HTTPS
scheme");
+ }
+ return theJwksURL;
+ }
+
// from Java 11
@SuppressWarnings("unchecked")
static <T> Predicate<T> not(Predicate<? super T> target) {
diff --git
a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AuthorizationMetadata.java
b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AuthorizationMetadata.java
index ad91bacea4c..eaa8febeb07 100644
---
a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AuthorizationMetadata.java
+++
b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AuthorizationMetadata.java
@@ -91,11 +91,11 @@ public class AuthorizationMetadata extends JsonMapObject {
}
public URL getJwksURL() {
- return getURLProperty(JWKS_URI);
+ return checkHttpsScheme(getURLProperty(JWKS_URI), JWKS_URI);
}
public void setJwksURL(URL jwksURL) {
- setURLProperty(JWKS_URI, jwksURL);
+ setURLProperty(JWKS_URI, checkHttpsScheme(jwksURL, JWKS_URI));
}
public URL getRegistrationEndpoint() {
@@ -263,4 +263,11 @@ public class AuthorizationMetadata extends JsonMapObject {
super.setProperty(name, url != null ? url.toString() : null);
}
+ private static URL checkHttpsScheme(URL url, String name) {
+ if (url != null && !"https".equalsIgnoreCase(url.getProtocol())) {
+ throw new IllegalArgumentException(name + " must use HTTPS
scheme");
+ }
+ return url;
+ }
+
}
diff --git
a/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/filters/JwsJwksJwtAccessTokenValidatorTest.java
b/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/filters/JwsJwksJwtAccessTokenValidatorTest.java
index 71a21de2ee7..4a16a68ad1f 100644
---
a/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/filters/JwsJwksJwtAccessTokenValidatorTest.java
+++
b/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/filters/JwsJwksJwtAccessTokenValidatorTest.java
@@ -87,4 +87,9 @@ public class JwsJwksJwtAccessTokenValidatorTest {
new
JwsJwksJwtAccessTokenValidator().getInitializedSignatureVerifier(new
JwsHeaders());
}
+ @Test(expected = IllegalArgumentException.class)
+ public void testSetJwksURLRejectsHttp() {
+ new JwsJwksJwtAccessTokenValidator().setJwksURL("http://any.url");
+ }
+
}
\ No newline at end of file