Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.

Commit 3c14c39

Browse files
author
Dan Richelson
committed
Add proxy authentication support
1 parent 08c0895 commit 3c14c39

File tree

3 files changed

+92
-9
lines changed

3 files changed

+92
-9
lines changed

CONTRIBUTING.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,28 @@
11
Contributing to the LaunchDarkly SDK for Java
22
================================================
33

4-
We encourage pull-requests and other contributions from the community. We've also published an [SDK contributor's guide](http://docs.launchdarkly.com/v1.0/docs/sdk-contributors-guide) that provides a detailed explanation of how our SDKs work.
4+
We encourage pull-requests and other contributions from the community. We've also published an [SDK contributor's guide](http://docs.launchdarkly.com/v1.0/docs/sdk-contributors-guide) that provides a detailed explanation of how our SDKs work.
5+
6+
7+
Testing Proxy Settings
8+
==================
9+
This is currently a manual process. These instructions are not complete.
10+
For Mac OS 10.11 using Squid Proxy 3.5.6 (newer versions were found to be problematic)
11+
12+
Installation is your own journey, but your squid.conf file should have auth/access sections that look something like this:
13+
14+
```
15+
auth_param basic program /usr/local/Cellar/squid/3.5.6/libexec/basic_ncsa_auth <SQUID_DIR>/passwords
16+
auth_param basic realm proxy
17+
acl authenticated proxy_auth REQUIRED
18+
http_access allow authenticated
19+
# And finally deny all other access to this proxy
20+
http_access deny all
21+
```
22+
23+
The contents of the passwords file is:
24+
```
25+
user:$apr1$sBfNiLFJ$7h3S84EgJhlbWM3v.90v61
26+
```
27+
28+
The username/password is: user/password

src/main/java/com/launchdarkly/client/LDConfig.java

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@
22

33
import com.google.common.io.Files;
44
import com.google.gson.Gson;
5+
import okhttp3.Authenticator;
56
import okhttp3.Cache;
67
import okhttp3.ConnectionPool;
8+
import okhttp3.Credentials;
79
import okhttp3.OkHttpClient;
810
import okhttp3.Request;
11+
import okhttp3.Response;
12+
import okhttp3.Route;
913
import org.slf4j.Logger;
1014
import org.slf4j.LoggerFactory;
1115

1216
import java.io.File;
17+
import java.io.IOException;
1318
import java.net.InetSocketAddress;
1419
import java.net.Proxy;
1520
import java.net.URI;
@@ -46,6 +51,7 @@ public final class LDConfig {
4651
final int socketTimeoutMillis;
4752
final int flushInterval;
4853
final Proxy proxy;
54+
final Authenticator proxyAuthenticator;
4955
final OkHttpClient httpClient;
5056
final boolean stream;
5157
final FeatureStore featureStore;
@@ -64,6 +70,7 @@ protected LDConfig(Builder builder) {
6470
this.socketTimeoutMillis = builder.socketTimeoutMillis;
6571
this.flushInterval = builder.flushIntervalSeconds;
6672
this.proxy = builder.proxy();
73+
this.proxyAuthenticator = builder.proxyAuthenticator();
6774
this.streamURI = builder.streamURI;
6875
this.stream = builder.stream;
6976
this.featureStore = builder.featureStore;
@@ -91,12 +98,24 @@ protected LDConfig(Builder builder) {
9198

9299
if (proxy != null) {
93100
httpClientBuilder.proxy(proxy);
101+
if (proxyAuthenticator != null) {
102+
httpClientBuilder.proxyAuthenticator(proxyAuthenticator);
103+
logger.info("Using proxy: " + proxy + " with authentication.");
104+
} else {
105+
logger.info("Using proxy: " + proxy + " without authentication.");
106+
}
94107
}
95108

96109
httpClient = httpClientBuilder
97110
.build();
98111
}
99112

113+
Request.Builder getRequestBuilder(String sdkKey) {
114+
return new Request.Builder()
115+
.addHeader("Authorization", sdkKey)
116+
.addHeader("User-Agent", "JavaClient/" + LDClient.CLIENT_VERSION);
117+
}
118+
100119
/**
101120
* A <a href="http://en.wikipedia.org/wiki/Builder_pattern">builder</a> that helps construct {@link com.launchdarkly.client.LDConfig} objects. Builder
102121
* calls can be chained, enabling the following pattern:
@@ -118,6 +137,8 @@ public static class Builder {
118137
private int flushIntervalSeconds = DEFAULT_FLUSH_INTERVAL_SECONDS;
119138
private String proxyHost = "localhost";
120139
private int proxyPort = -1;
140+
private String proxyUsername = null;
141+
private String proxyPassword = null;
121142
private boolean stream = true;
122143
private boolean useLdd = false;
123144
private boolean offline = false;
@@ -289,6 +310,30 @@ public Builder proxyPort(int port) {
289310
return this;
290311
}
291312

313+
/**
314+
* Sets the username for the optional HTTP proxy. Only used when {@link LDConfig.Builder#proxyPassword(String)}
315+
* is also called.
316+
*
317+
* @param username
318+
* @return
319+
*/
320+
public Builder proxyUsername(String username) {
321+
this.proxyUsername = username;
322+
return this;
323+
}
324+
325+
/**
326+
* Sets the password for the optional HTTP proxy. Only used when {@link LDConfig.Builder#proxyUsername(String)}
327+
* is also called.
328+
*
329+
* @param password
330+
* @return
331+
*/
332+
public Builder proxyPassword(String password) {
333+
this.proxyPassword = password;
334+
return this;
335+
}
336+
292337
/**
293338
* Deprecated. Only HTTP proxies are currently supported.
294339
*
@@ -352,7 +397,7 @@ public Builder startWaitMillis(long startWaitMillis) {
352397
* Enable event sampling. When set to the default of zero, sampling is disabled and all events
353398
* are sent back to LaunchDarkly. When set to greater than zero, there is a 1 in
354399
* <code>samplingInterval</code> chance events will be will be sent.
355-
*
400+
* <p>
356401
* <p>Example: if you want 5% sampling rate, set <code>samplingInterval</code> to 20.
357402
*
358403
* @param samplingInterval the sampling interval.
@@ -386,6 +431,24 @@ Proxy proxy() {
386431
}
387432
}
388433

434+
Authenticator proxyAuthenticator() {
435+
if (this.proxyUsername != null && this.proxyPassword != null) {
436+
final String credential = Credentials.basic(proxyUsername, proxyPassword);
437+
return new Authenticator() {
438+
public Request authenticate(Route route, Response response) throws IOException {
439+
if (response.request().header("Proxy-Authorization") != null) {
440+
return null; // Give up, we've already failed to authenticate with the proxy.
441+
} else {
442+
return response.request().newBuilder()
443+
.header("Proxy-Authorization", credential)
444+
.build();
445+
}
446+
}
447+
};
448+
}
449+
return null;
450+
}
451+
389452
/**
390453
* Build the configured {@link com.launchdarkly.client.LDConfig} object
391454
*
@@ -394,12 +457,5 @@ Proxy proxy() {
394457
public LDConfig build() {
395458
return new LDConfig(this);
396459
}
397-
398-
}
399-
400-
Request.Builder getRequestBuilder(String sdkKey) {
401-
return new Request.Builder()
402-
.addHeader("Authorization", sdkKey)
403-
.addHeader("User-Agent", "JavaClient/" + LDClient.CLIENT_VERSION);
404460
}
405461
}

src/main/java/com/launchdarkly/client/StreamProcessor.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ public void onError(Throwable throwable) {
135135

136136
if (config.proxy != null) {
137137
builder.proxy(config.proxy);
138+
if (config.proxyAuthenticator != null) {
139+
builder.proxyAuthenticator(config.proxyAuthenticator);
140+
}
138141
}
139142

140143
es = builder.build();

0 commit comments

Comments
 (0)