diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompiler.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompiler.java index af75f3e9aa8..fa394e2c104 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompiler.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompiler.java @@ -140,8 +140,6 @@ public class GroovyCompiler { RepositoryPolicy.UPDATE_POLICY_NEVER, RepositoryPolicy.CHECKSUM_POLICY_IGNORE)); } - builder.setProxy(AetherGrapeEngine.defaultProxy(repositoryConfiguration - .getUri().getScheme())); repositories.add(builder.build()); } return repositories; diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngine.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngine.java index d9afbd6967b..a137359892c 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngine.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngine.java @@ -42,7 +42,7 @@ import org.eclipse.aether.impl.DefaultServiceLocator; import org.eclipse.aether.internal.impl.DefaultRepositorySystem; import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.repository.LocalRepositoryManager; -import org.eclipse.aether.repository.Proxy; +import org.eclipse.aether.repository.ProxySelector; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.resolution.ArtifactResolutionException; import org.eclipse.aether.resolution.ArtifactResult; @@ -81,6 +81,8 @@ public class AetherGrapeEngine implements GrapeEngine { private final List repositories; + private ProxySelector proxySelector = new JreProxySelector(); + public AetherGrapeEngine(GroovyClassLoader classLoader, List remoteRepositories) { this.classLoader = classLoader; @@ -90,36 +92,13 @@ public class AetherGrapeEngine implements GrapeEngine { LocalRepositoryManager localRepositoryManager = this.repositorySystem .newLocalRepositoryManager(session, localRepository); session.setLocalRepositoryManager(localRepositoryManager); + session.setProxySelector(this.proxySelector); this.session = session; - this.repositories = new ArrayList(remoteRepositories); - this.progressReporter = getProgressReporter(session); - } - - public static Proxy defaultProxy(String protocol) { - // TODO: proxy authentication - if ("http".equals(protocol) || "dav".equals(protocol)) { - String proxyHost = System.getProperty("http.proxyHost"); - if (proxyHost != null) { - // Use defaults from normal JVM proxy handler - return new Proxy("http", proxyHost, new Integer(System.getProperty( - "http.proxyPort", "80"))); - } - } - else if ("https".equals(protocol) || "davs".equals(protocol)) { - String secureProxyHost = System.getProperty("https.proxyHost"); - if (secureProxyHost != null) { - return new Proxy("https", secureProxyHost, new Integer( - System.getProperty("https.proxyPort", "443"))); - } + this.repositories = new ArrayList(); + for (RemoteRepository repository : remoteRepositories) { + addRepository(repository); } - else if ("ftp".equals(protocol)) { - String secureProxyHost = System.getProperty("ftp.proxyHost"); - if (secureProxyHost != null) { - return new Proxy("ftp", secureProxyHost, new Integer(System.getProperty( - "ftp.proxyPort", "443"))); - } - } - return null; + this.progressReporter = getProgressReporter(session); } private ServiceLocator createServiceLocator() { @@ -275,11 +254,17 @@ public class AetherGrapeEngine implements GrapeEngine { String root = (String) args.get("root"); RemoteRepository.Builder builder = new RemoteRepository.Builder(name, "default", root); - String protocol = root.contains(":") ? root.substring(0, root.indexOf(":")) - : "none"; - builder.setProxy(AetherGrapeEngine.defaultProxy(protocol)); + RemoteRepository repository = builder.build(); + addRepository(repository); + } - this.repositories.add(builder.build()); + protected void addRepository(RemoteRepository repository) { + if (repository.getProxy() == null) { + RemoteRepository.Builder builder = new RemoteRepository.Builder(repository); + builder.setProxy(this.proxySelector.getProxy(repository)); + repository = builder.build(); + } + this.repositories.add(repository); } @Override diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/JreProxySelector.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/JreProxySelector.java new file mode 100644 index 00000000000..e52d5fdfeae --- /dev/null +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/JreProxySelector.java @@ -0,0 +1,157 @@ +/* + * Copyright 2012-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.cli.compiler.grape; + +import java.net.Authenticator; +import java.net.InetSocketAddress; +import java.net.PasswordAuthentication; +import java.net.SocketAddress; +import java.net.URI; +import java.net.URL; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.eclipse.aether.repository.Authentication; +import org.eclipse.aether.repository.AuthenticationContext; +import org.eclipse.aether.repository.AuthenticationDigest; +import org.eclipse.aether.repository.Proxy; +import org.eclipse.aether.repository.ProxySelector; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * (Copied from aether source code - not available yet in Maven repo.) + * + * @author dsyer + */ +public final class JreProxySelector implements ProxySelector { + + /** + * Creates a new proxy selector that delegates to + * {@link java.net.ProxySelector#getDefault()}. + */ + public JreProxySelector() { + } + + public Proxy getProxy(RemoteRepository repository) { + List proxies = null; + try { + URI uri = new URI(repository.getUrl()).parseServerAuthority(); + proxies = java.net.ProxySelector.getDefault().select(uri); + } + catch (Exception e) { + // URL invalid or not accepted by selector or no selector at all, simply use + // no proxy + } + if (proxies != null) { + for (java.net.Proxy proxy : proxies) { + if (java.net.Proxy.Type.DIRECT.equals(proxy.type())) { + break; + } + if (java.net.Proxy.Type.HTTP.equals(proxy.type()) + && isValid(proxy.address())) { + InetSocketAddress addr = (InetSocketAddress) proxy.address(); + return new Proxy(Proxy.TYPE_HTTP, addr.getHostName(), addr.getPort(), + JreProxyAuthentication.INSTANCE); + } + } + } + return null; + } + + private static boolean isValid(SocketAddress address) { + if (address instanceof InetSocketAddress) { + /* + * NOTE: On some platforms with java.net.useSystemProxies=true, unconfigured + * proxies show up as proxy objects with empty host and port 0. + */ + InetSocketAddress addr = (InetSocketAddress) address; + if (addr.getPort() <= 0) { + return false; + } + if (addr.getHostName() == null || addr.getHostName().length() <= 0) { + return false; + } + return true; + } + return false; + } + + private static final class JreProxyAuthentication implements Authentication { + + public static final Authentication INSTANCE = new JreProxyAuthentication(); + + public void fill(AuthenticationContext context, String key, + Map data) { + Proxy proxy = context.getProxy(); + if (proxy == null) { + return; + } + if (!AuthenticationContext.USERNAME.equals(key) + && !AuthenticationContext.PASSWORD.equals(key)) { + return; + } + + try { + URL url; + try { + url = new URL(context.getRepository().getUrl()); + } + catch (Exception e) { + url = null; + } + + PasswordAuthentication auth = Authenticator + .requestPasswordAuthentication(proxy.getHost(), null, + proxy.getPort(), "http", + "Credentials for proxy " + proxy, null, url, + Authenticator.RequestorType.PROXY); + if (auth != null) { + context.put(AuthenticationContext.USERNAME, auth.getUserName()); + context.put(AuthenticationContext.PASSWORD, auth.getPassword()); + } + else { + context.put(AuthenticationContext.USERNAME, + System.getProperty("http.proxyUser")); + context.put(AuthenticationContext.PASSWORD, + System.getProperty("http.proxyPassword")); + } + } + catch (SecurityException e) { + // oh well, let's hope the proxy can do without auth + } + } + + public void digest(AuthenticationDigest digest) { + // we don't know anything about the JRE's current authenticator, assume the + // worst (i.e. interactive) + digest.update(UUID.randomUUID().toString()); + } + + @Override + public boolean equals(Object obj) { + return this == obj || (obj != null && getClass().equals(obj.getClass())); + } + + @Override + public int hashCode() { + return getClass().hashCode(); + } + + } + +}