apisix icon indicating copy to clipboard operation
apisix copied to clipboard

bug: multi-auth throws an error when using default configuration parameters

Open mikyll opened this issue 1 year ago • 4 comments

Current Behavior

When I configure a route with multi-auth plugin and don't set conf.header value explicitly, the plugin breaks and returns 500 Internal Server Error:

<html>
<head><title>500 Internal Server Error</title></head>
<body>
<center><h1>500 Internal Server Error</h1></center>
<hr><center>openresty</center>
<p><em>Powered by <a href="https://apisix.apache.org/">APISIX</a>.</em></p></body>
</html>

Expected Behavior

I expect to obtain the classic response 401 Unauthorized:

{"message":"Missing API key found in request"}

Error Logs

2024/07/25 12:18:47 [error] 75#75: *522943 lua entry thread aborted: runtime error: /usr/local/openresty/lualib/resty/core/request.lua:118: bad argument #1 to 'lower' (string expected, got nil)
stack traceback:
coroutine 0:
        [C]: in function 'lower'
        /usr/local/openresty/lualib/resty/core/request.lua:118: in function '__index'
        /home/apisix/apisix_src/apisix/core/request.lua:110: in function 'header'
        /home/apisix/apisix_src/apisix/plugins/key-auth.lua:71: in function 'rewrite'
        /home/apisix/apisix_src/apisix/plugins/multi-auth.lua:71: in function 'phase_func'
        /home/apisix/apisix_src/apisix/plugin.lua:1155: in function 'run_plugin'
        /home/apisix/apisix_src/apisix/init.lua:696: in function 'http_access_phase'
        access_by_lua(nginx.conf:319):2: in main chunk, client: ::1, server: _, request: "GET /httpbin/test/multi-auth/test1/ HTTP/1.1", host: "localhost:9080"

Steps to Reproduce

multi-auth Example

Setup the multi-auth test routes:

# With multi-auth and conf.header default value
curl -s -X PUT "http://127.0.0.1:9180/apisix/admin/routes/3" -d '
{
    "uris": [ "/httpbin/test/multi-auth/test1/*" ],
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "httpbin.org:80": 1
        }
    },
    "plugins": {
        "proxy-rewrite": {
            "regex_uri": [
                "^/httpbin/test/multi-auth/test1/(.*)",
                "/get"
            ],
            "method": "GET"
        },
        "multi-auth":{
            "auth_plugins":[
                {
                    "basic-auth": {}
                },
                {
                    "key-auth": {
                        "hide_credentials":true
                    }
                }
            ]
        }
    }
}
'

# With multi-auth and conf.header custom value
curl -s -X PUT "http://127.0.0.1:9180/apisix/admin/routes/4" -d '
{
    "uris": [ "/httpbin/test/multi-auth/test2/*" ],
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "httpbin.org:80": 1
        }
    },
    "plugins": {
        "proxy-rewrite": {
            "regex_uri": [
                "^/httpbin/test/multi-auth/test2/(.*)",
                "/get"
            ],
            "method": "GET"
        },
        "multi-auth":{
            "auth_plugins":[
                {
                    "basic-auth": {}
                },
                {
                    "key-auth": {
                        "hide_credentials":true,
                        "header":"apikey"
                    }
                }
            ]
        }
    }
}
'

Test:

curl -s -i "http://localhost:9080/httpbin/test/multi-auth/test1/"    # This gives 500 Internal Server Error (see log message)
curl -s -i "http://localhost:9080/httpbin/test/multi-auth/test2/"    # This works

key-auth Example

With simple key-auth plugin it works just fine:

# With key-auth and conf.header default value
curl -s -X PUT "http://127.0.0.1:9180/apisix/admin/routes/1" -d '
{
    "uris": [ "/httpbin/test/key-auth/test1/*" ],
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "httpbin.org:80": 1
        }
    },
    "plugins": {
        "proxy-rewrite": {
            "regex_uri": [
                "^/httpbin/test/key-auth/test1/(.*)",
                "/get"
            ],
            "method": "GET"
        },
        "key-auth": {
            "hide_credentials":true
        }

    }
}
'

# With key-auth and conf.header custom value
curl -s -X PUT "http://127.0.0.1:9180/apisix/admin/routes/2" -d '
{
    "uris": [ "/httpbin/test/key-auth/test2/*" ],
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "httpbin.org:80": 1
        }
    },
    "plugins": {
        "proxy-rewrite": {
            "regex_uri": [
                "^/httpbin/test/key-auth/test2/(.*)",
                "/get"
            ],
            "method": "GET"
        },
        "key-auth": {
            "hide_credentials":true,
            "header":"apikey"
        }

    }
}
'

Test:

curl -s -i "http://localhost:9080/httpbin/test/key-auth/test1/"    # This works
curl -s -i "http://localhost:9080/httpbin/test/key-auth/test2/"    # This works

Environment

  • APISIX version (run apisix version):

    3.9.1
    
  • Operating system (run uname -a):

    Linux e911f1d22ca2 5.15.146.1-microsoft-standard-WSL2 #1 SMP Thu Jan 11 04:09:03 UTC 2024 x86_64 GNU/Linux
    
    (built from source, in custom Docker container, from `debian:bullseye-slim` image)
    
  • OpenResty / Nginx version (run openresty -V or nginx -V):

    nginx version: openresty/1.25.3.1
    built by gcc 10.2.1 20210110 (Debian 10.2.1-6) 
    built with OpenSSL 3.2.0 23 Nov 2023
    TLS SNI support enabled
    configure arguments: --prefix=/usr/local/openresty/nginx --with-debug --with-cc-opt='-DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC -O2 -DAPISIX_RUNTIME_VER=1.2.0 -DNGX_GRPC_CLI_ENGINE_PATH=/usr/local/openresty/libgrpc_engine.so -DNGX_HTTP_GRPC_CLI_ENGINE_PATH=/usr/local/openresty/libgrpc_engine.so -DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/zlib/include -I/usr/local/openresty/pcre/include -I/usr/local/openresty/openssl3/include' --add-module=../ngx_devel_kit-0.3.3 --add-module=../echo-nginx-module-0.63 --add-module=../xss-nginx-module-0.06 --add-module=../ngx_coolkit-0.2 --add-module=../set-misc-nginx-module-0.33 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.09 --add-module=../srcache-nginx-module-0.33 --add-module=../ngx_lua-0.10.26 --add-module=../ngx_lua_upstream-0.07 --add-module=../headers-more-nginx-module-0.37 --add-module=../array-var-nginx-module-0.06 --add-module=../memc-nginx-module-0.20 --add-module=../redis2-nginx-module-0.15 --add-module=../redis-nginx-module-0.3.9 --add-module=../ngx_stream_lua-0.0.14 --with-ld-opt='-Wl,-rpath,/usr/local/openresty/luajit/lib -Wl,-rpath,/usr/local/openresty/wasmtime-c-api/lib -L/usr/local/openresty/zlib/lib -L/usr/local/openresty/pcre/lib -L/usr/local/openresty/openssl3/lib -Wl,-rpath,/usr/local/openresty/zlib/lib:/usr/local/openresty/pcre/lib:/usr/local/openresty/openssl3/lib' --add-module=/tmp/tmp.PvubYudeuF/openresty-1.25.3.1/../mod_dubbo-1.0.2 --add-module=/tmp/tmp.PvubYudeuF/openresty-1.25.3.1/../ngx_multi_upstream_module-1.2.0 --add-module=/tmp/tmp.PvubYudeuF/openresty-1.25.3.1/../apisix-nginx-module-1.16.0 --add-module=/tmp/tmp.PvubYudeuF/openresty-1.25.3.1/../apisix-nginx-module-1.16.0/src/stream --add-module=/tmp/tmp.PvubYudeuF/openresty-1.25.3.1/../apisix-nginx-module-1.16.0/src/meta --add-module=/tmp/tmp.PvubYudeuF/openresty-1.25.3.1/../wasm-nginx-module-0.7.0 --add-module=/tmp/tmp.PvubYudeuF/openresty-1.25.3.1/../lua-var-nginx-module-v0.5.3 --add-module=/tmp/tmp.PvubYudeuF/openresty-1.25.3.1/../grpc-client-nginx-module-v0.5.0 --add-module=/tmp/tmp.PvubYudeuF/openresty-1.25.3.1/../lua-resty-events-0.2.0 --with-poll_module --with-pcre-jit --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-http_v2_module --with-http_v3_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --with-http_stub_status_module --with-http_realip_module --with-http_addition_module --with-http_auth_request_module --with-http_secure_link_module --with-http_random_index_module --with-http_gzip_static_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-threads --with-compat --with-stream --without-pcre2 --with-http_ssl_module
    
  • LuaRocks version, for installation issues (run luarocks --version):

    /usr/local/bin/luarocks 3.8.0
    

mikyll avatar Jul 25 '24 12:07 mikyll

If that behaviour is expected and multi-auth.auth_plugins are supposed to be configured explicitly, I would suggest to add a disclaimer or some kind of note in the documentation 👀

mikyll avatar Jul 25 '24 12:07 mikyll

This also happens with jwt-auth.

Examples

  1. multi-auth with jwt-auth default values:

    curl -s -X PUT "http://127.0.0.1:9180/apisix/admin/routes/5" -d '
    {
        "uris": [ "/httpbin/test/multi-auth/test3/*" ],
        "upstream": {
            "type": "roundrobin",
            "nodes": {
                "httpbin.org:80": 1
            }
        },
        "plugins": {
            "proxy-rewrite": {
                "regex_uri": [
                    "^/httpbin/test/multi-auth/test3/(.*)",
                    "/get"
                ],
                "method": "GET"
            },
            "multi-auth":{
                "auth_plugins":[
                    {
                        "basic-auth": {}
                    },
                    {
                        "key-auth": {
                            "hide_credentials":true,
                            "header":"apikey"
                        }
                    },
                    {
                        "jwt-auth": {
                            "hide_credentials":true
                        }
                    }
                ]
            }
        }
    }
    '
    

    test:

    curl -s -i "http://localhost:9080/httpbin/test/multi-auth/test3/"    # This gives 500 Internal Server Error (see log message below)
    

    log message:

    2024/07/25 12:55:15 [error] 849#849: *736191 lua entry thread aborted: runtime error: /usr/local/openresty/lualib/resty/core/request.lua:118: bad argument #1 to 'lower' (string expected, got nil)
    stack traceback:
    coroutine 0:
            [C]: in function 'lower'
            /usr/local/openresty/lualib/resty/core/request.lua:118: in function '__index'
            /home/apisix/apisix_src/apisix/core/request.lua:110: in function 'header'
            ...c/apisix/plugins/scm/builtin/apisix/plugins/jwt-auth.lua:182: in function 'fetch_jwt_token'
            ...c/apisix/plugins/scm/builtin/apisix/plugins/jwt-auth.lua:338: in function 'rewrite'
            /home/apisix/apisix_src/apisix/plugins/multi-auth.lua:71: in function 'phase_func'
            /home/apisix/apisix_src/apisix/plugin.lua:1155: in function 'run_plugin'
            /home/apisix/apisix_src/apisix/init.lua:696: in function 'http_access_phase'
            access_by_lua(nginx.conf:319):2: in main chunk, client: ::1, server: _, request: "GET /httpbin/test/multi-auth/test3/ HTTP/1.1", host: "localhost:9080"
    
  2. multi-auth with jwt-auth and custom value for conf.header:

    curl -s -X PUT "http://127.0.0.1:9180/apisix/admin/routes/6" -d '
    {
        "uris": [ "/httpbin/test/multi-auth/test4/*" ],
        "upstream": {
            "type": "roundrobin",
            "nodes": {
                "httpbin.org:80": 1
            }
        },
        "plugins": {
            "proxy-rewrite": {
                "regex_uri": [
                    "^/httpbin/test/multi-auth/test4/(.*)",
                    "/get"
                ],
                "method": "GET"
            },
            "multi-auth":{
                "auth_plugins":[
                    {
                        "basic-auth": {}
                    },
                    {
                        "key-auth": {
                            "hide_credentials":true,
                            "header":"apikey"
                        }
                    },
                    {
                        "jwt-auth": {
                            "hide_credentials":true,
                            "header":"jwt"
                        }
                    }
                ]
            }
        }
    }
    '
    

    test:

    curl -s -i "http://localhost:9080/httpbin/test/multi-auth/test4/"    # This gives 500 Internal Server Error (see log message below)
    

    log message:

    2024/07/25 12:55:17 [error] 843#843: *736393 lua entry thread aborted: runtime error: ...c/apisix/plugins/scm/builtin/apisix/plugins/jwt-auth.lua:208: attempt to concatenate field 'cookie' (a nil valu
    e)
    stack traceback:
    coroutine 0:
            ...c/apisix/plugins/scm/builtin/apisix/plugins/jwt-auth.lua: in function 'fetch_jwt_token'
            ...c/apisix/plugins/scm/builtin/apisix/plugins/jwt-auth.lua:338: in function 'rewrite'
            /home/apisix/apisix_src/apisix/plugins/multi-auth.lua:71: in function 'phase_func'
            /home/apisix/apisix_src/apisix/plugin.lua:1155: in function 'run_plugin'
            /home/apisix/apisix_src/apisix/init.lua:696: in function 'http_access_phase'
            access_by_lua(nginx.conf:319):2: in main chunk, client: ::1, server: _, request: "GET /httpbin/test/multi-auth/test4/ HTTP/1.1", host: "localhost:9080"
    
  3. multi-auth with jwt-auth and custom value for both conf.header and conf.cookie:

    curl -s -X PUT "http://127.0.0.1:9180/apisix/admin/routes/7" -d '
    {
        "uris": [ "/httpbin/test/multi-auth/test5/*" ],
        "upstream": {
            "type": "roundrobin",
            "nodes": {
                "httpbin.org:80": 1
            }
        },
        "plugins": {
            "proxy-rewrite": {
                "regex_uri": [
                    "^/httpbin/test/multi-auth/test5/(.*)",
                    "/get"
                ],
                "method": "GET"
            },
            "multi-auth":{
                "auth_plugins":[
                    {
                        "basic-auth": {}
                    },
                    {
                        "key-auth": {
                            "hide_credentials":true,
                            "header":"apikey"
                        }
                    },
                    {
                        "jwt-auth": {
                            "hide_credentials":true,
                            "header":"jwt",
                            "cookie":"jwt"
                        }
                    }
                ]
            }
        }
    }
    '
    

    test:

    curl -s -i "http://localhost:9080/httpbin/test/multi-auth/test5/"    # This works
    

mikyll avatar Jul 25 '24 12:07 mikyll

Hi @mikyll, thanks for your report. We will check and update here. (cc @bzp2010)

juzhiyuan avatar Aug 01 '24 02:08 juzhiyuan

This problem should have been fixed by this PR https://github.com/apache/apisix/pull/11145, but it seems that this modification is not included in version 3.9.1 https://github.com/apache/apisix/commits/3.9.1/

ronething avatar Aug 01 '24 02:08 ronething

This problem should have been fixed by this PR #11145, but it seems that this modification is not included in version 3.9.1 https://github.com/apache/apisix/commits/3.9.1/

#11145 will be included in 3.10

moonming avatar Aug 07 '24 02:08 moonming