You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@nifi.apache.org by "humpfhumpf (Jira)" <ji...@apache.org> on 2020/08/27 15:02:00 UTC

[jira] [Updated] (NIFI-7771) Infinite loop on WebUI when node stopped in cluster

     [ https://issues.apache.org/jira/browse/NIFI-7771?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

humpfhumpf updated NIFI-7771:
-----------------------------
    Description: 
h2. Context

Before the bug occurs, it needs:
 * One load-balancer which uses client IP affinity to “select” one NiFi instance in the cluster;
 * One fresh and successful OpenID Connect authentication on WebUI.

Then, stops the NiFi instance, which was “selected” by the load-balancer for you.

WebUI (javascript) continues to poll WebAPI by fetching status URLs, but all calls return HTTP 401 error. Then WebUI shows an error screen: “Unauthorized. Unable to validate the access token.”, with 2 links: “log out” and “home”.

If you click on the “home” link, *the browser enters in an infinite loop of redirects between NiFi and OIDC Identity Provider.*

The offending HTTP flows is:
 * “home” link calls: GET /nifi
 * Redirects to: GET /nifi/
 ** asynchronously calls: GET /nifi-api/flow/current-user => failed HTTP 401
 * Redirects to: GET /nifi/login
 * Redirects to: GET <my_idp_url>/openid-connect/auth
 * Redirects to: GET /nifi-api/access/oidc/callback
 * Redirects to: GET /nifi
 * Redirects to: GET /nifi/
 ** asynchronously calls: GET /nifi-api/flow/current-user => failed HTTP 401
 * [loop]

 

The stack trace of {{/nifi-api/flow/current-user}} call is:

 
{code:java}
ERROR [NiFi Web Server-284] o.a.nifi.web.security.jwt.JwtService There was an error validating the JWT io.jsonwebtoken.JwtException: Unable to validate the access token.
         at org.apache.nifi.web.security.jwt.JwtService.parseTokenFromBase64EncodedString(JwtService.java:106)
         at org.apache.nifi.web.security.jwt.JwtService.getAuthenticationFromToken(JwtService.java:60)
         at org.apache.nifi.web.security.jwt.JwtAuthenticationProvider.authenticate(JwtAuthenticationProvider.java:48)
         at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
         at org.apache.nifi.web.security.NiFiAuthenticationFilter.authenticate(NiFiAuthenticationFilter.java:78)
         at org.apache.nifi.web.security.NiFiAuthenticationFilter.doFilter(NiFiAuthenticationFilter.java:58)
         at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
         at org.apache.nifi.web.security.NiFiAuthenticationFilter.authenticate(NiFiAuthenticationFilter.java:99)
         at org.apache.nifi.web.security.NiFiAuthenticationFilter.doFilter(NiFiAuthenticationFilter.java:58)
         ...
Caused by: io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
         at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:342)
         at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:458)
         at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:518)
         at org.apache.nifi.web.security.jwt.JwtService.parseTokenFromBase64EncodedString(JwtService.java:102)
         ...
{code}
 

 

In my opinion, there are 2 problems:
h2. Problem 1

The NiFi JWT token is used (and not replaced) by nfCanvas.init() even after loadCurrentUser() failed with an authentication error (when GET /nifi-api/flow/current-user returns 401).

In such case, this token, stored in nfStorage (in Javascript Local Storage of browser), should be cleared before redirecting to /nifi/login.
h2. Problem 2

The NiFi JWT token is not shared among NiFi cluster.

This token is not the original id_token returned by the OIDC Identity Provider, but a new one, generated by the NiFi instance on which the browser was routed during the OIDC connection flow.

This token is closely related to some data stored in H2 users database (nifi-user-keys.h2.db).

Its “KEY” table contains the following data for each user: email, a primary key (auto increment) and a generated UUID.

The NiFi JWT token contains (among other things) a copy of email and the auto-incremented primary key. Moreover, this JWT is HS256-signed with UUID key.

*But, both primary key and UUID are not shared in NiFi cluster.*

It seems to be the reason why WebUI must interrupt its polling to WebAPI: stored JWT is no more valid on the new “selected” NiFi instance, to which the load-balancer routes your browser.

I think there are 3 solutions:
 * Use a shared secret (from a new property in nifi.properties) to sign NiFi JWT tokens. The uselessness of the primary key inside the token should be checked;
 * Synchronize the H2 users database among NiFi cluster;
 * Replace the NiFi interal JWT token by the official OIDC JWT “id_token” on every WebAPI call.

 

  was:
h2. Context

Before the bug occurs, it needs:
 * One load-balancer which uses client IP affinity to “select” one NiFi instance in the cluster;
 * One fresh and successful OpenID Connect authentication on WebUI.

Then, stops the NiFi instance, which was “selected” by the load-balancer for you.

WebUI (javascript) continues to poll WebAPI by fetching status URLs, but all calls return HTTP 401 error. Then WebUI shows an error screen: “Unauthorized. Unable to validate the access token.”, with 2 links: “log out” and “home”.

If you click on the “home” link, *the browser enters in an infinite loop of redirects between NiFi and OIDC Identity Provider.*

The offending HTTP flows is:
 * “home” link calls: GET /nifi
 * Redirects to: GET /nifi/
 ** asynchronously calls: GET /nifi-api/flow/current-user => failed HTTP 401
 * Redirects to: GET /nifi/login
 * Redirects to: GET <my_idp_url>/openid-connect/auth
 * Redirects to: GET /nifi-api/access/oidc/callback
 * Redirects to: GET /nifi
 * Redirects to: GET /nifi/
 ** asynchronously calls: GET /nifi-api/flow/current-user => failed HTTP 401
 * [loop]

 

The stack trace of {{/nifi-api/flow/current-user}} call is:

 
{code:java}
ERROR [NiFi Web Server-284] o.a.nifi.web.security.jwt.JwtService There was an error validating the JWT io.jsonwebtoken.JwtException: Unable to validate the access token.
         at org.apache.nifi.web.security.jwt.JwtService.parseTokenFromBase64EncodedString(JwtService.java:106)
         at org.apache.nifi.web.security.jwt.JwtService.getAuthenticationFromToken(JwtService.java:60)
         at org.apache.nifi.web.security.jwt.JwtAuthenticationProvider.authenticate(JwtAuthenticationProvider.java:48)
         at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
         at org.apache.nifi.web.security.NiFiAuthenticationFilter.authenticate(NiFiAuthenticationFilter.java:78)
         at org.apache.nifi.web.security.NiFiAuthenticationFilter.doFilter(NiFiAuthenticationFilter.java:58)
         at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
         at org.apache.nifi.web.security.NiFiAuthenticationFilter.authenticate(NiFiAuthenticationFilter.java:99)
         at org.apache.nifi.web.security.NiFiAuthenticationFilter.doFilter(NiFiAuthenticationFilter.java:58)
         ...
Caused by: io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
         at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:342)
         at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:458)
         at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:518)
         at org.apache.nifi.web.security.jwt.JwtService.parseTokenFromBase64EncodedString(JwtService.java:102)
         ...
{code}
 

 

In my opinion, there are 2 problems:
h2. Problem 1

The NiFi JWT token is used (and not replaced) by nfCanvas.init() even after loadCurrentUser() failed with an authentication error (when GET /nifi-api/flow/current-user returns 401).

In such case, this token, stored in nfStorage (in Javascript Local Storage of browser), should be cleared before redirecting to /nifi/login.
h2. Problem 2

The NiFi JWT token is not shared among NiFi cluster.

This token is not the original id_token returned by the OIDC Identity Provider, but a new one, generated by the NiFi instance on which your browser was routed during the OIDC connection flow.

This token is closely related to some data stored in H2 users database (nifi-user-keys.h2.db).

Its “KEY” table contains the following data for each user: email, a primary key (auto increment) and a generated UUID.

The NiFi JWT token contains (among other things) a copy of email and the auto-incremented primary key. Moreover, this JWT is HS256-signed with UUID key.

*But, both primary key and UUID are not shared in NiFi cluster.*

It seems to be the reason why WebUI must interrupt its polling to WebAPI: stored JWT is no more valid on the new “selected” NiFi instance, to which the load-balancer routes your browser.

I think there are 3 solutions:
 * Use a shared secret (from a new property in nifi.properties) to sign NiFi JWT tokens. The uselessness of the primary key inside the token should be checked;
 * Synchronize the H2 users database among NiFi cluster;
 * Replace the NiFi interal JWT token by the official OIDC JWT “id_token” on every WebAPI call.

 


> Infinite loop on WebUI when node stopped in cluster
> ---------------------------------------------------
>
>                 Key: NIFI-7771
>                 URL: https://issues.apache.org/jira/browse/NIFI-7771
>             Project: Apache NiFi
>          Issue Type: Bug
>          Components: Core UI
>    Affects Versions: 1.10.0, 1.9.2, 1.12.0, 1.11.4
>         Environment: Linux
>            Reporter: humpfhumpf
>            Priority: Critical
>
> h2. Context
> Before the bug occurs, it needs:
>  * One load-balancer which uses client IP affinity to “select” one NiFi instance in the cluster;
>  * One fresh and successful OpenID Connect authentication on WebUI.
> Then, stops the NiFi instance, which was “selected” by the load-balancer for you.
> WebUI (javascript) continues to poll WebAPI by fetching status URLs, but all calls return HTTP 401 error. Then WebUI shows an error screen: “Unauthorized. Unable to validate the access token.”, with 2 links: “log out” and “home”.
> If you click on the “home” link, *the browser enters in an infinite loop of redirects between NiFi and OIDC Identity Provider.*
> The offending HTTP flows is:
>  * “home” link calls: GET /nifi
>  * Redirects to: GET /nifi/
>  ** asynchronously calls: GET /nifi-api/flow/current-user => failed HTTP 401
>  * Redirects to: GET /nifi/login
>  * Redirects to: GET <my_idp_url>/openid-connect/auth
>  * Redirects to: GET /nifi-api/access/oidc/callback
>  * Redirects to: GET /nifi
>  * Redirects to: GET /nifi/
>  ** asynchronously calls: GET /nifi-api/flow/current-user => failed HTTP 401
>  * [loop]
>  
> The stack trace of {{/nifi-api/flow/current-user}} call is:
>  
> {code:java}
> ERROR [NiFi Web Server-284] o.a.nifi.web.security.jwt.JwtService There was an error validating the JWT io.jsonwebtoken.JwtException: Unable to validate the access token.
>          at org.apache.nifi.web.security.jwt.JwtService.parseTokenFromBase64EncodedString(JwtService.java:106)
>          at org.apache.nifi.web.security.jwt.JwtService.getAuthenticationFromToken(JwtService.java:60)
>          at org.apache.nifi.web.security.jwt.JwtAuthenticationProvider.authenticate(JwtAuthenticationProvider.java:48)
>          at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
>          at org.apache.nifi.web.security.NiFiAuthenticationFilter.authenticate(NiFiAuthenticationFilter.java:78)
>          at org.apache.nifi.web.security.NiFiAuthenticationFilter.doFilter(NiFiAuthenticationFilter.java:58)
>          at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
>          at org.apache.nifi.web.security.NiFiAuthenticationFilter.authenticate(NiFiAuthenticationFilter.java:99)
>          at org.apache.nifi.web.security.NiFiAuthenticationFilter.doFilter(NiFiAuthenticationFilter.java:58)
>          ...
> Caused by: io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
>          at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:342)
>          at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:458)
>          at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:518)
>          at org.apache.nifi.web.security.jwt.JwtService.parseTokenFromBase64EncodedString(JwtService.java:102)
>          ...
> {code}
>  
>  
> In my opinion, there are 2 problems:
> h2. Problem 1
> The NiFi JWT token is used (and not replaced) by nfCanvas.init() even after loadCurrentUser() failed with an authentication error (when GET /nifi-api/flow/current-user returns 401).
> In such case, this token, stored in nfStorage (in Javascript Local Storage of browser), should be cleared before redirecting to /nifi/login.
> h2. Problem 2
> The NiFi JWT token is not shared among NiFi cluster.
> This token is not the original id_token returned by the OIDC Identity Provider, but a new one, generated by the NiFi instance on which the browser was routed during the OIDC connection flow.
> This token is closely related to some data stored in H2 users database (nifi-user-keys.h2.db).
> Its “KEY” table contains the following data for each user: email, a primary key (auto increment) and a generated UUID.
> The NiFi JWT token contains (among other things) a copy of email and the auto-incremented primary key. Moreover, this JWT is HS256-signed with UUID key.
> *But, both primary key and UUID are not shared in NiFi cluster.*
> It seems to be the reason why WebUI must interrupt its polling to WebAPI: stored JWT is no more valid on the new “selected” NiFi instance, to which the load-balancer routes your browser.
> I think there are 3 solutions:
>  * Use a shared secret (from a new property in nifi.properties) to sign NiFi JWT tokens. The uselessness of the primary key inside the token should be checked;
>  * Synchronize the H2 users database among NiFi cluster;
>  * Replace the NiFi interal JWT token by the official OIDC JWT “id_token” on every WebAPI call.
>  



--
This message was sent by Atlassian Jira
(v8.3.4#803005)