Commit f1026b12 authored by Dave Syer's avatar Dave Syer

Add JreProxySelector to handle global proxy configuration

The JreProxySelector is used it to adjust the repositories
as they are added to the GrapeEngine. It looks at standard
System proeprties like http.proxyHost and http.proxyPort
and in addition consults standard JRE Authenticator features
for credentials (falling back to System properties
http.proxyUser and http.proxyPassword).

Fixes gh-136
parent e28e6d95
...@@ -140,8 +140,6 @@ public class GroovyCompiler { ...@@ -140,8 +140,6 @@ public class GroovyCompiler {
RepositoryPolicy.UPDATE_POLICY_NEVER, RepositoryPolicy.UPDATE_POLICY_NEVER,
RepositoryPolicy.CHECKSUM_POLICY_IGNORE)); RepositoryPolicy.CHECKSUM_POLICY_IGNORE));
} }
builder.setProxy(AetherGrapeEngine.defaultProxy(repositoryConfiguration
.getUri().getScheme()));
repositories.add(builder.build()); repositories.add(builder.build());
} }
return repositories; return repositories;
......
...@@ -42,7 +42,7 @@ import org.eclipse.aether.impl.DefaultServiceLocator; ...@@ -42,7 +42,7 @@ import org.eclipse.aether.impl.DefaultServiceLocator;
import org.eclipse.aether.internal.impl.DefaultRepositorySystem; import org.eclipse.aether.internal.impl.DefaultRepositorySystem;
import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.LocalRepositoryManager; 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.repository.RemoteRepository;
import org.eclipse.aether.resolution.ArtifactResolutionException; import org.eclipse.aether.resolution.ArtifactResolutionException;
import org.eclipse.aether.resolution.ArtifactResult; import org.eclipse.aether.resolution.ArtifactResult;
...@@ -81,6 +81,8 @@ public class AetherGrapeEngine implements GrapeEngine { ...@@ -81,6 +81,8 @@ public class AetherGrapeEngine implements GrapeEngine {
private final List<RemoteRepository> repositories; private final List<RemoteRepository> repositories;
private ProxySelector proxySelector = new JreProxySelector();
public AetherGrapeEngine(GroovyClassLoader classLoader, public AetherGrapeEngine(GroovyClassLoader classLoader,
List<RemoteRepository> remoteRepositories) { List<RemoteRepository> remoteRepositories) {
this.classLoader = classLoader; this.classLoader = classLoader;
...@@ -90,36 +92,13 @@ public class AetherGrapeEngine implements GrapeEngine { ...@@ -90,36 +92,13 @@ public class AetherGrapeEngine implements GrapeEngine {
LocalRepositoryManager localRepositoryManager = this.repositorySystem LocalRepositoryManager localRepositoryManager = this.repositorySystem
.newLocalRepositoryManager(session, localRepository); .newLocalRepositoryManager(session, localRepository);
session.setLocalRepositoryManager(localRepositoryManager); session.setLocalRepositoryManager(localRepositoryManager);
session.setProxySelector(this.proxySelector);
this.session = session; this.session = session;
this.repositories = new ArrayList<RemoteRepository>(remoteRepositories); this.repositories = new ArrayList<RemoteRepository>();
this.progressReporter = getProgressReporter(session); for (RemoteRepository repository : remoteRepositories) {
} addRepository(repository);
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")));
}
} }
else if ("ftp".equals(protocol)) { this.progressReporter = getProgressReporter(session);
String secureProxyHost = System.getProperty("ftp.proxyHost");
if (secureProxyHost != null) {
return new Proxy("ftp", secureProxyHost, new Integer(System.getProperty(
"ftp.proxyPort", "443")));
}
}
return null;
} }
private ServiceLocator createServiceLocator() { private ServiceLocator createServiceLocator() {
...@@ -275,11 +254,17 @@ public class AetherGrapeEngine implements GrapeEngine { ...@@ -275,11 +254,17 @@ public class AetherGrapeEngine implements GrapeEngine {
String root = (String) args.get("root"); String root = (String) args.get("root");
RemoteRepository.Builder builder = new RemoteRepository.Builder(name, "default", RemoteRepository.Builder builder = new RemoteRepository.Builder(name, "default",
root); root);
String protocol = root.contains(":") ? root.substring(0, root.indexOf(":")) RemoteRepository repository = builder.build();
: "none"; addRepository(repository);
builder.setProxy(AetherGrapeEngine.defaultProxy(protocol)); }
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 @Override
......
/*
* 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<java.net.Proxy> 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<String, String> 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();
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment