Skip to content

Commit d78a527

Browse files
authored
Merge pull request #39 from securenative/dev
Support proxy headers
2 parents 72cd7df + bd74ab8 commit d78a527

File tree

11 files changed

+187
-32
lines changed

11 files changed

+187
-32
lines changed

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ public void track(HttpServletRequest request, HttpServletResponse response) {
165165
System.err.printf("Could not get SecureNative instance; %s%n", e);
166166
}
167167

168-
SecureNativeContext context = SecureNativeContextBuilder.fromHttpServletRequest(request).build();
168+
SecureNativeContext context = securenative.fromHttpServletRequest(request).build();
169169

170170
EventOptions eventOptions = null;
171171
try {
@@ -199,7 +199,14 @@ public void track(HttpServletRequest request, HttpServletResponse response) {
199199
```java
200200
@RequestMapping("/verify")
201201
public void verify(HttpServletRequest request, HttpServletResponse response) {
202-
SecureNativeContext context = SecureNativeContextBuilder.fromHttpServletRequest(request).build();
202+
SecureNative securenative = null;
203+
try {
204+
securenative = SecureNative.getInstance();
205+
} catch (SecureNativeSDKIllegalStateException e) {
206+
System.err.printf("Could not get SecureNative instance; %s%n", e);
207+
}
208+
209+
SecureNativeContext context = securenative.fromHttpServletRequest(request).build();
203210

204211
EventOptions eventOptions = null;
205212
try {

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<groupId>com.securenative.java</groupId>
77
<artifactId>securenative-java</artifactId>
88
<packaging>jar</packaging>
9-
<version>0.5.5</version>
9+
<version>0.5.6</version>
1010
<url>https://github.com/securenative/securenative-java</url>
1111

1212
<name>${project.groupId}:${project.artifactId}:${project.version}</name>

src/main/java/com/securenative/SecureNative.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ public static SecureNativeContextBuilder contextBuilder() {
8888
return SecureNativeContextBuilder.defaultContextBuilder();
8989
}
9090

91+
public SecureNativeContextBuilder fromHttpServletRequest(HttpServletRequest request) {
92+
return SecureNativeContextBuilder.fromHttpServletRequest(request, this.options);
93+
}
94+
9195
public boolean verifyRequestPayload(HttpServletRequest request) throws IOException {
9296
String requestSignature = request.getHeader(SIGNATURE_HEADER);
9397
String body = request.getReader().lines().collect(Collectors.joining());

src/main/java/com/securenative/config/ConfigurationManager.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
import com.securenative.utils.Utils;
88

99
import java.io.FileInputStream;
10-
import java.io.FileNotFoundException;
1110
import java.io.IOException;
1211
import java.io.InputStream;
1312
import java.net.URL;
1413
import java.nio.file.Path;
14+
import java.util.ArrayList;
15+
import java.util.Arrays;
16+
import java.util.Objects;
1517
import java.util.Properties;
1618

1719
public class ConfigurationManager {
@@ -61,6 +63,12 @@ private static String getPropertyOrEnvOrDefault(Properties properties, String ke
6163
return res == null ? null : res.toString();
6264
}
6365

66+
private static ArrayList<String> getPropertyListOrEnvOrDefault(Properties properties, String key, Object defaultValue) {
67+
String defaultStrValue = defaultValue == null ? null : defaultValue.toString();
68+
Object res = properties.getOrDefault(key, getEnvOrDefault(key, defaultStrValue));
69+
return res == null ? null : new ArrayList<>(Arrays.asList(res.toString().split(",")));
70+
}
71+
6472
public static SecureNativeConfigurationBuilder configBuilder() {
6573
return SecureNativeConfigurationBuilder.defaultConfigBuilder();
6674
}
@@ -96,8 +104,8 @@ private static SecureNativeOptions getOptions(Properties properties) {
96104
.withAutoSend(Utils.parseBooleanOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_AUTO_SEND", defaultOptions.getAutoSend()), defaultOptions.getAutoSend()))
97105
.withDisable(Utils.parseBooleanOrDefault(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_DISABLE", defaultOptions.getDisabled()), defaultOptions.getDisabled()))
98106
.withLogLevel(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_LOG_LEVEL", defaultOptions.getLogLevel()))
99-
.withFailoverStrategy(FailoverStrategy.fromString(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_FAILOVER_STRATEGY", defaultOptions.getFailoverStrategy()), defaultOptions.getFailoverStrategy()));
100-
107+
.withFailoverStrategy(FailoverStrategy.fromString(Objects.requireNonNull(getPropertyOrEnvOrDefault(properties, "SECURENATIVE_FAILOVER_STRATEGY", defaultOptions.getFailoverStrategy())), defaultOptions.getFailoverStrategy()))
108+
.withProxyHeaders(getPropertyListOrEnvOrDefault(properties, "SECURENATIVE_PROXY_HEADERS", defaultOptions.getProxyHeaders()));
101109
return builder.build();
102110
}
103111
}

src/main/java/com/securenative/config/SecureNativeConfigurationBuilder.java

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

33
import com.securenative.enums.FailoverStrategy;
44

5+
import java.util.ArrayList;
6+
57
public class SecureNativeConfigurationBuilder {
68
/**
79
* Api Secret associated with SecureNative account
@@ -48,6 +50,11 @@ public class SecureNativeConfigurationBuilder {
4850
*/
4951
private FailoverStrategy failoverStrategy;
5052

53+
/**
54+
* Proxy Headers
55+
*/
56+
private ArrayList<String> proxyHeaders;
57+
5158
private SecureNativeConfigurationBuilder() {
5259
}
5360

@@ -61,7 +68,8 @@ public static SecureNativeConfigurationBuilder defaultConfigBuilder() {
6168
.withAutoSend(true)
6269
.withDisable(false)
6370
.withLogLevel("fatal")
64-
.withFailoverStrategy(FailoverStrategy.FAIL_OPEN);
71+
.withFailoverStrategy(FailoverStrategy.FAIL_OPEN)
72+
.withProxyHeaders(new ArrayList<>());
6573
}
6674

6775
public SecureNativeConfigurationBuilder withApiKey(String apiKey) {
@@ -109,8 +117,12 @@ public SecureNativeConfigurationBuilder withFailoverStrategy(FailoverStrategy fa
109117
return this;
110118
}
111119

120+
public SecureNativeConfigurationBuilder withProxyHeaders(ArrayList<String> proxyHeaders) {
121+
this.proxyHeaders = proxyHeaders;
122+
return this;
123+
}
112124

113125
public SecureNativeOptions build() {
114-
return new SecureNativeOptions(apiKey, apiUrl, interval, maxEvents, timeout, autoSend, disable, logLevel, failoverStrategy);
126+
return new SecureNativeOptions(apiKey, apiUrl, interval, maxEvents, timeout, autoSend, disable, logLevel, failoverStrategy, proxyHeaders);
115127
}
116128
}

src/main/java/com/securenative/config/SecureNativeOptions.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import com.securenative.enums.FailoverStrategy;
44

5+
import java.util.ArrayList;
6+
57
public class SecureNativeOptions {
68
/**
79
* Api Secret associated with SecureNative account
@@ -48,7 +50,12 @@ public class SecureNativeOptions {
4850
*/
4951
private final FailoverStrategy failoverStrategy;
5052

51-
public SecureNativeOptions(String apiKey, String apiUrl, int interval, int maxEvents, int timeout, boolean autoSend, boolean disable, String logLevel, FailoverStrategy failoverStrategy) {
53+
/**
54+
* Proxy Headers
55+
*/
56+
private final ArrayList<String> proxyHeaders;
57+
58+
public SecureNativeOptions(String apiKey, String apiUrl, int interval, int maxEvents, int timeout, boolean autoSend, boolean disable, String logLevel, FailoverStrategy failoverStrategy, ArrayList<String> proxyHeaders) {
5259
this.apiKey = apiKey;
5360
this.apiUrl = apiUrl;
5461
this.interval = interval;
@@ -58,6 +65,7 @@ public SecureNativeOptions(String apiKey, String apiUrl, int interval, int maxEv
5865
this.disable = disable;
5966
this.logLevel = logLevel;
6067
this.failoverStrategy = failoverStrategy;
68+
this.proxyHeaders = proxyHeaders;
6169
}
6270

6371
public String getApiKey() {
@@ -95,4 +103,8 @@ public String getLogLevel() {
95103
public FailoverStrategy getFailoverStrategy() {
96104
return failoverStrategy;
97105
}
106+
107+
public ArrayList<String> getProxyHeaders() {
108+
return proxyHeaders;
109+
}
98110
}

src/main/java/com/securenative/context/SecureNativeContextBuilder.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.securenative.context;
22

3+
import com.securenative.config.SecureNativeOptions;
34
import com.securenative.utils.RequestUtils;
45
import com.securenative.utils.Utils;
56

@@ -52,7 +53,7 @@ public static SecureNativeContextBuilder defaultContextBuilder() {
5253
return new SecureNativeContextBuilder();
5354
}
5455

55-
public static SecureNativeContextBuilder fromHttpServletRequest(HttpServletRequest request) {
56+
public static SecureNativeContextBuilder fromHttpServletRequest(HttpServletRequest request, SecureNativeOptions options) {
5657
Map<String, String> headers = RequestUtils.getHeadersFromRequest(request);
5758

5859
String clientToken = RequestUtils.getCookieValueFromRequest(request, RequestUtils.SECURENATIVE_COOKIE);
@@ -65,7 +66,7 @@ public static SecureNativeContextBuilder fromHttpServletRequest(HttpServletReque
6566
.withMethod(request.getMethod())
6667
.withHeaders(headers)
6768
.withClientToken(clientToken)
68-
.withIp(RequestUtils.getClientIpFromRequest(request, headers))
69+
.withIp(RequestUtils.getClientIpFromRequest(request, headers, options))
6970
.withRemoteIp(RequestUtils.getRemoteIpFromRequest(request))
7071
.withBody(null);
7172
}

src/main/java/com/securenative/utils/RequestUtils.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.securenative.utils;
22

3+
import com.securenative.config.SecureNativeOptions;
4+
35
import javax.servlet.http.Cookie;
46
import javax.servlet.http.HttpServletRequest;
57
import java.util.*;
@@ -35,7 +37,25 @@ public static String getCookieValueFromRequest(HttpServletRequest request, Strin
3537
return null;
3638
}
3739

38-
public static String getClientIpFromRequest(HttpServletRequest request, Map<String, String> headers) {
40+
public static String getClientIpFromRequest(HttpServletRequest request, Map<String, String> headers, SecureNativeOptions options) {
41+
if (options.getProxyHeaders().size() > 0) {
42+
for (String header : options.getProxyHeaders()) {
43+
if (headers.containsKey(header)) {
44+
String headerValue = headers.get(header);
45+
46+
Optional<String> ip = Arrays.stream(headerValue.split(","))
47+
.map(String::trim)
48+
.filter(IPUtils::isIpAddress)
49+
.filter(IPUtils::isValidPublicIp)
50+
.findFirst();
51+
52+
if (ip.isPresent()) {
53+
return ip.get();
54+
}
55+
}
56+
}
57+
}
58+
3959
Optional<String> bestCandidate = Optional.empty();
4060
for (String ipHeader : ipHeaders) {
4161
if (!headers.containsKey(ipHeader)) {

src/test/java/com/securenative/config/ConfigurationManagerTest.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.io.ByteArrayInputStream;
1010
import java.io.InputStream;
1111
import java.lang.reflect.Field;
12+
import java.util.ArrayList;
1213
import java.util.Map;
1314
import java.util.concurrent.TimeUnit;
1415

@@ -40,7 +41,8 @@ public void ParseConfigFileCorrectlyTest() throws SecureNativeConfigException {
4041
"SECURENATIVE_AUTO_SEND=true",
4142
"SECURENATIVE_DISABLE=false",
4243
"SECURENATIVE_LOG_LEVEL=fatal",
43-
"SECURENATIVE_FAILOVER_STRATEGY=fail-closed");
44+
"SECURENATIVE_FAILOVER_STRATEGY=fail-closed",
45+
"SECURENATIVE_PROXY_HEADERS=CF-Connecting-IP,Some-Random-Ip");
4446

4547
InputStream inputStream = new ByteArrayInputStream(config.getBytes());
4648

@@ -60,6 +62,7 @@ public void ParseConfigFileCorrectlyTest() throws SecureNativeConfigException {
6062
assertThat(options.getLogLevel()).isEqualTo("fatal");
6163
assertThat(options.getMaxEvents()).isEqualTo(100);
6264
assertThat(options.getTimeout()).isEqualTo(1500);
65+
assertThat(options.getProxyHeaders().size() == 0);
6366

6467
// restore resource stream
6568
ConfigurationManager.setResourceStream(new ResourceStreamImpl());
@@ -159,6 +162,7 @@ public void loadDefaultConfigTest() throws SecureNativeConfigException {
159162
assertThat(options.getDisabled()).isEqualTo(false);
160163
assertThat(options.getLogLevel()).isEqualTo("fatal");
161164
assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_OPEN);
165+
assertThat(options.getProxyHeaders().size() == 0);
162166

163167
ConfigurationManager.setResourceStream(new ResourceStreamImpl());
164168
}
@@ -177,6 +181,7 @@ public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException,
177181
setEnv("SECURENATIVE_DISABLE", "true");
178182
setEnv("SECURENATIVE_LOG_LEVEL", "fatal");
179183
setEnv("SECURENATIVE_FAILOVER_STRATEGY", "fail-closed");
184+
setEnv("SECURENATIVE_PROXY_HEADERS", "CF-Connecting-IP,Some-Random-Ip");
180185

181186
SecureNativeOptions options = ConfigurationManager.loadConfig();
182187

@@ -189,6 +194,7 @@ public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException,
189194
assertThat(options.getDisabled()).isEqualTo(true);
190195
assertThat(options.getLogLevel()).isEqualTo("fatal");
191196
assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_CLOSED);
197+
assertThat(options.getProxyHeaders().size() == 2);
192198

193199
setEnv("SECURENATIVE_API_KEY", "");
194200
setEnv("SECURENATIVE_API_URL", "");
@@ -199,6 +205,7 @@ public void getConfigFromEnvVariablesTest() throws SecureNativeConfigException,
199205
setEnv("SECURENATIVE_DISABLE", "");
200206
setEnv("SECURENATIVE_LOG_LEVEL", "");
201207
setEnv("SECURENATIVE_FAILOVER_STRATEGY", "");
208+
setEnv("SECURENATIVE_PROXY_HEADERS", "");
202209
}
203210

204211
@Test
@@ -215,7 +222,8 @@ public void overwriteEnvVariablesWithConfigFileTest() throws SecureNativeConfigE
215222
"SECURENATIVE_AUTO_SEND=false",
216223
"SECURENATIVE_DISABLE=false",
217224
"SECURENATIVE_LOG_LEVEL=fatal",
218-
"SECURENATIVE_FAILOVER_STRATEGY=fail-closed");
225+
"SECURENATIVE_FAILOVER_STRATEGY=fail-closed",
226+
"SECURENATIVE_PROXY_HEADERS=CF-Connecting-IP,Some-Random-Ip");
219227

220228
setEnv("SECURENATIVE_API_KEY", "API_KEY_FROM_ENV");
221229
setEnv("SECURENATIVE_API_URL", "API_URL_ENV");
@@ -226,6 +234,7 @@ public void overwriteEnvVariablesWithConfigFileTest() throws SecureNativeConfigE
226234
setEnv("SECURENATIVE_DISABLE", "true");
227235
setEnv("SECURENATIVE_LOG_LEVEL", "error");
228236
setEnv("SECURENATIVE_FAILOVER_STRATEGY", "fail-open");
237+
setEnv("SECURENATIVE_PROXY_HEADERS", "CF-Connecting-IP,Some-Random-Ip");
229238

230239
InputStream inputStream = new ByteArrayInputStream(config.getBytes());
231240

@@ -234,6 +243,9 @@ public void overwriteEnvVariablesWithConfigFileTest() throws SecureNativeConfigE
234243

235244
ConfigurationManager.setResourceStream(resourceStream);
236245
SecureNativeOptions options = ConfigurationManager.loadConfig();
246+
ArrayList<String> proxyHeaders = new ArrayList<>();
247+
proxyHeaders.add("CF-Connecting-IP");
248+
proxyHeaders.add("Some-Random-Ip");
237249

238250
assertThat(options).isNotNull();
239251
assertThat(options.getApiKey()).isEqualTo("API_KEY_FROM_FILE");
@@ -245,6 +257,7 @@ public void overwriteEnvVariablesWithConfigFileTest() throws SecureNativeConfigE
245257
assertThat(options.getDisabled()).isEqualTo(false);
246258
assertThat(options.getLogLevel()).isEqualTo("fatal");
247259
assertThat(options.getFailoverStrategy()).isEqualTo(FailoverStrategy.FAIL_CLOSED);
260+
assertThat(options.getProxyHeaders()).isEqualTo(proxyHeaders);
248261

249262
setEnv("SECURENATIVE_API_KEY", "");
250263
setEnv("SECURENATIVE_API_URL", "");
@@ -255,6 +268,7 @@ public void overwriteEnvVariablesWithConfigFileTest() throws SecureNativeConfigE
255268
setEnv("SECURENATIVE_DISABLE", "");
256269
setEnv("SECURENATIVE_LOG_LEVEL", "");
257270
setEnv("SECURENATIVE_FAILOVER_STRATEGY", "");
271+
setEnv("SECURENATIVE_PROXY_HEADERS", "");
258272

259273
// restore resource stream
260274
ConfigurationManager.setResourceStream(new ResourceStreamImpl());

0 commit comments

Comments
 (0)