Skip to content

Commit

Permalink
Merge pull request #513 from splitio/kerberos-module-refactor
Browse files Browse the repository at this point in the history
Refactor kerberos code to sub module
  • Loading branch information
chillaq authored Sep 11, 2024
2 parents 7d136d7 + 4d888cb commit cfdc429
Show file tree
Hide file tree
Showing 22 changed files with 564 additions and 336 deletions.
12 changes: 0 additions & 12 deletions client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -177,18 +177,6 @@
<artifactId>snakeyaml</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
<version>4.12.0</version>
<optional>true</optional>
</dependency>

<!-- Test deps -->
<dependency>
Expand Down
54 changes: 11 additions & 43 deletions client/src/main/java/io/split/client/SplitClientConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import io.split.client.impressions.ImpressionsManager;
import io.split.client.utils.FileTypeEnum;
import io.split.integrations.IntegrationsConfig;
import io.split.service.ProxyAuthScheme;
import io.split.service.CustomHttpModule;
import io.split.storages.enums.OperationMode;
import io.split.storages.enums.StorageMode;
import org.apache.hc.core5.http.HttpHost;
Expand Down Expand Up @@ -92,8 +92,7 @@ public class SplitClientConfig {
private final HashSet<String> _flagSetsFilter;
private final int _invalidSets;
private final CustomHeaderDecorator _customHeaderDecorator;
private final ProxyAuthScheme _proxyAuthScheme;
private final String _proxyKerberosPrincipalName;
private final CustomHttpModule _alternativeHTTPModule;

public static Builder builder() {
return new Builder();
Expand Down Expand Up @@ -151,8 +150,7 @@ private SplitClientConfig(String endpoint,
HashSet<String> flagSetsFilter,
int invalidSets,
CustomHeaderDecorator customHeaderDecorator,
ProxyAuthScheme proxyAuthScheme,
String proxyKerberosPrincipalName) {
CustomHttpModule alternativeHTTPModule) {
_endpoint = endpoint;
_eventsEndpoint = eventsEndpoint;
_featuresRefreshRate = pollForFeatureChangesEveryNSeconds;
Expand Down Expand Up @@ -205,8 +203,7 @@ private SplitClientConfig(String endpoint,
_flagSetsFilter = flagSetsFilter;
_invalidSets = invalidSets;
_customHeaderDecorator = customHeaderDecorator;
_proxyAuthScheme = proxyAuthScheme;
_proxyKerberosPrincipalName = proxyKerberosPrincipalName;
_alternativeHTTPModule = alternativeHTTPModule;

Properties props = new Properties();
try {
Expand Down Expand Up @@ -414,11 +411,8 @@ public int getInvalidSets() {
public CustomHeaderDecorator customHeaderDecorator() {
return _customHeaderDecorator;
}
public ProxyAuthScheme proxyAuthScheme() {
return _proxyAuthScheme;
}
public String proxyKerberosPrincipalName() { return _proxyKerberosPrincipalName; }

public CustomHttpModule alternativeHTTPModule() { return _alternativeHTTPModule; }
public static final class Builder {

private String _endpoint = SDK_ENDPOINT;
Expand Down Expand Up @@ -476,8 +470,7 @@ public static final class Builder {
private HashSet<String> _flagSetsFilter = new HashSet<>();
private int _invalidSetsCount = 0;
private CustomHeaderDecorator _customHeaderDecorator = null;
private ProxyAuthScheme _proxyAuthScheme = null;
private String _proxyKerberosPrincipalName = null;
private CustomHttpModule _alternativeHTTPModule = null;

public Builder() {
}
Expand Down Expand Up @@ -973,24 +966,13 @@ public Builder customHeaderDecorator(CustomHeaderDecorator customHeaderDecorator
}

/**
* Authentication Scheme
*
* @param proxyAuthScheme
* @return this builder
*/
public Builder proxyAuthScheme(ProxyAuthScheme proxyAuthScheme) {
_proxyAuthScheme = proxyAuthScheme;
return this;
}

/**
* Kerberos Principal Account Name
* Alternative Http Client
*
* @param proxyKerberosPrincipalName
* @param alternativeHTTPModule
* @return this builder
*/
public Builder proxyKerberosPrincipalName(String proxyKerberosPrincipalName) {
_proxyKerberosPrincipalName = proxyKerberosPrincipalName;
public Builder alternativeHTTPModule(CustomHttpModule alternativeHTTPModule) {
_alternativeHTTPModule = alternativeHTTPModule;
return this;
}

Expand Down Expand Up @@ -1052,17 +1034,6 @@ private void verifyEndPoints() {
}
}

private void verifyAuthScheme() {
if (_proxyAuthScheme == ProxyAuthScheme.KERBEROS) {
if (proxy() == null) {
throw new IllegalStateException("Kerberos mode require Proxy parameters.");
}
if (_proxyKerberosPrincipalName == null) {
throw new IllegalStateException("Kerberos mode require Kerberos Principal Name.");
}
}
}

private void verifyAllModes() {
switch (_impressionsMode) {
case OPTIMIZED:
Expand Down Expand Up @@ -1128,8 +1099,6 @@ public SplitClientConfig build() {
throw new IllegalArgumentException("Number of threads for fetching segments MUST be greater than zero");
}

verifyAuthScheme();

return new SplitClientConfig(
_endpoint,
_eventsEndpoint,
Expand Down Expand Up @@ -1183,8 +1152,7 @@ public SplitClientConfig build() {
_flagSetsFilter,
_invalidSetsCount,
_customHeaderDecorator,
_proxyAuthScheme,
_proxyKerberosPrincipalName);
_alternativeHTTPModule);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.split.inputValidation.ApiKeyValidator;
import io.split.grammar.Treatments;
import io.split.service.SplitHttpClient;
import io.split.storages.enums.StorageMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down
72 changes: 12 additions & 60 deletions client/src/main/java/io/split/client/SplitFactoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,9 @@
import io.split.engine.segments.SegmentChangeFetcher;
import io.split.engine.segments.SegmentSynchronizationTaskImp;
import io.split.integrations.IntegrationsConfig;
import io.split.service.ProxyAuthScheme;
import io.split.service.SplitHttpClientKerberosImpl;
import io.split.service.SplitHttpClientImpl;
import io.split.service.SplitHttpClient;
import io.split.service.HTTPKerberosAuthInterceptor;

import io.split.storages.SegmentCache;
import io.split.storages.SegmentCacheConsumer;
import io.split.storages.SegmentCacheProducer;
Expand All @@ -86,6 +84,7 @@
import io.split.telemetry.synchronizer.TelemetryInMemorySubmitter;
import io.split.telemetry.synchronizer.TelemetrySyncTask;
import io.split.telemetry.synchronizer.TelemetrySynchronizer;

import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.Credentials;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
Expand All @@ -108,26 +107,16 @@
import org.slf4j.LoggerFactory;
import pluggable.CustomStorageWrapper;

import okhttp3.Authenticator;
import okhttp3.OkHttpClient;
import okhttp3.OkHttpClient.Builder;
import okhttp3.logging.HttpLoggingInterceptor;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

import static io.split.client.utils.SplitExecutorFactory.buildExecutorService;

Expand Down Expand Up @@ -167,12 +156,13 @@ public class SplitFactoryImpl implements SplitFactory {
private final SplitSynchronizationTask _splitSynchronizationTask;
private final EventsTask _eventsTask;
private final SyncManager _syncManager;
private final SplitHttpClient _splitHttpClient;
private SplitHttpClient _splitHttpClient;
private final UserStorageWrapper _userStorageWrapper;
private final ImpressionsSender _impressionsSender;
private final URI _rootTarget;
private final URI _eventsRootTarget;
private final UniqueKeysTracker _uniqueKeysTracker;
private RequestDecorator _requestDecorator;

// Constructor for standalone mode
public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyntaxException, IOException {
Expand All @@ -199,8 +189,12 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn
_gates = new SDKReadinessGates();

// HttpClient
RequestDecorator requestDecorator = new RequestDecorator(config.customHeaderDecorator());
_splitHttpClient = buildSplitHttpClient(apiToken, config, _sdkMetadata, requestDecorator);
_requestDecorator = new RequestDecorator(config.customHeaderDecorator());
if (config.alternativeHTTPModule() == null) {
_splitHttpClient = buildSplitHttpClient(apiToken, config, _sdkMetadata, _requestDecorator);
} else {
_splitHttpClient = config.alternativeHTTPModule().createClient(apiToken, _sdkMetadata, _requestDecorator);
}

// Roots
_rootTarget = URI.create(config.endpoint());
Expand Down Expand Up @@ -269,7 +263,7 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn
// SyncManager
SplitTasks splitTasks = SplitTasks.build(_splitSynchronizationTask, _segmentSynchronizationTaskImp,
_impressionsManager, _eventsTask, _telemetrySyncTask, _uniqueKeysTracker);
SplitAPI splitAPI = SplitAPI.build(_splitHttpClient, buildSSEdHttpClient(apiToken, config, _sdkMetadata), requestDecorator);
SplitAPI splitAPI = SplitAPI.build(_splitHttpClient, buildSSEdHttpClient(apiToken, config, _sdkMetadata), _requestDecorator);

_syncManager = SyncManagerImp.build(splitTasks, _splitFetcher, splitCache, splitAPI,
segmentCache, _gates, _telemetryStorageProducer, _telemetrySynchronizer, config, splitParser,
Expand Down Expand Up @@ -505,34 +499,7 @@ public boolean isDestroyed() {

protected static SplitHttpClient buildSplitHttpClient(String apiToken, SplitClientConfig config,
SDKMetadata sdkMetadata, RequestDecorator requestDecorator)
throws URISyntaxException, IOException {
// setup Kerberos client
if (config.proxyAuthScheme() == ProxyAuthScheme.KERBEROS) {
_log.info("Using Kerberos-Proxy Authentication Scheme.");
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(config.proxy().getHostName(), config.proxy().getPort()));
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
if (config.debugEnabled()) {
logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);
} else {
logging.setLevel(HttpLoggingInterceptor.Level.NONE);
}

Map<String, String> kerberosOptions = new HashMap<>();
kerberosOptions.put("com.sun.security.auth.module.Krb5LoginModule", "required");
kerberosOptions.put("refreshKrb5Config", "false");
kerberosOptions.put("doNotPrompt", "false");
kerberosOptions.put("useTicketCache", "true");

Authenticator proxyAuthenticator = getProxyAuthenticator(config, kerberosOptions);
OkHttpClient client = buildOkHttpClient(proxy, config, logging, proxyAuthenticator);

return SplitHttpClientKerberosImpl.create(
client,
requestDecorator,
apiToken,
sdkMetadata);
}

throws URISyntaxException {
SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactoryBuilder.create()
.setSslContext(SSLContexts.createSystemDefault())
.setTlsVersions(TLS.V_1_1, TLS.V_1_2)
Expand Down Expand Up @@ -570,21 +537,6 @@ protected static SplitHttpClient buildSplitHttpClient(String apiToken, SplitClie
sdkMetadata);
}

protected static OkHttpClient buildOkHttpClient(Proxy proxy, SplitClientConfig config,
HttpLoggingInterceptor logging, Authenticator proxyAuthenticator) {
return new Builder()
.proxy(proxy)
.readTimeout(config.readTimeout(), TimeUnit.MILLISECONDS)
.connectTimeout(config.connectionTimeout(), TimeUnit.MILLISECONDS)
.addInterceptor(logging)
.proxyAuthenticator(proxyAuthenticator)
.build();
}

protected static HTTPKerberosAuthInterceptor getProxyAuthenticator(SplitClientConfig config,
Map<String, String> kerberosOptions) throws IOException {
return new HTTPKerberosAuthInterceptor(config.proxyKerberosPrincipalName(), kerberosOptions);
}
private static CloseableHttpClient buildSSEdHttpClient(String apiToken, SplitClientConfig config,
SDKMetadata sdkMetadata) {
RequestConfig requestConfig = RequestConfig.custom()
Expand Down
10 changes: 10 additions & 0 deletions client/src/main/java/io/split/service/CustomHttpModule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.split.service;

import io.split.client.RequestDecorator;
import io.split.client.utils.SDKMetadata;

import java.io.IOException;

public interface CustomHttpModule {
public SplitHttpClient createClient(String apiToken, SDKMetadata sdkMetadata, RequestDecorator requestDecorator) throws IOException;
}
2 changes: 1 addition & 1 deletion client/src/main/java/io/split/service/SplitHttpClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ public interface SplitHttpClient extends Closeable {
public SplitHttpResponse post(URI uri,
HttpEntity entity,
Map<String, List<String>> additionalHeaders) throws IOException;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.split.client.utils.LocalhostUtils;
import io.split.grammar.Treatments;
import io.split.service.SplitHttpClient;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
Expand Down
33 changes: 0 additions & 33 deletions client/src/test/java/io/split/client/SplitClientConfigTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import io.split.client.impressions.ImpressionsManager;
import io.split.client.dtos.RequestContext;
import io.split.integrations.IntegrationsConfig;
import io.split.service.ProxyAuthScheme;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
Expand Down Expand Up @@ -255,36 +254,4 @@ public Map<String, List<String>> getHeaderOverrides(RequestContext context) {
Assert.assertNull(config2.customHeaderDecorator());

}

@Test
public void checkExpectedAuthScheme() {
SplitClientConfig cfg = SplitClientConfig.builder()
.proxyAuthScheme(ProxyAuthScheme.KERBEROS)
.proxyKerberosPrincipalName("bilal@bilal")
.proxyHost("local")
.proxyPort(8080)
.build();
Assert.assertEquals(ProxyAuthScheme.KERBEROS, cfg.proxyAuthScheme());

cfg = SplitClientConfig.builder()
.build();
Assert.assertEquals(null, cfg.proxyAuthScheme());
}

@Test(expected = IllegalStateException.class)
public void testAuthSchemeWithoutProxy() {
SplitClientConfig.builder()
.proxyAuthScheme(ProxyAuthScheme.KERBEROS)
.proxyKerberosPrincipalName("bilal")
.build();
}

@Test(expected = IllegalStateException.class)
public void testAuthSchemeWithoutPrincipalName() {
SplitClientConfig.builder()
.proxyAuthScheme(ProxyAuthScheme.KERBEROS)
.proxyHost("local")
.proxyPort(8080)
.build();
}
}
Loading

0 comments on commit cfdc429

Please sign in to comment.