You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Would it be possible to to ensure that the client also receives the WWW-Authenticate header from the subrequest response if a 401 is returned similar to ngx_http_auth_request_module?
This should ensure that if basic auth is being requested the appropriate prompt will be presented to the client.
haproxy-auth-request does not send anything to the client by itself. It just performs a sub-request and sets variables. What you do with these variable is up to you.
You should be able to achieve what you need by doing something like the following:
Not sure if I'm doing something wrong but it looked to me like whenever I perform a http-request deny that the header would never be assigned, is this a HAProxy limitation?
I initially thought this may have been because we have HAProxy performing the TLS termination for the actual auth backend but I've tried reverting to a non-tls backend for the lua.auth-request with no success.
He's my full config in case it helps:
global
lua-prepend-path /usr/local/etc/haproxy/?/http.lua
lua-load /usr/local/etc/haproxy/auth-request.lua
log stdout format raw local0 debug
defaults
mode http log global option httplog option forwardfor
frontend fe_api bind *:8081 ssl crt /usr/local/etc/haproxy/haproxy.pem
stats enable stats uri /api
stats refresh10s stats adminif LOCALHOST
frontend fe_http bind *:8080 ssl crt /usr/local/etc/haproxy/haproxy.pem
acl api-path path_beg -i /api
acl headers-path path -i -m end /headers
acl host-authelia-portal hdr(host) -i login.example.com:8080 acl protected-frontends hdr(host) -m reg -i ^(?i)(admin|home|public|secure)\.example\.com
acl protected-frontends-basic hdr(host) -m reg -i ^(?i)(singlefactor)\.example\.com
http-request set-var(req.scheme) str(https) if { ssl_fc }
http-request set-var(req.scheme) str(http) if !{ ssl_fc }
http-request set-var(req.questionmark) str(?) if { query -m found }
http-request set-var(req.method) str(CONNECT) if { method CONNECT }
http-request set-var(req.method) str(GET) if { method GET }
http-request set-var(req.method) str(HEAD) if { method HEAD }
http-request set-var(req.method) str(OPTIONS) if { method OPTIONS }
http-request set-var(req.method) str(POST) if { method POST }
http-request set-var(req.method) str(TRACE) if { method TRACE }
http-request set-var(req.method) str(PUT) if { method PUT }
http-request set-var(req.method) str(PATCH) if { method PATCH }
http-request set-var(req.method) str(DELETE) if { method DELETE }
http-request set-header X-Forwarded-Method %[var(req.method)] http-request set-header X-Real-IP %[src] http-request set-header X-Forwarded-Proto %[var(req.scheme)] http-request set-header X-Forwarded-Host %[req.hdr(Host)] http-request set-header X-Forwarded-Uri %[path]%[var(req.questionmark)]%[query]# be_auth_request is used to make HAProxy do the TLS termination since the Lua script# does not know how to handle it (see https://github.com/TimWolla/haproxy-auth-request/issues/12). http-request lua.auth-request be_auth_request /api/verify if protected-frontends
http-request lua.auth-request be_auth_request /api/verify?auth=basic if protected-frontends-basic
http-request set-var(txn.auth) var(req.auth_response_header.www_authenticate) if protected-frontends-basic !{ var(txn.auth_response_successful) -m bool }
http-response set-header WWW-Authenticate %[var(txn.auth)]if !{ var(txn.auth_response_successful) -m bool }
http-request redirect location https://login.example.com:8080/?rd=%[var(req.scheme)]://%[base]%[var(req.questionmark)]%[query]if protected-frontends !{ var(txn.auth_response_successful) -m bool }
http-request deny deny_status 401if protected-frontends-basic !{ var(txn.auth_response_successful) -m bool }
use_backend be_authelia if host-authelia-portal api-path
use_backend fe_authelia if host-authelia-portal !api-path
use_backend be_httpbin if protected-frontends headers-path
use_backend be_mail if { hdr(host) -i mail.example.com:8080 }
use_backend be_protected if protected-frontends || protected-frontends-basic
backend be_auth_request mode http server proxy 127.0.0.1:8085
listen be_auth_request_proxy mode http bind127.0.0.1:8085 server authelia-backend authelia-backend:9091 ssl verify none
backend be_authelia server authelia-backend authelia-backend:9091 ssl verify none
backend fe_authelia server authelia-frontend authelia-frontend:3000
backend be_httpbin acl remote_user_exist var(req.auth_response_header.remote_user) -m found
acl remote_groups_exist var(req.auth_response_header.remote_groups) -m found
acl remote_name_exist var(req.auth_response_header.remote_name) -m found
acl remote_email_exist var(req.auth_response_header.remote_email) -m found
http-request set-header Remote-User %[var(req.auth_response_header.remote_user)]if remote_user_exist
http-request set-header Remote-Groups %[var(req.auth_response_header.remote_groups)]if remote_groups_exist
http-request set-header Remote-Name %[var(req.auth_response_header.remote_name)]if remote_name_exist
http-request set-header Remote-Email %[var(req.auth_response_header.remote_email)]if remote_email_exist
server httpbin-backend httpbin:8000
backend be_mail server smtp-backend smtp:1080
backend be_protected server nginx-backend nginx-backend:80
Ideally what I'm trying to achieve with this flow is if the auth request backend responds with a 401 and the WWW-Authenticate header that this illicits the same response to the client.
If I remove the http-request deny deny_status 401 if protected-frontends-basic !{ var(txn.auth_response_successful) -m bool } line then I can see the header present but it won't prompt the basic auth login prompt without the 401 response too.
If I add the http-request deny deny_status 401 if protected-frontends-basic !{ var(txn.auth_response_successful) -m bool } line then I don't see the header.
Not sure if I'm doing something wrong but it looked to me like whenever I perform a http-request deny that the header would never be assigned, is this a HAProxy limitation?
This is a HAProxy limitation. The http-response rules are not evaluated for responses generated by HAProxy. Either use http-after-response set-header www-authenticate %[var(txn.auth)] or http-response deny deny_status 401 hdr www-authenticate %[var(txn.auth)] (not sure whether I got the syntax 100% correct). Both needs HAProxy 2.2+.
Activity
TimWolla commentedon Mar 13, 2021
haproxy-auth-request does not send anything to the client by itself. It just performs a sub-request and sets variables. What you do with these variable is up to you.
You should be able to achieve what you need by doing something like the following:
nightah commentedon Mar 15, 2021
Thanks for the response @TimWolla.
Not sure if I'm doing something wrong but it looked to me like whenever I perform a
http-request denythat the header would never be assigned, is this a HAProxy limitation?I initially thought this may have been because we have HAProxy performing the TLS termination for the actual auth backend but I've tried reverting to a non-tls backend for the
lua.auth-requestwith no success.He's my full config in case it helps:
global lua-prepend-path /usr/local/etc/haproxy/?/http.lua lua-load /usr/local/etc/haproxy/auth-request.lua log stdout format raw local0 debug defaults mode http log global option httplog option forwardfor frontend fe_api bind *:8081 ssl crt /usr/local/etc/haproxy/haproxy.pem stats enable stats uri /api stats refresh 10s stats admin if LOCALHOST frontend fe_http bind *:8080 ssl crt /usr/local/etc/haproxy/haproxy.pem acl api-path path_beg -i /api acl headers-path path -i -m end /headers acl host-authelia-portal hdr(host) -i login.example.com:8080 acl protected-frontends hdr(host) -m reg -i ^(?i)(admin|home|public|secure)\.example\.com acl protected-frontends-basic hdr(host) -m reg -i ^(?i)(singlefactor)\.example\.com http-request set-var(req.scheme) str(https) if { ssl_fc } http-request set-var(req.scheme) str(http) if !{ ssl_fc } http-request set-var(req.questionmark) str(?) if { query -m found } http-request set-var(req.method) str(CONNECT) if { method CONNECT } http-request set-var(req.method) str(GET) if { method GET } http-request set-var(req.method) str(HEAD) if { method HEAD } http-request set-var(req.method) str(OPTIONS) if { method OPTIONS } http-request set-var(req.method) str(POST) if { method POST } http-request set-var(req.method) str(TRACE) if { method TRACE } http-request set-var(req.method) str(PUT) if { method PUT } http-request set-var(req.method) str(PATCH) if { method PATCH } http-request set-var(req.method) str(DELETE) if { method DELETE } http-request set-header X-Forwarded-Method %[var(req.method)] http-request set-header X-Real-IP %[src] http-request set-header X-Forwarded-Proto %[var(req.scheme)] http-request set-header X-Forwarded-Host %[req.hdr(Host)] http-request set-header X-Forwarded-Uri %[path]%[var(req.questionmark)]%[query] # be_auth_request is used to make HAProxy do the TLS termination since the Lua script # does not know how to handle it (see https://github.com/TimWolla/haproxy-auth-request/issues/12). http-request lua.auth-request be_auth_request /api/verify if protected-frontends http-request lua.auth-request be_auth_request /api/verify?auth=basic if protected-frontends-basic http-request set-var(txn.auth) var(req.auth_response_header.www_authenticate) if protected-frontends-basic !{ var(txn.auth_response_successful) -m bool } http-response set-header WWW-Authenticate %[var(txn.auth)] if !{ var(txn.auth_response_successful) -m bool } http-request redirect location https://login.example.com:8080/?rd=%[var(req.scheme)]://%[base]%[var(req.questionmark)]%[query] if protected-frontends !{ var(txn.auth_response_successful) -m bool } http-request deny deny_status 401 if protected-frontends-basic !{ var(txn.auth_response_successful) -m bool } use_backend be_authelia if host-authelia-portal api-path use_backend fe_authelia if host-authelia-portal !api-path use_backend be_httpbin if protected-frontends headers-path use_backend be_mail if { hdr(host) -i mail.example.com:8080 } use_backend be_protected if protected-frontends || protected-frontends-basic backend be_auth_request mode http server proxy 127.0.0.1:8085 listen be_auth_request_proxy mode http bind 127.0.0.1:8085 server authelia-backend authelia-backend:9091 ssl verify none backend be_authelia server authelia-backend authelia-backend:9091 ssl verify none backend fe_authelia server authelia-frontend authelia-frontend:3000 backend be_httpbin acl remote_user_exist var(req.auth_response_header.remote_user) -m found acl remote_groups_exist var(req.auth_response_header.remote_groups) -m found acl remote_name_exist var(req.auth_response_header.remote_name) -m found acl remote_email_exist var(req.auth_response_header.remote_email) -m found http-request set-header Remote-User %[var(req.auth_response_header.remote_user)] if remote_user_exist http-request set-header Remote-Groups %[var(req.auth_response_header.remote_groups)] if remote_groups_exist http-request set-header Remote-Name %[var(req.auth_response_header.remote_name)] if remote_name_exist http-request set-header Remote-Email %[var(req.auth_response_header.remote_email)] if remote_email_exist server httpbin-backend httpbin:8000 backend be_mail server smtp-backend smtp:1080 backend be_protected server nginx-backend nginx-backend:80Ideally what I'm trying to achieve with this flow is if the auth request backend responds with a 401 and the WWW-Authenticate header that this illicits the same response to the client.
If I remove the
http-request deny deny_status 401 if protected-frontends-basic !{ var(txn.auth_response_successful) -m bool }line then I can see the header present but it won't prompt the basic auth login prompt without the 401 response too.If I add the
http-request deny deny_status 401 if protected-frontends-basic !{ var(txn.auth_response_successful) -m bool }line then I don't see the header.TimWolla commentedon Mar 15, 2021
This is a HAProxy limitation. The
http-responserules are not evaluated for responses generated by HAProxy. Either usehttp-after-response set-header www-authenticate %[var(txn.auth)]orhttp-response deny deny_status 401 hdr www-authenticate %[var(txn.auth)](not sure whether I got the syntax 100% correct). Both needs HAProxy 2.2+.nightah commentedon Mar 16, 2021
Thanks for your support @TimWolla I've managed to get this working as expected.