Skip to content

Commit

Permalink
add support tls versioning
Browse files Browse the repository at this point in the history
  • Loading branch information
asep.rojali committed Jun 22, 2023
1 parent 2112be4 commit c4098e3
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 98 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,17 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>

<okhttp3.version>4.9.3</okhttp3.version>
<retrofit.version>2.6.4</retrofit.version>

<lombok.version>1.18.28</lombok.version>
<commons-lang.version>2.6</commons-lang.version>
<gson.version>2.10.1</gson.version>
<jackson-databind.version>2.15.2</jackson-databind.version>
<logback.version>1.4.7</logback.version>
<junit.version>4.13.2</junit.version>

<maven-compiler-plugin.version>3.2</maven-compiler-plugin.version>
<maven-source-plugin.version>3.2.1</maven-source-plugin.version>
<maven-javadoc-plugin.version>3.4.1</maven-javadoc-plugin.version>
Expand Down Expand Up @@ -77,6 +80,7 @@
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind.version}</version>
</dependency>

<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-jackson</artifactId>
Expand All @@ -93,6 +97,7 @@
<artifactId>adapter-rxjava</artifactId>
<version>${retrofit.version}</version>
</dependency>

<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
Expand Down
45 changes: 22 additions & 23 deletions src/main/java/io/github/avew/CustomHttpConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,42 +13,41 @@
@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<String> 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
private boolean retryConnectionFailure = false;
@Builder.Default
private List<String> 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);
}


}
43 changes: 43 additions & 0 deletions src/main/java/io/github/avew/CustomProxy.java
Original file line number Diff line number Diff line change
@@ -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<String> 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 +
'}';
}
}
7 changes: 7 additions & 0 deletions src/main/java/io/github/avew/HttpTls.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.github.avew;

public enum HttpTls {
TLS1_1,
TLS1_2,
TLS1_3
}
120 changes: 71 additions & 49 deletions src/main/java/io/github/avew/VewHttp.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -59,55 +58,75 @@ public Retrofit.Builder builder(Consumer<OkHttpClient.Builder> 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<Proxy> 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<Proxy> 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);
Expand Down Expand Up @@ -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<String> words, String msg) {
List<String> maskPatterns = words.stream().map(s -> "\"([" + s + "\"]+)\"\\s*:\\s*\"([^\"]+)\",?").collect(Collectors.toList());
List<String> 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);
Expand All @@ -164,13 +191,8 @@ private String maskingLog(List<String> 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() {
Expand Down
38 changes: 12 additions & 26 deletions src/test/java/io/github/avew/OkHttpTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,42 +20,28 @@
public class OkHttpTest {

private Retrofit retrofit;
private final List<String> maskingLog = Arrays.asList("https",
"password",
"docpass",
"docpas",
"pass",
"data",
"content",
"client_secret",
"user",
"token",
"sn",
"image",
"noidentitas",
"namedipungut",
"jwToken",
"refToken");
private final List<String> 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();
}

Expand Down

0 comments on commit c4098e3

Please sign in to comment.