[ 
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)

Reply via email to