View | Details | Raw Unified | Return to bug 48653
Collapse All | Expand All

(-)test/org/apache/catalina/valves/TestRemoteIpValve.java (+274 lines)
Lines 38-43 Link Here
38
    static class RemoteAddrAndHostTrackerValve extends ValveBase {
38
    static class RemoteAddrAndHostTrackerValve extends ValveBase {
39
        private String remoteAddr;
39
        private String remoteAddr;
40
        private String remoteHost;
40
        private String remoteHost;
41
        private String scheme;
42
        private boolean secure;
43
        private int serverPort;
41
        
44
        
42
        public String getRemoteAddr() {
45
        public String getRemoteAddr() {
43
            return remoteAddr;
46
            return remoteAddr;
Lines 47-56 Link Here
47
            return remoteHost;
50
            return remoteHost;
48
        }
51
        }
49
        
52
        
53
        public String getScheme() {
54
            return scheme;
55
        }
56
57
        public int getServerPort() {
58
            return serverPort;
59
        }
60
61
        public boolean isSecure() {
62
            return secure;
63
        }
64
        
50
        @Override
65
        @Override
51
        public void invoke(Request request, Response response) throws IOException, ServletException {
66
        public void invoke(Request request, Response response) throws IOException, ServletException {
52
            this.remoteHost = request.getRemoteHost();
67
            this.remoteHost = request.getRemoteHost();
53
            this.remoteAddr = request.getRemoteAddr();
68
            this.remoteAddr = request.getRemoteAddr();
69
            this.scheme = request.getScheme();
70
            this.secure = request.isSecure();
71
            this.serverPort = request.getServerPort();
54
        }
72
        }
55
    }
73
    }
56
    
74
    
Lines 271-276 Link Here
271
        assertEquals("postInvoke remoteAddr", "remote-host-original-value", actualPostInvokeRemoteHost);
289
        assertEquals("postInvoke remoteAddr", "remote-host-original-value", actualPostInvokeRemoteHost);
272
    }
290
    }
273
    
291
    
292
    public void testInvokeXforwardedProtoSaysHttpsForIncomingHttpRequest() throws Exception {
293
        
294
        // PREPARE
295
        RemoteIpValve remoteIpValve = new RemoteIpValve();
296
        remoteIpValve.setRemoteIpHeader("x-forwarded-for");
297
        remoteIpValve.setProtocolHeader("x-forwarded-proto");
298
        RemoteAddrAndHostTrackerValve remoteAddrAndHostTrackerValve = new RemoteAddrAndHostTrackerValve();
299
        remoteIpValve.setNext(remoteAddrAndHostTrackerValve);
300
        
301
        Request request = new Request();
302
        request.setCoyoteRequest(new org.apache.coyote.Request());
303
        // client ip
304
        request.setRemoteAddr("192.168.0.10");
305
        request.setRemoteHost("192.168.0.10");
306
        request.getCoyoteRequest().getMimeHeaders().addValue("x-forwarded-for").setString("140.211.11.130");
307
        // protocol
308
        request.getCoyoteRequest().getMimeHeaders().addValue("x-forwarded-proto").setString("https");
309
        request.setSecure(false);
310
        request.setServerPort(8080);
311
        request.getCoyoteRequest().scheme().setString("http");
312
        
313
        // TEST
314
        remoteIpValve.invoke(request, null);
315
        
316
        // VERIFY
317
        // client ip
318
        String actualXForwardedFor = request.getHeader("x-forwarded-for");
319
        assertNull("no intermediate non-trusted proxy, x-forwarded-for must be null", actualXForwardedFor);
320
        
321
        String actualXForwardedBy = request.getHeader("x-forwarded-by");
322
        assertNull("no intermediate trusted proxy", actualXForwardedBy);
323
        
324
        String actualRemoteAddr = remoteAddrAndHostTrackerValve.getRemoteAddr();
325
        assertEquals("remoteAddr", "140.211.11.130", actualRemoteAddr);
326
        
327
        String actualRemoteHost = remoteAddrAndHostTrackerValve.getRemoteHost();
328
        assertEquals("remoteHost", "140.211.11.130", actualRemoteHost);
329
        
330
        String actualPostInvokeRemoteAddr = request.getRemoteAddr();
331
        assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteAddr);
332
        
333
        String actualPostInvokeRemoteHost = request.getRemoteHost();
334
        assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteHost);
335
        
336
        // protocol
337
        String actualScheme = remoteAddrAndHostTrackerValve.getScheme();
338
        assertEquals("x-forwarded-proto says https", "https", actualScheme);
339
        
340
        int actualServerPort = remoteAddrAndHostTrackerValve.getServerPort();
341
        assertEquals("x-forwarded-proto says https", 443, actualServerPort);
342
        
343
        boolean actualSecure = remoteAddrAndHostTrackerValve.isSecure();
344
        assertEquals("x-forwarded-proto says https", true, actualSecure);
345
346
        boolean actualPostInvokeSecure = request.isSecure();
347
        assertEquals("postInvoke secure", false, actualPostInvokeSecure);
348
349
        int actualPostInvokeServerPort = request.getServerPort();
350
        assertEquals("postInvoke serverPort", 8080, actualPostInvokeServerPort);
351
352
        String actualPostInvokeScheme = request.getScheme();
353
        assertEquals("postInvoke scheme", "http", actualPostInvokeScheme);
354
    }
355
    
356
    public void testInvokeXforwardedProtoIsNullForIncomingHttpRequest() throws Exception {
357
        
358
        // PREPARE
359
        RemoteIpValve remoteIpValve = new RemoteIpValve();
360
        remoteIpValve.setRemoteIpHeader("x-forwarded-for");
361
        remoteIpValve.setProtocolHeader("x-forwarded-proto");
362
        RemoteAddrAndHostTrackerValve remoteAddrAndHostTrackerValve = new RemoteAddrAndHostTrackerValve();
363
        remoteIpValve.setNext(remoteAddrAndHostTrackerValve);
364
        
365
        Request request = new Request();
366
        request.setCoyoteRequest(new org.apache.coyote.Request());
367
        // client ip
368
        request.setRemoteAddr("192.168.0.10");
369
        request.setRemoteHost("192.168.0.10");
370
        request.getCoyoteRequest().getMimeHeaders().addValue("x-forwarded-for").setString("140.211.11.130");
371
        // protocol
372
        // null "x-forwarded-proto"
373
        request.setSecure(false);
374
        request.setServerPort(8080);
375
        request.getCoyoteRequest().scheme().setString("http");
376
        
377
        // TEST
378
        remoteIpValve.invoke(request, null);
379
        
380
        // VERIFY
381
        // client ip
382
        String actualXForwardedFor = request.getHeader("x-forwarded-for");
383
        assertNull("no intermediate non-trusted proxy, x-forwarded-for must be null", actualXForwardedFor);
384
        
385
        String actualXForwardedBy = request.getHeader("x-forwarded-by");
386
        assertNull("no intermediate trusted proxy", actualXForwardedBy);
387
        
388
        String actualRemoteAddr = remoteAddrAndHostTrackerValve.getRemoteAddr();
389
        assertEquals("remoteAddr", "140.211.11.130", actualRemoteAddr);
390
        
391
        String actualRemoteHost = remoteAddrAndHostTrackerValve.getRemoteHost();
392
        assertEquals("remoteHost", "140.211.11.130", actualRemoteHost);
393
        
394
        String actualPostInvokeRemoteAddr = request.getRemoteAddr();
395
        assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteAddr);
396
        
397
        String actualPostInvokeRemoteHost = request.getRemoteHost();
398
        assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteHost);
399
        
400
        // protocol
401
        String actualScheme = remoteAddrAndHostTrackerValve.getScheme();
402
        assertEquals("x-forwarded-proto is null", "http", actualScheme);
403
        
404
        int actualServerPort = remoteAddrAndHostTrackerValve.getServerPort();
405
        assertEquals("x-forwarded-proto is null", 8080, actualServerPort);
406
        
407
        boolean actualSecure = remoteAddrAndHostTrackerValve.isSecure();
408
        assertEquals("x-forwarded-proto is null", false, actualSecure);
409
410
        boolean actualPostInvokeSecure = request.isSecure();
411
        assertEquals("postInvoke secure", false, actualPostInvokeSecure);
412
413
        int actualPostInvokeServerPort = request.getServerPort();
414
        assertEquals("postInvoke serverPort", 8080, actualPostInvokeServerPort);
415
416
        String actualPostInvokeScheme = request.getScheme();
417
        assertEquals("postInvoke scheme", "http", actualPostInvokeScheme);
418
    }
419
    
420
    public void testInvokeXforwardedProtoSaysHttpForIncomingHttpsRequest() throws Exception {
421
        
422
        // PREPARE
423
        RemoteIpValve remoteIpValve = new RemoteIpValve();
424
        remoteIpValve.setRemoteIpHeader("x-forwarded-for");
425
        remoteIpValve.setProtocolHeader("x-forwarded-proto");
426
        RemoteAddrAndHostTrackerValve remoteAddrAndHostTrackerValve = new RemoteAddrAndHostTrackerValve();
427
        remoteIpValve.setNext(remoteAddrAndHostTrackerValve);
428
        
429
        Request request = new Request();
430
        request.setCoyoteRequest(new org.apache.coyote.Request());
431
        // client ip
432
        request.setRemoteAddr("192.168.0.10");
433
        request.setRemoteHost("192.168.0.10");
434
        request.getCoyoteRequest().getMimeHeaders().addValue("x-forwarded-for").setString("140.211.11.130");
435
        // protocol
436
        request.getCoyoteRequest().getMimeHeaders().addValue("x-forwarded-proto").setString("http");
437
        request.setSecure(true);
438
        request.setServerPort(8443);
439
        request.getCoyoteRequest().scheme().setString("https");
440
        
441
        // TEST
442
        remoteIpValve.invoke(request, null);
443
        
444
        // VERIFY
445
        // client ip
446
        String actualXForwardedFor = request.getHeader("x-forwarded-for");
447
        assertNull("no intermediate non-trusted proxy, x-forwarded-for must be null", actualXForwardedFor);
448
        
449
        String actualXForwardedBy = request.getHeader("x-forwarded-by");
450
        assertNull("no intermediate trusted proxy", actualXForwardedBy);
451
        
452
        String actualRemoteAddr = remoteAddrAndHostTrackerValve.getRemoteAddr();
453
        assertEquals("remoteAddr", "140.211.11.130", actualRemoteAddr);
454
        
455
        String actualRemoteHost = remoteAddrAndHostTrackerValve.getRemoteHost();
456
        assertEquals("remoteHost", "140.211.11.130", actualRemoteHost);
457
        
458
        String actualPostInvokeRemoteAddr = request.getRemoteAddr();
459
        assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteAddr);
460
        
461
        String actualPostInvokeRemoteHost = request.getRemoteHost();
462
        assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteHost);
463
        
464
        // protocol
465
        String actualScheme = remoteAddrAndHostTrackerValve.getScheme();
466
        assertEquals("x-forwarded-proto says http", "http", actualScheme);
467
        
468
        int actualServerPort = remoteAddrAndHostTrackerValve.getServerPort();
469
        assertEquals("x-forwarded-proto says http", 80, actualServerPort);
470
        
471
        boolean actualSecure = remoteAddrAndHostTrackerValve.isSecure();
472
        assertEquals("x-forwarded-proto says http", false, actualSecure);
473
474
        boolean actualPostInvokeSecure = request.isSecure();
475
        assertEquals("postInvoke secure", true, actualPostInvokeSecure);
476
477
        int actualPostInvokeServerPort = request.getServerPort();
478
        assertEquals("postInvoke serverPort", 8443, actualPostInvokeServerPort);
479
480
        String actualPostInvokeScheme = request.getScheme();
481
        assertEquals("postInvoke scheme", "https", actualPostInvokeScheme);
482
    }
483
    
484
    public void testInvokeXforwardedProtoIsNullForIncomingHttpsRequest() throws Exception {
485
        
486
        // PREPARE
487
        RemoteIpValve remoteIpValve = new RemoteIpValve();
488
        remoteIpValve.setRemoteIpHeader("x-forwarded-for");
489
        remoteIpValve.setProtocolHeader("x-forwarded-proto");
490
        RemoteAddrAndHostTrackerValve remoteAddrAndHostTrackerValve = new RemoteAddrAndHostTrackerValve();
491
        remoteIpValve.setNext(remoteAddrAndHostTrackerValve);
492
        
493
        Request request = new Request();
494
        request.setCoyoteRequest(new org.apache.coyote.Request());
495
        // client ip
496
        request.setRemoteAddr("192.168.0.10");
497
        request.setRemoteHost("192.168.0.10");
498
        request.getCoyoteRequest().getMimeHeaders().addValue("x-forwarded-for").setString("140.211.11.130");
499
        // protocol
500
        // Don't declare "x-forwarded-proto"
501
        request.setSecure(true);
502
        request.setServerPort(8443);
503
        request.getCoyoteRequest().scheme().setString("https");
504
        
505
        // TEST
506
        remoteIpValve.invoke(request, null);
507
        
508
        // VERIFY
509
        // client ip
510
        String actualXForwardedFor = request.getHeader("x-forwarded-for");
511
        assertNull("no intermediate non-trusted proxy, x-forwarded-for must be null", actualXForwardedFor);
512
        
513
        String actualXForwardedBy = request.getHeader("x-forwarded-by");
514
        assertNull("no intermediate trusted proxy", actualXForwardedBy);
515
        
516
        String actualRemoteAddr = remoteAddrAndHostTrackerValve.getRemoteAddr();
517
        assertEquals("remoteAddr", "140.211.11.130", actualRemoteAddr);
518
        
519
        String actualRemoteHost = remoteAddrAndHostTrackerValve.getRemoteHost();
520
        assertEquals("remoteHost", "140.211.11.130", actualRemoteHost);
521
        
522
        String actualPostInvokeRemoteAddr = request.getRemoteAddr();
523
        assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteAddr);
524
        
525
        String actualPostInvokeRemoteHost = request.getRemoteHost();
526
        assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteHost);
527
        
528
        // protocol
529
        String actualScheme = remoteAddrAndHostTrackerValve.getScheme();
530
        assertEquals("x-forwarded-proto is null", "https", actualScheme);
531
        
532
        int actualServerPort = remoteAddrAndHostTrackerValve.getServerPort();
533
        assertEquals("x-forwarded-proto is null", 8443, actualServerPort);
534
        
535
        boolean actualSecure = remoteAddrAndHostTrackerValve.isSecure();
536
        assertEquals("x-forwarded-proto is null", true, actualSecure);
537
538
        boolean actualPostInvokeSecure = request.isSecure();
539
        assertEquals("postInvoke secure", true, actualPostInvokeSecure);
540
541
        int actualPostInvokeServerPort = request.getServerPort();
542
        assertEquals("postInvoke serverPort", 8443, actualPostInvokeServerPort);
543
544
        String actualPostInvokeScheme = request.getScheme();
545
        assertEquals("postInvoke scheme", "https", actualPostInvokeScheme);
546
    }
547
    
274
    public void testInvokeNotAllowedRemoteAddr() throws Exception {
548
    public void testInvokeNotAllowedRemoteAddr() throws Exception {
275
        // PREPARE
549
        // PREPARE
276
        RemoteIpValve remoteIpValve = new RemoteIpValve();
550
        RemoteIpValve remoteIpValve = new RemoteIpValve();
(-)java/org/apache/catalina/valves/RemoteIpValve.java (-2 / +46 lines)
Lines 26-31 Link Here
26
import java.util.regex.PatternSyntaxException;
26
import java.util.regex.PatternSyntaxException;
27
27
28
import javax.servlet.ServletException;
28
import javax.servlet.ServletException;
29
import javax.servlet.ServletRequest;
29
30
30
import org.apache.tomcat.util.res.StringManager;
31
import org.apache.tomcat.util.res.StringManager;
31
import org.apache.catalina.connector.Request;
32
import org.apache.catalina.connector.Request;
Lines 126-131 Link Here
126
 * <td><code>https</code></td>
127
 * <td><code>https</code></td>
127
 * </tr>
128
 * </tr>
128
 * <tr>
129
 * <tr>
130
 * <td>httpServerPort</td>
131
 * <td>Value returned by {@link ServletRequest#getServerPort()} when the <code>protocolHeader</code> indicates <code>http</code> protocol</td>
132
 * <td>N/A</td>
133
 * <td>integer</td>
134
 * <td>80</td>
135
 * </tr>
136
 * <tr>
137
 * <td>httpsServerPort</td>
138
 * <td>Value returned by {@link ServletRequest#getServerPort()} when the <code>protocolHeader</code> indicates <code>https</code> protocol</td>
139
 * <td>N/A</td>
140
 * <td>integer</td>
141
 * <td>443</td>
142
 * </tr>
129
 * </table>
143
 * </table>
130
 * </p>
144
 * </p>
131
 * <p>
145
 * <p>
Lines 415-420 Link Here
415
    }
429
    }
416
    
430
    
417
    /**
431
    /**
432
     * @see #setHttpServerPort(int)
433
     */
434
    private int httpServerPort = 80;
435
    
436
    /**
418
     * @see #setHttpsServerPort(int)
437
     * @see #setHttpsServerPort(int)
419
     */
438
     */
420
    private int httpsServerPort = 443;
439
    private int httpsServerPort = 443;
Lines 456-461 Link Here
456
        return httpsServerPort;
475
        return httpsServerPort;
457
    }
476
    }
458
    
477
    
478
    public int getHttpServerPort() {
479
        return httpServerPort;
480
    }
481
    
459
    /**
482
    /**
460
     * Return descriptive information about this Valve implementation.
483
     * Return descriptive information about this Valve implementation.
461
     */
484
     */
Lines 507-513 Link Here
507
    public String getRemoteIpHeader() {
530
    public String getRemoteIpHeader() {
508
        return remoteIpHeader;
531
        return remoteIpHeader;
509
    }
532
    }
510
    
533
511
    /**
534
    /**
512
     * @see #setTrustedProxies(String)
535
     * @see #setTrustedProxies(String)
513
     * @return comma delimited list of trusted proxies
536
     * @return comma delimited list of trusted proxies
Lines 580-591 Link Here
580
            
603
            
581
            if (protocolHeader != null) {
604
            if (protocolHeader != null) {
582
                String protocolHeaderValue = request.getHeader(protocolHeader);
605
                String protocolHeaderValue = request.getHeader(protocolHeader);
583
                if (protocolHeaderValue != null && protocolHeaderHttpsValue.equalsIgnoreCase(protocolHeaderValue)) {
606
                if (protocolHeaderValue == null) {
607
                    // don't modify the secure,scheme and serverPort attributes
608
                    // of the request
609
                } else if (protocolHeaderHttpsValue.equalsIgnoreCase(protocolHeaderValue)) {
584
                    request.setSecure(true);
610
                    request.setSecure(true);
585
                    // use request.coyoteRequest.scheme instead of request.setScheme() because request.setScheme() is no-op in Tomcat 6.0
611
                    // use request.coyoteRequest.scheme instead of request.setScheme() because request.setScheme() is no-op in Tomcat 6.0
586
                    request.getCoyoteRequest().scheme().setString("https");
612
                    request.getCoyoteRequest().scheme().setString("https");
587
                    
613
                    
588
                    request.setServerPort(httpsServerPort);
614
                    request.setServerPort(httpsServerPort);
615
                } else {
616
                    request.setSecure(false);
617
                    // use request.coyoteRequest.scheme instead of request.setScheme() because request.setScheme() is no-op in Tomcat 6.0
618
                    request.getCoyoteRequest().scheme().setString("http");
619
                    
620
                    request.setServerPort(httpServerPort);
589
                }
621
                }
590
            }
622
            }
591
            
623
            
Lines 613-618 Link Here
613
    
645
    
614
    /**
646
    /**
615
     * <p>
647
     * <p>
648
     * Server Port value if the {@link #protocolHeader} is not <code>null</code> and does not indicate HTTP
649
     * </p>
650
     * <p>
651
     * Default value : 80
652
     * </p>
653
     */
654
    public void setHttpServerPort(int httpServerPort) {
655
        this.httpServerPort = httpServerPort;
656
    }
657
    
658
    /**
659
     * <p>
616
     * Server Port value if the {@link #protocolHeader} indicates HTTPS
660
     * Server Port value if the {@link #protocolHeader} indicates HTTPS
617
     * </p>
661
     * </p>
618
     * <p>
662
     * <p>
(-)java/org/apache/catalina/valves/mbeans-descriptors.xml (-2 / +12 lines)
Lines 365-371 Link Here
365
               description="Comma delimited list of internal proxies"
365
               description="Comma delimited list of internal proxies"
366
               type="java.lang.String"
366
               type="java.lang.String"
367
               writeable="false" />
367
               writeable="false" />
368
               
368
369
    <attribute name="httpServerPort"
370
               description="Value returned by ServletRequest.getServerPort() when the protocolHeader indicates http protocol"
371
               type="java.lang.String"
372
               writeable="false" />
373
    
374
    <attribute name="httpsServerPort"
375
               description="Value returned by ServletRequest.getServerPort() when the protocolHeader indicates https protocol"
376
               type="java.lang.String"
377
               writeable="false" />
378
    
369
    <attribute name="protocolHeader"
379
    <attribute name="protocolHeader"
370
               description="The protocol header (e.g. &quot;X-Forwarded-Proto&quot;)"
380
               description="The protocol header (e.g. &quot;X-Forwarded-Proto&quot;)"
371
               type="java.lang.String"
381
               type="java.lang.String"
Lines 381-387 Link Here
381
               type="java.lang.String"
391
               type="java.lang.String"
382
               writeable="false" />
392
               writeable="false" />
383
               
393
               
384
    <attribute name="remoteIpHedaer"
394
    <attribute name="remoteIpHeader"
385
               description="The remote IP header name (e.g. &quot;X-Forwarded-For&quot;)"
395
               description="The remote IP header name (e.g. &quot;X-Forwarded-For&quot;)"
386
               type="java.lang.String"
396
               type="java.lang.String"
387
               writeable="false" />
397
               writeable="false" />
(-)webapps/docs/config/valve.xml (-3 / +18 lines)
Lines 622-630 Link Here
622
    via a request headers (e.g. &quot;X-Forwarded-For&quot;).</p>
622
    via a request headers (e.g. &quot;X-Forwarded-For&quot;).</p>
623
623
624
    <p>Another feature of this valve is to replace the apparent scheme
624
    <p>Another feature of this valve is to replace the apparent scheme
625
    (http/https) and server port with the scheme presented by a proxy or a load
625
    (http/https), server port and <code>request.secure</code> with the scheme presented 
626
    balancer via a request header (e.g. &quot;X-Forwarded-Proto&quot;).</p>
626
    by a proxy or a load balancer via a request header 
627
 
627
    (e.g. &quot;X-Forwarded-Proto&quot;).</p>
628
    
628
    <p>This Valve may be used at the <code>Engine</code>, <code>Host</code> or
629
    <p>This Valve may be used at the <code>Engine</code>, <code>Host</code> or
629
    <code>Context</code> level as required. Normally, this Valve would be used
630
    <code>Context</code> level as required. Normally, this Valve would be used
630
    at the <code>Engine</code> level.</p>
631
    at the <code>Engine</code> level.</p>
Lines 690-695 Link Here
690
        used.</p>
691
        used.</p>
691
      </attribute>
692
      </attribute>
692
693
694
      <attribute name="httpServerPort" required="false">
695
         <p>Value returned by <code>ServletRequest.getServerPort()</code> 
696
         when the <strong>protocolHeader</strong> indicates <code>http</code> 
697
         protocol. If not specified, the default of <code>80</code> is
698
        used.</p>
699
      </attribute>
700
701
      <attribute name="httpsServerPort" required="false">
702
         <p>Value returned by <code>ServletRequest.getServerPort()</code> 
703
         when the <strong>protocolHeader</strong> indicates <code>https</code> 
704
         protocol. If not specified, the default of <code>443</code> is
705
        used.</p>
706
      </attribute>
707
      
693
    </attributes>
708
    </attributes>
694
709
695
  </subsection>
710
  </subsection>

Return to bug 48653