[ https://issues.apache.org/jira/browse/JENA-2011?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Alexander Radzin updated JENA-2011: ----------------------------------- Description: h1. Description Start fuseki server on IPv6 environment and navigate browser to [http://localhost:3030|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. h1. 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): {code:java} 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); } {code} (I put here only the relevant part). Now let's review {{HostPort.normalizeHost}}: {code:java} 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 + "]"; } {code} 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. h1. 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}}: {code:java} * 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. {code} we can assume that such format is "standard" and just add wrapped version of this IP to {{LocalhostFilter}}: {code:java} 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()); } {code} h1. Workaround Current workaround is to fix file {{shiro.ini}}: just uncomment line {code} ##/$/** = anon {code} This grant permission to anonymous user to access to access all APIs (that start with {{$}}). was: h1. Description Start fuseki server on IPv6 environment and navigate browser to [http://localhost:3030|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. h1. 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): {code:java} 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); } {code} (I put here only the relevant part). Now let's review {{HostPort.normalizeHost}}: {code:java} 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 + "]"; } {code} 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. h1. 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}}: {code:java} * 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. {code} we can assume that such format is "standard" and just add wrapped version of this IP to {{LocalhostFilter}}: {code:java} 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()); } {code} > Fuseki does not work in IPv6 environment with Jetty > --------------------------------------------------- > > Key: JENA-2011 > URL: https://issues.apache.org/jira/browse/JENA-2011 > Project: Apache Jena > Issue Type: Bug > Components: Fuseki > Affects Versions: Jena 3.17.0 > Environment: Tested on both Linux (with JDK 13) and Windows (with JDK > 15) > Reporter: Alexander Radzin > Priority: Major > Original Estimate: 1h > Remaining Estimate: 1h > > h1. Description > Start fuseki server on IPv6 environment and navigate browser to > [http://localhost:3030|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. > h1. 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): > {code:java} > 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); > } > {code} > (I put here only the relevant part). > Now let's review {{HostPort.normalizeHost}}: > {code:java} > 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 + "]"; > } > {code} > 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. > h1. 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}}: > {code:java} > * 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. > {code} > we can assume that such format is "standard" and just add wrapped version of > this IP to {{LocalhostFilter}}: > {code:java} > 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()); > } > {code} > h1. Workaround > Current workaround is to fix file {{shiro.ini}}: just uncomment line > {code} > ##/$/** = anon > {code} > This grant permission to anonymous user to access to access all APIs (that > start with {{$}}). -- This message was sent by Atlassian Jira (v8.3.4#803005)