1+ using Microsoft . AspNetCore . Builder ;
12using Microsoft . AspNetCore . Hosting ;
3+ using Microsoft . AspNetCore . Http ;
24using Microsoft . AspNetCore . TestHost ;
35using Microsoft . Extensions . DependencyInjection ;
46
@@ -9,6 +11,7 @@ public class IntegrationsTests : IDisposable
911 private readonly TestServer _server ;
1012 private HttpClient _httpClient ;
1113 private MockHttpMessageHandler _httpMessageHandler ;
14+ private const string FakeRequestIp = "192.168.200.200" ;
1215
1316 public IntegrationsTests ( )
1417 {
@@ -22,7 +25,16 @@ public IntegrationsTests()
2225 factory . CreateClient ( Arg . Any < string > ( ) ) . Returns ( _httpClient ) ;
2326 s . AddSingleton ( factory ) ;
2427 } )
25- . Configure ( app => { app . UseSentryTunneling ( ) ; } ) ;
28+ . Configure ( app =>
29+ {
30+ app . Use ( ( context , next ) =>
31+ {
32+ // The context doesn't get sent by TestServer automatically... so we fake a remote request here
33+ context . Connection . RemoteIpAddress = IPAddress . Parse ( FakeRequestIp ) ;
34+ return next ( ) ;
35+ } ) ;
36+ app . UseSentryTunneling ( ) ;
37+ } ) ;
2638 _server = new TestServer ( builder ) ;
2739 }
2840
@@ -35,9 +47,11 @@ public async Task TunnelMiddleware_CanForwardValidEnvelope(string host)
3547 var requestMessage = new HttpRequestMessage ( new HttpMethod ( "POST" ) , "/tunnel" )
3648 {
3749 Content = new StringContent (
38- @"{""sent_at"":""2021-01-01T00:00:00.000Z"",""sdk"":{""name"":""sentry.javascript.browser"",""version"":""6.8.0""},""dsn"":""https://dns@" + host + @"/1""}
39- {""type"":""session""}
40- {""sid"":""fda00e933162466c849962eaea0cfaff""}" )
50+ $$ """
51+ {"sent_at":"2021-01-01T00:00:00.000Z","sdk":{"name":"sentry.javascript.browser","version":"6.8.0"},"dsn":"https://dns@{{ host }} /1"}
52+ {"type":"session"}
53+ {"sid":"fda00e933162466c849962eaea0cfaff"}
54+ """ )
4155 } ;
4256 await _server . CreateClient ( ) . SendAsync ( requestMessage ) ;
4357
@@ -49,9 +63,12 @@ public async Task TunnelMiddleware_DoesNotForwardEnvelopeWithoutDsn()
4963 {
5064 var requestMessage = new HttpRequestMessage ( new HttpMethod ( "POST" ) , "/tunnel" )
5165 {
52- Content = new StringContent ( @"{}
53- {""type"":""session""}
54- {""sid"":""fda00e933162466c849962eaea0cfaff""}" )
66+ Content = new StringContent (
67+ """
68+ {}
69+ {"type":"session"}
70+ {"sid":"fda00e933162466c849962eaea0cfaff"}
71+ """ )
5572 } ;
5673 await _server . CreateClient ( ) . SendAsync ( requestMessage ) ;
5774
@@ -63,9 +80,11 @@ public async Task TunnelMiddleware_DoesNotForwardEnvelopeToArbitraryHost()
6380 {
6481 var requestMessage = new HttpRequestMessage ( new HttpMethod ( "POST" ) , "/tunnel" ) ;
6582 requestMessage . Content = new StringContent (
66- @"{""sent_at"":""2021-01-01T00:00:00.000Z"",""sdk"":{""name"":""sentry.javascript.browser"",""version"":""6.8.0""},""dsn"":""https://dns@evil.com/1""}
67- {""type"":""session""}
68- {""sid"":""fda00e933162466c849962eaea0cfaff""}" ) ;
83+ """
84+ {"sent_at":"2021-01-01T00:00:00.000Z","sdk":{"name":"sentry.javascript.browser","version":"6.8.0"},"dsn":"https://dns@evil.com/1"}
85+ {"type":"session"}
86+ {"sid":"fda00e933162466c849962eaea0cfaff"}
87+ """ ) ;
6988 await _server . CreateClient ( ) . SendAsync ( requestMessage ) ;
7089
7190 Assert . Equal ( 0 , _httpMessageHandler . NumberOfCalls ) ;
@@ -77,13 +96,46 @@ public async Task TunnelMiddleware_CanForwardEnvelopeToWhiteListedHost()
7796 var requestMessage = new HttpRequestMessage ( new HttpMethod ( "POST" ) , "/tunnel" )
7897 {
7998 Content = new StringContent (
80- @"{""sent_at"":""2021-01-01T00:00:00.000Z"",""sdk"":{""name"":""sentry.javascript.browser"",""version"":""6.8.0""},""dsn"":""https://dns@sentry.mywebsite.com/1""}
81- {""type"":""session""}
82- {""sid"":""fda00e933162466c849962eaea0cfaff""}" )
99+ """
100+ {"sent_at":"2021-01-01T00:00:00.000Z","sdk":{"name":"sentry.javascript.browser","version":"6.8.0"},"dsn":"https://dns@sentry.mywebsite.com/1"}
101+ {"type":"session"}
102+ {"sid":"fda00e933162466c849962eaea0cfaff"}
103+ """ )
104+ } ;
105+ await _server . CreateClient ( ) . SendAsync ( requestMessage ) ;
106+
107+ Assert . Equal ( 1 , _httpMessageHandler . NumberOfCalls ) ;
108+ }
109+
110+ [ Fact ]
111+ public async Task TunnelMiddleware_XForwardedFor_RetainsOriginIp ( )
112+ {
113+ // Arrange: Create a request with X-Forwarded-For header
114+ var requestMessage = new HttpRequestMessage ( new HttpMethod ( "POST" ) , "/tunnel" )
115+ {
116+ Content = new StringContent (
117+ """
118+ {"sent_at":"2021-01-01T00:00:00.000Z","sdk":{"name":"sentry.javascript.browser","version":"6.8.0"},"dsn":"https://dns@sentry.io/1"}
119+ {"type":"session"}
120+ {"sid":"fda00e933162466c849962eaea0cfaff"}
121+ """ )
83122 } ;
123+ const string originalForwardedFor = "192.168.1.100, 10.0.0.1" ;
124+ requestMessage . Headers . Add ( "X-Forwarded-For" , originalForwardedFor ) ;
125+
126+ // Act
84127 await _server . CreateClient ( ) . SendAsync ( requestMessage ) ;
85128
129+ // Assert
86130 Assert . Equal ( 1 , _httpMessageHandler . NumberOfCalls ) ;
131+
132+ var forwardedRequest = _httpMessageHandler . LastRequest ;
133+ Assert . NotNull ( forwardedRequest ) ;
134+
135+ Assert . True ( forwardedRequest . Headers . Contains ( "X-Forwarded-For" ) ) ;
136+ var forwardedForHeader = forwardedRequest . Headers . GetValues ( "X-Forwarded-For" ) . FirstOrDefault ( ) ;
137+ Assert . NotNull ( forwardedForHeader ) ;
138+ forwardedForHeader . Should ( ) . Be ( $ "{ originalForwardedFor } , { FakeRequestIp } ") ;
87139 }
88140
89141 public void Dispose ( )
0 commit comments