Skip to content

Commit 7fa2993

Browse files
authored
Merge pull request #2 from securenative/dev
Align ip extraction and add proxy headers tests
2 parents 2cb4f94 + 9e47116 commit 7fa2993

8 files changed

Lines changed: 141 additions & 33 deletions

File tree

SecureNative.SDK/Config/ConfigurationManager.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,17 @@ private static string GetPropertyOrEnvOrDefault(JObject properties, string key,
7070
private static string[] GetPropertyListOrEnvOrDefault(JObject properties, string key, object defaultValue)
7171
{
7272
object res = properties.GetValue(key);
73-
return res == null ? new[] {GetEnvOrDefault(key, defaultValue).ToString()} : new []{ res.ToString() };
73+
var data = string.Empty;
74+
if (!string.IsNullOrEmpty(res?.ToString()))
75+
{
76+
data = res.ToString();
77+
}
78+
else if(!string.IsNullOrEmpty(GetEnvOrDefault(key, defaultValue).ToString()))
79+
{
80+
data = GetEnvOrDefault(key, defaultValue).ToString();
81+
}
82+
83+
return data.Split(",");
7484
}
7585

7686
private static SecureNativeOptions GetOptions(JObject properties)

SecureNative.SDK/SecureNative.SDK.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<RootNamespace>SecureNative.SDK</RootNamespace>
66
<AssemblyName>SecureNative.SDK</AssemblyName>
77
<ProjectGuid>{F7AAD3F9-6BFA-4C68-AA26-90D5DA609012}</ProjectGuid>
8-
<PackageVersion>2.0.2</PackageVersion>
8+
<PackageVersion>2.0.3</PackageVersion>
99
<PackageName></PackageName>
1010
<Authors>SecureNative</Authors>
1111
<Owners>SecureNative</Owners>
@@ -16,7 +16,7 @@
1616
<PackageTags>SecureNative, SDK</PackageTags>
1717
<Title>SecureNative .Net SDK</Title>
1818
<NeutralLanguage>en</NeutralLanguage>
19-
<ReleaseVersion>2.0.0</ReleaseVersion>
19+
<ReleaseVersion>2.0.4</ReleaseVersion>
2020
<PackageId>SecureNative</PackageId>
2121
</PropertyGroup>
2222
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
@@ -27,10 +27,10 @@
2727
<DefineConstants>DEBUG;TRACE</DefineConstants>
2828
<ErrorReport>prompt</ErrorReport>
2929
<WarningLevel>1</WarningLevel>
30-
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
30+
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
3131
</PropertyGroup>
3232
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
33-
<DebugType>pdbonly</DebugType>
33+
<DebugType></DebugType>
3434
<Optimize>true</Optimize>
3535
<OutputPath>bin\Release\</OutputPath>
3636
<DefineConstants>TRACE</DefineConstants>

SecureNative.SDK/Utils/RequestUtils.cs

Lines changed: 69 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,11 @@ private static string ParseCookie(string cookieString, string cookieName)
7171
{
7272
if (cookie.Contains(cookieName) && !cookie.Contains("_sncid="))
7373
{
74-
return cookie.Replace(cookieName + "=", "");
74+
return cookie.Replace(cookieName + "=", "").Trim();
7575
}
7676
}
7777

78-
return "";
78+
return string.Empty;
7979
}
8080

8181
public static string GetClientIpFromRequest(HttpWebRequest request, SecureNativeOptions options)
@@ -84,9 +84,15 @@ public static string GetClientIpFromRequest(HttpWebRequest request, SecureNative
8484
{
8585
foreach (var header in options.GetProxyHeaders())
8686
{
87-
if (request.Headers.Get(header) != null)
87+
if (string.IsNullOrEmpty(request.Headers.Get(header)))
8888
{
89-
return request.Headers.Get(header);
89+
continue;
90+
}
91+
var ips = request.Headers.Get(header).Split(",");
92+
var extracted = GetValidIp(ips);
93+
if (!string.IsNullOrEmpty(extracted))
94+
{
95+
return extracted;
9096
}
9197
}
9298
}
@@ -95,15 +101,20 @@ public static string GetClientIpFromRequest(HttpWebRequest request, SecureNative
95101
{
96102
foreach (var header in IpHeaders.Where(header => request.Headers.Get(header) != null))
97103
{
98-
return request.Headers.Get(header);
104+
var ips = request.Headers.Get(header).Split(",");
105+
var extracted = GetValidIp(ips);
106+
if (!string.IsNullOrEmpty(extracted))
107+
{
108+
return extracted;
109+
}
99110
}
100111
}
101112
catch (Exception)
102113
{
103-
return "";
114+
return string.Empty;
104115
}
105116

106-
return "";
117+
return string.Empty;
107118
}
108119

109120
public static string GetRemoteIpFromRequest(HttpWebRequest request)
@@ -112,15 +123,21 @@ public static string GetRemoteIpFromRequest(HttpWebRequest request)
112123
{
113124
foreach (var header in IpHeaders.Where(header => request.Headers.Get(header) != null))
114125
{
115-
return request.Headers.Get(header);
126+
var ips = request.Headers.Get(header).Split(",");
127+
var extracted = GetValidIp(ips);
128+
if (!string.IsNullOrEmpty(extracted))
129+
{
130+
return extracted;
131+
}
132+
116133
}
117134
}
118135
catch (Exception)
119136
{
120-
return "";
137+
return string.Empty;
121138
}
122139

123-
return "";
140+
return string.Empty;
124141
}
125142

126143
public static Dictionary<string, string> GetHeadersFromRequest(HttpRequest request)
@@ -190,9 +207,11 @@ public static string GetClientIpFromRequest(HttpRequest request, SecureNativeOpt
190207
{
191208
foreach (var header in options.GetProxyHeaders())
192209
{
193-
if (request.Headers[header][0] != null)
210+
if (request.Headers[header].ToArray() == null) continue;
211+
var extracted = GetValidIp(request.Headers[header].ToArray());
212+
if (!string.IsNullOrEmpty(extracted))
194213
{
195-
return request.Headers[header][0];
214+
return extracted;
196215
}
197216
}
198217
}
@@ -201,7 +220,11 @@ public static string GetClientIpFromRequest(HttpRequest request, SecureNativeOpt
201220
{
202221
foreach (var header in IpHeaders.Where(header => request.Headers[header].Count > 0))
203222
{
204-
return request.Headers[header][0];
223+
var extracted = GetValidIp(request.Headers[header].ToArray());
224+
if (!string.IsNullOrEmpty(extracted))
225+
{
226+
return extracted;
227+
}
205228
}
206229

207230
if (request.HttpContext.Connection.LocalIpAddress != null)
@@ -211,10 +234,10 @@ public static string GetClientIpFromRequest(HttpRequest request, SecureNativeOpt
211234
}
212235
catch (Exception)
213236
{
214-
return "";
237+
return string.Empty;
215238
}
216239

217-
return "";
240+
return string.Empty;
218241
}
219242

220243
public static string GetRemoteIpFromRequest(HttpRequest request)
@@ -223,7 +246,11 @@ public static string GetRemoteIpFromRequest(HttpRequest request)
223246
{
224247
foreach (var header in IpHeaders.Where(header => request.Headers[header].Count > 0))
225248
{
226-
return request.Headers[header][0];
249+
var extracted = GetValidIp(request.Headers[header].ToArray());
250+
if (!string.IsNullOrEmpty(extracted))
251+
{
252+
return extracted;
253+
}
227254
}
228255

229256
if (request.HttpContext.Connection.RemoteIpAddress != null)
@@ -233,10 +260,34 @@ public static string GetRemoteIpFromRequest(HttpRequest request)
233260
}
234261
catch (Exception)
235262
{
236-
return "";
263+
return string.Empty;
264+
}
265+
266+
return string.Empty;
267+
}
268+
269+
private static string GetValidIp(IEnumerable<string> ipAddresses) {
270+
foreach (var extracted in ipAddresses)
271+
{
272+
var ips = extracted.Split(",");
273+
foreach (var ip in ips)
274+
{
275+
if (IpUtils.IsValidPublicIp(ip.Trim()))
276+
{
277+
return ip.Trim();
278+
}
279+
}
280+
281+
foreach (var ip in ips)
282+
{
283+
if (!IpUtils.IsLoopBack(ip.Trim()))
284+
{
285+
return ip.Trim();
286+
}
287+
}
237288
}
238289

239-
return "";
290+
return string.Empty;
240291
}
241292
}
242293
}

SecureNative.SDK/Utils/VersionUtils.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ public static class VersionUtils
55
public static string GetVersion()
66
{
77
// TODO: parse version correctly
8-
return "2.0.2";
8+
return "2.0.3";
99
}
1010
}
1111
}

SecureNative.Tests/ConfigurationManagerTests.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public void ParseConfigFileCorrectlyTest()
2525
Assert.AreEqual("fatal", options.GetLogLevel());
2626
Assert.AreEqual(100, options.GetMaxEvents());
2727
Assert.AreEqual(1500, options.GetTimeout());
28+
Assert.AreEqual(1, options.GetProxyHeaders().Length);
2829
}
2930
#endif
3031

@@ -35,6 +36,7 @@ public void IgnoreUnknownConfigInPropertiesFileTest()
3536

3637
Assert.IsNotNull(options);
3738
Assert.AreEqual(1500, options.GetTimeout());
39+
Assert.AreEqual(1, options.GetProxyHeaders().Length);
3840
}
3941

4042
[TestMethod]
@@ -52,6 +54,7 @@ public void LoadDefaultConfigTest()
5254
Assert.AreEqual(false, options.IsDisabled());
5355
Assert.AreEqual("fatal", options.GetLogLevel());
5456
Assert.AreEqual(FailOverStrategy.FAIL_OPEN, options.GetFailOverStrategy());
57+
Assert.AreEqual(1, options.GetProxyHeaders().Length);
5558
}
5659

5760
[TestMethod]
@@ -66,6 +69,7 @@ public void GetConfigFromEnvVariablesTest()
6669
Environment.SetEnvironmentVariable("SECURENATIVE_DISABLE", "True");
6770
Environment.SetEnvironmentVariable("SECURENATIVE_LOG_LEVEL", "debug");
6871
Environment.SetEnvironmentVariable("SECURENATIVE_FAILOVER_STRATEGY", "fail-closed");
72+
Environment.SetEnvironmentVariable("SECURENATIVE_PROXY_HEADERS", "CF-Connecting-Ip,Some-Random-Ip");
6973

7074
var options = ConfigurationManager.LoadConfig("some/path");
7175

@@ -78,6 +82,8 @@ public void GetConfigFromEnvVariablesTest()
7882
Assert.AreEqual(Environment.GetEnvironmentVariable("SECURENATIVE_DISABLE"), options.IsDisabled().ToString());
7983
Assert.AreEqual(Environment.GetEnvironmentVariable("SECURENATIVE_LOG_LEVEL"), options.GetLogLevel());
8084
Assert.AreEqual(Environment.GetEnvironmentVariable("SECURENATIVE_FAILOVER_STRATEGY"), options.GetFailOverStrategy());
85+
Assert.AreEqual(options.GetProxyHeaders()[0], "CF-Connecting-Ip");
86+
Assert.AreEqual(options.GetProxyHeaders()[1], "Some-Random-Ip");
8187

8288
Environment.SetEnvironmentVariable("SECURENATIVE_API_KEY", "");
8389
Environment.SetEnvironmentVariable("SECURENATIVE_API_URL", "");
@@ -88,6 +94,7 @@ public void GetConfigFromEnvVariablesTest()
8894
Environment.SetEnvironmentVariable("SECURENATIVE_DISABLE", "");
8995
Environment.SetEnvironmentVariable("SECURENATIVE_LOG_LEVEL", "");
9096
Environment.SetEnvironmentVariable("SECURENATIVE_FAILOVER_STRATEGY", "");
97+
Environment.SetEnvironmentVariable("SECURENATIVE_PROXY_HEADERS", "");
9198
}
9299
}
93100
}

SecureNative.Tests/RequestUtilsTests.cs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace SecureNative.Tests
1010
public class RequestUtilsTests
1111
{
1212
[TestMethod]
13-
public void ExtractRequestWithProxyHeaders()
13+
public void ExtractRequestWithProxyHeadersIpv4()
1414
{
1515
var options = SecureNativeConfigurationBuilder.DefaultConfigBuilder()
1616
.WithProxyHeaders(new[] {"CF-Connecting-IP"}).Build();
@@ -28,5 +28,45 @@ public void ExtractRequestWithProxyHeaders()
2828

2929
Assert.AreEqual("203.0.113.1", clientIp);
3030
}
31+
32+
[TestMethod]
33+
public void ExtractRequestWithProxyHeadersIpv6()
34+
{
35+
var options = SecureNativeConfigurationBuilder.DefaultConfigBuilder()
36+
.WithProxyHeaders(new[] {"CF-Connecting-IP"}).Build();
37+
38+
var headers = new WebHeaderCollection
39+
{
40+
{"CF-Connecting-IP", "f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d"}
41+
};
42+
43+
var uri = new Uri("http://www.securenative.com/login");
44+
var request = WebRequest.Create(uri);
45+
request.Headers = headers;
46+
47+
var clientIp = RequestUtils.GetClientIpFromRequest((HttpWebRequest)request, options);
48+
49+
Assert.AreEqual("f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d", clientIp);
50+
}
51+
52+
[TestMethod]
53+
public void ExtractRequestWithProxyHeadersMultipleIps()
54+
{
55+
var options = SecureNativeConfigurationBuilder.DefaultConfigBuilder()
56+
.WithProxyHeaders(new[] {"CF-Connecting-IP"}).Build();
57+
58+
var headers = new WebHeaderCollection
59+
{
60+
{"CF-Connecting-IP", "141.246.115.116, 203.0.113.1, 12.34.56.3"}
61+
};
62+
63+
var uri = new Uri("http://www.securenative.com/login");
64+
var request = WebRequest.Create(uri);
65+
request.Headers = headers;
66+
67+
var clientIp = RequestUtils.GetClientIpFromRequest((HttpWebRequest)request, options);
68+
69+
Assert.AreEqual("141.246.115.116", clientIp);
70+
}
3171
}
3272
}

SecureNative.Tests/SecureNative.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<TargetFramework>netcoreapp3.1</TargetFramework>
55

66
<IsPackable>false</IsPackable>
7-
<ReleaseVersion>2.0.0</ReleaseVersion>
7+
<ReleaseVersion>2.0.4</ReleaseVersion>
88
</PropertyGroup>
99

1010
<ItemGroup>

securenative-dotnet.sln

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio 15
4-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SecureNative.SDK", "SecureNative.SDK\SecureNative.SDK.csproj", "{AF169050-5727-44F3-BA33-800BA4461F77}"
5-
EndProject
64
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SecureNative.Tests", "SecureNative.Tests\SecureNative.Tests.csproj", "{C1EBCA51-0569-4855-8862-FEDED574E85F}"
75
EndProject
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SecureNative.SDK", "SecureNative.SDK\SecureNative.SDK.csproj", "{F7AAD3F9-6BFA-4C68-AA26-90D5DA609012}"
7+
EndProject
88
Global
99
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1010
Debug|Any CPU = Debug|Any CPU
1111
Release|Any CPU = Release|Any CPU
1212
EndGlobalSection
1313
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14-
{AF169050-5727-44F3-BA33-800BA4461F77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15-
{AF169050-5727-44F3-BA33-800BA4461F77}.Debug|Any CPU.Build.0 = Debug|Any CPU
16-
{AF169050-5727-44F3-BA33-800BA4461F77}.Release|Any CPU.ActiveCfg = Release|Any CPU
17-
{AF169050-5727-44F3-BA33-800BA4461F77}.Release|Any CPU.Build.0 = Release|Any CPU
1814
{C1EBCA51-0569-4855-8862-FEDED574E85F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1915
{C1EBCA51-0569-4855-8862-FEDED574E85F}.Debug|Any CPU.Build.0 = Debug|Any CPU
2016
{C1EBCA51-0569-4855-8862-FEDED574E85F}.Release|Any CPU.ActiveCfg = Release|Any CPU
2117
{C1EBCA51-0569-4855-8862-FEDED574E85F}.Release|Any CPU.Build.0 = Release|Any CPU
18+
{F7AAD3F9-6BFA-4C68-AA26-90D5DA609012}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19+
{F7AAD3F9-6BFA-4C68-AA26-90D5DA609012}.Debug|Any CPU.Build.0 = Debug|Any CPU
20+
{F7AAD3F9-6BFA-4C68-AA26-90D5DA609012}.Release|Any CPU.ActiveCfg = Release|Any CPU
21+
{F7AAD3F9-6BFA-4C68-AA26-90D5DA609012}.Release|Any CPU.Build.0 = Release|Any CPU
2222
EndGlobalSection
2323
GlobalSection(MonoDevelopProperties) = preSolution
24-
version = 2.0.0
24+
version = 2.0.4
2525
EndGlobalSection
2626
EndGlobal

0 commit comments

Comments
 (0)