diff --git a/src/main/java/org/simplify4u/plugins/AbstractPGPMojo.java b/src/main/java/org/simplify4u/plugins/AbstractPGPMojo.java index cfa99202..a5bb7299 100644 --- a/src/main/java/org/simplify4u/plugins/AbstractPGPMojo.java +++ b/src/main/java/org/simplify4u/plugins/AbstractPGPMojo.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Slawomir Jaranowski + * Copyright 2021 Slawomir Jaranowski * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugin.logging.Log; import org.apache.maven.plugins.annotations.Parameter; +import org.simplify4u.plugins.keyserver.KeyServerClientSettings; import org.simplify4u.plugins.keyserver.PGPKeysCache; import org.simplify4u.plugins.utils.PGPSignatureUtils; import org.slf4j.Logger; @@ -77,7 +78,7 @@ public abstract class AbstractPGPMojo extends AbstractMojo { /** * Choose which proxy to use (id from settings.xml in maven config). Uses no proxy if the proxy was not found. If it - * is not set, it will take the first active proxy if any or no proxy, if no active proxy was found) + * is not set, it will take the first active proxy if any or no proxy, if no active proxy was found. * * @since 1.8.0 */ @@ -124,7 +125,13 @@ public final Log getLog() { protected abstract void executeConfiguredMojo() throws MojoExecutionException, MojoFailureException; private void initPgpKeysCache() throws IOException { - pgpKeysCache.init(pgpKeysCachePath, pgpKeyServer, pgpKeyServerLoadBalance, proxyName); + + KeyServerClientSettings clientSettings = KeyServerClientSettings.builder() + .mavenSession(session) + .proxyName(proxyName) + .build(); + + pgpKeysCache.init(pgpKeysCachePath, pgpKeyServer, pgpKeyServerLoadBalance, clientSettings); } @Override diff --git a/src/main/java/org/simplify4u/plugins/keyserver/KeyServerClientSettings.java b/src/main/java/org/simplify4u/plugins/keyserver/KeyServerClientSettings.java new file mode 100644 index 00000000..9a606bfa --- /dev/null +++ b/src/main/java/org/simplify4u/plugins/keyserver/KeyServerClientSettings.java @@ -0,0 +1,67 @@ +/* + * Copyright 2021 Slawomir Jaranowski + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.simplify4u.plugins.keyserver; + +import java.util.Collections; +import java.util.Optional; + +import lombok.Builder; +import lombok.Getter; +import lombok.NonNull; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.settings.Proxy; + +/** + * Provide settings for key server client connection. + */ +@Builder +@Getter +public class KeyServerClientSettings { + + private static final int DEFAULT_CONNECT_TIMEOUT = 5000; + private static final int DEFAULT_READ_TIMEOUT = 20000; + public static final int DEFAULT_MAX_RETRIES = 10; + + @NonNull + MavenSession mavenSession; + + String proxyName; + + @Builder.Default + int connectTimeout = DEFAULT_CONNECT_TIMEOUT; + + @Builder.Default + int readTimeout = DEFAULT_READ_TIMEOUT; + + @Builder.Default + int maxRetries = DEFAULT_MAX_RETRIES; + + public Optional getProxy() { + + if (proxyName == null) { + return Optional.ofNullable(mavenSession.getSettings().getActiveProxy()); + } + + return Optional.ofNullable(mavenSession.getSettings().getProxies()).orElse(Collections.emptyList()) + .stream() + .filter(proxy -> proxyName.equalsIgnoreCase(proxy.getId())) + .findFirst(); + } + + public boolean isOffline() { + return mavenSession.isOffline(); + } +} diff --git a/src/main/java/org/simplify4u/plugins/keyserver/PGPKeysCache.java b/src/main/java/org/simplify4u/plugins/keyserver/PGPKeysCache.java index 39c42c3c..5e0725de 100644 --- a/src/main/java/org/simplify4u/plugins/keyserver/PGPKeysCache.java +++ b/src/main/java/org/simplify4u/plugins/keyserver/PGPKeysCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Slawomir Jaranowski + * Copyright 2021 Slawomir Jaranowski * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,6 @@ import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; import java.util.stream.Collectors; -import javax.inject.Inject; import javax.inject.Named; import static com.google.common.util.concurrent.Uninterruptibles.sleepUninterruptibly; @@ -45,7 +44,6 @@ import io.vavr.control.Try; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.simplify4u.plugins.utils.MavenProxy; import org.simplify4u.plugins.utils.PGPKeyId; import org.simplify4u.plugins.utils.PublicKeyUtils; import org.slf4j.Logger; @@ -61,25 +59,27 @@ public class PGPKeysCache { private static final Logger LOGGER = LoggerFactory.getLogger(PGPKeysCache.class); private static final String NL = System.lineSeparator(); + private static final Object LOCK = new Object(); private static final Pattern KEY_SERVERS_SPLIT_PATTERN = Pattern.compile("[;,\\s]"); - private final MavenProxy mavenProxy; - private File cachePath; private KeyServerList keyServerList; - - private static final Object LOCK = new Object(); - - @Inject - PGPKeysCache(MavenProxy mavenProxy) { - this.mavenProxy = mavenProxy; + PGPKeysCache() { } - public void init(File cachePath, String keyServers, boolean loadBalance, String proxyName) + /** + * Init Keys cache. + * @param cachePath a path where cache will be stored + * @param keyServers a list of key servers addresses + * @param loadBalance if use key servers list in balance mode + * @param clientSettings a kay server client settings + * @throws IOException in case of problems + */ + public void init(File cachePath, String keyServers, boolean loadBalance, KeyServerClientSettings clientSettings) throws IOException { - init(cachePath, prepareClients(keyServers, proxyName), loadBalance); + init(cachePath, prepareClients(keyServers, clientSettings), loadBalance); } // used by test @@ -105,7 +105,7 @@ void init(File cachePath, List pgpKeysServerClients, boolea } } - List prepareClients(String keyServers, String proxyName) { + List prepareClients(String keyServers, KeyServerClientSettings clientSettings) { List keyServersList = Arrays.stream(KEY_SERVERS_SPLIT_PATTERN.split(keyServers)) .map(String::trim) @@ -114,7 +114,7 @@ List prepareClients(String keyServers, String proxyName) { return keyServersList.stream() .map(keyserver -> Try.of(() -> - PGPKeysServerClient.getClient(keyserver, mavenProxy.getProxyByName(proxyName))).get()) + PGPKeysServerClient.getClient(keyserver, clientSettings)).get()) .collect(Collectors.toList()); } @@ -149,9 +149,15 @@ public String getUrlForShowKey(PGPKeyId keyID) { return keyServerList.getUriForShowKey(keyID).toString(); } + /** + * Return Public Key Ring from local cache or from key server. + * + * @param keyID a keyId for lookup + * @return Public Key Ring for given key + * @throws IOException in case of problems + */ public PGPPublicKeyRing getKeyRing(PGPKeyId keyID) throws IOException { - String path = keyID.getHashPath(); File keyFile = new File(cachePath, path); diff --git a/src/main/java/org/simplify4u/plugins/keyserver/PGPKeysServerClient.java b/src/main/java/org/simplify4u/plugins/keyserver/PGPKeysServerClient.java index 2a407a43..1cdfd335 100644 --- a/src/main/java/org/simplify4u/plugins/keyserver/PGPKeysServerClient.java +++ b/src/main/java/org/simplify4u/plugins/keyserver/PGPKeysServerClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Slawomir Jaranowski + * Copyright 2021 Slawomir Jaranowski * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import java.util.Arrays; import java.util.List; import java.util.Locale; +import java.util.Optional; import java.util.function.Function; import com.google.common.io.ByteStreams; @@ -60,83 +61,43 @@ */ abstract class PGPKeysServerClient { - private final Proxy proxy; + private static final List> IGNORE_EXCEPTION_FOR_RETRY = + Arrays.asList(PGPKeyNotFound.class, UnknownHostException.class); + + private final KeyServerClientSettings keyServerClientSettings; @FunctionalInterface public interface OnRetryConsumer { void onRetry(InetAddress address, int numberOfRetryAttempts, Duration waitInterval, Throwable lastThrowable); - } - - private static final int DEFAULT_CONNECT_TIMEOUT = 5000; - private static final int DEFAULT_READ_TIMEOUT = 20000; - public static final int DEFAULT_MAX_RETRIES = 10; - private static final List> IGNORE_EXCEPTION_FOR_RETRY = - Arrays.asList(PGPKeyNotFound.class, UnknownHostException.class); + } private final URI keyserver; - private final int connectTimeout; - private final int readTimeout; - private final int maxAttempts; /** * Protected constructor for {@code PGPKeysServerClient}. * - * @param keyserver - * The URI of the target key server. - * @param connectTimeout - * The timeout (in milliseconds) that the client should wait to establish a connection to - * the PGP server. - * @param readTimeout - * The timeout (in milliseconds) that the client should wait for data from the PGP server. - * @param maxAttempts - * The maximum number of automatically retry request by client + * @param keyserver The URI of the target key server. + * @param keyServerClientSettings The client configuration. * - * @see #getClient(String, Proxy) - * @see #getClient(String, Proxy, int, int, int) + * @see #getClient(String, KeyServerClientSettings) */ - protected PGPKeysServerClient(URI keyserver, int connectTimeout, int readTimeout, int maxAttempts, Proxy proxy) { + protected PGPKeysServerClient(URI keyserver, KeyServerClientSettings keyServerClientSettings) { this.keyserver = keyserver; - this.connectTimeout = connectTimeout; - this.readTimeout = readTimeout; - this.maxAttempts = maxAttempts; - this.proxy = proxy; - } - - /** - * Create a PGP key server client for a given URL. - * - * @param keyServer - * The key server address / URL. - * - * @param proxy the proxy server to use (if any) - * @return The right PGP client for the given address. - */ - static PGPKeysServerClient getClient(String keyServer, Proxy proxy) throws IOException { - return getClient(keyServer, proxy, DEFAULT_CONNECT_TIMEOUT, DEFAULT_READ_TIMEOUT, DEFAULT_MAX_RETRIES); + this.keyServerClientSettings = keyServerClientSettings; } /** * Create a PGP key server for a given URL. * - * @param keyServer - * The key server address / URL. - * @param proxy proxy server config - * @param connectTimeout - * The timeout (in milliseconds) that the client should wait to establish a connection to - * the PGP server. - * @param readTimeout - * The timeout (in milliseconds) that the client should wait for data from the PGP server. - * @param maxAttempts - * The maximum number of automatically retry request by client + * @param keyServer The key server address / URL. * * @return The right PGP client for the given address. * - * @throws IOException - * If some problem during client create. + * @throws IOException If some problem during client create. */ - static PGPKeysServerClient getClient(String keyServer, Proxy proxy, - int connectTimeout, int readTimeout, int maxAttempts) throws IOException { + static PGPKeysServerClient getClient(String keyServer, KeyServerClientSettings keyServerClientSettings) + throws IOException { final URI uri = Try.of(() -> new URI(keyServer)) .getOrElseThrow((Function) IOException::new); @@ -145,11 +106,11 @@ static PGPKeysServerClient getClient(String keyServer, Proxy proxy, switch (protocol) { case "hkp": case "http": - return new PGPKeysServerClientHttp(uri, connectTimeout, readTimeout, maxAttempts, proxy); + return new PGPKeysServerClientHttp(uri, keyServerClientSettings); case "hkps": case "https": - return new PGPKeysServerClientHttps(uri, connectTimeout, readTimeout, maxAttempts, proxy); + return new PGPKeysServerClientHttps(uri, keyServerClientSettings); default: throw new IOException("Unsupported protocol: " + protocol); @@ -163,8 +124,7 @@ private static String getQueryStringForGetKey(PGPKeyId keyID) { /** * Create URI for key download. * - * @param keyID - * key ID + * @param keyID key ID * * @return URI with given key */ @@ -181,8 +141,7 @@ private static String getQueryStringForShowKey(PGPKeyId keyID) { /** * Create URI for key lookup. * - * @param keyID - * key ID + * @param keyID key ID * * @return URI with given key */ @@ -193,34 +152,34 @@ URI getUriForShowKey(PGPKeyId keyID) { } /** - * Requests the PGP key with the specified key ID from the server and copies it to the specified - * output stream. + * Requests the PGP key with the specified key ID from the server and copies it to the specified output stream. * *

If the request fails due to connectivity issues or server load, the request will be - * retried automatically according to the configuration of the provided retry handler. If the - * request still fails after exhausting retries, the final exception will be re-thrown. + * retried automatically according to the configuration of the provided retry handler. If the request still fails + * after exhausting retries, the final exception will be re-thrown. * - * @param keyId - * The ID of the key to request from the server. - * @param outputStream - * The output stream to which the key will be written. - * @param onRetryConsumer - * The consumer which will be call on retry occurs + * @param keyId The ID of the key to request from the server. + * @param outputStream The output stream to which the key will be written. + * @param onRetryConsumer The consumer which will be call on retry occurs * - * @throws IOException - * If the request fails, or the key cannot be written to the output stream. + * @throws IOException If the request fails, or the key cannot be written to the output stream. */ void copyKeyToOutputStream(PGPKeyId keyId, OutputStream outputStream, OnRetryConsumer onRetryConsumer) throws IOException { final URI keyUri = getUriForGetKey(keyId); + if (keyServerClientSettings.isOffline()) { + throw new IOException("Not possible to download key: " + keyUri + " in offline mode."); + } + final HttpUriRequest request = new HttpGet(keyUri); - // use one instance of planer in order to remember failed hosts - final HttpRoutePlanner planer = proxy == null ? new RoundRobinRouterPlaner() : getNewProxyRoutePlanner(); + final HttpRoutePlanner planer = keyServerClientSettings.getProxy() + .map(PGPKeysServerClient::getNewProxyRoutePlanner) + .orElseGet(RoundRobinRouterPlaner::new); RetryConfig config = RetryConfig.custom() - .maxAttempts(maxAttempts) + .maxAttempts(keyServerClientSettings.getMaxRetries()) .intervalFunction(IntervalFunction.ofExponentialBackoff()) .retryOnException(PGPKeysServerClient::shouldRetryOnException) .build(); @@ -247,7 +206,7 @@ void copyKeyToOutputStream(PGPKeyId keyId, OutputStream outputStream, OnRetryCon } } - private HttpRoutePlanner getNewProxyRoutePlanner() { + private static HttpRoutePlanner getNewProxyRoutePlanner(Proxy proxy) { HttpHost httpHost = new HttpHost(proxy.getHost(), proxy.getPort()); return new DefaultProxyRoutePlanner(httpHost); } @@ -265,15 +224,18 @@ private static boolean shouldRetryOnException(Throwable throwable) { } private void processOnRetry(RetryEvent event, Duration waitInterval, - HttpRoutePlanner planer, OnRetryConsumer onRetryConsumer) { + HttpRoutePlanner planer, OnRetryConsumer onRetryConsumer) { InetAddress targetAddress = null; if (planer instanceof RoundRobinRouterPlaner) { // inform planer about error on last roue - HttpRoute httpRoute = ((RoundRobinRouterPlaner)planer).lastRouteCauseError(); + HttpRoute httpRoute = ((RoundRobinRouterPlaner) planer).lastRouteCauseError(); targetAddress = Try.of(() -> httpRoute.getTargetHost().getAddress()).getOrElse((InetAddress) null); - } else if (proxy != null) { - targetAddress = Try.of(() -> InetAddress.getByName(proxy.getHost())).getOrElse((InetAddress) null); + } else if (planer instanceof DefaultProxyRoutePlanner) { + targetAddress = keyServerClientSettings.getProxy() + .map(Proxy::getHost) + .map(host -> Try.of(() -> InetAddress.getByName(host)).getOrNull()) + .orElse(null); } // inform caller about retry @@ -289,20 +251,16 @@ private void processOnRetry(RetryEvent event, Duration waitInterval, /** - * Verify that the provided response was successful, and then copy the response to the given - * output buffer. + * Verify that the provided response was successful, and then copy the response to the given output buffer. * *

If the response was not successful (e.g. not a "200 OK") status code, or the response * payload was empty, an {@link IOException} will be thrown. * - * @param response - * A representation of the response from the server. - * @param outputStream - * The stream to which the response data will be written. + * @param response A representation of the response from the server. + * @param outputStream The stream to which the response data will be written. * - * @throws IOException - * If the response was unsuccessful, did not contain any data, or could not be written - * completely to the target output stream. + * @throws IOException If the response was unsuccessful, did not contain any data, or could not be written + * completely to the target output stream. */ private static void processKeyResponse(CloseableHttpResponse response, OutputStream outputStream) throws IOException { @@ -330,8 +288,7 @@ private static void processKeyResponse(CloseableHttpResponse response, OutputStr /** * Build an HTTP client with the given router planer. * - * @param planer - * The router planer for http client, used for load balancing + * @param planer The router planer for http client, used for load balancing * * @return The new HTTP client instance. */ @@ -349,33 +306,36 @@ private CloseableHttpClient buildClient(HttpRoutePlanner planer) { /** * Set connect and read timeouts for an HTTP client that is being built. * - * @param builder - * The client builder to which timeouts will be applied. + * @param builder The client builder to which timeouts will be applied. */ private void applyTimeouts(final HttpClientBuilder builder) { final RequestConfig requestConfig = RequestConfig .custom() - .setConnectionRequestTimeout(this.connectTimeout) - .setConnectTimeout(this.connectTimeout) - .setSocketTimeout(this.readTimeout) + .setConnectionRequestTimeout(keyServerClientSettings.getConnectTimeout()) + .setConnectTimeout(keyServerClientSettings.getConnectTimeout()) + .setSocketTimeout(keyServerClientSettings.getReadTimeout()) .build(); builder.setDefaultRequestConfig(requestConfig); } protected HttpClientBuilder setupProxy(HttpClientBuilder clientBuilder) { - if (this.proxy == null) { + + Optional optProxy = keyServerClientSettings.getProxy(); + if (!optProxy.isPresent()) { return clientBuilder; } + Proxy proxy = optProxy.get(); + if (proxy.getUsername() != null && !proxy.getUsername().isEmpty() && - proxy.getPassword() != null && !proxy.getPassword().isEmpty()) { + proxy.getPassword() != null && !proxy.getPassword().isEmpty()) { clientBuilder.setProxyAuthenticationStrategy(ProxyAuthenticationStrategy.INSTANCE); BasicCredentialsProvider basicCredentialsProvider = new BasicCredentialsProvider(); AuthScope proxyAuthScope = new AuthScope(proxy.getHost(), proxy.getPort()); UsernamePasswordCredentials proxyAuthentication = - new UsernamePasswordCredentials(proxy.getUsername(), proxy.getPassword()); + new UsernamePasswordCredentials(proxy.getUsername(), proxy.getPassword()); basicCredentialsProvider.setCredentials(proxyAuthScope, proxyAuthentication); clientBuilder.setDefaultCredentialsProvider(basicCredentialsProvider); } diff --git a/src/main/java/org/simplify4u/plugins/keyserver/PGPKeysServerClientHttp.java b/src/main/java/org/simplify4u/plugins/keyserver/PGPKeysServerClientHttp.java index b87c4f52..12902003 100644 --- a/src/main/java/org/simplify4u/plugins/keyserver/PGPKeysServerClientHttp.java +++ b/src/main/java/org/simplify4u/plugins/keyserver/PGPKeysServerClientHttp.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Slawomir Jaranowski + * Copyright 2021 Slawomir Jaranowski * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,17 +21,16 @@ import io.vavr.control.Try; import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.maven.settings.Proxy; /** * Implementation of a client for requesting keys from PGP key servers over HKP/HTTP. */ class PGPKeysServerClientHttp extends PGPKeysServerClient { - protected PGPKeysServerClientHttp(URI keyserver, int connectTimeout, int readTimeout, int maxAttempts, Proxy proxy) + protected PGPKeysServerClientHttp(URI keyserver, KeyServerClientSettings keyServerClientSettings) throws IOException { - super(prepareKeyServerURI(keyserver), connectTimeout, readTimeout, maxAttempts, proxy); + super(prepareKeyServerURI(keyserver), keyServerClientSettings); } private static URI prepareKeyServerURI(URI keyServer) throws IOException { diff --git a/src/main/java/org/simplify4u/plugins/keyserver/PGPKeysServerClientHttps.java b/src/main/java/org/simplify4u/plugins/keyserver/PGPKeysServerClientHttps.java index 1b1e6d4d..3601d58d 100644 --- a/src/main/java/org/simplify4u/plugins/keyserver/PGPKeysServerClientHttps.java +++ b/src/main/java/org/simplify4u/plugins/keyserver/PGPKeysServerClientHttps.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Slawomir Jaranowski + * Copyright 2021 Slawomir Jaranowski * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,6 @@ import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; -import org.apache.maven.settings.Proxy; /** * Implementation of a client for requesting keys from PGP key servers over HKPS/HTTPS. @@ -40,16 +39,16 @@ class PGPKeysServerClientHttps extends PGPKeysServerClient { private final SSLConnectionSocketFactory sslSocketFactory; - protected PGPKeysServerClientHttps(URI uri, int connectTimeout, int readTimeout, int maxAttempts, Proxy proxy) + protected PGPKeysServerClientHttps(URI uri, KeyServerClientSettings keyServerClientSettings) throws IOException { - super(prepareKeyServerURI(uri), connectTimeout, readTimeout, maxAttempts, proxy); + super(prepareKeyServerURI(uri), keyServerClientSettings); try { if (uri.getHost().toLowerCase(Locale.ROOT).endsWith("sks-keyservers.net")) { final CertificateFactory cf = CertificateFactory.getInstance("X.509"); final Certificate ca = cf.generateCertificate( - getClass().getClassLoader().getResourceAsStream("sks-keyservers.netCA.pem")); + Thread.currentThread().getContextClassLoader().getResourceAsStream("sks-keyservers.netCA.pem")); final KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); diff --git a/src/main/java/org/simplify4u/plugins/utils/MavenProxy.java b/src/main/java/org/simplify4u/plugins/utils/MavenProxy.java deleted file mode 100644 index 4df99c52..00000000 --- a/src/main/java/org/simplify4u/plugins/utils/MavenProxy.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2020 Slawomir Jaranowski - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.simplify4u.plugins.utils; - -import java.util.Collections; -import java.util.Optional; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; - -import org.apache.maven.settings.Proxy; -import org.apache.maven.settings.Settings; - -@Named -@Singleton -public class MavenProxy { - - private final Settings settings; - - @Inject - public MavenProxy(Settings settings) { - this.settings = settings; - } - - public Proxy getProxyByName(String proxyName) { - - if (proxyName == null) { - return settings.getActiveProxy(); - } - - return Optional.ofNullable(settings.getProxies()).orElse(Collections.emptyList()) - .stream() - .filter(proxy -> proxyName.equalsIgnoreCase(proxy.getId())) - .findFirst() - .orElse(null); - } -} diff --git a/src/test/java/org/simplify4u/plugins/AbstractPGPMojoTest.java b/src/test/java/org/simplify4u/plugins/AbstractPGPMojoTest.java index 947bf8bc..792b90bb 100644 --- a/src/test/java/org/simplify4u/plugins/AbstractPGPMojoTest.java +++ b/src/test/java/org/simplify4u/plugins/AbstractPGPMojoTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Slawomir Jaranowski + * Copyright 2021 Slawomir Jaranowski * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,10 +18,14 @@ import java.io.IOException; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; +import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.mockito.InjectMocks; @@ -54,6 +58,9 @@ protected void executeConfiguredMojo() { @Mock private PGPKeysCache pgpKeysCache; + @Mock + private MavenSession mavenSession; + @Spy @InjectMocks private TestMojo mojo; @@ -88,7 +95,7 @@ void shouldExecute() throws MojoFailureException, MojoExecutionException, IOExce // then verify(mojo).executeConfiguredMojo(); - verify(pgpKeysCache).init(null, null, false, null); + verify(pgpKeysCache).init(isNull(), isNull(), eq(false), any()); verifyNoInteractions(logger); } } diff --git a/src/test/java/org/simplify4u/plugins/PGPShowMojoTest.java b/src/test/java/org/simplify4u/plugins/PGPShowMojoTest.java index b2adf3be..d501821a 100644 --- a/src/test/java/org/simplify4u/plugins/PGPShowMojoTest.java +++ b/src/test/java/org/simplify4u/plugins/PGPShowMojoTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Slawomir Jaranowski + * Copyright 2021 Slawomir Jaranowski * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,6 +32,7 @@ import static org.simplify4u.plugins.ArtifactResolver.SignatureRequirement.NONE; import org.apache.maven.artifact.Artifact; +import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.repository.RepositorySystem; @@ -67,9 +68,13 @@ public class PGPShowMojoTest { @Mock private RepositorySystem repositorySystem; + @Mock + private MavenSession session; + @InjectMocks private PGPShowMojo mojo; + @Test void shouldReturnMojoName() { assertThat(mojo.getMojoName()).isEqualTo(PGPShowMojo.MOJO_NAME); @@ -125,7 +130,7 @@ void shouldProcessArtifact() throws MojoFailureException, MojoExecutionException verify(pgpSignatureUtils).getSignatureInfo(artifact, artifactAsc, pgpKeysCache); verify(pgpSignatureUtils).keyAlgorithmName(anyInt()); - verify(pgpKeysCache).init(null, null, false, null); + verify(pgpKeysCache).init(isNull(), isNull(), eq(false), any()); verifyNoMoreInteractions(artifactResolver, pgpKeysCache, pgpSignatureUtils, repositorySystem); } @@ -152,7 +157,7 @@ void shouldProcessArtifactWithPom() throws MojoFailureException, MojoExecutionEx verify(artifactResolver).resolveSignatures(anyCollection(), eq(NONE)); - verify(pgpKeysCache).init(null, null, false, null); + verify(pgpKeysCache).init(isNull(), isNull(), eq(false), any()); verifyNoMoreInteractions(artifactResolver, pgpKeysCache, pgpSignatureUtils, repositorySystem); } @@ -190,7 +195,7 @@ void shouldFailForNotResolvedArtifact() throws MojoExecutionException, IOExcepti verify(pgpSignatureUtils).keyAlgorithmName(anyInt()); - verify(pgpKeysCache).init(null, null, false, null); + verify(pgpKeysCache).init(isNull(), isNull(), eq(false), any()); verifyNoMoreInteractions(artifactResolver, pgpKeysCache, pgpSignatureUtils, repositorySystem); } @@ -229,7 +234,7 @@ void shouldFailForNotResolvedSignature() throws MojoExecutionException, IOExcept verify(pgpSignatureUtils).keyAlgorithmName(anyInt()); - verify(pgpKeysCache).init(null, null, false, null); + verify(pgpKeysCache).init(isNull(), isNull(), eq(false), any()); verifyNoMoreInteractions(artifactResolver, pgpKeysCache, pgpSignatureUtils, repositorySystem); } diff --git a/src/test/java/org/simplify4u/plugins/utils/MavenProxyTest.java b/src/test/java/org/simplify4u/plugins/keyserver/KeyServerClientSettingsTest.java similarity index 66% rename from src/test/java/org/simplify4u/plugins/utils/MavenProxyTest.java rename to src/test/java/org/simplify4u/plugins/keyserver/KeyServerClientSettingsTest.java index b73c9a7c..842832d7 100644 --- a/src/test/java/org/simplify4u/plugins/utils/MavenProxyTest.java +++ b/src/test/java/org/simplify4u/plugins/keyserver/KeyServerClientSettingsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Slawomir Jaranowski + * Copyright 2021 Slawomir Jaranowski * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.simplify4u.plugins.utils; +package org.simplify4u.plugins.keyserver; import java.util.Arrays; import java.util.List; +import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.times; @@ -25,10 +26,9 @@ import static org.mockito.Mockito.when; import static org.simplify4u.plugins.utils.ProxyUtil.makeMavenProxy; +import org.apache.maven.execution.MavenSession; import org.apache.maven.settings.Proxy; import org.apache.maven.settings.Settings; -import org.assertj.core.api.Condition; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; import org.testng.annotations.Listeners; @@ -38,13 +38,13 @@ * test on methods in the mojo itself */ @Listeners(MockitoTestNGListener.class) -public class MavenProxyTest { +public class KeyServerClientSettingsTest { @Mock - private Settings settings; + private MavenSession mavenSession; - @InjectMocks - private MavenProxy mavenProxy; + @Mock + private Settings settings; /** * test that if we set a proxy, we want to ensure that it is the right one from our config @@ -57,13 +57,18 @@ public void testIfProxyDeterminationWorksUsingIDs() { makeMavenProxy(null, null, "p1", true), makeMavenProxy(null, null, "p2", false)); + when(mavenSession.getSettings()).thenReturn(settings); when(settings.getProxies()).thenReturn(proxies); - assertThat(mavenProxy.getProxyByName("p2").getId()).isEqualTo("p2"); + Optional p1 = KeyServerClientSettings.builder().mavenSession(mavenSession).proxyName("p1").build().getProxy(); + assertThat(p1).map(Proxy::getId).hasValue("p1"); + + Optional p2 = KeyServerClientSettings.builder().mavenSession(mavenSession).proxyName("p2").build().getProxy(); + assertThat(p2).map(Proxy::getId).hasValue("p2"); - assertThat(mavenProxy.getProxyByName("p1").getId()).isEqualTo("p1"); + Optional p3 = KeyServerClientSettings.builder().mavenSession(mavenSession).proxyName("p3").build().getProxy(); - assertThat(mavenProxy.getProxyByName("p3")).isNull(); + assertThat(p3).isEmpty(); verify(settings, times(3)).getProxies(); verifyNoMoreInteractions(settings); @@ -76,11 +81,11 @@ public void testIfProxyDeterminationWorksUsingIDs() { @Test public void testIfProxyDeterminationWorksUsinFirstActive() { + when(mavenSession.getSettings()).thenReturn(settings); when(settings.getActiveProxy()).thenReturn(makeMavenProxy("p5")); - assertThat(mavenProxy.getProxyByName(null)) - .isNotNull() - .is(new Condition<>(p -> "p5".equals(p.getId()), "")); + Optional proxy = KeyServerClientSettings.builder().mavenSession(mavenSession).build().getProxy(); + assertThat(proxy).map(Proxy::getId).hasValue("p5"); verify(settings).getActiveProxy(); verifyNoMoreInteractions(settings); diff --git a/src/test/java/org/simplify4u/plugins/keyserver/PGPKeysServerClientIT.java b/src/test/java/org/simplify4u/plugins/keyserver/PGPKeysServerClientIT.java index e75bfaca..f056d273 100644 --- a/src/test/java/org/simplify4u/plugins/keyserver/PGPKeysServerClientIT.java +++ b/src/test/java/org/simplify4u/plugins/keyserver/PGPKeysServerClientIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Slawomir Jaranowski + * Copyright 2021 Slawomir Jaranowski * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,12 +23,16 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import static org.mockserver.model.HttpRequest.request; import static org.mockserver.model.HttpResponse.response; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.settings.Settings; import org.mockserver.client.MockServerClient; import org.mockserver.configuration.ConfigurationProperties; import org.mockserver.integration.ClientAndServer; @@ -45,6 +49,8 @@ public class PGPKeysServerClientIT { private ClientAndServer mockServer; + private MavenSession mavenSession; + @DataProvider(name = "goodServerUrls") Object[][] goodServerUrls() { return new Object[][]{ @@ -106,6 +112,9 @@ public void setupMockServer() { .when(request().withPath("/502")) .respond(response().withStatusCode(502)); + mavenSession = mock(MavenSession.class); + when(mavenSession.getSettings()).thenReturn(mock(Settings.class)); + } @AfterClass(alwaysRun = true) @@ -119,7 +128,11 @@ public void testClient(String keyServerUrl) throws Exception { tempFile.deleteOnExit(); - final PGPKeysServerClient client = PGPKeysServerClient.getClient(keyServerUrl, null); + KeyServerClientSettings clientSettings = KeyServerClientSettings.builder() + .mavenSession(mavenSession) + .build(); + + final PGPKeysServerClient client = PGPKeysServerClient.getClient(keyServerUrl, clientSettings); try (FileOutputStream outputStream = new FileOutputStream(tempFile)) { client.copyKeyToOutputStream(TEST_KEYID, outputStream, null); @@ -130,8 +143,8 @@ public void testClient(String keyServerUrl) throws Exception { @Test(dataProvider = "badServerUrls") public void testClientRetry(final String targetUrl, - final String expectedExceptionString, - final boolean shouldRetry) throws Exception { + final String expectedExceptionString, + final boolean shouldRetry) throws Exception { int maxRetries = 2; AtomicInteger attemptedRetries = new AtomicInteger(0); @@ -139,8 +152,15 @@ public void testClientRetry(final String targetUrl, // We use short timeouts for both timeouts since we don't want to hold up the tests on URLs // we know will take a while. + KeyServerClientSettings clientSettings = KeyServerClientSettings.builder() + .mavenSession(mavenSession) + .connectTimeout(SHORT_TEST_TIMEOUT) + .readTimeout(SHORT_TEST_TIMEOUT) + .maxRetries(maxRetries) + .build(); + final PGPKeysServerClient client - = new StubbedClient(targetUri, SHORT_TEST_TIMEOUT, SHORT_TEST_TIMEOUT, maxRetries); + = new StubbedClient(targetUri, clientSettings); IOException caughtException = null; @@ -166,14 +186,13 @@ public void testClientRetry(final String targetUrl, * A special key client that allows the URL the client is requesting to be stubbed-out by tests. * *

This is used by tests that are testing retry behavior, to allow them to control exactly - * which URL is being requested. Each URL provided by tests simulates a different type of - * failure. + * which URL is being requested. Each URL provided by tests simulates a different type of failure. */ private static class StubbedClient extends PGPKeysServerClientHttps { private final URI stubbedUri; - StubbedClient(URI stubbedUri, int connectTimeout, int readTimeout, int maxAttempts) throws IOException { - super(stubbedUri, connectTimeout, readTimeout, maxAttempts, null); + StubbedClient(URI stubbedUri, KeyServerClientSettings clientSettings) throws IOException { + super(stubbedUri, clientSettings); this.stubbedUri = stubbedUri; } diff --git a/src/test/java/org/simplify4u/plugins/keyserver/PGPKeysServerClientTest.java b/src/test/java/org/simplify4u/plugins/keyserver/PGPKeysServerClientTest.java index 5cf3b9a4..523d3a6c 100644 --- a/src/test/java/org/simplify4u/plugins/keyserver/PGPKeysServerClientTest.java +++ b/src/test/java/org/simplify4u/plugins/keyserver/PGPKeysServerClientTest.java @@ -1,27 +1,57 @@ +/* + * Copyright 2021 Slawomir Jaranowski + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.simplify4u.plugins.keyserver; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.when; +import static org.simplify4u.plugins.utils.ProxyUtil.makeMavenProxy; + import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.maven.execution.MavenSession; import org.apache.maven.settings.Proxy; +import org.apache.maven.settings.Settings; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.simplify4u.plugins.utils.PGPKeyId; import org.testng.Assert; import org.testng.annotations.DataProvider; +import org.testng.annotations.Listeners; import org.testng.annotations.Test; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; +@Listeners(MockitoTestNGListener.class) +public class PGPKeysServerClientTest { -import static org.simplify4u.plugins.utils.ProxyUtil.makeMavenProxy; + @Mock + Settings settings; -public class PGPKeysServerClientTest { + @Mock + MavenSession mavenSession; @DataProvider(name = "proxy") public static Object[][] proxy() { return new Object[][]{ - { makeMavenProxy("user", "password") }, - { makeMavenProxy("", "") }, - { makeMavenProxy(null, null) }, - { null }}; + {makeMavenProxy("user", "password")}, + {makeMavenProxy("", "")}, + {makeMavenProxy(null, null)}, + {null}}; } @Test(dataProvider = "proxy") @@ -32,7 +62,14 @@ public void testIfClientWithProxyProperties(Proxy proxy) throws URISyntaxExcepti } private void runProxyConfig(URI uri, Proxy proxy) throws IOException { - PGPKeysServerClient pgpKeysServerClient = new PGPKeysServerClient(uri, 10_000, 10_000, 10_000, proxy) { + + when(mavenSession.getSettings()).thenReturn(settings); + when(settings.getActiveProxy()).thenReturn(proxy); + KeyServerClientSettings clientSettings = KeyServerClientSettings.builder() + .mavenSession(mavenSession) + .build(); + + PGPKeysServerClient pgpKeysServerClient = new PGPKeysServerClient(uri, clientSettings) { @Override protected HttpClientBuilder createClientBuilder() { return null; @@ -46,4 +83,35 @@ protected HttpClientBuilder createClientBuilder() { Assert.assertNotNull(closeableHttpClient); } } -} \ No newline at end of file + + + @Test + public void offLineModeShouldThrowIOException() throws URISyntaxException { + + URI uri = new URI("https://localhost/"); + + when(mavenSession.isOffline()).thenReturn(true); + + KeyServerClientSettings clientSettings = KeyServerClientSettings.builder() + .mavenSession(mavenSession) + .build(); + + PGPKeysServerClient pgpKeysServerClient = new PGPKeysServerClient(uri, clientSettings) { + @Override + protected HttpClientBuilder createClientBuilder() { + return null; + } + }; + + assertThatThrownBy(() -> pgpKeysServerClient.copyKeyToOutputStream(PGPKeyId.from(0x0123456789ABCDEFL), null, null)) + .isExactlyInstanceOf(IOException.class) + .hasMessage("Not possible to download key: https://localhost/pks/lookup?op=get&options=mr&search=0x0123456789ABCDEF in offline mode."); + } + + @Test + public void unsupportedProtocolShouldThrowIOException() throws IOException { + assertThatThrownBy(() -> PGPKeysServerClient.getClient("abc://loclahost", null)) + .isExactlyInstanceOf(IOException.class) + .hasMessage("Unsupported protocol: abc"); + } +}