Repository: SAP/cloud-security-xsuaa-integration
Pull request #378 (2020-09-30 09:36:28)

Add tests for malicious jku header
This PR addes tests that check that non-trusted jku hosts are always rejected.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9cefc68a..15df4ddf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,18 @@
 
 All notable changes to this project will be documented in this file.
 
+## 2.7.8
+- [java-security-test] Supports JUnit 5 Tests with `XsuaaExtension`, `IasExtension` and `SecurityTestExtension` as documented [here](/java-security-test#junit-5).
+- [java-security] Does not fail in case of Xsuaa services of type: `apiacess` (#382).
+- [spring-xsuaa-starter] Upgrade Spring versions:
+  - spring.boot.version: 2.3.1.RELEASE --> 2.3.4.RELEASE
+  - spring.core.version: 5.2.8.RELEASE --> 5.2.9.RELEASE
+- The following dependencies were updated:
+  - Jetty 9.4.24.v20191120 --> 9.4.31.v20200723
+  - javax.servlet-api.version 3.0.1 --> 3.1.0
+  - Apache HTTP client 4.5.8 --> 4.5.9
+  - Wiremock 2.25.1 --> 2.27.2
+  
 ## 2.7.7
 - [spring-xsuaa] Update Spring versions
   - spring.core.version: 5.2.7.RELEASE --> 5.2.8.RELEASE
diff --git a/api/README.md b/api/README.md
index 516e70f8..9513139f 100644
--- a/api/README.md
+++ b/api/README.md
@@ -5,6 +5,6 @@
 <dependency>
     <groupId>com.sap.cloud.security.xsuaa</groupId>
     <artifactId>api</artifactId>
-    <version>2.7.7</version>
+    <version>2.7.8</version>
 </dependency>
 ```
diff --git a/api/pom.xml b/api/pom.xml
index 92c574d4..d3a9cb5c 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -8,7 +8,7 @@
 	<parent>
 		<groupId>com.sap.cloud.security.xsuaa</groupId>
 		<artifactId>parent</artifactId>
-		<version>2.7.7</version>
+		<version>2.7.8</version>
 	</parent>
 
 	<packaging>jar</packaging>
diff --git a/java-api/README.md b/java-api/README.md
index c91891f7..ae536e60 100644
--- a/java-api/README.md
+++ b/java-api/README.md
@@ -5,6 +5,6 @@
 <dependency>
     <groupId>com.sap.cloud.security</groupId>
     <artifactId>java-api</artifactId>
-    <version>2.7.7</version>
+    <version>2.7.8</version>
 </dependency>
 ```
diff --git a/java-api/pom.xml b/java-api/pom.xml
index 255d38d2..bd0294bc 100644
--- a/java-api/pom.xml
+++ b/java-api/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
 		<groupId>com.sap.cloud.security.xsuaa</groupId>
 		<artifactId>parent</artifactId>
-		<version>2.7.7</version>
+		<version>2.7.8</version>
 	</parent>
 
 	<groupId>com.sap.cloud.security</groupId>
diff --git a/java-security-it/pom.xml b/java-security-it/pom.xml
index 83e9dd39..a640bd21 100644
--- a/java-security-it/pom.xml
+++ b/java-security-it/pom.xml
@@ -7,7 +7,7 @@
     <parent>
         <artifactId>parent</artifactId>
         <groupId>com.sap.cloud.security.xsuaa</groupId>
-        <version>2.7.7</version>
+        <version>2.7.8</version>
     </parent>
 
     <artifactId>java-security-it</artifactId>
@@ -53,17 +53,7 @@
         </dependency>
         <dependency>
             <groupId>org.junit.jupiter</groupId>
-            <artifactId>junit-jupiter-api</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.junit.jupiter</groupId>
-            <artifactId>junit-jupiter-engine</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.junit.vintage</groupId>
-            <artifactId>junit-vintage-engine</artifactId>
+            <artifactId>junit-jupiter-params</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/java-security/Migration_SpringSecurityProjects.md b/java-security/Migration_SpringSecurityProjects.md
index e2a9815b..80fa734b 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:
 <dependency>
   <groupId>com.sap.cloud.security.xsuaa</groupId>
   <artifactId>api</artifactId>
-  <version>2.7.7</version>
+  <version>2.7.8</version>
 </dependency>
 <dependency>
   <groupId>com.sap.cloud.security</groupId>
   <artifactId>java-security</artifactId>
-  <version>2.7.7</version>
+  <version>2.7.8</version>
 </dependency>
 
 <!-- new java-security dependencies for unit tests -->
 <dependency>
   <groupId>com.sap.cloud.security</groupId>
   <artifactId>java-security-test</artifactId>
-  <version>2.7.7</version>
+  <version>2.7.8</version>
   <scope>test</scope>
 </dependency>
 ```
diff --git a/java-security/README.md b/java-security/README.md
index 92dc50f5..1b7c52a7 100644
--- a/java-security/README.md
+++ b/java-security/README.md
@@ -45,7 +45,7 @@ Token Validation for Java applications.
 <dependency>
     <groupId>com.sap.cloud.security</groupId>
     <artifactId>java-security</artifactId>
-    <version>2.7.7</version>
+    <version>2.7.8</version>
 </dependency>
 <dependency>
     <groupId>org.apache.httpcomponents</groupId>
diff --git a/java-security/pom.xml b/java-security/pom.xml
index 57b27968..e2e44cee 100644
--- a/java-security/pom.xml
+++ b/java-security/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
 		<groupId>com.sap.cloud.security.xsuaa</groupId>
 		<artifactId>parent</artifactId>
-		<version>2.7.7</version>
+		<version>2.7.8</version>
 	</parent>
 
 	<groupId>com.sap.cloud.security</groupId>
diff --git a/pom.xml b/pom.xml
index f9000c58..72610028 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
 
 	<groupId>com.sap.cloud.security.xsuaa</groupId>
 	<artifactId>parent</artifactId>
-	<version>2.7.7</version>
+	<version>2.7.8</version>
 	<packaging>pom</packaging>
 
 	<name>parent</name>
@@ -71,7 +71,7 @@
 		<commons.io.version>2.6</commons.io.version>
 		<javax.servlet.api.version>3.1.0</javax.servlet.api.version>
 		<mockwebserver.version>3.9.1</mockwebserver.version>
-		<junit.version>4.12</junit.version>
+		<junit.version>4.13.1</junit.version>
 		<junit-jupiter.version>5.7.0</junit-jupiter.version>
 		<hamcrest.version>1.3</hamcrest.version>
 		<mockito.version>2.23.0</mockito.version>
@@ -279,6 +279,11 @@
 				<artifactId>junit-vintage-engine</artifactId>
 				<version>${junit-jupiter.version}</version>
 			</dependency>
+			<dependency>
+				<groupId>org.junit.jupiter</groupId>
+				<artifactId>junit-jupiter-params</artifactId>
+				<version>${junit-jupiter.version}</version>
+			</dependency>
 			<dependency>
 				<groupId>org.hamcrest</groupId>
 				<artifactId>hamcrest-all</artifactId>
diff --git a/samples/java-security-usage/pom.xml b/samples/java-security-usage/pom.xml
index 17cd015c..52a3a622 100755
--- a/samples/java-security-usage/pom.xml
+++ b/samples/java-security-usage/pom.xml
@@ -3,13 +3,13 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.sap.cloud.security.xssec.samples</groupId>
     <artifactId>java-security-usage</artifactId>
-    <version>2.7.7</version>
+    <version>2.7.8</version>
     <packaging>jar</packaging>
 
     <properties>
         <maven.compiler.source>1.8</maven.compiler.source>
         <maven.compiler.target>1.8</maven.compiler.target>
-        <sap.cloud.security.version>2.7.7</sap.cloud.security.version>
+        <sap.cloud.security.version>2.7.8</sap.cloud.security.version>
         <slf4j.api.version>1.7.30</slf4j.api.version>
         <apache.httpclient.version>4.5.9</apache.httpclient.version>
         <javax.servlet.api.version>3.1.0</javax.servlet.api.version>
diff --git a/samples/java-tokenclient-usage/pom.xml b/samples/java-tokenclient-usage/pom.xml
index a97c15b3..2066f160 100755
--- a/samples/java-tokenclient-usage/pom.xml
+++ b/samples/java-tokenclient-usage/pom.xml
@@ -3,13 +3,13 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.sap.cloud.security.xssec.samples</groupId>
     <artifactId>java-tokenclient-usage</artifactId>
-    <version>2.7.7</version>
+    <version>2.7.8</version>
     <packaging>war</packaging>
 
     <properties>
         <maven.compiler.source>1.8</maven.compiler.source>
         <maven.compiler.target>1.8</maven.compiler.target>
-        <sap.cloud.security.version>2.7.7</sap.cloud.security.version>
+        <sap.cloud.security.version>2.7.8</sap.cloud.security.version>
         <apache.httpclient.version>4.5.9</apache.httpclient.version>
         <javax.servlet.api.version>3.1.0</javax.servlet.api.version>
     </properties>
diff --git a/samples/sap-java-buildpack-api-usage/pom.xml b/samples/sap-java-buildpack-api-usage/pom.xml
index 3ab2a969..087a0e24 100755
--- a/samples/sap-java-buildpack-api-usage/pom.xml
+++ b/samples/sap-java-buildpack-api-usage/pom.xml
@@ -3,13 +3,13 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>com.sap.cloud.security.xssec.samples</groupId>
 	<artifactId>sap-java-buildpack-api-usage</artifactId>
-	<version>2.7.7</version>
+	<version>2.7.8</version>
 	<packaging>war</packaging>
 
 	<properties>
 		<maven.compiler.source>1.8</maven.compiler.source>
 		<maven.compiler.target>1.8</maven.compiler.target>
-		<sap.cloud.security.version>2.7.7</sap.cloud.security.version>
+		<sap.cloud.security.version>2.7.8</sap.cloud.security.version>
 		<javax.servlet.api.version>3.1.0</javax.servlet.api.version>
 	</properties>
 
diff --git a/samples/spring-security-basic-auth/pom.xml b/samples/spring-security-basic-auth/pom.xml
index ba8e92bf..d071aa28 100644
--- a/samples/spring-security-basic-auth/pom.xml
+++ b/samples/spring-security-basic-auth/pom.xml
@@ -11,14 +11,14 @@
 	</parent>
 
 	<artifactId>spring-security-basic-auth</artifactId>
-	<version>2.7.7</version>
+	<version>2.7.8</version>
 	<name>spring-security-basic-auth</name>
 
 	<properties>
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
 		<java.version>1.8</java.version>
-		<sap.cloud.security.version>2.7.7</sap.cloud.security.version>
+		<sap.cloud.security.version>2.7.8</sap.cloud.security.version>
 	</properties>
 
 	<dependencies>
diff --git a/samples/spring-security-xsuaa-usage/pom.xml b/samples/spring-security-xsuaa-usage/pom.xml
index baefdd8c..951c8b4f 100644
--- a/samples/spring-security-xsuaa-usage/pom.xml
+++ b/samples/spring-security-xsuaa-usage/pom.xml
@@ -14,7 +14,7 @@
 
 	<groupId>com.sap.cloud.security.samples</groupId>
 	<artifactId>spring-security-xsuaa-usage</artifactId>
-	<version>2.7.7</version>
+	<version>2.7.8</version>
 	<name>spring-security-xsuaa-usage</name>
 
 	<properties>
@@ -27,7 +27,7 @@
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
 		<java.version>1.8</java.version>
-		<sap.cloud.security.version>2.7.7</sap.cloud.security.version>
+		<sap.cloud.security.version>2.7.8</sap.cloud.security.version>
 	</properties>
 
     <dependencies>
diff --git a/samples/spring-webflux-security-xsuaa-usage/pom.xml b/samples/spring-webflux-security-xsuaa-usage/pom.xml
index 2f151a95..f7e1a488 100644
--- a/samples/spring-webflux-security-xsuaa-usage/pom.xml
+++ b/samples/spring-webflux-security-xsuaa-usage/pom.xml
@@ -12,12 +12,12 @@
 
     <groupId>com.sap.cloud.security.samples</groupId>
     <artifactId>spring-webflux-security-xsuaa-usage</artifactId>
-    <version>2.7.7</version>
+    <version>2.7.8</version>
     <name>spring-webflux-security-xsuaa-usage</name>
 
     <properties>
         <java.version>1.8</java.version>
-        <sap.cloud.security.version>2.7.7</sap.cloud.security.version>
+        <sap.cloud.security.version>2.7.8</sap.cloud.security.version>
     </properties>
 
     <dependencies>
diff --git a/spring-xsuaa-it/pom.xml b/spring-xsuaa-it/pom.xml
index f2be6577..37ed1518 100644
--- a/spring-xsuaa-it/pom.xml
+++ b/spring-xsuaa-it/pom.xml
@@ -6,7 +6,7 @@
 	<parent>
 		<groupId>com.sap.cloud.security.xsuaa</groupId>
 		<artifactId>parent</artifactId>
-		<version>2.7.7</version>
+		<version>2.7.8</version>
 	</parent>
 
 	<artifactId>spring-xsuaa-it</artifactId>
diff --git a/spring-xsuaa-mock/README.md b/spring-xsuaa-mock/README.md
index 3dfb0eff..695563c3 100644
--- a/spring-xsuaa-mock/README.md
+++ b/spring-xsuaa-mock/README.md
@@ -21,7 +21,7 @@ The default implementation offers already valid *token_keys* for JWT tokens, tha
 <dependency>
     <groupId>com.sap.cloud.security.xsuaa</groupId>
     <artifactId>spring-xsuaa-mock</artifactId>
-    <version>2.7.7</version>
+    <version>2.7.8</version>
 </dependency>
 <dependency> <!-- new with version 1.5.0 - provided with org.springframework.boot:spring-boot-starter:jar -->
     <groupId>org.springframework.boot</groupId>
diff --git a/spring-xsuaa-mock/pom.xml b/spring-xsuaa-mock/pom.xml
index 690fb6eb..f1f5d0fe 100644
--- a/spring-xsuaa-mock/pom.xml
+++ b/spring-xsuaa-mock/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
 		<groupId>com.sap.cloud.security.xsuaa</groupId>
 		<artifactId>parent</artifactId>
-		<version>2.7.7</version>
+		<version>2.7.8</version>
 	</parent>
 
 	<artifactId>spring-xsuaa-mock</artifactId>
diff --git a/spring-xsuaa-starter/pom.xml b/spring-xsuaa-starter/pom.xml
index 0558a9a1..e2593660 100644
--- a/spring-xsuaa-starter/pom.xml
+++ b/spring-xsuaa-starter/pom.xml
@@ -14,7 +14,7 @@
 	<parent>
 		<groupId>com.sap.cloud.security.xsuaa</groupId>
 		<artifactId>parent</artifactId>
-		<version>2.7.7</version>
+		<version>2.7.8</version>
 	</parent>
 
 	<artifactId>xsuaa-spring-boot-starter</artifactId>
diff --git a/spring-xsuaa/README.md b/spring-xsuaa/README.md
index 7d2617e5..530dfc04 100644
--- a/spring-xsuaa/README.md
+++ b/spring-xsuaa/README.md
@@ -25,7 +25,7 @@ These (spring) dependencies needs to be provided:
 <dependency>
     <groupId>com.sap.cloud.security.xsuaa</groupId>
     <artifactId>spring-xsuaa</artifactId>
-    <version>2.7.7</version>
+    <version>2.7.8</version>
 </dependency>
 <dependency> <!-- new with version 1.5.0 -->
     <groupId>org.apache.logging.log4j</groupId>
@@ -40,7 +40,7 @@ These (spring) dependencies needs to be provided:
 <dependency>
     <groupId>com.sap.cloud.security.xsuaa</groupId>
     <artifactId>xsuaa-spring-boot-starter</artifactId>
-    <version>2.7.7</version>
+    <version>2.7.8</version>
 </dependency>
 ```
 
diff --git a/spring-xsuaa/pom.xml b/spring-xsuaa/pom.xml
index 0161c850..e8ca5aca 100644
--- a/spring-xsuaa/pom.xml
+++ b/spring-xsuaa/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
 		<groupId>com.sap.cloud.security.xsuaa</groupId>
 		<artifactId>parent</artifactId>
-		<version>2.7.7</version>
+		<version>2.7.8</version>
 	</parent>
 
 	<artifactId>spring-xsuaa</artifactId>
diff --git a/token-client/README.md b/token-client/README.md
index b2c47181..26c18a6f 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
 <dependency>
     <groupId>com.sap.cloud.security.xsuaa</groupId>
     <artifactId>token-client</artifactId>
-    <version>2.7.7</version>
+    <version>2.7.8</version>
 </dependency>
 <dependency>
   <groupId>org.apache.httpcomponents</groupId>
@@ -64,7 +64,7 @@ By default, the `DefaultOAuth2TokenService` caches tokens internally. The Cache
 <dependency>
     <groupId>com.sap.cloud.security.xsuaa</groupId>
     <artifactId>token-client</artifactId>
-    <version>2.7.7</version>
+    <version>2.7.8</version>
 </dependency>
 ```
 
@@ -95,7 +95,7 @@ In context of a Spring Boot application you may like to leverage auto-configurat
 <dependency>
     <groupId>com.sap.cloud.security.xsuaa</groupId>
     <artifactId>xsuaa-spring-boot-starter</artifactId>
-    <version>2.7.7</version>
+    <version>2.7.8</version>
 </dependency>
 ```
 
diff --git a/token-client/pom.xml b/token-client/pom.xml
index 82ba7aec..a08550e3 100644
--- a/token-client/pom.xml
+++ b/token-client/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
 		<groupId>com.sap.cloud.security.xsuaa</groupId>
 		<artifactId>parent</artifactId>
-		<version>2.7.7</version>
+		<version>2.7.8</version>
 	</parent>
 
 	<artifactId>token-client</artifactId>


Test patch:
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
new file mode 100644
index 00000000..86305a55
--- /dev/null
+++ b/java-security-it/src/test/java/com/sap/cloud/security/test/integration/ssrf/JavaSSRFAttackTest.java
@@ -0,0 +1,75 @@
+package com.sap.cloud.security.test.integration.ssrf;
+
+import com.sap.cloud.security.config.OAuth2ServiceConfigurationBuilder;
+import com.sap.cloud.security.config.Service;
+import com.sap.cloud.security.test.extension.SecurityTestExtension;
+import com.sap.cloud.security.token.Token;
+import com.sap.cloud.security.token.TokenHeader;
+import com.sap.cloud.security.token.validation.CombiningValidator;
+import com.sap.cloud.security.token.validation.ValidationResult;
+import com.sap.cloud.security.token.validation.validators.JwtValidatorBuilder;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+import java.io.IOException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.times;
+
+/**
+ * Test cases for <a href=
+ * "https://owasp.org/www-community/attacks/Server_Side_Request_Forgery">SSRF
+ * (Server Side Request Forgery)</a> attacks.
+ *
+ */
+public class JavaSSRFAttackTest {
+
+	private CloseableHttpClient httpClient = Mockito.spy(HttpClients.createDefault());
+
+	@RegisterExtension
+	static SecurityTestExtension extension = SecurityTestExtension.forService(Service.XSUAA).setPort(4242);
+
+	/**
+	 * This tests checks that an attacker cannot trick the token validation into
+	 * using his/her own token key server by manipulating the JWKS url. The
+	 * challenge is to redirect the request to a different token key server without
+	 * the token validation steps to fail.
+	 *
+	 * @param jwksUrl
+	 *            the JWKS url containing malicious parts
+	 * @param isValid
+	 *            {@code true} if the token validation is expected to be successful
+	 */
+	@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",
+	})
+	public void maliciousPartOfJwksIsNotUsedToObtainToken(String jwksUrl, boolean isValid) throws IOException {
+		OAuth2ServiceConfigurationBuilder configuration = extension.getContext()
+				.getOAuth2ServiceConfigurationBuilderFromFile("/xsuaa/vcap_services-single.json");
+		Token token = extension.getContext().getJwtGeneratorFromFile("/xsuaa/token.json")
+				.withHeaderParameter(TokenHeader.JWKS_URL, jwksUrl)
+				.createToken();
+		CombiningValidator<Token> tokenValidator = JwtValidatorBuilder
+				.getInstance(configuration.build())
+				.withHttpClient(httpClient)
+				.build();
+
+		ValidationResult result = tokenValidator.validate(token);
+
+		assertThat(result.isValid()).isEqualTo(isValid);
+		ArgumentCaptor<HttpUriRequest> httpUriRequestCaptor = ArgumentCaptor.forClass(HttpUriRequest.class);
+		Mockito.verify(httpClient, times(1)).execute(httpUriRequestCaptor.capture());
+		HttpUriRequest request = httpUriRequestCaptor.getValue();
+		assertThat(request.getURI().getHost()).isEqualTo("localhost"); // ensure request was sent to trusted host
+	}
+
+}
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
new file mode 100644
index 00000000..b02b6450
--- /dev/null
+++ b/java-security-it/src/test/java/com/sap/cloud/security/test/integration/ssrf/SpringSSRFAttackTest.java
@@ -0,0 +1,83 @@
+package com.sap.cloud.security.test.integration.ssrf;
+
+import com.sap.cloud.security.config.Service;
+import com.sap.cloud.security.test.SecurityTest;
+import com.sap.cloud.security.test.extension.SecurityTestExtension;
+import com.sap.cloud.security.token.TokenHeader;
+import com.sap.cloud.security.xsuaa.XsuaaCredentials;
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfigurationCustom;
+import com.sap.cloud.security.xsuaa.token.authentication.XsuaaJwtDecoderBuilder;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import org.springframework.http.RequestEntity;
+import org.springframework.security.oauth2.jwt.JwtDecoder;
+import org.springframework.security.oauth2.jwt.JwtException;
+import org.springframework.web.client.RestOperations;
+import org.springframework.web.client.RestTemplate;
+
+import java.io.IOException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Test cases for <a href=
+ * "https://owasp.org/www-community/attacks/Server_Side_Request_Forgery">SSRF
+ * (Server Side Request Forgery)</a> attacks.
+ */
+public class SpringSSRFAttackTest {
+
+	private RestOperations restOperations = Mockito.spy(new RestTemplate());
+
+	@RegisterExtension
+	static SecurityTestExtension extension = SecurityTestExtension.forService(Service.XSUAA).setPort(4242);
+
+	/**
+	 * This tests checks that an attacker cannot trick the token validation into
+	 * using his/her own token key server by manipulating the JWKS url. The
+	 * challenge is to redirect the request to a different token key server without
+	 * the token validation steps to fail.
+	 *
+	 * @param jwksUrl
+	 *            the JWKS url containing malicious parts
+	 * @param isValid
+	 *            {@code true} if the token validation is expected to be successful
+	 */
+	@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",
+	})
+	public void maliciousPartOfJwksIsNotUsedToObtainToken(String jwksUrl, boolean isValid) throws IOException {
+		String token = extension.getContext().getPreconfiguredJwtGenerator()
+				.withHeaderParameter(TokenHeader.JWKS_URL, jwksUrl)
+				.createToken()
+				.getTokenValue();
+		JwtDecoder jwtDecoder = new XsuaaJwtDecoderBuilder(
+				new XsuaaServiceConfigurationCustom(createXsuaaCredentials()))
+						.withRestOperations(restOperations)
+						.build();
+		try {
+			jwtDecoder.decode(token);
+			assertThat(isValid).isTrue();
+		} catch (JwtException e) {
+			assertThat(isValid).isFalse();
+		}
+		ArgumentCaptor<RequestEntity> requestArgumentCaptor = ArgumentCaptor.forClass(RequestEntity.class);
+		Mockito.verify(restOperations).exchange(requestArgumentCaptor.capture(),
+				ArgumentCaptor.forClass(Class.class).capture());
+		String host = requestArgumentCaptor.getValue().getUrl().getHost();
+		assertThat(host).isEqualTo("localhost");
+	}
+
+	private XsuaaCredentials createXsuaaCredentials() {
+		XsuaaCredentials xsuaaCredentials = new XsuaaCredentials();
+		xsuaaCredentials.setUaaDomain(SecurityTest.DEFAULT_DOMAIN);
+		xsuaaCredentials.setClientId(SecurityTest.DEFAULT_CLIENT_ID);
+		xsuaaCredentials.setXsAppName(SecurityTest.DEFAULT_APP_ID);
+		return xsuaaCredentials;
+	}
+}
diff --git a/java-security-test/README.md b/java-security-test/README.md
index 477bc59c..78e8e32e 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
 <dependency>
     <groupId>com.sap.cloud.security</groupId>
     <artifactId>java-security-test</artifactId>
-    <version>2.7.7</version>
+    <version>2.7.8</version>
     <scope>test</scope>
 </dependency>
 ```
diff --git a/java-security-test/pom.xml b/java-security-test/pom.xml
index 3ed85c68..fca9fe2e 100644
--- a/java-security-test/pom.xml
+++ b/java-security-test/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
 		<groupId>com.sap.cloud.security.xsuaa</groupId>
 		<artifactId>parent</artifactId>
-		<version>2.7.7</version>
+		<version>2.7.8</version>
 	</parent>
 
 	<groupId>com.sap.cloud.security</groupId>
diff --git a/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/XsuaaJkuValidatorTest.java b/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/XsuaaJkuValidatorTest.java
index a8ae93a6..00988556 100644
--- a/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/XsuaaJkuValidatorTest.java
+++ b/java-security/src/test/java/com/sap/cloud/security/token/validation/validators/XsuaaJkuValidatorTest.java
@@ -105,4 +105,16 @@ public class XsuaaJkuValidatorTest {
 				containsString("Jwt token does not contain a valid 'jku' header parameter"));
 	}
 
+	@Test
+	public void validationFails_whenJkuHasNonTrustedHost() {
+		when(token.getHeaderParameterAsString(JWKS_URL))
+				.thenReturn("http://myauth.ondemand.com\\@malicious.ondemand.com/token_keys");
+		assertThat(cut.validate(token).isValid(), is(false));
+		when(token.getHeaderParameterAsString(JWKS_URL))
+				.thenReturn("http://myauth.ondemand.com@malicious.ondemand.com/token_keys");
+		assertThat(cut.validate(token).isValid(), is(false));
+		when(token.getHeaderParameterAsString(JWKS_URL))
+				.thenReturn("http://malicious.ondemand.com/token_keys///myauth.ondemand.com/token_keys");
+		assertThat(cut.validate(token).isValid(), is(false));
+	}
 }
diff --git a/spring-xsuaa-test/README.md b/spring-xsuaa-test/README.md
index 8e6aee04..e50cde34 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)
 <dependency>
     <groupId>com.sap.cloud.security.xsuaa</groupId>
     <artifactId>spring-xsuaa-test</artifactId>
-    <version>2.7.7</version>
+    <version>2.7.8</version>
     <scope>test</scope>
 </dependency>
 
diff --git a/spring-xsuaa-test/pom.xml b/spring-xsuaa-test/pom.xml
index c845d142..f3bd79a5 100644
--- a/spring-xsuaa-test/pom.xml
+++ b/spring-xsuaa-test/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
 		<groupId>com.sap.cloud.security.xsuaa</groupId>
 		<artifactId>parent</artifactId>
-		<version>2.7.7</version>
+		<version>2.7.8</version>
 	</parent>
 
 	<artifactId>spring-xsuaa-test</artifactId>
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 a0a512b1..18f30786 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
@@ -56,12 +56,30 @@ public class XsuaaJwtDecoderTest {
 	@Test
 	public void decode_whenJwksContainsInvalidJwksDomain_throwsException() throws IOException {
 		String token = IOUtils.resourceToString("/token_user.txt", StandardCharsets.UTF_8);
-
 		XsuaaJwtDecoder cut = (XsuaaJwtDecoder) new XsuaaJwtDecoderBuilder(configuration).build();
+
 		cut.setTokenInfoExtractor(new TokenInfoExtractorImpl("https://subdomain.wrongoauth.ondemand.com/token_keys"));
+		assertThatThrownBy(() -> cut.decode(token)).isInstanceOf(JwtException.class)
+				.hasMessageContaining("JWT verification failed: Do not trust 'jku' token header");
 
+		cut.setTokenInfoExtractor(new TokenInfoExtractorImpl("http://myauth.ondemand.com@malicious.ondemand.com/token_keys"));
 		assertThatThrownBy(() -> cut.decode(token)).isInstanceOf(JwtException.class)
 				.hasMessageContaining("JWT verification failed: Do not trust 'jku' token header");
+
+		cut.setTokenInfoExtractor(new TokenInfoExtractorImpl("http://malicious.ondemand.com/token_keys///myauth.ondemand.com/token_keys"));
+		assertThatThrownBy(() -> cut.decode(token)).isInstanceOf(JwtException.class)
+				.hasMessageContaining("JWT verification failed: Do not trust 'jku' token header");
+	}
+
+	@Test
+	public void decode_whenJwksUrlIsNotValid_throwsException() throws IOException {
+		String token = IOUtils.resourceToString("/token_cc.txt", StandardCharsets.UTF_8);
+		XsuaaJwtDecoder cut = (XsuaaJwtDecoder) new XsuaaJwtDecoderBuilder(configuration).build();
+
+		cut.setTokenInfoExtractor(
+				new TokenInfoExtractorImpl("http://myauth.ondemand.com\\@malicious.ondemand.com/token_keys"));
+		assertThatThrownBy(() -> cut.decode(token)).isInstanceOf(JwtException.class)
+				.hasMessageContaining("JWT verification failed: JKU of token header is not valid");
 	}
 
 	@Test