Repository: SAP/cloud-security-xsuaa-integration
Pull request #101 (2019-07-04 14:10:59)

[version 1.5.0] introduce auto-configuration for mock server configuration
with jku introduction with PR #100 the lib became incompatible as tests had 
  - either to configure XsuaaMockAutoConfiguration
  ```@SpringBootTest(classes = { XsuaaAutoConfiguration.class, XsuaaMockAutoConfiguration.class })``` or
  - or to configure xsuaa.uaadomain via properties
  ```@SpringBootTest(properties = { "xsuaa.url=${mockxsuaaserver.url}", "xsuaa.uaadomain=localhost}" })```

I decided to introduce auto-configuration for XsuaaMockAutoConfiguration, as also documented in the Readme.

Further changes:
- improve log messages
- document new mvn dependencies

nenaraab: @firnkes ,@mwdb,

please have a look, as version 1.5. is blocked.

Thanks!

Patch:
diff --git a/spring-xsuaa-mock/README.md b/spring-xsuaa-mock/README.md
index 5eb60f49..6013e053 100644
--- a/spring-xsuaa-mock/README.md
+++ b/spring-xsuaa-mock/README.md
@@ -19,6 +19,10 @@ The default implementation offers already valid *token_keys* for JWT tokens, tha
     <artifactId>spring-xsuaa-mock</artifactId>
     <version>1.5.0</version>
 </dependency>
+<dependency> <!-- new with version 1.5.0 - provided with org.springframework.boot:spring-boot-starter:jar -->
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-autoconfigure</artifactId> <!--
+</dependency>
 ```
 
 ### Setup Mock Web Server
@@ -56,8 +60,9 @@ Then you have to register this class to `META-INF/spring.factories`:
 org.springframework.boot.env.EnvironmentPostProcessor=<<your package>>.XsuaaMockPostProcessor
 ```
 
+### XSUAA Service Configuration
 
-And finally you need to configure the `spring.security.oauth2.resourceserver.jwt.jwk-set-uri` and the `xsuaa.url` properties in the same way as done in this [`application-uaamock.properties`](src/test/resources/application-uaamock.properties) file.
+From version `1.5.0` on the [`MockXsuaaServiceConfiguration`](src/main/java/com/sap/cloud/security/xsuaa/mock/MockXsuaaServiceConfiguration.java) is auto-configured. This class overwrites Xsuaa url and uaadomain to point to the Xsuaa Mock Web Server. This is relevant for validating the `jku` URI that is provided as part of the JSON Web Signature (JWS). The `jku` of the Jwt token issued by the `JwtGenerator` references the public key URI of the `XsuaaMockWebServer` used for generating the signature.
 
 ### Extendability
 Note: it is possible to extend the dispatcher and pass this to the `XsuaaMockWebServer` constructor. An example `XsuaaMockPostProcessor` implementation can be found [here](src/test/java/com/sap/cloud/security/xsuaa/mock/XsuaaMockPostProcessor.java).
@@ -72,4 +77,4 @@ String jwtTokenHeaderKeyId = "legacy-token-key-" + yourSubdomain;
 String jwtToken = new JwtGenerator(yourClientId, yourSubdomain).setJwtHeaderKeyId(jwtTokenHeaderKeyId).getToken().getTokenValue();
 ```
 
-When configuring [`MockXsuaaServiceConfiguration`](src/main/java/com/sap/cloud/security/xsuaa/mock/MockXsuaaServiceConfiguration.java) instead of [`XsuaaServiceConfigurationDefault`](/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/XsuaaServiceConfigurationDefault.java) the `getTokenKeyUrl()` considers the `subdomain` from the token. Then your Mock Web Server can provide different token keys for different domains e.g. `testdomain`.
+Then your Mock Web Server can provide different token keys for different domains e.g. `testdomain`.
diff --git a/spring-xsuaa-mock/pom.xml b/spring-xsuaa-mock/pom.xml
index 2140c3f5..5f104f0d 100644
--- a/spring-xsuaa-mock/pom.xml
+++ b/spring-xsuaa-mock/pom.xml
@@ -42,6 +42,11 @@
 			<artifactId>spring-security-oauth2-jose</artifactId>
 			<scope>provided</scope>
 		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-autoconfigure</artifactId>
+			<scope>provided</scope>
+		</dependency>
 		<dependency>
 			<groupId>com.squareup.okhttp3</groupId>
 			<artifactId>mockwebserver</artifactId>
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 beff2382..323f5fcf 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
@@ -11,10 +11,18 @@ public class MockXsuaaServiceConfiguration extends XsuaaServiceConfigurationDefa
 
 	@Override
 	public String getUaaDomain() {
-		if (!mockXsuaaServerUrl.isEmpty() && mockXsuaaServerUrl == getUaaUrl()) {
+		if (!mockXsuaaServerUrl.isEmpty()) {
 			return "localhost";
 		}
 		return super.getUaaDomain();
 	}
 
+	@Override
+	public String getUaaUrl() {
+		if (!mockXsuaaServerUrl.isEmpty()) {
+			return mockXsuaaServerUrl;
+		}
+		return super.getUaaUrl();
+	}
+
 }
\ No newline at end of file
diff --git a/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/mock/XsuaaMockWebServer.java b/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/mock/XsuaaMockWebServer.java
index 1f0fbee9..1a742d9f 100644
--- a/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/mock/XsuaaMockWebServer.java
+++ b/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/mock/XsuaaMockWebServer.java
@@ -75,8 +75,8 @@ public class XsuaaMockWebServer extends PropertySource<MockWebServer> implements
 			this.started = true;
 			logger.warn(
 					">>>>>>>>>>>Started Xsuaa mock Server that provides public keys for offline JWT Token validation. NEVER run in productive environment!<<<<<<");
-		} catch (IOException e) {
-			throw new RuntimeException("Could not start XSUAA mock webserver" + mockWebServer, e);
+		} catch (IllegalStateException | IOException e) {
+			throw new RuntimeException("Could not start XSUAA mock webserver (localhost:33195). Make sure that it is not yet started in another process.", e);
 		}
 	}
 }
\ No newline at end of file
diff --git a/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/mock/autoconfiguration/XsuaaMockAutoConfiguration.java b/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/mock/autoconfiguration/XsuaaMockAutoConfiguration.java
new file mode 100644
index 00000000..68dc3038
--- /dev/null
+++ b/spring-xsuaa-mock/src/main/java/com/sap/cloud/security/xsuaa/mock/autoconfiguration/XsuaaMockAutoConfiguration.java
@@ -0,0 +1,41 @@
+package com.sap.cloud.security.xsuaa.mock.autoconfiguration;
+
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.mock.MockXsuaaServiceConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.security.oauth2.jwt.Jwt;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for default beans used by
+ * the XSUAA client library.
+ * <p>
+ * Activates when there is a bean of type {@link Jwt} configured in the context.
+ *
+ * <p>
+ * can be disabled
+ * with @EnableAutoConfiguration(exclude={XsuaaMockAutoConfiguration.class}) or with
+ * property spring.xsuaa.mock.auto = false
+ */
+@Configuration
+@ConditionalOnClass(Jwt.class)
+@ConditionalOnProperty(prefix = "spring.xsuaa.mock", name = "auto", havingValue = "true", matchIfMissing = true)
+public class XsuaaMockAutoConfiguration {
+		Logger logger = LoggerFactory.getLogger(getClass());
+
+		@Bean
+		@Primary
+		@ConditionalOnProperty(name = "mockxsuaaserver.url", matchIfMissing = false)
+		@ConditionalOnMissingBean(MockXsuaaServiceConfiguration.class)
+		public XsuaaServiceConfiguration xsuaaMockServiceConfiguration() {
+			logger.info("auto-configure MockXsuaaServiceConfiguration");
+			return new MockXsuaaServiceConfiguration();
+		}
+}
diff --git a/spring-xsuaa-mock/src/main/resources/META-INF/spring.factories b/spring-xsuaa-mock/src/main/resources/META-INF/spring.factories
new file mode 100644
index 00000000..09f6405d
--- /dev/null
+++ b/spring-xsuaa-mock/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+com.sap.cloud.security.xsuaa.mock.autoconfiguration.XsuaaMockAutoConfiguration
\ No newline at end of file
diff --git a/spring-xsuaa/README.md b/spring-xsuaa/README.md
index 8e1e3ab8..3a809681 100644
--- a/spring-xsuaa/README.md
+++ b/spring-xsuaa/README.md
@@ -25,6 +25,15 @@ This library enhances the [spring-security](https://github.com/spring-projects/s
     <artifactId>spring-xsuaa</artifactId>
     <version>1.5.0</version>
 </dependency>
+<dependency> <!-- new with version 1.5.0 - provided with org.springframework.boot:spring-boot-starter:jar -->
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-autoconfigure</artifactId> <!--
+</dependency>
+<dependency> <!-- new with version 1.5.0 - provided with org.springframework.boot:spring-boot-starter:jar -->
+    <groupId>org.apache.logging.log4j</groupId>
+    <artifactId>log4j-to-slf4j</artifactId>
+    <version>2.11.2</version>
+</dependency>
 ```
 
 ### Auto-configuration
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 0030c91b..ee1dba33 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
@@ -7,8 +7,8 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.security.oauth2.core.OAuth2TokenValidator;
 import org.springframework.security.oauth2.jwt.Jwt;
 import org.springframework.security.oauth2.jwt.JwtDecoder;
@@ -24,17 +24,17 @@ import com.nimbusds.jwt.JWTParser;
 import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
 
 public class XsuaaJwtDecoder implements JwtDecoder {
-	private final Log logger = LogFactory.getLog(XsuaaJwtDecoder.class);
+	private final Logger logger = LoggerFactory.getLogger(getClass());
 
 	Cache<String, JwtDecoder> cache;
-	private XsuaaServiceConfiguration xsuaaServiceConfiguration;
+	private String uaaDomain;
 	private OAuth2TokenValidator<Jwt> tokenValidators;
 
 	XsuaaJwtDecoder(XsuaaServiceConfiguration xsuaaServiceConfiguration, int cacheValidityInSeconds, int cacheSize,
 			OAuth2TokenValidator<Jwt> tokenValidators) {
 		cache = Caffeine.newBuilder().expireAfterWrite(cacheValidityInSeconds, TimeUnit.SECONDS).maximumSize(cacheSize)
 				.build();
-		this.xsuaaServiceConfiguration = xsuaaServiceConfiguration;
+		this.uaaDomain = xsuaaServiceConfiguration.getUaaDomain();
 		this.tokenValidators = tokenValidators;
 	}
 
@@ -46,21 +46,20 @@ public class XsuaaJwtDecoder implements JwtDecoder {
 		try {
 			jwt = JWTParser.parse(token);
 		} catch (ParseException ex) {
-			throw new JwtException("Error initializing JWT decoder:" + ex.getMessage());
+			throw new JwtException("Error initializing JWT decoder: " + ex.getMessage());
 		}
 
 		String jku = (String) jwt.getHeader().toJSONObject().getOrDefault("jku", null);
 		String kid = (String) jwt.getHeader().toJSONObject().getOrDefault("kid", null);
-		String uaadomain = xsuaaServiceConfiguration.getUaaDomain();
 
 		try {
-			canVerifyWithOnlineKey(jku, kid, uaadomain);
-			validateJKU(jku, uaadomain);
+			canVerifyWithOnlineKey(jku, kid, uaaDomain);
+			validateJKU(jku, uaaDomain);
 			return verifyWithOnlineKey(token, jku, kid);
 		} catch (JwtValidationException ex) {
 			throw ex;
 		} catch (JwtException ex) {
-			throw new JwtException("JWT verification failed:" + ex.getMessage());
+			throw new JwtException("JWT verification failed: " + ex.getMessage());
 		}
 	}
 
@@ -77,7 +76,7 @@ public class XsuaaJwtDecoder implements JwtDecoder {
 		if (uaadomain == null)
 			nullParams.add("uaadomain");
 
-		throw new JwtException(String.format("Cannot verify with online key, %s is null",
+		throw new JwtException(String.format("Cannot verify with online token key, %s is null",
 				String.join(", ", nullParams)));
 	}
 
@@ -89,10 +88,10 @@ public class XsuaaJwtDecoder implements JwtDecoder {
 			} else if (!jkuUri.getHost().endsWith(uaadomain)) {
 				logger.warn(String.format("Error: Do not trust jku '%s' because it does not match uaa domain '%s'",
 						jku, uaadomain));
-				throw new JwtException("JKU of token is not trusted");
+				throw new JwtException("JKU of token header is not trusted");
 			}
 		} catch (URISyntaxException e) {
-			throw new JwtException("JKU of token is not valid");
+			throw new JwtException("JKU of token header is not valid");
 		}
 	}
 


Test patch:
diff --git a/spring-xsuaa-it/src/main/java/testservice/api/basic/SecurityConfiguration.java b/spring-xsuaa-it/src/main/java/testservice/api/basic/SecurityConfiguration.java
index 5614d8e1..4705d1ea 100644
--- a/spring-xsuaa-it/src/main/java/testservice/api/basic/SecurityConfiguration.java
+++ b/spring-xsuaa-it/src/main/java/testservice/api/basic/SecurityConfiguration.java
@@ -15,9 +15,6 @@
  */
 package testservice.api.basic;
 
-import java.net.MalformedURLException;
-import java.net.URL;
-
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cache.CacheManager;
 import org.springframework.cache.annotation.EnableCaching;
diff --git a/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaTokenValidationIT.java b/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaTokenValidationIT.java
index a5591657..3135c26f 100644
--- a/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaTokenValidationIT.java
+++ b/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaTokenValidationIT.java
@@ -5,8 +5,6 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
-import java.net.URL;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
diff --git a/spring-xsuaa-mock/src/test/java/com/sap/cloud/security/xsuaa/mock/ApplicationTest.java b/spring-xsuaa-mock/src/test/java/com/sap/cloud/security/xsuaa/mock/ApplicationTest.java
index fd72c639..24683255 100644
--- a/spring-xsuaa-mock/src/test/java/com/sap/cloud/security/xsuaa/mock/ApplicationTest.java
+++ b/spring-xsuaa-mock/src/test/java/com/sap/cloud/security/xsuaa/mock/ApplicationTest.java
@@ -6,7 +6,7 @@ import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.junit4.SpringRunner;
 
 @RunWith(SpringRunner.class)
-@SpringBootTest(properties = { "xsuaa.url=${mockxsuaaserver.url}" }, classes = {
+@SpringBootTest(classes = {
 		XsuaaMockWebServer.class, XsuaaRequestDispatcher.class, MockXsuaaServiceConfiguration.class })
 public class ApplicationTest {
 
diff --git a/spring-xsuaa-mock/src/test/java/com/sap/cloud/security/xsuaa/mock/XsuaaMockWebServerSpringBootTest.java b/spring-xsuaa-mock/src/test/java/com/sap/cloud/security/xsuaa/mock/XsuaaMockWebServerSpringBootTest.java
index bc570df4..ba674f72 100644
--- a/spring-xsuaa-mock/src/test/java/com/sap/cloud/security/xsuaa/mock/XsuaaMockWebServerSpringBootTest.java
+++ b/spring-xsuaa-mock/src/test/java/com/sap/cloud/security/xsuaa/mock/XsuaaMockWebServerSpringBootTest.java
@@ -6,10 +6,13 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.nio.charset.StandardCharsets;
 
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.mock.autoconfiguration.XsuaaMockAutoConfiguration;
 import org.apache.commons.io.IOUtils;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.http.HttpStatus;
@@ -21,17 +24,17 @@ import org.springframework.web.client.RestTemplate;
 
 @RunWith(SpringRunner.class)
 @ActiveProfiles("uaamock")
-@SpringBootTest(classes = { XsuaaMockWebServer.class, XsuaaRequestDispatcher.class })
+@SpringBootTest(classes = { XsuaaMockWebServer.class, XsuaaRequestDispatcher.class, MockXsuaaServiceConfiguration.class })
 public class XsuaaMockWebServerSpringBootTest {
 
 	RestTemplate restTemplate = new RestTemplate();
 
-	@Value("${xsuaa.url}")
-	private String xsuaaMockServerUrl;
+	@Autowired
+	private XsuaaServiceConfiguration xsuaaServiceConfiguration;
 
 	@Test
 	public void xsuaaMockStarted() throws URISyntaxException {
-		ResponseEntity<String> response = restTemplate.getForEntity(new URI(xsuaaMockServerUrl + "/token_keys"),
+		ResponseEntity<String> response = restTemplate.getForEntity(new URI(xsuaaServiceConfiguration.getUaaUrl() + "/token_keys"),
 				String.class);
 		Assert.assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
 		Assert.assertThat(response.getBody(), notNullValue());
@@ -40,7 +43,7 @@ public class XsuaaMockWebServerSpringBootTest {
 	@Test
 	public void xsuaaMockReturnsTestDomainTokenKeys() throws Exception {
 		ResponseEntity<String> response = restTemplate
-				.getForEntity(new URI(xsuaaMockServerUrl + "/testdomain/token_keys"), String.class);
+				.getForEntity(new URI(xsuaaServiceConfiguration.getUaaUrl() + "/testdomain/token_keys"), String.class);
 		String testdomainTokenKeys = IOUtils.resourceToString("/mock/testdomain_token_keys.json",
 				StandardCharsets.UTF_8);
 		Assert.assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
@@ -52,13 +55,13 @@ public class XsuaaMockWebServerSpringBootTest {
 	@Test(expected = HttpClientErrorException.class)
 	public void xsuaaMockReturnsNotFound() throws URISyntaxException {
 		ResponseEntity<String> response = restTemplate
-				.getForEntity(new URI(xsuaaMockServerUrl + "/anyNotSupportedPath"), String.class);
+				.getForEntity(new URI(xsuaaServiceConfiguration.getUaaUrl() + "/anyNotSupportedPath"), String.class);
 	}
 
 	@Test
 	public void xsuaaMockReturnsCustomResponse() throws URISyntaxException {
 		ResponseEntity<String> response = restTemplate
-				.getForEntity(new URI(xsuaaMockServerUrl + "/customdomain/token_keys"), String.class);
+				.getForEntity(new URI(xsuaaServiceConfiguration.getUaaUrl() + "/customdomain/token_keys"), String.class);
 		Assert.assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
 		Assert.assertThat(response.getBody(), containsString("legacy-token-key-customdomain"));
 	}
diff --git a/spring-xsuaa-mock/src/test/java/com/sap/cloud/security/xsuaa/mock/autoconfiguration/XsuaaMockAutoConfigurationTest.java b/spring-xsuaa-mock/src/test/java/com/sap/cloud/security/xsuaa/mock/autoconfiguration/XsuaaMockAutoConfigurationTest.java
new file mode 100644
index 00000000..14874379
--- /dev/null
+++ b/spring-xsuaa-mock/src/test/java/com/sap/cloud/security/xsuaa/mock/autoconfiguration/XsuaaMockAutoConfigurationTest.java
@@ -0,0 +1,114 @@
+package com.sap.cloud.security.xsuaa.mock.autoconfiguration;
+
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfigurationDefault;
+import com.sap.cloud.security.xsuaa.autoconfiguration.XsuaaAutoConfiguration;
+import com.sap.cloud.security.xsuaa.mock.MockXsuaaServiceConfiguration;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.test.context.FilteredClassLoader;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.oauth2.jwt.Jwt;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = { XsuaaAutoConfiguration.class, XsuaaMockAutoConfiguration.class })
+public class XsuaaMockAutoConfigurationTest {
+
+    // create an ApplicationContextRunner that will create a context with the
+    // configuration under test.
+    private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
+            .withPropertyValues("mockxsuaaserver.url:http://localhost:12345")
+            .withConfiguration(AutoConfigurations.of(XsuaaAutoConfiguration.class, XsuaaMockAutoConfiguration.class));
+
+    @Autowired
+    private ApplicationContext context;
+
+    @Test
+    public final void autoConfigurationActive() {
+        contextRunner.run((context) -> {
+            assertThat(context.containsBean("xsuaaMockServiceConfiguration"), is(true));
+            assertThat(context.getBean("xsuaaMockServiceConfiguration"),
+                    instanceOf(MockXsuaaServiceConfiguration.class));
+            assertThat(context.getBean("xsuaaServiceConfiguration"),
+                    instanceOf(XsuaaServiceConfigurationDefault.class));
+            assertThat(context.getBean(XsuaaServiceConfiguration.class),
+                    instanceOf(MockXsuaaServiceConfiguration.class));
+        });
+    }
+
+    @Test
+    public final void autoConfigurationActiveInclProperties() {
+        contextRunner
+                .withPropertyValues("spring.xsuaa.mock.auto:true").run((context) -> {
+            assertThat(context.containsBean("xsuaaMockServiceConfiguration"), is(true));
+            assertThat(context.getBean(XsuaaServiceConfiguration.class),
+                    instanceOf(MockXsuaaServiceConfiguration.class));
+        });
+    }
+
+    @Test
+    public void autoConfigurationDisabledByProperty() {
+        contextRunner.withPropertyValues("spring.xsuaa.mock.auto:false").run((context) -> {
+            assertThat(context.containsBean("xsuaaMockServiceConfiguration"), is(false));
+            assertThat(context.getBean(XsuaaServiceConfiguration.class),
+                    instanceOf(XsuaaServiceConfigurationDefault.class));
+        });
+    }
+
+    @Test
+    public void autoConfigurationDisabledWhenNoMockWebServerRunning() {
+        ApplicationContextRunner contextRunner = new ApplicationContextRunner()
+                .withConfiguration(
+                        AutoConfigurations.of(XsuaaAutoConfiguration.class, XsuaaMockAutoConfiguration.class));
+
+        contextRunner.withPropertyValues("spring.xsuaa.mock.auto:false").run((context) -> {
+            assertThat(context.containsBean("xsuaaMockServiceConfiguration"), is(false));
+            assertThat(context.getBean(XsuaaServiceConfiguration.class),
+                    instanceOf(XsuaaServiceConfigurationDefault.class));
+        });
+    }
+
+    @Test
+    public final void autoConfigurationWithoutJwtOnClasspathInactive() {
+        contextRunner.withClassLoader(new FilteredClassLoader(Jwt.class)) // removes Jwt.class from classpath
+                .run((context) -> {
+                    assertThat(context.containsBean("xsuaaServiceConfiguration"), is(false));
+                });
+    }
+
+    @Test
+    public final void userConfigurationCanOverrideDefaultBeans() {
+        contextRunner.withUserConfiguration(UserConfiguration.class)
+                .run((context) -> {
+                    assertThat(context.containsBean("xsuaaMockServiceConfiguration"), is(false));
+                    assertThat(context.containsBean("customServiceConfiguration"), is(true));
+                    assertThat(context.getBean(XsuaaServiceConfiguration.class),
+                            instanceOf(CustomXsuaaConfiguration.class));
+                });
+    }
+
+    @Configuration
+    public static class UserConfiguration {
+
+        @Bean
+        public MockXsuaaServiceConfiguration customServiceConfiguration() {
+            return new CustomXsuaaConfiguration();
+        }
+    }
+
+    static class CustomXsuaaConfiguration extends MockXsuaaServiceConfiguration {
+
+    }
+
+}
diff --git a/spring-xsuaa-mock/src/test/resources/application-uaamock.properties b/spring-xsuaa-mock/src/test/resources/application-uaamock.properties
deleted file mode 100644
index 67c2eea6..00000000
--- a/spring-xsuaa-mock/src/test/resources/application-uaamock.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-# configures mock server that provides the public key for token validation
-# identityzoneid must be "uaa" to target the mock server
-spring.security.oauth2.resourceserver.jwt.jwk-set-uri=${mockxsuaaserver.url}/token_keys
-xsuaa.url=${mockxsuaaserver.url}
\ No newline at end of file