Chemistry
  1. Chemistry
  2. CMIS-500

AtomPubUtils: Take the X-Forwarded-Host and X-Forwarded-Proto request headers into account when calculating the baseUrl

    Details

    • Type: Improvement Improvement
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: OpenCMIS 0.7.0
    • Fix Version/s: OpenCMIS 0.7.0
    • Component/s: opencmis-server
    • Labels:

      Description

      When the OpenCMIS server is deployed behind a reverse proxy, the service document doesn't return the correct URLs.

      If it takes the X-Forwarded-Host and X-Forwarded-Proto request headers into account when calculating the baseUrl the URLs are correct.

      A patch against revision 1241367 is attached.

        Activity

        Hide
        Florent Guillaume added a comment -

        Florian why do you say "These headers are easy to spoof and could become a security issue"? We just generate URLs for the client that sent us this header, it's not a security issue, the client will use them, not us.

        There are tons of application that generate URLs taking into account these headers. I don't see why we have to go through a complex valve or filter setup.

        Show
        Florent Guillaume added a comment - Florian why do you say "These headers are easy to spoof and could become a security issue"? We just generate URLs for the client that sent us this header, it's not a security issue, the client will use them, not us. There are tons of application that generate URLs taking into account these headers. I don't see why we have to go through a complex valve or filter setup.
        Hide
        Gert Dewit added a comment - - edited

        This seems a good strategy to me.
        This filter can be used where the combination of the correct Apache reverse proxy config and Tomcat RemoteIpValve is not possible (no Apache reverse proxy, No Apache Tomcat).

        The sample configs below can be used with an Apache HTTP Server based reverse proxy and Apache Tomcat as backed server.
        The published url for the application is https://www.frontend.org/cmis, the Apache HTTP server handles https termination and it's IP address is 192.168.100.254.

        httpd.conf snippet:

        <Location /cmis>
          RequestHeader set X-Forwarded-Proto "https"
          ProxyPreserveHost
          ProxyPass http://tomcat.backend.org:8080/cmis
          ProxyPassReverse http://tomcat.backend.org:8080/cmis
        </Location>

        The ProxyPreserveHost directive will pass the Original Host HTTP header to the proxied host, for this example www.frontend.org, which will be returned by request.getServerName().

        tomcat server.xml snippet:

        <Valve 
           className="org.apache.catalina.valves.RemoteIpValve"
           internalProxies="192\.168\.100\.254"
           remoteIpHeader="x-forwarded-for"
           remoteIpProxiesHeader="x-forwarded-by"
           protocolHeader="x-forwarded-proto"
           />

        The valve will take care of binding the https scheme to the request.getScheme() and 443 to request.getServerPort()

        Show
        Gert Dewit added a comment - - edited This seems a good strategy to me. This filter can be used where the combination of the correct Apache reverse proxy config and Tomcat RemoteIpValve is not possible (no Apache reverse proxy, No Apache Tomcat). The sample configs below can be used with an Apache HTTP Server based reverse proxy and Apache Tomcat as backed server. The published url for the application is https://www.frontend.org/cmis , the Apache HTTP server handles https termination and it's IP address is 192.168.100.254. httpd.conf snippet: <Location /cmis> RequestHeader set X-Forwarded-Proto "https" ProxyPreserveHost ProxyPass http: //tomcat.backend.org:8080/cmis ProxyPassReverse http: //tomcat.backend.org:8080/cmis </Location> The ProxyPreserveHost directive will pass the Original Host HTTP header to the proxied host, for this example www.frontend.org, which will be returned by request.getServerName(). tomcat server.xml snippet: <Valve className= "org.apache.catalina.valves.RemoteIpValve" internalProxies= "192\.168\.100\.254" remoteIpHeader= "x-forwarded- for " remoteIpProxiesHeader= "x-forwarded-by" protocolHeader= "x-forwarded-proto" /> The valve will take care of binding the https scheme to the request.getScheme() and 443 to request.getServerPort()
        Hide
        Florian Müller added a comment -

        I have moved the X-Forwarded code out of the AtomPub servlet and put into a servlet filter. If it is not needed it doesn't harm. If something like this is required we have a solution but don't force the server operator to use it if other/better/different facilities are available.

        Show
        Florian Müller added a comment - I have moved the X-Forwarded code out of the AtomPub servlet and put into a servlet filter. If it is not needed it doesn't harm. If something like this is required we have a solution but don't force the server operator to use it if other/better/different facilities are available.
        Hide
        Gert Dewit added a comment -

        I'll look into the apache valves, this can be a solution for my tomcat deployments.
        I will have to check for a similar solution for jetty and jboss though.

        Show
        Gert Dewit added a comment - I'll look into the apache valves, this can be a solution for my tomcat deployments. I will have to check for a similar solution for jetty and jboss though.
        Hide
        Jens Hübel added a comment -

        I did not look at the details, I only had the impression that this is something similar. Should we perhaps post this to the Tomcat list then?

        Show
        Jens Hübel added a comment - I did not look at the details, I only had the impression that this is something similar. Should we perhaps post this to the Tomcat list then?
        Hide
        Florian Müller added a comment -

        I looked at RemoteIpValve and it's a solution for a different problem. In general, I agree and I also thought that there must be a generic solution. In fact, it is possible to move the code into a separate, OpenCMIS independent filter. But I haven't found anything that would be reusable across different servlet engines.

        Show
        Florian Müller added a comment - I looked at RemoteIpValve and it's a solution for a different problem. In general, I agree and I also thought that there must be a generic solution. In fact, it is possible to move the code into a separate, OpenCMIS independent filter. But I haven't found anything that would be reusable across different servlet engines.
        Hide
        Gert Dewit added a comment -

        You have a point for tomcat deployments. Something like the RemoteIpValve could do the job there.

        Show
        Gert Dewit added a comment - You have a point for tomcat deployments. Something like the RemoteIpValve could do the job there.
        Hide
        Jens Hübel added a comment -

        Are we really sure that the best answer to this problem is to handle this on application level? I can't believe that zillions of Java web applications have to deal with how to work behind a proxy. What happens with other webapps on the same server?
        Aren't there more generic solutions available to this issue, something like http://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/valves/RemoteIpValve.html.
        I only want to keep our stuff simple, if possible.

        Show
        Jens Hübel added a comment - Are we really sure that the best answer to this problem is to handle this on application level? I can't believe that zillions of Java web applications have to deal with how to work behind a proxy. What happens with other webapps on the same server? Aren't there more generic solutions available to this issue, something like http://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/valves/RemoteIpValve.html . I only want to keep our stuff simple, if possible.
        Hide
        Florian Müller added a comment -

        I just hadn't had the time last night to adjust the unit tests. I deliberately didn't close the issue because of the unit tests and because I wanted to wait for your feedback.

        Show
        Florian Müller added a comment - I just hadn't had the time last night to adjust the unit tests. I deliberately didn't close the issue because of the unit tests and because I wanted to wait for your feedback.
        Hide
        Gert Dewit added a comment -

        It works indeed.

        On a side note, why didn't you retain the unit tests ? I'll adapt them to your implementation if that suits you.

        Show
        Gert Dewit added a comment - It works indeed. On a side note, why didn't you retain the unit tests ? I'll adapt them to your implementation if that suits you.
        Hide
        Gert Dewit added a comment -

        It looks like it would work, I'll test it out tomorrow and get back to you.

        The tomcat approach doesn't work in our environment BTW, because our CMIS repository should be accessible from different networks (internet, intranet, extranet) which all hide behind different reverse proxies in different DNS domains.

        Show
        Gert Dewit added a comment - It looks like it would work, I'll test it out tomorrow and get back to you. The tomcat approach doesn't work in our environment BTW, because our CMIS repository should be accessible from different networks (internet, intranet, extranet) which all hide behind different reverse proxies in different DNS domains.
        Hide
        Florian Müller added a comment -

        These headers are easy to spoof and could become a security issue. That's why I went for a different implementation. The web.xml now contains a parameter that defines IP addresses of trusted proxies. The X-Forwarded headers are only evaluated if the request went through such a trusted proxy.
        Please let us know if that works for you.

        Show
        Florian Müller added a comment - These headers are easy to spoof and could become a security issue. That's why I went for a different implementation. The web.xml now contains a parameter that defines IP addresses of trusted proxies. The X-Forwarded headers are only evaluated if the request went through such a trusted proxy. Please let us know if that works for you.
        Hide
        Florian Müller added a comment -

        The preferred way for Tomcat is to change the proxyName and proxyPort settings in the server.xml [1].
        I'll check if evaluating the X-Forwarded-Host and X-Forwarded-Proto headers introduces a security issue and if not, I'll apply the patch.

        [1] http://tomcat.apache.org/tomcat-7.0-doc/config/http.html#Proxy_Support

        Show
        Florian Müller added a comment - The preferred way for Tomcat is to change the proxyName and proxyPort settings in the server.xml [1] . I'll check if evaluating the X-Forwarded-Host and X-Forwarded-Proto headers introduces a security issue and if not, I'll apply the patch. [1] http://tomcat.apache.org/tomcat-7.0-doc/config/http.html#Proxy_Support
        Hide
        Carlo Sciolla added a comment -

        +1

        A must have for us.

        Show
        Carlo Sciolla added a comment - +1 A must have for us.
        Hide
        Gert Dewit added a comment -

        This patch contains the code and JUnit tests

        Show
        Gert Dewit added a comment - This patch contains the code and JUnit tests

          People

          • Assignee:
            Florian Müller
            Reporter:
            Gert Dewit
          • Votes:
            1 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development