Uploaded image for project: 'Apache Jena'
  1. Apache Jena
  2. JENA-2011

Fuseki does not work in IPv6 environment with Jetty

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • Jena 3.17.0
    • Jena 4.0.0
    • Fuseki
    • None
    • Tested on both Linux (with JDK 13) and Windows (with JDK 15)

    Description

      Description

      Start fuseki server on IPv6 environment and navigate browser to http://localhost:3030.

      The UI does not show any datasets and all attempts to do anything with UI fail. Press F12 (dev tools) in your browser and see that GET request to `$/server` returns with error status 403 Forbidden.

      Analysis

      The discovery shows the following problem. The status is set by org.apache.jena.fuseki.authz.LocalhostFilter: isAccessAllowed() returns `false`.
      This happens in turn because the remoteAddr should be one of 0:0:0:0:0:0:0:1 or 127.0.0.1.

      Now let's take a look on code in `org.eclipse.jetty.server.Request` (implementation of `HttpServletRequest` used in Jetty): 

          public String getRemoteAddr() {
             ..............................................
              // Add IPv6 brackets if necessary, to be consistent
              // with cases where _remote has been built from other
              // sources such as forward headers or PROXY protocol.
              return HostPort.normalizeHost(result);
          }
      

      (I put here only the relevant part).

      Now let's review HostPort.normalizeHost:

          public static String normalizeHost(String host)
          {
              // if it is normalized IPv6 or could not be IPv6, return
              if (host.isEmpty() || host.charAt(0) == '[' || host.indexOf(':') < 0)
                  return host;
      
              // normalize with [ ]
              return "[" + host + "]";
          }
      

      In case of IPv6 we this function wraps the address using squire brackets, i.e. address 0:0:0:0:0:0:0:1 becomes [0:0:0:0:0:0:0:1]. However jumping back to the LocalhostFilter.isAccessAllowed() the wrapped string is compared to unwrapped one that causes isAccessAllowed to return false.

      Suggested fix

      Since wrapping of the address with squire brackets is the Jetty specific we cannot just changes string "0:0:0:0:0:0:0:1" to "[0:0:0:0:0:0:0:1]" in LocalhostFilter because such change might break this code in other environments. However taking in cosideration comment in HostPort.normalizeHost:

           * Normalizes IPv6 address as per https://tools.ietf.org/html/rfc2732
           * and https://tools.ietf.org/html/rfc6874,
           * surrounding with square brackets if they are absent.
      

      we can assume that such format is "standard" and just add wrapped version of this IP to LocalhostFilter:

      private static final Collection<String> localhosts = new HashSet<>(Arrays.asList(LOCALHOST_IpV4, LOCALHOST_IpV6, "[" +LOCALHOST_IpV4 + "]"));
      
      protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
          return  localhosts.contains(request.getRemoteAddr());
      }
      

      Workaround

      Current workaround is to fix file shiro.ini: just uncomment line

      ##/$/** = anon
      

      This grant permission to anonymous user to access to access all APIs (that start with $).

      Attachments

        Activity

          People

            andy Andy Seaborne
            alexander_radzin Alexander Radzin
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Time Tracking

                Estimated:
                Original Estimate - 1h
                1h
                Remaining:
                Time Spent - 40m Remaining Estimate - 20m
                20m
                Logged:
                Time Spent - 40m Remaining Estimate - 20m
                40m