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

(-)java/org/apache/catalina/valves/RemoteIpValve.java (-2 / +22 lines)
Lines 60-66 import org.apache.tomcat.util.http.MimeHeaders; Link Here
60
 * <li>otherwise, the ip/host is declared to be the remote ip and looping is stopped.</li>
60
 * <li>otherwise, the ip/host is declared to be the remote ip and looping is stopped.</li>
61
 * </ul>
61
 * </ul>
62
 * </li>
62
 * </li>
63
 * <li>If the request http header named <code>$protocolHeader</code> (e.g. <code>x-forwarded-for</code>) equals to the value of
63
 * <li>If the request http header named <code>$protocolHeader</code> (e.g. <code>x-forwarded-proto</code>) consists only of forwards that match
64
 * <code>protocolHeaderHttpsValue</code> configuration parameter (default <code>https</code>) then <code>request.isSecure = true</code>,
64
 * <code>protocolHeaderHttpsValue</code> configuration parameter (default <code>https</code>) then <code>request.isSecure = true</code>,
65
 * <code>request.scheme = https</code> and <code>request.serverPort = 443</code>. Note that 443 can be overwritten with the
65
 * <code>request.scheme = https</code> and <code>request.serverPort = 443</code>. Note that 443 can be overwritten with the
66
 * <code>$httpsServerPort</code> configuration parameter.</li>
66
 * <code>$httpsServerPort</code> configuration parameter.</li>
Lines 642-648 public class RemoteIpValve extends ValveBase { Link Here
642
                if (protocolHeaderValue == null) {
642
                if (protocolHeaderValue == null) {
643
                    // don't modify the secure,scheme and serverPort attributes
643
                    // don't modify the secure,scheme and serverPort attributes
644
                    // of the request
644
                    // of the request
645
                } else if (protocolHeaderHttpsValue.equalsIgnoreCase(protocolHeaderValue)) {
645
                } else if (isForwardedProtoHeaderValueSecure(protocolHeaderValue)) {
646
                    request.setSecure(true);
646
                    request.setSecure(true);
647
                    // use request.coyoteRequest.scheme instead of request.setScheme() because request.setScheme() is no-op in Tomcat 6.0
647
                    // use request.coyoteRequest.scheme instead of request.setScheme() because request.setScheme() is no-op in Tomcat 6.0
648
                    request.getCoyoteRequest().scheme().setString("https");
648
                    request.getCoyoteRequest().scheme().setString("https");
Lines 709-714 public class RemoteIpValve extends ValveBase { Link Here
709
        }
709
        }
710
    }
710
    }
711
711
712
    /**
713
     * Considers the value to be secure if it exclusively holds forwards for
714
     * {@link #protocolHeaderHttpsValue}.
715
     */
716
    private boolean isForwardedProtoHeaderValueSecure(String protocolHeaderValue) {
717
        if (!protocolHeaderValue.contains(",")) {
718
            return protocolHeaderHttpsValue.equalsIgnoreCase(protocolHeaderValue);
719
        }
720
        String[] forwardedProtocols = commaDelimitedListToStringArray(protocolHeaderValue);
721
        if (forwardedProtocols.length == 0) {
722
            return false;
723
        }
724
        for (int i = 0; i < forwardedProtocols.length; i++) {
725
            if (!protocolHeaderHttpsValue.equalsIgnoreCase(forwardedProtocols[i])) {
726
                return false;
727
            }
728
        }
729
        return true;
730
    }
731
712
    private void setPorts(Request request, int defaultPort) {
732
    private void setPorts(Request request, int defaultPort) {
713
        int port = defaultPort;
733
        int port = defaultPort;
714
        if (portHeader != null) {
734
        if (portHeader != null) {
(-)test/org/apache/catalina/valves/TestRemoteIpValve.java (+99 lines)
Lines 683-688 public class TestRemoteIpValve { Link Here
683
        Assert.assertEquals("postInvoke scheme", "https", actualPostInvokeScheme);
683
        Assert.assertEquals("postInvoke scheme", "https", actualPostInvokeScheme);
684
    }
684
    }
685
685
686
    @Test
687
    public void testInvokeXforwardedProtoSaysMultipleHttpsForwardsForIncomingHttpsRequest() throws Exception {
688
        performXForwardedProtoWithMultipleForwardsTest("https,https", true, true);
689
    }
690
691
    @Test
692
    public void testInvokeXforwardedProtoSaysMultipleForwardsWithFirstBeingHttpForIncomingHttpsRequest() throws Exception {
693
        performXForwardedProtoWithMultipleForwardsTest("http,https", true, false);
694
    }
695
696
    @Test
697
    public void testInvokeXforwardedProtoSaysMultipleForwardsWithLastBeingHttpForIncomingHttpsRequest() throws Exception {
698
        performXForwardedProtoWithMultipleForwardsTest("https,http", false, false);
699
    }
700
701
    @Test
702
    public void testInvokeXforwardedProtoSaysMultipleForwardsWithMiddleBeingHttpForIncomingHttpsRequest() throws Exception {
703
        performXForwardedProtoWithMultipleForwardsTest("https,http,https", true, false);
704
    }
705
706
    @Test
707
    public void testInvokeXforwardedProtoSaysMultipleHttpForwardsForIncomingHttpsRequest() throws Exception {
708
        performXForwardedProtoWithMultipleForwardsTest("http,http", false, false);
709
    }
710
711
    @Test
712
    public void testInvokeXforwardedProtoSaysInvalidValueForIncomingHttpsRequest() throws Exception {
713
        performXForwardedProtoWithMultipleForwardsTest(",", false, false);
714
    }
715
716
    private void performXForwardedProtoWithMultipleForwardsTest(String incomingHeaderValue,
717
            boolean arrivesAsSecure, boolean shouldBeSecure) throws Exception {
718
719
        // PREPARE
720
        String incomingScheme = arrivesAsSecure ? "https" : "http";
721
        String expectedScheme = shouldBeSecure ? "https" : "http";
722
        int incommingServerPort = arrivesAsSecure ? 8443 : 8080;
723
        int expectedServerPort = shouldBeSecure ? 443 : 80;
724
        RemoteIpValve remoteIpValve = new RemoteIpValve();
725
        remoteIpValve.setRemoteIpHeader("x-forwarded-for");
726
        remoteIpValve.setProtocolHeader("x-forwarded-proto");
727
        RemoteAddrAndHostTrackerValve remoteAddrAndHostTrackerValve = new RemoteAddrAndHostTrackerValve();
728
        remoteIpValve.setNext(remoteAddrAndHostTrackerValve);
729
730
        Request request = new MockRequest();
731
        request.setCoyoteRequest(new org.apache.coyote.Request());
732
        // client ip
733
        request.setRemoteAddr("192.168.0.10");
734
        request.setRemoteHost("192.168.0.10");
735
        request.getCoyoteRequest().getMimeHeaders().addValue("x-forwarded-for").setString("140.211.11.130");
736
        // protocol
737
        request.getCoyoteRequest().getMimeHeaders().addValue("x-forwarded-proto").setString(incomingHeaderValue);
738
        request.setSecure(arrivesAsSecure);
739
        request.setServerPort(incommingServerPort);
740
        request.getCoyoteRequest().scheme().setString(incomingScheme);
741
742
        // TEST
743
        remoteIpValve.invoke(request, null);
744
745
        // VERIFY
746
        // client ip
747
        String actualXForwardedFor = remoteAddrAndHostTrackerValve.getForwardedFor();
748
        Assert.assertNull("no intermediate non-trusted proxy, x-forwarded-for must be null", actualXForwardedFor);
749
750
        String actualXForwardedBy = remoteAddrAndHostTrackerValve.getForwardedBy();
751
        Assert.assertNull("no intermediate trusted proxy", actualXForwardedBy);
752
753
        String actualRemoteAddr = remoteAddrAndHostTrackerValve.getRemoteAddr();
754
        Assert.assertEquals("remoteAddr", "140.211.11.130", actualRemoteAddr);
755
756
        String actualRemoteHost = remoteAddrAndHostTrackerValve.getRemoteHost();
757
        Assert.assertEquals("remoteHost", "140.211.11.130", actualRemoteHost);
758
759
        String actualPostInvokeRemoteAddr = request.getRemoteAddr();
760
        Assert.assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteAddr);
761
762
        String actualPostInvokeRemoteHost = request.getRemoteHost();
763
        Assert.assertEquals("postInvoke remoteAddr", "192.168.0.10", actualPostInvokeRemoteHost);
764
765
        // protocol
766
        String actualScheme = remoteAddrAndHostTrackerValve.getScheme();
767
        Assert.assertEquals("x-forwarded-proto says " + expectedScheme, expectedScheme, actualScheme);
768
769
        int actualServerPort = remoteAddrAndHostTrackerValve.getServerPort();
770
        Assert.assertEquals("x-forwarded-proto says " + expectedScheme, expectedServerPort, actualServerPort);
771
772
        boolean actualSecure = remoteAddrAndHostTrackerValve.isSecure();
773
        Assert.assertEquals("x-forwarded-proto says " + expectedScheme, shouldBeSecure, actualSecure);
774
775
        boolean actualPostInvokeSecure = request.isSecure();
776
        Assert.assertEquals("postInvoke secure", arrivesAsSecure, actualPostInvokeSecure);
777
778
        int actualPostInvokeServerPort = request.getServerPort();
779
        Assert.assertEquals("postInvoke serverPort", incommingServerPort, actualPostInvokeServerPort);
780
781
        String actualPostInvokeScheme = request.getScheme();
782
        Assert.assertEquals("postInvoke scheme", incomingScheme, actualPostInvokeScheme);
783
    }
784
686
    @Test
785
    @Test
687
    public void testInvokeXforwardedProtoIsNullForIncomingHttpsRequest() throws Exception {
786
    public void testInvokeXforwardedProtoIsNullForIncomingHttpsRequest() throws Exception {
688
787

Return to bug 62978