From c4098e3b25b10e562f55acea404afc85959c19e6 Mon Sep 17 00:00:00 2001 From: "asep.rojali" Date: Thu, 22 Jun 2023 18:58:34 +0700 Subject: [PATCH] add support tls versioning --- pom.xml | 5 + .../java/io/github/avew/CustomHttpConfig.java | 45 ++++--- src/main/java/io/github/avew/CustomProxy.java | 43 +++++++ src/main/java/io/github/avew/HttpTls.java | 7 + src/main/java/io/github/avew/VewHttp.java | 120 +++++++++++------- src/test/java/io/github/avew/OkHttpTest.java | 38 ++---- 6 files changed, 160 insertions(+), 98 deletions(-) create mode 100644 src/main/java/io/github/avew/CustomProxy.java create mode 100644 src/main/java/io/github/avew/HttpTls.java diff --git a/pom.xml b/pom.xml index 3a6a157..1fc92ea 100644 --- a/pom.xml +++ b/pom.xml @@ -29,14 +29,17 @@ UTF-8 11 11 + 4.9.3 2.6.4 + 1.18.28 2.6 2.10.1 2.15.2 1.4.7 4.13.2 + 3.2 3.2.1 3.4.1 @@ -77,6 +80,7 @@ jackson-databind ${jackson-databind.version} + com.squareup.retrofit2 converter-jackson @@ -93,6 +97,7 @@ adapter-rxjava ${retrofit.version} + com.squareup.okhttp3 logging-interceptor diff --git a/src/main/java/io/github/avew/CustomHttpConfig.java b/src/main/java/io/github/avew/CustomHttpConfig.java index 09473ba..cdce639 100644 --- a/src/main/java/io/github/avew/CustomHttpConfig.java +++ b/src/main/java/io/github/avew/CustomHttpConfig.java @@ -13,21 +13,18 @@ @NoArgsConstructor @AllArgsConstructor public class CustomHttpConfig { + private String url; + @Builder.Default - private boolean proxy = false; + private CustomProxy proxy = new CustomProxy(); + @Builder.Default - private boolean proxyAuth = false; - private String proxyUsername; - private String proxyPassword; - private List urlSkipProxy; - private String proxyHost; - private int proxyPort; - private String agent; + private String agent = null; + @Builder.Default private CustomTimeout customTimeout = new CustomTimeout(); - @Builder.Default private boolean masking = true; @Builder.Default @@ -35,20 +32,22 @@ public class CustomHttpConfig { @Builder.Default private List excludeHeaders = new ArrayList<>(); + @Builder.Default + private HttpTls TLS = HttpTls.TLS1_2; + + public static String mask(String value) { + if (value == null) { + return null; + } - @Override - public String toString() { - return "CustomHttpConfig{" + - "url='" + url + '\'' + - ", proxy=" + proxy + - ", proxyAuth=" + proxyAuth + - ", proxyUsername='" + proxyUsername + '\'' + - ", proxyPassword='" + proxyPassword + '\'' + - ", urlSkipProxy=" + urlSkipProxy + - ", proxyHost='" + proxyHost + '\'' + - ", proxyPort=" + proxyPort + - ", agent='" + agent + '\'' + - ", customTimeout=" + customTimeout + - '}'; + char[] chs = new char[value.length()]; + for (int i = 1; i < chs.length; i++) { + chs[i] = '*'; + } + chs[0] = value.charAt(0); + chs[chs.length - 1] = value.charAt(value.length() - 1); + return new String(chs); } + + } diff --git a/src/main/java/io/github/avew/CustomProxy.java b/src/main/java/io/github/avew/CustomProxy.java new file mode 100644 index 0000000..b12abb6 --- /dev/null +++ b/src/main/java/io/github/avew/CustomProxy.java @@ -0,0 +1,43 @@ +package io.github.avew; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import static io.github.avew.CustomHttpConfig.mask; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CustomProxy { + + @Builder.Default + private boolean proxy = false; + @Builder.Default + private boolean auth = false; + private String username; + private String password; + @Builder.Default + private List urlSkip = new ArrayList<>(); + private String host; + private int port; + + @Override + public String toString() { + return "CustomProxy{" + + "proxy=" + proxy + + ", auth=" + auth + + ", username='" + mask(username) + '\'' + + ", password='" + mask(password) + '\'' + + ", urlSkip=" + urlSkip + + ", host='" + host + '\'' + + ", port=" + port + + '}'; + } +} diff --git a/src/main/java/io/github/avew/HttpTls.java b/src/main/java/io/github/avew/HttpTls.java new file mode 100644 index 0000000..f9837ba --- /dev/null +++ b/src/main/java/io/github/avew/HttpTls.java @@ -0,0 +1,7 @@ +package io.github.avew; + +public enum HttpTls { + TLS1_1, + TLS1_2, + TLS1_3 +} diff --git a/src/main/java/io/github/avew/VewHttp.java b/src/main/java/io/github/avew/VewHttp.java index 0479800..9efbfe8 100644 --- a/src/main/java/io/github/avew/VewHttp.java +++ b/src/main/java/io/github/avew/VewHttp.java @@ -4,10 +4,8 @@ import com.bartoszwesolowski.okhttp3.logging.CustomizableHttpLoggingInterceptor; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import okhttp3.*; import okhttp3.Authenticator; -import okhttp3.Credentials; -import okhttp3.OkHttpClient; -import okhttp3.Request; import okhttp3.logging.HttpLoggingInterceptor; import org.apache.commons.lang.StringUtils; import retrofit2.Retrofit; @@ -19,6 +17,7 @@ import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.function.Consumer; import java.util.regex.Matcher; @@ -59,55 +58,75 @@ public Retrofit.Builder builder(Consumer configureClient) httpClient.addInterceptor(chain -> { Request original = chain.request(); Request.Builder request = original.newBuilder(); - request.header("User-Agent", config.getAgent()); + if (config.getAgent() != null) + request.header("User-Agent", config.getAgent()); if (config.isRetryConnectionFailure()) request.header("Connection", "close"); return chain.proceed(request.build()); }); - if (config.isMasking()) { - httpClient.addNetworkInterceptor(customNetworkInterceptors()); - } else { - httpClient.addInterceptor(httpLoggingInterceptor()); + httpClient.addNetworkInterceptor(customNetworkInterceptors()); + + switch (config.getTLS()) { + case TLS1_1: + ConnectionSpec tls11 = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) + .tlsVersions(TlsVersion.TLS_1_0, TlsVersion.TLS_1_1) + .build(); + httpClient.connectionSpecs(List.of(tls11)); + break; + case TLS1_2: + ConnectionSpec tls12 = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) + .tlsVersions(TlsVersion.TLS_1_2) + .build(); + httpClient.connectionSpecs(List.of(tls12)); + break; + case TLS1_3: + ConnectionSpec tls13 = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) + .tlsVersions(TlsVersion.TLS_1_3) + .build(); + httpClient.connectionSpecs(List.of(tls13)); + break; } this.setTrustManager(httpClient); - if (config.isProxy()) { - log.info("CONNECTION TO {} USE PROXY", config.getUrl()); - - if (config.isProxyAuth()) { - log.info("CONNECTION TO {} USE PROXY WITH AUTH", config.getUrl()); - Authenticator proxyAuthenticator = (route, response) -> { - String credential = Credentials.basic(config.getProxyUsername(), config.getProxyPassword()); - return response.request().newBuilder() - .header("Proxy-Authorization", credential) - .build(); - }; - httpClient.proxyAuthenticator(proxyAuthenticator); - } + if (config.getProxy() != null) { + CustomProxy proxy = config.getProxy(); + if (proxy.isProxy()) { + log.info("CONNECTION TO {} USE PROXY", config.getUrl()); + + if (proxy.isAuth()) { + log.info("CONNECTION TO {} USE PROXY WITH AUTH", config.getUrl()); + Authenticator proxyAuthenticator = (route, response) -> { + String credential = Credentials.basic(proxy.getUsername(), proxy.getPassword()); + return response.request().newBuilder() + .header("Proxy-Authorization", credential) + .build(); + }; + httpClient.proxyAuthenticator(proxyAuthenticator); + } - httpClient.proxySelector(new ProxySelector() { - @Override - public List select(URI uri) { - - // Host - final String host = uri.getHost(); - - String noProxyHost = config.getUrlSkipProxy().stream().collect(Collectors.joining(",")); - if (StringUtils.contains(noProxyHost, host)) { - return List.of(Proxy.NO_PROXY); - } else { - // Add Proxy - return List.of(new Proxy(Proxy.Type.HTTP, - new InetSocketAddress(config.getProxyHost(), config.getProxyPort()))); + httpClient.proxySelector(new ProxySelector() { + @Override + public List select(URI uri) { + + // Host + final String host = uri.getHost(); + + String noProxyHost = proxy.getUrlSkip().stream().collect(Collectors.joining(",")); + if (StringUtils.contains(noProxyHost, host)) { + return List.of(Proxy.NO_PROXY); + } else { + // Add Proxy + return List.of(new Proxy(Proxy.Type.HTTP, + new InetSocketAddress(proxy.getHost(), proxy.getPort()))); + } } - } - - @Override - public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { - throw new UnsupportedOperationException("Proxy Not supported yet."); - } - }); + @Override + public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { + throw new UnsupportedOperationException("Proxy Not supported yet."); + } + }); + } } if (configureClient != null) configureClient.accept(httpClient); @@ -150,10 +169,18 @@ public java.security.cert.X509Certificate[] getAcceptedIssuers() { SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); httpClient.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]); httpClient.hostnameVerifier((String s, SSLSession sslSession) -> true); + + } private String maskingLog(List words, String msg) { - List maskPatterns = words.stream().map(s -> "\"([" + s + "\"]+)\"\\s*:\\s*\"([^\"]+)\",?").collect(Collectors.toList()); + List maskPatterns; + if (config.isMasking()) { + maskPatterns = words.stream().map(s -> "\"([" + s + "\"]+)\"\\s*:\\s*\"([^\"]+)\",?").collect(Collectors.toList()); + } else { + maskPatterns = new ArrayList<>(); + } + Pattern multilinePattern = Pattern.compile(String.join("|", maskPatterns), Pattern.MULTILINE); StringBuilder sb = new StringBuilder(msg); Matcher matcher = multilinePattern.matcher(sb); @@ -164,13 +191,8 @@ private String maskingLog(List words, String msg) { } }); } - return sb.toString(); - } - private HttpLoggingInterceptor httpLoggingInterceptor() { - HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); - httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); - return httpLoggingInterceptor; + return sb.toString(); } private CustomizableHttpLoggingInterceptor customNetworkInterceptors() { diff --git a/src/test/java/io/github/avew/OkHttpTest.java b/src/test/java/io/github/avew/OkHttpTest.java index 9ff7c89..2cbb939 100644 --- a/src/test/java/io/github/avew/OkHttpTest.java +++ b/src/test/java/io/github/avew/OkHttpTest.java @@ -20,42 +20,28 @@ public class OkHttpTest { private Retrofit retrofit; - private final List maskingLog = Arrays.asList("https", - "password", - "docpass", - "docpas", - "pass", - "data", - "content", - "client_secret", - "user", - "token", - "sn", - "image", - "noidentitas", - "namedipungut", - "jwToken", - "refToken"); + private final List maskingLog = Arrays.asList("user", "password", "name"); + + private ObjectMapper mapper() { + ObjectMapper mapper = new ObjectMapper(); + mapper.writerWithDefaultPrettyPrinter(); + mapper.coercionConfigFor(LogicalType.POJO) + .setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + return mapper; + } @Before public void init() { CustomHttpConfig customHttpConfig = CustomHttpConfig.builder() .url("https://reqres.in") - .agent("OkHttp/4.1.0") .masking(true) - .excludeHeaders(Arrays.asList("X-Api-Key","User-Agent","Host")) + .excludeHeaders(List.of("X-Api-Key")) .build(); - log.debug("CONFIG {}", customHttpConfig.getCustomTimeout()); - log.debug("CONFIG {}", customHttpConfig.getExcludeHeaders()); - ObjectMapper mapper = new ObjectMapper(); - mapper.writerWithDefaultPrettyPrinter(); - mapper.coercionConfigFor(LogicalType.POJO) - .setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); retrofit = new VewHttp(customHttpConfig, maskingLog, true) .builder() - .addConverterFactory(JacksonConverterFactory.create(mapper)) + .addConverterFactory(JacksonConverterFactory.create(mapper())) .build(); }