This is an automated email from the ASF dual-hosted git repository. heneveld pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git
commit 21da50685935380be46a6819c0441f97b879a752 Author: Alex Heneveld <[email protected]> AuthorDate: Fri Jul 29 14:26:13 2022 +0100 allow use of trust all to be configured via brooklyn properties and entity config see BrooklynHttpConfig --- .../catalog/internal/BasicBrooklynCatalog.java | 2 +- .../PropertiesFileExternalConfigSupplier.java | 4 +- .../vault/VaultExternalConfigSupplier.java | 3 +- .../core/effector/http/HttpCommandEffector.java | 54 +++---- .../core/location/LocationConfigUtils.java | 35 +++-- .../mgmt/ha/BrooklynBomOsgiArchiveInstaller.java | 2 +- .../org/apache/brooklyn/feed/http/HttpFeed.java | 60 +++----- .../brooklyn/location/ssh/SshMachineLocation.java | 2 +- .../apache/brooklyn/util/core/ResourceUtils.java | 38 ++++- .../util/core/javalang/BrooklynHttpConfig.java | 155 +++++++++++++++++++++ .../brooklyn/util/core/osgi/BundleMaker.java | 2 +- .../util/core/task/ssh/SshPutTaskFactory.java | 7 + .../util/executor/HttpExecutorFactoryImpl.java | 10 +- .../brooklyn/util/core/ResourceUtilsTest.java | 2 +- .../location/jclouds/CreateUserStatements.java | 3 +- .../brooklyn/location/jclouds/JcloudsLocation.java | 6 +- .../jclouds/JcloudsSshMachineLocation.java | 3 +- .../entity/brooklynnode/DeployBlueprintTest.java | 4 +- .../brooklyn/rest/BrooklynRestApiLauncherTest.java | 2 +- .../entity/brooklynnode/EntityHttpClientImpl.java | 6 +- .../brooklynnode/BrooklynNodeIntegrationTest.java | 23 ++- .../org/apache/brooklyn/test/HttpTestUtils.java | 138 +++++------------- .../org/apache/brooklyn/test/WebAppMonitor.java | 3 +- .../org/apache/brooklyn/util/http/HttpAsserts.java | 16 +-- .../org/apache/brooklyn/util/http/HttpTool.java | 50 ++++--- .../util/http/TrustingSslSocketFactory.java | 6 +- .../executor/apacheclient/HttpExecutorImpl.java | 7 + .../brooklyn/util/jmx/jmxmp/JmxmpClient.java | 11 +- 28 files changed, 394 insertions(+), 260 deletions(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java index 8e742eb6cf..b8d37a3257 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java @@ -1233,7 +1233,7 @@ public class BasicBrooklynCatalog implements BrooklynCatalog { // org.reflections requires the URL to be "file:" containg ".jar" File fJar = Os.newTempFile(containingBundle.getVersionedName().toOsgiString(), ".jar"); try { - Streams.copy(ResourceUtils.create().getResourceFromUrl(url), new FileOutputStream(fJar)); + Streams.copy(ResourceUtils.create(mgmt).getResourceFromUrl(url), new FileOutputStream(fJar)); subCatalog.addToClasspath(new String[] { "file:"+fJar.getAbsolutePath() }); Collection<CatalogItemDtoAbstract<?, ?>> result = scanAnnotationsInternal(mgmt, subCatalog, MutableMap.of("version", containingBundle.getSuppliedVersionString()), containingBundle); return result; diff --git a/core/src/main/java/org/apache/brooklyn/core/config/external/PropertiesFileExternalConfigSupplier.java b/core/src/main/java/org/apache/brooklyn/core/config/external/PropertiesFileExternalConfigSupplier.java index e9db17ea5b..eb640bcf34 100644 --- a/core/src/main/java/org/apache/brooklyn/core/config/external/PropertiesFileExternalConfigSupplier.java +++ b/core/src/main/java/org/apache/brooklyn/core/config/external/PropertiesFileExternalConfigSupplier.java @@ -54,10 +54,10 @@ public class PropertiesFileExternalConfigSupplier extends AbstractExternalConfig return properties.getProperty(key); } - private static Properties loadProperties(String propertiesUrl) throws IOException { + private Properties loadProperties(String propertiesUrl) throws IOException { InputStream is = null; try { - is = ResourceUtils.create().getResourceFromUrl(propertiesUrl); + is = ResourceUtils.create(getManagementContext()).getResourceFromUrl(propertiesUrl); Properties p = new Properties(); p.load(is); return p; diff --git a/core/src/main/java/org/apache/brooklyn/core/config/external/vault/VaultExternalConfigSupplier.java b/core/src/main/java/org/apache/brooklyn/core/config/external/vault/VaultExternalConfigSupplier.java index 2a976f10ed..28f9c84362 100644 --- a/core/src/main/java/org/apache/brooklyn/core/config/external/vault/VaultExternalConfigSupplier.java +++ b/core/src/main/java/org/apache/brooklyn/core/config/external/vault/VaultExternalConfigSupplier.java @@ -29,6 +29,7 @@ import com.google.gson.JsonObject; import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.core.config.external.AbstractExternalConfigSupplier; import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.core.javalang.BrooklynHttpConfig; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.http.HttpTool; import org.apache.brooklyn.util.http.HttpToolResponse; @@ -69,7 +70,7 @@ public abstract class VaultExternalConfigSupplier extends AbstractExternalConfig super(managementContext, name); this.config = config; this.name = name; - httpClient = HttpTool.httpClientBuilder().build(); + httpClient = BrooklynHttpConfig.httpClientBuilder(managementContext, true).build(); gson = new GsonBuilder().create(); List<String> errors = Lists.newArrayListWithCapacity(2); diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java b/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java index 6a3fddfe11..ea21e2ca5f 100644 --- a/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java +++ b/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java @@ -18,21 +18,14 @@ */ package org.apache.brooklyn.core.effector.http; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.Map; -import java.util.concurrent.Callable; - +import com.google.common.annotations.Beta; +import com.google.common.base.Enums; +import com.google.common.base.Joiner; +import com.google.common.base.Optional; +import com.google.common.base.Throwables; +import com.google.common.io.ByteStreams; +import com.google.common.net.HttpHeaders; +import com.jayway.jsonpath.JsonPath; import org.apache.brooklyn.api.effector.Effector; import org.apache.brooklyn.api.mgmt.Task; import org.apache.brooklyn.config.ConfigKey; @@ -45,26 +38,27 @@ import org.apache.brooklyn.core.entity.EntityInitializers; import org.apache.brooklyn.core.sensor.Sensors; import org.apache.brooklyn.util.collections.Jsonya; import org.apache.brooklyn.util.core.config.ConfigBag; +import org.apache.brooklyn.util.core.javalang.BrooklynHttpConfig; import org.apache.brooklyn.util.core.task.Tasks; import org.apache.brooklyn.util.exceptions.Exceptions; -import org.apache.brooklyn.util.http.executor.HttpConfig; +import org.apache.brooklyn.util.http.auth.UsernamePassword; import org.apache.brooklyn.util.http.executor.HttpExecutor; import org.apache.brooklyn.util.http.executor.HttpRequest; import org.apache.brooklyn.util.http.executor.HttpResponse; -import org.apache.brooklyn.util.http.auth.UsernamePassword; -import org.apache.brooklyn.util.http.executor.apacheclient.HttpExecutorImpl; import org.apache.brooklyn.util.text.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.annotations.Beta; -import com.google.common.base.Enums; -import com.google.common.base.Joiner; -import com.google.common.base.Optional; -import com.google.common.base.Throwables; -import com.google.common.io.ByteStreams; -import com.google.common.net.HttpHeaders; -import com.jayway.jsonpath.JsonPath; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.concurrent.Callable; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; /** * An {@link Effector} to invoke REST endpoints. @@ -141,7 +135,7 @@ public final class HttpCommandEffector extends AddEffectorInitializerAbstract { if(!Strings.isEmpty(jsonPath) && !pathsAndSensors.isEmpty()) { throw new IllegalArgumentException("Both jsonPath and pathsAndSensors are defined, please pick just one to resolve the ambiguity"); } - final HttpExecutor httpExecutor = HttpExecutorImpl.newInstance(); + final HttpExecutor httpExecutor = BrooklynHttpConfig.newHttpExecutor(entity()); final HttpRequest request = buildHttpRequest(httpVerb, uri, headers, httpUsername, httpPassword, payload); Task t = Tasks.builder().displayName(effector.getName()).body(new Callable<Object>() { @@ -205,11 +199,7 @@ public final class HttpCommandEffector extends AddEffectorInitializerAbstract { HttpRequest.Builder httpRequestBuilder = new HttpRequest.Builder() .uri(uri) .method(httpVerb) - .config(HttpConfig.builder() - .trustSelfSigned(true) - .trustAll(true) - .laxRedirect(true) - .build()); + .config(BrooklynHttpConfig.httpConfigBuilder(entity()).build()); if (headers != null) { httpRequestBuilder.headers(headers); diff --git a/core/src/main/java/org/apache/brooklyn/core/location/LocationConfigUtils.java b/core/src/main/java/org/apache/brooklyn/core/location/LocationConfigUtils.java index 73607af8cc..3011d8baf0 100644 --- a/core/src/main/java/org/apache/brooklyn/core/location/LocationConfigUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/location/LocationConfigUtils.java @@ -63,12 +63,18 @@ public class LocationConfigUtils { * {@link LocationConfigKeys#PRIVATE_KEY_DATA} and {@link LocationConfigKeys#PRIVATE_KEY_FILE} * (defaulting to the private key file + ".pub"). **/ + public static OsCredential getOsCredential(ConfigBag config, ResourceUtils ru) { + return OsCredential.newInstance(config).withResourceUtils(ru); + } + + @Deprecated /** @deprecated since 1.1, pass a ResourceUtils for external lookup */ + // only used in tests public static OsCredential getOsCredential(ConfigBag config) { return OsCredential.newInstance(config); } /** Convenience class for holding private/public keys and passwords, inferring from config keys. - * See {@link LocationConfigUtils#getOsCredential(ConfigBag)}. */ + * See {@link LocationConfigUtils#getOsCredential(ConfigBag, ResourceUtils)}. */ @Beta // would be nice to replace with a builder pattern public static class OsCredential { private final ConfigBag config; @@ -84,11 +90,17 @@ public class LocationConfigUtils { private String privateKeyData; private String publicKeyData; private String password; + private ResourceUtils resourceUtils; private OsCredential(ConfigBag config) { this.config = config; } + public OsCredential withResourceUtils(ResourceUtils ru) { + this.resourceUtils = ru; + return this; + } + /** throws if there are any problems */ public OsCredential checkNotEmpty() { checkNoErrors(); @@ -200,7 +212,12 @@ public class LocationConfigUtils { public static OsCredential newInstance(ConfigBag config) { return new OsCredential(config); } - + + private ResourceUtils getResourceUtils() { + if (resourceUtils==null) resourceUtils = ResourceUtils.create("OsCredentials-uninitialized"); //shouldn't be used + return resourceUtils; + } + private synchronized void infer() { if (!dirty) return; warningMessages.clear(); @@ -208,7 +225,7 @@ public class LocationConfigUtils { log.debug("Inferring OS credentials"); privateKeyData = config.get(LocationConfigKeys.PRIVATE_KEY_DATA); password = config.get(LocationConfigKeys.PASSWORD); - publicKeyData = getKeyDataFromDataKeyOrFileKey(config, LocationConfigKeys.PUBLIC_KEY_DATA, LocationConfigKeys.PUBLIC_KEY_FILE); + publicKeyData = getKeyDataFromDataKeyOrFileKey(config, LocationConfigKeys.PUBLIC_KEY_DATA, LocationConfigKeys.PUBLIC_KEY_FILE, getResourceUtils()); KeyPair privateKey = null; @@ -228,7 +245,7 @@ public class LocationConfigUtils { // not real important, but we get it for free if "files" is a list instead. // using ResourceUtils is useful for classpath resources if (file!=null) - privateKeyData = ResourceUtils.create().getResourceAsString(file); + privateKeyData = getResourceUtils().getResourceAsString(file); // else use data already set privateKey = getValidatedPrivateKey(file); @@ -241,7 +258,7 @@ public class LocationConfigUtils { } else { String publicKeyFile = (file!=null ? file+".pub" : "(data)"); try { - publicKeyData = ResourceUtils.create().getResourceAsString(publicKeyFile); + publicKeyData = getResourceUtils().getResourceAsString(publicKeyFile); log.debug("Loaded private key data from "+file+ " and public key data from "+publicKeyFile); @@ -363,7 +380,7 @@ public class LocationConfigUtils { } } - private static String getKeyDataFromDataKeyOrFileKey(ConfigBag config, ConfigKey<String> dataKey, ConfigKey<String> fileKey) { + private static String getKeyDataFromDataKeyOrFileKey(ConfigBag config, ConfigKey<String> dataKey, ConfigKey<String> fileKey, ResourceUtils ru) { boolean unused = config.isUnused(dataKey); String data = config.get(dataKey); if (Strings.isNonBlank(data) && !unused) { @@ -374,7 +391,7 @@ public class LocationConfigUtils { if (groovyTruth(file)) { List<String> files = Arrays.asList(file.split(File.pathSeparator)); List<String> filesTidied = tidyFilePaths(files); - String fileData = getFileContents(filesTidied); + String fileData = getFileContents(filesTidied, ru); if (fileData == null) { log.warn("Invalid file" + (files.size() > 1 ? "s" : "") + " for " + fileKey + " (given " + files + (files.equals(filesTidied) ? "" : "; converted to " + filesTidied) + ") " + @@ -398,14 +415,14 @@ public class LocationConfigUtils { * * @param files list of file paths */ - private static String getFileContents(Iterable<String> files) { + private static String getFileContents(Iterable<String> files, ResourceUtils ru) { Iterator<String> fi = files.iterator(); while (fi.hasNext()) { String file = fi.next(); if (groovyTruth(file)) { try { // see comment above - String result = ResourceUtils.create().getResourceAsString(file); + String result = ru.getResourceAsString(file); if (result!=null) return result; log.debug("Invalid file "+file+" ; " + (!fi.hasNext() ? "no more files to try" : "trying next file")+" (null)"); } catch (Exception e) { diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/BrooklynBomOsgiArchiveInstaller.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/BrooklynBomOsgiArchiveInstaller.java index fc1440738d..bccc8d0d50 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/BrooklynBomOsgiArchiveInstaller.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/BrooklynBomOsgiArchiveInstaller.java @@ -330,7 +330,7 @@ public class BrooklynBomOsgiArchiveInstaller { // get a handle on the zip file (although we could skip if not doing persistence - but that feels even worse than this!) try { url = Strings.removeFromStart(url, "system:"); - File zipTemp = new BundleMaker(ResourceUtils.create()).createJarFromClasspathDir(url); + File zipTemp = new BundleMaker(ResourceUtils.create(mgmt)).createJarFromClasspathDir(url); zipIn = new FileInputStream(zipTemp); } catch (FileNotFoundException e) { throw Exceptions.propagate(e); diff --git a/core/src/main/java/org/apache/brooklyn/feed/http/HttpFeed.java b/core/src/main/java/org/apache/brooklyn/feed/http/HttpFeed.java index c1897173a2..2f0247bc8b 100644 --- a/core/src/main/java/org/apache/brooklyn/feed/http/HttpFeed.java +++ b/core/src/main/java/org/apache/brooklyn/feed/http/HttpFeed.java @@ -18,20 +18,11 @@ */ package org.apache.brooklyn.feed.http; -import static com.google.common.base.Preconditions.checkNotNull; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.net.URI; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeUnit; - +import com.google.common.base.*; +import com.google.common.collect.*; +import com.google.common.io.BaseEncoding; +import com.google.common.io.ByteStreams; +import com.google.common.reflect.TypeToken; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.EntityLocal; import org.apache.brooklyn.api.location.Location; @@ -46,15 +37,14 @@ import org.apache.brooklyn.core.feed.Poller; import org.apache.brooklyn.core.location.Locations; import org.apache.brooklyn.core.location.Machines; import org.apache.brooklyn.core.location.internal.LocationInternal; +import org.apache.brooklyn.util.core.javalang.BrooklynHttpConfig; import org.apache.brooklyn.util.executor.HttpExecutorFactory; import org.apache.brooklyn.util.guava.Maybe; import org.apache.brooklyn.util.http.HttpToolResponse; -import org.apache.brooklyn.util.http.executor.HttpConfig; +import org.apache.brooklyn.util.http.auth.UsernamePassword; import org.apache.brooklyn.util.http.executor.HttpExecutor; import org.apache.brooklyn.util.http.executor.HttpRequest; import org.apache.brooklyn.util.http.executor.HttpResponse; -import org.apache.brooklyn.util.http.auth.UsernamePassword; -import org.apache.brooklyn.util.http.executor.apacheclient.HttpExecutorImpl; import org.apache.brooklyn.util.stream.Streams; import org.apache.brooklyn.util.time.Duration; import org.apache.http.auth.Credentials; @@ -62,20 +52,19 @@ import org.apache.http.auth.UsernamePasswordCredentials; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Objects; -import com.google.common.base.Optional; -import com.google.common.base.Supplier; -import com.google.common.base.Suppliers; -import com.google.common.base.Throwables; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.SetMultimap; -import com.google.common.collect.Sets; -import com.google.common.io.BaseEncoding; -import com.google.common.io.ByteStreams; -import com.google.common.reflect.TypeToken; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; + +import static com.google.common.base.Preconditions.checkNotNull; /** * Provides a feed of attribute values, by polling over http. @@ -346,7 +335,8 @@ public class HttpFeed extends AbstractFeed { Map<String, Object> httpExecutorProps = ((LocationInternal)location.get()).config().getBag().getAllConfig(); httpExecutor = httpExecutorFactory.getHttpExecutor(httpExecutorProps); } else { - httpExecutor = HttpExecutorImpl.newInstance(); + httpExecutor = BrooklynHttpConfig.newHttpExecutor( + Preconditions.checkNotNull(location.isPresent() ? location.get() : builder.entity, "feed requires a location or entity") ); } } @@ -423,11 +413,7 @@ public class HttpFeed extends AbstractFeed { .credentials(creds) .method(pollInfo.method) .body(pollInfo.body) - .config(HttpConfig.builder() - .trustSelfSigned(true) - .trustAll(true) - .laxRedirect(true) - .build()) + .config(BrooklynHttpConfig.httpConfigBuilder(getEntity()).build()) .build()); return createHttpToolRespose(response, startTime); }}; diff --git a/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java b/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java index 9f7a8e3d1d..a1619b7e00 100644 --- a/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java +++ b/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java @@ -1018,7 +1018,7 @@ public class SshMachineLocation extends AbstractMachineLocation implements Machi /** returns the un-passphrased key-pair info if a key is being used, or else null */ public KeyPair findKeyPair() { - OsCredential creds = LocationConfigUtils.getOsCredential(config().getBag()); + OsCredential creds = LocationConfigUtils.getOsCredential(config().getBag(), ResourceUtils.create(this)); if (creds.hasKey()) { String data = creds.getPrivateKeyData(); return SecureKeys.readPem(data.getBytes(), getConfig(SshTool.PROP_PRIVATE_KEY_PASSPHRASE)); diff --git a/core/src/main/java/org/apache/brooklyn/util/core/ResourceUtils.java b/core/src/main/java/org/apache/brooklyn/util/core/ResourceUtils.java index b5bb384440..1191b05125 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/ResourceUtils.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/ResourceUtils.java @@ -32,20 +32,26 @@ import java.net.URL; import java.net.URLDecoder; import java.util.List; import java.util.NoSuchElementException; +import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.annotation.Nullable; +import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext; +import org.apache.brooklyn.api.objs.BrooklynObject; import org.apache.brooklyn.api.typereg.RegisteredType; import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog.BrooklynLoaderTracker; import org.apache.brooklyn.core.catalog.internal.CatalogUtils; import org.apache.brooklyn.core.internal.BrooklynInitialization; +import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext; import org.apache.brooklyn.core.mgmt.classloading.OsgiBrooklynClassLoadingContext; import org.apache.brooklyn.location.ssh.SshMachineLocation; import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.core.javalang.BrooklynHttpConfig; +import org.apache.brooklyn.util.core.task.Tasks; import org.apache.brooklyn.util.core.text.DataUriSchemeParser; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.http.HttpTool; @@ -139,9 +145,9 @@ public class ResourceUtils { public static final ResourceUtils create(RegisteredType type, ManagementContext mgmt, boolean includeThreadAndJavaClassLoader) { if (includeThreadAndJavaClassLoader) { - return create(CatalogUtils.newClassLoadingContext(mgmt, type), type.getId()); + return create(CatalogUtils.newClassLoadingContext(mgmt, type), type.getId()).withHttpClientBuilder(() -> BrooklynHttpConfig.httpClientBuilder(mgmt, true)); } else { - return create(new OsgiBrooklynClassLoadingContext(mgmt, type.getId(), type.getLibraries()), type.getId()); + return create(new OsgiBrooklynClassLoadingContext(mgmt, type.getId(), type.getLibraries()), type.getId()).withHttpClientBuilder(() -> BrooklynHttpConfig.httpClientBuilder(mgmt, true)); } } @@ -149,6 +155,7 @@ public class ResourceUtils { * Creates a {@link ResourceUtils} object with itself as the context. * * @see ResourceUtils#create(Object) + * @deprecated since 1.1, supply an object such as an entity or adjunct to use the correct classpaths and correct certificate trust settings */ public static final ResourceUtils create() { return new ResourceUtils(null); @@ -165,7 +172,7 @@ public class ResourceUtils { } public ResourceUtils(Object contextObject, String contextMessage) { - this(contextObject==null ? null : getClassLoadingContextInternal(null, contextObject), contextObject, contextMessage); + this(contextObject==null || contextObject instanceof String ? null : getClassLoadingContextInternal(null, contextObject), contextObject, contextMessage); } public ResourceUtils(Object contextObject) { @@ -203,7 +210,7 @@ public class ResourceUtils { * Better for callers use {@link CatalogUtils#getClassLoadingContext(org.apache.brooklyn.api.entity.Entity)} or similar. }. */ private BrooklynClassLoadingContext getLoader() { - return (loader!=null ? loader : getClassLoadingContextInternal(null, contextObject!=null ? contextObject : this)); + return (loader!=null ? loader : getClassLoadingContextInternal(null, contextObject!=null && !(contextObject instanceof String) ? contextObject : this)); } /** @@ -430,11 +437,28 @@ public class ResourceUtils { } } + Supplier<HttpClientBuilder> httpClientBuilderSupplier; + + public ResourceUtils withHttpClientBuilder(Supplier<HttpClientBuilder> httpClientBuilderSupplier) { + this.httpClientBuilderSupplier = httpClientBuilderSupplier; + return this; + } + + protected HttpClientBuilder newHttpClientBuilder() { + if (httpClientBuilderSupplier!=null) return httpClientBuilderSupplier.get(); + + if (contextObject instanceof ManagementContext) return BrooklynHttpConfig.httpClientBuilder( (ManagementContext) contextObject, true ); + else if (contextObject instanceof BrooklynObject) return BrooklynHttpConfig.httpClientBuilder((BrooklynObject) contextObject); + + Entity entity = BrooklynTaskTags.getContextEntity(Tasks.current()); + if (entity!=null) return BrooklynHttpConfig.httpClientBuilder(entity); + + return BrooklynHttpConfig.httpClientBuilderDefaultStrict(); + } + private InputStream getResourceViaHttp(String resource, @Nullable String username, @Nullable String password) throws IOException { URI uri = URI.create(resource); - HttpClientBuilder builder = HttpTool.httpClientBuilder() - .laxRedirect(true) - .uri(uri); + HttpClientBuilder builder = newHttpClientBuilder().uri(uri); Credentials credentials; if (username != null) { credentials = new UsernamePasswordCredentials(username, password); diff --git a/core/src/main/java/org/apache/brooklyn/util/core/javalang/BrooklynHttpConfig.java b/core/src/main/java/org/apache/brooklyn/util/core/javalang/BrooklynHttpConfig.java new file mode 100644 index 0000000000..db470eb5e9 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/util/core/javalang/BrooklynHttpConfig.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.brooklyn.util.core.javalang; + +import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.api.objs.BrooklynObject; +import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.core.config.ConfigKeys; +import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; +import org.apache.brooklyn.core.objs.BrooklynObjectInternal; +import org.apache.brooklyn.util.core.task.Tasks; +import org.apache.brooklyn.util.http.HttpTool; +import org.apache.brooklyn.util.http.executor.HttpConfig; +import org.apache.brooklyn.util.http.executor.HttpExecutor; +import org.apache.brooklyn.util.http.executor.apacheclient.HttpExecutorImpl; + +import java.util.function.Consumer; +import java.util.function.Function; + +public class BrooklynHttpConfig { + + public static final String HTTPS_CONFIG = "brooklyn.https.config."; + public static final ConfigKey<Boolean> TRUST_ALL = ConfigKeys.newBooleanConfigKey(HTTPS_CONFIG + "trustAll", + "Whether HTTPS and TLS connections should trust all certificates"); + public static final ConfigKey<Boolean> TRUST_SELF_SIGNED = ConfigKeys.newBooleanConfigKey(HTTPS_CONFIG + "trustSelfSigned", + "Whether HTTPS and TLS connections should trust self-signed certificates"); + public static final ConfigKey<Boolean> LAX_REDIRECT = ConfigKeys.newBooleanConfigKey(HTTPS_CONFIG + "laxRedirect", + "Whether HTTPS and TLS connections should be lax about redirecting"); + + private static final boolean DEFAULT_FOR_MGMT_LAX_AND_TRUSTING = true; + + public static HttpConfig.Builder httpConfigBuilder(ManagementContext mgmt, boolean lookForContextEntity) { + return httpConfigBuilder(mgmt, DEFAULT_FOR_MGMT_LAX_AND_TRUSTING, lookForContextEntity); + } + public static HttpConfig.Builder httpConfigBuilder(ManagementContext mgmt, boolean defaultLaxAndTrusting, boolean lookForContextEntity) { + HttpConfig.Builder hcb = httpConfigBuilderDefault(defaultLaxAndTrusting, false); + apply(hcb, mgmt.getConfig()::getConfig); + if (lookForContextEntity) applyContextEntity(hcb); + return hcb; + } + + private static void apply(HttpConfig.Builder hcb, Function<ConfigKey<Boolean>,Boolean> getter) { + applyIfNonNull(getter.apply(TRUST_ALL), hcb::trustAll); + applyIfNonNull(getter.apply(TRUST_SELF_SIGNED), hcb::trustSelfSigned); + applyIfNonNull(getter.apply(LAX_REDIRECT), hcb::laxRedirect); + } + + private static void applyContextEntity(HttpConfig.Builder hcb) { + BrooklynObject entity = BrooklynTaskTags.getContextEntity(Tasks.current()); + if (entity!=null) apply(hcb, entity.config()::get); + } + + private static void applyIfNonNull(Boolean v, Consumer<Boolean> target) { + if (v!=null) target.accept(v); + } + + public static HttpConfig.Builder httpConfigBuilder(BrooklynObject entity) { + return httpConfigBuilder(entity, DEFAULT_FOR_MGMT_LAX_AND_TRUSTING); + } + public static HttpConfig.Builder httpConfigBuilder(BrooklynObject entity, boolean defaultLaxAndTrusting) { + HttpConfig.Builder hcb = httpConfigBuilder(((BrooklynObjectInternal)entity).getManagementContext(), defaultLaxAndTrusting, false); + apply(hcb, entity.config()::get); + return hcb; + } + + private static HttpConfig.Builder httpConfigBuilderDefault(boolean laxAndTrusting, boolean lookForContextEntities) { + HttpConfig.Builder hcb = HttpConfig.builder().laxRedirect(laxAndTrusting).trustAll(laxAndTrusting).trustSelfSigned(laxAndTrusting); + if (lookForContextEntities) applyContextEntity(hcb); + return hcb; + } + + + + public static HttpTool.HttpClientBuilder httpClientBuilder(ManagementContext mgmt, boolean lookForContextEntity) { + return httpClientBuilder(mgmt, DEFAULT_FOR_MGMT_LAX_AND_TRUSTING, lookForContextEntity); + } + public static HttpTool.HttpClientBuilder httpClientBuilder(ManagementContext mgmt, boolean defaultLaxAndTrusting, boolean lookForContextEntity) { + HttpTool.HttpClientBuilder hcb = httpClientBuilderDefault(defaultLaxAndTrusting, false); + apply(hcb, mgmt.getConfig()::getConfig); + if (lookForContextEntity) { + applyContextEntity(hcb); + } + return hcb; + } + + private static void apply(HttpTool.HttpClientBuilder hcb, Function<ConfigKey<Boolean>,Boolean> getter) { + applyIfNonNull(getter.apply(TRUST_ALL), hcb::trustAll); + applyIfNonNull(getter.apply(TRUST_SELF_SIGNED), hcb::trustSelfSigned); + applyIfNonNull(getter.apply(LAX_REDIRECT), hcb::laxRedirect); + } + + private static void applyContextEntity(HttpTool.HttpClientBuilder hcb) { + BrooklynObject entity = BrooklynTaskTags.getContextEntity(Tasks.current()); + if (entity!=null) apply(hcb, entity.config()::get); + } + + public static HttpTool.HttpClientBuilder httpClientBuilderDefaultStrict() { + return httpClientBuilderDefault(false, false); + } + + private static HttpTool.HttpClientBuilder httpClientBuilderDefault(boolean defaultLaxAndTrusting, boolean lookForContextEntity) { + HttpTool.HttpClientBuilder hcb = HttpTool.httpClientBuilder(); + if (defaultLaxAndTrusting) { + hcb.trustAll(true); + hcb.trustSelfSigned(true); + hcb.laxRedirect(true); + } + if (lookForContextEntity) { + applyContextEntity(hcb); + } + return hcb; + } + + public static HttpTool.HttpClientBuilder httpClientBuilder(BrooklynObject entity) { + return httpClientBuilder(entity, DEFAULT_FOR_MGMT_LAX_AND_TRUSTING); + } + + public static HttpTool.HttpClientBuilder httpClientBuilder(BrooklynObject entity, boolean defaultLaxAndTrusting) { + HttpTool.HttpClientBuilder hcb = httpClientBuilder(((BrooklynObjectInternal)entity).getManagementContext(), defaultLaxAndTrusting, false); + apply(hcb, entity.config()::get); + return hcb; + } + + public static HttpExecutor newHttpExecutor(BrooklynObject entity) { + return HttpExecutorImpl.newInstance().withConfig(httpConfigBuilder(entity, false).build()); + } + + public static HttpExecutor newHttpExecutorDefault() { + return HttpExecutorImpl.newInstance().withConfig(httpConfigBuilderDefault(false, true).build()); + } + + // SslTrustUtils.trustAll and TRUST_ALL -- only used in unsafe methods + // TrustingSslSocketFactory - only used in unsafe methods + // HttpTool and HttpTestUtils methods -- only used in tests and check code, methods marked unsafe, not for content + // HttpTool.TrustAllStrategy -- only used in unsafe methods above and by HttpClientBuilder which is routed above in production code + // HttpExecutorImpl -- only used with config supplied by above + // HttpExecutorFactory not set, except in tests; our HttpExecutorFactoryImpl only used in tests + // HttpConfig.Builder -- all uses routed through here +} diff --git a/core/src/main/java/org/apache/brooklyn/util/core/osgi/BundleMaker.java b/core/src/main/java/org/apache/brooklyn/util/core/osgi/BundleMaker.java index f2eeb0fb5c..1510e6d810 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/osgi/BundleMaker.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/osgi/BundleMaker.java @@ -75,7 +75,7 @@ public class BundleMaker { } public BundleMaker(@Nonnull ManagementContext mgmt) { - this(((ManagementContextInternal) mgmt).getOsgiManager().get().getFramework(), ResourceUtils.create()); + this(((ManagementContextInternal) mgmt).getOsgiManager().get().getFramework(), ResourceUtils.create(mgmt)); } /** if set, this will be used to resolve relative classpath fragments; diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshPutTaskFactory.java b/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshPutTaskFactory.java index 5e369d112c..5d65019ce8 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshPutTaskFactory.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshPutTaskFactory.java @@ -21,6 +21,7 @@ package org.apache.brooklyn.util.core.task.ssh; import java.io.InputStream; import java.io.Reader; +import com.google.common.base.Supplier; import org.apache.brooklyn.api.mgmt.TaskFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -89,6 +90,12 @@ public class SshPutTaskFactory extends SshPutTaskStub implements TaskFactory<Ssh return self(); } + public SshPutTaskFactory contents(Supplier<InputStream> stream) { + markDirty(); + this.contents = stream; + return self(); + } + public SshPutTaskFactory contents(Reader reader) { markDirty(); this.contents = Suppliers.ofInstance(new ReaderInputStream(reader)); diff --git a/core/src/main/java/org/apache/brooklyn/util/executor/HttpExecutorFactoryImpl.java b/core/src/main/java/org/apache/brooklyn/util/executor/HttpExecutorFactoryImpl.java index b652dba0b1..3a72fbc66e 100644 --- a/core/src/main/java/org/apache/brooklyn/util/executor/HttpExecutorFactoryImpl.java +++ b/core/src/main/java/org/apache/brooklyn/util/executor/HttpExecutorFactoryImpl.java @@ -18,11 +18,10 @@ */ package org.apache.brooklyn.util.executor; -import java.util.Map; -import java.util.Map.Entry; - +import com.google.common.collect.Maps; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.ClassLoaderUtils; +import org.apache.brooklyn.util.core.javalang.BrooklynHttpConfig; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.http.executor.HttpExecutor; import org.apache.brooklyn.util.http.executor.apacheclient.HttpExecutorImpl; @@ -31,7 +30,8 @@ import org.apache.brooklyn.util.text.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.collect.Maps; +import java.util.Map; +import java.util.Map.Entry; public class HttpExecutorFactoryImpl implements HttpExecutorFactory { private static final Logger LOG = LoggerFactory.getLogger(HttpExecutorFactoryImpl.class); @@ -62,7 +62,7 @@ public class HttpExecutorFactoryImpl implements HttpExecutorFactory { } else { LOG.info(HTTP_EXECUTOR_CLASS_CONFIG + " parameter not provided. Using the default implementation " + HttpExecutorImpl.class.getName()); - httpExecutor = HttpExecutorImpl.newInstance(); + httpExecutor = BrooklynHttpConfig.newHttpExecutorDefault(); } return httpExecutor; diff --git a/core/src/test/java/org/apache/brooklyn/util/core/ResourceUtilsTest.java b/core/src/test/java/org/apache/brooklyn/util/core/ResourceUtilsTest.java index 11914f8aab..c45b5d3bc0 100644 --- a/core/src/test/java/org/apache/brooklyn/util/core/ResourceUtilsTest.java +++ b/core/src/test/java/org/apache/brooklyn/util/core/ResourceUtilsTest.java @@ -182,7 +182,7 @@ public class ResourceUtilsTest { @Test public void testGetResources() { - Iterable<URL> manifests = ResourceUtils.create().getResources("META-INF/MANIFEST.MF"); + Iterable<URL> manifests = ResourceUtils.create("test").getResources("META-INF/MANIFEST.MF"); assertFalse(Iterables.isEmpty(manifests)); } diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/CreateUserStatements.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/CreateUserStatements.java index d275fc102f..994fd10613 100644 --- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/CreateUserStatements.java +++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/CreateUserStatements.java @@ -26,6 +26,7 @@ import java.util.List; import javax.annotation.Nullable; import org.apache.brooklyn.core.location.LocationConfigUtils; +import org.apache.brooklyn.util.core.ResourceUtils; import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.core.crypto.SecureKeys; import org.apache.brooklyn.util.text.Identifiers; @@ -129,7 +130,7 @@ public class CreateUserStatements { : null; final boolean dontCreateUser = config.get(JcloudsLocation.DONT_CREATE_USER); final boolean grantUserSudo = config.get(JcloudsLocation.GRANT_USER_SUDO); - final LocationConfigUtils.OsCredential credential = LocationConfigUtils.getOsCredential(config); + final LocationConfigUtils.OsCredential credential = LocationConfigUtils.getOsCredential(config, ResourceUtils.create(location)); credential.checkNoErrors().logAnyWarnings(); final String passwordToSet = Strings.isNonBlank(credential.getPassword()) ? credential.getPassword() : Identifiers.makeRandomId(12); diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java index a7b3d13bf3..de1b09949b 100644 --- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java +++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java @@ -1045,7 +1045,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im } else { List<String> extraKeyDataToAuth = MutableList.of(); for (String keyUrl : extraKeyUrlsToAuth) { - extraKeyDataToAuth.add(ResourceUtils.create().getResourceAsString(keyUrl)); + extraKeyDataToAuth.add(ResourceUtils.create(this).getResourceAsString(keyUrl)); } executeCommandThrowingOnError( (SshMachineLocation)machineLocation, @@ -1978,7 +1978,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im } NodeMetadata node = Iterables.getOnlyElement(candidateNodes); - OsCredential osCredentials = LocationConfigUtils.getOsCredential(config).checkNoErrors().logAnyWarnings(); + OsCredential osCredentials = LocationConfigUtils.getOsCredential(config, ResourceUtils.create(this)).checkNoErrors().logAnyWarnings(); String pkd = osCredentials.getPrivateKeyData(); String password = osCredentials.getPassword(); LoginCredentials expectedCredentials = node.getCredentials(); @@ -2490,7 +2490,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im protected LoginCredentials extractVmCredentials(ConfigBag setup, NodeMetadata node, LoginCredentials nodeCredentials) { boolean windows = isWindows(node, setup); String user = getUser(setup); - OsCredential localCredentials = LocationConfigUtils.getOsCredential(setup).checkNoErrors(); + OsCredential localCredentials = LocationConfigUtils.getOsCredential(setup, ResourceUtils.create(this)).checkNoErrors(); LOG.debug("Credentials extracted for {}: {}/{} with {}/{}", new Object[] { node, user, nodeCredentials.getUser(), localCredentials, nodeCredentials }); diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsSshMachineLocation.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsSshMachineLocation.java index 68dd4924c2..199283ed61 100644 --- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsSshMachineLocation.java +++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsSshMachineLocation.java @@ -39,6 +39,7 @@ import org.apache.brooklyn.core.location.BasicOsDetails; import org.apache.brooklyn.core.location.LocationConfigUtils; import org.apache.brooklyn.core.location.LocationConfigUtils.OsCredential; import org.apache.brooklyn.location.ssh.SshMachineLocation; +import org.apache.brooklyn.util.core.ResourceUtils; import org.apache.brooklyn.util.core.config.ResolvingConfigBag; import org.apache.brooklyn.util.core.flags.SetFromFlag; import org.apache.brooklyn.util.exceptions.Exceptions; @@ -458,7 +459,7 @@ public class JcloudsSshMachineLocation extends SshMachineLocation implements Jcl } private LoginCredentials getLoginCredentials() { - OsCredential creds = LocationConfigUtils.getOsCredential(new ResolvingConfigBag(getManagementContext(), config().getBag())); + OsCredential creds = LocationConfigUtils.getOsCredential(new ResolvingConfigBag(getManagementContext(), config().getBag()), ResourceUtils.create(this)); return LoginCredentials.builder() .user(getUser()) diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/test/entity/brooklynnode/DeployBlueprintTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/test/entity/brooklynnode/DeployBlueprintTest.java index 87d4604bba..4d1d3b6821 100644 --- a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/test/entity/brooklynnode/DeployBlueprintTest.java +++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/test/entity/brooklynnode/DeployBlueprintTest.java @@ -77,11 +77,11 @@ public class DeployBlueprintTest extends BrooklynRestResourceTest { log.info("got: "+id); - String apps = HttpTool.getContent(getEndpointAddress() + "/applications"); + String apps = HttpTool.getContentUnsafe(getEndpointAddress() + "/applications"); List<String> appType = parseJsonList(apps, ImmutableList.of("spec", "type"), String.class); assertEquals(appType, ImmutableList.of(BasicApplication.class.getName())); - String status = HttpTool.getContent(getEndpointAddress()+"/applications/"+id+"/entities/"+id+"/sensors/service.status"); + String status = HttpTool.getContentUnsafe(getEndpointAddress()+"/applications/"+id+"/entities/"+id+"/sensors/service.status"); log.info("STATUS: "+status); } diff --git a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncherTest.java b/rest/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncherTest.java index 26c8fb012d..f887ed3566 100644 --- a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncherTest.java +++ b/rest/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncherTest.java @@ -55,7 +55,7 @@ public class BrooklynRestApiLauncherTest extends BrooklynRestApiLauncherTestFixt int code = Asserts.succeedsEventually(new Callable<Integer>() { @Override public Integer call() throws Exception { - int code = HttpTool.getHttpStatusCode(rootUrl+"catalog/entities"); + int code = HttpTool.getHttpStatusCodeUnsafe(rootUrl+"catalog/entities"); if (code == HttpStatus.SC_FORBIDDEN) { throw new RuntimeException("Retry request"); } else { diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/EntityHttpClientImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/EntityHttpClientImpl.java index ab08924997..c6d649126b 100644 --- a/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/EntityHttpClientImpl.java +++ b/software/base/src/main/java/org/apache/brooklyn/entity/brooklynnode/EntityHttpClientImpl.java @@ -28,6 +28,7 @@ import org.apache.brooklyn.api.sensor.AttributeSensor; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.core.javalang.BrooklynHttpConfig; import org.apache.brooklyn.util.http.HttpTool; import org.apache.brooklyn.util.http.HttpToolResponse; import org.apache.brooklyn.util.core.task.Tasks; @@ -67,10 +68,7 @@ public class EntityHttpClientImpl implements EntityHttpClient { @Override public HttpTool.HttpClientBuilder getHttpClientForBrooklynNode() { String baseUrl = getEntityUrl(); - HttpTool.HttpClientBuilder builder = HttpTool.httpClientBuilder() - .trustAll() - .laxRedirect(true) - .uri(baseUrl); + HttpTool.HttpClientBuilder builder = BrooklynHttpConfig.httpClientBuilder(entity).uri(baseUrl); if (entity.getConfig(BrooklynNode.MANAGEMENT_USER) != null) { UsernamePasswordCredentials credentials = new UsernamePasswordCredentials( entity.getConfig(BrooklynNode.MANAGEMENT_USER), diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java index 7f2e6edab2..7506db7ead 100644 --- a/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java +++ b/software/base/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java @@ -57,6 +57,7 @@ import org.apache.brooklyn.test.HttpTestUtils; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.ResourceUtils; import org.apache.brooklyn.util.core.config.ConfigBag; +import org.apache.brooklyn.util.core.javalang.BrooklynHttpConfig; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.guava.Functionals; import org.apache.brooklyn.util.http.HttpAsserts; @@ -253,7 +254,7 @@ services: app.start(locs); log.info("started "+app+" containing "+brooklynNode+" for "+JavaClassNames.niceClassAndMethod()); - assertEquals(ResourceUtils.create().getResourceAsString(pseudoBrooklynCatalogFile.getAbsolutePath()), catalogContents); + assertEquals(ResourceUtils.create(app).getResourceAsString(pseudoBrooklynCatalogFile.getAbsolutePath()), catalogContents); // Confirm the catalog item has taken effect (by deploying an app) final URI webConsoleUri = brooklynNode.getAttribute(BrooklynNode.WEB_CONSOLE_URI); @@ -263,7 +264,7 @@ services: .configure(DeployBlueprintEffector.BLUEPRINT_TYPE, "BrooklynNodeIntegrationTest.mycatalog:1.0") .getAllConfig()).get(); - String apps = HttpTestUtils.getContent(webConsoleUri.toString()+"/v1/applications"); + String apps = HttpTool.getContentUnsafe(webConsoleUri.toString()+"/v1/applications"); List<String> appType = parseJsonList(apps, ImmutableList.of("spec", "type"), String.class); assertEquals(appType, ImmutableList.of(BasicApplication.class.getName())); @@ -465,7 +466,7 @@ services: URI webConsoleUri = brooklynNode.getAttribute(BrooklynNode.WEB_CONSOLE_URI); waitForApps(webConsoleUri, 1); - String apps = HttpTestUtils.getContent(webConsoleUri.toString()+"/v1/applications"); + String apps = HttpTool.getContentUnsafe(webConsoleUri.toString()+"/v1/applications"); List<String> appType = parseJsonList(apps, ImmutableList.of("spec", "type"), String.class); assertEquals(appType, ImmutableList.of(BasicApplication.class.getName())); } @@ -484,7 +485,7 @@ services: @Override public void run() { //Wait all apps to become managed - String appsContent = HttpTestUtils.getContent(webConsoleUri.toString()+"/v1/applications"); + String appsContent = HttpTool.getContentUnsafe(webConsoleUri.toString()+"/v1/applications"); List<String> appIds = parseJsonList(appsContent, ImmutableList.of("id"), String.class); assertEquals(appIds.size(), num); @@ -510,7 +511,7 @@ services: .configure(DeployBlueprintEffector.BLUEPRINT_TYPE, BasicApplication.class.getName()) .getAllConfig()).get(); - String apps = HttpTestUtils.getContent(webConsoleUri.toString()+"/v1/applications"); + String apps = HttpTool.getContentUnsafe(webConsoleUri.toString()+"/v1/applications"); List<String> appType = parseJsonList(apps, ImmutableList.of("spec", "type"), String.class); assertEquals(appType, ImmutableList.of(BasicApplication.class.getName())); @@ -538,17 +539,17 @@ services: waitForApps(webConsoleUri, 1); // Check that "mynamedloc" has been picked up from the brooklyn.properties - String locsContent = HttpTestUtils.getContent(webConsoleUri.toString()+"/v1/locations"); + String locsContent = HttpTool.getContentUnsafe(webConsoleUri.toString()+"/v1/locations"); List<String> locNames = parseJsonList(locsContent, ImmutableList.of("name"), String.class); assertTrue(locNames.contains("mynamedloc"), "locNames="+locNames); // Find the id of the concrete location instance of the app - String appsContent = HttpTestUtils.getContent(webConsoleUri.toString()+"/v1/applications"); + String appsContent = HttpTool.getContentUnsafe(webConsoleUri.toString()+"/v1/applications"); List<String[]> appLocationIds = parseJsonList(appsContent, ImmutableList.of("spec", "locations"), String[].class); String appLocationId = Iterables.getOnlyElement(appLocationIds)[0]; // app.getManagementContext().getLocationRegistry() // Check that the concrete location is of the required type - String locatedLocationsContent = HttpTestUtils.getContent(webConsoleUri.toString()+"/v1/locations/usage/LocatedLocations"); + String locatedLocationsContent = HttpTool.getContentUnsafe(webConsoleUri.toString()+"/v1/locations/usage/LocatedLocations"); assertEquals(parseJson(locatedLocationsContent, ImmutableList.of(appLocationId, "name"), String.class), "myname"); assertEquals(parseJson(locatedLocationsContent, ImmutableList.of(appLocationId, "longitude"), Double.class), 45.6, 0.00001); } @@ -576,10 +577,8 @@ services: Assert.assertTrue(webConsoleUri.toString().contains(""+httpsPort), "web console not using right https port ("+httpsPort+"): "+webConsoleUri); HttpTestUtils.assertHttpStatusCodeEquals(webConsoleUri.toString(), 401); - HttpClient http = HttpTool.httpClientBuilder() - .trustAll() + HttpClient http = BrooklynHttpConfig.httpClientBuilder(app) .uri(webConsoleUri) - .laxRedirect(true) .credentials(new UsernamePasswordCredentials("admin", adminPassword)) .build(); HttpToolResponse response = HttpTool.httpGet(http, webConsoleUri, MutableMap.<String,String>of()); @@ -653,7 +652,7 @@ services: BrooklynNode.RestartSoftwareParameters.RESTART_MACHINE.getName(), "false")).getUnchecked(); waitForApps(webConsoleUri.toString()); - String apps = HttpTestUtils.getContent(webConsoleUri.toString()+"/v1/applications"); + String apps = HttpTool.getContentUnsafe(webConsoleUri.toString()+"/v1/applications"); List<String> appType = parseJsonList(apps, ImmutableList.of("spec", "type"), String.class); assertEquals(appType, ImmutableList.of(BasicApplication.class.getName())); } diff --git a/test-support/src/main/java/org/apache/brooklyn/test/HttpTestUtils.java b/test-support/src/main/java/org/apache/brooklyn/test/HttpTestUtils.java index 1006befda8..21bf1906aa 100644 --- a/test-support/src/main/java/org/apache/brooklyn/test/HttpTestUtils.java +++ b/test-support/src/main/java/org/apache/brooklyn/test/HttpTestUtils.java @@ -18,42 +18,30 @@ */ package org.apache.brooklyn.test; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import com.google.common.base.Throwables; +import com.google.common.collect.Lists; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.http.HttpTool; +import org.apache.brooklyn.util.stream.Streams; +import org.apache.brooklyn.util.time.Time; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; -import java.net.URL; import java.net.URLConnection; import java.util.List; import java.util.Map; -import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSession; - -import org.apache.brooklyn.util.collections.MutableMap; -import org.apache.brooklyn.util.crypto.SslTrustUtils; -import org.apache.brooklyn.util.exceptions.Exceptions; -import org.apache.brooklyn.util.http.HttpTool; -import org.apache.brooklyn.util.http.TrustingSslSocketFactory; -import org.apache.brooklyn.util.stream.Streams; -import org.apache.brooklyn.util.time.Time; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; - -import com.google.common.base.Throwables; -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListeningExecutorService; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; /** * Utility methods to aid testing HTTP. @@ -69,76 +57,20 @@ public class HttpTestUtils { private static final Logger LOG = LoggerFactory.getLogger(HttpTestUtils.class); static final ExecutorService executor = Executors.newCachedThreadPool(); - - /** - * Connects to the given url and returns the connection. - * Caller should {@code connection.getInputStream().close()} the result of this - * (especially if they are making heavy use of this method). - */ + + @Deprecated /** @deprecated since 1.1, refer to (and replace per) method in HttpTool */ public static URLConnection connectToUrl(String u) throws Exception { - final URL url = new URL(u); - final AtomicReference<Exception> exception = new AtomicReference<Exception>(); - - // sometimes openConnection hangs, so run in background - Future<URLConnection> f = executor.submit(new Callable<URLConnection>() { - @Override - public URLConnection call() { - try { - HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { - @Override public boolean verify(String s, SSLSession sslSession) { - return true; - } - }); - URLConnection connection = url.openConnection(); - TrustingSslSocketFactory.configure(connection); - connection.connect(); - - connection.getContentLength(); // Make sure the connection is made. - return connection; - } catch (Exception e) { - exception.set(e); - LOG.debug("Error connecting to url "+url+" (propagating): "+e, e); - } - return null; - } - }); - try { - URLConnection result = null; - try { - result = f.get(60, TimeUnit.SECONDS); - } catch (InterruptedException e) { - throw e; - } catch (Exception e) { - LOG.debug("Error connecting to url "+url+", probably timed out (rethrowing): "+e); - throw new IllegalStateException("Connect to URL not complete within 60 seconds, for url "+url+": "+e); - } - if (exception.get() != null) { - LOG.debug("Error connecting to url "+url+", thread caller of "+exception, new Throwable("source of rethrown error "+exception)); - throw exception.get(); - } else { - return result; - } - } finally { - f.cancel(true); - } + return HttpTool.connectToUrlUnsafe(u); } public static void assertHealthyStatusCode(int code) { if (code>=200 && code<=299) return; Assert.fail("Wrong status code: "+code); } - + + @Deprecated /** @deprecated since 1.1, refer to (and replace per) method in HttpTool */ public static int getHttpStatusCode(String url) throws Exception { - URLConnection connection = connectToUrl(url); - long startTime = System.currentTimeMillis(); - int status = ((HttpURLConnection) connection).getResponseCode(); - - // read fully if possible, then close everything, trying to prevent cached threads at server - consumeAndCloseQuietly((HttpURLConnection) connection); - - if (LOG.isDebugEnabled()) - LOG.debug("connection to {} ({}ms) gives {}", new Object[] { url, (System.currentTimeMillis()-startTime), status }); - return status; + return HttpTool.getHttpStatusCodeUnsafe(url); } /** @@ -147,7 +79,7 @@ public class HttpTestUtils { */ public static void assertUrlReachable(String url) { try { - getHttpStatusCode(url); + HttpTool.getHttpStatusCodeUnsafe(url); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException("Interrupted for "+url+" (in assertion that is reachable)", e); @@ -158,7 +90,7 @@ public class HttpTestUtils { public static void assertUrlUnreachable(String url) { try { - int statusCode = getHttpStatusCode(url); + int statusCode = HttpTool.getHttpStatusCodeUnsafe(url); fail("Expected url "+url+" unreachable, but got status code "+statusCode); } catch (InterruptedException e) { Thread.currentThread().interrupt(); @@ -192,7 +124,7 @@ public class HttpTestUtils { acceptableCodes.add(code); } try { - int actualCode = getHttpStatusCode(url); + int actualCode = HttpTool.getHttpStatusCodeUnsafe(url); assertTrue(acceptableCodes.contains(actualCode), "code="+actualCode+"; expected="+acceptableCodes+"; url="+url); } catch (InterruptedException e) { @@ -218,7 +150,7 @@ public class HttpTestUtils { public static void assertContentContainsText(final String url, final String phrase, final String ...additionalPhrases) { try { - String contents = getContent(url); + String contents = HttpTool.getContentUnsafe(url); Assert.assertTrue(contents != null && contents.length() > 0); for (String text: Lists.asList(phrase, additionalPhrases)) { if (!contents.contains(text)) { @@ -233,7 +165,7 @@ public class HttpTestUtils { public static void assertContentNotContainsText(final String url, final String phrase, final String ...additionalPhrases) { try { - String contents = getContent(url); + String contents = HttpTool.getContentUnsafe(url); Assert.assertTrue(contents != null); for (String text: Lists.asList(phrase, additionalPhrases)) { if (contents.contains(text)) { @@ -248,7 +180,7 @@ public class HttpTestUtils { public static void assertErrorContentContainsText(final String url, final String phrase, final String ...additionalPhrases) { try { - String contents = getErrorContent(url); + String contents = HttpTool.getErrorContent(url); Assert.assertTrue(contents != null && contents.length() > 0); for (String text: Lists.asList(phrase, additionalPhrases)) { if (!contents.contains(text)) { @@ -264,7 +196,7 @@ public class HttpTestUtils { public static void assertErrorContentNotContainsText(final String url, final String phrase, final String ...additionalPhrases) { try { - String err = getErrorContent(url); + String err = HttpTool.getErrorContent(url); Assert.assertTrue(err != null); for (String text: Lists.asList(phrase, additionalPhrases)) { if (err.contains(text)) { @@ -291,7 +223,7 @@ public class HttpTestUtils { } public static void assertContentMatches(String url, String regex) { - String contents = getContent(url); + String contents = HttpTool.getContentUnsafe(url); Assert.assertNotNull(contents); Assert.assertTrue(contents.matches(regex), "Contents does not match expected regex ("+regex+"): "+contents); } @@ -308,7 +240,8 @@ public class HttpTestUtils { } }); } - + + @Deprecated /** @deprecated since 1.1, refer to (and replace per) method in HttpTool */ public static String getErrorContent(String url) { try { HttpURLConnection connection = (HttpURLConnection) connectToUrl(url); @@ -332,13 +265,10 @@ public class HttpTestUtils { throw Exceptions.propagate(e); } } - + + @Deprecated /** @deprecated since 1.1, refer to (and replace per) method in HttpTool */ public static String getContent(String url) { - try { - return Streams.readFullyStringAndClose(SslTrustUtils.trustAll(new URL(url).openConnection()).getInputStream()); - } catch (Exception e) { - throw Throwables.propagate(e); - } + return HttpTool.getContentUnsafe(url); } /** @@ -380,7 +310,7 @@ public class HttpTestUtils { * Ignores all exceptions completely, not even logging them! * * Consuming the stream fully is useful for preventing idle TCP connections. - * See {@linkplain http://docs.oracle.com/javase/8/docs/technotes/guides/net/http-keepalive.html}. + * See http://docs.oracle.com/javase/8/docs/technotes/guides/net/http-keepalive.html */ public static void consumeAndCloseQuietly(HttpURLConnection connection) { try { Streams.readFully(connection.getInputStream()); } catch (Exception e) {} diff --git a/test-support/src/main/java/org/apache/brooklyn/test/WebAppMonitor.java b/test-support/src/main/java/org/apache/brooklyn/test/WebAppMonitor.java index 439013fd3b..1e59d867ed 100644 --- a/test-support/src/main/java/org/apache/brooklyn/test/WebAppMonitor.java +++ b/test-support/src/main/java/org/apache/brooklyn/test/WebAppMonitor.java @@ -25,6 +25,7 @@ import java.util.concurrent.atomic.AtomicReference; import org.apache.brooklyn.test.Asserts; import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.http.HttpTool; import org.apache.brooklyn.util.time.Duration; import org.slf4j.Logger; import org.testng.Assert; @@ -80,7 +81,7 @@ public class WebAppMonitor implements Runnable { long startTime = System.currentTimeMillis(); try { if (preAttempt()) { - int code = HttpTestUtils.getHttpStatusCode(url); + int code = HttpTool.getHttpStatusCodeUnsafe(url); lastTime.set(System.currentTimeMillis() - startTime); lastStatus.set(code); if (isResponseOkay(code)) { diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/http/HttpAsserts.java b/utils/common/src/main/java/org/apache/brooklyn/util/http/HttpAsserts.java index b4f253866b..afa368ee8f 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/http/HttpAsserts.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/http/HttpAsserts.java @@ -89,7 +89,7 @@ public class HttpAsserts { */ public static void assertUrlReachable(String url) { try { - HttpTool.getHttpStatusCode(url); + HttpTool.getHttpStatusCodeUnsafe(url); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException("Interrupted for "+url+" (in assertion that is reachable)", e); @@ -106,7 +106,7 @@ public class HttpAsserts { public static void assertUrlUnreachable(String url) { try { - int statusCode = HttpTool.getHttpStatusCode(url); + int statusCode = HttpTool.getHttpStatusCodeUnsafe(url); Asserts.fail("Expected url " + url + " unreachable, but got status code " + statusCode); } catch (InterruptedException e) { Thread.currentThread().interrupt(); @@ -159,7 +159,7 @@ public class HttpAsserts { acceptableCodes.add(code); } try { - int actualCode = HttpTool.getHttpStatusCode(url); + int actualCode = HttpTool.getHttpStatusCodeUnsafe(url); Asserts.assertTrue(acceptableCodes.contains(actualCode), "code=" + actualCode + "; expected=" + acceptableCodes + "; url=" + url); } catch (InterruptedException e) { @@ -185,7 +185,7 @@ public class HttpAsserts { public static void assertContentContainsText(final String url, final String phrase, final String ...additionalPhrases) { try { - String contents = HttpTool.getContent(url); + String contents = HttpTool.getContentUnsafe(url); Asserts.assertTrue(contents != null && contents.length() > 0); for (String text: Lists.asList(phrase, additionalPhrases)) { if (!contents.contains(text)) { @@ -200,7 +200,7 @@ public class HttpAsserts { public static void assertContentNotContainsText(final String url, final String phrase, final String ...additionalPhrases) { try { - String contents = HttpTool.getContent(url); + String contents = HttpTool.getContentUnsafe(url); Asserts.assertTrue(contents != null); for (String text: Lists.asList(phrase, additionalPhrases)) { if (contents.contains(text)) { @@ -215,7 +215,7 @@ public class HttpAsserts { public static void assertErrorContentContainsText(final String url, final String phrase, final String ...additionalPhrases) { try { - String contents = HttpTool.getErrorContent(url); + String contents = HttpTool.getErrorContentUnsafe(url); Asserts.assertTrue(contents != null && contents.length() > 0); for (String text: Lists.asList(phrase, additionalPhrases)) { if (!contents.contains(text)) { @@ -231,7 +231,7 @@ public class HttpAsserts { public static void assertErrorContentNotContainsText(final String url, final String phrase, final String ...additionalPhrases) { try { - String err = HttpTool.getErrorContent(url); + String err = HttpTool.getErrorContentUnsafe(url); Asserts.assertTrue(err != null); for (String text: Lists.asList(phrase, additionalPhrases)) { if (err.contains(text)) { @@ -279,7 +279,7 @@ public class HttpAsserts { } public static void assertContentMatches(String url, String regex) { - String contents = HttpTool.getContent(url); + String contents = HttpTool.getContentUnsafe(url); Asserts.assertNotNull(contents); Asserts.assertTrue(contents.matches(regex), "Contents does not match expected regex ("+regex+"): "+contents); } diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/http/HttpTool.java b/utils/common/src/main/java/org/apache/brooklyn/util/http/HttpTool.java index 52b8d7a435..7a3d5ac022 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/http/HttpTool.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/http/HttpTool.java @@ -103,12 +103,18 @@ public class HttpTool { static final ExecutorService executor = Executors.newCachedThreadPool(); + @Deprecated /** @deprecated since 1.1, use #getContentUnsafe if you don't need to trust the remote endpoint, otherwise use a more sophisticated method */ + public static URLConnection connectToUrl(String u) throws Exception { + return connectToUrlUnsafe(u); + } /** * Connects to the given url and returns the connection. * Caller should {@code connection.getInputStream().close()} the result of this * (especially if they are making heavy use of this method). - */ - public static URLConnection connectToUrl(String u) throws Exception { + * + * trusts all connections, so the content could be hacked and should not be relied upon */ + // only used in tests and test assertions + public static URLConnection connectToUrlUnsafe(String u) throws Exception { final URL url = new URL(u); final AtomicReference<Exception> exception = new AtomicReference<Exception>(); @@ -117,16 +123,8 @@ public class HttpTool { @Override public URLConnection call() { try { - HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { - @Override - public boolean verify(String s, SSLSession sslSession) { - return true; - } - }); - URLConnection connection = url.openConnection(); - TrustingSslSocketFactory.configure(connection); + URLConnection connection = SslTrustUtils.trustAll(url.openConnection()); connection.connect(); - connection.getContentLength(); // Make sure the connection is made. return connection; } catch (Exception e) { @@ -157,10 +155,14 @@ public class HttpTool { } } - - + @Deprecated /** @deprecated since 1.1, use #getContentUnsafe if you don't need to trust the remote endpoint, otherwise use a more sophisticated method */ public static int getHttpStatusCode(String url) throws Exception { - URLConnection connection = connectToUrl(url); + return getHttpStatusCodeUnsafe(url); + } + /** trusts all connections, so the content could be hacked */ + // only used in tests, test assertions, and pre-checks + public static int getHttpStatusCodeUnsafe(String url) throws Exception { + URLConnection connection = connectToUrlUnsafe(url); long startTime = System.currentTimeMillis(); int status = ((HttpURLConnection) connection).getResponseCode(); @@ -172,8 +174,9 @@ public class HttpTool { return status; } - - public static String getContent(String url) { + /** trusts all connections, so the content could be hacked */ + // only used in tests and test assertions + public static String getContentUnsafe(String url) { try { return Streams.readFullyStringAndClose(SslTrustUtils.trustAll(new URL(url).openConnection()).getInputStream()); } catch (Exception e) { @@ -181,9 +184,20 @@ public class HttpTool { } } + @Deprecated /** @deprecated since 1.1, use #getContentUnsafe if you don't need to trust the remote endpoint, otherwise use a more sophisticated method */ + public static String getContent(String url) { + return getContentUnsafe(url); + } + + @Deprecated /** @deprecated since 1.1, use #getErrorContentUnsafe if you don't need to trust the remote endpoint, otherwise use a more sophisticated method */ public static String getErrorContent(String url) { + return getErrorContentUnsafe(url); + } + /** trusts all connections, so the content could be hacked */ + // only used in tests and test assertions + public static String getErrorContentUnsafe(String url) { try { - HttpURLConnection connection = (HttpURLConnection) connectToUrl(url); + HttpURLConnection connection = (HttpURLConnection) connectToUrlUnsafe(url); long startTime = System.currentTimeMillis(); String err; @@ -242,7 +256,7 @@ public class HttpTool { public static HttpClientBuilder httpClientBuilder() { return new HttpClientBuilder(); } - + // TODO deprecate this and use the new Apache Commons HttpClientBuilder instead @SuppressWarnings("deprecation") public static class HttpClientBuilder { diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/http/TrustingSslSocketFactory.java b/utils/common/src/main/java/org/apache/brooklyn/util/http/TrustingSslSocketFactory.java index 6b035361cc..5968ef6e5e 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/http/TrustingSslSocketFactory.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/http/TrustingSslSocketFactory.java @@ -36,8 +36,7 @@ import org.slf4j.LoggerFactory; import com.google.common.base.Throwables; -// FIXME copied from brooklyn-core because core not visible here - +@Deprecated /** since 1.1 use org.apache.brooklyn.util.crypto.TrustingSslSocketFactory */ public class TrustingSslSocketFactory extends SSLSocketFactory { private static final Logger logger = LoggerFactory.getLogger(TrustingSslSocketFactory.class); @@ -57,7 +56,8 @@ public class TrustingSslSocketFactory extends SSLSocketFactory { } } - /** configures a connection to accept all certificates, if it is for https */ + /** configures a connection to accept all certificates, if it is for https + * @deprecated use {@link org.apache.brooklyn.util.crypto.SslTrustUtils#trustAll(URLConnection)} if required. */ public static <T extends URLConnection> T configure(T connection) { if (connection instanceof HttpsURLConnection) { ((HttpsURLConnection)connection).setSSLSocketFactory(getInstance()); diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/http/executor/apacheclient/HttpExecutorImpl.java b/utils/common/src/main/java/org/apache/brooklyn/util/http/executor/apacheclient/HttpExecutorImpl.java index 7642c901ff..79cd722366 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/http/executor/apacheclient/HttpExecutorImpl.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/http/executor/apacheclient/HttpExecutorImpl.java @@ -59,6 +59,13 @@ public class HttpExecutorImpl implements HttpExecutor { public HttpExecutorImpl() { } + HttpConfig config = DEFAULT_CONFIG; + + public HttpExecutorImpl withConfig(HttpConfig config) { + this.config = config; + return this; + } + @Override public HttpResponse execute(HttpRequest request) throws IOException { HttpConfig config = (request.config() != null) ? request.config() : DEFAULT_CONFIG; diff --git a/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpClient.java b/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpClient.java index 1d766ea6d5..b2375421e0 100644 --- a/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpClient.java +++ b/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpClient.java @@ -40,6 +40,7 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; +import com.google.common.base.Preconditions; import org.apache.brooklyn.util.core.crypto.SecureKeys; import org.apache.brooklyn.util.crypto.SslTrustUtils; import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent; @@ -59,12 +60,16 @@ public class JmxmpClient { } jmxc.close(); - } + } + + public void connectTls(String urlString, KeyStore keyStore, String keyStorePass, KeyStore trustStore) throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, InvalidKeyException, CertificateException, SecurityException, SignatureException, IOException, KeyManagementException { + connectTls(urlString, keyStore, keyStorePass, SecureKeys.getTrustManager(Preconditions.checkNotNull(trustStore, "trust store must be provided or explicit TRUST ALL manager"))); + } /** tries to connect to the given JMX url over tls, * optionally using the given keystore (if null using a randomly generated key) * and optionally using the given truststore (if null trusting all) */ - public void connectTls(String urlString, KeyStore keyStore, String keyStorePass, KeyStore trustStore) throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, InvalidKeyException, CertificateException, SecurityException, SignatureException, IOException, KeyManagementException { + public void connectTls(String urlString, KeyStore keyStore, String keyStorePass, TrustManager tms) throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, InvalidKeyException, CertificateException, SecurityException, SignatureException, IOException, KeyManagementException { Map env = new LinkedHashMap(); env.put("jmx.remote.profiles", JmxmpAgent.TLS_JMX_REMOTE_PROFILES); @@ -73,8 +78,6 @@ public class JmxmpClient { KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); //"SunX509"); kmf.init(keyStore, (keyStorePass!=null ? keyStorePass : "").toCharArray()); - TrustManager tms = trustStore!=null ? SecureKeys.getTrustManager(trustStore) : SslTrustUtils.TRUST_ALL; - SSLContext ctx = SSLContext.getInstance("TLSv1"); ctx.init(kmf.getKeyManagers(), new TrustManager[] { tms }, null); SSLSocketFactory ssf = ctx.getSocketFactory();
