Skip to content

Commit 27a3077

Browse files
authored
SCANJLIB-235 Set deprecated SSL and proxy properties for SQ < 10.6 (#203)
* SCANJLIB-235 Extract Http properties parsing in a separate class * Rename ServerConnection -> ScannerHttpClient * Move userAgent to HttpConfig * Move the other properties to HttpConfig * SCANJLIB-235 Set deprecated properties for SQ < 10.6
1 parent e05d3f9 commit 27a3077

20 files changed

+587
-270
lines changed

its/it-tests/src/test/java/com/sonar/scanner/lib/it/SSLTest.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ private static void startSSLTransparentReverseProxy(boolean requireClientAuth) t
115115

116116
// Handler Structure
117117
HandlerCollection handlers = new HandlerCollection();
118-
handlers.setHandlers(new Handler[]{proxyHandler(), new DefaultHandler()});
118+
handlers.setHandlers(new Handler[] {proxyHandler(), new DefaultHandler()});
119119
server.setHandler(handlers);
120120

121121
ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(httpConfig));
@@ -227,8 +227,7 @@ public void simple_analysis_with_server_and_without_client_certificate_is_failin
227227
p.matches(failedAnalysis + "Caused by: javax\\.net\\.ssl\\.SSLProtocolException: Broken pipe \\(Write failed\\).*") ||
228228
p.matches(failedAnalysis + "Caused by: javax\\.net\\.ssl\\.SSLHandshakeException: Received fatal alert: bad_certificate.*") ||
229229
p.matches(failedAnalysis + "Caused by: java\\.net\\.SocketException: Broken pipe.*") ||
230-
p.matches(failedAnalysis + "Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target.*")
231-
);
230+
p.matches(failedAnalysis + "Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target.*"));
232231
}
233232

234233
private static Path project(String projectName) {
@@ -238,7 +237,8 @@ private static Path project(String projectName) {
238237
@Test
239238
@UseDataProvider("variousClientTrustStores")
240239
public void simple_analysis_with_server_certificate(String clientTrustStore, String keyStorePassword, boolean useJavaSslProperties) throws Exception {
241-
assumeTrue("New SSL properties have been introduced in 10.6", ORCHESTRATOR.getServer().version().isGreaterThanOrEquals(10,6) || useJavaSslProperties);
240+
assumeTrue("Support for PKCS12 keystore generated by openssl was added in SQ 10.7", !clientTrustStore.endsWith("-openssl.p12") ||
241+
ORCHESTRATOR.getServer().version().isGreaterThanOrEquals(10, 7));
242242
startSSLTransparentReverseProxy(false);
243243
SimpleScanner scanner = new SimpleScanner();
244244

lib/src/main/java/org/sonarsource/scanner/lib/ScannerEngineBootstrapper.java

+62-16
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,18 @@
1919
*/
2020
package org.sonarsource.scanner.lib;
2121

22+
import java.net.InetSocketAddress;
2223
import java.nio.file.Path;
2324
import java.nio.file.Paths;
25+
import java.time.temporal.ChronoUnit;
2426
import java.util.HashMap;
2527
import java.util.Locale;
2628
import java.util.Map;
2729
import java.util.Objects;
30+
import javax.annotation.Nonnull;
2831
import javax.annotation.Nullable;
2932
import org.apache.commons.io.FileUtils;
33+
import org.apache.commons.lang3.StringUtils;
3034
import org.slf4j.Logger;
3135
import org.slf4j.LoggerFactory;
3236
import org.sonarsource.scanner.lib.internal.ArchResolver;
@@ -36,12 +40,12 @@
3640
import org.sonarsource.scanner.lib.internal.Paths2;
3741
import org.sonarsource.scanner.lib.internal.ScannerEngineLauncherFactory;
3842
import org.sonarsource.scanner.lib.internal.cache.FileCache;
39-
import org.sonarsource.scanner.lib.internal.http.ServerConnection;
43+
import org.sonarsource.scanner.lib.internal.http.HttpConfig;
44+
import org.sonarsource.scanner.lib.internal.http.ScannerHttpClient;
4045
import org.sonarsource.scanner.lib.internal.util.VersionUtils;
4146

4247
import static org.sonarsource.scanner.lib.ScannerProperties.SCANNER_ARCH;
4348
import static org.sonarsource.scanner.lib.ScannerProperties.SCANNER_OS;
44-
import static org.sonarsource.scanner.lib.internal.http.ServerConnection.removeTrailingSlash;
4549

4650
/**
4751
* Entry point to run a Sonar analysis programmatically.
@@ -57,14 +61,14 @@ public class ScannerEngineBootstrapper {
5761
private final IsolatedLauncherFactory launcherFactory;
5862
private final ScannerEngineLauncherFactory scannerEngineLauncherFactory;
5963
private final Map<String, String> bootstrapProperties = new HashMap<>();
60-
private final ServerConnection serverConnection;
64+
private final ScannerHttpClient scannerHttpClient;
6165
private final System2 system;
6266

6367
ScannerEngineBootstrapper(String app, String version, System2 system,
64-
ServerConnection serverConnection, IsolatedLauncherFactory launcherFactory,
68+
ScannerHttpClient scannerHttpClient, IsolatedLauncherFactory launcherFactory,
6569
ScannerEngineLauncherFactory scannerEngineLauncherFactory) {
6670
this.system = system;
67-
this.serverConnection = serverConnection;
71+
this.scannerHttpClient = scannerHttpClient;
6872
this.launcherFactory = launcherFactory;
6973
this.scannerEngineLauncherFactory = scannerEngineLauncherFactory;
7074
this.setBootstrapProperty(InternalProperties.SCANNER_APP, app)
@@ -73,7 +77,7 @@ public class ScannerEngineBootstrapper {
7377

7478
public static ScannerEngineBootstrapper create(String app, String version) {
7579
System2 system = new System2();
76-
return new ScannerEngineBootstrapper(app, version, system, new ServerConnection(),
80+
return new ScannerEngineBootstrapper(app, version, system, new ScannerHttpClient(),
7781
new IsolatedLauncherFactory(), new ScannerEngineLauncherFactory(system));
7882
}
7983

@@ -106,20 +110,62 @@ public ScannerEngineFacade bootstrap() {
106110
var isSimulation = properties.containsKey(InternalProperties.SCANNER_DUMP_TO_FILE);
107111
var sonarUserHome = resolveSonarUserHome(properties);
108112
var fileCache = FileCache.create(sonarUserHome);
109-
serverConnection.init(properties, sonarUserHome);
113+
var httpConfig = new HttpConfig(bootstrapProperties, sonarUserHome);
114+
scannerHttpClient.init(httpConfig);
110115
String serverVersion = null;
111116
if (!isSonarCloud) {
112-
serverVersion = getServerVersion(serverConnection, isSimulation, properties);
117+
serverVersion = getServerVersion(scannerHttpClient, isSimulation, properties);
113118
}
114119

115120
if (isSimulation) {
116121
return new SimulationScannerEngineFacade(properties, isSonarCloud, serverVersion);
117122
} else if (isSonarCloud || VersionUtils.isAtLeastIgnoringQualifier(serverVersion, SQ_VERSION_NEW_BOOTSTRAPPING)) {
118-
var launcher = scannerEngineLauncherFactory.createLauncher(serverConnection, fileCache, properties);
123+
var launcher = scannerEngineLauncherFactory.createLauncher(scannerHttpClient, fileCache, properties);
119124
return new NewScannerEngineFacade(properties, launcher, isSonarCloud, serverVersion);
120125
} else {
121-
var launcher = launcherFactory.createLauncher(serverConnection, fileCache);
122-
return new InProcessScannerEngineFacade(properties, launcher, false, serverVersion);
126+
var launcher = launcherFactory.createLauncher(scannerHttpClient, fileCache);
127+
var adaptedProperties = adaptDeprecatedProperties(properties, httpConfig);
128+
return new InProcessScannerEngineFacade(adaptedProperties, launcher, false, serverVersion);
129+
}
130+
}
131+
132+
/**
133+
* Older SonarQube versions used to rely on some different properties, or even {@link System} properties.
134+
* For backward compatibility, we adapt the new properties to the old format.
135+
*/
136+
@Nonnull
137+
Map<String, String> adaptDeprecatedProperties(Map<String, String> properties, HttpConfig httpConfig) {
138+
var adaptedProperties = new HashMap<>(properties);
139+
if (!adaptedProperties.containsKey(HttpConfig.READ_TIMEOUT_SEC_PROPERTY)) {
140+
adaptedProperties.put(HttpConfig.READ_TIMEOUT_SEC_PROPERTY, "" + httpConfig.getSocketTimeout().get(ChronoUnit.SECONDS));
141+
}
142+
var proxy = httpConfig.getProxy();
143+
if (proxy != null) {
144+
setSystemPropertyIfNotAlreadySet("http.proxyHost", ((InetSocketAddress) proxy.address()).getHostString());
145+
setSystemPropertyIfNotAlreadySet("https.proxyHost", ((InetSocketAddress) proxy.address()).getHostString());
146+
setSystemPropertyIfNotAlreadySet("http.proxyPort", "" + ((InetSocketAddress) proxy.address()).getPort());
147+
setSystemPropertyIfNotAlreadySet("https.proxyPort", "" + ((InetSocketAddress) proxy.address()).getPort());
148+
}
149+
setSystemPropertyIfNotAlreadySet("http.proxyUser", httpConfig.getProxyUser());
150+
setSystemPropertyIfNotAlreadySet("http.proxyPassword", httpConfig.getProxyPassword());
151+
152+
var keyStore = httpConfig.getSslConfig().getKeyStore();
153+
if (keyStore != null) {
154+
setSystemPropertyIfNotAlreadySet("javax.net.ssl.keyStore", keyStore.getPath().toString());
155+
setSystemPropertyIfNotAlreadySet("javax.net.ssl.keyStorePassword", keyStore.getKeyStorePassword());
156+
}
157+
var trustStore = httpConfig.getSslConfig().getTrustStore();
158+
if (trustStore != null) {
159+
setSystemPropertyIfNotAlreadySet("javax.net.ssl.trustStore", trustStore.getPath().toString());
160+
setSystemPropertyIfNotAlreadySet("javax.net.ssl.trustStorePassword", trustStore.getKeyStorePassword());
161+
}
162+
163+
return Map.copyOf(adaptedProperties);
164+
}
165+
166+
private void setSystemPropertyIfNotAlreadySet(String key, String value) {
167+
if (system.getProperty(key) == null && StringUtils.isNotBlank(value)) {
168+
System.setProperty(key, value);
123169
}
124170
}
125171

@@ -134,16 +180,16 @@ private static Path resolveSonarUserHome(Map<String, String> properties) {
134180
return Paths.get(sonarUserHome);
135181
}
136182

137-
private static String getServerVersion(ServerConnection serverConnection, boolean isSimulation, Map<String, String> properties) {
183+
private static String getServerVersion(ScannerHttpClient scannerHttpClient, boolean isSimulation, Map<String, String> properties) {
138184
if (isSimulation) {
139185
return properties.getOrDefault(InternalProperties.SCANNER_VERSION_SIMULATION, "5.6");
140186
}
141187

142188
try {
143-
return serverConnection.callRestApi("/analysis/version");
189+
return scannerHttpClient.callRestApi("/analysis/version");
144190
} catch (Exception e) {
145191
try {
146-
return serverConnection.callWebApi("/api/server/version");
192+
return scannerHttpClient.callWebApi("/api/server/version");
147193
} catch (Exception e2) {
148194
var ex = new IllegalStateException("Failed to get server version", e2);
149195
ex.addSuppressed(e);
@@ -154,8 +200,8 @@ private static String getServerVersion(ServerConnection serverConnection, boolea
154200

155201
private void initBootstrapDefaultValues() {
156202
setBootstrapPropertyIfNotAlreadySet(ScannerProperties.HOST_URL, getSonarCloudUrl());
157-
setBootstrapPropertyIfNotAlreadySet(ScannerProperties.API_BASE_URL, isSonarCloud(bootstrapProperties) ?
158-
SONARCLOUD_REST_API : (removeTrailingSlash(bootstrapProperties.get(ScannerProperties.HOST_URL)) + "/api/v2"));
203+
setBootstrapPropertyIfNotAlreadySet(ScannerProperties.API_BASE_URL,
204+
isSonarCloud(bootstrapProperties) ? SONARCLOUD_REST_API : (StringUtils.removeEnd(bootstrapProperties.get(ScannerProperties.HOST_URL), "/") + "/api/v2"));
159205
if (!bootstrapProperties.containsKey(SCANNER_OS)) {
160206
setBootstrapProperty(SCANNER_OS, new OsResolver(system, new Paths2()).getOs().name().toLowerCase(Locale.ENGLISH));
161207
}

lib/src/main/java/org/sonarsource/scanner/lib/internal/BootstrapIndexDownloader.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@
2323
import java.util.Collection;
2424
import org.slf4j.Logger;
2525
import org.slf4j.LoggerFactory;
26-
import org.sonarsource.scanner.lib.internal.http.ServerConnection;
26+
import org.sonarsource.scanner.lib.internal.http.ScannerHttpClient;
2727

2828
class BootstrapIndexDownloader {
2929

3030
private static final Logger LOG = LoggerFactory.getLogger(BootstrapIndexDownloader.class);
3131

32-
private final ServerConnection conn;
32+
private final ScannerHttpClient conn;
3333

34-
BootstrapIndexDownloader(ServerConnection conn) {
34+
BootstrapIndexDownloader(ScannerHttpClient conn) {
3535
this.conn = conn;
3636
}
3737

lib/src/main/java/org/sonarsource/scanner/lib/internal/IsolatedLauncherFactory.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
import org.sonarsource.scanner.lib.internal.batch.IsolatedLauncher;
3333
import org.sonarsource.scanner.lib.internal.cache.CachedFile;
3434
import org.sonarsource.scanner.lib.internal.cache.FileCache;
35-
import org.sonarsource.scanner.lib.internal.http.ServerConnection;
35+
import org.sonarsource.scanner.lib.internal.http.ScannerHttpClient;
3636

3737
public class IsolatedLauncherFactory {
3838

@@ -61,11 +61,11 @@ private IsolatedClassloader createClassLoader(List<Path> jarFiles, ClassloadRule
6161
return classloader;
6262
}
6363

64-
public IsolatedLauncherAndClassloader createLauncher(ServerConnection serverConnection, FileCache fileCache) {
64+
public IsolatedLauncherAndClassloader createLauncher(ScannerHttpClient scannerHttpClient, FileCache fileCache) {
6565
Set<String> unmaskRules = new HashSet<>();
6666
unmaskRules.add("org.sonarsource.scanner.lib.internal.batch.");
6767
ClassloadRules rules = new ClassloadRules(Collections.emptySet(), unmaskRules);
68-
LegacyScannerEngineDownloader legacyScannerEngineDownloader = new LegacyScannerEngineDownloaderFactory(serverConnection, fileCache).create();
68+
LegacyScannerEngineDownloader legacyScannerEngineDownloader = new LegacyScannerEngineDownloaderFactory(scannerHttpClient, fileCache).create();
6969
return createLauncher(legacyScannerEngineDownloader, rules);
7070
}
7171

lib/src/main/java/org/sonarsource/scanner/lib/internal/JavaRunnerFactory.java

+11-11
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
import org.sonarsource.scanner.lib.internal.cache.CachedFile;
4747
import org.sonarsource.scanner.lib.internal.cache.FileCache;
4848
import org.sonarsource.scanner.lib.internal.cache.HashMismatchException;
49-
import org.sonarsource.scanner.lib.internal.http.ServerConnection;
49+
import org.sonarsource.scanner.lib.internal.http.ScannerHttpClient;
5050
import org.sonarsource.scanner.lib.internal.util.CompressionUtils;
5151

5252
import static java.lang.String.format;
@@ -72,7 +72,7 @@ public JavaRunnerFactory(System2 system, ProcessWrapperFactory processWrapperFac
7272
this.processWrapperFactory = processWrapperFactory;
7373
}
7474

75-
public JavaRunner createRunner(ServerConnection serverConnection, FileCache fileCache, Map<String, String> properties) {
75+
public JavaRunner createRunner(ScannerHttpClient scannerHttpClient, FileCache fileCache, Map<String, String> properties) {
7676
String javaExecutablePropValue = properties.get(JAVA_EXECUTABLE_PATH);
7777
if (javaExecutablePropValue != null) {
7878
LOG.info("Using the configured java executable '{}'", javaExecutablePropValue);
@@ -82,7 +82,7 @@ public JavaRunner createRunner(ServerConnection serverConnection, FileCache file
8282
if (skipJreProvisioning) {
8383
LOG.info("JRE provisioning is disabled");
8484
} else {
85-
var cachedFile = getJreFromServer(serverConnection, fileCache, properties, true);
85+
var cachedFile = getJreFromServer(scannerHttpClient, fileCache, properties, true);
8686
if (cachedFile.isPresent()) {
8787
return new JavaRunner(cachedFile.get().getPathInCache(), cachedFile.get().isCacheHit() ? JreCacheHit.HIT : JreCacheHit.MISS);
8888
}
@@ -129,34 +129,34 @@ private Path findJavaInPath(String javaExe) {
129129
}
130130
}
131131

132-
private static Optional<CachedFile> getJreFromServer(ServerConnection serverConnection, FileCache fileCache, Map<String, String> properties, boolean retry) {
132+
private static Optional<CachedFile> getJreFromServer(ScannerHttpClient scannerHttpClient, FileCache fileCache, Map<String, String> properties, boolean retry) {
133133
String os = properties.get(SCANNER_OS);
134134
String arch = properties.get(SCANNER_ARCH);
135135
LOG.info("JRE provisioning: os[{}], arch[{}]", os, arch);
136136

137137
try {
138-
var jreMetadata = getJreMetadata(serverConnection, os, arch);
138+
var jreMetadata = getJreMetadata(scannerHttpClient, os, arch);
139139
if (jreMetadata.isEmpty()) {
140140
LOG.info("No JRE found for this OS/architecture");
141141
return Optional.empty();
142142
}
143143
var cachedFile = fileCache.getOrDownload(jreMetadata.get().getFilename(), jreMetadata.get().getSha256(), "SHA-256",
144-
new JreDownloader(serverConnection, jreMetadata.get()));
144+
new JreDownloader(scannerHttpClient, jreMetadata.get()));
145145
var extractedDirectory = extractArchive(cachedFile.getPathInCache());
146146
return Optional.of(new CachedFile(extractedDirectory.resolve(jreMetadata.get().javaPath), cachedFile.isCacheHit()));
147147
} catch (HashMismatchException e) {
148148
if (retry) {
149149
// A new JRE might have been published between the metadata fetch and the download
150150
LOG.warn("Failed to get the JRE, retrying...");
151-
return getJreFromServer(serverConnection, fileCache, properties, false);
151+
return getJreFromServer(scannerHttpClient, fileCache, properties, false);
152152
}
153153
throw e;
154154
}
155155
}
156156

157-
private static Optional<JreMetadata> getJreMetadata(ServerConnection serverConnection, String os, String arch) {
157+
private static Optional<JreMetadata> getJreMetadata(ScannerHttpClient scannerHttpClient, String os, String arch) {
158158
try {
159-
String response = serverConnection.callRestApi(format(API_PATH_JRE + "?os=%s&arch=%s", os, arch));
159+
String response = scannerHttpClient.callRestApi(format(API_PATH_JRE + "?os=%s&arch=%s", os, arch));
160160
Type listType = new TypeToken<ArrayList<JreMetadata>>() {
161161
}.getType();
162162
List<JreMetadata> jres = new Gson().fromJson(response, listType);
@@ -239,10 +239,10 @@ private static void extract(Path compressedFile, Path targetDir) throws IOExcept
239239
}
240240

241241
static class JreDownloader implements FileCache.Downloader {
242-
private final ServerConnection connection;
242+
private final ScannerHttpClient connection;
243243
private final JreMetadata jreMetadata;
244244

245-
JreDownloader(ServerConnection connection, JreMetadata jreMetadata) {
245+
JreDownloader(ScannerHttpClient connection, JreMetadata jreMetadata) {
246246
this.connection = connection;
247247
this.jreMetadata = jreMetadata;
248248
}

lib/src/main/java/org/sonarsource/scanner/lib/internal/LegacyScannerEngineDownloader.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import org.sonarsource.scanner.lib.internal.BootstrapIndexDownloader.JarEntry;
3131
import org.sonarsource.scanner.lib.internal.cache.CachedFile;
3232
import org.sonarsource.scanner.lib.internal.cache.FileCache;
33-
import org.sonarsource.scanner.lib.internal.http.ServerConnection;
33+
import org.sonarsource.scanner.lib.internal.http.ScannerHttpClient;
3434

3535
import static java.lang.String.format;
3636

@@ -70,9 +70,9 @@ private List<CachedFile> getOrDownloadScannerEngineFiles() {
7070
}
7171

7272
static class ScannerFileDownloader implements FileCache.Downloader {
73-
private final ServerConnection connection;
73+
private final ScannerHttpClient connection;
7474

75-
ScannerFileDownloader(ServerConnection conn) {
75+
ScannerFileDownloader(ScannerHttpClient conn) {
7676
this.connection = conn;
7777
}
7878

lib/src/main/java/org/sonarsource/scanner/lib/internal/LegacyScannerEngineDownloaderFactory.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,20 @@
2020
package org.sonarsource.scanner.lib.internal;
2121

2222
import org.sonarsource.scanner.lib.internal.cache.FileCache;
23-
import org.sonarsource.scanner.lib.internal.http.ServerConnection;
23+
import org.sonarsource.scanner.lib.internal.http.ScannerHttpClient;
2424

2525
class LegacyScannerEngineDownloaderFactory {
26-
private final ServerConnection serverConnection;
26+
private final ScannerHttpClient scannerHttpClient;
2727
private final FileCache fileCache;
2828

29-
LegacyScannerEngineDownloaderFactory(ServerConnection conn, FileCache fileCache) {
30-
this.serverConnection = conn;
29+
LegacyScannerEngineDownloaderFactory(ScannerHttpClient conn, FileCache fileCache) {
30+
this.scannerHttpClient = conn;
3131
this.fileCache = fileCache;
3232
}
3333

3434
LegacyScannerEngineDownloader create() {
35-
BootstrapIndexDownloader bootstrapIndexDownloader = new BootstrapIndexDownloader(serverConnection);
36-
LegacyScannerEngineDownloader.ScannerFileDownloader scannerFileDownloader = new LegacyScannerEngineDownloader.ScannerFileDownloader(serverConnection);
35+
BootstrapIndexDownloader bootstrapIndexDownloader = new BootstrapIndexDownloader(scannerHttpClient);
36+
LegacyScannerEngineDownloader.ScannerFileDownloader scannerFileDownloader = new LegacyScannerEngineDownloader.ScannerFileDownloader(scannerHttpClient);
3737
JarExtractor jarExtractor = new JarExtractor();
3838
return new LegacyScannerEngineDownloader(scannerFileDownloader, bootstrapIndexDownloader, fileCache, jarExtractor);
3939
}

0 commit comments

Comments
 (0)