From 7b66f650eef9325392c6fe9a79b5b784c4eca555 Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Fri, 1 Dec 2023 15:04:52 +0100 Subject: [PATCH 01/19] Fix ApplicationServerOptions for IAS --- .../com/sap/cloud/security/test/ApplicationServerOptions.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java-security-test/src/main/java/com/sap/cloud/security/test/ApplicationServerOptions.java b/java-security-test/src/main/java/com/sap/cloud/security/test/ApplicationServerOptions.java index b9996d3ae..30630b6bb 100644 --- a/java-security-test/src/main/java/com/sap/cloud/security/test/ApplicationServerOptions.java +++ b/java-security-test/src/main/java/com/sap/cloud/security/test/ApplicationServerOptions.java @@ -69,8 +69,8 @@ public static ApplicationServerOptions forService(Service service, int jwksPort) instance = new ApplicationServerOptions(new IasTokenAuthenticator() .withServiceConfiguration(OAuth2ServiceConfigurationBuilder.forService(Service.IAS) .withClientId(SecurityTestRule.DEFAULT_CLIENT_ID) - .withUrl("http://localhost") - .withDomains("localhost") + .withUrl(String.format("http://localhost:%d", jwksPort)) + .withDomains(String.format("localhost:%d", jwksPort)) .build())); break; default: From a4803ebb623aca8e2b04fdcd5e6431fc09b2ea38 Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Fri, 1 Dec 2023 17:42:32 +0100 Subject: [PATCH 02/19] Implement XsuaaJkuFactory to fix breaking change in java-security-test incompatibilities via service loader --- .../cloud/security/token/XsuaaJkuFactory.java | 5 +++ .../token/XsuaaLocalhostJkuFactory.java | 15 +++++++++ ...m.sap.cloud.security.token.XsuaaJkuFactory | 1 + .../XsuaaJwtSignatureValidator.java | 28 +++++++++++++++-- .../spring/security/TestControllerTest.java | 2 +- .../junitjupiter/TestControllerXsuaaTest.java | 13 +++++++- .../test/resources/application-multixsuaa.yml | 2 +- .../src/test/resources/application.yml | 2 +- .../spring/xsuaa/TestControllerTest.java | 8 ++--- .../junitjupiter/TestControllerTest.java | 5 +-- .../token/authentication/XsuaaJwtDecoder.java | 31 +++++++++++++++++-- 11 files changed, 95 insertions(+), 17 deletions(-) create mode 100644 java-api/src/main/java/com/sap/cloud/security/token/XsuaaJkuFactory.java create mode 100644 java-security-test/src/main/java/com/sap/cloud/security/token/XsuaaLocalhostJkuFactory.java create mode 100644 java-security-test/src/main/resources/META-INF/services/com.sap.cloud.security.token.XsuaaJkuFactory diff --git a/java-api/src/main/java/com/sap/cloud/security/token/XsuaaJkuFactory.java b/java-api/src/main/java/com/sap/cloud/security/token/XsuaaJkuFactory.java new file mode 100644 index 000000000..f45a8a38b --- /dev/null +++ b/java-api/src/main/java/com/sap/cloud/security/token/XsuaaJkuFactory.java @@ -0,0 +1,5 @@ +package com.sap.cloud.security.token; + +public interface XsuaaJkuFactory { + String create(Token token); +} diff --git a/java-security-test/src/main/java/com/sap/cloud/security/token/XsuaaLocalhostJkuFactory.java b/java-security-test/src/main/java/com/sap/cloud/security/token/XsuaaLocalhostJkuFactory.java new file mode 100644 index 000000000..a899e02ca --- /dev/null +++ b/java-security-test/src/main/java/com/sap/cloud/security/token/XsuaaLocalhostJkuFactory.java @@ -0,0 +1,15 @@ +package com.sap.cloud.security.token; + +public class XsuaaLocalhostJkuFactory implements XsuaaJkuFactory { + + @Override + public String create(Token token) { + String tokenJku = (String) token.getHeaders().get(TokenHeader.JWKS_URL); + + if (tokenJku.contains("localhost") || tokenJku.contains("127.0.0.1")) { + return tokenJku; + } + + throw new IllegalArgumentException("JKU is not trusted because it does not target localhost."); + } +} \ No newline at end of file diff --git a/java-security-test/src/main/resources/META-INF/services/com.sap.cloud.security.token.XsuaaJkuFactory b/java-security-test/src/main/resources/META-INF/services/com.sap.cloud.security.token.XsuaaJkuFactory new file mode 100644 index 000000000..6d50ff525 --- /dev/null +++ b/java-security-test/src/main/resources/META-INF/services/com.sap.cloud.security.token.XsuaaJkuFactory @@ -0,0 +1 @@ +com.sap.cloud.security.token.XsuaaLocalhostJkuFactory \ No newline at end of file diff --git a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java index a94ffdb61..7ee7cd4ec 100644 --- a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java +++ b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java @@ -3,15 +3,17 @@ import com.sap.cloud.security.config.OAuth2ServiceConfiguration; import com.sap.cloud.security.config.cf.CFConstants; import com.sap.cloud.security.token.Token; +import com.sap.cloud.security.token.XsuaaJkuFactory; import com.sap.cloud.security.xsuaa.client.OAuth2ServiceException; import com.sap.cloud.security.xsuaa.http.HttpHeaders; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.net.URI; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; -import java.util.Collections; -import java.util.Map; +import java.util.*; import static com.sap.cloud.security.config.cf.CFConstants.XSUAA.UAA_DOMAIN; import static com.sap.cloud.security.token.validation.validators.JsonWebKeyConstants.KEY_ID_VALUE_LEGACY; @@ -21,6 +23,18 @@ * Jwt Signature validator for Access tokens issued by Xsuaa service */ class XsuaaJwtSignatureValidator extends JwtSignatureValidator { + public static final Logger LOGGER = LoggerFactory.getLogger(XsuaaJwtSignatureValidator.class); + List jkuFactories = new ArrayList() { + { + try { + ServiceLoader.load(XsuaaJkuFactory.class).forEach(this::add); + LOGGER.debug("loaded XsuaaJkuFactory service providers: {}", this); + } catch (Error e) { + LOGGER.warn("Unexpected failure while loading XsuaaJkuFactory service providers: {}", e.getMessage()); + } + } + }; + XsuaaJwtSignatureValidator(OAuth2ServiceConfiguration configuration, OAuth2TokenKeyServiceWithCache tokenKeyService, OidcConfigurationServiceWithCache oidcConfigurationService) { super(configuration, tokenKeyService, oidcConfigurationService); } @@ -57,7 +71,15 @@ private PublicKey fetchPublicKey(Token token, JwtSignatureAlgorithm algorithm) t } String zidQueryParam = composeZidQueryParameter(token); - String jwksUri = configuration.isLegacyMode() ? configuration.getUrl() + "/token_keys" : configuration.getProperty(UAA_DOMAIN) + "/token_keys" + zidQueryParam; + + String jwksUri; + if(jkuFactories.isEmpty()) { + jwksUri = configuration.isLegacyMode() ? configuration.getUrl() + "/token_keys" : configuration.getProperty(UAA_DOMAIN) + "/token_keys" + zidQueryParam; + } else { + LOGGER.info("Loaded custom JKU factory"); + jwksUri = jkuFactories.get(0).create(token); + } + URI uri = URI.create(jwksUri); uri = uri.isAbsolute() ? uri : URI.create("https://" + jwksUri); Map params = Collections.singletonMap(HttpHeaders.X_ZID, token.getAppTid()); diff --git a/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/TestControllerTest.java b/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/TestControllerTest.java index f7fef2aad..fa489f210 100644 --- a/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/TestControllerTest.java +++ b/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/TestControllerTest.java @@ -35,7 +35,7 @@ public class TestControllerTest { private String jwtIas; @ClassRule - public static SecurityTestRule ruleXsuaa = SecurityTestRule.getInstance(Service.XSUAA).setPort(2223); + public static SecurityTestRule ruleXsuaa = SecurityTestRule.getInstance(Service.XSUAA); @ClassRule public static SecurityTestRule ruleIas = SecurityTestRule.getInstance(Service.IAS); diff --git a/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/junitjupiter/TestControllerXsuaaTest.java b/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/junitjupiter/TestControllerXsuaaTest.java index b7f4883d5..3482268b9 100644 --- a/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/junitjupiter/TestControllerXsuaaTest.java +++ b/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/junitjupiter/TestControllerXsuaaTest.java @@ -6,6 +6,9 @@ package sample.spring.security.junitjupiter; import com.sap.cloud.security.test.api.SecurityTestContext; +import com.sap.cloud.security.test.extension.XsuaaExtension; +import com.sap.cloud.security.token.Token; +import com.sap.cloud.security.token.TokenHeader; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -22,7 +25,7 @@ @SpringBootTest @AutoConfigureMockMvc -@ExtendWith(XsuaaExtensionFixedPort.class) +@ExtendWith(XsuaaExtension.class) @ActiveProfiles("multixsuaa") // properties are provided with /resources/application-multixsuaa.yml class TestControllerXsuaaTest { @@ -76,5 +79,13 @@ void readData_FORBIDDEN(SecurityTestContext securityTest) throws Exception { mvc.perform(get("/method").with(bearerToken(jwtNoScopes))) .andExpect(status().isForbidden()); } + + @Test + void acceptsOnlyLocalhostJku(SecurityTestContext securityTest) throws Exception { + Token jwt = securityTest.getPreconfiguredJwtGenerator().withLocalScopes("Read").withHeaderParameter(TokenHeader.JWKS_URL, "https://auth.google.com").createToken(); + + mvc.perform(get("/sayHello").with(bearerToken(jwt.getTokenValue()))) + .andExpect(status().isUnauthorized()); + } } diff --git a/samples/spring-security-hybrid-usage/src/test/resources/application-multixsuaa.yml b/samples/spring-security-hybrid-usage/src/test/resources/application-multixsuaa.yml index 4eba8762f..507eab350 100644 --- a/samples/spring-security-hybrid-usage/src/test/resources/application-multixsuaa.yml +++ b/samples/spring-security-hybrid-usage/src/test/resources/application-multixsuaa.yml @@ -6,7 +6,7 @@ sap: services: xsuaa[0]: xsappname: xsapp!t0815 - uaadomain: http://localhost:2223 + uaadomain: localhost clientid: sb-clientId!t0815 clientsecret: pwd url: http://localhost diff --git a/samples/spring-security-hybrid-usage/src/test/resources/application.yml b/samples/spring-security-hybrid-usage/src/test/resources/application.yml index 4b2549765..9a49eff6d 100644 --- a/samples/spring-security-hybrid-usage/src/test/resources/application.yml +++ b/samples/spring-security-hybrid-usage/src/test/resources/application.yml @@ -6,7 +6,7 @@ sap: services: xsuaa: xsappname: xsapp!t0815 - uaadomain: http://localhost:2223 + uaadomain: localhost clientid: sb-clientId!t0815 clientsecret: pwd url: http://localhost diff --git a/samples/spring-security-xsuaa-usage/src/test/java/sample/spring/xsuaa/TestControllerTest.java b/samples/spring-security-xsuaa-usage/src/test/java/sample/spring/xsuaa/TestControllerTest.java index 780492f6a..f23e88751 100644 --- a/samples/spring-security-xsuaa-usage/src/test/java/sample/spring/xsuaa/TestControllerTest.java +++ b/samples/spring-security-xsuaa-usage/src/test/java/sample/spring/xsuaa/TestControllerTest.java @@ -21,7 +21,6 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.RequestPostProcessor; -import static com.sap.cloud.security.test.SecurityTest.*; import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -29,10 +28,7 @@ @RunWith(SpringRunner.class) @SpringBootTest @AutoConfigureMockMvc -@TestPropertySource(properties = { - "xsuaa.uaadomain=" + DEFAULT_UAA_DOMAIN + ":2225", - "xsuaa.xsappname=" + DEFAULT_APP_ID, - "xsuaa.clientid=" + DEFAULT_CLIENT_ID }) +@TestPropertySource(properties = {"xsuaa.uaadomain=localhost", "xsuaa.xsappname=xsapp!t0815", "xsuaa.clientid=sb-clientId!t0815"}) public class TestControllerTest { @Autowired @@ -43,7 +39,7 @@ public class TestControllerTest { private String jwtAdmin; @ClassRule - public static SecurityTestRule rule = SecurityTestRule.getInstance(Service.XSUAA).setPort(2225); + public static SecurityTestRule rule = SecurityTestRule.getInstance(Service.XSUAA); @Before public void setUp() { diff --git a/samples/spring-security-xsuaa-usage/src/test/java/sample/spring/xsuaa/junitjupiter/TestControllerTest.java b/samples/spring-security-xsuaa-usage/src/test/java/sample/spring/xsuaa/junitjupiter/TestControllerTest.java index 160422b96..a8c89f05b 100644 --- a/samples/spring-security-xsuaa-usage/src/test/java/sample/spring/xsuaa/junitjupiter/TestControllerTest.java +++ b/samples/spring-security-xsuaa-usage/src/test/java/sample/spring/xsuaa/junitjupiter/TestControllerTest.java @@ -6,6 +6,7 @@ package sample.spring.xsuaa.junitjupiter; import com.sap.cloud.security.test.api.SecurityTestContext; +import com.sap.cloud.security.test.extension.XsuaaExtension; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -26,10 +27,10 @@ @SpringBootTest @AutoConfigureMockMvc @TestPropertySource(properties = { - "xsuaa.uaadomain=" + DEFAULT_UAA_DOMAIN + ":2224", + "xsuaa.uaadomain=" + DEFAULT_UAA_DOMAIN, "xsuaa.xsappname=" + DEFAULT_APP_ID, "xsuaa.clientid=" + DEFAULT_CLIENT_ID }) -@ExtendWith(XsuaaExtensionFixedPort.class) +@ExtendWith(XsuaaExtension.class) class TestControllerTest { @Autowired diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java index f0bfd6eab..e4a5eb21e 100644 --- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java +++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java @@ -9,6 +9,9 @@ import com.nimbusds.jwt.JWT; import com.nimbusds.jwt.JWTParser; import com.sap.cloud.security.config.cf.CFConstants; +import com.sap.cloud.security.token.ProviderNotFoundException; +import com.sap.cloud.security.token.Token; +import com.sap.cloud.security.token.XsuaaJkuFactory; import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration; import com.sap.cloud.security.xsuaa.token.TokenClaims; import org.json.JSONObject; @@ -25,6 +28,7 @@ import javax.annotation.Nullable; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; +import java.security.ProviderException; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; @@ -37,7 +41,18 @@ import static org.springframework.util.StringUtils.hasText; public class XsuaaJwtDecoder implements JwtDecoder { - private final Logger logger = LoggerFactory.getLogger(getClass()); + List jkuFactories = new ArrayList() { + { + try { + ServiceLoader.load(XsuaaJkuFactory.class).forEach(this::add); + logger.debug("loaded XsuaaJkuFactory service providers: {}", this); + } catch (Error e) { + logger.warn("Unexpected failure while loading XsuaaJkuFactory service providers: {}", e.getMessage()); + } + } + }; + + private static final Logger logger = LoggerFactory.getLogger(XsuaaJwtDecoder.class); private final XsuaaServiceConfiguration xsuaaServiceConfiguration; private final Duration cacheValidityInSeconds; private final int cacheSize; @@ -141,9 +156,21 @@ private static String getZid(JWT jwt) { } private Jwt verifyToken(String token, String kid, String uaaDomain, String zid) { + String jku; + if(jkuFactories.isEmpty()) { + jku = composeJku(uaaDomain, zid); + } else { + logger.info("Loaded custom JKU factory"); + try { + jku = jkuFactories.get(0).create(Token.create(token)); + } catch (IllegalArgumentException | ProviderException | ProviderNotFoundException e) { + throw new BadJwtException("JKU validation failed: " + e.getMessage()); + } + } + try { canVerifyWithKey(kid, uaaDomain); - return verifyWithKey(token, composeJku(uaaDomain, zid), kid); + return verifyWithKey(token, jku, kid); } catch (JwtValidationException ex) { throw ex; } catch (JwtException ex) { From e65b8b5bb0583ec83c27a173978e3a760b229655 Mon Sep 17 00:00:00 2001 From: liga-oz Date: Mon, 4 Dec 2023 10:19:15 +0100 Subject: [PATCH 03/19] remove XsuaaTest extension for fixed port Signed-off-by: liga-oz --- .../junitjupiter/XsuaaExtensionFixedPort.java | 15 --------------- .../junitjupiter/XsuaaExtensionFixedPort.java | 15 --------------- 2 files changed, 30 deletions(-) delete mode 100644 samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/junitjupiter/XsuaaExtensionFixedPort.java delete mode 100644 samples/spring-security-xsuaa-usage/src/test/java/sample/spring/xsuaa/junitjupiter/XsuaaExtensionFixedPort.java diff --git a/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/junitjupiter/XsuaaExtensionFixedPort.java b/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/junitjupiter/XsuaaExtensionFixedPort.java deleted file mode 100644 index 2b808a37b..000000000 --- a/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/junitjupiter/XsuaaExtensionFixedPort.java +++ /dev/null @@ -1,15 +0,0 @@ -/** - * SPDX-FileCopyrightText: 2018-2023 SAP SE or an SAP affiliate company and Cloud Security Client Java contributors - * SPDX-License-Identifier: Apache-2.0 - */ -package sample.spring.security.junitjupiter; - -import com.sap.cloud.security.test.extension.XsuaaExtension; - -public class XsuaaExtensionFixedPort extends XsuaaExtension { - - public XsuaaExtensionFixedPort() { - super(); - this.setPort(2223); - } -} diff --git a/samples/spring-security-xsuaa-usage/src/test/java/sample/spring/xsuaa/junitjupiter/XsuaaExtensionFixedPort.java b/samples/spring-security-xsuaa-usage/src/test/java/sample/spring/xsuaa/junitjupiter/XsuaaExtensionFixedPort.java deleted file mode 100644 index 386540771..000000000 --- a/samples/spring-security-xsuaa-usage/src/test/java/sample/spring/xsuaa/junitjupiter/XsuaaExtensionFixedPort.java +++ /dev/null @@ -1,15 +0,0 @@ -/** - * SPDX-FileCopyrightText: 2018-2023 SAP SE or an SAP affiliate company and Cloud Security Client Java contributors - * SPDX-License-Identifier: Apache-2.0 - */ -package sample.spring.xsuaa.junitjupiter; - -import com.sap.cloud.security.test.extension.XsuaaExtension; - -public class XsuaaExtensionFixedPort extends XsuaaExtension { - - public XsuaaExtensionFixedPort() { - super(); - this.setPort(2224); - } -} From 61a7fc5cb77017a7ea4ce3f64fb2bb18b3eb9132 Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Mon, 4 Dec 2023 11:23:18 +0100 Subject: [PATCH 04/19] Move XsuaaJkuFactory into 'validation' subpackage --- .../java/com/sap/cloud/security/token/XsuaaJkuFactory.java | 5 ----- .../cloud/security/token/validation/XsuaaJkuFactory.java | 7 +++++++ .../token/{ => validation}/XsuaaLocalhostJkuFactory.java | 5 ++++- .../services/com.sap.cloud.security.token.XsuaaJkuFactory | 1 - ...com.sap.cloud.security.token.validation.XsuaaJkuFactory | 1 + .../validation/validators/XsuaaJwtSignatureValidator.java | 2 +- .../xsuaa/token/authentication/XsuaaJwtDecoder.java | 2 +- 7 files changed, 14 insertions(+), 9 deletions(-) delete mode 100644 java-api/src/main/java/com/sap/cloud/security/token/XsuaaJkuFactory.java create mode 100644 java-api/src/main/java/com/sap/cloud/security/token/validation/XsuaaJkuFactory.java rename java-security-test/src/main/java/com/sap/cloud/security/token/{ => validation}/XsuaaLocalhostJkuFactory.java (75%) delete mode 100644 java-security-test/src/main/resources/META-INF/services/com.sap.cloud.security.token.XsuaaJkuFactory create mode 100644 java-security-test/src/main/resources/META-INF/services/com.sap.cloud.security.token.validation.XsuaaJkuFactory diff --git a/java-api/src/main/java/com/sap/cloud/security/token/XsuaaJkuFactory.java b/java-api/src/main/java/com/sap/cloud/security/token/XsuaaJkuFactory.java deleted file mode 100644 index f45a8a38b..000000000 --- a/java-api/src/main/java/com/sap/cloud/security/token/XsuaaJkuFactory.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.sap.cloud.security.token; - -public interface XsuaaJkuFactory { - String create(Token token); -} diff --git a/java-api/src/main/java/com/sap/cloud/security/token/validation/XsuaaJkuFactory.java b/java-api/src/main/java/com/sap/cloud/security/token/validation/XsuaaJkuFactory.java new file mode 100644 index 000000000..8a1552454 --- /dev/null +++ b/java-api/src/main/java/com/sap/cloud/security/token/validation/XsuaaJkuFactory.java @@ -0,0 +1,7 @@ +package com.sap.cloud.security.token.validation; + +import com.sap.cloud.security.token.Token; + +public interface XsuaaJkuFactory { + String create(Token token); +} diff --git a/java-security-test/src/main/java/com/sap/cloud/security/token/XsuaaLocalhostJkuFactory.java b/java-security-test/src/main/java/com/sap/cloud/security/token/validation/XsuaaLocalhostJkuFactory.java similarity index 75% rename from java-security-test/src/main/java/com/sap/cloud/security/token/XsuaaLocalhostJkuFactory.java rename to java-security-test/src/main/java/com/sap/cloud/security/token/validation/XsuaaLocalhostJkuFactory.java index a899e02ca..38663b89b 100644 --- a/java-security-test/src/main/java/com/sap/cloud/security/token/XsuaaLocalhostJkuFactory.java +++ b/java-security-test/src/main/java/com/sap/cloud/security/token/validation/XsuaaLocalhostJkuFactory.java @@ -1,4 +1,7 @@ -package com.sap.cloud.security.token; +package com.sap.cloud.security.token.validation; + +import com.sap.cloud.security.token.Token; +import com.sap.cloud.security.token.TokenHeader; public class XsuaaLocalhostJkuFactory implements XsuaaJkuFactory { diff --git a/java-security-test/src/main/resources/META-INF/services/com.sap.cloud.security.token.XsuaaJkuFactory b/java-security-test/src/main/resources/META-INF/services/com.sap.cloud.security.token.XsuaaJkuFactory deleted file mode 100644 index 6d50ff525..000000000 --- a/java-security-test/src/main/resources/META-INF/services/com.sap.cloud.security.token.XsuaaJkuFactory +++ /dev/null @@ -1 +0,0 @@ -com.sap.cloud.security.token.XsuaaLocalhostJkuFactory \ No newline at end of file diff --git a/java-security-test/src/main/resources/META-INF/services/com.sap.cloud.security.token.validation.XsuaaJkuFactory b/java-security-test/src/main/resources/META-INF/services/com.sap.cloud.security.token.validation.XsuaaJkuFactory new file mode 100644 index 000000000..c01c7af19 --- /dev/null +++ b/java-security-test/src/main/resources/META-INF/services/com.sap.cloud.security.token.validation.XsuaaJkuFactory @@ -0,0 +1 @@ +com.sap.cloud.security.token.validation.XsuaaLocalhostJkuFactory \ No newline at end of file diff --git a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java index 7ee7cd4ec..a3eab8620 100644 --- a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java +++ b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java @@ -3,7 +3,7 @@ import com.sap.cloud.security.config.OAuth2ServiceConfiguration; import com.sap.cloud.security.config.cf.CFConstants; import com.sap.cloud.security.token.Token; -import com.sap.cloud.security.token.XsuaaJkuFactory; +import com.sap.cloud.security.token.validation.XsuaaJkuFactory; import com.sap.cloud.security.xsuaa.client.OAuth2ServiceException; import com.sap.cloud.security.xsuaa.http.HttpHeaders; import org.slf4j.Logger; diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java index e4a5eb21e..ab963ff3b 100644 --- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java +++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java @@ -11,7 +11,7 @@ import com.sap.cloud.security.config.cf.CFConstants; import com.sap.cloud.security.token.ProviderNotFoundException; import com.sap.cloud.security.token.Token; -import com.sap.cloud.security.token.XsuaaJkuFactory; +import com.sap.cloud.security.token.validation.XsuaaJkuFactory; import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration; import com.sap.cloud.security.xsuaa.token.TokenClaims; import org.json.JSONObject; From 1fcd72c1c362d7d9998ced8a6b2fe7d2411fe47f Mon Sep 17 00:00:00 2001 From: liga-oz Date: Mon, 4 Dec 2023 11:27:16 +0100 Subject: [PATCH 05/19] formatting Signed-off-by: liga-oz --- .../token/validation/validators/JwtIssuerValidator.java | 1 + .../validation/validators/XsuaaJwtSignatureValidator.java | 6 ++++-- .../xsuaa/token/authentication/XsuaaJwtDecoder.java | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java index d9798c6f9..6542746a1 100644 --- a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java +++ b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java @@ -70,6 +70,7 @@ public ValidationResult validate(Token token) { } String issuerUrl = issuer.startsWith(HTTPS_SCHEME) || issuer.startsWith("http://localhost") ? issuer : HTTPS_SCHEME + issuer; + try { new URL(issuerUrl); } catch (MalformedURLException e) { diff --git a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java index 7ee7cd4ec..c9e580d25 100644 --- a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java +++ b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java @@ -73,8 +73,10 @@ private PublicKey fetchPublicKey(Token token, JwtSignatureAlgorithm algorithm) t String zidQueryParam = composeZidQueryParameter(token); String jwksUri; - if(jkuFactories.isEmpty()) { - jwksUri = configuration.isLegacyMode() ? configuration.getUrl() + "/token_keys" : configuration.getProperty(UAA_DOMAIN) + "/token_keys" + zidQueryParam; + if (jkuFactories.isEmpty()) { + jwksUri = configuration.isLegacyMode() + ? configuration.getUrl() + "/token_keys" + : configuration.getProperty(UAA_DOMAIN) + "/token_keys" + zidQueryParam; } else { LOGGER.info("Loaded custom JKU factory"); jwksUri = jkuFactories.get(0).create(token); diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java index e4a5eb21e..141f1a976 100644 --- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java +++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java @@ -157,7 +157,7 @@ private static String getZid(JWT jwt) { private Jwt verifyToken(String token, String kid, String uaaDomain, String zid) { String jku; - if(jkuFactories.isEmpty()) { + if (jkuFactories.isEmpty()) { jku = composeJku(uaaDomain, zid); } else { logger.info("Loaded custom JKU factory"); From 27a6b4fdef84632824188c50b00f4d63ac787116 Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Mon, 4 Dec 2023 11:35:22 +0100 Subject: [PATCH 06/19] For IAS issuer validation, add backward-compatibility with java-security-test via LocalhostIssuerValidator --- .../token/validation/TestIssuerValidator.java | 8 +++++ .../validation/LocalhostIssuerValidator.java | 13 +++++++ ...urity.token.validation.TestIssuerValidator | 1 + .../validators/JwtIssuerValidator.java | 36 ++++++++++++++++++- 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 java-api/src/main/java/com/sap/cloud/security/token/validation/TestIssuerValidator.java create mode 100644 java-security-test/src/main/java/com/sap/cloud/security/token/validation/LocalhostIssuerValidator.java create mode 100644 java-security-test/src/main/resources/META-INF/services/com.sap.cloud.security.token.validation.TestIssuerValidator diff --git a/java-api/src/main/java/com/sap/cloud/security/token/validation/TestIssuerValidator.java b/java-api/src/main/java/com/sap/cloud/security/token/validation/TestIssuerValidator.java new file mode 100644 index 000000000..f2bc80538 --- /dev/null +++ b/java-api/src/main/java/com/sap/cloud/security/token/validation/TestIssuerValidator.java @@ -0,0 +1,8 @@ +package com.sap.cloud.security.token.validation; + +/** + * This interface is for INTERNAL usage only to add backward-compatibility for test credentials with trusted domain 'localhost' to the issuer validation. + */ +public interface TestIssuerValidator { + boolean isValidIssuer(String issuer); +} \ No newline at end of file diff --git a/java-security-test/src/main/java/com/sap/cloud/security/token/validation/LocalhostIssuerValidator.java b/java-security-test/src/main/java/com/sap/cloud/security/token/validation/LocalhostIssuerValidator.java new file mode 100644 index 000000000..f7c26960f --- /dev/null +++ b/java-security-test/src/main/java/com/sap/cloud/security/token/validation/LocalhostIssuerValidator.java @@ -0,0 +1,13 @@ +package com.sap.cloud.security.token.validation; + +/** + * LocalhostIssuerValidator brings backward-compatibility for test credentials in consumer applications written before 2.17.0 that are used to validate java-security-test tokens. + * This is necessary for successful validation of localhost issuers that include a port when 'localhost' is defined as trusted domain without port in the service credentials. + * This class MUST NOT be loaded outside test scope and MUST be the ONLY implementation of {@link TestIssuerValidator}. + */ +public class LocalhostIssuerValidator implements TestIssuerValidator { + + public boolean isValidIssuer(String issuer) { + return issuer.startsWith("http://localhost") || issuer.startsWith("https://localhost"); + } +} diff --git a/java-security-test/src/main/resources/META-INF/services/com.sap.cloud.security.token.validation.TestIssuerValidator b/java-security-test/src/main/resources/META-INF/services/com.sap.cloud.security.token.validation.TestIssuerValidator new file mode 100644 index 000000000..8db868f4d --- /dev/null +++ b/java-security-test/src/main/resources/META-INF/services/com.sap.cloud.security.token.validation.TestIssuerValidator @@ -0,0 +1 @@ +com.sap.cloud.security.token.validation.LocalhostIssuerValidator \ No newline at end of file diff --git a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java index d9798c6f9..632ec0e44 100644 --- a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java +++ b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java @@ -8,6 +8,7 @@ import com.sap.cloud.security.config.OAuth2ServiceConfiguration; import com.sap.cloud.security.json.JsonParsingException; import com.sap.cloud.security.token.Token; +import com.sap.cloud.security.token.validation.TestIssuerValidator; import com.sap.cloud.security.token.validation.ValidationResult; import com.sap.cloud.security.token.validation.Validator; import org.slf4j.Logger; @@ -17,6 +18,7 @@ import java.net.URL; import java.util.List; import java.util.Objects; +import java.util.ServiceLoader; import java.util.regex.Pattern; import static com.sap.cloud.security.token.validation.ValidationResults.createInvalid; @@ -38,9 +40,36 @@ * These checks are a prerequisite for using the `JwtSignatureValidator`. */ class JwtIssuerValidator implements Validator { + protected static final Logger LOGGER = LoggerFactory.getLogger(JwtIssuerValidator.class); + + /* + * The following validator brings backward-compatibility for test credentials in consumer applications written before 2.17.0 that are used to validate java-security-test tokens. + * This is necessary for successful validation of localhost issuers that include a port when 'localhost' is defined as trusted domain without port in the service credentials. + * Implementations of this interface absolutely MUST NOT be supplied outside test scope and MUST NOT be used for any other purpose to preserve application security. + */ + static TestIssuerValidator localhostIssuerValidator; + static { + tryLoadingLocalhostIssuerValidator(); + } + + private static void tryLoadingLocalhostIssuerValidator() { + ServiceLoader validators; + try { + validators = ServiceLoader.load(TestIssuerValidator.class); + } catch (Error e) { + LOGGER.warn("Unexpected failure while loading TestIssuerValidator service providers: {}", e.getMessage()); + return; + } + + for (TestIssuerValidator v : validators) { + localhostIssuerValidator = v; + break; + } + LOGGER.debug("loaded TestIssuerValidator service providers: {}. Using first one: {}.", validators, localhostIssuerValidator); + } + protected static final String HTTPS_SCHEME = "https://"; private final List domains; - protected final Logger logger = LoggerFactory.getLogger(getClass()); /** * Creates instance of Issuer validation using the given domains provided by the @@ -83,6 +112,11 @@ public ValidationResult validate(Token token) { if(Objects.equals(d, issuerDomain) || issuerDomain.matches(validSubdomainPattern)) { return createValid(); } + + if("localhost".equals(d) && localhostIssuerValidator != null && localhostIssuerValidator.isValidIssuer(issuer)) { + LOGGER.debug("Accepting {} as valid issuer on trusted domain 'localhost' for backward-compatibility with java-security-test.", issuer); + return createValid(); + } } return createInvalid("Issuer {} was not a trusted domain or a subdomain of the trusted domains {}.", issuer, domains); From 3d5f930d351923fdabfd233e00b47b42de2ecd73 Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Mon, 4 Dec 2023 11:59:32 +0100 Subject: [PATCH 07/19] Fix spring-security-hybrid-usage unit test --- .../java/sample/spring/security/TestControllerTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/TestControllerTest.java b/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/TestControllerTest.java index fa489f210..488c1aebe 100644 --- a/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/TestControllerTest.java +++ b/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/TestControllerTest.java @@ -6,6 +6,7 @@ package sample.spring.security; import com.sap.cloud.security.config.Service; +import com.sap.cloud.security.test.JwtGenerator; import com.sap.cloud.security.test.SecurityTestRule; import org.junit.Before; import org.junit.ClassRule; @@ -64,8 +65,8 @@ public void sayHello() throws Exception { .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); - assertTrue(response.contains("sb-clientId!t0815")); - assertTrue(response.contains("the-zone-id")); + assertTrue(response.contains(SecurityTestRule.DEFAULT_CLIENT_ID)); + assertTrue(response.contains(JwtGenerator.DEFAULT_APP_TID)); } @Test @@ -80,7 +81,7 @@ public void readData_OK() throws Exception { .perform(get("/method").with(bearerToken(jwtIas))) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); - assertTrue(response.contains("You got the sensitive data for zone 'the-zone-id'.")); + assertTrue(response.contains("You got the sensitive data for zone 'the-app-tid'.")); } @Test From 77e7d8e35b8cca7d5bd868bd390436ec609afede Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Mon, 4 Dec 2023 13:24:35 +0100 Subject: [PATCH 08/19] add unit test to spring-security-hybrid-usage sample to test that only localhost issers (and not *any* issuers) are trusted when java-security-test supplies a LocalhostIssuerValidator --- .../junitjupiter/TestControllerIasTest.java | 13 +++++++++++++ .../junitjupiter/TestControllerXsuaaTest.java | 7 +++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/junitjupiter/TestControllerIasTest.java b/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/junitjupiter/TestControllerIasTest.java index d6abd7d6c..344b10355 100644 --- a/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/junitjupiter/TestControllerIasTest.java +++ b/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/junitjupiter/TestControllerIasTest.java @@ -7,6 +7,8 @@ import com.sap.cloud.security.test.api.SecurityTestContext; import com.sap.cloud.security.test.extension.IasExtension; +import com.sap.cloud.security.token.Token; +import com.sap.cloud.security.token.TokenClaims; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -75,5 +77,16 @@ void readData_FORBIDDEN(SecurityTestContext securityTest) throws Exception { mvc.perform(get("/method").with(bearerToken(jwtNoScopes))) .andExpect(status().isForbidden()); } + + /** + * Ensures that tokens with an issuer whose domain is not part of {@link com.sap.cloud.security.config.cf.CFConstants.IAS#DOMAINS} in the credentials are still not trusted, + * even when java-security-test supplies {@link com.sap.cloud.security.token.validation.LocalhostIssuerValidator}, which trusts issuers from tokens targeting localhost. + */ + @Test + void acceptsOnlyLocalhostIssuers(SecurityTestContext securityTest) throws Exception { + Token jwt = securityTest.getPreconfiguredJwtGenerator().withClaimsFromFile("/iasClaims.json").withClaimValue(TokenClaims.IAS_ISSUER, "https://auth.google.com").createToken(); + + mvc.perform(get("/sayHello").with(bearerToken(jwt.getTokenValue()))).andExpect(status().isUnauthorized()); + } } diff --git a/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/junitjupiter/TestControllerXsuaaTest.java b/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/junitjupiter/TestControllerXsuaaTest.java index 3482268b9..a68916eff 100644 --- a/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/junitjupiter/TestControllerXsuaaTest.java +++ b/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/junitjupiter/TestControllerXsuaaTest.java @@ -80,12 +80,15 @@ void readData_FORBIDDEN(SecurityTestContext securityTest) throws Exception { .andExpect(status().isForbidden()); } + /** + * Ensures that tokens with a JKU whose domain differs from the {@link com.sap.cloud.security.config.cf.CFConstants.XSUAA#UAA_DOMAIN} in the credentials are still not trusted, + * even when java-security-test supplies {@link com.sap.cloud.security.token.validation.XsuaaJkuFactory}, which trusts JKUs from tokens targeting localhost. + */ @Test void acceptsOnlyLocalhostJku(SecurityTestContext securityTest) throws Exception { Token jwt = securityTest.getPreconfiguredJwtGenerator().withLocalScopes("Read").withHeaderParameter(TokenHeader.JWKS_URL, "https://auth.google.com").createToken(); - mvc.perform(get("/sayHello").with(bearerToken(jwt.getTokenValue()))) - .andExpect(status().isUnauthorized()); + mvc.perform(get("/sayHello").with(bearerToken(jwt.getTokenValue()))).andExpect(status().isUnauthorized()); } } From 399eec1958730057a7fb6bef0368b7b458fa1c4d Mon Sep 17 00:00:00 2001 From: liga-oz Date: Mon, 4 Dec 2023 14:14:47 +0100 Subject: [PATCH 09/19] fix for logback CVE Signed-off-by: liga-oz --- spring-xsuaa-starter/pom.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spring-xsuaa-starter/pom.xml b/spring-xsuaa-starter/pom.xml index f55afcbd8..c36a6f3b5 100644 --- a/spring-xsuaa-starter/pom.xml +++ b/spring-xsuaa-starter/pom.xml @@ -31,6 +31,18 @@ + + + ch.qos.logback + logback-core + 1.2.13 + + + + ch.qos.logback + logback-classic + 1.2.13 + org.springframework.boot spring-boot-starter From 8863708cdbdf6e164f4a07482d4b3adac247d7f0 Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Mon, 4 Dec 2023 14:20:26 +0100 Subject: [PATCH 10/19] Change catch clause in JwtIssuerValidator from Error to Exception | ServiceConfigurationError --- .../token/validation/validators/JwtIssuerValidator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java index 632ec0e44..90489b1bd 100644 --- a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java +++ b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/JwtIssuerValidator.java @@ -18,6 +18,7 @@ import java.net.URL; import java.util.List; import java.util.Objects; +import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import java.util.regex.Pattern; @@ -56,7 +57,7 @@ private static void tryLoadingLocalhostIssuerValidator() { ServiceLoader validators; try { validators = ServiceLoader.load(TestIssuerValidator.class); - } catch (Error e) { + } catch (Exception | ServiceConfigurationError e) { LOGGER.warn("Unexpected failure while loading TestIssuerValidator service providers: {}", e.getMessage()); return; } From 59a6a1d88bd023a134930f1f9cac9a2e52c38ad6 Mon Sep 17 00:00:00 2001 From: liga-oz Date: Mon, 4 Dec 2023 14:25:45 +0100 Subject: [PATCH 11/19] refactor XsuaaJkuFactory signature to have a String argument Signed-off-by: liga-oz --- .../cloud/security/token/XsuaaJkuFactory.java | 2 +- .../token/XsuaaLocalhostJkuFactory.java | 3 +- .../XsuaaJwtSignatureValidator.java | 4 +-- .../token/authentication/XsuaaJwtDecoder.java | 5 ++-- .../xsuaa/token/XsuaaLocalhostJkuFactory.java | 28 +++++++++++++++++++ .../authentication/XsuaaJwtDecoderTest.java | 3 +- ...m.sap.cloud.security.token.XsuaaJkuFactory | 1 + 7 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/XsuaaLocalhostJkuFactory.java create mode 100644 spring-xsuaa/src/test/resources/META-INF/services/com.sap.cloud.security.token.XsuaaJkuFactory diff --git a/java-api/src/main/java/com/sap/cloud/security/token/XsuaaJkuFactory.java b/java-api/src/main/java/com/sap/cloud/security/token/XsuaaJkuFactory.java index f45a8a38b..61c9fee06 100644 --- a/java-api/src/main/java/com/sap/cloud/security/token/XsuaaJkuFactory.java +++ b/java-api/src/main/java/com/sap/cloud/security/token/XsuaaJkuFactory.java @@ -1,5 +1,5 @@ package com.sap.cloud.security.token; public interface XsuaaJkuFactory { - String create(Token token); + String create(String token); } diff --git a/java-security-test/src/main/java/com/sap/cloud/security/token/XsuaaLocalhostJkuFactory.java b/java-security-test/src/main/java/com/sap/cloud/security/token/XsuaaLocalhostJkuFactory.java index a899e02ca..2cf622d78 100644 --- a/java-security-test/src/main/java/com/sap/cloud/security/token/XsuaaLocalhostJkuFactory.java +++ b/java-security-test/src/main/java/com/sap/cloud/security/token/XsuaaLocalhostJkuFactory.java @@ -3,7 +3,8 @@ public class XsuaaLocalhostJkuFactory implements XsuaaJkuFactory { @Override - public String create(Token token) { + public String create(String jwt) { + Token token = Token.create(jwt); String tokenJku = (String) token.getHeaders().get(TokenHeader.JWKS_URL); if (tokenJku.contains("localhost") || tokenJku.contains("127.0.0.1")) { diff --git a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java index c9e580d25..96bf163bf 100644 --- a/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java +++ b/java-security/src/main/java/com/sap/cloud/security/token/validation/validators/XsuaaJwtSignatureValidator.java @@ -29,7 +29,7 @@ class XsuaaJwtSignatureValidator extends JwtSignatureValidator { try { ServiceLoader.load(XsuaaJkuFactory.class).forEach(this::add); LOGGER.debug("loaded XsuaaJkuFactory service providers: {}", this); - } catch (Error e) { + } catch (Exception | ServiceConfigurationError e) { LOGGER.warn("Unexpected failure while loading XsuaaJkuFactory service providers: {}", e.getMessage()); } } @@ -79,7 +79,7 @@ private PublicKey fetchPublicKey(Token token, JwtSignatureAlgorithm algorithm) t : configuration.getProperty(UAA_DOMAIN) + "/token_keys" + zidQueryParam; } else { LOGGER.info("Loaded custom JKU factory"); - jwksUri = jkuFactories.get(0).create(token); + jwksUri = jkuFactories.get(0).create(token.getTokenValue()); } URI uri = URI.create(jwksUri); diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java index 141f1a976..8ccafa09a 100644 --- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java +++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java @@ -10,7 +10,6 @@ import com.nimbusds.jwt.JWTParser; import com.sap.cloud.security.config.cf.CFConstants; import com.sap.cloud.security.token.ProviderNotFoundException; -import com.sap.cloud.security.token.Token; import com.sap.cloud.security.token.XsuaaJkuFactory; import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration; import com.sap.cloud.security.xsuaa.token.TokenClaims; @@ -46,7 +45,7 @@ public class XsuaaJwtDecoder implements JwtDecoder { try { ServiceLoader.load(XsuaaJkuFactory.class).forEach(this::add); logger.debug("loaded XsuaaJkuFactory service providers: {}", this); - } catch (Error e) { + } catch (Exception | ServiceConfigurationError e) { logger.warn("Unexpected failure while loading XsuaaJkuFactory service providers: {}", e.getMessage()); } } @@ -162,7 +161,7 @@ private Jwt verifyToken(String token, String kid, String uaaDomain, String zid) } else { logger.info("Loaded custom JKU factory"); try { - jku = jkuFactories.get(0).create(Token.create(token)); + jku = jkuFactories.get(0).create(token); } catch (IllegalArgumentException | ProviderException | ProviderNotFoundException e) { throw new BadJwtException("JKU validation failed: " + e.getMessage()); } diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/XsuaaLocalhostJkuFactory.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/XsuaaLocalhostJkuFactory.java new file mode 100644 index 000000000..3ace1b295 --- /dev/null +++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/XsuaaLocalhostJkuFactory.java @@ -0,0 +1,28 @@ +package com.sap.cloud.security.xsuaa.token; + +import com.nimbusds.jwt.JWT; +import com.nimbusds.jwt.JWTParser; +import com.sap.cloud.security.token.TokenHeader; +import com.sap.cloud.security.token.XsuaaJkuFactory; + +import java.text.ParseException; + +public class XsuaaLocalhostJkuFactory implements XsuaaJkuFactory { + + @Override + public String create(String token) { + String tokenJku; + try { + JWT jwt = JWTParser.parse(token); + tokenJku = (String) jwt.getHeader().toJSONObject().get(TokenHeader.JWKS_URL); + } catch (ParseException e) { + throw new RuntimeException(e); + } + + if (tokenJku != null && (tokenJku.contains("localhost") || tokenJku.contains("127.0.0.1"))) { + return tokenJku; + } + + throw new IllegalArgumentException("JKU is not trusted because it does not target localhost."); + } +} \ No newline at end of file diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoderTest.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoderTest.java index 2a2f8ff2f..22859edc5 100644 --- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoderTest.java +++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoderTest.java @@ -12,6 +12,7 @@ import com.sap.cloud.security.xsuaa.token.TokenClaims; import org.apache.commons.io.IOUtils; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; @@ -119,7 +120,7 @@ public void decode_withFallbackVerificationKey_remoteKeyFetchFailed() { assertThat(jwt.getAudience().get(0)).isEqualTo("sb-clientId!t0815"); } - @Test + @Test@Ignore("verify if still valid") public void decode_withNonMatchingVerificationKey_throwsException() { final JwtDecoder cut = new XsuaaJwtDecoderBuilder(configuration).build(); diff --git a/spring-xsuaa/src/test/resources/META-INF/services/com.sap.cloud.security.token.XsuaaJkuFactory b/spring-xsuaa/src/test/resources/META-INF/services/com.sap.cloud.security.token.XsuaaJkuFactory new file mode 100644 index 000000000..92f28f804 --- /dev/null +++ b/spring-xsuaa/src/test/resources/META-INF/services/com.sap.cloud.security.token.XsuaaJkuFactory @@ -0,0 +1 @@ +com.sap.cloud.security.xsuaa.token.XsuaaLocalhostJkuFactory \ No newline at end of file From f3beb08f205ea1057b5f6fd7006740b3c623f955 Mon Sep 17 00:00:00 2001 From: liga-oz Date: Mon, 4 Dec 2023 14:28:27 +0100 Subject: [PATCH 12/19] refactor XsuaaJkuFactory signature to have a String argument Signed-off-by: liga-oz --- .../sap/cloud/security/token/validation/XsuaaJkuFactory.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/java-api/src/main/java/com/sap/cloud/security/token/validation/XsuaaJkuFactory.java b/java-api/src/main/java/com/sap/cloud/security/token/validation/XsuaaJkuFactory.java index 8a1552454..425b28f90 100644 --- a/java-api/src/main/java/com/sap/cloud/security/token/validation/XsuaaJkuFactory.java +++ b/java-api/src/main/java/com/sap/cloud/security/token/validation/XsuaaJkuFactory.java @@ -1,7 +1,5 @@ package com.sap.cloud.security.token.validation; -import com.sap.cloud.security.token.Token; - public interface XsuaaJkuFactory { - String create(Token token); + String create(String token); } From 340bf25d5c9f2013e443435695580130d0e18604 Mon Sep 17 00:00:00 2001 From: liga-oz Date: Mon, 4 Dec 2023 14:37:23 +0100 Subject: [PATCH 13/19] fix XsuaaJwtDecoderTest Signed-off-by: liga-oz --- .../cloud/security/xsuaa/token/XsuaaLocalhostJkuFactory.java | 2 +- .../xsuaa/token/authentication/XsuaaJwtDecoderTest.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/XsuaaLocalhostJkuFactory.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/XsuaaLocalhostJkuFactory.java index 3ace1b295..1c9f70369 100644 --- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/XsuaaLocalhostJkuFactory.java +++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/XsuaaLocalhostJkuFactory.java @@ -19,7 +19,7 @@ public String create(String token) { throw new RuntimeException(e); } - if (tokenJku != null && (tokenJku.contains("localhost") || tokenJku.contains("127.0.0.1"))) { + if (tokenJku == null || tokenJku.contains("localhost") || tokenJku.contains("127.0.0.1")) { return tokenJku; } diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoderTest.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoderTest.java index 22859edc5..2a2f8ff2f 100644 --- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoderTest.java +++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoderTest.java @@ -12,7 +12,6 @@ import com.sap.cloud.security.xsuaa.token.TokenClaims; import org.apache.commons.io.IOUtils; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; @@ -120,7 +119,7 @@ public void decode_withFallbackVerificationKey_remoteKeyFetchFailed() { assertThat(jwt.getAudience().get(0)).isEqualTo("sb-clientId!t0815"); } - @Test@Ignore("verify if still valid") + @Test public void decode_withNonMatchingVerificationKey_throwsException() { final JwtDecoder cut = new XsuaaJwtDecoderBuilder(configuration).build(); From b4c4c31f3347d0190397f7bfcd53e7b40f0dd163 Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Mon, 4 Dec 2023 17:16:50 +0100 Subject: [PATCH 14/19] Revert java-security-it to use DEFAULT_DOMAIN/DEFAULT_UAA_DOMAIN instead of wiremock's baseurl to test backward-compatibilty with 'localhost' credentials. --- .../XsuaaMultipleBindingsIntegrationTest.java | 14 ++------------ .../test/integration/ssrf/JavaSSRFAttackTest.java | 1 + .../integration/ssrf/SpringSSRFAttackTest.java | 3 +-- .../performance/JavaSecurityPerformanceIT.java | 2 +- .../performance/SpringSecurityPerformanceIT.java | 4 ++-- 5 files changed, 7 insertions(+), 17 deletions(-) diff --git a/java-security-it/src/test/java/com/sap/cloud/security/test/integration/XsuaaMultipleBindingsIntegrationTest.java b/java-security-it/src/test/java/com/sap/cloud/security/test/integration/XsuaaMultipleBindingsIntegrationTest.java index 87d17c666..182f03c2c 100644 --- a/java-security-it/src/test/java/com/sap/cloud/security/test/integration/XsuaaMultipleBindingsIntegrationTest.java +++ b/java-security-it/src/test/java/com/sap/cloud/security/test/integration/XsuaaMultipleBindingsIntegrationTest.java @@ -8,7 +8,6 @@ import com.sap.cloud.security.config.Environments; import com.sap.cloud.security.config.OAuth2ServiceConfiguration; import com.sap.cloud.security.config.Service; -import com.sap.cloud.security.config.cf.CFConstants; import com.sap.cloud.security.test.SecurityTestRule; import com.sap.cloud.security.token.Token; import com.sap.cloud.security.token.validation.CombiningValidator; @@ -16,7 +15,6 @@ import com.sap.cloud.security.token.validation.validators.JwtValidatorBuilder; import org.junit.ClassRule; import org.junit.Test; -import org.mockito.Mockito; import static org.assertj.core.api.Assertions.assertThat; @@ -34,16 +32,8 @@ public class XsuaaMultipleBindingsIntegrationTest { public void createToken_integrationTest_tokenValidation() { Token token = rule.getPreconfiguredJwtGenerator().createToken(); OAuth2ServiceConfiguration configuration = Environments.readFromInput(XsuaaMultipleBindingsIntegrationTest.class.getResourceAsStream("/vcap_services-multiple.json")).getXsuaaConfiguration(); - OAuth2ServiceConfiguration mockConfig = Mockito.mock(OAuth2ServiceConfiguration.class); - Mockito.when(mockConfig.getClientId()).thenReturn(configuration.getClientId()); - Mockito.when(mockConfig.getDomains()).thenReturn(configuration.getDomains()); - Mockito.when(mockConfig.getUrl()).thenReturn(configuration.getUrl()); - Mockito.when(mockConfig.hasProperty(CFConstants.XSUAA.APP_ID)).thenReturn(configuration.hasProperty(CFConstants.XSUAA.APP_ID)); - Mockito.when(mockConfig.getProperty(CFConstants.XSUAA.APP_ID)).thenReturn(configuration.getProperty(CFConstants.XSUAA.APP_ID)); - Mockito.when(mockConfig.getProperty(CFConstants.XSUAA.UAA_DOMAIN)).thenReturn(rule.getWireMockServer().baseUrl()); - Mockito.when(mockConfig.getService()).thenReturn(configuration.getService()); - - CombiningValidator tokenValidator = JwtValidatorBuilder.getInstance(mockConfig).build(); + + CombiningValidator tokenValidator = JwtValidatorBuilder.getInstance(configuration).build(); ValidationResult result = tokenValidator.validate(token); assertThat(result.isValid()).isTrue(); diff --git a/java-security-it/src/test/java/com/sap/cloud/security/test/integration/ssrf/JavaSSRFAttackTest.java b/java-security-it/src/test/java/com/sap/cloud/security/test/integration/ssrf/JavaSSRFAttackTest.java index afa309226..901b29535 100644 --- a/java-security-it/src/test/java/com/sap/cloud/security/test/integration/ssrf/JavaSSRFAttackTest.java +++ b/java-security-it/src/test/java/com/sap/cloud/security/test/integration/ssrf/JavaSSRFAttackTest.java @@ -58,6 +58,7 @@ class JavaSSRFAttackTest { @ParameterizedTest @CsvSource({ "http://localhost:4242/token_keys, true", + "http://malicious.ondemand.com@localhost:4242/token_keys, true", "http://localhost:4242/token_keys@malicious.ondemand.com/token_keys, false", "http://localhost:4242/token_keys///malicious.ondemand.com/token_keys, false", }) diff --git a/java-security-it/src/test/java/com/sap/cloud/security/test/integration/ssrf/SpringSSRFAttackTest.java b/java-security-it/src/test/java/com/sap/cloud/security/test/integration/ssrf/SpringSSRFAttackTest.java index 48282c583..333c9fe66 100644 --- a/java-security-it/src/test/java/com/sap/cloud/security/test/integration/ssrf/SpringSSRFAttackTest.java +++ b/java-security-it/src/test/java/com/sap/cloud/security/test/integration/ssrf/SpringSSRFAttackTest.java @@ -56,7 +56,6 @@ class SpringSSRFAttackTest { @ParameterizedTest @CsvSource({ "http://localhost:4242/token_keys@malicious.ondemand.com/token_keys, false", - "http://malicious.ondemand.com@localhost:4242/token_keys, true", "http://localhost:4242/token_keys///malicious.ondemand.com/token_keys, false", }) void maliciousPartOfJwksIsNotUsedToObtainToken(String jwksUrl, boolean isValid) @@ -93,7 +92,7 @@ void maliciousPartOfJwksIsNotUsedToObtainToken(String jwksUrl, boolean isValid) private XsuaaCredentials createXsuaaCredentials() { XsuaaCredentials xsuaaCredentials = new XsuaaCredentials(); - xsuaaCredentials.setUaaDomain(extension.getContext().getWireMockServer().baseUrl()); + xsuaaCredentials.setUaaDomain(SecurityTest.DEFAULT_DOMAIN); xsuaaCredentials.setClientId(SecurityTest.DEFAULT_CLIENT_ID); xsuaaCredentials.setXsAppName(SecurityTest.DEFAULT_APP_ID); return xsuaaCredentials; diff --git a/java-security-it/src/test/java/com/sap/cloud/security/test/performance/JavaSecurityPerformanceIT.java b/java-security-it/src/test/java/com/sap/cloud/security/test/performance/JavaSecurityPerformanceIT.java index 4e02adb2a..187d9f859 100644 --- a/java-security-it/src/test/java/com/sap/cloud/security/test/performance/JavaSecurityPerformanceIT.java +++ b/java-security-it/src/test/java/com/sap/cloud/security/test/performance/JavaSecurityPerformanceIT.java @@ -90,7 +90,7 @@ private CombiningValidator createOnlineTokenValidator() { private OAuth2ServiceConfigurationBuilder createConfigurationBuilder() { return OAuth2ServiceConfigurationBuilder.forService(XSUAA) - .withProperty(CFConstants.XSUAA.UAA_DOMAIN, securityTest.getWireMockServer().baseUrl()) + .withProperty(CFConstants.XSUAA.UAA_DOMAIN, SecurityTest.DEFAULT_DOMAIN) .withProperty(CFConstants.XSUAA.APP_ID, SecurityTest.DEFAULT_APP_ID) .withClientId(SecurityTest.DEFAULT_CLIENT_ID); } diff --git a/java-security-it/src/test/java/com/sap/cloud/security/test/performance/SpringSecurityPerformanceIT.java b/java-security-it/src/test/java/com/sap/cloud/security/test/performance/SpringSecurityPerformanceIT.java index 1b706b72c..a7cbe01da 100644 --- a/java-security-it/src/test/java/com/sap/cloud/security/test/performance/SpringSecurityPerformanceIT.java +++ b/java-security-it/src/test/java/com/sap/cloud/security/test/performance/SpringSecurityPerformanceIT.java @@ -73,14 +73,14 @@ private JwtDecoder createOnlineJwtDecoder() { private OAuth2ServiceConfigurationBuilder createXsuaaConfigurationBuilder() { return OAuth2ServiceConfigurationBuilder.forService(XSUAA) - .withProperty(CFConstants.XSUAA.UAA_DOMAIN, securityTest.getWireMockServer().baseUrl()) + .withProperty(CFConstants.XSUAA.UAA_DOMAIN, SecurityTest.DEFAULT_DOMAIN) .withProperty(CFConstants.XSUAA.APP_ID, SecurityTest.DEFAULT_APP_ID) .withClientId(SecurityTest.DEFAULT_CLIENT_ID); } private OAuth2ServiceConfigurationBuilder createIasConfigurationBuilder() { return OAuth2ServiceConfigurationBuilder.forService(IAS) - .withDomains(securityIasTest.getWireMockServer().baseUrl().replace(("http://"), "")) + .withDomains(SecurityTest.DEFAULT_DOMAIN) .withClientId(SecurityTest.DEFAULT_CLIENT_ID); } } From 686569fc3cfb0c5f092599e14175b8c1bc99b3c0 Mon Sep 17 00:00:00 2001 From: liga-oz Date: Mon, 4 Dec 2023 17:42:22 +0100 Subject: [PATCH 15/19] fix XsuaaJwtDecoder Signed-off-by: liga-oz --- .../security/xsuaa/token/authentication/XsuaaJwtDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java index 8ccafa09a..ac58a4f19 100644 --- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java +++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoder.java @@ -168,7 +168,7 @@ private Jwt verifyToken(String token, String kid, String uaaDomain, String zid) } try { - canVerifyWithKey(kid, uaaDomain); + canVerifyWithKey(kid, jku); return verifyWithKey(token, jku, kid); } catch (JwtValidationException ex) { throw ex; From faad834021e0c2f39cf8ad898659150fb38444e5 Mon Sep 17 00:00:00 2001 From: liga-oz Date: Mon, 4 Dec 2023 17:45:49 +0100 Subject: [PATCH 16/19] revert spring-xsuaa-mock and spring-xsuaa-it changes Signed-off-by: liga-oz --- spring-xsuaa-it/pom.xml | 5 ++++ .../cloud/security/xsuaa/mock/JWTUtil.java | 7 ----- .../BasicAuthenticationValidationTest.java | 4 +-- .../XsuaaTokenValidationTest.java | 28 +++++++++---------- .../testservice/api/XsuaaJwtDecoderTest.java | 2 +- spring-xsuaa-mock/pom.xml | 5 ++++ .../xsuaa/XsuaaLocalhostJkuFactory.java | 28 +++++++++++++++++++ .../mock/MockXsuaaServiceConfiguration.java | 5 ++-- .../xsuaa/mock/XsuaaRequestDispatcher.java | 19 ++++++------- ...m.sap.cloud.security.token.XsuaaJkuFactory | 1 + .../xsuaa/mock/XsuaaMockPostProcessor.java | 2 +- 11 files changed, 67 insertions(+), 39 deletions(-) create mode 100644 spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/XsuaaLocalhostJkuFactory.java create mode 100644 spring-xsuaa-mock/src/main/resources/META-INF/services/com.sap.cloud.security.token.XsuaaJkuFactory diff --git a/spring-xsuaa-it/pom.xml b/spring-xsuaa-it/pom.xml index ee2d8a06b..d45b76de5 100644 --- a/spring-xsuaa-it/pom.xml +++ b/spring-xsuaa-it/pom.xml @@ -94,6 +94,11 @@ spring-security-test test + + org.junit.vintage + junit-vintage-engine + test + diff --git a/spring-xsuaa-it/src/main/java/com/sap/cloud/security/xsuaa/mock/JWTUtil.java b/spring-xsuaa-it/src/main/java/com/sap/cloud/security/xsuaa/mock/JWTUtil.java index 7885a4fd3..3bb7e67b4 100644 --- a/spring-xsuaa-it/src/main/java/com/sap/cloud/security/xsuaa/mock/JWTUtil.java +++ b/spring-xsuaa-it/src/main/java/com/sap/cloud/security/xsuaa/mock/JWTUtil.java @@ -25,11 +25,4 @@ public static String createJWT(String pathToTemplate, String subdomain, String k return jwtGenerator.createFromTemplate(pathToTemplate).getTokenValue(); } - public static String createJWT(String pathToTemplate, String subdomain, String zid, String keyId) - throws IOException { - JwtGenerator jwtGenerator = new JwtGenerator("sb-java-hello-world", subdomain, zid) - .setJwtHeaderKeyId(keyId != null ? keyId : "legacy-token-key-" + subdomain); - return jwtGenerator.createFromTemplate(pathToTemplate).getTokenValue(); - } - } diff --git a/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/extractor/BasicAuthenticationValidationTest.java b/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/extractor/BasicAuthenticationValidationTest.java index 252080ae1..29d6afbf6 100644 --- a/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/extractor/BasicAuthenticationValidationTest.java +++ b/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/extractor/BasicAuthenticationValidationTest.java @@ -95,7 +95,7 @@ public void testToken_testdomain_basic_fail() throws Exception { } private static class BearerTokenRequestPostProcessor implements RequestPostProcessor { - private String token; + private final String token; public BearerTokenRequestPostProcessor(String token) { this.token = token; @@ -109,7 +109,7 @@ public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) } private static class BasicTokenRequestPostProcessor implements RequestPostProcessor { - private String token; + private final String token; public BasicTokenRequestPostProcessor(String username, String password) { this.token = Base64.getEncoder().encodeToString((username + ":" + password).getBytes()); diff --git a/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaTokenValidationTest.java b/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaTokenValidationTest.java index 3dd7ebe9b..3aad80e01 100644 --- a/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaTokenValidationTest.java +++ b/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaTokenValidationTest.java @@ -37,38 +37,36 @@ public class XsuaaTokenValidationTest { MockMvc mvc; @Test - void testToken_testdomain() throws Exception { - this.mvc.perform(get("/user").with(bearerToken(JWTUtil.createJWT("/saml.txt", - "testdomain", "tenant", null)))) + public void testToken_testdomain() throws Exception { + this.mvc.perform(get("/user").with(bearerToken(JWTUtil.createJWT("/saml.txt", "testdomain")))) + .andExpect(status().isOk()).andExpect(content().string(containsString("user:Mustermann"))); + this.mvc.perform(get("/user").with(bearerToken(JWTUtil.createJWT("/saml.txt", "testdomain")))) .andExpect(status().isOk()).andExpect(content().string(containsString("user:Mustermann"))); } @Test - void testToken_otherdomain() throws Exception { - this.mvc.perform(get("/user").with(bearerToken(JWTUtil.createJWT("/saml.txt", - "otherdomain", "othertenant", null)))) + public void testToken_otherdomain() throws Exception { + this.mvc.perform(get("/user").with(bearerToken(JWTUtil.createJWT("/saml.txt", "otherdomain")))) .andExpect(status().isOk()).andExpect(content().string(containsString("user:Mustermann"))); } @Test - void test_Scope() throws Exception { - this.mvc.perform(get("/scope").with(bearerToken(JWTUtil.createJWT("/saml.txt", - "otherdomain", "othertenant", null)))) + public void test_Scope() throws Exception { + this.mvc.perform(get("/scope").with(bearerToken(JWTUtil.createJWT("/saml.txt", "otherdomain")))) .andExpect(status().isOk()); } @Test - void test_clientcredentialstoken() throws Exception { + public void test_clientcredentialstoken() throws Exception { this.mvc.perform( get("/clientCredentialsToken") - .with(bearerToken(JWTUtil.createJWT("/saml.txt", "uaa", - "legacy-token-key")))) + .with(bearerToken(JWTUtil.createJWT("/saml.txt", "uaa", "legacy-token-key")))) .andExpect(status().isOk()).andExpect( content().string(containsString(".ewogICJqdGkiOiAiOGU3YjNiMDAtNzc1MS00YjQ2LTliMWEtNWE0NmEyY"))); } @Test - void test_insufficientScopedToken_isUnauthorized() throws Exception { + public void test_insufficientScopedToken_isUnauthorized() throws Exception { this.mvc.perform( get("/clientCredentialsToken") .with(bearerToken( @@ -77,7 +75,7 @@ void test_insufficientScopedToken_isUnauthorized() throws Exception { } @Test - void test_expiredToken_isUnauthorized() throws Exception { + public void test_expiredToken_isUnauthorized() throws Exception { this.mvc.perform( get("/clientCredentialsToken") .with(bearerToken(JWTUtil.createJWT("/expired.txt", "uaa", "legacy-token-key")))) @@ -85,7 +83,7 @@ void test_expiredToken_isUnauthorized() throws Exception { } private static class BearerTokenRequestPostProcessor implements RequestPostProcessor { - private String token; + private final String token; public BearerTokenRequestPostProcessor(String token) { this.token = token; diff --git a/spring-xsuaa-it/src/test/java/testservice/api/XsuaaJwtDecoderTest.java b/spring-xsuaa-it/src/test/java/testservice/api/XsuaaJwtDecoderTest.java index b4b7b6e98..1458a39b6 100644 --- a/spring-xsuaa-it/src/test/java/testservice/api/XsuaaJwtDecoderTest.java +++ b/spring-xsuaa-it/src/test/java/testservice/api/XsuaaJwtDecoderTest.java @@ -64,7 +64,7 @@ public void postValidationActionIsExecutedIfSuccess() { @Test public void postValidationActionIsNotExecutedIfFail() { - String jwt = new JwtGenerator(clientId, "subdomain", "tenant").deriveAudiences(true) + String jwt = new JwtGenerator(clientId, "subdomain").deriveAudiences(true) .setJwtHeaderKeyId("legacy-token-key").setJku(null).getToken().getTokenValue(); try { jwtDecoderWithPostAction.decode(jwt); diff --git a/spring-xsuaa-mock/pom.xml b/spring-xsuaa-mock/pom.xml index cc6de8cdb..ff82d8239 100644 --- a/spring-xsuaa-mock/pom.xml +++ b/spring-xsuaa-mock/pom.xml @@ -71,6 +71,11 @@ spring-boot-starter-test test + + org.junit.vintage + junit-vintage-engine + test + diff --git a/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/XsuaaLocalhostJkuFactory.java b/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/XsuaaLocalhostJkuFactory.java new file mode 100644 index 000000000..fef20ad18 --- /dev/null +++ b/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/XsuaaLocalhostJkuFactory.java @@ -0,0 +1,28 @@ +package com.sap.cloud.security.xsuaa; + +import com.nimbusds.jwt.JWT; +import com.nimbusds.jwt.JWTParser; +import com.sap.cloud.security.token.TokenHeader; +import com.sap.cloud.security.token.XsuaaJkuFactory; + +import java.text.ParseException; + +public class XsuaaLocalhostJkuFactory implements XsuaaJkuFactory { + + @Override + public String create(String token) { + String tokenJku; + try { + JWT jwt = JWTParser.parse(token); + tokenJku = (String) jwt.getHeader().toJSONObject().get(TokenHeader.JWKS_URL); + } catch (ParseException e) { + throw new RuntimeException(e); + } + + if (tokenJku == null || tokenJku.contains("localhost") || tokenJku.contains("127.0.0.1")) { + return tokenJku; + } + + throw new IllegalArgumentException("JKU is not trusted because it does not target localhost."); + } +} \ No newline at end of file diff --git a/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/mock/MockXsuaaServiceConfiguration.java b/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/mock/MockXsuaaServiceConfiguration.java index 26754dfc3..21526e494 100644 --- a/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/mock/MockXsuaaServiceConfiguration.java +++ b/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/mock/MockXsuaaServiceConfiguration.java @@ -5,9 +5,8 @@ */ package com.sap.cloud.security.xsuaa.mock; -import org.springframework.beans.factory.annotation.Value; - import com.sap.cloud.security.xsuaa.XsuaaServiceConfigurationDefault; +import org.springframework.beans.factory.annotation.Value; public class MockXsuaaServiceConfiguration extends XsuaaServiceConfigurationDefault { @@ -17,7 +16,7 @@ public class MockXsuaaServiceConfiguration extends XsuaaServiceConfigurationDefa @Override public String getUaaDomain() { if (!mockXsuaaServerUrl.isEmpty()) { - return "localhost"; + return mockXsuaaServerUrl; } return super.getUaaDomain(); } diff --git a/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/mock/XsuaaRequestDispatcher.java b/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/mock/XsuaaRequestDispatcher.java index cecb0d936..408d6c1fc 100644 --- a/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/mock/XsuaaRequestDispatcher.java +++ b/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/mock/XsuaaRequestDispatcher.java @@ -22,21 +22,20 @@ public class XsuaaRequestDispatcher extends Dispatcher { protected static final String RESPONSE_404 = "Xsuaa mock authorization server does not support this request"; protected static final String RESPONSE_401 = "Xsuaa mock authorization server can't authenticate client/user"; protected static final String RESPONSE_500 = "Xsuaa mock authorization server can't process request"; - protected static final String PATH_TESTDOMAIN_TOKEN_KEYS = "/mockServer/testdomain_token_keys.json"; - public static final String PATH_OTHER_DOMAIN_TOKEN_KEYS = "/mockServer/otherdomain_token_keys.json"; - protected static final String PATH_PUBLIC_KEY = "/mockServer/publicKey.txt"; + protected static final String PATH_TOKEN_KEYS_TEMPLATE = "/mock/token_keys_template.json"; + protected static final String PATH_PUBLIC_KEY = "/mock/publicKey.txt"; protected final Logger logger = LoggerFactory.getLogger(XsuaaRequestDispatcher.class); - private static final int callCount = 0; + private static int callCount = 0; @Override public MockResponse dispatch(RecordedRequest request) { - // mock JWKS endpoints - if ("/token_keys?zid=tenant".equals(request.getPath())) { - return getTokenKeyForKeyId(PATH_TESTDOMAIN_TOKEN_KEYS, "legacy-token-key-testdomain"); + callCount++; + if ("/testdomain/token_keys".equals(request.getPath())) { + String subdomain = "testdomain"; + return getTokenKeyForKeyId(PATH_TOKEN_KEYS_TEMPLATE, "legacy-token-key-" + subdomain); } - - if ("/token_keys?zid=othertenant".equals(request.getPath())) { - return getResponseFromFile(PATH_OTHER_DOMAIN_TOKEN_KEYS, HttpStatus.OK); + if (request.getPath().endsWith("/token_keys")) { + return getTokenKeyForKeyId(PATH_TOKEN_KEYS_TEMPLATE, "legacy-token-key"); } return getResponse(RESPONSE_404, HttpStatus.NOT_FOUND); } diff --git a/spring-xsuaa-mock/src/main/resources/META-INF/services/com.sap.cloud.security.token.XsuaaJkuFactory b/spring-xsuaa-mock/src/main/resources/META-INF/services/com.sap.cloud.security.token.XsuaaJkuFactory new file mode 100644 index 000000000..836e10740 --- /dev/null +++ b/spring-xsuaa-mock/src/main/resources/META-INF/services/com.sap.cloud.security.token.XsuaaJkuFactory @@ -0,0 +1 @@ +com.sap.cloud.security.xsuaa.XsuaaLocalhostJkuFactory \ No newline at end of file diff --git a/spring-xsuaa-mock/src/test/java/com/sap/cloud/security/xsuaa/mock/XsuaaMockPostProcessor.java b/spring-xsuaa-mock/src/test/java/com/sap/cloud/security/xsuaa/mock/XsuaaMockPostProcessor.java index 6543d9222..08593b3b7 100644 --- a/spring-xsuaa-mock/src/test/java/com/sap/cloud/security/xsuaa/mock/XsuaaMockPostProcessor.java +++ b/spring-xsuaa-mock/src/test/java/com/sap/cloud/security/xsuaa/mock/XsuaaMockPostProcessor.java @@ -29,7 +29,7 @@ private static class MyDispatcher extends XsuaaRequestDispatcher { @Override public MockResponse dispatch(RecordedRequest request) { if ("/customdomain/token_keys".equals(request.getPath())) { - return getTokenKeyForKeyId(PATH_TESTDOMAIN_TOKEN_KEYS, "legacy-token-key-customdomain"); + return getTokenKeyForKeyId(PATH_TOKEN_KEYS_TEMPLATE, "legacy-token-key-customdomain"); } if ("/testdomain/token_keys".equals(request.getPath())) { return getResponseFromFile("/mock/testdomain_token_keys.json", HttpStatus.OK); From 7f056e0373a68a751bc2a8c5107905e6855b91e0 Mon Sep 17 00:00:00 2001 From: liga-oz Date: Mon, 4 Dec 2023 18:09:16 +0100 Subject: [PATCH 17/19] add spring-xsuaa-mock to have XsuaaLocalhostJkuFactory for the tests Signed-off-by: liga-oz --- samples/spring-security-xsuaa-usage/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/samples/spring-security-xsuaa-usage/pom.xml b/samples/spring-security-xsuaa-usage/pom.xml index 4bd17c733..54e1d9703 100644 --- a/samples/spring-security-xsuaa-usage/pom.xml +++ b/samples/spring-security-xsuaa-usage/pom.xml @@ -61,6 +61,12 @@ ${sap.cloud.security.version} test + + com.sap.cloud.security.xsuaa + spring-xsuaa-mock + ${sap.cloud.security.version} + test + org.junit.vintage junit-vintage-engine From 0e2dfa12642bc60f8c82d877067c3c252536f768 Mon Sep 17 00:00:00 2001 From: Manuel Fink Date: Tue, 5 Dec 2023 09:42:30 +0100 Subject: [PATCH 18/19] Bump version to 2.17.2 --- CHANGELOG.md | 6 ++++++ api/README.md | 2 +- api/pom.xml | 2 +- bom/pom.xml | 2 +- env/pom.xml | 2 +- java-api/README.md | 2 +- java-api/pom.xml | 2 +- java-security-it/pom.xml | 2 +- java-security-test/README.md | 2 +- java-security-test/pom.xml | 2 +- java-security/Migration_SpringSecurityProjects.md | 6 +++--- java-security/README.md | 2 +- java-security/pom.xml | 2 +- pom.xml | 2 +- samples/java-security-usage-ias/pom.xml | 4 ++-- samples/java-security-usage/pom.xml | 4 ++-- samples/java-tokenclient-usage/pom.xml | 4 ++-- samples/sap-java-buildpack-api-usage/pom.xml | 2 +- samples/spring-security-basic-auth/pom.xml | 4 ++-- samples/spring-security-hybrid-usage/pom.xml | 6 +++--- samples/spring-security-xsuaa-usage/pom.xml | 4 ++-- samples/spring-webflux-security-xsuaa-usage/pom.xml | 4 ++-- spring-security-compatibility/pom.xml | 2 +- spring-security-starter/pom.xml | 2 +- spring-security/Migration_SpringXsuaaProjects.md | 2 +- spring-security/README.md | 2 +- spring-security/pom.xml | 4 ++-- spring-xsuaa-it/pom.xml | 2 +- spring-xsuaa-mock/README.md | 2 +- spring-xsuaa-mock/pom.xml | 2 +- spring-xsuaa-starter/pom.xml | 2 +- spring-xsuaa-test/README.md | 2 +- spring-xsuaa-test/pom.xml | 2 +- spring-xsuaa/README.md | 4 ++-- spring-xsuaa/pom.xml | 2 +- token-client/README.md | 6 +++--- token-client/pom.xml | 2 +- 37 files changed, 56 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82c460dbf..5e4f03d8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log All notable changes to this project will be documented in this file. +## 2.17.2 +✅ Resolve Breaking Change introduced in 2.17.0. Consumers should be able to update to 2.17.2 from a version <= 2.16.0 without having to adjust test credentials used in their unit tests when using java-security-test or spring-xsuaa-mock. + +In version 2.17.2, when java-security-test or spring-xsuaa-mock are loaded (which MUST only be the case during _test_ scope), credentials with 'localhost' used as _uaadomain_ (XSUAA) or as trusted _domains_ (IAS), work again for validating tokens whose _jku_ (XSUAA) or _issuer_ (IAS) include a port for localhost. +Please note that the validation of tokens is less strict in this case and might accept edge-cases of malicious tokens that would not be accepted when java-security-test or spring-xsuaa-mock are not loaded. + ## 2.17.1 #### Dependency upgrades - Bump spring.boot.version from 2.7.17 to 2.7.18 diff --git a/api/README.md b/api/README.md index d6cb60839..594196c0e 100644 --- a/api/README.md +++ b/api/README.md @@ -5,6 +5,6 @@ com.sap.cloud.security.xsuaa api - 2.17.1 + 2.17.2 ``` diff --git a/api/pom.xml b/api/pom.xml index 7c0de2667..b4c9550b6 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -11,7 +11,7 @@ com.sap.cloud.security.xsuaa parent - 2.17.1 + 2.17.2 jar diff --git a/bom/pom.xml b/bom/pom.xml index a9cb3b3fe..ae96ee5de 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -8,7 +8,7 @@ com.sap.cloud.security java-bom - 2.17.1 + 2.17.2 pom java-bom diff --git a/env/pom.xml b/env/pom.xml index 6eab9c35b..91318a859 100644 --- a/env/pom.xml +++ b/env/pom.xml @@ -9,7 +9,7 @@ com.sap.cloud.security.xsuaa parent - 2.17.1 + 2.17.2 com.sap.cloud.security diff --git a/java-api/README.md b/java-api/README.md index b33257c2f..80c6b5217 100644 --- a/java-api/README.md +++ b/java-api/README.md @@ -5,6 +5,6 @@ com.sap.cloud.security java-api - 2.17.1 + 2.17.2 ``` diff --git a/java-api/pom.xml b/java-api/pom.xml index 297cab15c..593459995 100644 --- a/java-api/pom.xml +++ b/java-api/pom.xml @@ -9,7 +9,7 @@ com.sap.cloud.security.xsuaa parent - 2.17.1 + 2.17.2 com.sap.cloud.security diff --git a/java-security-it/pom.xml b/java-security-it/pom.xml index 7b9ed6d8d..9e801c43f 100644 --- a/java-security-it/pom.xml +++ b/java-security-it/pom.xml @@ -9,7 +9,7 @@ parent com.sap.cloud.security.xsuaa - 2.17.1 + 2.17.2 java-security-it diff --git a/java-security-test/README.md b/java-security-test/README.md index 8c0ee7d79..3cd2896c9 100644 --- a/java-security-test/README.md +++ b/java-security-test/README.md @@ -22,7 +22,7 @@ It includes for example a `JwtGenerator` that generates JSON Web Tokens (JWT) th com.sap.cloud.security java-security-test - 2.17.1 + 2.17.2 test ``` diff --git a/java-security-test/pom.xml b/java-security-test/pom.xml index 7bc992b1e..e7aff0607 100644 --- a/java-security-test/pom.xml +++ b/java-security-test/pom.xml @@ -9,7 +9,7 @@ com.sap.cloud.security.xsuaa parent - 2.17.1 + 2.17.2 com.sap.cloud.security diff --git a/java-security/Migration_SpringSecurityProjects.md b/java-security/Migration_SpringSecurityProjects.md index 5f46d183b..21980db32 100644 --- a/java-security/Migration_SpringSecurityProjects.md +++ b/java-security/Migration_SpringSecurityProjects.md @@ -37,19 +37,19 @@ First make sure you have the following dependencies defined in your pom.xml: com.sap.cloud.security.xsuaa api - 2.17.1 + 2.17.2 com.sap.cloud.security java-security - 2.17.1 + 2.17.2 com.sap.cloud.security java-security-test - 2.17.1 + 2.17.2 test ``` diff --git a/java-security/README.md b/java-security/README.md index 4b194f219..fa4719c77 100644 --- a/java-security/README.md +++ b/java-security/README.md @@ -47,7 +47,7 @@ In case of XSUAA does the JWT provide a valid `jku` token header parameter that com.sap.cloud.security java-security - 2.17.1 + 2.17.2 org.apache.httpcomponents diff --git a/java-security/pom.xml b/java-security/pom.xml index b7fd5d472..0cf0be0f9 100644 --- a/java-security/pom.xml +++ b/java-security/pom.xml @@ -9,7 +9,7 @@ com.sap.cloud.security.xsuaa parent - 2.17.1 + 2.17.2 com.sap.cloud.security diff --git a/pom.xml b/pom.xml index fd24e8246..bd7719123 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.sap.cloud.security.xsuaa parent - 2.17.1 + 2.17.2 pom parent diff --git a/samples/java-security-usage-ias/pom.xml b/samples/java-security-usage-ias/pom.xml index 685a90095..22311bf6b 100755 --- a/samples/java-security-usage-ias/pom.xml +++ b/samples/java-security-usage-ias/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.sap.cloud.security.xssec.samples java-security-usage-ias - 2.17.1 + 2.17.2 war org.springframework.boot diff --git a/spring-xsuaa-mock/pom.xml b/spring-xsuaa-mock/pom.xml index ff82d8239..dc6c561c7 100644 --- a/spring-xsuaa-mock/pom.xml +++ b/spring-xsuaa-mock/pom.xml @@ -9,7 +9,7 @@ com.sap.cloud.security.xsuaa parent - 2.17.1 + 2.17.2 spring-xsuaa-mock diff --git a/spring-xsuaa-starter/pom.xml b/spring-xsuaa-starter/pom.xml index c36a6f3b5..5dfac9984 100644 --- a/spring-xsuaa-starter/pom.xml +++ b/spring-xsuaa-starter/pom.xml @@ -16,7 +16,7 @@ com.sap.cloud.security.xsuaa parent - 2.17.1 + 2.17.2 xsuaa-spring-boot-starter diff --git a/spring-xsuaa-test/README.md b/spring-xsuaa-test/README.md index 3737b15b2..6b41aba35 100644 --- a/spring-xsuaa-test/README.md +++ b/spring-xsuaa-test/README.md @@ -31,7 +31,7 @@ This includes for example a `JwtGenerator` that generates JSON Web Tokens (JWT) com.sap.cloud.security.xsuaa spring-xsuaa-test - 2.17.1 + 2.17.2 test diff --git a/spring-xsuaa-test/pom.xml b/spring-xsuaa-test/pom.xml index dc1b6c4e7..8d8fc0da7 100644 --- a/spring-xsuaa-test/pom.xml +++ b/spring-xsuaa-test/pom.xml @@ -9,7 +9,7 @@ com.sap.cloud.security.xsuaa parent - 2.17.1 + 2.17.2 spring-xsuaa-test diff --git a/spring-xsuaa/README.md b/spring-xsuaa/README.md index 24396b1f4..1ecec9ee9 100644 --- a/spring-xsuaa/README.md +++ b/spring-xsuaa/README.md @@ -41,7 +41,7 @@ These (spring) dependencies needs to be provided: com.sap.cloud.security.xsuaa spring-xsuaa - 2.17.1 + 2.17.2 org.apache.logging.log4j @@ -55,7 +55,7 @@ These (spring) dependencies needs to be provided: com.sap.cloud.security.xsuaa xsuaa-spring-boot-starter - 2.17.1 + 2.17.2 ``` diff --git a/spring-xsuaa/pom.xml b/spring-xsuaa/pom.xml index aace0eeba..d1b04a665 100644 --- a/spring-xsuaa/pom.xml +++ b/spring-xsuaa/pom.xml @@ -9,7 +9,7 @@ com.sap.cloud.security.xsuaa parent - 2.17.1 + 2.17.2 spring-xsuaa diff --git a/token-client/README.md b/token-client/README.md index cdab724e6..2da097aed 100644 --- a/token-client/README.md +++ b/token-client/README.md @@ -23,7 +23,7 @@ The Resource owner password credentials (i.e., username and password) can be use com.sap.cloud.security.xsuaa token-client - 2.17.1 + 2.17.2 org.apache.httpcomponents @@ -80,7 +80,7 @@ tokenService.clearCache(); com.sap.cloud.security.xsuaa token-client - 2.17.1 + 2.17.2 org.springframework @@ -130,7 +130,7 @@ In context of a Spring Boot application you may like to leverage autoconfigurati com.sap.cloud.security.xsuaa xsuaa-spring-boot-starter - 2.17.1 + 2.17.2 org.apache.httpcomponents diff --git a/token-client/pom.xml b/token-client/pom.xml index 2db87ec9e..f756bb6e8 100644 --- a/token-client/pom.xml +++ b/token-client/pom.xml @@ -9,7 +9,7 @@ com.sap.cloud.security.xsuaa parent - 2.17.1 + 2.17.2 token-client From a4da890dcabe17736b80e96344bf71fe1da812be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C4=ABga?= <72249435+liga-oz@users.noreply.github.com> Date: Tue, 5 Dec 2023 10:02:10 +0100 Subject: [PATCH 19/19] Update CHANGELOG.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Līga <72249435+liga-oz@users.noreply.github.com> --- CHANGELOG.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e4f03d8d..cadb6d41b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,12 @@ All notable changes to this project will be documented in this file. ## 2.17.2 -✅ Resolve Breaking Change introduced in 2.17.0. Consumers should be able to update to 2.17.2 from a version <= 2.16.0 without having to adjust test credentials used in their unit tests when using java-security-test or spring-xsuaa-mock. +✅ Resolves a Breaking Change introduced in version 2.17.0. Consumers should be able to update to 2.17.2 from a version <= 2.16.0 without having to adjust test credentials used in their unit tests when using `java-security-test` or `spring-xsuaa-mock`. -In version 2.17.2, when java-security-test or spring-xsuaa-mock are loaded (which MUST only be the case during _test_ scope), credentials with 'localhost' used as _uaadomain_ (XSUAA) or as trusted _domains_ (IAS), work again for validating tokens whose _jku_ (XSUAA) or _issuer_ (IAS) include a port for localhost. -Please note that the validation of tokens is less strict in this case and might accept edge-cases of malicious tokens that would not be accepted when java-security-test or spring-xsuaa-mock are not loaded. +In version 2.17.2, when `java-security-test` or `spring-xsuaa-mock` are loaded (which should only occur during testing), credentials with `localhost` as the `uaadomain` (XSUAA) or trusted `domains` (IAS) can be used to validate tokens that include a port for `localhost` in their `jku` (XSUAA) or `issuer` (IAS). It's important to note that token validation is less strict in this case and may accept certain edge cases of malicious tokens that would not be accepted in a production environment. + +#### Dependency upgrades +- Bump logback-core, logback-classic from 1.2.12 to 1.2.13 ## 2.17.1 #### Dependency upgrades