diff --git a/spring-boot-cli/pom.xml b/spring-boot-cli/pom.xml
index b6ce765cb9e..0aa1b0bac80 100644
--- a/spring-boot-cli/pom.xml
+++ b/spring-boot-cli/pom.xml
@@ -67,6 +67,16 @@
org.apache.maven
maven-settings-builder
+
+ org.codehaus.plexus
+ plexus-component-api
+
+
+ *
+ *
+
+
+
org.eclipse.aether
aether-api
diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/SettingsXmlRepositorySystemSessionAutoConfiguration.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/SettingsXmlRepositorySystemSessionAutoConfiguration.java
index 1f79b5cf43c..62a25b30ffb 100644
--- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/SettingsXmlRepositorySystemSessionAutoConfiguration.java
+++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/SettingsXmlRepositorySystemSessionAutoConfiguration.java
@@ -17,6 +17,8 @@
package org.springframework.boot.cli.compiler.grape;
import java.io.File;
+import java.lang.reflect.Field;
+import java.util.List;
import org.apache.maven.settings.Mirror;
import org.apache.maven.settings.Proxy;
@@ -26,6 +28,10 @@ import org.apache.maven.settings.building.DefaultSettingsBuilderFactory;
import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;
import org.apache.maven.settings.building.SettingsBuildingException;
import org.apache.maven.settings.building.SettingsBuildingRequest;
+import org.apache.maven.settings.crypto.DefaultSettingsDecrypter;
+import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
+import org.apache.maven.settings.crypto.SettingsDecrypter;
+import org.apache.maven.settings.crypto.SettingsDecryptionResult;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.repository.Authentication;
@@ -38,6 +44,9 @@ import org.eclipse.aether.util.repository.ConservativeAuthenticationSelector;
import org.eclipse.aether.util.repository.DefaultAuthenticationSelector;
import org.eclipse.aether.util.repository.DefaultMirrorSelector;
import org.eclipse.aether.util.repository.DefaultProxySelector;
+import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
+import org.sonatype.plexus.components.cipher.PlexusCipherException;
+import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
/**
* Auto-configuration for a RepositorySystemSession that uses Maven's settings.xml to
@@ -48,18 +57,34 @@ import org.eclipse.aether.util.repository.DefaultProxySelector;
public class SettingsXmlRepositorySystemSessionAutoConfiguration implements
RepositorySystemSessionAutoConfiguration {
- private static final String HOME_DIR = System.getProperty("user.home");
+ private static final String DEFAULT_HOME_DIR = System.getProperty("user.home");
+
+ private final String homeDir;
+
+ public SettingsXmlRepositorySystemSessionAutoConfiguration() {
+ this(DEFAULT_HOME_DIR);
+ }
+
+ SettingsXmlRepositorySystemSessionAutoConfiguration(String homeDir) {
+ this.homeDir = homeDir;
+ }
@Override
public void apply(DefaultRepositorySystemSession session,
RepositorySystem repositorySystem) {
Settings settings = loadSettings();
+ SettingsDecryptionResult decryptionResult = decryptSettings(settings);
+ if (!decryptionResult.getProblems().isEmpty()) {
+ throw new IllegalStateException("Settings decryption failed: "
+ + decryptionResult.getProblems());
+ }
session.setOffline(settings.isOffline());
session.setMirrorSelector(createMirrorSelector(settings));
- session.setAuthenticationSelector(createAuthenticationSelector(settings));
- session.setProxySelector(createProxySelector(settings));
+ session.setAuthenticationSelector(createAuthenticationSelector(decryptionResult
+ .getServers()));
+ session.setProxySelector(createProxySelector(decryptionResult.getProxies()));
String localRepository = settings.getLocalRepository();
if (localRepository != null) {
@@ -69,7 +94,7 @@ public class SettingsXmlRepositorySystemSessionAutoConfiguration implements
}
private Settings loadSettings() {
- File settingsFile = new File(HOME_DIR, ".m2/settings.xml");
+ File settingsFile = new File(this.homeDir, ".m2/settings.xml");
SettingsBuildingRequest request = new DefaultSettingsBuildingRequest();
request.setUserSettingsFile(settingsFile);
try {
@@ -82,6 +107,32 @@ public class SettingsXmlRepositorySystemSessionAutoConfiguration implements
}
}
+ private SettingsDecryptionResult decryptSettings(Settings settings) {
+ DefaultSettingsDecryptionRequest request = new DefaultSettingsDecryptionRequest(
+ settings);
+
+ return createSettingsDecrypter().decrypt(request);
+ }
+
+ private SettingsDecrypter createSettingsDecrypter() {
+ SettingsDecrypter settingsDecrypter = new DefaultSettingsDecrypter();
+ setField(DefaultSettingsDecrypter.class, "securityDispatcher", settingsDecrypter,
+ new SpringBootSecDispatcher());
+ return settingsDecrypter;
+ }
+
+ private void setField(Class> clazz, String fieldName, Object target, Object value) {
+ try {
+ Field field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ field.set(target, value);
+ }
+ catch (Exception e) {
+ throw new IllegalStateException("Failed to set field '" + fieldName
+ + "' on '" + target + "'", e);
+ }
+ }
+
private MirrorSelector createMirrorSelector(Settings settings) {
DefaultMirrorSelector selector = new DefaultMirrorSelector();
for (Mirror mirror : settings.getMirrors()) {
@@ -91,9 +142,9 @@ public class SettingsXmlRepositorySystemSessionAutoConfiguration implements
return selector;
}
- private AuthenticationSelector createAuthenticationSelector(Settings settings) {
+ private AuthenticationSelector createAuthenticationSelector(List servers) {
DefaultAuthenticationSelector selector = new DefaultAuthenticationSelector();
- for (Server server : settings.getServers()) {
+ for (Server server : servers) {
AuthenticationBuilder auth = new AuthenticationBuilder();
auth.addUsername(server.getUsername()).addPassword(server.getPassword());
auth.addPrivateKey(server.getPrivateKey(), server.getPassphrase());
@@ -102,9 +153,9 @@ public class SettingsXmlRepositorySystemSessionAutoConfiguration implements
return new ConservativeAuthenticationSelector(selector);
}
- private ProxySelector createProxySelector(Settings settings) {
+ private ProxySelector createProxySelector(List proxies) {
DefaultProxySelector selector = new DefaultProxySelector();
- for (Proxy proxy : settings.getProxies()) {
+ for (Proxy proxy : proxies) {
Authentication authentication = new AuthenticationBuilder()
.addUsername(proxy.getUsername()).addPassword(proxy.getPassword())
.build();
@@ -114,4 +165,19 @@ public class SettingsXmlRepositorySystemSessionAutoConfiguration implements
}
return selector;
}
+
+ private class SpringBootSecDispatcher extends DefaultSecDispatcher {
+
+ public SpringBootSecDispatcher() {
+ this._configurationFile = new File(
+ SettingsXmlRepositorySystemSessionAutoConfiguration.this.homeDir,
+ ".m2/settings-security.xml").getAbsolutePath();
+ try {
+ this._cipher = new DefaultPlexusCipher();
+ }
+ catch (PlexusCipherException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
}
diff --git a/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/SettingsXmlRepositorySystemSessionAutoConfigurationTests.java b/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/SettingsXmlRepositorySystemSessionAutoConfigurationTests.java
index 19c48334e1e..123f81bb486 100644
--- a/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/SettingsXmlRepositorySystemSessionAutoConfigurationTests.java
+++ b/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/SettingsXmlRepositorySystemSessionAutoConfigurationTests.java
@@ -20,7 +20,11 @@ import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.apache.maven.settings.building.SettingsBuildingException;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.repository.Authentication;
+import org.eclipse.aether.repository.AuthenticationContext;
import org.eclipse.aether.repository.LocalRepositoryManager;
+import org.eclipse.aether.repository.Proxy;
+import org.eclipse.aether.repository.RemoteRepository;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -28,6 +32,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
@@ -49,12 +54,60 @@ public class SettingsXmlRepositorySystemSessionAutoConfigurationTests {
@Test
public void basicSessionCustomization() throws SettingsBuildingException {
+ assertSessionCustomization("src/test/resources/maven-settings/basic");
+ }
+
+ @Test
+ public void encryptedSettingsSessionCustomization() throws SettingsBuildingException {
+ assertSessionCustomization("src/test/resources/maven-settings/encrypted");
+ }
+
+ private void assertSessionCustomization(String userHome) {
DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
- new SettingsXmlRepositorySystemSessionAutoConfiguration().apply(session,
+ new SettingsXmlRepositorySystemSessionAutoConfiguration(userHome).apply(session,
this.repositorySystem);
- assertNotNull(session.getMirrorSelector());
- assertNotNull(session.getProxySelector());
+ RemoteRepository repository = new RemoteRepository.Builder("my-server",
+ "default", "http://maven.example.com").build();
+
+ assertMirrorSelectorConfiguration(session, repository);
+ assertProxySelectorConfiguration(session, repository);
+ assertAuthenticationSelectorConfiguration(session, repository);
+ }
+
+ private void assertProxySelectorConfiguration(DefaultRepositorySystemSession session,
+ RemoteRepository repository) {
+ Proxy proxy = session.getProxySelector().getProxy(repository);
+ repository = new RemoteRepository.Builder(repository).setProxy(proxy).build();
+ AuthenticationContext authenticationContext = AuthenticationContext.forProxy(
+ session, repository);
+ assertEquals("proxy.example.com", proxy.getHost());
+ assertEquals("proxyuser",
+ authenticationContext.get(AuthenticationContext.USERNAME));
+ assertEquals("somepassword",
+ authenticationContext.get(AuthenticationContext.PASSWORD));
+ }
+
+ private void assertMirrorSelectorConfiguration(
+ DefaultRepositorySystemSession session, RemoteRepository repository) {
+ RemoteRepository mirror = session.getMirrorSelector().getMirror(repository);
+ assertNotNull("No mirror configured for repository " + repository.getId(), mirror);
+ assertEquals("maven.example.com", mirror.getHost());
+ }
+
+ private void assertAuthenticationSelectorConfiguration(
+ DefaultRepositorySystemSession session, RemoteRepository repository) {
+ Authentication authentication = session.getAuthenticationSelector()
+ .getAuthentication(repository);
+
+ repository = new RemoteRepository.Builder(repository).setAuthentication(
+ authentication).build();
+
+ AuthenticationContext authenticationContext = AuthenticationContext
+ .forRepository(session, repository);
+
+ assertEquals("tester", authenticationContext.get(AuthenticationContext.USERNAME));
+ assertEquals("secret", authenticationContext.get(AuthenticationContext.PASSWORD));
}
}
diff --git a/spring-boot-cli/src/test/resources/maven-settings/basic/.m2/settings.xml b/spring-boot-cli/src/test/resources/maven-settings/basic/.m2/settings.xml
new file mode 100644
index 00000000000..b2b97db3302
--- /dev/null
+++ b/spring-boot-cli/src/test/resources/maven-settings/basic/.m2/settings.xml
@@ -0,0 +1,31 @@
+
+
+
+
+ my-mirror
+ http://maven.example.com/mirror
+ my-server
+
+
+
+
+
+ my-server
+ tester
+ secret
+
+
+
+
+
+ my-proxy
+ true
+ http
+ proxy.example.com
+ 8080
+ proxyuser
+ somepassword
+
+
+
+
\ No newline at end of file
diff --git a/spring-boot-cli/src/test/resources/maven-settings/encrypted/.m2/settings-security.xml b/spring-boot-cli/src/test/resources/maven-settings/encrypted/.m2/settings-security.xml
new file mode 100644
index 00000000000..7b6597c44e9
--- /dev/null
+++ b/spring-boot-cli/src/test/resources/maven-settings/encrypted/.m2/settings-security.xml
@@ -0,0 +1,3 @@
+
+ {oAyWuFO63U8HHgiplpqtgXih0/pwcRA0d+uA+Z7TBEk=}
+
\ No newline at end of file
diff --git a/spring-boot-cli/src/test/resources/maven-settings/encrypted/.m2/settings.xml b/spring-boot-cli/src/test/resources/maven-settings/encrypted/.m2/settings.xml
new file mode 100644
index 00000000000..b8701c783a1
--- /dev/null
+++ b/spring-boot-cli/src/test/resources/maven-settings/encrypted/.m2/settings.xml
@@ -0,0 +1,31 @@
+
+
+
+
+ my-mirror
+ http://maven.example.com/mirror
+ my-server
+
+
+
+
+
+ my-server
+ tester
+ {Ur5BpeQGlYUHhXsHahO/HbMBcPSFSUtN5gbWuFFPYGw=}
+
+
+
+
+
+ my-proxy
+ true
+ http
+ proxy.example.com
+ 8080
+ proxyuser
+ {3iRQQyaIUgQHwH8uzTvr9/52pZAjLOTWz/SlWDB7CM4=}
+
+
+
+
\ No newline at end of file
diff --git a/spring-boot-parent/pom.xml b/spring-boot-parent/pom.xml
index 2c581b6bdf7..afbb5bf3cc7 100644
--- a/spring-boot-parent/pom.xml
+++ b/spring-boot-parent/pom.xml
@@ -98,6 +98,11 @@
plexus-archiver
2.4.4
+
+ org.codehaus.plexus
+ plexus-component-api
+ 1.0-alpha-33
+
org.codehaus.plexus
plexus-utils